Переработка интерфейса animesss
// ==UserScript==
// @name Animesss Pro Redesign
// @namespace http://tampermonkey.net/
// @version 2.1.4
// @description Переработка интерфейса animesss
// @author VladLIO
// @match https://animesss.tv/*
// @match https://animesss.com/*
// @license MIT
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
// ===================== РАННІЙ СТАРТ ФОНУ (до рендеру сторінки) =====================
// Запускається при document-start — html елемент вже є, body ще немає.
//
// ЧОМУ localStorage а не GM_getValue для раннього читання:
// GM_getValue → йде через API розширення (async bridge) — є затримка ~1-5мс
// localStorage → синхронний, читається з пам'яті, ~0мс
// На document-start кожна мілісекунда важлива — різниця між "блик є" і "блика нема".
//
// localStorage тут — тільки швидкий кеш. GM_setValue залишається джерелом правди
// і синхронізує localStorage при кожному збереженні налаштувань.
(function earlyBackground() {
const lsUrl = localStorage.getItem('glass_bg_url');
const lsB64 = localStorage.getItem('glass_bg_b64'); // просто маркер "є base64"
// Для URL-фону — preload: браузер починає качати картинку ДО того як CSS застосується
if (lsUrl && lsUrl.startsWith('http')) {
const preload = document.createElement('link');
preload.rel = 'preload';
preload.as = 'image';
preload.href = lsUrl;
document.documentElement.appendChild(preload);
}
// Визначаємо bgUrl для CSS
// base64 важкий для localStorage тому читаємо через GM_getValue (він в пам'яті розширення)
let bgUrl;
if (lsB64) {
bgUrl = GM_getValue('custom_bg_base64_image', null) || '../images/fon2024.webp';
} else if (lsUrl) {
bgUrl = lsUrl;
} else {
bgUrl = '../images/fon2024.webp';
}
const style = document.createElement('style');
style.id = 'glass-bg-early';
style.textContent = `
html {
background-image: url('${bgUrl}') !important;
background-size: cover !important;
background-position: center center !important;
background-repeat: no-repeat !important;
background-attachment: fixed !important;
}
.wrapper-as {
background-image: none !important;
background-color: transparent !important;
}
`;
document.documentElement.appendChild(style);
})();
// Безпечний запуск: якщо DOM вже готовий (наприклад браузер кешував сторінку
// або сайт використовує навігацію без перезавантаження) — запускаємось одразу,
// інакше чекаємо DOMContentLoaded. Це виправляє випадки коли скрипт не вмикався.
function domReady(fn) {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', fn);
} else {
fn(); // DOM вже готовий — запускаємось негайно
}
}
domReady(function () {
// ===================== КЛЮЧІ СХОВИЩА =====================
const BG_KEY = 'custom_bg_base64_image';
const BG_URL_KEY = 'custom_bg_preset_url';
const TT_KEY = 'glassui_color_tt';
const TT2_KEY = 'glassui_color_tt2';
const ACCENT_KEY = 'glassui_accent';
const BG2_KEY = 'glassui_bg2';
const PWALL_KEY = 'glassui_pwall_enabled';
const PWALL_CLR_KEY = 'glassui_pwall_color';
const PWALL_EMO_KEY = 'glassui_pwall_emo_size';
const BLUR_KEY = 'glassui_blur';
const FONT_KEY = 'glassui_font';
const CARDS_UI_KEY = 'glassui_cards_ui';
const POSTER_KEY = 'glassui_poster_enabled';
const NCARD_KEY = 'glassui_ncard_tabs';
const BLUR_DEFAULT = 20;
// ===================== ОПТИМІЗАЦІЯ: читаємо всі налаштування ОДИН РАЗ =====================
// Було: 10+ окремих GM_getValue розкиданих по коду при кожному перезавантаженні
// Стало: один об'єкт CFG, решта коду читає з нього
const CFG = {
bg: GM_getValue(BG_KEY, null),
bgUrl: GM_getValue(BG_URL_KEY, null),
tt: GM_getValue(TT_KEY, null),
tt2: GM_getValue(TT2_KEY, null),
accent: GM_getValue(ACCENT_KEY, null),
bg2: GM_getValue(BG2_KEY, null),
pwall: GM_getValue(PWALL_KEY, false),
pwallClr: GM_getValue(PWALL_CLR_KEY, '#0b1030'),
pwallEmo: GM_getValue(PWALL_EMO_KEY, 30),
blur: GM_getValue(BLUR_KEY, BLUR_DEFAULT),
font: GM_getValue(FONT_KEY, ''),
cardsUi: GM_getValue(CARDS_UI_KEY, true),
poster: GM_getValue(POSTER_KEY, true),
ncardTabs: GM_getValue(NCARD_KEY, true),
};
// ===================== ДОПОМІЖНА ФУНКЦІЯ =====================
// Замість дублювання "get or create style element" скрізь
function getOrCreateStyle(id) {
let s = document.getElementById(id);
if (!s) { s = document.createElement('style'); s.id = id; document.head.appendChild(s); }
return s;
}
// ===================== ФУНКЦІЇ ФОНУ =====================
// ОПТИМІЗАЦІЯ: замість background-attachment:fixed на .wrapper-as
// використовуємо окремий fixed div з will-change:transform.
// background-attachment:fixed не дозволяє браузеру оптимізувати скрол через GPU compositing,
// а окремий div браузер виносить в окремий шар один раз і більше не чіпає.
function getOrCreateBgDiv() {
let bg = document.getElementById('glass-bg-fixed');
if (!bg) {
bg = document.createElement('div');
bg.id = 'glass-bg-fixed';
bg.style.cssText = [
'position:fixed', 'inset:0', 'z-index:-1',
'background-size:cover', 'background-position:center center',
'background-repeat:no-repeat', 'pointer-events:none',
'will-change:transform',
].join(';');
document.body.appendChild(bg);
}
return bg;
}
// Кешуємо .wrapper-as щоб не шукати в DOM при кожній зміні фону
let _wrapperAs = null;
function getWrapperAs() {
if (!_wrapperAs) _wrapperAs = document.querySelector('.wrapper-as');
return _wrapperAs;
}
function setBackground(url) {
const bg = getOrCreateBgDiv();
if (url && (url.startsWith('data:image') || url.startsWith('http'))) {
bg.style.backgroundImage = `url('${url}')`;
} else {
bg.style.backgroundImage = 'url(../images/fon2024.webp)';
}
const el = getWrapperAs();
if (el) {
el.style.backgroundImage = 'none';
el.style.backgroundAttachment = '';
}
const earlyStyle = document.getElementById('glass-bg-early');
if (earlyStyle) {
requestAnimationFrame(() => requestAnimationFrame(() => {
earlyStyle.remove();
}));
}
}
function saveAndApplyBase64(file) {
const reader = new FileReader();
reader.onload = function(e) {
const b64 = e.target.result;
setBackground(b64);
GM_setValue(BG_KEY, b64);
GM_setValue(BG_URL_KEY, null);
CFG.bg = b64; CFG.bgUrl = null;
// Синхронізуємо кеш: зберігаємо маркер (не сам base64 — він занадто важкий для LS)
localStorage.setItem('glass_bg_b64', '1');
localStorage.removeItem('glass_bg_url');
};
reader.readAsDataURL(file);
}
function saveAndApplyUrl(url) {
setBackground(url);
GM_setValue(BG_URL_KEY, url);
GM_setValue(BG_KEY, null);
CFG.bgUrl = url; CFG.bg = null;
// Синхронізуємо кеш: URL легкий — зберігаємо повністю
localStorage.setItem('glass_bg_url', url);
localStorage.removeItem('glass_bg_b64');
}
function resetBackground() {
setBackground(null);
GM_setValue(BG_KEY, null);
GM_setValue(BG_URL_KEY, null);
CFG.bg = null; CFG.bgUrl = null;
// Очищаємо кеш
localStorage.removeItem('glass_bg_url');
localStorage.removeItem('glass_bg_b64');
}
function initBackground() {
if (CFG.bg) setBackground(CFG.bg);
else if (CFG.bgUrl) setBackground(CFG.bgUrl);
else setBackground(null);
}
// ===================== КОЛЬОРИ І СТИЛІ =====================
function hexDarken(hex, factor) {
const r = Math.max(0, Math.round(parseInt(hex.slice(1,3),16) * factor));
const g = Math.max(0, Math.round(parseInt(hex.slice(3,5),16) * factor));
const b = Math.max(0, Math.round(parseInt(hex.slice(5,7),16) * factor));
return '#' + [r,g,b].map(v => v.toString(16).padStart(2,'0')).join('');
}
function applyAccent(hex) {
const darker = hexDarken(hex, 0.75);
getOrCreateStyle('glassui-accent-style').textContent =
`body, body.dt-is-active, body.dle_theme_dark { --accent: ${hex} !important; --accent-darker: ${darker} !important; }`;
}
function applyBg2(hex) {
getOrCreateStyle('glassui-bg2-style').textContent =
`body, body.dt-is-active, body.dle_theme_dark { --bg-2: ${hex} !important; }`;
}
function applyPwall(enabled, color) {
const s = getOrCreateStyle('glassui-pwall-style');
if (!enabled) { s.textContent = ''; return; }
const clr = color || '#0b1030';
const r = parseInt(clr.slice(1,3),16), g = parseInt(clr.slice(3,5),16), b = parseInt(clr.slice(5,7),16);
const rD = Math.max(0,r-10), gD = Math.max(0,g-10), bD = Math.max(0,b-10);
s.textContent = `
.pwall {
--bg0: rgb(${r}, ${g}, ${b}) !important;
--bg1: rgb(${rD}, ${gD}, ${bD}) !important;
background: linear-gradient(135deg, rgba(${r+20}, ${g+20}, ${b+30}, 0.98) 0%, rgba(${r}, ${g}, ${b}, 0.95) 60%, rgba(${rD}, ${gD}, ${bD}, 0.98) 100%) !important;
}
.pwall__write { background: rgba(${rD}, ${gD}, ${bD}, 0.5) !important; }
.pwall__textarea { background: rgba(${r}, ${g}, ${b}, 0.65) !important; }
.pwall__pager { background: rgba(${r}, ${g}, ${b}, 0.35) !important; }
.pwall__smiles-modal { background: rgba(${rD}, ${gD}, ${bD}, 0.97) !important; }
.pwall__nav, .pwall__report, .pwall__delete, .pwall__emo, .pwall__cards {
background: rgba(${r}, ${g}, ${b}, 0.55) !important;
}
.pwall__page.is-active {
background: rgba(${Math.min(255,r+40)}, ${Math.min(255,g+40)}, ${Math.min(255,b+60)}, 0.25) !important;
}`;
}
function applyPwallEmoSize(px) {
getOrCreateStyle('glassui-pwall-emo-style').textContent =
`.pwall__smile { width: ${px}px !important; height: ${px}px !important; vertical-align: -${Math.round((px-16)/2)}px !important; }`;
}
function applyBlur(px) {
getOrCreateStyle('glassui-blur-style').textContent =
`:root { --glass-blur: ${px}px !important; }
#glass-settings-panel { backdrop-filter: blur(20px) !important; -webkit-backdrop-filter: blur(20px) !important; }`;
}
function applyTextColors() {
if (CFG.tt) {
getOrCreateStyle('glassui-tt-style').textContent = `body { --tt: ${CFG.tt} !important; }`;
}
if (CFG.tt2) {
getOrCreateStyle('glassui-tt2-style').textContent = `body { --tt-2: ${CFG.tt2} !important; }`;
}
}
// ===================== ІНІЦІАЛІЗАЦІЯ (без дублювань) =====================
// Було: initBackground() + setTimeout(initBackground, 800)
// initDesignColors() + setTimeout(initDesignColors, 800)
// initBlur() + setTimeout(initBlur, 800)
// Стало: один виклик кожного + один запасний setTimeout(300ms) для обох
initBackground();
applyBlur(CFG.blur);
applyTextColors();
if (CFG.accent) applyAccent(CFG.accent);
if (CFG.bg2) applyBg2(CFG.bg2);
if (CFG.pwall) applyPwall(true, CFG.pwallClr);
if (CFG.pwallEmo !== 30) applyPwallEmoSize(CFG.pwallEmo);
setTimeout(() => {
initBackground();
applyBlur(CFG.blur);
}, 300);
// ===================== СИСТЕМА ШРИФТІВ =====================
const FONTS = [
{ name: 'Стандартный сайта', value: '', url: '' },
{ name: 'Inter', value: 'Inter', url: 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap' },
{ name: 'Nunito', value: 'Nunito', url: 'https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;500;600;700&display=swap' },
{ name: 'Outfit', value: 'Outfit', url: 'https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap' },
{ name: 'Rubik', value: 'Rubik', url: 'https://fonts.googleapis.com/css2?family=Rubik:wght@300;400;500;600;700&display=swap' },
{ name: 'Exo 2', value: 'Exo 2', url: 'https://fonts.googleapis.com/css2?family=Exo+2:wght@300;400;500;600;700&display=swap' },
{ name: 'Raleway', value: 'Raleway', url: 'https://fonts.googleapis.com/css2?family=Raleway:wght@300;400;500;600;700&display=swap' },
{ name: 'Montserrat', value: 'Montserrat', url: 'https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap' },
{ name: 'Comfortaa', value: 'Comfortaa', url: 'https://fonts.googleapis.com/css2?family=Comfortaa:wght@300;400;500;600;700&display=swap' },
{ name: 'Poppins', value: 'Poppins', url: 'https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap' },
{ name: 'Ubuntu', value: 'Ubuntu', url: 'https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;500;700&display=swap' },
{ name: 'Fira Sans', value: 'Fira Sans', url: 'https://fonts.googleapis.com/css2?family=Fira+Sans:wght@300;400;500;600;700&display=swap' },
];
function applyFont(fontValue) {
const oldLink = document.getElementById('glassui-font-link');
if (oldLink) oldLink.remove();
const oldStyle = document.getElementById('glassui-font-style');
if (oldStyle) oldStyle.remove();
if (!fontValue) return;
const font = FONTS.find(f => f.value === fontValue);
if (!font) return;
// Preconnect до Google Fonts — тільки якщо шрифт вибраний, один раз
if (!document.getElementById('glassui-font-preconnect')) {
const pc1 = document.createElement('link');
pc1.id = 'glassui-font-preconnect';
pc1.rel = 'preconnect'; pc1.href = 'https://fonts.googleapis.com';
const pc2 = document.createElement('link');
pc2.rel = 'preconnect'; pc2.href = 'https://fonts.gstatic.com'; pc2.crossOrigin = '';
document.head.appendChild(pc1);
document.head.appendChild(pc2);
}
const link = document.createElement('link');
link.id = 'glassui-font-link';
link.rel = 'stylesheet';
// Завантажуємо асинхронно через media=print — не блокує рендер
link.href = font.url;
link.media = 'print';
link.onload = function() { this.media = 'all'; };
document.head.appendChild(link);
const style = document.createElement('style');
style.id = 'glassui-font-style';
style.textContent = `body { font-family: '${fontValue}', sans-serif !important; }`;
document.head.appendChild(style);
}
if (CFG.font) applyFont(CFG.font);
// ===================== ПАНЕЛЬ НАЛАШТУВАНЬ =====================
// ===================== СТИЛІЗАЦІЯ ПАНЕЛІ ФІЛЬТРІВ =====================
function buildGlassFilterPanel() {
const popup = document.querySelector('.popup[data-type=side]');
if (!popup || popup.dataset.glassBuilt) return;
popup.dataset.glassBuilt = '1';
// ── CSS ──────────────────────────────────────────────────────────────
if (!document.getElementById('glass-filter-style')) {
const s = document.createElement('style');
s.id = 'glass-filter-style';
s.textContent = `
/* Panel */
.popup[data-type=side] .popup__content._disable-scroll {
background: rgba(10,10,20,0.93) !important;
backdrop-filter: blur(24px) !important;
-webkit-backdrop-filter: blur(24px) !important;
border-left: 1px solid rgba(255,255,255,0.08) !important;
box-shadow: -8px 0 40px rgba(0,0,0,0.6) !important;
}
.popup-overlay { background: rgba(0,0,0,0.65) !important; }
.catalog-filter.paper {
background: transparent !important;
border-radius: 0 !important;
box-shadow: none !important;
}
/* Header */
.filter-header {
background: rgba(255,255,255,0.025) !important;
border-bottom: 1px solid rgba(255,255,255,0.07) !important;
height: 48px !important; padding: 0 16px !important;
}
.filter-title { color:var(--tt)!important; font-size:15px!important; font-weight:600!important; }
.sover-filtr {
background: rgba(255,255,255,0.02)!important;
color: rgba(255,255,255,0.35)!important;
font-size:11px!important;
border-bottom:1px solid rgba(255,255,255,0.05)!important;
padding:8px 16px!important; margin:0!important;
}
/* Жанри/Теми */
.sk_sl {
background:rgba(255,255,255,0.04)!important;
border:1px solid rgba(255,255,255,0.08)!important;
border-radius:10px!important;
margin:4px 12px!important; padding:11px 14px!important;
transition:background 0.15s!important;
}
.sk_sl:hover { background:rgba(255,255,255,0.08)!important; }
.sk_gc { color:var(--tt)!important; font-size:14px!important; font-weight:500!important; }
.sk_ga { color:rgba(255,255,255,0.4)!important; }
/* Sections */
.sb_ii { padding:12px 14px!important; border-bottom:1px solid rgba(255,255,255,0.05)!important; }
.sb_ci {
color:rgba(255,255,255,0.35)!important; font-size:10px!important; font-weight:700!important;
text-transform:uppercase!important; letter-spacing:0.9px!important;
margin-bottom:10px!important; display:flex!important; align-items:center!important; gap:8px!important;
}
.sb_ci::before {
content:''; display:inline-block; width:3px; height:12px;
background:var(--accent); border-radius:2px; opacity:0.7;
}
/* Inputs */
.catalog-filter .form-input__field {
background:rgba(255,255,255,0.06)!important;
border:1px solid rgba(255,255,255,0.1)!important;
border-radius:8px!important; color:var(--tt)!important; font-size:13px!important;
}
.catalog-filter .form-input__field:focus {
border-color:var(--accent)!important; outline:none!important;
background:rgba(255,255,255,0.09)!important;
}
.catalog-filter .sc_se span { color:rgba(255,255,255,0.4)!important; }
/* HIDE original checkboxes — we render toggle sliders */
.catalog-filter .r8_r9 { display:none!important; }
/* Footer */
.catalog-filter .filter-footer {
background:rgba(0,0,0,0.35)!important;
border-top:1px solid rgba(255,255,255,0.07)!important;
padding:12px 16px!important; gap:10px!important;
}
.catalog-filter .btn.is-plain.is-outline {
background:rgba(255,255,255,0.05)!important;
border:1px solid rgba(255,255,255,0.18)!important;
border-radius:10px!important; color:var(--tt)!important;
font-weight:600!important; height:40px!important;
}
.catalog-filter .btn.is-plain.is-outline:hover { background:rgba(255,255,255,0.1)!important; }
.catalog-filter .btn.is-filled.variant-primary {
background:var(--accent)!important; border:none!important;
border-radius:10px!important; color:#fff!important; font-weight:700!important;
height:40px!important; text-transform:uppercase!important; letter-spacing:0.5px!important;
box-shadow:0 4px 16px rgba(142,46,175,0.4)!important;
}
.catalog-filter .btn.is-filled.variant-primary:hover { opacity:0.9!important; }
.catalog-filter .btn.is-icon.is-outline.variant-light {
background:rgba(255,255,255,0.05)!important;
border:1px solid rgba(255,255,255,0.18)!important;
border-radius:10px!important; color:var(--tt)!important;
height:40px!important; width:40px!important;
}
.catalog-filter .filter-layout .filter-footer .btn {
background:var(--accent)!important; border:none!important;
border-radius:10px!important; color:#fff!important;
font-weight:700!important; height:40px!important;
text-transform:uppercase!important;
}
.catalog-filter .btn.is-link { color:var(--accent)!important; font-weight:600!important; }
.filter-content::-webkit-scrollbar { width:3px!important; }
.filter-content::-webkit-scrollbar-thumb { background:rgba(255,255,255,0.15)!important; border-radius:3px!important; }
/* Toggle grid */
.gf-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 5px;
margin-top: 2px;
}
.gf-grid.gf-single { grid-template-columns: 1fr; }
/* Toggle item */
.gf-item {
display: flex; align-items: center; justify-content: space-between;
background: rgba(255,255,255,0.04);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 8px;
padding: 7px 10px;
cursor: pointer;
transition: background 0.15s, border-color 0.2s;
user-select: none;
min-width: 0;
gap: 6px;
}
.gf-item:hover { background: rgba(255,255,255,0.07); }
.gf-item.state-yes {
background: rgba(60,206,123,0.12);
border-color: rgba(60,206,123,0.45);
}
.gf-item.state-no {
background: rgba(244,67,54,0.12);
border-color: rgba(244,67,54,0.45);
}
.gf-label {
font-size: 12px; color: var(--tt);
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
flex: 1; min-width: 0;
}
/* 3-way toggle switch */
.gf-toggle {
flex-shrink: 0;
position: relative;
width: 44px; height: 22px;
border-radius: 11px;
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.12);
transition: background 0.2s, border-color 0.2s;
overflow: hidden;
}
.gf-toggle-knob {
position: absolute;
top: 2px;
width: 16px; height: 16px;
border-radius: 50%;
background: rgba(255,255,255,0.5);
transition: left 0.2s cubic-bezier(.4,0,.2,1), background 0.2s;
left: 13px; /* center = neutral */
}
.gf-item.state-yes .gf-toggle {
background: rgba(60,206,123,0.3);
border-color: rgba(60,206,123,0.6);
}
.gf-item.state-yes .gf-toggle-knob {
background: #3CCE7B;
left: 24px; /* right */
}
.gf-item.state-no .gf-toggle {
background: rgba(244,67,54,0.3);
border-color: rgba(244,67,54,0.6);
}
.gf-item.state-no .gf-toggle-knob {
background: #F44336;
left: 2px; /* left */
}
`;
document.head.appendChild(s);
}
// ── BUILD TOGGLE GRIDS ───────────────────────────────────────────────
const obs = new MutationObserver((() => {
let _tRaf = null;
return () => { if (_tRaf) return; _tRaf = requestAnimationFrame(() => { _tRaf = null; buildToggleGrids(); }); };
})());
obs.observe(popup, { attributes: true, attributeFilter: ['class'], childList: true, subtree: true });
buildToggleGrids();
// ── Hook into reset button ────────────────────────────────────────────
document.addEventListener('click', e => {
if (e.target.id === 'reset_filter' || e.target.closest('#reset_filter')) {
setTimeout(() => {
document.querySelectorAll('.gf-item').forEach(el => {
el.classList.remove('state-yes','state-no');
});
}, 50);
}
});
}
// Map: controlEl -> current state ('', 'include', 'exclude')
const _gfStateMap = new WeakMap();
function buildToggleGrids() {
document.querySelectorAll('.catalog-filter .r8_r9').forEach(grid => {
// Skip if already has a sibling toggle grid
if (grid.nextElementSibling && grid.nextElementSibling.classList.contains('gf-grid')) return;
const controls = Array.from(grid.querySelectorAll('.control'));
if (!controls.length) return;
// Determine if single column (sort section — radio, or big list)
const isSingle = controls.length <= 3;
const wrapper = document.createElement('div');
wrapper.className = 'gf-grid' + (isSingle ? ' gf-single' : '');
controls.forEach(ctrl => {
const input = ctrl.querySelector('input');
const label = ctrl.querySelector('.control__text span') || ctrl.querySelector('.control__text');
if (!input || !label) return;
const item = document.createElement('div');
item.className = 'gf-item';
item.title = label.textContent.trim();
const labelEl = document.createElement('span');
labelEl.className = 'gf-label';
labelEl.textContent = label.textContent.trim();
const toggle = document.createElement('div');
toggle.className = 'gf-toggle';
const knob = document.createElement('div');
knob.className = 'gf-toggle-knob';
toggle.appendChild(knob);
item.appendChild(labelEl);
item.appendChild(toggle);
wrapper.appendChild(item);
// Restore state from control's data-indeterminate
const curState = ctrl.dataset.indeterminate || 'disabled';
if (curState === 'include') item.classList.add('state-yes');
else if (curState === 'exclude') item.classList.add('state-no');
// Helper: get current state index -1=no 0=neutral 1=yes
function getState() {
if (item.classList.contains('state-yes')) return 1;
if (item.classList.contains('state-no')) return -1;
return 0;
}
// Helper: apply state and sync original control
function applyState(target) {
const cur = getState();
if (target === cur) return;
const steps = ((target - cur) + 3) % 3; // how many clicks needed
item.classList.remove('state-yes','state-no');
if (target === 1) item.classList.add('state-yes');
if (target === -1) item.classList.add('state-no');
for (let i = 0; i < steps; i++) ctrl.click();
}
// ── Drag / Swipe ─────────────────────────────────────────
let dragStartX = null;
let dragStartState = 0;
let dragged = false;
const DRAG_THRESHOLD = 8; // px before считается drag
function onDragStart(clientX) {
dragStartX = clientX;
dragStartState = getState();
dragged = false;
knob.style.transition = 'none';
}
function onDragMove(clientX) {
if (dragStartX === null) return;
const dx = clientX - dragStartX;
if (Math.abs(dx) > DRAG_THRESHOLD) dragged = true;
if (!dragged) return;
// Live knob position feedback
const toggleW = toggle.offsetWidth || 44;
const knobW = knob.offsetWidth || 16;
const minL = 2, maxL = toggleW - knobW - 2;
const midL = (minL + maxL) / 2;
// base position from dragStartState
const baseL = dragStartState === 1 ? maxL : dragStartState === -1 ? minL : midL;
const newL = Math.max(minL, Math.min(maxL, baseL + dx));
knob.style.left = newL + 'px';
// Preview color
const ratio = (newL - minL) / (maxL - minL); // 0..1
if (ratio > 0.66) {
toggle.style.background = 'rgba(60,206,123,0.3)';
toggle.style.borderColor = 'rgba(60,206,123,0.6)';
knob.style.background = '#3CCE7B';
} else if (ratio < 0.33) {
toggle.style.background = 'rgba(244,67,54,0.3)';
toggle.style.borderColor = 'rgba(244,67,54,0.6)';
knob.style.background = '#F44336';
} else {
toggle.style.background = '';
toggle.style.borderColor = '';
knob.style.background = 'rgba(255,255,255,0.5)';
}
}
function onDragEnd(clientX) {
if (dragStartX === null) return;
knob.style.transition = '';
knob.style.left = '';
toggle.style.background = '';
toggle.style.borderColor = '';
knob.style.background = '';
if (dragged) {
const dx = clientX - dragStartX;
const toggleW = toggle.offsetWidth || 44;
// Decide target by dx relative to toggle width
if (dx > toggleW * 0.25) applyState(1); // свайп вправо → так
else if (dx < -toggleW * 0.25) applyState(-1); // свайп вліво → ні
else applyState(0); // мало рухнув → нейтрал
} else {
// Tap: cycle neutral→yes→no→neutral
const cur = getState();
applyState(cur === 0 ? 1 : cur === 1 ? -1 : 0);
}
dragStartX = null;
}
// Mouse events
item.addEventListener('mousedown', e => { e.preventDefault(); onDragStart(e.clientX); });
window.addEventListener('mousemove', e => onDragMove(e.clientX));
window.addEventListener('mouseup', e => { if (dragStartX !== null) onDragEnd(e.clientX); });
// Touch events
item.addEventListener('touchstart', e => { onDragStart(e.touches[0].clientX); }, { passive: true });
item.addEventListener('touchmove', e => { onDragMove(e.touches[0].clientX); }, { passive: true });
item.addEventListener('touchend', e => { onDragEnd(e.changedTouches[0].clientX); });
});
// Insert after the hidden grid
grid.parentNode.insertBefore(wrapper, grid.nextSibling);
});
}
function applyFix() {
const menus = document.querySelector('div.menus');
if (menus) menus.style.setProperty('display', 'none', 'important');
// Ховаємо "ПО ГОДАМ" і "ЖАНРЫ" з бокового меню
document.querySelectorAll('.side-block_content.side-block_menu li, .side-block__menu li').forEach(li => {
const a = li.querySelector('a');
if (!a) return;
});
buildGlassFilterPanel();
// Кнопка ФІЛЬТР в .sect__header праворуч
if (!document.getElementById('glass-filter-btn')) {
const sectHeader = document.querySelector('.sect__header');
const origFilter = document.querySelector('li.sect__btn-filter');
if (sectHeader && origFilter) {
const btn = document.createElement('button');
btn.id = 'glass-filter-btn';
btn.innerHTML = `<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="4" y1="6" x2="20" y2="6"/><line x1="8" y1="12" x2="16" y2="12"/><line x1="11" y1="18" x2="13" y2="18"/></svg> Фильтры`;
sectHeader.appendChild(btn);
btn.addEventListener('click', () => origFilter.click());
}
}
if (!document.getElementById('glass-settings-btn')) {
const themeBtn = document.querySelector('.header__theme');
if (!themeBtn) return;
const btn = document.createElement('div');
btn.id = 'glass-settings-btn';
btn.innerHTML = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>`;
btn.style.cssText = `
display: flex; align-items: center; justify-content: center;
width: 40px; height: 40px; cursor: pointer;
color: rgba(255,255,255,0.75);
border-radius: 50%;
transition: background 0.2s, color 0.2s;
position: relative;
background-color: var(--bg-btn-dark);
`;
btn.addEventListener('mouseenter', () => btn.style.color = '#fff');
btn.addEventListener('mouseleave', () => btn.style.color = 'rgba(255,255,255,0.75)');
themeBtn.parentElement.insertBefore(btn, themeBtn);
themeBtn.style.setProperty('display', 'none', 'important');
const panel = document.createElement('div');
panel.id = 'glass-settings-panel';
panel.style.cssText = `
display: none; position: fixed; top: 70px; left: 0;
width: 520px; z-index: 2147483647;
background: rgba(10, 10, 20, 0.90);
backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
max-height: calc(100vh - 90px); overflow-y: auto;
border: 1px solid rgba(255,255,255,0.10);
border-radius: 12px; padding: 16px;
box-shadow: 0 8px 32px rgba(0,0,0,0.5);
color: rgba(255,255,255,0.85); font-size: 13px;
`;
panel.innerHTML = `
<!-- HEADER -->
<div style="font-weight:700; font-size:15px; margin-bottom:12px; color:#fff; border-bottom:1px solid rgba(255,255,255,0.1); padding-bottom:10px; display:flex; align-items:center; gap:8px;">
⚙️ Glass UI — Настройки
</div>
<!-- ТЕМА + ШРИФТ — повна ширина -->
<div id="glassui-toprow" style="display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-bottom:12px;">
<div>
<div style="font-size:11px; font-weight:600; color:rgba(255,255,255,0.45); text-transform:uppercase; letter-spacing:1px; margin-bottom:6px;">🌓 Тема</div>
<div style="display:flex; gap:6px;">
<button id="glassui-theme-light" style="flex:1; padding:8px 4px; background:rgba(255,220,80,0.15); color:#ffd84f; border:1px solid rgba(255,220,80,0.25); border-radius:8px; cursor:pointer; font-size:12px; font-weight:700;">☀️ День</button>
<button id="glassui-theme-dark" style="flex:1; padding:8px 4px; background:rgba(100,120,255,0.15); color:#9ab4ff; border:1px solid rgba(100,120,255,0.25); border-radius:8px; cursor:pointer; font-size:12px; font-weight:700;">🌙 Ночь</button>
</div>
</div>
<div>
<div style="font-size:11px; font-weight:600; color:rgba(255,255,255,0.45); text-transform:uppercase; letter-spacing:1px; margin-bottom:6px;">🔤 Шрифт</div>
<div style="position:relative;">
<div id="glassui-font-current" style="
width:100%; padding:8px 30px 8px 10px; box-sizing:border-box;
background:rgba(255,255,255,0.07); border:1px solid rgba(255,255,255,0.12);
border-radius:8px; color:#fff; font-size:12px; cursor:pointer;
display:flex; align-items:center; justify-content:space-between;
transition: border-color 0.2s, background 0.2s; user-select:none;">
<span id="glassui-font-label" style="overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">Стандартный</span>
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" style="opacity:0.5; flex-shrink:0; transition:transform 0.2s;" id="glassui-font-arrow"><polyline points="6 9 12 15 18 9"/></svg>
</div>
<div id="glassui-font-dropdown" style="
display:none; position:absolute; left:0; right:0; top:calc(100% + 4px);
background:rgba(12,12,24,0.97); border:1px solid rgba(255,255,255,0.12);
border-radius:10px; z-index:99999; overflow:hidden;
box-shadow: 0 8px 32px rgba(0,0,0,0.6); max-height:200px; overflow-y:auto;">
</div>
</div>
</div>
</div>
<div style="border-top:1px solid rgba(255,255,255,0.08); margin:0 0 12px;"></div>
<!-- ── ДИЗАЙН ПАНЕЛЕЙ ── -->
<div style="background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.08); border-radius:8px; padding:10px; margin-bottom:12px;">
<div style="display:grid; grid-template-columns:1fr 1fr; gap:8px;">
<!-- Дизайн панелей -->
<div style="display:flex; align-items:center; justify-content:space-between; gap:8px; background:rgba(255,255,255,0.04); border-radius:6px; padding:8px 10px;">
<div>
<div style="font-size:11px; color:rgba(255,255,255,0.85); font-weight:600;">Дизайн панелей</div>
<div style="font-size:10px; color:rgba(255,255,255,0.35); margin-top:1px;">Ранги, замочки, звёзды</div>
</div>
<label id="glassui-cards-toggle-label" style="position:relative; display:inline-block; width:38px; height:22px; cursor:pointer; flex-shrink:0;">
<input type="checkbox" id="glassui-cards-toggle" style="opacity:0; width:0; height:0; position:absolute;">
<span id="glassui-cards-track" style="position:absolute; inset:0; border-radius:11px; background:rgba(255,255,255,0.15); transition:background 0.2s;">
<span id="glassui-cards-thumb" style="position:absolute; top:3px; left:3px; width:16px; height:16px; border-radius:50%; background:#fff; transition:transform 0.2s; box-shadow:0 1px 3px rgba(0,0,0,0.4);"></span>
</span>
</label>
</div>
<!-- Фон профиля -->
<div style="display:flex; align-items:center; justify-content:space-between; gap:8px; background:rgba(255,255,255,0.04); border-radius:6px; padding:8px 10px;">
<div>
<div style="font-size:11px; color:rgba(255,255,255,0.85); font-weight:600;">Фон профиля</div>
<div style="font-size:10px; color:rgba(255,255,255,0.35); margin-top:1px;">Видео / картинка</div>
</div>
<label id="glassui-poster-toggle-label" style="position:relative; display:inline-block; width:38px; height:22px; cursor:pointer; flex-shrink:0;">
<input type="checkbox" id="glassui-poster-toggle" style="opacity:0; width:0; height:0; position:absolute;">
<span id="glassui-poster-track" style="position:absolute; inset:0; border-radius:11px; background:rgba(255,255,255,0.15); transition:background 0.2s;">
<span id="glassui-poster-thumb" style="position:absolute; top:3px; left:3px; width:16px; height:16px; border-radius:50%; background:#fff; transition:transform 0.2s; box-shadow:0 1px 3px rgba(0,0,0,0.4);"></span>
</span>
</label>
</div>
<!-- Навигация карточек -->
<div style="display:flex; align-items:center; justify-content:space-between; gap:8px; background:rgba(255,255,255,0.04); border-radius:6px; padding:8px 10px; grid-column:1/-1;">
<div>
<div style="font-size:11px; color:rgba(255,255,255,0.85); font-weight:600;">Дизнайн кнопок навигации</div>
<div style="font-size:10px; color:rgba(255,255,255,0.35); margin-top:1px;">Прогресс колод, колоды, блок/разблк и др.</div>
</div>
<label id="glassui-ncard-toggle-label" style="position:relative; display:inline-block; width:38px; height:22px; cursor:pointer; flex-shrink:0;">
<input type="checkbox" id="glassui-ncard-toggle" style="opacity:0; width:0; height:0; position:absolute;">
<span id="glassui-ncard-track" style="position:absolute; inset:0; border-radius:11px; background:rgba(255,255,255,0.15); transition:background 0.2s;">
<span id="glassui-ncard-thumb" style="position:absolute; top:3px; left:3px; width:16px; height:16px; border-radius:50%; background:#fff; transition:transform 0.2s; box-shadow:0 1px 3px rgba(0,0,0,0.4);"></span>
</span>
</label>
</div>
</div>
</div>
<div style="border-top:1px solid rgba(255,255,255,0.08); margin:0 0 12px;"></div>
<!-- 2-КОЛОНКИ (десктоп) / 1-колонка (мобільний) -->
<div id="glassui-cols" style="display:grid; grid-template-columns:1fr 1fr; gap:12px; align-items:start;">
<!-- === ЛІВА КОЛОНКА: ФОН + БЛЮР === -->
<div style="display:flex; flex-direction:column; gap:8px; justify-content:space-between;">
<div>
<div style="font-size:11px; font-weight:600; color:rgba(255,255,255,0.45); text-transform:uppercase; letter-spacing:1px; margin-bottom:7px;">🖼 Фон</div>
<div style="background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.08); border-radius:8px; padding:10px; margin-bottom:5px;">
<div style="font-size:11px; margin-bottom:6px; color:rgba(255,255,255,0.6);">Из файла (JPG/PNG/WEBP/GIF)</div>
<input type="file" id="glassui-file-input" accept="image/jpeg,image/png,image/webp,image/gif,.jpg,.jpeg,.png,.webp,.gif" style="display:none;">
<button id="glassui-file-btn" style="width:100%; padding:7px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">📁 Выбрать файл</button>
<div style="font-size:10px; color:rgba(255,255,255,0.3); margin-top:4px;">*Хранится в браузере</div>
</div>
<div style="background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.08); border-radius:8px; padding:10px; margin-bottom:5px;">
<div style="font-size:11px; margin-bottom:6px; color:rgba(255,255,255,0.6);">Прямая ссылка (JPG/PNG/WEBP/GIF)</div>
<div style="display:flex; gap:5px;">
<input type="text" id="glassui-url-input" placeholder="https://..." style="flex:1; padding:5px 7px; background:rgba(255,255,255,0.08); border:1px solid rgba(255,255,255,0.12); border-radius:6px; color:#fff; font-size:11px; outline:none; min-width:0;">
<button id="glassui-url-btn" style="padding:5px 8px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700; white-space:nowrap;">OK</button>
</div>
</div>
<button id="glassui-reset-btn" style="width:100%; padding:7px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:600;">
↺ Сбросить фон
</button>
</div>
<div style="border-top:1px solid rgba(255,255,255,0.08);"></div>
<div>
<div style="font-size:11px; font-weight:600; color:rgba(255,255,255,0.45); text-transform:uppercase; letter-spacing:1px; margin-bottom:7px;">💧 Блюр</div>
<div style="background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.08); border-radius:8px; padding:10px;">
<div style="display:flex; gap:6px; align-items:center; margin-bottom:6px;">
<input type="range" id="glassui-blur-single" min="0" max="40" value="20" style="flex:1; accent-color:var(--accent);">
<span id="glassui-blur-single-val" style="font-size:11px; color:rgba(255,255,255,0.5); min-width:32px; text-align:right;">20px</span>
</div>
<div style="display:flex; gap:5px;">
<button id="glassui-blur-apply" style="flex:1; padding:6px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">Применить</button>
<button id="glassui-blur-reset" style="padding:6px 9px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">↺</button>
</div>
</div>
</div>
<!-- ═══ СЕКЦІЯ ВІКНО КОМЕНТАРІВ ═══ -->
<div>
<div style="font-size:11px; font-weight:600; color:rgba(255,255,255,0.45); text-transform:uppercase; letter-spacing:1px; margin-bottom:7px;">💬 Окно комментариев</div>
<div style="background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.08); border-radius:8px; padding:10px;">
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:8px;">
<div>
<div style="font-size:11px; color:rgba(255,255,255,0.8); font-weight:600;">Кастомный цвет</div>
<div style="font-size:10px; color:rgba(255,255,255,0.35);">вкл/выкл свой цвет фона</div>
</div>
<label id="glassui-pwall-toggle-label" style="position:relative; display:inline-block; width:38px; height:22px; cursor:pointer; flex-shrink:0;">
<input type="checkbox" id="glassui-pwall-toggle" style="opacity:0; width:0; height:0; position:absolute;">
<span id="glassui-pwall-track" style="position:absolute; inset:0; border-radius:11px; background:rgba(255,255,255,0.15); transition:background 0.2s;">
<span id="glassui-pwall-thumb" style="position:absolute; top:3px; left:3px; width:16px; height:16px; border-radius:50%; background:#fff; transition:transform 0.2s; box-shadow:0 1px 3px rgba(0,0,0,0.4);"></span>
</span>
</label>
</div>
<!-- Розмір емодзи — завжди видний -->
<div style="margin-bottom:8px;">
<div style="display:flex; justify-content:space-between; margin-bottom:4px;">
<div style="font-size:11px; color:rgba(255,255,255,0.8); font-weight:600;">Размер эмодзи</div>
<span id="glassui-pwall-emo-val" style="font-size:11px; color:rgba(255,255,255,0.5);">30px</span>
</div>
<input type="range" id="glassui-pwall-emo" min="30" max="90" value="30" style="width:100%; accent-color:var(--accent);">
</div>
<div id="glassui-pwall-color-row" style="display:none;">
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:6px;">
<div style="font-size:11px; color:rgba(255,255,255,0.8); font-weight:600;">Цвет фона</div>
<div id="glassui-pwall-swatch" style="width:30px; height:30px; border-radius:6px; cursor:pointer; border:2px solid rgba(255,255,255,0.2); background:#0b1030; flex-shrink:0;"></div>
</div>
<div id="glassui-slot-pwall"></div>
<div style="display:flex; gap:5px;">
<button id="glassui-pwall-apply" style="flex:1; padding:6px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">Применить</button>
<button id="glassui-pwall-reset" style="padding:6px 9px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">↺</button>
</div>
</div>
</div>
</div>
</div>
<!-- === ПРАВА КОЛОНКА: КОЛІР ТЕКСТУ === -->
<div style="display:flex; flex-direction:column; gap:8px;">
<div>
<div style="font-size:11px; font-weight:600; color:rgba(255,255,255,0.45); text-transform:uppercase; letter-spacing:1px; margin-bottom:7px;">🎨 Цвет текста</div>
<div style="background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.08); border-radius:8px; padding:10px; margin-bottom:5px;">
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:6px;">
<div style="font-size:11px; color:rgba(255,255,255,0.8); font-weight:600;">Основной</div>
<div id="glassui-tt-swatch" style="width:30px; height:30px; border-radius:6px; cursor:pointer; border:2px solid rgba(255,255,255,0.2); background:#c4c4c4; flex-shrink:0;"></div>
</div>
<div style="display:flex; gap:5px; align-items:center; margin-bottom:8px;">
<input type="range" id="glassui-tt-opacity" min="0" max="100" value="77" style="flex:1; accent-color:var(--accent);">
<span id="glassui-tt-opacity-val" style="font-size:11px; color:rgba(255,255,255,0.5); min-width:28px; text-align:right;">77%</span>
</div>
<div id="glassui-slot-tt"></div>
<div style="display:flex; gap:5px;">
<button id="glassui-tt-apply" style="flex:1; padding:6px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">Применить</button>
<button id="glassui-tt-reset" style="padding:6px 9px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">↺</button>
</div>
</div>
<div style="background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.08); border-radius:8px; padding:10px;">
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:6px;">
<div style="font-size:11px; color:rgba(255,255,255,0.8); font-weight:600;">Второстепенный</div>
<div id="glassui-tt2-swatch" style="width:30px; height:30px; border-radius:6px; cursor:pointer; border:2px solid rgba(255,255,255,0.2); background:#a6a6a6; flex-shrink:0;"></div>
</div>
<div style="display:flex; gap:5px; align-items:center; margin-bottom:8px;">
<input type="range" id="glassui-tt2-opacity" min="0" max="100" value="100" style="flex:1; accent-color:var(--accent);">
<span id="glassui-tt2-opacity-val" style="font-size:11px; color:rgba(255,255,255,0.5); min-width:28px; text-align:right;">100%</span>
</div>
<div id="glassui-slot-tt2"></div>
<div style="display:flex; gap:5px;">
<button id="glassui-tt2-apply" style="flex:1; padding:6px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">Применить</button>
<button id="glassui-tt2-reset" style="padding:6px 9px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">↺</button>
</div>
</div>
</div>
<div style="border-top:1px solid rgba(255,255,255,0.08);"></div>
<div>
<div style="font-size:11px; font-weight:600; color:rgba(255,255,255,0.45); text-transform:uppercase; letter-spacing:1px; margin-bottom:7px;">🖌 Цвета дизайна</div>
<div style="background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.08); border-radius:8px; padding:10px; margin-bottom:5px;">
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:8px;">
<div>
<div style="font-size:11px; color:rgba(255,255,255,0.8); font-weight:600;">Акцентный</div>
<div style="font-size:10px; color:rgba(255,255,255,0.35);">кнопки, рамки, подсветка</div>
</div>
<div id="glassui-accent-swatch" style="width:30px; height:30px; border-radius:6px; cursor:pointer; border:2px solid rgba(255,255,255,0.2); background:#b5003c; flex-shrink:0;"></div>
</div>
<div id="glassui-slot-accent"></div>
<div style="display:flex; gap:5px;">
<button id="glassui-accent-apply" style="flex:1; padding:6px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">Применить</button>
<button id="glassui-accent-reset" style="padding:6px 9px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">↺</button>
</div>
</div>
<div style="background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.08); border-radius:8px; padding:10px;">
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:8px;">
<div>
<div style="font-size:11px; color:rgba(255,255,255,0.8); font-weight:600;">Фон элементов</div>
<div style="font-size:10px; color:rgba(255,255,255,0.35);">Элементы сайта</div>
</div>
<div id="glassui-bg2-swatch" style="width:30px; height:30px; border-radius:6px; cursor:pointer; border:2px solid rgba(255,255,255,0.2); background:#1b1b1b; flex-shrink:0;"></div>
</div>
<div id="glassui-slot-bg2"></div>
<div style="display:flex; gap:5px;">
<button id="glassui-bg2-apply" style="flex:1; padding:6px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">Применить</button>
<button id="glassui-bg2-reset" style="padding:6px 9px; background:var(--accent); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:11px; font-weight:700;">↺</button>
</div>
</div>
</div>
</div>
</div>
<!-- ═══ КАСТОМНИЙ ПІККЕР (вбудований) ═══ -->
<div id="glassui-cpanel" style="display:none; margin:8px 0 6px; background:rgba(0,0,0,0.25); border:1px solid rgba(255,255,255,0.1); border-radius:8px; padding:10px;">
<div style="display:flex; align-items:center; gap:10px; margin-bottom:10px;">
<div id="glassui-cp-preview" style="width:32px; height:32px; border-radius:7px; border:2px solid rgba(255,255,255,0.2); flex-shrink:0;"></div>
<div style="flex:1;">
<div style="font-size:10px; color:rgba(255,255,255,0.4); margin-bottom:3px;">HEX</div>
<input type="text" id="glassui-cp-hex" maxlength="7" placeholder="#ffffff"
style="width:100%; padding:5px 8px; background:rgba(255,255,255,0.07); border:1px solid rgba(255,255,255,0.12); border-radius:6px; color:#fff; font-size:12px; font-family:monospace; outline:none; box-sizing:border-box;">
</div>
</div>
<div style="margin-bottom:8px;">
<div style="display:flex; justify-content:space-between; margin-bottom:3px;">
<span style="font-size:10px; color:rgba(255,255,255,0.4);">Оттенок</span>
<span id="glassui-cp-h-val" style="font-size:10px; color:rgba(255,255,255,0.4);">0°</span>
</div>
<input type="range" id="glassui-cp-h" min="0" max="360" value="0"
style="width:100%; height:10px; border-radius:5px; outline:none; border:none; cursor:pointer; -webkit-appearance:none; appearance:none;
background:linear-gradient(to right,hsl(0,100%,50%),hsl(30,100%,50%),hsl(60,100%,50%),hsl(90,100%,50%),hsl(120,100%,50%),hsl(150,100%,50%),hsl(180,100%,50%),hsl(210,100%,50%),hsl(240,100%,50%),hsl(270,100%,50%),hsl(300,100%,50%),hsl(330,100%,50%),hsl(360,100%,50%));">
</div>
<div style="margin-bottom:8px;">
<div style="display:flex; justify-content:space-between; margin-bottom:3px;">
<span style="font-size:10px; color:rgba(255,255,255,0.4);">Насыщенность</span>
<span id="glassui-cp-s-val" style="font-size:10px; color:rgba(255,255,255,0.4);">100%</span>
</div>
<input type="range" id="glassui-cp-s" min="0" max="100" value="100"
style="width:100%; height:10px; border-radius:5px; outline:none; border:none; cursor:pointer; -webkit-appearance:none; appearance:none;">
</div>
<div>
<div style="display:flex; justify-content:space-between; margin-bottom:3px;">
<span style="font-size:10px; color:rgba(255,255,255,0.4);">Яркость</span>
<span id="glassui-cp-l-val" style="font-size:10px; color:rgba(255,255,255,0.4);">50%</span>
</div>
<input type="range" id="glassui-cp-l" min="0" max="100" value="50"
style="width:100%; height:10px; border-radius:5px; outline:none; border:none; cursor:pointer; -webkit-appearance:none; appearance:none;">
</div>
</div>
`;
// Overlay для мобільного
const overlay = document.createElement('div');
overlay.id = 'glass-settings-overlay';
overlay.style.cssText = `
display: none; position: fixed; inset: 0;
background: rgba(0,0,0,0.5); z-index: 2147483640;
backdrop-filter: blur(2px);
`;
document.body.appendChild(overlay);
document.body.appendChild(panel);
// Кнопка закриття в хедері панелі (для мобільного)
const closeBtn = document.createElement('div');
closeBtn.style.cssText = `
position: absolute; top: 14px; right: 14px;
width: 28px; height: 28px; border-radius: 50%;
background: rgba(255,255,255,0.08); cursor: pointer;
display: flex; align-items: center; justify-content: center;
color: rgba(255,255,255,0.6); font-size: 16px; line-height: 1;
transition: background 0.2s;
`;
closeBtn.innerHTML = '✕';
closeBtn.addEventListener('mouseenter', () => closeBtn.style.background = 'rgba(255,255,255,0.15)');
closeBtn.addEventListener('mouseleave', () => closeBtn.style.background = 'rgba(255,255,255,0.08)');
panel.style.position = 'fixed';
panel.appendChild(closeBtn);
panel.addEventListener('click', (e) => e.stopPropagation());
panel.addEventListener('mousedown', (e) => e.stopPropagation());
// Обробники для налаштувань фону
panel.querySelector('#glassui-file-btn').addEventListener('click', () => {
panel.querySelector('#glassui-file-input').click();
});
panel.querySelector('#glassui-file-input').addEventListener('change', (e) => {
if (e.target.files.length > 0) {
saveAndApplyBase64(e.target.files[0]);
panel.style.display = 'none';
}
});
panel.querySelector('#glassui-url-btn').addEventListener('click', () => {
const url = panel.querySelector('#glassui-url-input').value.trim();
if (url && (url.startsWith('http://') || url.startsWith('https://'))) {
saveAndApplyUrl(url);
panel.style.display = 'none';
}
});
panel.querySelector('#glassui-reset-btn').addEventListener('click', () => {
resetBackground();
panel.style.display = 'none';
});
// Заповнюємо поле URL якщо є збережений
if (CFG.bgUrl) panel.querySelector('#glassui-url-input').value = CFG.bgUrl;
// ════════════════════════════════════════════════════
// КАСТОМНИЙ ПІККЕР (вбудований, без нативного input)
// ════════════════════════════════════════════════════
function rgbaToHex(rgba) {
const m = rgba.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
if (!m) return '#888888';
return '#' + [m[1],m[2],m[3]].map(n=>parseInt(n).toString(16).padStart(2,'0')).join('');
}
function hexToHsl(hex) {
let r=parseInt(hex.slice(1,3),16)/255, g=parseInt(hex.slice(3,5),16)/255, b=parseInt(hex.slice(5,7),16)/255;
const max=Math.max(r,g,b), min=Math.min(r,g,b);
let h=0, s=0, l=(max+min)/2;
if (max!==min) {
const d=max-min;
s=l>0.5?d/(2-max-min):d/(max+min);
switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break;}
h/=6;
}
return [Math.round(h*360), Math.round(s*100), Math.round(l*100)];
}
function hslToHex(h,s,l) {
s/=100; l/=100;
const a=s*Math.min(l,1-l);
const f=n=>{const k=(n+h/30)%12;const c=l-a*Math.max(-1,Math.min(k-3,9-k,1));return Math.round(255*c).toString(16).padStart(2,'0');};
return '#'+f(0)+f(8)+f(4);
}
function updateSliderBgs(h, s, l) {
cpS.style.background = `linear-gradient(to right, hsl(${h},0%,${l}%), hsl(${h},100%,${l}%))`;
cpL.style.background = `linear-gradient(to right, hsl(${h},${s}%,0%), hsl(${h},${s}%,50%), hsl(${h},${s}%,100%))`;
}
const cpPanel = panel.querySelector('#glassui-cpanel');
const cpPreview = panel.querySelector('#glassui-cp-preview');
const cpHexInp = panel.querySelector('#glassui-cp-hex');
const cpH = panel.querySelector('#glassui-cp-h');
const cpS = panel.querySelector('#glassui-cp-s');
const cpL = panel.querySelector('#glassui-cp-l');
const cpHVal = panel.querySelector('#glassui-cp-h-val');
const cpSVal = panel.querySelector('#glassui-cp-s-val');
const cpLVal = panel.querySelector('#glassui-cp-l-val');
let cpTarget = null;
const swatches = {
tt: panel.querySelector('#glassui-tt-swatch'),
tt2: panel.querySelector('#glassui-tt2-swatch'),
accent: panel.querySelector('#glassui-accent-swatch'),
bg2: panel.querySelector('#glassui-bg2-swatch'),
pwall: panel.querySelector('#glassui-pwall-swatch'),
};
function cpGetHex() { return hslToHex(+cpH.value, +cpS.value, +cpL.value); }
// ОПТИМІЗАЦІЯ: RAF-дебаунс для color picker
// Рух слайдера більше не перераховує стилі 60+ разів на секунду, тільки раз на кадр
let _cpRaf = null;
function cpRefresh() {
if (_cpRaf) return;
_cpRaf = requestAnimationFrame(() => {
_cpRaf = null;
const hex = cpGetHex();
cpPreview.style.background = hex;
cpHexInp.value = hex;
cpHVal.textContent = cpH.value + '°';
cpSVal.textContent = cpS.value + '%';
cpLVal.textContent = cpL.value + '%';
updateSliderBgs(+cpH.value, +cpS.value, +cpL.value);
if (cpTarget && swatches[cpTarget]) swatches[cpTarget].style.background = hex;
});
}
function anyColorToHex(color) {
if (/^#[0-9a-fA-F]{6}$/.test(color)) return color;
const m = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
if (m) return '#' + [m[1],m[2],m[3]].map(v=>parseInt(v).toString(16).padStart(2,'0')).join('');
return '#888888';
}
function cpOpen(target, currentHex) {
if (cpTarget === target && cpPanel.style.display !== 'none') {
cpPanel.style.display = 'none'; cpTarget = null; return;
}
cpTarget = target;
const safe = anyColorToHex(currentHex || '#888888');
const [h,s,l] = hexToHsl(safe);
cpH.value=h; cpS.value=s; cpL.value=l;
cpRefresh();
const slot = panel.querySelector('#glassui-slot-' + target);
if (slot) {
slot.innerHTML = '';
slot.appendChild(cpPanel);
}
cpPanel.style.display = 'block';
setTimeout(()=>{ cpPanel.scrollIntoView({behavior:'smooth', block:'nearest'}); }, 50);
}
cpH.addEventListener('input', cpRefresh);
cpS.addEventListener('input', cpRefresh);
cpL.addEventListener('input', cpRefresh);
cpHexInp.addEventListener('input', () => {
const v = cpHexInp.value;
if (/^#[0-9a-fA-F]{6}$/.test(v)) {
const [h,s,l]=hexToHsl(v);
cpH.value=h; cpS.value=s; cpL.value=l; cpRefresh();
}
});
cpHexInp.addEventListener('click', e=>e.stopPropagation());
Object.entries(swatches).forEach(([key, el]) => {
if (!el) return;
el.addEventListener('click', (e) => {
e.stopPropagation();
cpOpen(key, el.style.background);
});
});
// ── Цвет текста ──────────────────────────────────────────────
const ttSwatch = swatches.tt;
const tt2Swatch = swatches.tt2;
const ttOpacity = panel.querySelector('#glassui-tt-opacity');
const ttOpacityVal = panel.querySelector('#glassui-tt-opacity-val');
const tt2Opacity = panel.querySelector('#glassui-tt2-opacity');
const tt2OpacityVal= panel.querySelector('#glassui-tt2-opacity-val');
if (CFG.tt) {
const hex=rgbaToHex(CFG.tt); ttSwatch.style.background=hex;
const mOp=CFG.tt.match(/[\d.]+\)$/);
if(mOp){const v=Math.round(parseFloat(mOp[0])*100);ttOpacity.value=v;ttOpacityVal.textContent=v+'%';}
}
if (CFG.tt2) {
const hex2=rgbaToHex(CFG.tt2); tt2Swatch.style.background=hex2;
const mOp2=CFG.tt2.match(/[\d.]+\)$/);
if(mOp2){const v2=Math.round(parseFloat(mOp2[0])*100);tt2Opacity.value=v2;tt2OpacityVal.textContent=v2+'%';}
}
ttOpacity.addEventListener('input', () => ttOpacityVal.textContent = ttOpacity.value + '%');
tt2Opacity.addEventListener('input', () => tt2OpacityVal.textContent = tt2Opacity.value + '%');
function applyTtStyle(val) {
getOrCreateStyle('glassui-tt-style').textContent = `body{--tt:${val}!important;}`;
}
function applyTt2Style(val) {
getOrCreateStyle('glassui-tt2-style').textContent = `body{--tt-2:${val}!important;}`;
}
panel.querySelector('#glassui-tt-apply').addEventListener('click', () => {
const safe = anyColorToHex(cpTarget==='tt' ? cpGetHex() : ttSwatch.style.background);
const op=(parseInt(ttOpacity.value)/100).toFixed(2);
const r=parseInt(safe.slice(1,3),16),g=parseInt(safe.slice(3,5),16),b=parseInt(safe.slice(5,7),16);
const val=`rgba(${r},${g},${b},${op})`;
applyTtStyle(val); GM_setValue(TT_KEY, val); CFG.tt=val;
});
panel.querySelector('#glassui-tt-reset').addEventListener('click', () => {
applyTtStyle('hsla(0,0%,100%,.77)'); GM_setValue(TT_KEY, null); CFG.tt=null;
ttOpacity.value=77; ttOpacityVal.textContent='77%';
ttSwatch.style.background='#c4c4c4';
if(cpTarget==='tt'){cpPanel.style.display='none';cpTarget=null;}
});
panel.querySelector('#glassui-tt2-apply').addEventListener('click', () => {
const safe = anyColorToHex(cpTarget==='tt2' ? cpGetHex() : tt2Swatch.style.background);
const op=(parseInt(tt2Opacity.value)/100).toFixed(2);
const r=parseInt(safe.slice(1,3),16),g=parseInt(safe.slice(3,5),16),b=parseInt(safe.slice(5,7),16);
const val=`rgba(${r},${g},${b},${op})`;
applyTt2Style(val); GM_setValue(TT2_KEY, val); CFG.tt2=val;
});
panel.querySelector('#glassui-tt2-reset').addEventListener('click', () => {
applyTt2Style('#a6a6a6'); GM_setValue(TT2_KEY, null); CFG.tt2=null;
tt2Swatch.style.background='#a6a6a6';
tt2Opacity.value=100; tt2OpacityVal.textContent='100%';
if(cpTarget==='tt2'){cpPanel.style.display='none';cpTarget=null;}
});
// ── Цвета дизайна ─────────────────────────────────────────────
const accentSwatch = swatches.accent;
const bg2Swatch = swatches.bg2;
if (CFG.accent) accentSwatch.style.background = CFG.accent;
if (CFG.bg2) bg2Swatch.style.background = CFG.bg2;
panel.querySelector('#glassui-accent-apply').addEventListener('click', () => {
const safe = anyColorToHex(cpTarget==='accent' ? cpGetHex() : accentSwatch.style.background);
applyAccent(safe); GM_setValue(ACCENT_KEY, safe); CFG.accent=safe;
});
panel.querySelector('#glassui-accent-reset').addEventListener('click', () => {
const s=document.getElementById('glassui-accent-style'); if(s) s.textContent='';
GM_setValue(ACCENT_KEY, null); CFG.accent=null;
accentSwatch.style.background='#b5003c';
if(cpTarget==='accent'){cpPanel.style.display='none';cpTarget=null;}
});
panel.querySelector('#glassui-bg2-apply').addEventListener('click', () => {
const safe = anyColorToHex(cpTarget==='bg2' ? cpGetHex() : bg2Swatch.style.background);
applyBg2(safe); GM_setValue(BG2_KEY, safe); CFG.bg2=safe;
});
panel.querySelector('#glassui-bg2-reset').addEventListener('click', () => {
const s=document.getElementById('glassui-bg2-style'); if(s) s.textContent='';
GM_setValue(BG2_KEY, null); CFG.bg2=null;
bg2Swatch.style.background='#1b1b1b';
if(cpTarget==='bg2'){cpPanel.style.display='none';cpTarget=null;}
});
// ── Окно комментариев (pwall) ─────────────────────────────────
const pwallToggle = panel.querySelector('#glassui-pwall-toggle');
const pwallTrack = panel.querySelector('#glassui-pwall-track');
const pwallThumb = panel.querySelector('#glassui-pwall-thumb');
const pwallColorRow = panel.querySelector('#glassui-pwall-color-row');
const pwallSwatch = panel.querySelector('#glassui-pwall-swatch');
function updatePwallToggleUI(enabled) {
pwallToggle.checked = enabled;
pwallTrack.style.background = enabled ? 'var(--accent)' : 'rgba(255,255,255,0.15)';
pwallThumb.style.transform = enabled ? 'translateX(16px)' : 'translateX(0)';
pwallColorRow.style.display = enabled ? 'block' : 'none';
}
updatePwallToggleUI(CFG.pwall);
if (pwallSwatch) pwallSwatch.style.background = CFG.pwallClr;
setTimeout(() => {
const _es = panel.querySelector('#glassui-pwall-emo');
const _ev = panel.querySelector('#glassui-pwall-emo-val');
if (_es) { _es.value = CFG.pwallEmo; _ev.textContent = CFG.pwallEmo + 'px'; }
}, 0);
pwallToggle.addEventListener('change', () => {
const enabled = pwallToggle.checked;
GM_setValue(PWALL_KEY, enabled); CFG.pwall=enabled;
updatePwallToggleUI(enabled);
applyPwall(enabled, CFG.pwallClr);
});
panel.querySelector('#glassui-pwall-apply').addEventListener('click', () => {
const safe = anyColorToHex(cpTarget === 'pwall' ? cpGetHex() : (pwallSwatch ? pwallSwatch.style.background : '#0b1030'));
GM_setValue(PWALL_CLR_KEY, safe); CFG.pwallClr=safe;
if (pwallSwatch) pwallSwatch.style.background = safe;
applyPwall(true, safe);
});
panel.querySelector('#glassui-pwall-reset').addEventListener('click', () => {
GM_setValue(PWALL_CLR_KEY, '#0b1030');
GM_setValue(PWALL_EMO_KEY, 30);
CFG.pwallClr='#0b1030'; CFG.pwallEmo=30;
if (pwallSwatch) pwallSwatch.style.background = '#0b1030';
const pwEmoEl = panel.querySelector('#glassui-pwall-emo');
const pwEmoValEl = panel.querySelector('#glassui-pwall-emo-val');
if (pwEmoEl) { pwEmoEl.value = 30; pwEmoValEl.textContent = '30px'; }
applyPwall(GM_getValue(PWALL_KEY, false), '#0b1030');
applyPwallEmoSize(30);
if (cpTarget === 'pwall') { cpPanel.style.display = 'none'; cpTarget = null; }
});
// ── Pwall emoji size slider ───────────────────────────────────────
const pwEmoSlider = panel.querySelector('#glassui-pwall-emo');
const pwEmoVal = panel.querySelector('#glassui-pwall-emo-val');
if (pwEmoSlider) {
pwEmoSlider.value = CFG.pwallEmo;
pwEmoVal.textContent = CFG.pwallEmo + 'px';
pwEmoSlider.addEventListener('input', () => {
const px = parseInt(pwEmoSlider.value);
pwEmoVal.textContent = px + 'px';
applyPwallEmoSize(px);
GM_setValue(PWALL_EMO_KEY, px); CFG.pwallEmo=px;
});
}
// ---- Блюр — RAF-дебаунс для слайдера ----
// ОПТИМІЗАЦІЯ: рух слайдера більше не перезаписує стиль 60+ разів, тільки раз на кадр
const blurSlider = panel.querySelector('#glassui-blur-single');
const blurVal = panel.querySelector('#glassui-blur-single-val');
blurSlider.value = CFG.blur; blurVal.textContent = CFG.blur + 'px';
let _blurRaf = null;
blurSlider.addEventListener('input', () => {
blurVal.textContent = blurSlider.value + 'px';
if (_blurRaf) cancelAnimationFrame(_blurRaf);
_blurRaf = requestAnimationFrame(() => {
_blurRaf = null;
applyBlur(parseInt(blurSlider.value));
});
});
panel.querySelector('#glassui-blur-apply').addEventListener('click', () => {
const val = parseInt(blurSlider.value);
GM_setValue(BLUR_KEY, val); CFG.blur=val;
applyBlur(val);
});
panel.querySelector('#glassui-blur-reset').addEventListener('click', () => {
GM_setValue(BLUR_KEY, BLUR_DEFAULT); CFG.blur=BLUR_DEFAULT;
blurSlider.value = BLUR_DEFAULT; blurVal.textContent = BLUR_DEFAULT + 'px';
applyBlur(BLUR_DEFAULT);
});
// ── Тоггл дизайну карток ──────────────────────────────────────────
const cardsToggle = panel.querySelector('#glassui-cards-toggle');
const cardsTrack = panel.querySelector('#glassui-cards-track');
const cardsThumb = panel.querySelector('#glassui-cards-thumb');
function updateCardsToggleUI(enabled) {
if (!cardsToggle) return;
cardsToggle.checked = enabled;
cardsTrack.style.background = enabled ? 'var(--accent)' : 'rgba(255,255,255,0.15)';
cardsThumb.style.transform = enabled ? 'translateX(16px)' : 'translateX(0)';
}
function applyCardsUi(enabled) {
const wrap = document.getElementById('gs-rank-wrap');
const starsRow = document.getElementById('gs-stars-row');
const nav = document.querySelector('.tabs__nav.tab__menu');
const starShow = nav ? nav.querySelector('.tabs__navigate__stars__show') : null;
const sortBlock = document.querySelector('.sort-block');
if (enabled) {
if (wrap) wrap.style.removeProperty('display');
if (starsRow) starsRow.style.removeProperty('display');
if (nav) nav.style.setProperty('display', 'none', 'important');
if (sortBlock) sortBlock.style.removeProperty('display');
// starShow прихований в rebuildTabsNav — при увімкненому дизайні це правильно
} else {
if (wrap) wrap.style.setProperty('display', 'none', 'important');
if (starsRow) starsRow.style.setProperty('display', 'none', 'important');
if (nav) nav.style.setProperty('display', 'flex', 'important');
if (sortBlock) sortBlock.style.removeProperty('display');
// Відновлюємо кнопку зірок в оригінальному nav
if (starShow) starShow.style.removeProperty('display');
}
}
if (cardsToggle) {
updateCardsToggleUI(CFG.cardsUi);
applyCardsUi(CFG.cardsUi);
cardsToggle.addEventListener('change', () => {
const enabled = cardsToggle.checked;
GM_setValue(CARDS_UI_KEY, enabled);
CFG.cardsUi = enabled;
updateCardsToggleUI(enabled);
applyCardsUi(enabled);
});
}
// ── Тоггл фону профілю (usn_poster) ──────────────────────────────
const posterToggle = panel.querySelector('#glassui-poster-toggle');
const posterTrack = panel.querySelector('#glassui-poster-track');
const posterThumb = panel.querySelector('#glassui-poster-thumb');
function applyPosterVisibility(enabled) {
const poster = document.querySelector('.usn__poster');
const usn = document.querySelector('.usn[data-user-id]');
if (poster) poster.style.setProperty('display', enabled ? '' : 'none', 'important');
if (usn) {
if (enabled) {
usn.style.removeProperty('padding-top');
} else {
usn.style.setProperty('padding-top', '40px', 'important');
}
}
}
function updatePosterToggleUI(enabled) {
if (!posterToggle) return;
posterToggle.checked = enabled;
posterTrack.style.background = enabled ? 'var(--accent)' : 'rgba(255,255,255,0.15)';
posterThumb.style.transform = enabled ? 'translateX(16px)' : 'translateX(0)';
}
if (posterToggle) {
updatePosterToggleUI(CFG.poster);
applyPosterVisibility(CFG.poster);
posterToggle.addEventListener('change', () => {
const enabled = posterToggle.checked;
GM_setValue(POSTER_KEY, enabled);
CFG.poster = enabled;
updatePosterToggleUI(enabled);
applyPosterVisibility(enabled);
});
}
// Застосовуємо при старті (якщо togglel не знайдено — все одно виконуємо)
if (!posterToggle) applyPosterVisibility(CFG.poster);
// ── Тоггл кнопок навігації (ncard__tabs) ──────────────────────────
const ncardToggle = panel.querySelector('#glassui-ncard-toggle');
const ncardTrack = panel.querySelector('#glassui-ncard-track');
const ncardThumb = panel.querySelector('#glassui-ncard-thumb');
function applyNcardTabs(enabled) {
const styleId = 'glassui-ncard-disable';
let s = document.getElementById(styleId);
if (!enabled) {
if (!s) { s = document.createElement('style'); s.id = styleId; document.head.appendChild(s); }
s.textContent = `
.ncard__tabs { background: none !important; backdrop-filter: none !important;
-webkit-backdrop-filter: none !important; border: none !important;
border-radius: 0 !important; padding: 0 !important; box-shadow: none !important; }
.ncard__tabs-btns { background: none !important; }
.ncard__tabs-btn { background: var(--bg-2) !important; border: none !important;
color: var(--tt) !important; border-radius: 6px !important; }
.ncard__tabs-btn:hover { background: var(--accent) !important; color: #fff !important; }
.ncard__tabs-btn.is-active { background: var(--accent) !important; color: #fff !important; }
`;
} else {
if (s) s.remove();
}
}
function updateNcardToggleUI(enabled) {
if (!ncardToggle) return;
ncardToggle.checked = enabled;
ncardTrack.style.background = enabled ? 'var(--accent)' : 'rgba(255,255,255,0.15)';
ncardThumb.style.transform = enabled ? 'translateX(16px)' : 'translateX(0)';
}
if (ncardToggle) {
updateNcardToggleUI(CFG.ncardTabs);
applyNcardTabs(CFG.ncardTabs);
ncardToggle.addEventListener('change', () => {
const enabled = ncardToggle.checked;
GM_setValue(NCARD_KEY, enabled);
CFG.ncardTabs = enabled;
updateNcardToggleUI(enabled);
applyNcardTabs(enabled);
});
}
applyNcardTabs(CFG.ncardTabs);
function updateThemeBtns() {
const isDark = document.body.classList.contains('dt-is-active') ||
document.documentElement.dataset.theme === 'dark' ||
document.cookie.includes('theme=dark');
const lightBtn = panel.querySelector('#glassui-theme-light');
const darkBtn = panel.querySelector('#glassui-theme-dark');
if (lightBtn && darkBtn) {
lightBtn.style.opacity = isDark ? '0.5' : '1';
lightBtn.style.borderColor = isDark ? 'rgba(255,220,80,0.15)' : 'rgba(255,220,80,0.5)';
darkBtn.style.opacity = isDark ? '1' : '0.5';
darkBtn.style.borderColor = isDark ? 'rgba(100,120,255,0.5)' : 'rgba(100,120,255,0.15)';
}
}
updateThemeBtns();
panel.querySelector('#glassui-theme-light').addEventListener('click', (e) => {
e.stopPropagation();
const nativeBtn = document.querySelector('.header__theme');
const isDark = document.body.classList.contains('dt-is-active');
if (isDark && nativeBtn) nativeBtn.click();
updateThemeBtns();
});
panel.querySelector('#glassui-theme-dark').addEventListener('click', (e) => {
e.stopPropagation();
const nativeBtn = document.querySelector('.header__theme');
const isDark = document.body.classList.contains('dt-is-active');
if (!isDark && nativeBtn) nativeBtn.click();
updateThemeBtns();
});
// ---- Шрифти ----
const fontCurrent = panel.querySelector('#glassui-font-current');
const fontLabel = panel.querySelector('#glassui-font-label');
const fontArrow = panel.querySelector('#glassui-font-arrow');
const fontDropdown = panel.querySelector('#glassui-font-dropdown');
let currentFont = CFG.font;
FONTS.forEach(f => {
const item = document.createElement('div');
item.dataset.value = f.value;
item.textContent = f.name;
const isActive = f.value === currentFont;
item.style.cssText = `
padding: 10px 14px; font-size: 13px; cursor: pointer;
color: ${isActive ? '#fff' : 'rgba(255,255,255,0.65)'};
background: ${isActive ? 'rgba(255,255,255,0.10)' : 'transparent'};
transition: background 0.15s, color 0.15s;
border-bottom: 1px solid rgba(255,255,255,0.05);
`;
if (isActive) fontLabel.textContent = f.name;
item.addEventListener('mouseenter', () => {
if (item.dataset.value !== currentFont) {
item.style.background = 'rgba(255,255,255,0.06)';
item.style.color = '#fff';
}
});
item.addEventListener('mouseleave', () => {
if (item.dataset.value !== currentFont) {
item.style.background = 'transparent';
item.style.color = 'rgba(255,255,255,0.65)';
}
});
item.addEventListener('click', (e) => {
e.stopPropagation();
fontDropdown.querySelectorAll('div').forEach(el => {
el.style.background = 'transparent';
el.style.color = 'rgba(255,255,255,0.65)';
});
item.style.background = 'rgba(255,255,255,0.10)';
item.style.color = '#fff';
currentFont = f.value; CFG.font = f.value;
fontLabel.textContent = f.name;
applyFont(f.value);
GM_setValue(FONT_KEY, f.value);
fontDropdown.style.display = 'none';
fontArrow.style.transform = '';
fontCurrent.style.borderColor = 'rgba(255,255,255,0.12)';
fontCurrent.style.background = 'rgba(255,255,255,0.07)';
});
fontDropdown.appendChild(item);
});
fontCurrent.addEventListener('click', (e) => {
e.stopPropagation();
const isOpen = fontDropdown.style.display !== 'none';
fontDropdown.style.display = isOpen ? 'none' : 'block';
fontArrow.style.transform = isOpen ? '' : 'rotate(180deg)';
fontCurrent.style.borderColor = isOpen ? 'rgba(255,255,255,0.12)' : 'rgba(255,255,255,0.28)';
fontCurrent.style.background = isOpen ? 'rgba(255,255,255,0.07)' : 'rgba(255,255,255,0.11)';
});
document.addEventListener('click', () => {
fontDropdown.style.display = 'none';
fontArrow.style.transform = '';
fontCurrent.style.borderColor = 'rgba(255,255,255,0.12)';
fontCurrent.style.background = 'rgba(255,255,255,0.07)';
});
function closePanel() {
panel.style.display = 'none';
overlay.style.display = 'none';
cpTarget = null;
}
closeBtn.addEventListener('click', (e) => { e.stopPropagation(); closePanel(); });
overlay.addEventListener('click', closePanel);
btn.addEventListener('click', (e) => {
e.stopPropagation();
if (panel.style.display === 'none') {
const isMobile = Math.min(window.innerWidth, window.innerHeight) < 500 || (navigator.maxTouchPoints > 0 && window.innerWidth < 1024);
if (isMobile) {
panel.style.top = '0'; panel.style.left = '0';
panel.style.right = '0'; panel.style.bottom = '0';
panel.style.width = '100%'; panel.style.borderRadius = '0';
panel.style.maxHeight = '100vh'; panel.style.overflowY = 'auto';
overlay.style.display = 'none';
const cols = panel.querySelector('#glassui-cols');
const toprow = panel.querySelector('#glassui-toprow');
if (cols) cols.style.gridTemplateColumns = '1fr';
if (toprow) toprow.style.gridTemplateColumns = '1fr';
} else {
panel.style.bottom = ''; panel.style.right = '';
panel.style.borderRadius = '12px';
panel.style.maxHeight = 'calc(100vh - 90px)';
panel.style.overflowY = 'auto';
const rect = btn.getBoundingClientRect();
panel.style.top = (rect.bottom + 6) + 'px';
const panelW = (window.innerWidth >= 600) ? 520 : 280;
panel.style.width = panelW + 'px';
const cols = panel.querySelector('#glassui-cols');
const toprow = panel.querySelector('#glassui-toprow');
if (cols) cols.style.gridTemplateColumns = (window.innerWidth >= 600) ? '1fr 1fr' : '1fr';
if (toprow) toprow.style.gridTemplateColumns = (window.innerWidth >= 600) ? '1fr 1fr' : '1fr';
const leftPos = Math.min(rect.left, window.innerWidth - panelW - 8);
panel.style.left = Math.max(8, leftPos) + 'px';
}
panel.style.display = 'block';
updateThemeBtns();
} else {
closePanel();
}
});
document.addEventListener('mousedown', (e) => {
if (panel.style.display === 'none') return;
if (panel.contains(e.target)) return;
if (btn.contains(e.target)) return;
closePanel();
});
}
}
applyFix();
// ===================== МЕНЮ ПРОФІЛЮ GLASS UI =====================
(function initLgnMenu() {
// Inject CSS один раз
if (document.getElementById('glass-lgn-style')) return;
const st = document.createElement('style');
st.id = 'glass-lgn-style';
st.textContent = `
.lgn {
background: rgba(10,10,22,0.93) !important;
backdrop-filter: blur(24px) !important;
-webkit-backdrop-filter: blur(24px) !important;
border: 1px solid rgba(255,255,255,0.09) !important;
border-radius: 16px !important;
box-shadow: 0 24px 64px rgba(0,0,0,0.7) !important;
overflow: hidden !important;
}
.lgn__ava-holder {
background: rgba(255,255,255,0.03) !important;
border-right: 1px solid rgba(255,255,255,0.08) !important;
}
.lgn__menus { background: transparent !important; }
.lgn__btn {
border-radius: 10px !important;
font-weight: 600 !important;
height: 38px !important;
font-size: 13px !important;
}
.lgn__btn-profile {
background: var(--accent) !important;
border: none !important;
color: #fff !important;
box-shadow: 0 4px 14px rgba(142,46,175,0.4) !important;
}
.lgn__btn-vozv {
background: var(--accent) !important;
border: none !important;
box-shadow: 0 4px 14px rgba(142,46,175,0.4) !important;
}
.lgn__name { color: var(--tt) !important; font-weight: 700 !important; }
.lgn__caption {
color: rgba(255,255,255,0.32) !important;
font-size: 9.5px !important;
font-weight: 700 !important;
text-transform: uppercase !important;
letter-spacing: 1px !important;
padding: 14px 14px 6px !important;
display: flex !important;
align-items: center !important;
gap: 7px !important;
}
.lgn__caption::before {
content: '' !important;
display: inline-block !important;
width: 3px !important; height: 11px !important;
background: var(--accent) !important;
border-radius: 2px !important;
opacity: 0.7 !important;
flex-shrink: 0 !important;
}
/* Кожен пункт — рамка, flex з фіксованою іконкою */
.lgn__menu li a {
display: flex !important;
align-items: center !important;
padding: 9px 14px !important;
border-radius: 8px !important;
margin: 2px 8px !important;
font-size: 13.5px !important;
color: rgba(255,255,255,0.75) !important;
transition: background 0.15s, color 0.15s !important;
border: 1px solid rgba(255,255,255,0.07) !important;
gap: 0 !important;
}
.lgn__menu li a:hover {
background: rgba(255,255,255,0.07) !important;
color: #fff !important;
border-color: rgba(255,255,255,0.13) !important;
}
/* Іконка — завжди 32px, текст починається з одного місця */
.lgn__menu li a > i,
.lgn__menu li a > svg,
.lgn__menu li a > span[class*="fa"],
.lgn__menu li a > .fal,
.lgn__menu li a > .fas,
.lgn__menu li a > .far,
.lgn__menu li a > .fad {
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
width: 32px !important;
min-width: 32px !important;
height: 20px !important;
opacity: 0.55 !important;
flex-shrink: 0 !important;
font-size: 14px !important;
}
/* Лічильник (112) */
.lgn__menu li a .ms-auto,
.lgn__menu li a [class*="count"],
.lgn__menu li a span:last-child:not(:first-child) {
margin-left: auto !important;
background: rgba(var(--accent-rgb, 142,46,175), 0.25) !important;
border: 1px solid rgba(var(--accent-rgb, 142,46,175), 0.5) !important;
border-radius: 5px !important;
padding: 2px 8px !important;
font-size: 11px !important;
color: rgba(255,255,255,0.8) !important;
font-weight: 600 !important;
}
/* Вийти — червоний */
.lgn__menu li a[href*="logout"],
.lgn__menu li a[href*="exit"] {
color: rgba(240,80,80,0.75) !important;
}
.lgn__menu li a[href*="logout"]:hover,
.lgn__menu li a[href*="exit"]:hover {
background: rgba(240,80,80,0.1) !important;
color: rgb(240,80,80) !important;
}
.login_close { color: rgba(255,255,255,0.4) !important; transition: color 0.15s !important; }
.login_close:hover { color: #fff !important; }
/* Мобільний скрол */
@media (max-width: 700px) {
.lgn__menus { overflow-y: auto !important; max-height: 72vh !important; }
}
@media (max-height: 500px) {
.lgn__menus { overflow-y: auto !important; max-height: 70vh !important; }
.lgn__menu li a { padding: 7px 12px !important; }
}
`;
document.head.appendChild(st);
// Мапи перейменувань
const RENAME = {
'Мой клуб':'Клуб','Моя коллекция':'Коллекция','Моя коллекція':'Коллекция',
'Мои закладки':'Закладки','Мої закладки':'Закладки',
'Мои списки':'Списки','Мої списки':'Списки','списки':'Списки',
'Сообщения:':'Сообщения','Повідомлення:':'Сообщения',
'Мой профиль':'Профиль','Мій профіль':'Профиль',
'Мои карты':'Карты','Мої карти':'Карты',
'Нове':'Новое','Піднесення':'Возвышение',
'Все комментарии':'Комментарии','Всі коментарі':'Комментарии',
'Вийти':'Выйти',
'МОЙ ПРОФИЛЬ':'ПРОФИЛЬ','МОЙ ПРОФІЛЬ':'ПРОФИЛЬ',
'МОИ КАРТЫ':'КАРТЫ','МОЇ КАРТИ':'КАРТЫ',
};
const PREFIX_RE = /^(Мой|Моя|Мои|Мій|Мої)\s+/i;
function renameText(str) {
const t = str.trim();
if (RENAME[t]) return RENAME[t];
const cleaned = t.replace(PREFIX_RE, '');
return cleaned === 'списки' ? 'Списки' : cleaned;
}
function renameLgn() {
// Кнопки зліва
document.querySelectorAll('.lgn__btn span').forEach(el => {
el.textContent = renameText(el.textContent);
});
// Пункти меню — тільки прямі text-node
document.querySelectorAll('.lgn__menu li a').forEach(a => {
a.childNodes.forEach(n => {
if (n.nodeType === 3) { // TEXT_NODE
const renamed = renameText(n.textContent);
if (renamed !== n.textContent.trim()) n.textContent = renamed;
}
});
// span з текстом (але не лічильник)
a.querySelectorAll('span:not(.ms-auto)').forEach(sp => {
if (!sp.querySelector('*')) sp.textContent = renameText(sp.textContent);
});
});
// Заголовки секцій
document.querySelectorAll('.lgn__caption').forEach(cap => {
const t = cap.textContent.trim().toLowerCase();
if (t.includes('персональн')) cap.textContent = 'Личное меню';
else if (t.includes('жизнь') || t.includes('сайт')) cap.textContent = 'Сайт';
});
}
// Слухаємо тільки .lgn клас-зміну — мінімально
const lgnEl = document.querySelector('.lgn');
if (!lgnEl) return;
let _renamed = false;
new MutationObserver(() => {
const active = lgnEl.classList.contains('is-active');
if (active && !_renamed) { _renamed = true; setTimeout(renameLgn, 0); }
else if (!active) { _renamed = false; }
}).observe(lgnEl, { attributes: true, attributeFilter: ['class'] });
if (lgnEl.classList.contains('is-active')) { _renamed = true; renameLgn(); }
})();
// ===================== DPM МЕНЮ — GLASS UI =====================
(function initDpmMenu() {
const STORAGE_KEY = 'gls-dpm-bg';
function applyDpmBg(data) {
const main = document.querySelector('.dpm-main');
if (!main) return;
main.style.setProperty('backdrop-filter', 'blur(20px)', 'important');
main.style.setProperty('-webkit-backdrop-filter', 'blur(20px)', 'important');
if (data.type === 'color') {
// Очищаємо картинку якщо була
main.style.removeProperty('background-image');
main.style.removeProperty('background-size');
main.style.removeProperty('background-position');
main.style.removeProperty('background-repeat');
main.removeAttribute('data-gls-img');
const hex = data.value;
const a = data.alpha !== undefined ? data.alpha : 0.82;
const r=parseInt(hex.slice(1,3),16), g=parseInt(hex.slice(3,5),16), b=parseInt(hex.slice(5,7),16);
main.style.setProperty('background',
`linear-gradient(rgba(${r},${g},${b},${a}),rgba(${r},${g},${b},${a}))`, 'important');
} else if (data.type === 'image') {
main.style.removeProperty('background');
main.style.setProperty('background-image', `url("${data.value}")`, 'important');
main.style.setProperty('background-size', 'cover', 'important');
main.style.setProperty('background-position', 'center center', 'important');
main.style.setProperty('background-repeat', 'no-repeat', 'important');
main.setAttribute('data-gls-img', '1');
}
}
function saveBg(data) {
try { localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); } catch {}
}
// Відновити збережений фон
const saved = (() => { try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || 'null'); } catch { return null; } })();
if (saved) applyDpmBg(saved);
function buildDpmMenu(menuEl) {
if (menuEl.dataset.glsBuilt) return;
menuEl.dataset.glsBuilt = '1';
const links = [...menuEl.querySelectorAll('a')];
const clearLink = links.find(a => a.href.includes('clear') || a.textContent.includes('истори') || a.textContent.includes('чисти'));
const ignoreLink = links.find(a => a.href.includes('ignore') || a.textContent.includes('игнор') || a.textContent.includes('ігнор'));
menuEl.innerHTML = '';
// ── Секція: Фон чата ──
const curColor = (saved?.type === 'color') ? saved.value : '#00141a';
const curUrl = (saved?.type === 'image') ? saved.value : '';
// ── helper: HSL → HEX ──
function hslToHex(h,s,l) {
s/=100; l/=100;
const a=s*Math.min(l,1-l);
const f=n=>{const k=(n+h/30)%12;return l-a*Math.max(Math.min(k-3,9-k,1),-1);};
return '#'+[f(0),f(8),f(4)].map(x=>Math.round(255*x).toString(16).padStart(2,'0')).join('');
}
function hexToHsl(hex) {
let r=parseInt(hex.slice(1,3),16)/255, g=parseInt(hex.slice(3,5),16)/255, b=parseInt(hex.slice(5,7),16)/255;
const max=Math.max(r,g,b), min=Math.min(r,g,b); let h,s,l=(max+min)/2;
if(max===min){h=s=0;}else{const d=max-min;s=l>0.5?d/(2-max-min):d/(max+min);
switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;}h*=60;}
return [Math.round(h), Math.round(s*100), Math.round(l*100)];
}
const initHex = (saved?.type==='color') ? saved.value : '#00141a';
const [initH, initS, initL] = hexToHsl(initHex);
const bgSection = document.createElement('div');
bgSection.className = 'gls-dpm-bg-section';
const isColorOpen = saved?.type === 'color';
const initAlpha = saved?.alpha !== undefined ? Math.round(saved.alpha*100) : 82;
bgSection.innerHTML = `
<div class="gls-dpm-bg-section-title">Фон чата</div>
<div style="font-size:11px;margin-bottom:6px;color:rgba(255,255,255,0.6);">Из файла (JPG/PNG/WEBP/GIF)</div>
<input type="file" class="gls-dpm-file-input" accept="image/jpeg,image/png,image/webp,image/gif" style="display:none;">
<button class="gls-dpm-file-btn" style="width:100%;padding:7px;background:var(--accent);color:#fff;border:none;border-radius:6px;cursor:pointer;font-size:11px;font-weight:700;font-family:inherit;margin-bottom:4px;">
📁 Выбрать файл
</button>
<div style="font-size:10px;color:rgba(255,255,255,0.35);margin-bottom:4px;">*Хранится в браузере</div>
<div style="font-size:11px;margin-bottom:6px;color:rgba(255,255,255,0.6);">Прямая ссылка (JPG/PNG/WEBP/GIF)</div>
<div style="display:flex;gap:6px;margin-bottom:4px;">
<input type="text" class="gls-url-input" placeholder="https://..." value="${(saved?.type==='image'?saved.value:'')}"
style="flex:1;height:30px;border-radius:6px;border:1px solid rgba(255,255,255,0.1);background:rgba(255,255,255,0.06);color:var(--tt);font-size:12px;padding:0 10px;outline:none;font-family:inherit;">
<button class="gls-url-apply-btn"
style="padding:5px 8px;background:var(--accent);color:#fff;border:none;border-radius:6px;cursor:pointer;font-size:11px;font-weight:700;font-family:inherit;white-space:nowrap;">
OK
</button>
</div>
<div style="height:1px;background:rgba(255,255,255,0.07);margin:10px 0 8px;"></div>
<button class="gls-cp-toggle-btn ${isColorOpen ? 'open' : ''}"
style="width:100%;height:32px;background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.09);border-radius:8px;color:rgba(255,255,255,0.65);font-size:12px;font-weight:600;cursor:pointer;font-family:inherit;display:flex;align-items:center;gap:8px;padding:0 12px;margin-bottom:0;">
<i class="fal fa-palette"></i> Цвет наложения
<i class="fal fa-chevron-down gls-cp-arrow" style="margin-left:auto;font-size:11px;transition:transform .2s;${isColorOpen?'transform:rotate(180deg)':''}"></i>
</button>
<div class="gls-cp-body" style="display:${isColorOpen?'block':'none'};padding-top:10px;">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px;">
<div class="gls-cp-swatch" style="width:38px;height:38px;border-radius:8px;border:1px solid rgba(255,255,255,0.15);background:${initHex};flex-shrink:0;"></div>
<div style="flex:1;display:flex;flex-direction:column;gap:3px;">
<span style="font-size:9px;color:rgba(255,255,255,0.35);text-transform:uppercase;letter-spacing:.8px;">HEX</span>
<input class="gls-cp-hex-input" type="text" value="${initHex}" spellcheck="false"
style="width:100%;height:30px;border-radius:6px;border:1px solid rgba(255,255,255,0.12);background:rgba(255,255,255,0.07);color:var(--tt);font-size:13px;padding:0 10px;outline:none;font-family:monospace;font-weight:600;">
</div>
</div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">
<span style="font-size:10px;color:rgba(255,255,255,0.4);width:60px;flex-shrink:0;font-weight:600;">Оттенок</span>
<input class="gls-cp-range gls-cp-hue" type="range" min="0" max="360" value="${initH}" style="flex:1;accent-color:var(--accent);">
<span class="gls-cp-val" style="font-size:10px;color:rgba(255,255,255,0.4);width:30px;text-align:right;flex-shrink:0;">${initH}°</span>
</div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">
<span style="font-size:10px;color:rgba(255,255,255,0.4);width:60px;flex-shrink:0;font-weight:600;">Насыщен.</span>
<input class="gls-cp-range gls-cp-sat" type="range" min="0" max="100" value="${initS}" style="flex:1;accent-color:var(--accent);">
<span class="gls-cp-val" style="font-size:10px;color:rgba(255,255,255,0.4);width:30px;text-align:right;flex-shrink:0;">${initS}%</span>
</div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">
<span style="font-size:10px;color:rgba(255,255,255,0.4);width:60px;flex-shrink:0;font-weight:600;">Яркость</span>
<input class="gls-cp-range gls-cp-lit" type="range" min="0" max="100" value="${initL}" style="flex:1;accent-color:var(--accent);">
<span class="gls-cp-val" style="font-size:10px;color:rgba(255,255,255,0.4);width:30px;text-align:right;flex-shrink:0;">${initL}%</span>
</div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:10px;">
<span style="font-size:10px;color:rgba(255,255,255,0.4);width:60px;flex-shrink:0;font-weight:600;">Прозрач.</span>
<input class="gls-cp-alpha" type="range" min="0" max="100" value="${initAlpha}" style="flex:1;accent-color:var(--accent);">
<span class="gls-cp-alpha-val" style="font-size:10px;color:rgba(255,255,255,0.4);width:30px;text-align:right;flex-shrink:0;">${initAlpha}%</span>
</div>
<button class="gls-cp-apply-btn"
style="width:100%;padding:7px;background:var(--accent);color:#fff;border:none;border-radius:6px;cursor:pointer;font-size:12px;font-weight:700;font-family:inherit;display:flex;align-items:center;justify-content:center;gap:6px;box-shadow:0 4px 12px rgba(142,46,175,.4);">
<i class="fal fa-check"></i> Применить цвет
</button>
</div>
<button class="gls-bg-reset-btn" style="width:100%;padding:7px;background:var(--accent)!important;color:#fff!important;border:none!important;border-radius:6px;cursor:pointer;font-size:11px;font-weight:700;font-family:inherit;margin-top:8px;display:flex;align-items:center;justify-content:center;gap:6px;box-shadow:0 4px 12px rgba(142,46,175,.35);">
<i class="fal fa-undo"></i> Сбросить
</button>
`;
menuEl.appendChild(bgSection);
// Refs
const swatch = bgSection.querySelector('.gls-cp-swatch');
const hexInput = bgSection.querySelector('.gls-cp-hex-input');
const hueR = bgSection.querySelector('.gls-cp-hue');
const satR = bgSection.querySelector('.gls-cp-sat');
const litR = bgSection.querySelector('.gls-cp-lit');
const alphaR = bgSection.querySelector('.gls-cp-alpha');
const alphaVal = bgSection.querySelector('.gls-cp-alpha-val');
const hslVals = bgSection.querySelectorAll('.gls-cp-val');
function updateFromHsl() {
const h=+hueR.value, s=+satR.value, l=+litR.value;
const hex = hslToHex(h,s,l);
hexInput.value = hex;
swatch.style.background = hex;
hslVals[0].textContent = h+'°';
hslVals[1].textContent = s+'%';
hslVals[2].textContent = l+'%';
}
function updateFromHex(hex) {
if(!/^#[0-9a-f]{6}$/i.test(hex)) return;
const [h,s,l] = hexToHsl(hex);
hueR.value=h; satR.value=s; litR.value=l;
swatch.style.background = hex;
hslVals[0].textContent=h+'°';
hslVals[1].textContent=s+'%';
hslVals[2].textContent=l+'%';
}
alphaR.oninput = () => { alphaVal.textContent = alphaR.value+'%'; };
[hueR,satR,litR].forEach(r => r.oninput = updateFromHsl);
hexInput.oninput = () => updateFromHex(hexInput.value);
updateFromHsl();
// Toggle collapse
const toggleBtn = bgSection.querySelector('.gls-cp-toggle-btn');
const cpBody = bgSection.querySelector('.gls-cp-body');
const cpArrow = bgSection.querySelector('.gls-cp-arrow');
toggleBtn.onclick = () => {
const open = cpBody.style.display !== 'none';
cpBody.style.display = open ? 'none' : 'block';
cpArrow.style.transform = open ? '' : 'rotate(180deg)';
toggleBtn.classList.toggle('open', !open);
};
bgSection.querySelector('.gls-cp-apply-btn').onclick = () => {
const data = { type:'color', value: hexInput.value, alpha: +alphaR.value/100 };
applyDpmBg(data); saveBg(data);
};
// Файл — читаємо як base64 через FileReader (як в Glass UI)
bgSection.querySelector('.gls-dpm-file-btn').onclick = () => {
bgSection.querySelector('.gls-dpm-file-input').click();
};
bgSection.querySelector('.gls-dpm-file-input').onchange = (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
const b64 = ev.target.result;
// Перевірка розміру — localStorage має ліміт ~5MB
if (b64.length > 4_000_000) {
alert('Файл занадто великий (>3MB). Оберіть менший або використайте URL.');
return;
}
const data = { type:'image', value: b64 };
applyDpmBg(data); saveBg(data);
};
reader.readAsDataURL(file);
};
// URL
bgSection.querySelector('.gls-url-apply-btn').onclick = () => {
const url = bgSection.querySelector('.gls-url-input').value.trim();
if(!url) return;
const data = { type:'image', value:url };
applyDpmBg(data); saveBg(data);
};
bgSection.querySelector('.gls-bg-reset-btn').onclick = () => {
const main = document.querySelector('.dpm-main');
if (main) {
main.style.removeProperty('background');
main.style.removeProperty('background-image');
main.style.removeProperty('background-size');
main.style.removeProperty('background-position');
main.style.removeProperty('background-repeat');
main.style.removeProperty('backdrop-filter');
main.style.removeProperty('-webkit-backdrop-filter');
main.removeAttribute('data-gls-img');
}
try { localStorage.removeItem(STORAGE_KEY); } catch {}
};
// ── Секція: Дії ──
const actSection = document.createElement('div');
actSection.className = 'gls-dpm-action-section';
actSection.innerHTML = `<div class="gls-dpm-action-title">Действия</div><div class="gls-action-btns"></div>`;
const actBtns = actSection.querySelector('.gls-action-btns');
function makeActionBtn(icon, label, color, onClick) {
const btn = document.createElement('button');
btn.style.cssText = `
width:100%; height:36px; border-radius:8px; cursor:pointer;
display:flex; align-items:center; gap:10px; padding:0 14px;
font-size:13px; font-weight:600; transition:background 0.15s;
background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.08);
color:${color}; font-family:inherit;
`;
btn.innerHTML = `<i class="fal ${icon}" style="opacity:0.7;width:18px;text-align:center"></i>${label}`;
btn.onmouseenter = () => btn.style.background = 'rgba(255,255,255,0.09)';
btn.onmouseleave = () => btn.style.background = 'rgba(255,255,255,0.05)';
btn.onclick = onClick;
return btn;
}
if (ignoreLink) {
const countMatch = ignoreLink.textContent.match(/\((\d+)\)/);
const label = 'Игнорируемые' + (countMatch ? ` (${countMatch[1]})` : '');
actBtns.appendChild(makeActionBtn('fa-user-slash', label, 'rgba(255,255,255,0.7)', () => {
ignoreLink.click();
}));
}
if (clearLink) {
actBtns.appendChild(makeActionBtn('fa-trash-alt', 'Очистить историю', 'rgba(240,80,80,0.85)', () => {
clearLink.click();
}));
}
menuEl.appendChild(actSection);
}
// Спостерігаємо за появою .dpm-menu-content — з RAF і auto-disconnect
let _dpmRaf = null;
const dpmObs = new MutationObserver(() => {
if (_dpmRaf) return;
_dpmRaf = requestAnimationFrame(() => {
_dpmRaf = null;
const found = document.querySelectorAll('.dpm-menu-content:not([data-gls-built])');
found.forEach(buildDpmMenu);
// Якщо вже збудовано — відключаємось
if (document.querySelector('.dpm-menu-content[data-gls-built]')) {
dpmObs.disconnect();
}
});
});
document.querySelectorAll('.dpm-menu-content').forEach(buildDpmMenu);
// Підключаємо тільки якщо меню ще не існує
if (!document.querySelector('.dpm-menu-content[data-gls-built]')) {
dpmObs.observe(document.body, { childList: true, subtree: true });
}
})();
// ===================== ЄДИНИЙ MutationObserver З RAF-ДЕБАУНСОМ =====================
// Було: два окремих observer на весь document.body з subtree:true
// — кожна DOM-мутація (їх сотні) тригерила обидва callback синхронно
// Стало: один observer + requestAnimationFrame
// — реагує тільки раз на кадр, не на кожну мікро-мутацію
// — після виконання обох задач відключається повністю
let _domRaf = null;
let _popularDone = false;
const domObserver = new MutationObserver(() => {
if (_domRaf) return;
_domRaf = requestAnimationFrame(() => {
_domRaf = null;
// Перевірка кнопок (налаштувань і навігація-тогл)
if (!document.getElementById('glass-settings-btn') && document.querySelector('.header__theme')) {
applyFix();
}
// Popular padding — після знаходження більше не перевіряємо
if (!_popularDone) {
const firstPopular = document.querySelector('.popular:first-child');
if (firstPopular) {
firstPopular.style.setProperty('padding', '0 10px', 'important');
_popularDone = true;
}
}
// Якщо обидві задачі виконані — відключаємо observer повністю
if (_popularDone && document.getElementById('glass-settings-btn')) {
domObserver.disconnect();
}
});
});
domObserver.observe(document.body, { childList: true, subtree: true });
// ===================== ОРИГІНАЛЬНИЙ CSS (БЕЗ ЗМІН) =====================
GM_addStyle(`
/* ===================== WRAPPER ===================== */
body:not(.fscr-active) .wrapper-container.wrapper-main,
body:not(.fscr-active) div.content,
body:not(.fscr-active) .content.flex-grow-1.cols.d-flex,
body:not(.fscr-active) main.col-main,
body:not(.fscr-active) .col-main.flex-grow-1 {
background: transparent !important;
box-shadow: none !important;
}
/* ===================== ФІКС РЕЖИМУ КІНОТЕАТРУ ===================== */
/* Скидаємо тільки наші скляні стилі — сайт сам керує layout кінотеатру */
body.fscr-active .wrapper-container.wrapper-main,
body.fscr-active div.content,
body.fscr-active .content.flex-grow-1.cols.d-flex,
body.fscr-active main.col-main,
body.fscr-active .col-main.flex-grow-1,
body.fscr-active aside.col-side,
body.fscr-active .col-side,
body.fscr-active aside.col-side.col-side--not-active,
body.fscr-active .col-side.col-side--not-active {
background: unset !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
border: none !important;
border-radius: 0 !important;
box-shadow: none !important;
padding: unset !important;
}
/* ===================== КІНОТЕАТР: ХОВАЄМО ТІЛЬКИ ДАЛЕКИЙ КОНТЕНТ ===================== */
body.fscr-active .page__fix-grid,
body.fscr-active .page__stats,
body.fscr-active .page__comments,
body.fscr-active .sect.pmovie__related,
body.fscr-active .pcoln__header,
body.fscr-active .pcoln__poster,
body.fscr-active .pcoln__info,
body.fscr-active .pcoln__info2,
body.fscr-active .page__text,
body.fscr-active .fon-dob,
body.fscr-active .speedbar,
body.fscr-active div.speedbar,
body.fscr-active footer.footer,
body.fscr-active .pbtm__connect {
display: none !important;
}
/* ===================== DLE CONTENT GRID ===================== */
body:not(.fscr-active) #dle-content > *:not(.grid-item) {
grid-column: 1 / -1 !important;
margin-bottom: 40px !important;
}
/* ===================== ХЕДЕР ===================== */
body:not(.fscr-active) header.header,
body:not(.fscr-active) header.header.d-flex {
background: rgba(10, 10, 20, 0.40) !important;
backdrop-filter: blur(var(--glass-blur, 20px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 20px)) !important;
border-bottom: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
}
/* Хедер в кінотеатрі - прибираємо повністю */
body.fscr-active header.header {
display: none !important;
}
/* ===================== САЙДБАР ===================== */
body:not(.fscr-active) aside.col-side,
body:not(.fscr-active) .col-side,
body:not(.fscr-active) aside.col-side.col-side--not-active,
body:not(.fscr-active) .col-side.col-side--not-active {
background: rgba(10, 10, 20, 0.28) !important;
background-image: none !important;
backdrop-filter: blur(var(--glass-blur, 18px)) saturate(1.3) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 18px)) saturate(1.3) !important;
border: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
border-radius: 12px !important;
box-sizing: border-box !important;
}
body:not(.fscr-active) aside.col-side::before,
body:not(.fscr-active) aside.col-side::after,
body:not(.fscr-active) .col-side::before,
body:not(.fscr-active) .col-side::after {
display: none !important;
background: none !important;
background-image: none !important;
}
/* ===================== НАВ БЛОК ===================== */
.side-block.js-this-in-mobile-menu {
background: transparent !important;
border: none !important;
box-shadow: none !important;
padding: 0 !important;
margin-bottom: 16px !important;
overflow: visible !important;
border-radius: 8px !important;
}
.side-block_content.side-block_menu {
padding: 0 !important;
overflow: visible !important;
border-radius: 8px !important;
}
.side-block_menu li a {
margin: 0 !important;
display: block !important;
box-sizing: border-box !important;
}
/* ===================== ІКОНКИ ===================== */
.side-block__menu li .fal,
.side-block__menu li .fas,
.side-block__menu li .far,
.side-block__menu li span[class*="fa"] {
position: absolute !important;
left: 10px !important;
top: 15px !important;
pointer-events: none !important;
color: var(--tt-dark) !important;
}
/* ===================== ПІДМЕНЮ (По Годам, Жанры) ===================== */
.side-block__menu li {
position: relative !important;
}
.side-block__menu li:hover > .side-block__menu-hidden {
display: block !important;
}
.side-block__menu-hidden.anim {
position: absolute !important;
left: 100% !important;
top: 0 !important;
min-width: 180px !important;
background: rgba(14,14,28,0.97) !important;
border: 1px solid rgba(255,255,255,0.09) !important;
border-radius: 12px !important;
box-shadow: 0 8px 24px rgba(0,0,0,0.6) !important;
padding: 6px 0 !important;
z-index: 9999 !important;
margin-left: 6px !important;
}
.side-block__menu-hidden.anim li {
position: static !important;
}
.side-block__menu-hidden.anim li a {
display: block !important;
padding: 7px 16px !important;
color: rgba(255,255,255,0.75) !important;
font-size: 13px !important;
font-weight: 400 !important;
white-space: nowrap !important;
border-radius: 0 !important;
transition: background 0.12s, color 0.12s !important;
margin: 0 !important;
}
.side-block__menu-hidden.anim li a:hover {
background: rgba(255,255,255,0.07) !important;
color: #fff !important;
}
/* ===================== ТАБИ ===================== */
div.menus, #custom-tabs-moved {
display: none !important;
}
/* Кнопка ФІЛЬТР в .sect__header */
#glass-filter-btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 14px;
background: var(--accent) !important;
border: 1px solid var(--accent-darker, var(--accent)) !important;
border-radius: 6px;
color: #fff !important;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: opacity 0.2s;
user-select: none;
white-space: nowrap;
margin-left: auto;
margin-top: -9px;
flex-shrink: 0;
text-transform: uppercase;
letter-spacing: 0;
opacity: 0.9;
}
#glass-filter-btn:hover {
opacity: 1;
}
/* ===================== ПАНЕЛЬ ФІЛЬТРІВ ===================== */
/* Overlay */
.popup-overlay {
background: rgba(0,0,0,0.6) !important;
}
/* Сама панель */
.popup[data-type=side] .popup__content._disable-scroll {
background: rgba(10, 10, 20, 0.92) !important;
backdrop-filter: blur(24px) !important;
-webkit-backdrop-filter: blur(24px) !important;
border-left: 1px solid rgba(255,255,255,0.08) !important;
}
/* Кнопки Жанри/Теми */
.sk_sl {
background: rgba(255,255,255,0.04) !important;
border: 1px solid rgba(255,255,255,0.08) !important;
border-radius: 8px !important;
margin: 3px 10px !important;
}
.sk_sl:hover { background: rgba(255,255,255,0.08) !important; }
/* Секції */
.sb_ii { border-bottom: 1px solid rgba(255,255,255,0.05) !important; }
/* Заголовки секцій */
.sb_ci {
color: rgba(255,255,255,0.38) !important;
font-size: 10px !important;
text-transform: uppercase !important;
letter-spacing: 0.8px !important;
}
/* Чекбокси */
.catalog-filter .control {
background: rgba(255,255,255,0.04) !important;
border: 1px solid rgba(255,255,255,0.09) !important;
border-radius: 6px !important;
padding: 4px 8px 4px 6px !important;
margin-bottom: 4px !important;
width: 100% !important;
box-sizing: border-box !important;
}
.catalog-filter .control:hover { background: rgba(255,255,255,0.08) !important; }
.catalog-filter .control__indicator i.fas.fa-square { color: var(--accent) !important; }
/* Інпути */
.catalog-filter .form-input__field {
background: rgba(255,255,255,0.06) !important;
border: 1px solid rgba(255,255,255,0.1) !important;
border-radius: 6px !important;
color: var(--tt) !important;
}
.catalog-filter .form-input__field:focus { border-color: var(--accent) !important; outline: none !important; }
/* Футер */
.catalog-filter .filter-footer {
background: rgba(0,0,0,0.3) !important;
border-top: 1px solid rgba(255,255,255,0.07) !important;
}
/* Кнопки футера */
.catalog-filter #reset_filter {
border: 1px solid rgba(255,255,255,0.18) !important;
color: var(--tt) !important;
border-radius: 8px !important;
}
.catalog-filter .btn.is-filled.variant-primary {
background: var(--accent) !important;
color: #fff !important;
border: none !important;
border-radius: 8px !important;
}
/* Хедер фільтра */
.filter-header {
background: rgba(255,255,255,0.025) !important;
border-bottom: 1px solid rgba(255,255,255,0.07) !important;
}
/* Скролбар */
.filter-content::-webkit-scrollbar { width: 3px !important; }
.filter-content::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.18) !important; border-radius: 3px !important; }
/* ===================== КАРУСЕЛЬКА ===================== */
.carou, div.carou {
background: rgba(10, 10, 20, 0.22) !important;
backdrop-filter: blur(var(--glass-blur, 18px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 18px)) !important;
border-radius: 12px !important;
border: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
}
/* ===================== СЕКЦІЯ КАРТОК ===================== */
.sect.sect--padding,
section.sect.sect--padding {
background: rgba(10, 10, 20, 0.22) !important;
backdrop-filter: blur(var(--glass-blur, 18px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 18px)) !important;
border-radius: 12px !important;
border: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
section.desc.order-last {
display: none !important;
}
/* ===================== ФІЛЬТР БЛОК ===================== */
.filter-blockcat,
div.filter-blockcat {
background: rgba(10, 10, 20, 0.22) !important;
backdrop-filter: blur(var(--glass-blur, 18px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 18px)) !important;
border-radius: 12px !important;
border: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
margin-bottom: 8px !important;
padding: 12px 28px !important;
}
/* ===================== КНОПКИ ФІЛЬТРА ===================== */
.tail-select .select-label,
.filter-block_cell .select-label {
background: rgba(255,255,255,0.06) !important;
border: 1px solid rgba(255,255,255,0.10) !important;
border-radius: 8px !important;
color: rgba(255,255,255,0.75) !important;
box-shadow: none !important;
transition: background 0.2s ease, border-color 0.2s ease !important;
}
.tail-select .select-label:hover,
.filter-block_cell .select-label:hover {
background: rgba(255,255,255,0.11) !important;
border-color: rgba(255,255,255,0.20) !important;
}
/* ===================== SIDE-BLOCK ===================== */
.side-block, div.side-block {
background: rgba(10, 10, 20, 0.20) !important;
backdrop-filter: blur(var(--glass-blur, 14px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 14px)) !important;
border-radius: 10px !important;
border: 1px solid rgba(255,255,255,0.06) !important;
box-shadow: none !important;
margin-bottom: 10px !important;
overflow: hidden !important;
}
/* ===================== ЗАГОЛОВОК "Комментарии" ===================== */
.side-block .side-block_title,
.side-block__title {
font-weight: 700 !important;
font-size: 18px !important;
margin-bottom: 5px !important;
padding: 10px 0 10px 27px !important;
}
/* ===================== КОМЕНТАРІ ===================== */
.lcomm__text {
color: var(--tt) !important;
}
.page__comments-info {
color: var(--tt-2) !important;
}
.lcomm, div.lcomm, div.lcomm.js-comm {
border-bottom: none !important;
border-top: none !important;
margin: 0 !important;
padding: 10px 12px !important;
box-sizing: border-box !important;
}
.lcomm:not(:last-child) {
border-bottom: 1px solid rgba(255,255,255,0.05) !important;
padding-bottom: 10px !important;
margin-bottom: 0 !important;
}
.side-block_content.d-grid-mob {
width: 100% !important;
box-sizing: border-box !important;
padding: 4px 8px 8px !important;
}
/* ===================== СЛУЧАЙНЕ АНІМЕ ===================== */
#chat-place-before .side-block_content,
#chat-place-before .d-grid-mob {
display: flex !important;
flex-direction: column !important;
align-items: center !important;
padding: 8px !important;
width: 100% !important;
box-sizing: border-box !important;
}
#chat-place-before .top,
#chat-place-before a.top {
display: block !important;
width: 100% !important;
border-radius: 8px !important;
overflow: hidden !important;
}
#chat-place-before img {
width: 100% !important;
height: auto !important;
min-height: 140px !important;
object-fit: cover !important;
border-radius: 8px !important;
display: block !important;
}
/* ===================== КОМЕНТАРІ НА СТОРІНЦІ АНІМЕ ===================== */
.ncomm_body,
div.ncomm_body {
background: rgba(10, 10, 20, 0.35) !important;
backdrop-filter: blur(var(--glass-blur, 14px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 14px)) !important;
border-radius: 10px !important;
border: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
}
/* ===================== ФОН СТОРІНКИ АНІМЕ ===================== */
.pcoln,
div.pcoln {
background: transparent !important;
box-shadow: none !important;
}
/* ===================== САЙДБАР POPULAR ===================== */
.popular + .popular {
padding: 0 10px !important;
}
/* ===================== ПРЕМІУМ БЛОК ===================== */
body .lootbox_descr,
div .lootbox_descr,
.ncard-premium__text .lootbox_descr {
border: 10px solid var(--bdc) !important;
border-radius: 12px 12px 0 0 !important;
border-bottom: none !important;
}
.ncard-premium__left {
border-radius: 0 0 12px 12px !important;
border: 1px solid var(--bdc) !important;
border-top: none !important;
}
/* ===================== ASBM ПАНЕЛЬ (карти) ===================== */
#asbm_container,
div#asbm_container {
background: rgba(10, 10, 20, 0.40) !important;
backdrop-filter: blur(var(--glass-blur, 20px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 20px)) !important;
border: none !important;
box-shadow: none !important;
}
#asbm_bar,
div#asbm_bar {
border: none !important;
box-shadow: none !important;
outline: none !important;
}
/* Без постера — дефолт */
.usn__poster {
border: none !important;
box-shadow: none !important;
}
/* ===================== ПОВІДОМЛЕННЯ — GLASS UI ===================== */
/* Головний контейнер */
.dpm-wrapper {
border-radius: 16px !important;
overflow: hidden !important;
}
.dpm-container {
min-height: 0 !important;
}
/* Кнопка бургера — квадратна акцентна */
.dpm-sidebar-menu-icon {
width: 36px !important;
height: 36px !important;
min-width: 36px !important;
border-radius: 8px !important;
background: var(--accent) !important;
color: #fff !important;
box-shadow: 0 4px 12px rgba(142,46,175,0.4) !important;
transition: opacity 0.15s !important;
}
.dpm-sidebar-menu-icon:hover { opacity: 0.85 !important; }
.dpm-sidebar-menu-icon .fal { color: #fff !important; }
/* ── ЛІВА ПАНЕЛЬ (сайдбар) ──
Оригінал мав: wrapper-as::before (blur) + .dpm-container-empty (blur) + sidebar сам
Залишаємо ОДИН blur тільки на sidebar */
.dpm-sidebar {
background: rgba(10,10,20,0.55) !important;
backdrop-filter: blur(18px) !important;
-webkit-backdrop-filter: blur(18px) !important;
border-right: 1px solid rgba(255,255,255,0.07) !important;
}
/* Шапка сайдбару — без свого blur (вже є на .dpm-sidebar) */
.dpm-sidebar-header {
background: rgba(255,255,255,0.04) !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
border-bottom: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
}
/* Поле пошуку */
.dpm-search {
background: rgba(255,255,255,0.06) !important;
border: 1px solid rgba(255,255,255,0.1) !important;
border-radius: 8px !important;
color: var(--tt) !important;
}
.dpm-search::placeholder { color: rgba(255,255,255,0.35) !important; }
/* Кожен контакт у списку — тонка рамка, hover */
.dpm-users-profile {
border-radius: 10px !important;
margin: 2px 6px !important;
padding: 8px 10px !important;
transition: background 0.15s !important;
border: 1px solid rgba(255,255,255,0.05) !important;
}
.dpm-users-profile:hover {
background: rgba(255,255,255,0.06) !important;
border-color: rgba(255,255,255,0.1) !important;
}
.dpm-users li.active .dpm-users-profile,
.dpm-users li.is-active .dpm-users-profile {
background: rgba(var(--accent-rgb,142,46,175),0.18) !important;
border-color: rgba(var(--accent-rgb,142,46,175),0.4) !important;
}
/* ── ПРАВА ЧАСТИНА (чат) — власний Glass blur ── */
.dpm-main {
background: rgba(10,10,20,0.45) !important;
backdrop-filter: blur(20px) !important;
-webkit-backdrop-filter: blur(20px) !important;
position: relative !important;
isolation: isolate !important;
}
/* Картинка фону — фіксована відносно вікна (не розтягується по висоті) */
.dpm-main[data-gls-img] {
background-attachment: fixed !important;
}
/* Порожній стан */
.dpm-container-empty {
background: transparent !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
border: none !important;
}
/* Список повідомлень і діалог */
.dpm-dialog-list,
.dpm-dialog {
background: transparent !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
border: none !important;
}
.dpm-dialog {
border-radius: 12px !important;
}
/* ── МЕНЮ (бургер кнопка → попап) ── */
.dpm-menu-content,
div.dpm-menu-content {
background: rgba(10,10,22,0.92) !important;
backdrop-filter: blur(24px) !important;
-webkit-backdrop-filter: blur(24px) !important;
border: 1px solid rgba(255,255,255,0.09) !important;
border-radius: 16px !important;
box-shadow: 0 16px 48px rgba(0,0,0,0.7) !important;
padding: 0 !important;
overflow: hidden !important;
display: flex !important;
flex-direction: column !important;
}
/* Секція «Фон сайдбару» — зверху */
.gls-dpm-bg-section {
padding: 14px 16px 12px !important;
border-bottom: 1px solid rgba(255,255,255,0.07) !important;
}
.gls-dpm-bg-section-title {
font-size: 9px !important;
font-weight: 700 !important;
text-transform: uppercase !important;
letter-spacing: 1px !important;
color: rgba(255,255,255,0.3) !important;
margin-bottom: 10px !important;
display: flex !important;
align-items: center !important;
gap: 6px !important;
}
.gls-dpm-bg-section-title::before {
content: '' !important;
width: 3px !important; height: 10px !important;
background: var(--accent) !important;
border-radius: 2px !important;
opacity: 0.7 !important;
flex-shrink: 0 !important;
}
/* Color Picker */
.gls-cp-preview-row {
display: flex !important; align-items: center !important; gap: 10px !important;
margin-bottom: 12px !important;
}
.gls-cp-swatch {
width: 38px !important; height: 38px !important;
border-radius: 8px !important;
border: 1px solid rgba(255,255,255,0.15) !important;
flex-shrink: 0 !important;
background: #00141a !important;
}
.gls-cp-hex-wrap {
flex: 1 !important;
display: flex !important; flex-direction: column !important; gap: 3px !important;
}
.gls-cp-hex-label {
font-size: 9px !important; color: rgba(255,255,255,0.35) !important;
text-transform: uppercase !important; letter-spacing: 0.8px !important;
}
.gls-cp-hex-input {
width: 100% !important; height: 30px !important;
border-radius: 7px !important;
border: 1px solid rgba(255,255,255,0.12) !important;
background: rgba(255,255,255,0.07) !important;
color: var(--tt) !important; font-size: 13px !important;
padding: 0 10px !important; outline: none !important;
font-family: monospace !important; font-weight: 600 !important;
}
.gls-cp-divider {
height: 1px !important; background: rgba(255,255,255,0.07) !important;
margin: 12px 0 8px !important;
}
/* gls-cp-toggle/body — inline styles only */
.gls-bg-row-label {
font-size: 10px !important; color: rgba(255,255,255,0.35) !important;
font-weight: 600 !important; text-transform: uppercase !important;
letter-spacing: 0.5px !important; margin-bottom: 6px !important;
display: flex !important; align-items: center !important; gap: 6px !important;
}
.gls-bg-url-wrap {
display: flex !important; gap: 6px !important;
}
.gls-url-input {
flex: 1 !important; height: 32px !important;
border-radius: 7px !important;
border: 1px solid rgba(255,255,255,0.1) !important;
background: rgba(255,255,255,0.06) !important;
color: var(--tt) !important; font-size: 13px !important;
padding: 0 10px !important; outline: none !important; font-family: inherit !important;
}
.gls-url-input::placeholder { color: rgba(255,255,255,0.25) !important; }
.gls-url-apply-btn {
width: 36px !important; height: 32px !important; flex-shrink: 0 !important;
background: rgba(var(--accent-rgb,142,46,175),0.3) !important;
border: 1px solid rgba(var(--accent-rgb,142,46,175),0.5) !important;
border-radius: 7px !important; color: #fff !important; cursor: pointer !important;
font-family: inherit !important; display: flex !important;
align-items: center !important; justify-content: center !important;
}
/* .gls-bg-reset-btn — inline style only */
/* Секція «Дії» — знизу */
.gls-dpm-action-section {
padding: 12px 16px 14px !important;
}
.gls-dpm-action-title {
font-size: 9px !important;
font-weight: 700 !important;
text-transform: uppercase !important;
letter-spacing: 1px !important;
color: rgba(255,255,255,0.3) !important;
margin-bottom: 10px !important;
display: flex !important;
align-items: center !important;
gap: 6px !important;
}
.gls-dpm-action-title::before {
content: '' !important;
width: 3px !important; height: 10px !important;
background: rgba(240,80,80,0.7) !important;
border-radius: 2px !important;
flex-shrink: 0 !important;
}
.gls-action-btns {
display: flex !important;
flex-direction: column !important;
gap: 6px !important;
}
/* Ховаємо старі кнопки очистити/ігнорувати — замінюємо своїми */
.dpm-menu-content a:not(.gls-bg-btn):not(.gls-action-btn),
.dpm-menu-content > a {
display: none !important;
}
/* ===================== БАНЕР АНІМЕ ===================== */
.blurred-bg,
div.blurred-bg {
border-radius: 12px !important;
}
/* ===================== ОПИС КЛУБУ ===================== */
.nclub-enter__descr,
div.nclub-enter__descr {
border-radius: 12px !important;
border: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
background-color: var(--bg-2) !important;
padding: 15px !important;
}
/* ===================== ТОП КЛУБІВ КАРУСЕЛЬ ===================== */
.nclub__top-carou,
div.nclub__top-carou {
background: rgba(10, 10, 20, 0.22) !important;
backdrop-filter: blur(var(--glass-blur, 18px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 18px)) !important;
border-radius: 12px !important;
border: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
}
/* ===================== КНОПКА "ВСІ КЛУБИ" ===================== */
.nclub-enter__btn-all,
a.nclub-enter__btn-all {
box-shadow: none !important;
background-color: var(--bg-2) !important;
}
.nclub-enter__btn-all:hover,
a.nclub-enter__btn-all:hover {
background: var(--accent-darker) !important;
border-color: var(--accent-darker) !important;
color: #fff !important;
}
.btn-border {
background: none !important;
border: 1px solid var(--accent) !important;
background-color: var(--bg-2) !important;
}
/* ===================== БІБЛІОТЕКА КАРТ ===================== */
.anime-cards,
.anime-cards.anime-cards--full-page {
background: transparent !important;
box-shadow: none !important;
}
/* ===================== PWALL — ПРИБИРАЄМО ХАРДКОДНІ КОЛЬОРИ ===================== */
.pwall {
--bg0: #070b16;
--bg1: #0b1030;
background: radial-gradient(120% 140% at 20% 0%, #101a45 0%, var(--bg0) 55%, #040711 100%);
}
/* ===================== ОПТИМІЗАЦІЯ ЗАВАНТАЖЕННЯ КАРТ ===================== */
.lazy-hidden,
.anime-cards__image .lazy-hidden,
.anime-cards img.lazy-hidden,
.anime-cards img.owl-lazy {
opacity: 1 !important;
}
.lazy-loaded,
.anime-cards img.lazy-loaded,
.anime-cards__image img {
transition: none !important;
opacity: 1 !important;
}
.anime-cards__image {
background: rgba(255,255,255,0.04) !important;
}
/* ===================== SCHEDULE СТОРІНКА ===================== */
body:not(.fscr-active) .page-padding,
body:not(.fscr-active) div.page-padding {
background: rgba(10, 10, 20, 0.22) !important;
backdrop-filter: blur(var(--glass-blur, 18px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 18px)) !important;
border-radius: 12px !important;
border: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
box-sizing: border-box !important;
}
body.fscr-active .page-padding,
body.fscr-active div.page-padding {
background: unset !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
border-radius: 0 !important;
border: none !important;
padding: 0 !important;
margin: 0 !important;
max-width: none !important;
width: 100% !important;
}
/* ===================== DESC БЛОК ===================== */
div.desc {
background: rgba(10, 10, 20, 0.22) !important;
backdrop-filter: blur(var(--glass-blur, 18px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 18px)) !important;
border-radius: 12px !important;
border: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
}
/* ===================== ПАГІНАЦІЯ ===================== */
.pagination_pages a,
.pagination_pages span {
background: rgba(10, 10, 20, 0.35) !important;
border: 1px solid rgba(255,255,255,0.10) !important;
border-radius: 8px !important;
box-shadow: none !important;
transition: background 0.2s ease !important;
}
.pagination_pages a:hover {
background: rgba(255,255,255,0.12) !important;
border-color: rgba(255,255,255,0.20) !important;
}
.pagination__pages > a,
.pagination__pages > span,
.pagination__pages-btn > a,
.pagination__pages-btn > span {
background-color: var(--bg-2) !important;
}
.pagination__pages > span:not(.nav_ext),
.pagination__pages-btn > span {
background: var(--accent) !important;
color: var(--tt-3) !important;
}
/* ===================== SPEEDBAR ===================== */
.speedbar,
div.speedbar,
.speedbar.ws-nowrap {
background: rgba(10, 10, 20, 0.22) !important;
backdrop-filter: blur(var(--glass-blur, 18px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 18px)) !important;
border-radius: 12px !important;
border: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
box-sizing: border-box !important;
padding: 10px 20px !important;
margin: 0 !important;
}
/* ===================== STONE INVENTORY & CARD AWAKENING ===================== */
.stone_inner,
div.stone_inner,
.stone_charge-panel,
div.stone_charge-panel,
.stone_main,
div.stone_main,
.card-awakening-list,
div.card-awakening-list {
background: transparent !important;
background-color: transparent !important;
box-shadow: none !important;
}
.stone_inventory,
div.stone_inventory {
background: transparent !important;
background-color: transparent !important;
box-shadow: none !important;
}
/* ===================== STONE__INVENTORY (double underscore) ===================== */
.stone__inventory {
background-color: transparent !important;
}
/* ===================== TRADE__INVENTORY ===================== */
.trade__inventory {
background-color: transparent !important;
}
/* ===================== BACK LINK ===================== */
.back-link {
display: inline-flex !important;
font-size: 17px !important;
background-color: var(--bg-2) !important;
border-radius: 8px !important;
border: 1px solid rgba(255, 255, 255, 0.07) !important;
padding: 10px !important;
}
/* ===================== MULTIRATING WRAPPER ===================== */
.multirating-wrapper,
div.multirating-wrapper,
.multirating-wrapper.ignore-select {
background: var(--bg-2) !important;
background-color: var(--bg-2) !important;
border: 1px solid rgba(255,255,255,0.07) !important;
border-radius: 12px !important;
box-shadow: none !important;
}
/* ===================== CARD FILTER LIST ===================== */
.card-filter-list,
div.card-filter-list {
background: transparent !important;
background-color: transparent !important;
box-shadow: none !important;
}
/* ===================== CLOUD TAGS ===================== */
.cloud-tags span a {
backdrop-filter: blur(var(--glass-blur, 18px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 18px)) !important;
}
/* ===================== NCOMM AUTHOR ===================== */
.ncomm_author,
div.ncomm_author {
backdrop-filter: blur(var(--glass-blur, 18px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 18px)) !important;
}
/* ===================== NCOMM RATING ===================== */
.ncomm__rating:has(.ratingplus) {
background-color: rgb(40 255 0 / 5%) !important;
color: #00ff19 !important;
border-color: var(--rating-bg-green) !important;
}
.ncomm__rating:has(.ratingminus) {
background-color: rgb(255 0 0 / 5%) !important;
color: #ff0000 !important;
border-color: var(--rating-bg-red) !important;
}
/* ===================== NCARD ABOUT ===================== */
.ncard__about {
border: 1px solid var(--accent) !important;
border-right-color: var(--accent) !important;
border-right-width: 3px !important;
border-left-color: var(--accent) !important;
border-left-width: 3px !important;
background-color: var(--bg-2) !important;
}
/* ===================== NCARD PREMIUM FUNCTION ===================== */
.ncard-premium__function {
background-color: var(--bg-2) !important;
}
/* ===================== LOOTBOX DESCR ===================== */
.lootbox__descr {
border: 10px solid var(--bdc) !important;
border-radius: 8px !important;
}
/* ===================== PBTM INFO ===================== */
.pbtm .pbtm__info {
background-color: var(--bg-2) !important;
}
/* ===================== КІНОТЕАТР: FSCR КОНТЕЙНЕР ===================== */
.fscr-active .fscr {
padding: 0px !important;
gap: 0 0px !important;
}
/* ===================== ПЛЕЄР: БЛОК ОЗВУЧОК ===================== */
.b-translators__block {
background: transparent !important;
box-shadow: none !important;
border: none !important;
}
.pmovie__player-controls {
background: transparent !important;
background-color: transparent !important;
}
/* ===================== ПЛЕЄР: НИЖНІЙ БЛОК КНОПОК ===================== */
#anime-player__controls,
.pbtm__main {
background: rgba(10,10,22,0.82) !important;
backdrop-filter: blur(16px) !important;
-webkit-backdrop-filter: blur(16px) !important;
border: 1px solid rgba(255,255,255,0.07) !important;
border-top: none !important;
border-radius: 0 0 14px 14px !important;
padding: 10px 16px !important;
--indent: 0px !important;
--indent-negative: 0px !important;
}
/* Кнопка "Режим кинотеатра" */
.anime-player__fullscreen-btn {
background: var(--accent, #8b5cf6) !important;
border: none !important;
border-radius: 8px !important;
color: #fff !important;
font-size: 13px !important;
font-weight: 700 !important;
letter-spacing: 0.4px !important;
text-transform: uppercase !important;
padding: 9px 20px !important;
height: auto !important;
min-height: 38px !important;
margin: 0 8px 0 0 !important;
box-shadow: 0 4px 14px rgba(139,92,246,0.35) !important;
transition: opacity 0.18s, transform 0.18s !important;
gap: 8px !important;
flex-shrink: 0 !important;
white-space: nowrap !important;
position: relative !important;
left: auto !important;
}
.anime-player__fullscreen-btn:hover {
opacity: 0.88 !important;
transform: translateY(-1px) !important;
}
/* ===================== КІНОТЕАТР: ХОВАЄМО ТІЛЬКИ ДАЛЕКИЙ КОНТЕНТ ===================== */
body.fscr-active .page__fix-grid,
body.fscr-active .page__stats,
body.fscr-active .page__comments,
body.fscr-active .sect.pmovie__related,
body.fscr-active .pcoln__header,
body.fscr-active .pcoln__poster,
body.fscr-active .pcoln__info,
body.fscr-active .pcoln__info2,
body.fscr-active .page__text,
body.fscr-active .fon-dob,
body.fscr-active .speedbar,
body.fscr-active div.speedbar,
body.fscr-active footer.footer,
body.fscr-active .pbtm__connect {
display: none !important;
}
/* ===================== DECK OWNERS ===================== */
.deck-owners {
background-color: var(--bg-2) !important;
}
/* ===================== CLUB MEMBER NAME ===================== */
.club__member-name {
background-color: var(--bg-2) !important;
border-radius: 8px !important;
border: 1px solid rgba(255, 255, 255, 0.07) !important;
}
/* ===================== TELEGRAM БЛОК ===================== */
.tlgm {
background-color: rgb(0 188 255 / 40%) !important;
}
/* ===================== NCARD TABS BTNS ===================== */
/* Застосовується тільки якщо кнопки навігації увімкнено (перевіряється нижче через JS) */
/* ===================== TOP USERS / NCARD MENU ===================== */
.ncard__menu {
background: rgba(10, 10, 20, 0.40) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 20px)) !important;
border-radius: 12px !important;
border: 1px solid rgba(255,255,255,0.07) !important;
padding: 10px !important;
}
.ncard__menu-tabs {
background: rgba(255,255,255,0.05) !important;
border-radius: 10px !important;
padding: 4px !important;
gap: 4px !important;
}
.ncard__menu-tabs a,
.ncard__menu-tabs .watchlist__sort-active {
border-radius: 8px !important;
border: none !important;
border-bottom: none !important;
padding: 6px 16px !important;
transition: background 0.2s !important;
}
.ncard__menu-tabs .watchlist__sort-active {
background: var(--accent) !important;
color: #fff !important;
border-bottom: none !important;
}
.ncard__menu-content {
background: rgba(255, 255, 255, 0.05) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 20px)) !important;
margin: 0 !important;
border-radius: 10px !important;
}
.ncard__menu-tabs a:not(.watchlist__sort-active):hover {
background: rgba(255,255,255,0.08) !important;
}
/* ===================== USER ANIME PROGRESS TOP ===================== */
.user-anime__progress-top {
background-color: var(--bg-2) !important;
}
/* ===================== МОДАЛЬНІ ВІКНА (ОБМІН) ===================== */
.ui-dialog-titlebar {
border-radius: 16px 16px 0 0 !important;
}
/* ===================== BOSS: прихований старий HP bar ===================== */
.sao-healthbar {
display: none !important;
}
/* ===================== BOSS: новий HP bar ===================== */
.club-boost--boss {
position: relative !important;
}
.boss-wrap, .boss {
position: relative !important;
overflow: hidden !important;
border-radius: 10px !important;
}
#boss-hp-bar-wrap {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 6px 10px 8px;
box-sizing: border-box;
background: rgba(0,0,0,0.6);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
border-top: 1px solid rgba(255,255,255,0.08);
z-index: 10;
}
#boss-hp-bar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 5px;
font-size: 12px;
font-weight: 700;
color: #fff;
text-shadow: 0 1px 3px rgba(0,0,0,0.8);
white-space: nowrap;
gap: 6px;
}
#boss-hp-bar-text {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 11px;
}
#boss-hp-bar-track {
width: 100%;
height: 10px;
border-radius: 999px;
background: rgba(255,255,255,0.15);
overflow: hidden;
box-shadow: inset 0 1px 3px rgba(0,0,0,0.5);
}
#boss-hp-bar-fill {
height: 100%;
border-radius: 999px;
transition: width 0.4s ease, background 0.4s ease;
background: linear-gradient(90deg, #4ade80, #22c55e);
}
#boss-hp-bar-fill.lvl2 {
background: linear-gradient(90deg, #fde047, #f59e0b);
}
#boss-hp-bar-fill.lvl3 {
background: linear-gradient(90deg, #f87171, #ef4444);
}
#boss-hp-bar-level {
display: inline-block;
padding: 1px 6px;
border-radius: 4px;
font-size: 11px;
font-weight: 700;
background: rgba(255,255,255,0.15);
color: #fff;
}
/* ===================== BOSS: кнопки УДАРИТЬ і Найти карту ===================== */
/* Всі правила скоуповані під .is-boss-page — щоб не зачіпати сторінку вкладів */
body.is-boss-page .club-boost--content .club-boost__inner {
width: 100% !important;
}
body.is-boss-page .club-boost--content .club-boost__inner > div[style*="flex"] {
width: 100% !important;
}
body.is-boss-page .mine__boost-btn,
body.is-boss-page .mine__boost__refresh-btn {
flex: 1 !important;
width: 100% !important;
margin-left: 0 !important;
}
body.is-boss-page .club-boost__owners {
width: 100% !important;
}
body.is-boss-page .club-boost__owners a.button--block {
display: block !important;
width: 100% !important;
box-sizing: border-box !important;
text-align: center !important;
}
/* ===================== FOOTER ===================== */
footer.footer {
background: rgba(10, 10, 20, 0.45) !important;
backdrop-filter: blur(var(--glass-blur, 20px)) !important;
-webkit-backdrop-filter: blur(var(--glass-blur, 20px)) !important;
border-top: 1px solid rgba(255,255,255,0.07) !important;
box-shadow: none !important;
border-radius: 12px !important;
overflow: hidden !important;
}
/* ── Фон карток друзів / профілю ── */
div[id*="ajax-friend-container"] {
background: rgba(15, 12, 28, 0.65) !important;
backdrop-filter: blur(8px) !important;
-webkit-backdrop-filter: blur(8px) !important;
border: 1px solid rgba(255,255,255,0.06) !important;
border-radius: 10px !important;
box-shadow: none !important;
overflow: hidden !important;
}
div[id*="ajax-friend-container"]:hover {
background: rgba(30, 20, 55, 0.75) !important;
border-color: rgba(139,92,246,0.25) !important;
}
/* Прибираємо рамки з вкладених card-inline елементів */
div[id*="ajax-friend-container"] .card-inline,
div[id*="ajax-friend-container"] [class*="card-inline"] {
background: none !important;
border: none !important;
box-shadow: none !important;
backdrop-filter: none !important;
border-radius: 0 !important;
}
`);
}); // end domReady
// ===================== BOSS PAGE: фільтр нотифікацій =====================
// Запускається одразу (поза domReady) — перехоплює DLEPush до першого кліку
(function bossPushFilter() {
const path = window.location.pathname;
const isBoss = path.includes('boss_inv');
const isMine = path.includes('clubs/boost') || path.includes('clubs_boost');
if (!isBoss && !isMine) return;
// Ставимо клас на body тільки для сторінки боса — CSS-правила кнопок скоуповані під нього
if (isBoss) {
if (document.body) {
document.body.classList.add('is-boss-page');
} else {
document.addEventListener('DOMContentLoaded', function() {
document.body.classList.add('is-boss-page');
});
}
}
// Тексти які повністю приховуємо
const HIDE_TEXTS = [
'промахнул',
'Слишком часто',
'Нужная в событии',
'Нужная клубу',
'Неизвестная ошибка',
'Ошибка сервера',
'опередили',
];
function shouldHide(text) {
return HIDE_TEXTS.some(function(s) { return String(text).includes(s); });
}
// --- Метод 1: замінюємо DLEPush методи ---
function doIntercept() {
if (typeof DLEPush === 'undefined' || typeof DLEPush.warning !== 'function') {
setTimeout(doIntercept, 150);
return;
}
const _warn = DLEPush.warning.bind(DLEPush);
const _info = DLEPush.info.bind(DLEPush);
DLEPush.warning = function(msg) {
const stunMatch = String(msg).match(/(\d+)\s*сек/i);
if (stunMatch && String(msg).toLowerCase().includes('оглушени')) {
showStunCountdown(parseInt(stunMatch[1]));
return;
}
if (shouldHide(msg)) return;
_warn(msg);
};
DLEPush.info = function(msg) {
if (String(msg).includes('промахнул')) return;
_info(msg);
};
}
doIntercept();
// --- Метод 2 (ядерний): MutationObserver видаляє нотифікацію з DOM ---
// Спрацьовує навіть якщо DLEPush обходить наш перехват
function startDOMFilter() {
// Шукаємо тільки відомі контейнери нотифікацій
var container = document.getElementById('acm-notification-container')
|| document.querySelector('.acm-container');
if (container) {
attachFilter(container);
return;
}
// Контейнер ще не існує — чекаємо тільки прямих дітей body (НЕ subtree)
// і обмежуємо час очікування 10 секундами щоб не вічно висіти
var deadline = Date.now() + 10000;
var bodyObs = new MutationObserver(function() {
if (Date.now() > deadline) { bodyObs.disconnect(); return; }
var c = document.getElementById('acm-notification-container')
|| document.querySelector('.acm-container');
if (c) { bodyObs.disconnect(); attachFilter(c); }
});
// childList:true, subtree:false — тільки прямі діти body, не весь DOM
bodyObs.observe(document.body, { childList: true });
}
function attachFilter(container) {
var obs = new MutationObserver(function(mutations) {
mutations.forEach(function(m) {
m.addedNodes.forEach(function(node) {
if (node.nodeType !== 1) return;
var text = node.textContent || node.innerText || '';
// Оглушення — перехоплюємо і показуємо свій відлік
var stunMatch = text.match(/(\d+)\s*сек/i);
if (stunMatch && text.toLowerCase().includes('оглушени')) {
node.remove();
showStunCountdown(parseInt(stunMatch[1]));
return;
}
// Приховуємо непотрібне
if (shouldHide(text)) {
node.remove();
}
});
});
});
obs.observe(container, { childList: true });
}
// Запускаємо DOM-фільтр після того як body готовий
if (document.body) {
startDOMFilter();
} else {
document.addEventListener('DOMContentLoaded', startDOMFilter);
}
})();
// Зберігаємо абсолютний час закінчення стану
var _stunTimer = null;
function showStunCountdown(seconds) {
// Якщо таймер вже тіче — оновлюємо тільки лічильник, не дублюємо блок
if (_stunTimer) {
var existingEl = document.getElementById('boss-stun-countdown');
if (existingEl) return;
clearInterval(_stunTimer);
_stunTimer = null;
}
// Створюємо власний фіксований оверлей незалежно від DLEPush контейнера
var el = document.createElement('div');
el.id = 'boss-stun-countdown';
el.style.cssText = [
'position:fixed',
'top:70px',
'left:50%',
'transform:translateX(-50%)',
'z-index:99999',
'background:linear-gradient(145deg,rgba(250,166,26,0.97),rgba(200,80,0,0.97))',
'color:#fff',
'padding:12px 28px',
'border-radius:12px',
'font-size:15px',
'font-weight:bold',
'text-align:center',
'box-shadow:0 6px 24px rgba(0,0,0,0.5)',
'pointer-events:none',
'white-space:nowrap',
'letter-spacing:0.5px',
'transition:opacity 0.4s ease',
].join(';');
document.body.appendChild(el);
var remaining = seconds;
el.textContent = '⚡ Вас контузило — ' + remaining + 'с';
_stunTimer = setInterval(function() {
remaining--;
if (remaining <= 0) {
clearInterval(_stunTimer);
_stunTimer = null;
el.style.opacity = '0';
setTimeout(function() { if (el.parentNode) el.remove(); }, 420);
} else {
el.textContent = '⚡ Вас контузило — ' + remaining + 'с';
}
}, 1000);
}
// ===================== BOSS: новий HP bar =====================
(function bossHPBar() {
if (!window.location.pathname.includes('boss_inv')) return;
var MAX_HP = 100000;
function getLvl(hp) {
if (hp > 65000) return 1;
if (hp > 30000) return 2;
return 3;
}
function formatHP(n) {
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
}
// Читаємо живий HP безпосередньо з оригінального SAO бару який сайт вже оновлює
// #hpFill має CSS-змінні --health і --max-health встановлені через style.setProperty
function readLiveHP() {
// Спосіб 1: getBossHP() якщо доступний
if (typeof window.getBossHP === 'function') {
return window.getBossHP();
}
// Спосіб 2: читаємо --health з #hpFill (живі CSS-змінні)
var hpFill = document.getElementById('hpFill');
if (hpFill) {
var val = hpFill.style.getPropertyValue('--health');
if (val) {
var n = parseInt(val, 10);
if (!isNaN(n)) return n;
}
}
// Спосіб 3: fallback — data-damage (статичний, тільки при завантаженні)
var bossEl = document.getElementById('boss') || document.querySelector('.boss');
var damage = bossEl ? parseInt(bossEl.getAttribute('data-damage') || '0', 10) : 0;
return Math.max(0, MAX_HP - damage);
}
function createBar() {
var bossWrap = document.querySelector('.boss-wrap') || document.querySelector('.boss') || document.querySelector('.club-boost--boss');
if (!bossWrap || document.getElementById('boss-hp-bar-wrap')) return;
var wrap = document.createElement('div');
wrap.id = 'boss-hp-bar-wrap';
wrap.innerHTML = [
'<div id="boss-hp-bar-header">',
'<span id="boss-hp-bar-text">HP: ...</span>',
'<span id="boss-hp-bar-level">LVL 1</span>',
'</div>',
'<div id="boss-hp-bar-track">',
'<div id="boss-hp-bar-fill"></div>',
'</div>',
].join('');
bossWrap.style.position = 'relative';
bossWrap.style.overflow = 'hidden';
bossWrap.appendChild(wrap);
updateBar();
}
function updateBar() {
var fill = document.getElementById('boss-hp-bar-fill');
var text = document.getElementById('boss-hp-bar-text');
var lvlEl = document.getElementById('boss-hp-bar-level');
if (!fill || !text || !lvlEl) return;
var hp = readLiveHP();
var pct = Math.max(0, Math.min(100, (hp / MAX_HP) * 100));
var lvl = getLvl(hp);
fill.style.width = pct.toFixed(2) + '%';
fill.className = lvl === 1 ? '' : (lvl === 2 ? 'lvl2' : 'lvl3');
text.textContent = 'HP: ' + formatHP(hp);
lvlEl.textContent = 'LVL ' + lvl;
}
// Хукаємо setBossDamage для миттєвого відгуку при кліку
function hookDamage() {
if (typeof window.setBossDamage !== 'function') {
setTimeout(hookDamage, 200);
return;
}
var _orig = window.setBossDamage;
window.setBossDamage = function(damage, withAnim) {
var result = _orig.apply(this, arguments);
// Затримка 50мс — оригінал встигає оновити hp
setTimeout(updateBar, 50);
return result;
};
}
// MutationObserver на #hpFill — реагує на зміну style (--health змінна)
// Це найнадійніший спосіб: саме туди сайт пише живий HP
function watchSaoBar() {
function attach() {
var hpFill = document.getElementById('hpFill');
if (!hpFill) { setTimeout(attach, 300); return; }
// Спостерігаємо тільки за атрибутом style на самому #hpFill — без subtree
var obs = new MutationObserver(function() {
updateBar();
});
obs.observe(hpFill, { attributes: true, attributeFilter: ['style'] });
}
attach();
}
// Polling як останній fallback — кожні 500мс
function startPolling() {
setInterval(updateBar, 500);
}
function init() {
var bossBlock = document.querySelector('.club-boost--boss');
if (!bossBlock) { setTimeout(init, 300); return; }
createBar();
hookDamage();
watchSaoBar();
startPolling();
}
init();
})();
// ===================== SETTINGS PAGE: Glass UI редизайн =====================
(function settingsPageRedesign() {
if (!document.querySelector('#options.settings-page')) return;
GM_addStyle(`
/* ── Загальна обгортка — повна ширина як в оригіналі ── */
.settings-page {
max-width: 100% !important;
width: 100% !important;
padding-bottom: 80px !important;
}
/* ── Таб-навігація ── */
.ncard__tabs {
background: rgba(10, 10, 22, 0.82) !important;
backdrop-filter: blur(20px) !important;
-webkit-backdrop-filter: blur(20px) !important;
border: 1px solid rgba(255,255,255,0.08) !important;
border-radius: 14px !important;
padding: 10px 14px !important;
margin-bottom: 14px !important;
flex-wrap: wrap !important;
}
.ncard__tabs-btns {
flex-wrap: wrap !important;
gap: 6px !important;
}
.ncard__tabs-btn {
background: rgba(255,255,255,0.06) !important;
border: 1px solid rgba(255,255,255,0.10) !important;
color: rgba(255,255,255,0.60) !important;
border-radius: 9px !important;
padding: 8px 16px !important;
font-size: 13px !important;
font-weight: 600 !important;
letter-spacing: 0.3px !important;
transition: all 0.18s ease !important;
text-transform: none !important;
}
.ncard__tabs-btn:hover {
background: rgba(255,255,255,0.12) !important;
color: rgba(255,255,255,0.90) !important;
border-color: rgba(255,255,255,0.18) !important;
}
.ncard__tabs-btn.is-active {
background: var(--accent, #8b5cf6) !important;
border-color: transparent !important;
color: #fff !important;
box-shadow: 0 4px 14px rgba(139,92,246,0.35) !important;
}
/* ── Панелі налаштувань — повна ширина ── */
.settings-panels {
margin-top: 0 !important;
width: 100% !important;
}
.settings-panel {
background: rgba(10, 10, 22, 0.82) !important;
backdrop-filter: blur(20px) !important;
-webkit-backdrop-filter: blur(20px) !important;
border: 1px solid rgba(255,255,255,0.08) !important;
border-radius: 14px !important;
overflow: hidden !important;
width: 100% !important;
}
/* ── Рядки форми — зберігаємо оригінальний grid ── */
.settings-form-row {
background: transparent !important;
border-bottom: 1px solid rgba(255,255,255,0.06) !important;
padding: 24px 26px !important;
gap: 24px !important;
grid-template-columns: 240px minmax(0,1fr) !important;
}
.settings-form-row:last-child {
border-bottom: 0 !important;
}
/* ── Лейбли ── */
.settings-form-label {
font-size: 11px !important;
font-weight: 700 !important;
text-transform: uppercase !important;
letter-spacing: 0.9px !important;
color: rgba(255,255,255,0.45) !important;
padding-top: 6px !important;
}
.settings-form-label label {
color: inherit !important;
font: inherit !important;
}
/* ── Інпути ── */
.settings-form-control > input[type="text"],
.settings-form-control > input[type="password"],
.settings-form-control > textarea,
.settings-form-control > select,
.settings-form-control > .twofactorselect {
background: rgba(255,255,255,0.07) !important;
border: 1px solid rgba(255,255,255,0.12) !important;
border-radius: 10px !important;
color: rgba(255,255,255,0.85) !important;
font-size: 15px !important;
min-height: 52px !important;
padding: 0 14px !important;
transition: border-color 0.2s, background 0.2s, box-shadow 0.2s !important;
box-shadow: none !important;
}
.settings-form-control > textarea {
min-height: 108px !important;
padding: 13px 14px !important;
resize: vertical !important;
}
.settings-form-control > input[type="text"]:focus,
.settings-form-control > input[type="password"]:focus,
.settings-form-control > textarea:focus,
.settings-form-control > select:focus,
.settings-form-control > .twofactorselect:focus {
background: rgba(255,255,255,0.10) !important;
border-color: var(--accent, #8b5cf6) !important;
box-shadow: 0 0 0 3px rgba(139,92,246,0.18) !important;
outline: none !important;
}
.settings-form-control > input::placeholder,
.settings-form-control > textarea::placeholder {
color: rgba(255,255,255,0.25) !important;
}
/* ── Нотатки ── */
.settings-form-note {
color: rgba(255,255,255,0.30) !important;
font-size: 13px !important;
margin-top: 9px !important;
line-height: 1.6 !important;
}
/* ── Чекбокси ── */
.settings-checkbox-list {
gap: 11px !important;
}
.settings-checkbox-item {
font-size: 14px !important;
color: rgba(255,255,255,0.75) !important;
gap: 10px !important;
}
.settings-checkbox-item input[type="checkbox"] {
accent-color: var(--accent, #8b5cf6) !important;
width: 16px !important;
height: 16px !important;
}
.settings-checkbox-item label {
color: rgba(255,255,255,0.75) !important;
}
/* ── select / twofactorselect ── */
.twofactorselect,
.settings-form-control > select {
appearance: none !important;
-webkit-appearance: none !important;
cursor: pointer !important;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='rgba(255,255,255,0.45)' stroke-width='2.5'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") !important;
background-repeat: no-repeat !important;
background-position: right 14px center !important;
padding-right: 36px !important;
}
.twofactorselect option,
.settings-form-control > select option {
background: #16162a !important;
color: #fff !important;
}
/* ── Telegram-блоки ── */
.profile-telegram-attached,
.profile-telegram-connect {
background: rgba(255,255,255,0.06) !important;
border: 1px solid rgba(255,255,255,0.10) !important;
border-radius: 10px !important;
color: rgba(255,255,255,0.75) !important;
}
.settings-link-inline,
.settings-link-inline a {
color: var(--accent, #8b5cf6) !important;
}
.settings-danger-zone a {
color: #f87171 !important;
}
/* ── Кнопка збереження ── */
.settings-submit-bar {
position: sticky !important;
bottom: 20px !important;
z-index: 30 !important;
display: flex !important;
justify-content: flex-end !important;
padding-top: 14px !important;
margin-top: 10px !important;
}
.settings-submit-bar .form__btn,
.settings-submit-bar button[type="submit"] {
background: var(--accent, #8b5cf6) !important;
border: none !important;
border-radius: 10px !important;
color: #fff !important;
font-size: 13px !important;
font-weight: 700 !important;
letter-spacing: 0.5px !important;
text-transform: uppercase !important;
padding: 12px 36px !important;
min-width: 180px !important;
cursor: pointer !important;
box-shadow: 0 4px 16px rgba(139,92,246,0.40) !important;
transition: opacity 0.18s, transform 0.18s, box-shadow 0.18s !important;
}
.settings-submit-bar .form__btn:hover,
.settings-submit-bar button[type="submit"]:hover {
opacity: 0.88 !important;
transform: translateY(-1px) !important;
box-shadow: 0 6px 22px rgba(139,92,246,0.50) !important;
}
/* ── Аватари/фони з колекції ── */
.profile-images-list {
background: rgba(255,255,255,0.04) !important;
border: 1px solid rgba(255,255,255,0.07) !important;
border-radius: 10px !important;
padding: 8px !important;
}
.profile-images-list .image__item {
border: 2px solid rgba(255,255,255,0.08) !important;
border-radius: 8px !important;
overflow: hidden !important;
transition: border-color 0.18s, transform 0.18s !important;
cursor: pointer !important;
}
.profile-images-list .image__item:hover {
border-color: var(--accent, #8b5cf6) !important;
transform: scale(1.04) !important;
}
.profile-images-list .image__item[style*="#f60"] {
border-color: var(--accent, #8b5cf6) !important;
box-shadow: 0 0 0 2px rgba(139,92,246,0.40) !important;
}
/* ── Кнопка Imпорт Shikimori ── */
.blue-btn.small {
background: rgba(255,255,255,0.08) !important;
border: 1px solid rgba(255,255,255,0.14) !important;
color: rgba(255,255,255,0.75) !important;
border-radius: 8px !important;
padding: 9px 16px !important;
font-size: 13px !important;
font-weight: 600 !important;
transition: background 0.18s, color 0.18s !important;
}
.blue-btn.small:hover {
background: var(--accent, #8b5cf6) !important;
color: #fff !important;
border-color: transparent !important;
}
/* ── Мобільна версія ── */
@media (max-width: 768px) {
.settings-form-row {
grid-template-columns: 1fr !important;
gap: 10px !important;
padding: 16px 14px !important;
}
.settings-form-label {
padding-top: 0 !important;
font-size: 13px !important;
}
.ncard__tabs {
padding: 8px 10px !important;
}
.ncard__tabs-btn {
font-size: 11px !important;
padding: 6px 10px !important;
}
}
`);
// ── Замінюємо input[type=file] на Glass-кнопку ──
function replaceFileInput() {
const fileInput = document.querySelector('input[type="file"]#image');
if (!fileInput || fileInput.dataset.glassReplaced) return;
fileInput.dataset.glassReplaced = '1';
// Ховаємо нативний інпут повністю
fileInput.style.cssText = `
position: absolute !important;
opacity: 0 !important;
width: 0 !important;
height: 0 !important;
pointer-events: none !important;
`;
// Контейнер з кнопкою + назвою файлу
const wrapper = document.createElement('div');
wrapper.style.cssText = `
display: flex;
align-items: center;
gap: 12px;
min-height: 52px;
`;
const btn = document.createElement('button');
btn.type = 'button';
btn.textContent = '📁 Вибрати файл';
btn.style.cssText = `
flex-shrink: 0;
padding: 10px 20px;
background: var(--accent, #8b5cf6);
border: none;
border-radius: 10px;
color: #fff;
font-size: 13px;
font-weight: 700;
letter-spacing: 0.4px;
text-transform: uppercase;
cursor: pointer;
box-shadow: 0 4px 14px rgba(139,92,246,0.40);
transition: opacity 0.18s, transform 0.18s;
white-space: nowrap;
`;
btn.addEventListener('mouseenter', () => { btn.style.opacity = '0.85'; btn.style.transform = 'translateY(-1px)'; });
btn.addEventListener('mouseleave', () => { btn.style.opacity = '1'; btn.style.transform = 'translateY(0)'; });
btn.addEventListener('click', () => fileInput.click());
const label = document.createElement('span');
label.textContent = 'Файл не вибрано';
label.style.cssText = `
color: rgba(255,255,255,0.35);
font-size: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
fileInput.addEventListener('change', () => {
label.textContent = fileInput.files.length
? fileInput.files[0].name
: 'Файл не вибрано';
label.style.color = fileInput.files.length
? 'rgba(255,255,255,0.80)'
: 'rgba(255,255,255,0.35)';
});
wrapper.appendChild(btn);
wrapper.appendChild(label);
// Вставляємо wrapper після прихованого інпуту
fileInput.parentNode.insertBefore(wrapper, fileInput.nextSibling);
}
// Запускаємо після рендеру
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', replaceFileInput);
} else {
replaceFileInput();
}
// ── Замінюємо чекбокси на повзунки (зелений/червоний) ──
GM_addStyle(`
/* Ховаємо оригінальний чекбокс */
.settings-checkbox-item input[type="checkbox"].gs-hidden-cb {
position: absolute !important;
opacity: 0 !important;
width: 0 !important;
height: 0 !important;
pointer-events: none !important;
}
/* Обгортка повзунка */
.gs-toggle-wrap {
position: relative;
display: inline-block;
flex-shrink: 0;
width: 44px;
height: 24px;
cursor: pointer;
}
/* Трек */
.gs-toggle-track {
position: absolute;
inset: 0;
border-radius: 12px;
background: rgba(244,67,54,0.28);
border: 1px solid rgba(244,67,54,0.55);
transition: background 0.22s, border-color 0.22s;
}
/* Кулька */
.gs-toggle-thumb {
position: absolute;
top: 3px;
left: 3px;
width: 18px;
height: 18px;
border-radius: 50%;
background: #F44336;
box-shadow: 0 1px 4px rgba(0,0,0,0.45);
transition: transform 0.22s cubic-bezier(.4,0,.2,1), background 0.22s;
}
/* Стан: увімкнено */
.gs-toggle-wrap.is-on .gs-toggle-track {
background: rgba(60,206,123,0.28);
border-color: rgba(60,206,123,0.55);
}
.gs-toggle-wrap.is-on .gs-toggle-thumb {
background: #3CCE7B;
transform: translateX(20px);
}
/* Лейбл в .settings-checkbox-item */
.settings-checkbox-item {
align-items: center !important;
}
.settings-checkbox-item label {
cursor: pointer !important;
}
`);
function replaceCheckboxes() {
document.querySelectorAll('.settings-checkbox-item input[type="checkbox"]').forEach(function(cb) {
if (cb.dataset.gsReplaced) return;
cb.dataset.gsReplaced = '1';
// Ховаємо оригінальний
cb.classList.add('gs-hidden-cb');
// Будуємо повзунок
const wrap = document.createElement('span');
wrap.className = 'gs-toggle-wrap' + (cb.checked ? ' is-on' : '');
const track = document.createElement('span');
track.className = 'gs-toggle-track';
const thumb = document.createElement('span');
thumb.className = 'gs-toggle-thumb';
wrap.appendChild(track);
wrap.appendChild(thumb);
// Вставляємо одразу після чекбоксу
cb.parentNode.insertBefore(wrap, cb.nextSibling);
// Клік по повзунку або по label — перемикає
function toggleState() {
cb.checked = !cb.checked;
wrap.classList.toggle('is-on', cb.checked);
// Тригер change для сайту
cb.dispatchEvent(new Event('change', { bubbles: true }));
}
wrap.addEventListener('click', toggleState);
// Клік по label теж має перемикати (label вже linked через for/id або є parent)
const lbl = cb.closest('.settings-checkbox-item')
? cb.closest('.settings-checkbox-item').querySelector('label')
: null;
if (lbl) {
// Відв'язуємо нативну прив'язку label→checkbox щоб уникнути подвійного спрацювання
const forAttr = lbl.getAttribute('for');
if (forAttr) {
lbl.removeAttribute('for');
lbl.dataset.gsCbId = forAttr;
lbl.style.cursor = 'pointer';
lbl.addEventListener('click', toggleState);
}
}
// Синхронізуємо якщо стан змінився ззовні
cb.addEventListener('change', function() {
wrap.classList.toggle('is-on', cb.checked);
});
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', replaceCheckboxes);
} else {
replaceCheckboxes();
}
})();
// ===================== ACHIEVEMENTS SHOWCASE: Glass UI редизайн =====================
(function achievementsRedesign() {
if (!window.location.pathname.includes('achievements_showcase')) return;
GM_addStyle(`
/* ── Таб-навігація ── */
.ncard__tabs {
background: rgba(10, 10, 22, 0.82) !important;
backdrop-filter: blur(20px) !important;
-webkit-backdrop-filter: blur(20px) !important;
border: 1px solid rgba(255,255,255,0.08) !important;
border-radius: 14px !important;
padding: 10px 14px !important;
margin-bottom: 18px !important;
flex-wrap: wrap !important;
}
.ncard__tabs-btns { flex-wrap: wrap !important; gap: 6px !important; }
.ncard__tabs-btn {
background: rgba(255,255,255,0.06) !important;
border: 1px solid rgba(255,255,255,0.10) !important;
color: rgba(255,255,255,0.60) !important;
border-radius: 9px !important;
padding: 8px 16px !important;
font-size: 13px !important;
font-weight: 600 !important;
letter-spacing: 0.3px !important;
transition: all 0.18s ease !important;
text-transform: none !important;
}
.ncard__tabs-btn:hover {
background: rgba(255,255,255,0.12) !important;
color: rgba(255,255,255,0.90) !important;
}
.ncard__tabs-btn.is-active {
background: var(--accent, #8b5cf6) !important;
border-color: transparent !important;
color: #fff !important;
box-shadow: 0 4px 14px rgba(139,92,246,0.35) !important;
}
/* ── Заголовок ── */
.ncard__main-title {
color: rgba(255,255,255,0.92) !important;
font-size: 20px !important;
letter-spacing: 0.3px !important;
margin-bottom: 0 !important;
}
/* ── Обгортка всієї витрини ── */
.showcase {
background: rgba(10, 10, 22, 0.75) !important;
backdrop-filter: blur(16px) !important;
-webkit-backdrop-filter: blur(16px) !important;
border: 1px solid rgba(255,255,255,0.07) !important;
border-radius: 14px !important;
padding: 16px 52px !important;
position: relative !important;
}
/* ── Слоти витрини (НЕ чіпаємо flex/display owl-carousel) ── */
.showcase__item__arch {
border-radius: 12px !important;
border: 2px solid rgba(255,255,255,0.08) !important;
background: rgba(255,255,255,0.04) !important;
transition: border-color 0.18s, transform 0.18s !important;
overflow: hidden !important;
}
.showcase__item__arch:hover {
border-color: rgba(139,92,246,0.50) !important;
transform: scale(1.05) !important;
}
.showcase__item__arch img {
border-radius: 10px !important;
object-fit: contain !important;
}
/* ── Стрілки owl-carousel ── */
.owl-prev, .owl-next {
background: rgba(10,10,22,0.80) !important;
border: 1px solid rgba(255,255,255,0.12) !important;
border-radius: 50% !important;
width: 34px !important;
height: 34px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
color: rgba(255,255,255,0.70) !important;
transition: background 0.18s !important;
}
.owl-prev:hover, .owl-next:hover {
background: rgba(139,92,246,0.35) !important;
color: #fff !important;
}
/* ── Блок налаштувань (нижня частина) ── */
.settings__inner {
background: rgba(10, 10, 22, 0.75) !important;
backdrop-filter: blur(16px) !important;
-webkit-backdrop-filter: blur(16px) !important;
border: 1px solid rgba(255,255,255,0.07) !important;
border-radius: 14px !important;
padding: 16px !important;
}
/* ── Список ачивок для вибору ── */
.card-filter-list {
background: transparent !important;
border-radius: 10px !important;
overflow-y: auto !important;
padding: 0 !important;
margin: 0 !important;
}
.card-filter-list__items {
display: grid !important;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)) !important;
gap: 12px !important;
padding: 4px !important;
}
.card-filter-list__card {
background: rgba(255,255,255,0.04) !important;
border: 2px solid rgba(255,255,255,0.07) !important;
border-radius: 12px !important;
padding: 8px !important;
cursor: pointer !important;
transition: border-color 0.18s, background 0.18s, transform 0.18s !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
aspect-ratio: 1 / 1 !important;
overflow: hidden !important;
}
.card-filter-list__card:hover {
border-color: rgba(139,92,246,0.55) !important;
background: rgba(139,92,246,0.10) !important;
transform: translateY(-2px) scale(1.03) !important;
}
.card-filter-list__card img {
width: 100% !important;
height: 100% !important;
object-fit: contain !important;
border-radius: 8px !important;
display: block !important;
/* скасовуємо старий фіксований розмір з вбудованого CSS */
width: unset !important;
height: unset !important;
max-width: 100% !important;
max-height: 100% !important;
}
/* ── Кнопка Зберегти — з відступом зверху ── */
.d-flex.jc-center {
margin-top: 20px !important;
}
.showcase__save-btn-arch {
background: var(--accent, #8b5cf6) !important;
border: none !important;
border-radius: 12px !important;
color: #fff !important;
font-size: 14px !important;
font-weight: 700 !important;
letter-spacing: 0.5px !important;
text-transform: uppercase !important;
padding: 14px 48px !important;
min-width: 200px !important;
height: auto !important;
cursor: pointer !important;
box-shadow: 0 4px 18px rgba(139,92,246,0.40) !important;
transition: opacity 0.18s, transform 0.18s !important;
}
.showcase__save-btn-arch:hover {
opacity: 0.88 !important;
transform: translateY(-1px) !important;
}
/* ── Scrollbar для card-filter-list ── */
.card-filter-list::-webkit-scrollbar { width: 4px !important; }
.card-filter-list::-webkit-scrollbar-thumb {
background: rgba(139,92,246,0.35) !important;
border-radius: 4px !important;
}
`);
})();
})();
// ===================== CARDS PAGE: Glass UI таб-панелі v2 =====================
(function cardsPageTabs() {
// Активуємо тільки на сторінках з картками
if (!document.querySelector('.tabs__nav.tab__menu') &&
!document.querySelector('.ncard__tabs-btns')) return;
// Читаємо стан тоггла напряму з GM_getValue (IIFE поза domReady)
const _cardsUiEnabled = GM_getValue('glassui_cards_ui', true);
const _ncardEnabled = GM_getValue('glassui_ncard_tabs', true);
// ── CSS ──────────────────────────────────────────────────────────────────
GM_addStyle(`
/* ── .ncard__tabs (верхня і нижня nav-панель) ── */
${_ncardEnabled ? `
.ncard__tabs {
background: rgba(10,10,22,0.84) !important;
backdrop-filter: blur(20px) !important;
-webkit-backdrop-filter: blur(20px) !important;
border: 1px solid rgba(255,255,255,0.08) !important;
border-radius: 14px !important;
padding: 8px 12px !important;
flex-wrap: wrap !important;
}
.ncard__tabs-btns { flex-wrap: wrap !important; gap: 5px !important; background-color: var(--bg-2) !important; }
.ncard__tabs .ncard__tabs-btn,
.ncard__tabs a.ncard__tabs-btn,
.ncard__tabs button.ncard__tabs-btn {
background: var(--bg-2) !important;
border: 1px solid rgba(255,255,255,0.08) !important;
color: var(--tt) !important;
border-radius: 8px !important;
padding: 8px 16px !important;
font-size: 13px !important;
font-weight: 600 !important;
letter-spacing: 0.2px !important;
transition: background 0.18s, color 0.18s, border-color 0.18s !important;
text-transform: none !important;
height: auto !important;
line-height: 1.5 !important;
}
.ncard__tabs .ncard__tabs-btn:hover,
.ncard__tabs a.ncard__tabs-btn:hover,
.ncard__tabs button.ncard__tabs-btn:hover {
background: var(--accent) !important;
color: #fff !important;
border-color: transparent !important;
}
.ncard__tabs .ncard__tabs-btn.is-active,
.ncard__tabs a.ncard__tabs-btn.is-active,
.ncard__tabs button.ncard__tabs-btn.is-active {
background: var(--accent) !important;
border-color: transparent !important;
color: #fff !important;
box-shadow: 0 3px 12px rgba(139,92,246,.35) !important;
}
` : ``}
/* ── Sort-block: ховаємо в кастомному дизайні, видно тільки в стандартному ── */
${_cardsUiEnabled ? `` : ``}
/* ── Обгортка для рангів + зірок ── */
#gs-rank-wrap {
display: flex !important;
flex-direction: column !important;
gap: 8px !important;
box-sizing: border-box !important;
min-width: 0 !important;
}
/* ── Рядок рангів — плаский flex ── */
#gs-rank-row {
display: flex !important;
flex-wrap: wrap !important;
align-items: center !important;
gap: 5px !important;
background: rgba(10,10,22,0.84) !important;
backdrop-filter: blur(20px) !important;
-webkit-backdrop-filter: blur(20px) !important;
border: 1px solid rgba(255,255,255,0.08) !important;
border-radius: 14px !important;
padding: 8px 10px !important;
box-sizing: border-box !important;
min-width: 0 !important;
}
/* Роздільник між рангами і замочками */
.gs-sep {
display: inline-block !important;
width: 1px !important;
height: 20px !important;
background: rgba(255,255,255,0.12) !important;
margin: 0 2px !important;
flex-shrink: 0 !important;
align-self: center !important;
}
/* ── Рядок зірок ── */
#gs-stars-row {
display: flex !important;
flex-wrap: wrap !important;
align-items: center !important;
gap: 5px !important;
background: rgba(10,10,22,0.72) !important;
backdrop-filter: blur(16px) !important;
-webkit-backdrop-filter: blur(16px) !important;
border: 1px solid rgba(255,255,255,0.06) !important;
border-radius: 12px !important;
padding: 6px 12px !important;
box-sizing: border-box !important;
min-width: 0 !important;
}
#gs-stars-row .gs-label {
font-size: 10px !important;
font-weight: 700 !important;
text-transform: uppercase !important;
letter-spacing: 0.8px !important;
color: rgba(255,200,50,0.55) !important;
margin-right: 4px !important;
}
/* ── Загальна кнопка рангу/замочку/іконки ── */
.gs-btn {
display: inline-flex !important;
align-items: center !important;
gap: 5px !important;
border-radius: 8px !important;
padding: 7px 13px !important;
font-size: 13px !important;
font-weight: 700 !important;
letter-spacing: 0.3px !important;
cursor: pointer !important;
transition: background 0.18s, border-color 0.18s, color 0.18s, box-shadow 0.18s !important;
border: 1px solid rgba(255,255,255,0.09) !important;
line-height: 1.4 !important;
text-transform: uppercase !important;
color: rgba(255,255,255,0.65) !important;
background: rgba(255,255,255,0.06) !important;
}
.gs-btn:hover {
background: rgba(255,255,255,0.16) !important;
color: #fff !important;
border-color: rgba(255,255,255,0.22) !important;
}
/* ВСЕ — активна */
.gs-btn[data-rank=""].gs-active {
background: #4a2090 !important;
border-color: var(--accent,#8b5cf6) !important;
color: #fff !important;
box-shadow: 0 3px 10px rgba(139,92,246,.35) !important;
}
/* ── Кольори рангів ── */
.gs-btn[data-rank="sss"] { background:rgba(30,30,30,.35) !important; border-color:rgba(200,200,200,.2) !important; color:rgba(220,220,220,.85) !important; }
.gs-btn[data-rank="sss"]:hover { background:rgba(50,50,50,.65) !important; color:#fff !important; border-color:rgba(200,200,200,.4) !important; }
.gs-btn[data-rank="sss"].gs-active { background:#1a1a1a !important; border-color:#666 !important; color:#fff !important; box-shadow:0 3px 8px rgba(0,0,0,.5) !important; }
.gs-btn[data-rank="ass"] { background:rgba(80,20,150,.20) !important; border-color:rgba(130,60,220,.35) !important; color:rgba(180,120,255,.9) !important; }
.gs-btn[data-rank="ass"]:hover { background:rgba(80,20,160,.40) !important; color:#d4aaff !important; border-color:rgba(130,60,220,.6) !important; }
.gs-btn[data-rank="ass"].gs-active { background:#3d1a70 !important; border-color:#7b40d8 !important; color:#d4aaff !important; box-shadow:0 3px 8px rgba(100,40,200,.4) !important; }
.gs-btn[data-rank="s"] { background:rgba(70,50,140,.20) !important; border-color:rgba(140,110,255,.35) !important; color:rgba(180,160,255,.9) !important; }
.gs-btn[data-rank="s"]:hover { background:rgba(85,64,160,.40) !important; color:#e8e0ff !important; border-color:rgba(140,110,255,.6) !important; }
.gs-btn[data-rank="s"].gs-active { background:#5540a0 !important; border-color:#9070e0 !important; color:#e8e0ff !important; box-shadow:0 3px 8px rgba(85,64,160,.45) !important; }
.gs-btn[data-rank="a"] { background:rgba(140,20,20,.20) !important; border-color:rgba(220,60,60,.35) !important; color:rgba(255,120,120,.9) !important; }
.gs-btn[data-rank="a"]:hover { background:rgba(140,20,20,.40) !important; color:#ffaaaa !important; border-color:rgba(220,60,60,.6) !important; }
.gs-btn[data-rank="a"].gs-active { background:#7a1a1a !important; border-color:#c03030 !important; color:#ffaaaa !important; box-shadow:0 3px 8px rgba(192,48,48,.4) !important; }
.gs-btn[data-rank="b"] { background:rgba(20,70,160,.20) !important; border-color:rgba(50,120,220,.35) !important; color:rgba(100,160,255,.9) !important; }
.gs-btn[data-rank="b"]:hover { background:rgba(20,70,160,.40) !important; color:#aaccff !important; border-color:rgba(50,120,220,.6) !important; }
.gs-btn[data-rank="b"].gs-active { background:#1a3a70 !important; border-color:#2060c0 !important; color:#aaccff !important; box-shadow:0 3px 8px rgba(32,96,192,.4) !important; }
.gs-btn[data-rank="c"] { background:rgba(15,100,45,.20) !important; border-color:rgba(40,160,90,.35) !important; color:rgba(80,200,120,.9) !important; }
.gs-btn[data-rank="c"]:hover { background:rgba(15,100,45,.40) !important; color:#80e0a0 !important; border-color:rgba(40,160,90,.6) !important; }
.gs-btn[data-rank="c"].gs-active { background:#0f4020 !important; border-color:#20803a !important; color:#80e0a0 !important; box-shadow:0 3px 8px rgba(32,128,58,.4) !important; }
.gs-btn[data-rank="d"] { background:rgba(60,60,60,.20) !important; border-color:rgba(120,120,120,.3) !important; color:rgba(160,160,160,.9) !important; }
.gs-btn[data-rank="d"]:hover { background:rgba(60,60,60,.45) !important; color:#ccc !important; border-color:rgba(140,140,140,.5) !important; }
.gs-btn[data-rank="d"].gs-active { background:#303030 !important; border-color:#666 !important; color:#ccc !important; box-shadow:0 3px 8px rgba(0,0,0,.4) !important; }
.gs-btn[data-rank="e"] { background:rgba(100,65,15,.20) !important; border-color:rgba(180,130,80,.35) !important; color:rgba(200,158,100,.9) !important; }
.gs-btn[data-rank="e"]:hover { background:rgba(100,65,15,.40) !important; color:#d4aa70 !important; border-color:rgba(180,130,80,.6) !important; }
.gs-btn[data-rank="e"].gs-active { background:#4a2e10 !important; border-color:#8a5a28 !important; color:#d4aa70 !important; box-shadow:0 3px 8px rgba(138,90,40,.4) !important; }
/* ── Замочок / іконки ── */
.gs-btn[data-locked="1"] { color:rgba(252,54,59,.75) !important; }
.gs-btn[data-locked="1"]:hover { background:rgba(252,54,59,.15) !important; color:#fc363b !important; }
.gs-btn[data-locked="1"].gs-active { background:rgba(252,54,59,.22) !important; border-color:rgba(252,54,59,.55) !important; color:#fc363b !important; }
.gs-btn[data-locked="0"] { color:rgba(60,206,123,.75) !important; }
.gs-btn[data-locked="0"]:hover { background:rgba(60,206,123,.15) !important; color:#3cce7b !important; }
.gs-btn[data-locked="0"].gs-active { background:rgba(60,206,123,.22) !important; border-color:rgba(60,206,123,.55) !important; color:#3cce7b !important; }
.gs-btn[data-locked="2"] { color:rgba(139,92,246,.8) !important; }
.gs-btn[data-locked="2"]:hover { background:rgba(139,92,246,.15) !important; color:#c084fc !important; }
.gs-btn[data-locked="2"].gs-active { background:rgba(139,92,246,.22) !important; border-color:rgba(139,92,246,.55) !important; color:#c084fc !important; }
/* ── Зірки ── */
.gs-btn[data-stars] { color:rgba(255,190,30,.80) !important; border-color:rgba(255,190,30,.2) !important; }
.gs-btn[data-stars]:hover { background:rgba(255,190,30,.15) !important; color:#ffc107 !important; }
.gs-btn[data-stars].gs-active { background:rgba(255,190,30,.22) !important; border-color:rgba(255,190,30,.55) !important; color:#ffc107 !important; box-shadow:0 3px 10px rgba(255,190,0,.3) !important; }
/* ── Іконки-кнопки (eraser, copy) ── */
.gs-btn.gs-icon { padding:5px 8px !important; }
/* ── Пошук ── */
.card-filter-form__search {
background: rgba(10,10,22,0.84) !important;
border: 1px solid rgba(255,255,255,0.10) !important;
border-radius: 10px !important;
color: rgba(255,255,255,0.85) !important;
font-size: 13px !important;
padding: 10px 50px 10px 16px !important;
transition: border-color .2s, box-shadow .2s !important;
}
.card-filter-form__search::placeholder { color:rgba(255,255,255,.25) !important; }
.card-filter-form__search:focus {
border-color: var(--accent,#8b5cf6) !important;
box-shadow: 0 0 0 3px rgba(139,92,246,.15) !important;
outline: none !important;
}
.tabs__search-btn {
background: rgba(139,92,246,.18) !important;
border: none !important;
color: rgba(255,255,255,.60) !important;
border-radius: 0 10px 10px 0 !important;
transition: background .18s !important;
}
.tabs__search-btn:hover { background:var(--accent,#8b5cf6) !important; color:#fff !important; }
/* ── Sort select ── */
#cards_order, .sort-block select {
background: rgba(10,10,22,0.84) !important;
border: 1px solid rgba(255,255,255,0.10) !important;
border-radius: 10px !important;
color: rgba(255,255,255,0.75) !important;
font-size: 11px !important;
font-weight: 600 !important;
padding: 7px 30px 7px 12px !important;
height: auto !important;
appearance: none !important;
-webkit-appearance: none !important;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='11' viewBox='0 0 24 24' fill='none' stroke='rgba(255,255,255,0.45)' stroke-width='2.5'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") !important;
background-repeat: no-repeat !important;
background-position: right 9px center !important;
cursor: pointer !important;
}
#cards_order option, .sort-block select option { background:#16162a !important; color:#fff !important; }
/* ── Кнопки дій ── */
/* ── Кнопки дій — точно по onclick ── */
.btn-green, .btn-red {
border-radius: 10px !important;
padding: 9px 18px !important;
font-size: 13px !important;
font-weight: 700 !important;
letter-spacing: 0.4px !important;
text-transform: uppercase !important;
height: auto !important;
width: auto !important;
display: inline-flex !important;
align-items: center !important;
gap: 6px !important;
transition: background 0.18s !important;
}
/* Блокувати карти — ЧЕРВОНА */
button[onclick*="PageLockCards"] {
background: #5c1a1a !important;
border: 1px solid rgba(244,67,54,0.55) !important;
color: #ff8080 !important;
}
button[onclick*="PageLockCards"]:hover {
background: #6e2020 !important;
}
/* Зняти блокування — ЗЕЛЕНА */
button[onclick*="PageUnLockCards"] {
background: #1a5c38 !important;
border: 1px solid rgba(60,206,123,0.55) !important;
color: #3cce7b !important;
}
button[onclick*="PageUnLockCards"]:hover {
background: #216e42 !important;
}
/* Блокування без дублів (зелена посилання) */
.custom-lock-visible {
background: #1a5c38 !important;
border: 1px solid rgba(60,206,123,0.55) !important;
color: #3cce7b !important;
}
.custom-lock-visible:hover {
background: #216e42 !important;
}
/* Контейнер кнопок дій */
.action_lock_show_block,
.action_list_show_block {
display: flex !important;
flex-wrap: wrap !important;
justify-content: center !important;
gap: 8px !important;
}
/* ── Пагінація ── */
.pagination {
background: rgba(10,10,22,0.78) !important;
backdrop-filter: blur(16px) !important;
border: 1px solid rgba(255,255,255,0.07) !important;
border-radius: 12px !important;
padding: 8px 12px !important;
}
.pagination a, .pagination span {
background: rgba(255,255,255,0.06) !important;
border: 1px solid rgba(255,255,255,0.09) !important;
border-radius: 7px !important;
color: rgba(255,255,255,0.65) !important;
font-size: 11px !important;
font-weight: 600 !important;
padding: 5px 10px !important;
transition: all .18s !important;
text-align: center !important;
}
.pagination a:hover { background:var(--accent,#8b5cf6) !important; border-color:transparent !important; color:#fff !important; }
.pagination span:not(.nav_ext) { background:var(--accent,#8b5cf6) !important; border-color:transparent !important; color:#fff !important; box-shadow:0 3px 10px rgba(139,92,246,.35) !important; }
/* ══ MOBILE ≤600px ══ */
@media (max-width: 600px) {
#gs-rank-wrap {
gap: 5px !important;
overflow: hidden !important;
width: 100% !important;
}
#gs-rank-row {
flex-wrap: nowrap !important;
overflow-x: auto !important;
overflow-y: hidden !important;
padding: 7px 8px !important;
border-radius: 12px !important;
gap: 4px !important;
scrollbar-width: none !important;
-ms-overflow-style: none !important;
width: 100% !important;
max-width: 100% !important;
}
#gs-rank-row::-webkit-scrollbar { display: none !important; }
#gs-stars-row {
flex-wrap: nowrap !important;
overflow-x: auto !important;
overflow-y: hidden !important;
padding: 6px 8px !important;
border-radius: 10px !important;
gap: 4px !important;
scrollbar-width: none !important;
-ms-overflow-style: none !important;
width: 100% !important;
max-width: 100% !important;
}
#gs-stars-row::-webkit-scrollbar { display: none !important; }
.gs-btn {
flex-shrink: 0 !important;
padding: 7px 10px !important;
font-size: 11px !important;
border-radius: 7px !important;
white-space: nowrap !important;
}
.gs-sep { flex-shrink: 0 !important; }
.ncard__tabs {
padding: 6px 8px !important;
border-radius: 12px !important;
}
.ncard__tabs-btns {
display: grid !important;
grid-template-columns: repeat(2, 1fr) !important;
gap: 4px !important;
width: 100% !important;
}
/* Якщо остання кнопка непарна — розтягуємо на весь рядок */
.ncard__tabs-btn:last-child:nth-child(odd) {
grid-column: 1 / -1 !important;
}
.ncard__tabs-btn {
padding: 9px 6px !important;
font-size: 10px !important;
border-radius: 7px !important;
justify-content: center !important;
display: flex !important;
text-align: center !important;
white-space: normal !important;
}
.sort-block--btn { width: 100% !important; }
#cards_order, .sort-block select {
width: 100% !important;
font-size: 11px !important;
padding: 8px 28px 8px 10px !important;
border-radius: 8px !important;
}
.card-filter-form__search {
font-size: 13px !important;
padding: 9px 44px 9px 12px !important;
border-radius: 8px !important;
}
.pagination { padding: 6px 8px !important; border-radius: 10px !important; }
.pagination a, .pagination span {
padding: 4px 8px !important;
font-size: 10px !important;
border-radius: 5px !important;
}
}
`);
// ── JS: перебудова tabs__nav ─────────────────────────────────────────────
function rebuildTabsNav() {
const nav = document.querySelector('.tabs__nav.tab__menu');
if (!nav || nav.dataset.gsRebuilt) return;
nav.dataset.gsRebuilt = '1';
// Збираємо всі оригінальні кнопки
const rankBtns = nav.querySelectorAll('.tabs__navigate__rank');
const lockBtns = nav.querySelectorAll('.tabs__navigate__lock');
const starShow = nav.querySelector('.tabs__navigate__stars__show');
const starBtns = nav.querySelectorAll('.tabs__navigate__stars');
const otherBtns = nav.querySelectorAll('.tabs__item:not(.tabs__navigate__rank):not(.tabs__navigate__lock):not(.tabs__navigate__stars):not(.tabs__navigate__stars__show)');
// Ховаємо оригінальний nav
nav.style.cssText = 'display:none !important';
// Створюємо обгортку
const wrap = document.createElement('div');
wrap.id = 'gs-rank-wrap';
// ── Рядок 1: Ранги + замочки + іконки ──
const rankRow = document.createElement('div');
rankRow.id = 'gs-rank-row';
function cloneAsGsBtn(orig) {
const btn = document.createElement('button');
btn.className = 'gs-btn';
btn.innerHTML = orig.innerHTML;
Array.from(orig.attributes).forEach(attr => {
if (attr.name.startsWith('data-')) btn.setAttribute(attr.name, attr.value);
});
// Клік — проксі на оригінал, синхронізація з затримкою
btn.addEventListener('click', () => {
orig.click();
setTimeout(syncActive, 50);
});
return btn;
}
// Всі кнопки в ОДНОМУ пласкому рядку — без sub-контейнерів
const rankClones = [];
rankBtns.forEach(orig => {
const btn = cloneAsGsBtn(orig);
rankClones.push({ orig, btn });
rankRow.appendChild(btn);
});
// Роздільник (тільки якщо є замочки)
const lockClones = [];
if (lockBtns.length > 0) {
const sep = document.createElement('span');
sep.className = 'gs-sep';
rankRow.appendChild(sep);
lockBtns.forEach(orig => {
const btn = cloneAsGsBtn(orig);
lockClones.push({ orig, btn });
rankRow.appendChild(btn);
});
}
// Іконки (eraser, copy тощо)
otherBtns.forEach(orig => {
const btn = cloneAsGsBtn(orig);
btn.classList.add('gs-icon');
rankRow.appendChild(btn);
});
// Передаємо кількість рангів у CSS для grid на мобайлі
rankRow.style.setProperty('--gs-rank-count', rankBtns.length);
wrap.appendChild(rankRow);
// ── Рядок 2: Зірки (без підпису, завжди видні) ──
const starsRow = document.createElement('div');
starsRow.id = 'gs-stars-row';
const starClones = [];
starBtns.forEach(orig => {
const btn = cloneAsGsBtn(orig);
starClones.push({ orig, btn });
starsRow.appendChild(btn);
});
// Зірки показуємо тільки на сторінці власних карток /user/cards/
// На базі карт (/user/cards/need/, /cards_showcase/ тощо — не показуємо)
const _path = window.location.pathname;
const showStars = _path.match(/^\/user\/cards\/?(\?|$)/) ||
_path.includes('/user/') && _path.includes('/cards') && !_path.includes('/need') && !_path.includes('/showcase');
if (showStars) {
wrap.appendChild(starsRow);
}
// Вставляємо після оригінального nav
nav.parentNode.insertBefore(wrap, nav.nextSibling);
// Ховаємо кнопку "показати зірки" в оригіналі
if (starShow) starShow.style.display = 'none';
// ── Синхронізація: перевіряємо кожен клон напряму ──
function syncActive() {
rankClones.forEach(({ orig, btn }) => {
btn.classList.toggle('gs-active', orig.classList.contains('tabs__item--active'));
});
lockClones.forEach(({ orig, btn }) => {
btn.classList.toggle('gs-active', orig.classList.contains('tabs__item--active'));
});
starClones.forEach(({ orig, btn }) => {
btn.classList.toggle('gs-active', orig.classList.contains('tabs__item--active'));
});
}
// Початковий синхрон
syncActive();
// MutationObserver — один observer на nav замість N на кожну кнопку
// + RAF-дебаунс щоб не запускати syncActive кілька разів за один клік
let _syncRaf = null;
const obs = new MutationObserver(() => {
if (_syncRaf) return;
_syncRaf = requestAnimationFrame(() => {
_syncRaf = null;
syncActive();
});
});
obs.observe(nav, { attributes: true, attributeFilter: ['class'], subtree: true });
}
// Завжди запускаємо rebuild, потім застосовуємо початковий стан тоггла
function _runAfterBuild() {
rebuildTabsNav();
// Якщо вимкнено — одразу ховаємо наш дизайн
if (!_cardsUiEnabled) {
const wrap = document.getElementById('gs-rank-wrap');
const starsRow = document.getElementById('gs-stars-row');
const nav = document.querySelector('.tabs__nav.tab__menu');
const starShow = nav ? nav.querySelector('.tabs__navigate__stars__show') : null;
if (wrap) wrap.style.setProperty('display', 'none', 'important');
if (starsRow) starsRow.style.setProperty('display', 'none', 'important');
if (nav) nav.style.setProperty('display', 'flex', 'important');
// Відновлюємо кнопку зірок яку rebuildTabsNav приховав
if (starShow) starShow.style.removeProperty('display');
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', _runAfterBuild);
} else {
_runAfterBuild();
}
// ── Кольори кнопок блокування — тільки на сторінці карток ──
function fixLockBtnColors() {
// Запускаємо тільки якщо є блок action_lock_show
const lockBlock = document.querySelector('.action_lock_show_block');
if (!lockBlock) return;
lockBlock.querySelectorAll('button[onclick]').forEach(btn => {
const oc = btn.getAttribute('onclick') || '';
if (oc.includes('PageLockCards') && !oc.includes('UnLock')) {
btn.style.setProperty('background', '#1a5c38', 'important');
btn.style.setProperty('border', '1px solid rgba(60,206,123,0.55)', 'important');
btn.style.setProperty('color', '#3cce7b', 'important');
btn.style.setProperty('background-color', '#1a5c38', 'important');
} else if (oc.includes('PageUnLockCards')) {
btn.style.setProperty('background', '#5c1a1a', 'important');
btn.style.setProperty('border', '1px solid rgba(244,67,54,0.55)', 'important');
btn.style.setProperty('color', '#ff8080', 'important');
btn.style.setProperty('background-color', '#5c1a1a', 'important');
}
});
document.querySelectorAll('.custom-lock-visible').forEach(btn => {
btn.style.setProperty('background', '#1a5c38', 'important');
btn.style.setProperty('border', '1px solid rgba(60,206,123,0.55)', 'important');
btn.style.setProperty('color', '#3cce7b', 'important');
btn.style.setProperty('background-color', '#1a5c38', 'important');
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', fixLockBtnColors);
} else {
fixLockBtnColors();
}
})();