:root {
    --bg-color: #f4f4f4;
    --text-color: #333;
    --text-color-primary: #111;          /* основной цвет текста в виджетах (адаптируется к теме) */
    --text-muted: #888;
    --input-bg: #fff;
    --input-border: #ccc;
    --button-bg: #007bff;
    --button-hover: #0056b3;
    --card-bg: #fff;
    --card-shadow: rgba(0,0,0,0.1);
    --border-color: #e0e0e0;
    --success-color: #0a6e0a;
    --warning-color: #aa4400;
    --warning-bg: rgba(255, 244, 220, 0.5);
    --warning-border: #f0c674;
    --danger-color: #c00;
    --error-color: #c62828;

    /* ============================================================
     * Тематические переменные для виджета «Исследование местности».
     *
     * Раньше стили виджета (карточки, прогресс-бар, кнопки навигации
     * карусели) использовали жёстко заданные цвета rgba(15, 23, 42, ...)
     * (это тёмно-синие тени/границы) и color-mix с #ffffff. На тёмной
     * теме эти значения визуально терялись: тёмные тени плохо видны на
     * тёмном фоне, а белые градиенты в графиках прогресса конфликтовали
     * с подложкой.
     *
     * Решение: выделяем семантический слой переменных (--expl-surface-*
     * для фона/границ/теней и --expl-on-accent-fg для цвета контента на
     * акцентной заливке), определяем их один раз в :root и
     * переопределяем в .dark-theme — все вложенные правила виджета
     * автоматически подстраиваются под активную тему без дублирования
     * media/селекторов.
     * ============================================================ */
    --expl-surface-bg: #ffffff;             /* подложка карточек/кнопок */
    --expl-surface-border: rgba(15, 23, 42, 0.08);
    --expl-surface-border-strong: color-mix(in srgb,
        var(--widget-accent, #14b8a6) 32%, transparent);
    --expl-surface-track: rgba(15, 23, 42, 0.06);   /* фон прогресс-бара */
    --expl-surface-shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.04),
                              0 2px 8px rgba(15, 23, 42, 0.04);
    --expl-surface-shadow-md: 0 1px 2px rgba(15, 23, 42, 0.04),
                              0 8px 24px -8px rgba(15, 23, 42, 0.10),
                              0 16px 40px -16px rgba(15, 23, 42, 0.10);
    --expl-inset-shadow: inset 0 1px 1px rgba(15, 23, 42, 0.04);
    --expl-nav-shadow: 0 1px 2px rgba(15, 23, 42, 0.06),
                       0 8px 22px -8px rgba(15, 23, 42, 0.22);
    --expl-progress-hi: #ffffff;            /* светлый край градиента % исследования */
    --expl-bar-hi: #ffffff;                /* светлый край градиента заполнения */
    --expl-on-accent-fg: #ffffff;          /* цвет контента на заливке --widget-accent */

    /* ============================================================
     * Тематические переменные для stat-карточек hero раздела
     * «Достижения» (#sectionGeotracker → .achievements-hero-stat).
     *
     * Карточки лежат поверх фиксированного яркого hero-градиента
     * (`.geotracker-hero`, цвета #0ea5e9 → #10b981, в тёмной теме НЕ
     * переопределяется — он остаётся ярким пятном на тёмной странице).
     * Поэтому цвет текста (--achv-stat-fg) держим белым в обеих
     * темах, а вот фон/границы/кольцо фокуса подкручиваем:
     * в тёмной теме яркая страница рядом с чёрным фоном сильнее
     * «слепит», поэтому стекло делаем чуть плотнее, а границы и
     * focus-ring — заметнее, чтобы карточки не сливались с подложкой.
     *
     * Парные переопределения лежат в .dark-theme ниже — фронт
     * автоматически подстраивается под активную тему без отдельных
     * media/селекторов.
     * ============================================================ */
    --achv-stat-bg: rgba(255, 255, 255, 0.18);            /* стекло-фон */
    --achv-stat-bg-hover: rgba(255, 255, 255, 0.28);      /* стекло при hover/focus-visible */
    --achv-stat-border: rgba(255, 255, 255, 0.22);        /* тонкая граница */
    --achv-stat-border-hover: rgba(255, 255, 255, 0.45);  /* усиленная граница при hover/focus-visible */
    --achv-stat-focus-ring: rgba(255, 255, 255, 0.6);     /* кольцо фокуса для a11y */
    --achv-stat-fg: #ffffff;                              /* цвет текста/эмодзи (белый) */
}

.impersonate-banner {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 10px 16px;
    background: linear-gradient(90deg, #ff9800 0%, #f44336 100%);
    color: #fff;
    font-size: 14px;
    font-weight: 600;
    box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}
.impersonate-banner.hidden { display: none; }
.impersonate-banner-icon { font-size: 18px; }
.impersonate-banner-text { flex: 1; text-align: center; }
.impersonate-banner-btn {
    background: rgba(255,255,255,0.2);
    color: #fff;
    border: 1px solid rgba(255,255,255,0.6);
    border-radius: 4px;
    padding: 4px 12px;
    font-size: 13px;
    cursor: pointer;
    font-weight: 600;
}
.impersonate-banner-btn:hover { background: rgba(255,255,255,0.35); }
body.has-impersonate-banner #app { padding-top: 44px; }
body.has-impersonate-banner #loading-screen { top: 44px; }

.dark-theme {
    --bg-color: #2b2b2b;
    --text-color: #f0f0f0;
    --text-color-primary: #f0f0f0;      /* светлый текст для тёмной темы (input/strowok bot invite) */
    --text-muted: #a0a0a0;
    --input-bg: #3a3a3a;
    --input-border: #666;
    --button-bg: #0d7bff;
    --button-hover: #0a6ad8;
    --card-bg: #3a3a3a;
    --card-shadow: rgba(0,0,0,0.4);
    --border-color: #4a4a4a;
    --success-color: #6fcf6f;
    --warning-color: #f0c674;
    --warning-bg: rgba(240, 198, 116, 0.12);
    --warning-border: #8a6a2a;
    --danger-color: #ff6b6b;
    --error-color: #ff6b6b;

    --bg-primary: #3a3a3a;
    --bg-secondary: #2b2b2b;
    --bg-hover: #4a4a4a;

    /* Тёмная тема для виджета «Исследование местности» — парные
       переопределения семантических переменных, объявленных в :root.
       Без них жёстко заданные rgba(15,23,42,...) тени и белые градиенты
       выглядели бы инверсно/плоско на тёмной подложке. */
    --expl-surface-bg: color-mix(in srgb, var(--input-bg, #3a3a3a) 92%, #000);
    --expl-surface-border: color-mix(in srgb, var(--input-border, #4a4a4a) 65%, transparent);
    --expl-surface-track: color-mix(in srgb,
        var(--widget-accent, #14b8a6) 18%,
        rgba(255, 255, 255, 0.04));
    --expl-surface-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.30),
                              0 4px 14px rgba(0, 0, 0, 0.22);
    --expl-surface-shadow-md: 0 1px 2px rgba(0, 0, 0, 0.30),
                              0 12px 28px -10px color-mix(in srgb, var(--widget-accent, #14b8a6) 35%, transparent),
                              0 22px 50px -22px color-mix(in srgb, var(--widget-accent, #14b8a6) 40%, transparent);
    --expl-inset-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.35);
    --expl-nav-shadow: 0 1px 2px rgba(0, 0, 0, 0.40),
                       0 8px 24px -8px rgba(0, 0, 0, 0.55);
    --expl-on-accent-fg: #0b1220;
    /* --expl-progress-hi и --expl-bar-hi оставляем #ffffff: на тёмной
       теме белый светлый край в градиентах процента/заполнения/точки
       делает акцентный цвет ярче и контрастнее, что и требуется. */

    /* [P0 #1] Тёмная тема для stat-карточек hero раздела
       «Достижения». Стекло делаем чуть плотнее, границы и focus-ring
       — заметнее, чтобы яркие карточки не сливались с ярким
       hero-градиентом на тёмной странице. Текст остаётся белым —
       читается одинаково хорошо в обеих темах на фиксированном
       зелёно-голубом фоне. */
    --achv-stat-bg: rgba(255, 255, 255, 0.20);
    --achv-stat-bg-hover: rgba(255, 255, 255, 0.32);
    --achv-stat-border: rgba(255, 255, 255, 0.30);
    --achv-stat-border-hover: rgba(255, 255, 255, 0.55);
    --achv-stat-focus-ring: rgba(255, 255, 255, 0.85);
    /* --achv-stat-fg не переопределяем — белый остаётся белым. */
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    margin: 0;
    padding: 0;
    background-color: var(--bg-color);
    color: var(--text-color);
    transition: background-color 0.3s, color 0.3s;
}

.container {
    max-width: 800px;
    margin: 0 auto;
    background: var(--card-bg);
    color: var(--text-color);
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 0 10px rgba(0,0,0,0.1);
}

.hidden {
    display: none;
}

h2, h3 {
    color: #333;
}

input, select, button {
    display: block;
    margin: 10px 0;
    padding: 10px;
    width: 100%;
    box-sizing: border-box;
}

button {
    background-color: #007bff;
    color: white;
    border: none;
    cursor: pointer;
}

button:hover {
    background-color: #0056b3;
}

#map {
    height: 500px;
    margin-top: 20px;
    position: relative;
}

#zonesFormMap,
.zones-form-map {
    height: 320px;
    margin-top: 12px;
    position: relative;
    border-radius: 6px;
    overflow: hidden;
}

#map.fullscreen-map {
    height: 100%;
    margin-top: 0;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    z-index: 1001;
}

#topMenu.top-menu-hidden {
    display: none;
}

/* === Pill-glassmorphism кнопки на карте =============================
   Единый стиль для .fullscreen-button и .legend-toggle (в miniapp).
   Совпадает по визуалу с playback-панелью, #playbackShowButton
   и .route-selector-wrap: glassmorphism pill + голубая рамка +
   многослойная тень + микро-анимации. */
.fullscreen-button {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 999;

    display: inline-flex;
    align-items: center;
    gap: 8px;

    padding: 8px 16px;
    border: 1px solid rgba(76, 139, 245, 0.28);
    border-radius: 999px;

    background: linear-gradient(180deg,
                rgba(255, 255, 255, 0.92) 0%,
                rgba(245, 247, 250, 0.86) 100%);
    -webkit-backdrop-filter: blur(10px) saturate(160%);
    backdrop-filter: blur(10px) saturate(160%);
    color: #2c6fd6;

    box-shadow:
        0 2px 4px rgba(15, 23, 42, 0.08),
        0 8px 20px rgba(76, 139, 245, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.95);

    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.01em;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;

    transition:
        background 220ms ease,
        box-shadow 220ms ease,
        border-color 220ms ease,
        color 220ms ease,
        transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.fullscreen-button:hover {
    background: linear-gradient(180deg,
                #ffffff 0%,
                #f0f4ff 100%);
    border-color: rgba(76, 139, 245, 0.5);
    color: #1e5fb8;
    box-shadow:
        0 3px 6px rgba(15, 23, 42, 0.1),
        0 12px 26px rgba(76, 139, 245, 0.28),
        inset 0 1px 0 rgba(255, 255, 255, 1);
    transform: translateY(-1px);
}

.fullscreen-button:active {
    transform: translateY(0) scale(0.97);
    box-shadow:
        0 1px 3px rgba(15, 23, 42, 0.12),
        0 4px 10px rgba(15, 23, 42, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.85);
}

.fullscreen-button:focus-visible {
    outline: none;
    box-shadow:
        0 0 0 3px rgba(76, 139, 245, 0.4),
        0 3px 6px rgba(15, 23, 42, 0.1),
        0 12px 26px rgba(76, 139, 245, 0.28),
        inset 0 1px 0 rgba(255, 255, 255, 1);
}

.fullscreen-button__icon {
    font-size: 14px;
    line-height: 1;
    transition: transform 280ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.fullscreen-button:hover .fullscreen-button__icon {
    transform: scale(1.12);
}

.dark-theme .fullscreen-button {
    background: linear-gradient(180deg,
                rgba(45, 55, 72, 0.92) 0%,
                rgba(26, 32, 44, 0.88) 100%);
    border-color: rgba(120, 175, 255, 0.4);
    color: #9ec5ff;
    box-shadow:
        0 2px 4px rgba(0, 0, 0, 0.5),
        0 10px 24px rgba(76, 139, 245, 0.28),
        inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

.dark-theme .fullscreen-button:hover {
    background: linear-gradient(180deg,
                rgba(60, 78, 105, 0.95) 0%,
                rgba(36, 50, 70, 0.92) 100%);
    border-color: rgba(150, 200, 255, 0.6);
    color: #cfe2ff;
    box-shadow:
        0 3px 6px rgba(0, 0, 0, 0.55),
        0 14px 32px rgba(76, 139, 245, 0.38),
        inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

.leaflet-top,
.leaflet-bottom,
.maplibregl-top,
.maplibregl-bottom {
    z-index: 998 !important;
}

/* Скрываем блок атрибуции maplibregl (OpenFreeMap / OpenMapTiles / OpenStreetMap). */
.maplibregl-ctrl-bottom-right,
.maplibregl-ctrl-attrib {
    display: none !important;
}

.leaflet-control-zoom,
.maplibregl-ctrl-zoom {
    z-index: 998 !important;
}

.leaflet-control-zoom a,
.maplibregl-ctrl-zoom a,
.maplibregl-ctrl button {
    z-index: 998 !important;
}

#routeInfo {
    display: none;
    margin: 10px 0;
    padding: 12px 16px;
    background-color: var(--input-bg);
    border: 1px solid var(--input-border);
    border-radius: 8px;
    font-size: 12px;
    line-height: 1.1;
    color: var(--text-color);
}

.route-info-notice {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed var(--input-border);
    color: var(--text-secondary, #666);
    font-size: 13px;
    line-height: 1.4;
    white-space: pre-line;
}

.route-info-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
}

.route-info-block {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: var(--card-bg);
    border: 1px solid var(--input-border);
    border-radius: 10px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
    min-width: 0;
}

.route-info-block:hover {
    transform: translateY(-1px);
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.08);
    border-color: var(--accent-color, #2ea043);
}

.route-info-block__icon {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 9px;
    color: #fff;
}

.route-info-block--start    .route-info-block__icon { background: linear-gradient(135deg, #4f8cff, #2b5fd9); }
.route-info-block--end      .route-info-block__icon { background: linear-gradient(135deg, #8b5cf6, #6d28d9); }
.route-info-block--count    .route-info-block__icon { background: linear-gradient(135deg, #14b8a6, #0d9488); }
.route-info-block--distance .route-info-block__icon { background: linear-gradient(135deg, #f59e0b, #d97706); }
.route-info-block--time     .route-info-block__icon { background: linear-gradient(135deg, #4f8cff, #2b5fd9); }
.route-info-block--speed    .route-info-block__icon { background: linear-gradient(135deg, #ef4444, #b91c1c); }

.route-info-block__body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.route-info-block__label {
    font-size: 11px;
    font-weight: 500;
    color: var(--text-secondary, #666);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.route-info-block__value {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-color);
    word-break: break-word;
    line-height: 1.25;
}

@media (max-width: 720px) {
    .route-info-grid {
        grid-template-columns: 1fr;
    }
}

.points-chart-container {
    display: none;
    margin: 0 0 10px 0;
}
.points-chart-container.is-visible {
    display: block;
}

/* ============================================================
 * Карточка «Количество данных геопозиции» — sparkline в стиле widget-activity
 * ============================================================ */
.points-chart-card {
    /* Добавляем лёгкую нижнюю подложку, чтобы виджет не «слипался» с картой */
    margin-bottom: 10px;
}

.points-chart-body {
    /* Аналог widget-activity .widget-body */
    padding-top: 6px;
    max-height: none;
}

.points-chart-card .widget-header {
    /* Шапка с иконкой и заголовком в две строки:
     * иконка слева, справа — заголовок и подпись (subtitle) */
    align-items: flex-start;
}
.points-chart-title-wrap {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.points-chart-title-wrap h3 {
    flex: 0 0 auto;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
}

.points-chart-card .widget-header h3 {
    margin: 0;
    font-size: 13px;
    line-height: 1.2;
}

.points-chart-subtitle {
    font-size: 10.5px;
    font-weight: 500;
    color: var(--text-muted, #94a3b8);
    margin-top: 2px;
}

.points-chart-total {
    /* Растягиваем единственный totals-блок на всю ширину */
    grid-column: 1 / -1;
}

.points-chart-svg {
    /* Внутренний svg — на полную ширину контейнера, высота как у activity-spark */
    width: 100%;
    height: 86px;
    display: block;
    overflow: visible;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}

.points-chart-path {
    /* Локальный путь sparkline — используем акцент из widget-tint-cyan */
    stroke: var(--widget-accent, #3b82f6);
}

.points-chart-empty {
    background: var(--card-bg);
    border: 1px dashed var(--input-border);
    border-radius: 10px;
    padding: 10px 12px;
    font-size: 12px;
    color: var(--text-secondary, #888);
    text-align: center;
}

/* ============================================================
 * Тёмная тема — наследует поведение от widget-activity
 * ============================================================ */
.dark-theme .points-chart-svg .activity-spark-grid-line {
    stroke: rgba(148, 163, 184, 0.18);
}
.dark-theme .points-chart-svg .activity-spark-dot {
    fill: #1e293b;
}

/* ============================================================
 * Адаптивность для маленьких экранов
 * ============================================================ */
@media (max-width: 480px) {
    .points-chart-svg {
        height: 78px;
    }
}
@media (max-width: 360px) {
    .points-chart-card .widget-header h3 {
        font-size: 12px;
    }
    .points-chart-subtitle {
        font-size: 9.5px;
    }
}

#error {
    color: #e74c3c;
    margin-top: 10px;
    background-color: #ffeaea;
    padding: 10px;
    border-radius: 6px;
    border: 1px solid #f5c6cb;
}

.fullscreen-app {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    z-index: 1000;
    background-color: white;
}

#app {
    padding: 20px;
}

#app.fullscreen-app {
    padding: 0px;
}

.fullscreen-app #controls {
    display: none;
}

.hidden {
    display: none;
}

h2, h3 {
    color: var(--text-color);
    font-weight: 600;
    margin-bottom: 15px;
}

input, select, button {
    display: block;
    margin: 10px 0;
    padding: 12px 16px;
    width: 100%;
    box-sizing: border-box;
    border: 1px solid var(--input-border);
    border-radius: 8px;
    font-size: 16px;
    background-color: var(--input-bg);
    color: var(--text-color);
    transition: border-color 0.3s, box-shadow 0.3s;
}

input:focus, select:focus {
    outline: none;
    border-color: var(--button-bg);
    box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
}

button {
    background-color: var(--button-bg);
    color: white;
    border: none;
    cursor: pointer;
    font-weight: 500;
    transition: background-color 0.3s, transform 0.1s;
}

button:hover {
    background-color: var(--button-hover);
}

button:active {
    transform: scale(0.98);
}

#error {
    color: red;
    margin-top: 10px;
}

/* === Timeline header (collapsed/expanded handle) =====================
   Умная шапка-ручка: единая кликабельная зона с прогрессом,
   текущим временем и круглой кнопкой-шевроном справа. */
.timeline-header {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 10px 12px;
    box-sizing: border-box;
    cursor: pointer;
    user-select: none;
    border-radius: 10px;
    transition: background-color 180ms ease;
    outline: none;
}

.timeline-header:hover,
.timeline-header:focus-visible {
    background-color: rgba(0, 0, 0, 0.04);
}

.timeline-header:focus-visible {
    box-shadow: 0 0 0 2px rgba(76, 139, 245, 0.45);
}

.dark-theme .timeline-header:hover,
.dark-theme .timeline-header:focus-visible {
    background-color: rgba(255, 255, 255, 0.06);
}

.timeline-header__progress-fill {
    position: absolute;
    left: 8px;
    right: 8px;
    bottom: 2px;
    height: 2px;
    border-radius: 2px;
    background: rgba(0, 0, 0, 0.08);
    overflow: hidden;
    pointer-events: none;
}

.timeline-header__progress-fill::after {
    content: "";
    position: absolute;
    inset: 0;
    width: var(--header-progress, 0%);
    background: linear-gradient(90deg, #4c8bf5, #2ecc71);
    border-radius: inherit;
    transition: width 320ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.dark-theme .timeline-header__progress-fill {
    background: rgba(255, 255, 255, 0.1);
}

.timeline-header__left {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    flex: 0 0 auto;
}

.timeline-header__center {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.timeline-header__mini-track {
    position: relative;
    width: 100%;
    max-width: 220px;
    height: 4px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.1);
    overflow: hidden;
}

.dark-theme .timeline-header__mini-track {
    background: rgba(255, 255, 255, 0.14);
}

.timeline-header__mini-fill {
    position: absolute;
    inset: 0;
    width: var(--header-mini-progress, 0%);
    background: linear-gradient(90deg, #4c8bf5 0%, #2ecc71 100%);
    border-radius: inherit;
    box-shadow: 0 0 6px rgba(76, 139, 245, 0.5);
    transition: width 320ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.timeline-header__dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #95a5a6;
    box-shadow: 0 0 0 3px rgba(149, 165, 166, 0.18);
    flex: 0 0 auto;
    transition: background-color 200ms ease, box-shadow 200ms ease;
}

.timeline-header__dot.is-playing {
    background: #2ecc71;
    box-shadow: 0 0 0 3px rgba(46, 204, 113, 0.18);
    animation: timeline-dot-pulse 1.8s ease-in-out infinite;
}

.timeline-header__dot.is-paused {
    background: #f1c40f;
    box-shadow: 0 0 0 3px rgba(241, 196, 15, 0.2);
}

.timeline-header__dot.is-stopped {
    background: #95a5a6;
    box-shadow: 0 0 0 3px rgba(149, 165, 166, 0.18);
}

@keyframes timeline-dot-pulse {
    0%, 100% {
        box-shadow: 0 0 0 3px rgba(46, 204, 113, 0.18);
    }
    50% {
        box-shadow: 0 0 0 6px rgba(46, 204, 113, 0);
    }
}

@media (prefers-reduced-motion: reduce) {
    .timeline-header__dot.is-playing {
        animation: none;
    }
}

.timeline-header__time {
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--text-color, #333);
    letter-spacing: 0.02em;
}

.dark-theme .timeline-header__time {
    color: #f0f0f0;
}

.progress-display {
    font-size: 13px;
    color: var(--text-color);
    font-weight: 700;
    min-width: 38px;
    font-variant-numeric: tabular-nums;
    text-align: left;
}

.dark-theme .progress-display {
    color: #f0f0f0;
}

/* Кнопка-шеврон сворачивания/разворачивания панели */
.collapse-button {
    position: relative;
    background: linear-gradient(135deg, rgba(76, 139, 245, 0.12), rgba(46, 204, 113, 0.12));
    border: 1px solid rgba(76, 139, 245, 0.28);
    width: 32px;
    height: 32px;
    border-radius: 50%;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    box-shadow: 0 2px 6px rgba(76, 139, 245, 0.18);
    color: #2c6fd6;
    transition: transform 200ms ease, box-shadow 200ms ease,
                background 200ms ease, border-color 200ms ease;
    flex: 0 0 auto;
}

.collapse-button:hover {
    background: linear-gradient(135deg, rgba(76, 139, 245, 0.22), rgba(46, 204, 113, 0.22));
    border-color: rgba(76, 139, 245, 0.5);
    box-shadow: 0 4px 10px rgba(76, 139, 245, 0.28);
    transform: translateY(-1px);
}

.collapse-button:active {
    transform: translateY(0) scale(0.95);
}

.collapse-button:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(76, 139, 245, 0.45);
}

.collapse-button__icon,
button.collapse-button .collapse-button__icon {
    font-size: 13px;
    line-height: 1;
    transition: transform 280ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Свернутое состояние: шеврон направлен вверх (призыв "развернуть") */
.timeline-container.collapsed .collapse-button__icon {
    transform: rotate(180deg);
}

/* В свернутом виде мягко пульсируем шеврон, чтобы привлечь внимание */
.timeline-container.collapsed .collapse-button {
    animation: timeline-handle-pulse 2.6s ease-in-out infinite;
}

@keyframes timeline-handle-pulse {
    0%, 100% {
        box-shadow: 0 2px 6px rgba(76, 139, 245, 0.18),
                    0 0 0 0 rgba(76, 139, 245, 0.35);
    }
    50% {
        box-shadow: 0 2px 6px rgba(76, 139, 245, 0.18),
                    0 0 0 8px rgba(76, 139, 245, 0);
    }
}

@media (prefers-reduced-motion: reduce) {
    .timeline-container.collapsed .collapse-button {
        animation: none;
    }
}

.dark-theme .collapse-button {
    background: linear-gradient(135deg, rgba(76, 139, 245, 0.22), rgba(46, 204, 113, 0.18));
    border-color: rgba(120, 175, 255, 0.4);
    color: #cfe2ff;
}

.dark-theme .collapse-button:hover {
    background: linear-gradient(135deg, rgba(76, 139, 245, 0.32), rgba(46, 204, 113, 0.28));
    border-color: rgba(120, 175, 255, 0.6);
}

/* Свернутый контейнер: видна только шапка, увеличенная зона нажатия */
.timeline-container.collapsed .timeline-content {
    max-height: 0;
    opacity: 0;
    overflow: hidden;
    padding-top: 0;
    padding-bottom: 0;
    margin-top: 0;
    pointer-events: none;
    transition: max-height 360ms cubic-bezier(0.22, 0.61, 0.36, 1),
                opacity 260ms ease,
                padding 360ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.timeline-container .timeline-content {
    max-height: 800px;
    opacity: 1;
    transition: max-height 360ms cubic-bezier(0.22, 0.61, 0.36, 1),
                opacity 280ms ease,
                padding 360ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.timeline-container.collapsed {
    padding: 4px 6px 6px;
}

.timeline-container.collapsed .timeline-header {
    padding: 6px 8px;
}

.timeline-container {
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translate(-50%, 0);
    width: min(560px, 96%);
    background-color: rgba(255, 255, 255, 0.95);
    padding: 6px 10px 10px;
    border-radius: 14px 14px 0 0;
    box-shadow: 0 -2px 14px rgba(0, 0, 0, 0.22);
    z-index: 998;
    display: flex;
    flex-direction: column;
    align-items: center;
    transition: transform 380ms cubic-bezier(0.22, 0.61, 0.36, 1),
                padding 380ms cubic-bezier(0.22, 0.61, 0.36, 1);
    will-change: transform;
    touch-action: pan-y;
}

.timeline-container.panel-collapsed {
    transform: translate(-50%, calc(100% + 24px));
    pointer-events: none;
}

.timeline-container.hidden {
    display: none;
}

/* === Floating pill handle ===========================================
   Кнопка-капсула, скрывающая/показывающая всю панель playback.
   Расположена сверху панели; визуально читается как drag-handle. */
.playback-toggle-handle {
    position: relative;
    width: 100%;
    background: none;
    border: none;
    padding: 6px 0 4px;
    margin: 0;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: none;
    color: var(--text-color, #444);
    -webkit-tap-highlight-color: transparent;
}

.playback-toggle-handle__pill {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 5px 12px 5px 10px;
    border-radius: 999px;
    background: linear-gradient(180deg,
                rgba(255, 255, 255, 0.7) 0%,
                rgba(245, 247, 250, 0.55) 100%);
    border: 1px solid rgba(0, 0, 0, 0.06);
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.06),
        0 4px 12px rgba(15, 23, 42, 0.08),
        inset 0 1px 0 rgba(255, 255, 255, 0.8);
    backdrop-filter: blur(8px) saturate(140%);
    -webkit-backdrop-filter: blur(8px) saturate(140%);
    color: #4a5568;
    transition: transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1),
                box-shadow 220ms ease,
                background 220ms ease,
                border-color 220ms ease;
}

/* При hover капсула приподнимается и подсвечивается */
.playback-toggle-handle:hover .playback-toggle-handle__pill,
.playback-toggle-handle:focus-visible .playback-toggle-handle__pill {
    transform: translateY(-1px);
    background: linear-gradient(180deg,
                rgba(255, 255, 255, 0.85) 0%,
                rgba(245, 247, 250, 0.7) 100%);
    border-color: rgba(76, 139, 245, 0.35);
    box-shadow:
        0 2px 4px rgba(15, 23, 42, 0.08),
        0 8px 18px rgba(76, 139, 245, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.9);
}

.playback-toggle-handle:focus-visible {
    outline: none;
}

.playback-toggle-handle:focus-visible .playback-toggle-handle__pill {
    box-shadow:
        0 0 0 3px rgba(76, 139, 245, 0.35),
        0 2px 4px rgba(15, 23, 42, 0.08),
        0 8px 18px rgba(76, 139, 245, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.9);
}

.playback-toggle-handle:active .playback-toggle-handle__pill {
    transform: translateY(0) scale(0.97);
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.1),
        0 3px 8px rgba(15, 23, 42, 0.1),
        inset 0 1px 0 rgba(255, 255, 255, 0.7);
}

/* Grip — три точки как классический drag-handle affordance */
.playback-toggle-handle__grip {
    display: inline-flex;
    align-items: center;
    gap: 2.5px;
    padding: 4px 3px;
}

.playback-toggle-handle__grip > span {
    display: block;
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: rgba(74, 85, 104, 0.55);
    transition: background-color 200ms ease, transform 200ms ease;
}

.playback-toggle-handle:hover .playback-toggle-handle__grip > span,
.playback-toggle-handle:focus-visible .playback-toggle-handle__grip > span {
    background: #4c8bf5;
}

/* Шеврон — направление показывает текущее состояние панели */
.playback-toggle-handle__icon {
    font-size: 12px;
    line-height: 1;
    color: #4a5568;
    transition: transform 320ms cubic-bezier(0.22, 0.61, 0.36, 1),
                color 220ms ease;
}

.playback-toggle-handle:hover .playback-toggle-handle__icon,
.playback-toggle-handle:focus-visible .playback-toggle-handle__icon {
    color: #2c6fd6;
}

/* Когда панель полностью скрыта — шеврон переворачивается вверх */
.timeline-container.panel-collapsed .playback-toggle-handle__icon {
    transform: rotate(180deg);
    color: #2c6fd6;
}

/* Когда свернуто содержимое — лёгкая пульсация grip-точек,
   чтобы ручка привлекала внимание (но не отвлекала) */
.timeline-container.collapsed .playback-toggle-handle__grip > span {
    animation: playback-grip-blink 2.4s ease-in-out infinite;
}

.timeline-container.collapsed .playback-toggle-handle__grip > span:nth-child(2) {
    animation-delay: 0.2s;
}

.timeline-container.collapsed .playback-toggle-handle__grip > span:nth-child(3) {
    animation-delay: 0.4s;
}

@keyframes playback-grip-blink {
    0%, 100% { background: rgba(74, 85, 104, 0.55); }
    50%      { background: #4c8bf5; }
}

@media (prefers-reduced-motion: reduce) {
    .timeline-container.collapsed .playback-toggle-handle__grip > span {
        animation: none;
    }
    .playback-toggle-handle__icon,
    .playback-toggle-handle__pill {
        transition-duration: 0ms;
    }
}

/* === Dark theme ===================================================== */
.dark-theme .playback-toggle-handle {
    color: #cbd5e0;
}

.dark-theme .playback-toggle-handle__pill {
    background: linear-gradient(180deg,
                rgba(45, 55, 72, 0.75) 0%,
                rgba(26, 32, 44, 0.65) 100%);
    border-color: rgba(255, 255, 255, 0.08);
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.4),
        0 6px 16px rgba(0, 0, 0, 0.4),
        inset 0 1px 0 rgba(255, 255, 255, 0.08);
    color: #cbd5e0;
}

.dark-theme .playback-toggle-handle:hover .playback-toggle-handle__pill,
.dark-theme .playback-toggle-handle:focus-visible .playback-toggle-handle__pill {
    background: linear-gradient(180deg,
                rgba(60, 75, 100, 0.9) 0%,
                rgba(36, 46, 60, 0.85) 100%);
    border-color: rgba(120, 175, 255, 0.45);
    box-shadow:
        0 2px 4px rgba(0, 0, 0, 0.5),
        0 10px 22px rgba(76, 139, 245, 0.22),
        inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

.dark-theme .playback-toggle-handle__grip > span {
    background: rgba(203, 213, 224, 0.55);
}

.dark-theme .playback-toggle-handle:hover .playback-toggle-handle__grip > span,
.dark-theme .playback-toggle-handle:focus-visible .playback-toggle-handle__grip > span {
    background: #6cb1ff;
}

.dark-theme .playback-toggle-handle__icon {
    color: #cbd5e0;
}

.dark-theme .playback-toggle-handle:hover .playback-toggle-handle__icon,
.dark-theme .playback-toggle-handle:focus-visible .playback-toggle-handle__icon {
    color: #9ec5ff;
}

.dark-theme .timeline-container.panel-collapsed .playback-toggle-handle__icon {
    color: #9ec5ff;
}

/* Переопределяем keyframes для dark-theme через специальный класс-маркер.
   Используем CSS-переменную: light-вариант keyframes ниже задаёт дефолт,
   а dark-вариант перебивает через :where/.dark-theme scope на :root. */
.dark-theme .timeline-container.collapsed .playback-toggle-handle__grip > span {
    animation-name: playback-grip-blink-dark;
}

@keyframes playback-grip-blink-dark {
    0%, 100% { background: rgba(203, 213, 224, 0.55); }
    50%      { background: #6cb1ff; }
}

.timeline-content {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 0 15px 15px;
    box-sizing: border-box;
}

.playback-stats {
    width: 100%;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    margin-top: 6px;
}

.playback-stats .route-info-block {
    padding: 4px 6px;
    gap: 6px;
    border-radius: 7px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
    background: var(--card-bg);
}

.playback-stats .route-info-block__icon {
    width: 22px;
    height: 22px;
    border-radius: 6px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

.playback-stats .route-info-block__icon svg {
    width: 12px;
    height: 12px;
}

.playback-stats .route-info-block__label {
    font-size: 9px;
    letter-spacing: 0.03em;
}

.playback-stats .route-info-block__value {
    font-size: 10px;
    font-weight: 600;
    line-height: 1.2;
}

@media (max-width: 720px) {
    .playback-stats {
        grid-template-columns: 1fr;
    }
}

.dark-theme .timeline-container {
    background-color: rgba(58, 58, 58, 0.92);
    box-shadow: 0 -2px 14px rgba(0, 0, 0, 0.5);
}

@media (max-width: 720px) {
    .timeline-container {
        width: 100%;
        border-radius: 14px 14px 0 0;
    }

    /* На узких экранах прячем время точки в свернутой шапке,
       чтобы шапка оставалась лаконичной. Полный блок виден в развёрнутом виде. */
    .timeline-container.collapsed .timeline-header__time,
    .timeline-container.collapsed .timeline-header__dot {
        display: none;
    }

    .timeline-container.collapsed .timeline-header {
        gap: 6px;
    }

    .timeline-container.collapsed .timeline-header__center {
        flex: 1 1 auto;
    }

    /* Чуть компактнее прогресс-чип слева */
    .timeline-container.collapsed .progress-display {
        min-width: 34px;
        font-size: 12px;
    }
}

.time-slider {
    width: 100%;
    margin: 2px 0;
    padding: 0;
    -webkit-appearance: none;
    appearance: none;
    height: 12px;
    line-height: 0;
    font-size: 0;
    border: none;
    border-radius: 0;
    background: transparent;
    outline: none;
}

.time-slider::-webkit-slider-runnable-track {
    height: 4px;
    border: none;
    border-radius: 2px;
    background: #ddd;
}

.time-slider::-moz-range-track {
    height: 4px;
    border: none;
    border-radius: 2px;
    background: #ddd;
}

.dark-theme .time-slider::-webkit-slider-runnable-track {
    background: #555;
}

.dark-theme .time-slider::-moz-range-track {
    background: #555;
}

.time-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 12px;
    height: 12px;
    margin-top: -4px;
    border: none;
    border-radius: 50%;
    background: #007bff;
    cursor: pointer;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}

.dark-theme .time-slider::-webkit-slider-thumb {
    background: #5a9bd5;
}

.time-slider::-moz-range-thumb {
    width: 12px;
    height: 12px;
    border: none;
    border-radius: 50%;
    background: #007bff;
    cursor: pointer;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}

.dark-theme .time-slider::-moz-range-thumb {
    background: #5a9bd5;
}

.current-time-display {
    font-size: 12px;
    line-height: 1.1;
    font-weight: 500;
    color: #333;
    margin-top: 2px;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

.dark-theme .current-time-display {
    color: #f0f0f0;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.time-marker-icon {
    width: 20px;
    height: 20px;
    background-color: #ff0000;
    border: 2px solid #ffffff;
    border-radius: 50%;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}

/* Контейнер маркера-точки (тот самый div, который задаётся в divIcon HTML).
   По умолчанию шим ставит ему inline-стили width/height = 20×20 px и оставляет
   overflow без явного значения. Чтобы метка скорости могла «выступать»
   вверх за пределы квадрата 20×20, нужен явный position: relative (для
   абсолютного позиционирования метки) и overflow: visible (чтобы метка не
   обрезалась границами контейнера). */
.time-marker {
    position: relative;
    overflow: visible;
}

/* Метка с текущей скоростью между двумя соседними точками маршрута
   (км/ч). Отрисовывается НАД точкой: position: absolute + bottom: 100%
   прижимает нижнюю границу метки к верхней границе контейнера (т.е. метка
   «висит» прямо над красной точкой). translateX(-50%) центрирует её по
   горизонтали относительно точки.
   Внешний вид — компактная «таблетка» с тенью, чтобы читалась на любом
   фоне карты. */
.time-marker-speed {
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translate(-50%, -6px);
    padding: 2px 8px;
    background-color: rgba(255, 255, 255, 0.95);
    color: #1f1f1f;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    border-radius: 10px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
    pointer-events: none;
    user-select: none;
}

/* Маленький «хвостик»-треугольник под меткой, указывающий на точку. */
.time-marker-speed::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
    border-top-color: rgba(255, 255, 255, 0.95);
}

/* Тёмная тема: метка должна оставаться читаемой и не сливаться с фоном. */
.dark-theme .time-marker-speed {
    background-color: rgba(32, 32, 36, 0.92);
    color: #f0f0f0;
}
.dark-theme .time-marker-speed::after {
    border-top-color: rgba(32, 32, 36, 0.92);
}

.marker-fade-in {
    animation: fadeIn 0.3s ease-in;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

.player-controls {
    display: flex;
    justify-content: center;
    gap: 10px;
    margin: 5px 0;
}

.player-button {
    background-color: transparent;
    border: none;
    width: 30px;
    height: 30px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: none;
    transition: transform 0.1s;
    border-radius: 50%;
}

.player-button img {
    width: 32px;
    height: 32px;
}

.player-button:active {
    transform: scale(0.95);
}

#followButton {
    font-size: 14px;
}

#heatMapButton {
    font-size: 14px;
}

.player-button {
    position: relative;
}

.player-button::before {
    content: attr(data-tooltip);
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%) translateY(-8px);
    background: linear-gradient(135deg, #3a3a3a 0%, #1a1a1a 100%);
    color: #fff;
    padding: 6px 12px;
    border-radius: 8px;
    font-size: 12px;
    font-weight: 500;
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s ease, visibility 0.25s ease, transform 0.25s ease;
    pointer-events: none;
    z-index: 1000;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
    letter-spacing: 0.3px;
}

.player-button::after {
    content: '';
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%) translateY(0px);
    border: 6px solid transparent;
    border-top-color: #1a1a1a;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s ease, visibility 0.25s ease;
    z-index: 1000;
}

.player-button:hover::before,
.player-button:active::before {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(-12px);
}

.player-button:hover::after,
.player-button:active::after {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(-4px);
}

#exportCsvButton {
    display: block;
    margin: 20px auto;
    background-color: var(--button-bg);
    color: white;
    border: none;

    padding: 12px 22px;
    border-radius: 8px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
    transition: background-color 0.3s, transform 0.1s;
}

#exportCsvButton:hover {
    background-color: var(--button-hover);
}

#exportCsvButton:active {
    transform: scale(0.95);
}

.dark-theme #exportCsvButton {
    background-color: var(--button-bg);
}

.dark-theme #exportCsvButton:hover {
    background-color: var(--button-hover);
}

/* ============================================================
   Date filter — современные кнопки выбора даты
   (стилистически согласовано с UserSelect)
   ============================================================ */
.date-filter {
    margin-bottom: 14px;
    padding: 14px 14px 12px;
    border: 1px solid var(--us-border, rgba(15, 23, 42, 0.08));
    border-radius: 14px;
    background-color: var(--us-bg, #ffffff);
    box-shadow: 0 1px 0 rgba(15, 23, 42, 0.02);
    transition: border-color 160ms cubic-bezier(0.22, 0.61, 0.36, 1),
                box-shadow 200ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

body.dark-theme .date-filter {
    background-color: var(--us-bg, #1f1f23);
    border-color: var(--us-border-strong, rgba(255, 255, 255, 0.16));
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
}

.date-filter h4 {
    margin: 0 0 10px 0;
    color: var(--us-text, #0f172a);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.01em;
    text-transform: uppercase;
    opacity: 0.75;
}

body.dark-theme .date-filter h4 {
    color: var(--us-text, #f1f5f9);
    opacity: 0.65;
}

.filter-controls {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.filter-controls select {
    flex: 1;
    padding: 10px 12px;
    border: 1px solid var(--input-border);
    border-radius: 10px;
    background-color: var(--input-bg);
    color: var(--text-color);
    font-size: 14px;
}

.filter-controls select:focus {
    outline: none;
    border-color: var(--button-bg);
    box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.1);
}

body.dark-theme .filter-controls select {
    background-color: var(--input-bg);
    border-color: var(--input-border);
    color: var(--text-color);
}

.scrollable-select {
    max-height: 150px;
    overflow-y: auto;
    flex: 2;
}

.scrollable-select option {
    padding: 8px;
    cursor: pointer;
}

.scrollable-select option:hover {
    background-color: var(--button-bg);
    color: white;
}

/* ----- Кнопка-инпут даты (для pushable-варианта в Геотрекере) -----
   Стили самой кнопки (.date-button) переопределены в секции
   .pushable. Здесь оставлены только правила для вложенного
   контента и заполненного состояния. */
.date-button {
    /* Совместимость: класс может присутствовать на pushable-кнопке,
       сбрасываем те свойства, что могут конфликтовать с pushable. */
    background-color: transparent;
    border: none;
    box-shadow: none;
    -webkit-appearance: none;
    appearance: none;
}

.date-button:hover,
.date-button:active {
    background-color: transparent;
    border: none;
    box-shadow: none;
    transform: none;
}

.date-button:focus-visible {
    outline: none;
    box-shadow: none;
    border: none;
}

.date-button-content {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}

/* Цвета label/value для pushable.date-button задаются в секции
   .filter-controls .pushable (стиль как у us-button). */
.date-button-label,
.date-button-value {
    /* Сброс старых pushable-стилей (белый цвет) — на us-button-варианте
       значения переопределяются в .filter-controls .pushable. */
    color: inherit;
    font-weight: inherit;
}

.date-button-value {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Заполненное состояние для кнопок-дат (pushable.date-button.has-value)
   реализовано в секции .filter-controls .pushable выше. */

/* Адаптив */
@media (max-width: 480px) {
    .date-button-value {
        font-size: 14px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .date-button,
    .date-button::before,
    .date-button::after,
    .date-filter {
        transition: none !important;
    }
}

/* ============================================================
   Modal — современный базовый стиль (согласовано с UserSelect)
   Применяется ко ВСЕМ модалкам. Если у какой-то модалки свой
   стиль — она переопределяет нужные правила ниже.
   ============================================================ */
.modal {
    display: none;
    position: fixed;
    z-index: 2000;
    inset: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(15, 23, 42, 0.32);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    justify-content: center;
    align-items: center;
    padding: 16px;
    box-sizing: border-box;
    opacity: 0;
    transition: opacity 180ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.modal.show {
    display: flex;
    opacity: 1;
}

body.dark-theme .modal {
    background-color: rgba(0, 0, 0, 0.55);
}

#shareLiveModal,
#shareLiveResultModal,
#myLiveModal,
#deleteMyLiveModal {
    z-index: 2100;
}

.modal-content {
    background-color: var(--us-bg, #ffffff);
    color: var(--us-text, #0f172a);
    padding: 22px 20px 18px;
    border-radius: 18px;
    width: 100%;
    max-width: 380px;
    max-height: calc(100vh - 32px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.06),
        0 10px 30px -10px rgba(15, 23, 42, 0.20),
        0 20px 50px -20px rgba(15, 23, 42, 0.20);
    position: relative;
    border: 1px solid var(--us-border, rgba(15, 23, 42, 0.08));
    transform: translateY(8px) scale(0.98);
    opacity: 0;
    transition:
        opacity 180ms cubic-bezier(0.22, 0.61, 0.36, 1),
        transform 200ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.modal.show .modal-content {
    transform: translateY(0) scale(1);
    opacity: 1;
}

body.dark-theme .modal-content {
    background-color: var(--us-bg, #1f1f23);
    color: var(--us-text, #f1f5f9);
    border-color: var(--us-border-strong, rgba(255, 255, 255, 0.16));
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.4),
        0 10px 30px -10px rgba(0, 0, 0, 0.6),
        0 20px 50px -20px rgba(0, 0, 0, 0.5);
}

.modal-content h3 {
    margin: 0 0 16px 0;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--us-text, #0f172a);
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -0.01em;
    padding-right: 32px; /* место под крестик */
}

body.dark-theme .modal-content h3 {
    color: var(--us-text, #f1f5f9);
}

.modal-close {
    position: absolute;
    top: 14px;
    right: 14px;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    cursor: pointer;
    color: var(--us-text-muted, #64748b);
    background: transparent;
    border: 0;
    border-radius: 10px;
    transition:
        background-color 160ms cubic-bezier(0.22, 0.61, 0.36, 1),
        color 160ms cubic-bezier(0.22, 0.61, 0.36, 1),
        transform 160ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.modal-close:hover {
    color: var(--us-text, #0f172a);
    background: var(--us-hover, rgba(15, 23, 42, 0.05));
}

.modal-close:active {
    transform: scale(0.94);
}

.modal-close:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(36, 129, 204, 0.25);
}

body.dark-theme .modal-close {
    color: var(--us-text-muted, #94a3b8);
}

body.dark-theme .modal-close:hover {
    color: var(--us-text, #f1f5f9);
    background: var(--us-hover, rgba(255, 255, 255, 0.06));
}

.modal h3 {
    margin: 0 0 15px 0;
    color: var(--us-text, #0f172a);
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -0.01em;
}

body.dark-theme .modal h3 {
    color: var(--us-text, #f1f5f9);
}

/* ----- Фильтры в шапке модалки (Год / Месяц) ----- */
.modal-filter {
    display: flex;
    gap: 10px;
    margin-bottom: 14px;
}

.modal-filter select,
.modal-filter .modal-select {
    flex: 1;
    min-width: 0;
    padding: 10px 36px 10px 14px;
    border: 1px solid var(--us-border-strong, rgba(15, 23, 42, 0.14));
    border-radius: 12px;
    background-color: var(--us-bg, #ffffff);
    color: var(--us-text, #0f172a);
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    cursor: pointer;
    transition:
        border-color 160ms cubic-bezier(0.22, 0.61, 0.36, 1),
        box-shadow 200ms cubic-bezier(0.22, 0.61, 0.36, 1),
        background-color 160ms cubic-bezier(0.22, 0.61, 0.36, 1);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='m6 9 6 6 6-6'/></svg>");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 16px 16px;
    text-overflow: ellipsis;
}

.modal-filter select:hover {
    border-color: var(--us-accent, #2481cc);
}

.modal-filter select:focus-visible {
    outline: none;
    border-color: var(--us-accent, #2481cc);
    box-shadow: 0 0 0 4px rgba(36, 129, 204, 0.18);
}

body.dark-theme .modal-filter select {
    background-color: var(--us-bg, #1f1f23);
    color: var(--us-text, #f1f5f9);
    border-color: var(--us-border-strong, rgba(255, 255, 255, 0.16));
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='m6 9 6 6 6-6'/></svg>");
}

body.dark-theme .modal-filter select:focus-visible {
    box-shadow: 0 0 0 4px rgba(94, 177, 255, 0.28);
}

/* ----- Список дат (scrollable-select) ----- */
.scrollable-select {
    width: 100%;
    border: 1px solid var(--us-border-strong, rgba(15, 23, 42, 0.14));
    border-radius: 12px;
    background-color: var(--us-bg, #ffffff);
    color: var(--us-text, #0f172a);
    padding: 4px;
    font: inherit;
    font-size: 14px;
    max-height: 200px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: var(--us-border-strong, rgba(15, 23, 42, 0.14)) transparent;
}

.scrollable-select::-webkit-scrollbar {
    width: 8px;
}

.scrollable-select::-webkit-scrollbar-thumb {
    background: var(--us-border-strong, rgba(15, 23, 42, 0.14));
    border-radius: 8px;
}

.scrollable-select option {
    padding: 10px 12px;
    cursor: pointer;
    border-radius: 8px;
    margin: 2px 0;
    transition: background-color 120ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.scrollable-select option:hover {
    background-color: var(--us-hover, rgba(15, 23, 42, 0.05));
    color: var(--us-text, #0f172a);
}

.scrollable-select option:checked,
.scrollable-select option:focus {
    background-color: var(--us-active, rgba(36, 129, 204, 0.12));
    color: var(--us-accent, #2481cc);
    font-weight: 600;
}

body.dark-theme .scrollable-select {
    background-color: var(--us-bg, #1f1f23);
    color: var(--us-text, #f1f5f9);
    border-color: var(--us-border-strong, rgba(255, 255, 255, 0.16));
}

body.dark-theme .scrollable-select option:hover {
    background-color: var(--us-hover, rgba(255, 255, 255, 0.06));
    color: var(--us-text, #f1f5f9);
}

body.dark-theme .scrollable-select option:checked,
body.dark-theme .scrollable-select option:focus {
    background-color: var(--us-active, rgba(94, 177, 255, 0.18));
    color: var(--us-accent, #5eb1ff);
}

/* ----- Поле времени ----- */
.modal-time {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 14px;
    padding: 12px 14px;
    background-color: var(--us-hover, rgba(15, 23, 42, 0.03));
    border-radius: 12px;
    border: 1px solid var(--us-border, rgba(15, 23, 42, 0.08));
}

body.dark-theme .modal-time {
    background-color: var(--us-hover, rgba(255, 255, 255, 0.04));
    border-color: var(--us-border, rgba(255, 255, 255, 0.08));
}

.modal-time label {
    flex-shrink: 0;
    font-size: 13px;
    font-weight: 500;
    color: var(--us-text-muted, #64748b);
    margin: 0;
    letter-spacing: 0.01em;
}

body.dark-theme .modal-time label {
    color: var(--us-text-muted, #94a3b8);
}

.modal-time input {
    flex: 1;
    min-width: 0;
    padding: 4px 4px;
    border: 1px solid var(--us-border-strong, rgba(15, 23, 42, 0.14));
    border-radius: 10px;
    background-color: var(--us-bg, #ffffff);
    color: var(--us-text, #0f172a);
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    color-scheme: light;
    transition:
        border-color 160ms cubic-bezier(0.22, 0.61, 0.36, 1),
        box-shadow 200ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.modal-time input:focus-visible {
    outline: none;
    border-color: var(--us-accent, #2481cc);
    box-shadow: 0 0 0 4px rgba(36, 129, 204, 0.18);
}

body.dark-theme .modal-time input {
    background-color: var(--us-bg, #1f1f23);
    color: var(--us-text, #f1f5f9);
    border-color: none;
    color-scheme: dark;
}

body.dark-theme .modal-time input:focus-visible {
    box-shadow: 0 0 0 4px rgba(94, 177, 255, 0.28);
}

/* ----- Кнопки в модалке ----- */
.modal-actions {
    display: flex;
    gap: 10px;
    margin-top: 18px;
}

.modal-btn {
    flex: 1;
    padding: 12px 16px;
    border: 1px solid transparent;
    border-radius: 12px;
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0.005em;
    cursor: pointer;
    min-height: 44px;
    transition:
        background-color 160ms cubic-bezier(0.22, 0.61, 0.36, 1),
        border-color 160ms cubic-bezier(0.22, 0.61, 0.36, 1),
        color 160ms cubic-bezier(0.22, 0.61, 0.36, 1),
        box-shadow 200ms cubic-bezier(0.22, 0.61, 0.36, 1),
        transform 120ms cubic-bezier(0.22, 0.61, 0.36, 1);
    -webkit-appearance: none;
    appearance: none;
}

.modal-btn:active {
    transform: scale(0.985);
}

.modal-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 4px rgba(36, 129, 204, 0.22);
}

.modal-btn-cancel {
    background-color: var(--us-bg, #ffffff);
    color: var(--us-text, #0f172a);
    border-color: var(--us-border-strong, rgba(15, 23, 42, 0.14));
}

.modal-btn-cancel:hover {
    background-color: var(--us-hover, rgba(15, 23, 42, 0.05));
    border-color: var(--us-border-strong, rgba(15, 23, 42, 0.22));
}

body.dark-theme .modal-btn-cancel {
    background-color: transparent;
    color: var(--us-text, #f1f5f9);
    border-color: var(--us-border-strong, rgba(255, 255, 255, 0.20));
}

body.dark-theme .modal-btn-cancel:hover {
    background-color: var(--us-hover, rgba(255, 255, 255, 0.06));
    border-color: var(--us-border-strong, rgba(255, 255, 255, 0.32));
}

.modal-btn-apply {
    background-color: var(--us-accent, #2481cc);
    color: #ffffff;
    border-color: transparent;
    box-shadow: 0 1px 0 rgba(15, 23, 42, 0.05), 0 4px 12px -4px rgba(36, 129, 204, 0.4);
}

.modal-btn-apply:hover {
    background-color: var(--button-hover, #1d6fb3);
    box-shadow: 0 1px 0 rgba(15, 23, 42, 0.05), 0 6px 16px -4px rgba(36, 129, 204, 0.55);
}

body.dark-theme .modal-btn-apply {
    background-color: var(--us-accent, #5eb1ff);
    color: #0a0a0c;
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 4px 12px -4px rgba(94, 177, 255, 0.5);
}

body.dark-theme .modal-btn-apply:hover {
    background-color: #7cc2ff;
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 6px 16px -4px rgba(94, 177, 255, 0.7);
}

/* ----- Адаптив + снижение движения ----- */
@media (max-width: 480px) {
    .modal {
        padding: 12px;
    }
    .modal-content {
        max-width: none;
        border-radius: 16px;
        padding: 20px 16px 16px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .modal,
    .modal-content,
    .modal-btn,
    .modal-close,
    .modal-filter select,
    .modal-time input,
    .scrollable-select option {
        transition: none !important;
    }
}

.legend-toggle {
    position: absolute;
    top: 56px; /* под .fullscreen-button (top:10, height ~36, gap ~10) */
    right: 10px;
    z-index: 999;

    display: inline-flex;
    align-items: center;
    gap: 6px;

    padding: 6px 14px;
    border: 1px solid rgba(76, 139, 245, 0.28);
    border-radius: 999px;

    background: linear-gradient(180deg,
                rgba(255, 255, 255, 0.92) 0%,
                rgba(245, 247, 250, 0.86) 100%);
    -webkit-backdrop-filter: blur(10px) saturate(160%);
    backdrop-filter: blur(10px) saturate(160%);
    color: #2c6fd6;

    box-shadow:
        0 2px 4px rgba(15, 23, 42, 0.08),
        0 8px 20px rgba(76, 139, 245, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.95);

    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: 0.01em;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;

    transition:
        background 220ms ease,
        box-shadow 220ms ease,
        border-color 220ms ease,
        color 220ms ease,
        transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.legend-toggle:hover {
    background: linear-gradient(180deg,
                #ffffff 0%,
                #f0f4ff 100%);
    border-color: rgba(76, 139, 245, 0.5);
    color: #1e5fb8;
    box-shadow:
        0 3px 6px rgba(15, 23, 42, 0.1),
        0 12px 26px rgba(76, 139, 245, 0.28),
        inset 0 1px 0 rgba(255, 255, 255, 1);
    transform: translateY(-1px);
}

.legend-toggle:active {
    transform: translateY(0) scale(0.97);
    box-shadow:
        0 1px 3px rgba(15, 23, 42, 0.12),
        0 4px 10px rgba(15, 23, 42, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.85);
}

.legend-toggle:focus-visible {
    outline: none;
    box-shadow:
        0 0 0 3px rgba(76, 139, 245, 0.4),
        0 3px 6px rgba(15, 23, 42, 0.1),
        0 12px 26px rgba(76, 139, 245, 0.28),
        inset 0 1px 0 rgba(255, 255, 255, 1);
}

.legend-toggle i,
.legend-toggle__icon {
    font-size: 13px;
    line-height: 1;
    transition: transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.legend-toggle:hover i,
.legend-toggle:hover .legend-toggle__icon {
    transform: rotate(-12deg) scale(1.08);
}

.dark-theme .legend-toggle {
    background: linear-gradient(180deg,
                rgba(45, 55, 72, 0.92) 0%,
                rgba(26, 32, 44, 0.88) 100%);
    border-color: rgba(120, 175, 255, 0.4);
    color: #9ec5ff;
    box-shadow:
        0 2px 4px rgba(0, 0, 0, 0.5),
        0 10px 24px rgba(76, 139, 245, 0.28),
        inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

.dark-theme .legend-toggle:hover {
    background: linear-gradient(180deg,
                rgba(60, 78, 105, 0.95) 0%,
                rgba(36, 50, 70, 0.92) 100%);
    border-color: rgba(150, 200, 255, 0.6);
    color: #cfe2ff;
    box-shadow:
        0 3px 6px rgba(0, 0, 0, 0.55),
        0 14px 32px rgba(76, 139, 245, 0.38),
        inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

/* 3D-кнопка отображается ПОД "Показать легенду" (.legend-toggle).
   Высота pill ~32px + зазор 10px → смещение 102px. */
#threeDToggle {
    top: 102px;
    right: 10px;
}
#threeDToggle.active {
    /* Активный 3D-режим: индиго-градиент вместо голубого */
    background: linear-gradient(135deg,
                rgba(99, 102, 241, 0.95) 0%,
                rgba(139, 92, 246, 0.95) 100%);
    border-color: rgba(99, 102, 241, 0.7);
    color: #ffffff;
    box-shadow:
        0 2px 4px rgba(15, 23, 42, 0.12),
        0 10px 24px rgba(99, 102, 241, 0.4),
        inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
#threeDToggle.active:hover {
    background: linear-gradient(135deg,
                rgba(99, 102, 241, 1) 0%,
                rgba(139, 92, 246, 1) 100%);
    border-color: rgba(99, 102, 241, 0.85);
    color: #ffffff;
    box-shadow:
        0 3px 6px rgba(15, 23, 42, 0.18),
        0 14px 32px rgba(99, 102, 241, 0.5),
        inset 0 1px 0 rgba(255, 255, 255, 0.3);
}

/* === Floating playback-show button ==================================
   Кнопка "Управление" появляется в нижней части карты по центру,
   когда вся панель playback скрыта через .panel-collapsed.
   Расположение совпадает с тем местом, куда уезжает панель,
   поэтому пользователь сразу понимает, что делать. */
#playbackShowButton {
    /* Координаты: по центру внизу карты */
    top: auto;
    right: auto;
    left: 50%;
    bottom: 18px;

    /* Базовая геометрия pill-кнопки */
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 18px 9px 16px;
    border-radius: 999px;
    user-select: none;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.01em;
    white-space: nowrap;

    /* Glassmorphism в стиле playback-панели */
    background: linear-gradient(180deg,
                rgba(255, 255, 255, 0.92) 0%,
                rgba(245, 247, 250, 0.86) 100%);
    border: 1px solid rgba(76, 139, 245, 0.28);
    color: #2c6fd6;
    box-shadow:
        0 2px 4px rgba(15, 23, 42, 0.08),
        0 8px 20px rgba(76, 139, 245, 0.22),
        inset 0 1px 0 rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(10px) saturate(160%);
    -webkit-backdrop-filter: blur(10px) saturate(160%);

    /* CSS-переменные для унификации translate-X/Y в transform:
       --pb-tx держит горизонтальное центрирование,
       --pb-ty управляет вертикальным смещением для анимации. */
    --pb-tx: -50%;
    --pb-ty: 18px;
    transform: translate(var(--pb-tx), var(--pb-ty));

    /* По умолчанию скрыта (opacity 0, pointer-events none).
       Класс .is-visible добавляется JS при сворачивании панели. */
    opacity: 0;
    pointer-events: none;

    /* Анимация отключена по требованию: все переходы между
       состояниями (.is-visible / :hover / :active / :focus-visible)
       происходят мгновенно, без transition. */
    transition: none;
    z-index: 1001; /* выше панели (998) и контролов карты (999) */
}

#playbackShowButton i {
    font-size: 14px;
    line-height: 1;
    color: inherit;
    /* Анимация иконки (rotate/scale на hover) отключена. */
    transition: none;
}

#playbackShowButton.is-visible {
    --pb-ty: 0;
    opacity: 1;
    pointer-events: auto;
}

/* Поднимаем и усиливаем glow при hover (без анимации). */
#playbackShowButton.is-visible:hover {
    --pb-ty: -2px;
    /* Явно дублируем transform сюда, чтобы центрирование
       --pb-tx: -50% не перебивалось общим .legend-toggle:hover. */
    transform: translate(var(--pb-tx), var(--pb-ty));
    background: linear-gradient(180deg,
                #ffffff 0%,
                #f0f4ff 100%);
    border-color: rgba(76, 139, 245, 0.55);
    box-shadow:
        0 3px 6px rgba(15, 23, 42, 0.1),
        0 12px 28px rgba(76, 139, 245, 0.32),
        inset 0 1px 0 rgba(255, 255, 255, 1);
}

/* Раньше иконка поворачивалась/масштабировалась на hover
   (transform: rotate(-12deg) scale(1.08)). Анимация отключена —
   правило оставлено пустым, чтобы случайно не вернуть transform. */

#playbackShowButton.is-visible:active {
    --pb-ty: 0;
    transform: translate(var(--pb-tx), var(--pb-ty)) scale(0.96);
    box-shadow:
        0 1px 3px rgba(15, 23, 42, 0.12),
        0 4px 10px rgba(15, 23, 42, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.85);
}

#playbackShowButton:focus-visible {
    outline: none;
}

#playbackShowButton.is-visible:focus-visible {
    box-shadow:
        0 0 0 3px rgba(76, 139, 245, 0.4),
        0 3px 6px rgba(15, 23, 42, 0.1),
        0 12px 28px rgba(76, 139, 245, 0.32),
        inset 0 1px 0 rgba(255, 255, 255, 1);
}

/* === Dark theme ===================================================== */
.dark-theme #playbackShowButton {
    background: linear-gradient(180deg,
                rgba(45, 55, 72, 0.92) 0%,
                rgba(26, 32, 44, 0.88) 100%);
    border-color: rgba(120, 175, 255, 0.4);
    color: #9ec5ff;
    box-shadow:
        0 2px 4px rgba(0, 0, 0, 0.5),
        0 10px 24px rgba(76, 139, 245, 0.3),
        inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

.dark-theme #playbackShowButton.is-visible:hover {
    background: linear-gradient(180deg,
                rgba(60, 78, 105, 0.95) 0%,
                rgba(36, 50, 70, 0.92) 100%);
    border-color: rgba(150, 200, 255, 0.6);
    box-shadow:
        0 3px 6px rgba(0, 0, 0, 0.55),
        0 14px 32px rgba(76, 139, 245, 0.4),
        inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

/* === Mobile ========================================================= */
@media (max-width: 480px) {
    #playbackShowButton {
        bottom: 12px;
        padding: 8px 14px 8px 12px;
        font-size: 12px;
    }
    #playbackShowButton i {
        font-size: 13px;
    }
}

/* === Адаптивные кнопки карты =======================================
   На узких экранах кнопки переходят в icon-only режим,
   чтобы не наслаиваться друг на друга и на селектор маршрута.
   Текстовая метка заменяется на tooltip в title="" и aria-label.
   При fullscreen карты (#map.fullscreen-map) кнопки масштабируются
   вверх вместе с размером карты на экране. */
@media (max-width: 600px) {
    /* Скрываем текстовые подписи — оставляем только иконки */
    .fullscreen-button__text,
    .legend-toggle__text,
    #threeDToggleLabel {
        display: none !important;
    }

    /* Делаем кнопки квадратными (только иконка), плотнее */
    .fullscreen-button,
    #legendToggle,
    #threeDToggle {
        padding: 8px !important;
        gap: 0 !important;
    }

    /* Корректируем вертикальный стек: высота квадратной кнопки ~36px,
       расстояние 6px → смещения пересчитываем. */
    #legendToggle { top: 54px !important; }
    #threeDToggle { top: 98px !important; }

    /* Иконки чуть крупнее для лучшей видимости */
    .fullscreen-button__icon {
        font-size: 15px !important;
    }
    #legendToggle .legend-toggle__icon {
        font-size: 14px !important;
    }
    #threeDToggle i {
        font-size: 15px !important;
    }

    /* Селектор маршрута тоже сжимаем: прячем текст маршрута,
       оставляем только иконку route + chevron-dropdown */
    .route-selector-wrap .custom-select-text {
        display: none !important;
    }
    .route-selector-wrap {
        padding: 5px 8px 5px 12px !important;
    }
    .route-selector-wrap .custom-select-trigger {
        padding: 7px 4px !important;
        gap: 4px !important;
    }

    /* Блок легенды (если открыт) прижимаем под compact-кнопки */
    .legend {
        top: 142px !important;
        max-width: calc(100vw - 20px) !important;
    }
}

/* Очень узкие экраны (<= 380px): ультра-компактные кнопки */
@media (max-width: 380px) {
    .fullscreen-button,
    #legendToggle,
    #threeDToggle {
        padding: 7px !important;
    }
    .route-selector-wrap {
        padding: 4px 6px 4px 10px !important;
    }
}

/* === Fullscreen карты: кнопки масштабируются вместе с размером ====
   Когда карта развёрнута на весь экран, она может занимать
   большое пространство (особенно на десктоп-мониторах).
   Увеличиваем кнопки и шрифт для комфортного таргетинга.
   Размер зависит от min(vw, vh) — пропорционально "короткой"
   стороне viewport, чтобы кнопки выглядели гармонично и на
   вертикальных планшетах, и на широких мониторах. */
#map.fullscreen-map .fullscreen-button,
#map.fullscreen-map .legend-toggle,
#map.fullscreen-map .route-selector-wrap,
#map.fullscreen-map #playbackShowButton {
    font-size: clamp(13px, 1.4vmin, 16px);
    padding-top: clamp(7px, 1vmin, 11px);
    padding-bottom: clamp(7px, 1vmin, 11px);
    padding-left: clamp(13px, 1.6vmin, 20px);
    padding-right: clamp(13px, 1.6vmin, 20px);
}

#map.fullscreen-map .fullscreen-button__icon,
#map.fullscreen-map .legend-toggle__icon,
#map.fullscreen-map .route-selector-wrap .custom-select-icon,
#map.fullscreen-map #playbackShowButton i {
    font-size: clamp(13px, 1.6vmin, 17px);
}

/* При fullscreen карты — ОТМЕНЯЕМ компактный icon-only режим,
   даже если viewport браузера ≤600px. Карта занимает весь экран,
   места достаточно для полноразмерных кнопок с текстом.
   Viewport браузера при fullscreen карты НЕ меняется, поэтому
   @media (max-width: 600px) продолжает срабатывать — нужно явно
   переопределить его правила через более специфичный селектор
   + !important. */
@media (max-width: 600px) {
    /* Возвращаем текстовые подписи */
    #map.fullscreen-map .fullscreen-button__text,
    #map.fullscreen-map .legend-toggle__text,
    #map.fullscreen-map #threeDToggleLabel,
    #map.fullscreen-map .route-selector-wrap .custom-select-text {
        display: inline !important;
    }

    /* Полноразмерные кнопки с гэпом для иконка+текст */
    #map.fullscreen-map .fullscreen-button,
    #map.fullscreen-map #legendToggle,
    #map.fullscreen-map #threeDToggle {
        padding: 8px 16px !important;
        gap: 8px !important;
    }

    /* Десктопный вертикальный стек (не мобильный) */
    #map.fullscreen-map #legendToggle { top: 56px !important; }
    #map.fullscreen-map #threeDToggle { top: 102px !important; }

    /* Селектор маршрута — полноразмерный */
    #map.fullscreen-map .route-selector-wrap {
        padding: 5px 6px 5px 14px !important;
    }
    #map.fullscreen-map .route-selector-wrap .custom-select-trigger {
        padding: 7px 8px 7px 4px !important;
        gap: 6px !important;
    }

    /* Блок легенды (если открыт) — под десктопной кнопкой */
    #map.fullscreen-map .legend {
        top: 102px !important;
        max-width: 280px !important;
    }
}

/* Полноразмерные иконки при fullscreen карты (вместо icon-only).
   На мобильных fullscreen карты — иконки крупные для тапа пальцем.
   На десктопе — обычный размер из общего fullscreen правила выше. */
@media (max-width: 600px) {
    #map.fullscreen-map .fullscreen-button__icon,
    #map.fullscreen-map #legendToggle .legend-toggle__icon,
    #map.fullscreen-map #threeDToggle i {
        font-size: 14px !important;
    }
    #map.fullscreen-map .route-selector-wrap .custom-select-icon {
        font-size: 14px !important;
    }
}

/* Кнопки вверху карты: полупрозрачные (0.85) в обычном состоянии,
   полностью непрозрачные (1) при наведении — единый стиль для
   #fullscreenButton, #legendToggle, #threeDToggle.
   (#playbackShowButton и .route-selector-wrap используют собственные
   правила выше и НЕ участвуют в этом групповом opacity-правиле,
   чтобы не конфликтовать с их собственной opacity/glassmorphism
   визуализацией.) */
/* Прозрачность (opacity 0.85 → 1 на hover) для верхних кнопок карты
   ранее применялась групповым правилом к #fullscreenButton, #legendToggle
   и #threeDToggle. Сейчас все три используют собственный glassmorphism
   gradient в составе pill-кнопки, и общее приглушение делает их блёклыми.
   При hover каждый селектор уже управляет background/border-color/shadow
   в своих собственных правилах выше. */

/* Селектор маршрута на карте (miniapp). Показывается, когда загружено
   более одного сегмента маршрута. Расположен в верхнем левом углу
   карты — в освободившемся месте после переноса #playbackShowButton
   в нижнюю центральную часть. Внешний вид унифицирован с playback
   panel и playbackShowButton: glassmorphism pill + голубая рамка +
   многослойная тень. */
.native-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    opacity: 0 !important;
    pointer-events: none !important;
    left: -9999px !important;
    top: auto !important;
    margin: 0 !important;
    padding: 0 !important;
}
.route-selector-wrap {
    /* Позиция: верхний левый угол карты */
    position: absolute;
    top: 10px;
    left: 10px;
    right: auto;
    z-index: 999;

    /* Геометрия pill-капсулы в стиле #playbackShowButton */
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 6px 5px 14px;
    border-radius: 999px;

    /* Glassmorphism: полупрозрачный градиент + blur */
    background: linear-gradient(180deg,
                rgba(255, 255, 255, 0.92) 0%,
                rgba(245, 247, 250, 0.86) 100%) !important;
    -webkit-backdrop-filter: blur(10px) saturate(160%) !important;
    backdrop-filter: blur(10px) saturate(160%) !important;
    border: 1px solid rgba(76, 139, 245, 0.28) !important;
    box-shadow:
        0 2px 4px rgba(15, 23, 42, 0.08),
        0 8px 20px rgba(76, 139, 245, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.95) !important;
    color: #2c6fd6 !important;
    font-size: 13px !important;
    font-weight: 600;
    letter-spacing: 0.01em;
    user-select: none;
    max-width: calc(100vw - 20px);

    /* Плавный переход для hover (на случай если понадобится в будущем) */
    transition:
        background 220ms ease,
        box-shadow 220ms ease,
        border-color 220ms ease,
        transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.route-selector-wrap:hover {
    background: linear-gradient(180deg,
                #ffffff 0%,
                #f0f4ff 100%) !important;
    border-color: rgba(76, 139, 245, 0.5) !important;
    box-shadow:
        0 3px 6px rgba(15, 23, 42, 0.1),
        0 12px 26px rgba(76, 139, 245, 0.28),
        inset 0 1px 0 rgba(255, 255, 255, 1) !important;
}

.dark-theme .route-selector-wrap {
    background: linear-gradient(180deg,
                rgba(45, 55, 72, 0.92) 0%,
                rgba(26, 32, 44, 0.88) 100%) !important;
    border-color: rgba(120, 175, 255, 0.4) !important;
    color: #9ec5ff !important;
    box-shadow:
        0 2px 4px rgba(0, 0, 0, 0.5),
        0 10px 24px rgba(76, 139, 245, 0.28),
        inset 0 1px 0 rgba(255, 255, 255, 0.08) !important;
}

.dark-theme .route-selector-wrap:hover {
    background: linear-gradient(180deg,
                rgba(60, 78, 105, 0.95) 0%,
                rgba(36, 50, 70, 0.92) 100%) !important;
    border-color: rgba(150, 200, 255, 0.6) !important;
    box-shadow:
        0 3px 6px rgba(0, 0, 0, 0.55),
        0 14px 32px rgba(76, 139, 245, 0.38),
        inset 0 1px 0 rgba(255, 255, 255, 0.12) !important;
}

.route-selector-wrap .custom-select-icon {
    color: inherit !important;
    font-size: 14px !important;
    flex-shrink: 0 !important;
    transition: transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.route-selector-wrap:hover .custom-select-icon {
    transform: rotate(-12deg) scale(1.08);
}

.route-selector-wrap .custom-select {
    position: relative !important;
    display: inline-flex !important;
    align-items: center !important;
}
/* Сброс глобальных стилей input/select/button (в miniapp на них
   действует `input, select, button { display: block; margin: 10px 0;
   padding: 10px/12px; width: 100%; ... }`). Для элементов селектора
   маршрута эти правила неуместны — они растягивают триггер на всю
   ширину и добавляют лишние отступы. Переопределяем ТОЛЬКО внутри
   .route-selector-wrap, чтобы не задеть остальные формы. */
.route-selector-wrap select,
.route-selector-wrap button,
.route-selector-wrap input {
    display: inline-block !important;
    margin: 0 !important;
    padding: 0 !important;
    width: auto !important;
    box-sizing: border-box !important;
    border: none !important;
    border-radius: 0 !important;
    background: transparent !important;
    color: inherit !important;
    font-size: inherit !important;
    font-family: inherit !important;
    transition: none !important;
}
.route-selector-wrap select:focus,
.route-selector-wrap button:focus,
.route-selector-wrap input:focus {
    outline: none !important;
    box-shadow: none !important;
}
/* Pill-кнопка trigger внутри капсулы .route-selector-wrap.
   Прозрачная, наследует визуал pill — свой фон/тень не нужны,
   интерактивность даёт вся капсула. */
.route-selector-wrap .custom-select-trigger {
    background: transparent !important;
    border: none !important;
    color: inherit !important;
    font-family: inherit !important;
    font-size: 13px !important;
    font-weight: 600 !important;
    line-height: 1.2 !important;
    letter-spacing: 0.01em !important;
    padding: 7px 8px 7px 4px !important;
    cursor: pointer !important;
    display: inline-flex !important;
    align-items: center !important;
    gap: 6px !important;
    border-radius: 999px !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    transition: color 220ms ease !important;
    text-align: left !important;
    white-space: nowrap !important;
    box-shadow: none !important;
}
.route-selector-wrap .custom-select-trigger:hover {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
}
.route-selector-wrap.is-open .custom-select-trigger {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
}
.route-selector-wrap .custom-select-arrow {
    color: inherit !important;
    opacity: 0.7 !important;
    font-size: 10px !important;
    transition: transform 280ms cubic-bezier(0.22, 0.61, 0.36, 1),
                opacity 220ms ease !important;
}
.route-selector-wrap:hover .custom-select-arrow {
    opacity: 1;
}
.dark-theme .route-selector-wrap .custom-select-arrow {
    color: inherit !important;
}

/* Текст внутри custom-select-trigger (например, "Все маршруты") в miniapp */
.route-selector-wrap .custom-select-text {
    font-size: 13px !important;
    font-weight: 600 !important;
}
.route-selector-wrap.is-open .custom-select-arrow {
    transform: rotate(180deg) !important;
    opacity: 1;
}
/* Выпадающий список: glassmorphism с blur, как у trip.html. */
.route-selector-wrap .custom-select-options {
    position: absolute !important;
    top: calc(100% + 8px) !important;
    right: auto !important;
    left: 0 !important;
    min-width: 100% !important;
    width: max-content !important;
    max-width: 280px !important;
    /* Высота под 4 пункта + внутренний padding 6px*2 = ~156-168px.
       Скроллится по вертикали, если пунктов больше. */
    max-height: 160px !important;
    overflow-y: auto !important;
    overflow-x: hidden !important;
    overscroll-behavior: contain !important;
    margin: 0 !important;
    padding: 6px !important;
    list-style: none !important;
    background-color: rgba(255, 255, 255, 0.95) !important;
    -webkit-backdrop-filter: blur(24px) !important;
    backdrop-filter: blur(24px) !important;
    border: 1px solid rgba(0, 0, 0, 0.1) !important;
    border-radius: 14px !important;
    box-shadow: 0 24px 50px -12px rgba(0, 0, 0, 0.4),
                0 0 0 1px rgba(99, 102, 241, 0.1) !important;
    color: #0f172a !important;
    z-index: 1000 !important;
    display: block !important;
    opacity: 0 !important;
    transform: translateY(-8px) scale(0.96) !important;
    transform-origin: top left !important;
    pointer-events: none !important;
    transition: opacity 0.2s ease, transform 0.2s ease !important;
    scrollbar-gutter: stable !important;
}
.dark-theme .route-selector-wrap .custom-select-options {
    background-color: rgba(15, 23, 42, 0.95) !important;
    border-color: rgba(255, 255, 255, 0.14) !important;
    color: #e8ecf6 !important;
    box-shadow: 0 24px 50px -12px rgba(0, 0, 0, 0.7),
                0 0 0 1px rgba(99, 102, 241, 0.15) !important;
}
.route-selector-wrap.is-open .custom-select-options {
    opacity: 1 !important;
    transform: translateY(0) scale(1) !important;
    pointer-events: auto !important;
}
.route-selector-wrap.is-flipped .custom-select-options {
    top: auto !important;
    bottom: calc(100% + 8px) !important;
    transform-origin: bottom left !important;
    transform: translateY(8px) scale(0.96) !important;
}
.route-selector-wrap.is-flipped.is-open .custom-select-options {
    transform: translateY(0) scale(1) !important;
}
.route-selector-wrap .custom-select-options li {
    padding: 6px 14px !important;
    cursor: pointer !important;
    display: flex !important;
    align-items: center !important;
    gap: 10px !important;
    font-size: 12px !important;
    font-weight: 600 !important;
    letter-spacing: 0.02em !important;
    color: inherit !important;
    border-radius: 9px !important;
    list-style: none !important;
    white-space: nowrap !important;
    user-select: none !important;
    transition: background-color 0.15s ease, color 0.15s ease !important;
}
.route-selector-wrap .custom-select-options li:hover {
    background-color: rgba(0, 0, 0, 0.05) !important;
    color: inherit !important;
}
.dark-theme .route-selector-wrap .custom-select-options li:hover {
    background-color: rgba(255, 255, 255, 0.06) !important;
    color: inherit !important;
}
.route-selector-wrap .custom-select-options li.is-active {
    background: linear-gradient(135deg, rgba(99, 102, 241, 0.18), rgba(16, 185, 129, 0.12)) !important;
    color: inherit !important;
}
.route-selector-wrap .custom-select-options .custom-select-label {
    flex: 1 !important;
}
/* Обёртка для названия маршрута + дата/время первой точки.
   Нужна, чтобы meta отображалась отдельной строкой под label. */
.route-selector-wrap .custom-select-options .custom-select-main {
    flex: 1 1 auto !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 1px !important;
    min-width: 0 !important;
    line-height: 1.15 !important;
}
/* Дата/время первой точки маршрута — мелким 8px шрифтом под label. */
.route-selector-wrap .custom-select-options .custom-select-meta {
    font-size: 8px !important;
    font-weight: 400 !important;
    opacity: 0.65 !important;
    line-height: 1.1 !important;
    letter-spacing: 0 !important;
    white-space: nowrap !important;
    color: inherit !important;
}
.route-selector-wrap .custom-select-options .custom-select-check {
    color: var(--button-bg) !important;
    font-size: 12px !important;
    opacity: 0 !important;
    transform: scale(0.6) !important;
    transition: opacity 0.15s ease, transform 0.15s ease !important;
}
.route-selector-wrap .custom-select-options li.is-active .custom-select-check {
    opacity: 1 !important;
    transform: scale(1) !important;
}
/* Скроллбар внутри выпадающего списка — как в trip.html. */
.route-selector-wrap .custom-select-options::-webkit-scrollbar { width: 6px !important; }
.route-selector-wrap .custom-select-options::-webkit-scrollbar-track { background: transparent !important; }
.route-selector-wrap .custom-select-options::-webkit-scrollbar-thumb {
    background: rgba(0, 0, 0, 0.18) !important;
    border-radius: 999px !important;
}
.dark-theme .route-selector-wrap .custom-select-options::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.08) !important;
}
.route-selector-wrap .custom-select-options::-webkit-scrollbar-thumb:hover {
    background: rgba(0, 0, 0, 0.3) !important;
}
.dark-theme .route-selector-wrap .custom-select-options::-webkit-scrollbar-thumb:hover {
    background: rgba(255, 255, 255, 0.14) !important;
}

/* Тултип «Маршрут N · Начало/Конец» рядом с circleMarker-ами начала и
   конца сегментов. Стилизация совпадает с trip.html:
   прозрачный фон + тонкая граница + светлый текст (без заливки
   var(--button-bg), как в старой версии miniapp). */
.route-segment-tooltip {
    background: rgba(20, 27, 56, 0) !important;
    color: var(--text-color, #0f172a) !important;
    border: 1px solid var(--border-color, rgba(0, 0, 0, 0.14)) !important;
    box-shadow: none !important;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
    font-weight: 600 !important;
    font-size: 11px !important;
    line-height: 1.3 !important;
    border-radius: 8px !important;
    padding: 0 !important;
    white-space: nowrap !important;
    background-color: rgba(255, 255, 255, 0.92) !important;
    -webkit-backdrop-filter: blur(6px) !important;
    backdrop-filter: blur(6px) !important;
}
.dark-theme .route-segment-tooltip {
    color: #e8ecf6 !important;
    border-color: rgba(255, 255, 255, 0.14) !important;
    background-color: rgba(20, 27, 56, 0.85) !important;
}
/* Дефолтные стили MapLibre красят .maplibregl-popup-content в тёмный
   цвет — это «просвечивает» сквозь наш полупрозрачный фон popup'а и
   делает текст нечитаемым в светлой теме. Переопределяем фон и
   цвет текста внутреннего контейнера, чтобы он соответствовал
   текущей теме. */
.route-segment-tooltip .maplibregl-popup-content {
    background-color: rgba(255, 255, 255, 0.92) !important;
    color: #0f172a !important;
    border-radius: 8px !important;
    padding: 4px 8px !important;
    box-shadow: none !important;
}
.dark-theme .route-segment-tooltip .maplibregl-popup-content {
    background-color: rgb(85 85 85 / 85%) !important;
    color: #e8ecf6 !important;
}
/* Скрываем «хвостик» Leaflet-тултипа, чтобы мини-карта выглядела
   аккуратно (как в trip.html). */
.route-segment-tooltip::before { display: none !important; }
.route-segment-tooltip::after { display: none !important; }

/* Позиция #legendToggle наследуется от .legend-toggle (top: 56px).
   Раньше требовалось отдельное правило для старой раскладки; сейчас
   оно не нужно — оставлено как no-op для документирования. */

/* Блок легенды открывается ПОД pill-кнопкой #legendToggle
   (top:56 + ~32px высота + ~6px зазор = ~94px). */
.legend {
    position: absolute;
    top: 102px;
    right: 10px;
    z-index: 999;
    background-color: rgba(255, 255, 255, 0.95);
    padding: 12px 15px;
    border-radius: 10px;
    box-shadow: 0 2px 15px rgba(0, 0, 0, 0.25);
    max-width: 280px;
    font-size: 12px;
}

.dark-theme .legend {
    background-color: rgba(58, 58, 58, 0.95);
}

.legend.hidden {
    display: none;
}

.legend-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 10px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--input-border);
    font-weight: 600;
    color: var(--text-color);
}

.legend-close {
    background: none;
    border: none;
    font-size: 20px;
    cursor: pointer;
    color: #888;
    padding: 0;
    margin: 0;
    width: auto;
    line-height: 1;
}

.legend-close:hover {
    color: #333;
    background: none;
}

.dark-theme .legend-close {
    color: #aaa;
}

.dark-theme .legend-close:hover {
    color: #fff;
    background: none;
}

.legend-item {
    display: flex;
    align-items: flex-start;
    margin-bottom: 10px;
    padding: 4px 0;
}

.legend-item:last-child {
    margin-bottom: 0;
}

.legend-icon {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    margin-right: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.legend-icon img {
    width: 24px;
    height: 24px;
}

.legend-text {
    flex: 1;
}

.legend-text strong {
    display: block;
    color: var(--text-color);
    font-size: 13px;
    margin-bottom: 2px;
}

.legend-text p {
    margin: 0;
    color: #666;
    font-size: 11px;
    line-height: 1.3;
}

.dark-theme .legend-text p {
    color: #aaa;
}

.top-menu {
    display: flex;
    justify-content: space-around;
    background: var(--card-bg);
    padding: 8px 4px;
    border-bottom: 1px solid var(--input-border);
    position: sticky;
    top: 0;
    z-index: 1000;
    box-shadow: 0 2px 8px var(--card-shadow);
}

.menu-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    background: transparent;
    border: none;
    padding: 6px 12px;
    cursor: pointer;
    color: var(--text-color);
    border-radius: 8px;
    transition: background-color 0.2s;
    width: auto;
    margin: 0;
    font-size: 12px;
}

.menu-btn:hover {
    background-color: var(--button-bg);
    color: white;
}

.menu-btn.active {
    background-color: var(--button-bg);
    color: white;
}

.menu-icon {
    font-size: 20px;
    margin-bottom: 2px;
}

/* =========================================================
   Bottom navigation — floating glass dock
   ========================================================= */
.bottom-nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(20px + max(12px, env(safe-area-inset-bottom)));
    z-index: 1000;
    display: flex;
    justify-content: center;
    pointer-events: none; /* only the pill catches events */
    padding: 0 12px;
    animation: bottom-nav-in 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.bottom-nav-pill {
    pointer-events: auto;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-around;
    gap: 2px;
    width: 100%;
    max-width: 520px;
    padding: 6px;
    border-radius: 22px;
    background: color-mix(in srgb, var(--card-bg) 78%, transparent);
    -webkit-backdrop-filter: saturate(180%) blur(22px);
    backdrop-filter: saturate(180%) blur(22px);
    box-shadow:
        0 10px 30px -10px rgba(0, 0, 0, 0.35),
        0 2px 8px rgba(0, 0, 0, 0.12),
        inset 0 1px 0 rgba(255, 255, 255, 0.12);
    border: 1px solid color-mix(in srgb, var(--input-border) 70%, transparent);
    overflow: hidden;
    isolation: isolate;
}

/* Subtle gradient sheen across the dock */
.bottom-nav-pill::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(
        180deg,
        rgba(255, 255, 255, 0.08) 0%,
        rgba(255, 255, 255, 0) 50%
    );
    pointer-events: none;
    z-index: 0;
}

/* Sliding pill indicator under the active tab */
.bottom-nav-indicator {
    position: absolute;
    top: 16px;
    bottom: 16px;
    left: 0px;
    width: var(--nav-indicator-w, 0px);
    transform: translate3d(var(--nav-indicator-x, 0px), 0, 0);
    border-radius: 14px;
    background: linear-gradient(
        135deg,
        var(--button-bg) 0%,
        color-mix(in srgb, var(--button-bg) 70%, #ffffff 30%) 100%
    );
    box-shadow:
        0 6px 16px -4px color-mix(in srgb, var(--button-bg) 60%, transparent),
        inset 0 1px 0 rgba(255, 255, 255, 0.35);
    transition:
        transform 0.45s cubic-bezier(0.34, 1.36, 0.64, 1),
        width 0.35s cubic-bezier(0.34, 1.36, 0.64, 1),
        opacity 0.25s ease;
    z-index: 0;
    opacity: 0;
}

.bottom-nav-pill.ready .bottom-nav-indicator {
    opacity: 1;
}

/* Hover: подсвечиваем наведённый таб тем же градиентом, что у активного.
   Это гарантирует идентичный фон без артефактов скользящего индикатора. */
.nav-tab:hover {
    color: #ffffff;
    background: linear-gradient(
        135deg,
        var(--button-bg) 0%,
        color-mix(in srgb, var(--button-bg) 70%, #ffffff 30%) 100%
    );
    box-shadow:
        0 6px 16px -4px color-mix(in srgb, var(--button-bg) 60%, transparent),
        inset 0 1px 0 rgba(255, 255, 255, 0.35);
}

.nav-tab:hover .nav-icon {
    transform: translateY(-2px) scale(1.08);
}

.nav-tab:hover .nav-label {
    font-weight: 600;
    letter-spacing: 0.01em;
}

.nav-tab {
    position: relative;
    z-index: 1;
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    padding: 8px 4px 6px;
    cursor: pointer;
    color: var(--text-muted, #8a8f9b);
    border-radius: 16px;
    transition: color 0.25s ease, transform 0.25s ease;
    min-width: 0;
    gap: 3px;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    font-family: inherit;
}

.nav-tab:active {
    transform: scale(0.94);
}

.nav-tab.active {
    color: #ffffff;
}

.nav-tab.active .nav-icon {
    transform: translateY(-2px) scale(1.08);
}

.nav-tab.active .nav-label {
    font-weight: 600;
    letter-spacing: 0.01em;
}

.nav-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    font-size: 20px;
    line-height: 1;
    transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.05));
}

.nav-icon .fa {
    display: block;
}

.nav-label {
    font-size: 10.5px;
    font-weight: 500;
    white-space: nowrap;
    line-height: 1.1;
    transition: font-weight 0.2s ease, letter-spacing 0.2s ease;
}

@keyframes bottom-nav-in {
    from {
        opacity: 0;
        transform: translateY(20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Reduced motion: keep functional look, drop animations */
@media (prefers-reduced-motion: reduce) {
    .bottom-nav,
    .bottom-nav-indicator,
    .nav-tab,
    .nav-icon,
    .nav-label {
        transition: none !important;
        animation: none !important;
    }
}

body.fullscreen-app .bottom-nav,
.fullscreen-map ~ .bottom-nav {
    display: none;
}

body {
    padding-bottom: 140px;
}

body.fullscreen-app {
    padding-bottom: 0;
}

/* Legacy / theme overrides (kept for backward compatibility) */
.nav-icon .fa { font-size: 20px; line-height: 1; }
.nav-icon {
    /* (intentionally re-declared above; this block is a no-op for new markup) */
}

#app {
    padding: 16px;
    padding-bottom: 100px;
}

.top-menu {
    display: none !important;
}

.section {
    padding: 16px;
    max-width: 800px;
    margin: 0 auto;
}

.section-header {
    margin-bottom: 16px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--input-border);
}

.section-header h2 {
    margin: 0 0 8px 0;
    font-size: 18px;

    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.settings-group {
    background: var(--card-bg);
    border-radius: 12px;
    padding: 16px;
    margin-bottom: 16px;
    box-shadow: 0 2px 8px var(--card-shadow);
}

.settings-group h3 {
    margin: 0 0 12px 0;
    font-size: 14px;
    color: var(--text-color);
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.settings-select {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--input-border);
    border-radius: 8px;
    background: var(--input-bg);
    color: var(--text-color);
    font-size: 14px;
    cursor: pointer;
}

.settings-select:focus {
    outline: none;
    border-color: var(--button-bg);
}

.user-id-display {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

#myUserId {
    font-size: 16px;
    font-weight: bold;
    color: var(--button-bg);
}

.copy-btn {
    padding: 8px 16px;
    background: var(--button-bg);
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 12px;
    width: auto;
    margin: 0;
}

.copy-btn:hover {
    background: var(--button-hover);
}

.settings-group .button-row {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    margin: 0;
}

.settings-group .button-row .copy-btn {
    flex: 1 1 0;
    min-width: 140px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 10px 14px;
    font-size: 14px;
}

/* ============================================
   Настройки — современный карточный дизайн
   ============================================ */

#sectionSettings {
    --settings-accent: var(--button-bg);
    --settings-row-hover: rgba(0, 123, 255, 0.06);
    --settings-card-radius: 18px;
}

/* Hero-шапка */
.settings-hero {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 18px 18px;
    margin-bottom: 18px;
    border-radius: 18px;
    background: linear-gradient(135deg, var(--button-bg) 0%, color-mix(in srgb, var(--button-bg) 60%, #6f42c1 40%) 100%);
    color: #fff;
    box-shadow: 0 8px 24px color-mix(in srgb, var(--button-bg) 30%, transparent);
    position: relative;
    overflow: hidden;
}

.settings-hero::after {
    content: "";
    position: absolute;
    right: -30px;
    top: -30px;
    width: 140px;
    height: 140px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.08);
    pointer-events: none;
}

.settings-hero-icon {
    width: 48px;
    height: 48px;
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.2);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 22px;
    flex-shrink: 0;
    position: relative;
    z-index: 1;
}

.settings-hero-text {
    position: relative;
    z-index: 1;
    min-width: 0;
}

.settings-hero-text h2 {
    margin: 0 0 2px 0;
    font-size: 20px;
    font-weight: 700;
    color: #fff;
    letter-spacing: -0.2px;
}

.settings-hero-text p {
    margin: 0;
    font-size: 13px;
    color: rgba(255, 255, 255, 0.85);
    line-height: 1.35;
}

/* Карточка */
.settings-card {
    background: var(--card-bg);
    border-radius: var(--settings-card-radius);
    margin-bottom: 14px;
    box-shadow:
        0 1px 2px var(--card-shadow),
        0 4px 16px color-mix(in srgb, var(--card-shadow) 60%, transparent);
    overflow: hidden;
    border: 1px solid color-mix(in srgb, var(--input-border) 60%, transparent);
    transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.settings-card:hover {
    transform: translateY(-1px);
    box-shadow:
        0 2px 4px var(--card-shadow),
        0 8px 24px color-mix(in srgb, var(--card-shadow) 70%, transparent);
}

/* Шапка карточки */
.settings-card-header {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 16px 16px 12px 16px;
}

.settings-card-icon {
    width: 42px;
    height: 42px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 18px;
    flex-shrink: 0;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12);
}

.settings-icon-purple { background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%); }
.settings-icon-blue   { background: linear-gradient(135deg, #0ea5e9 0%, #2563eb 100%); }
.settings-icon-green  { background: linear-gradient(135deg, #10b981 0%, #059669 100%); }
.settings-icon-orange { background: linear-gradient(135deg, #f59e0b 0%, #ef4444 100%); }
.settings-icon-pink   { background: linear-gradient(135deg, #ec4899 0%, #db2777 100%); }
.settings-icon-red    { background: linear-gradient(135deg, #ef4444 0%, #b91c1c 100%); }

.settings-card-title {
    flex: 1;
    min-width: 0;
}

.settings-card-title h3 {
    margin: 0 0 2px 0;
    font-size: 15px;
    font-weight: 600;
    color: var(--text-color);
    letter-spacing: -0.1px;
}

.settings-card-sub {
    margin: 0;
    font-size: 12.5px;
    color: color-mix(in srgb, var(--text-color) 60%, transparent);
    line-height: 1.4;
}

/* Список строк */
.settings-list {
    border-top: 1px solid color-mix(in srgb, var(--input-border) 50%, transparent);
}

.settings-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    transition: background 0.15s ease;
    border-bottom: 1px solid color-mix(in srgb, var(--input-border) 35%, transparent);
}

.settings-row:hover {
    background: var(--settings-row-hover);
}

.settings-row-last {
    border-bottom: none;
}

.settings-row-label {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    color: var(--text-color);
    font-weight: 500;
    min-width: 0;
}

.settings-row-label i {
    width: 18px;
    text-align: center;
    color: color-mix(in srgb, var(--text-color) 50%, transparent);
    font-size: 14px;
}

.settings-row-control {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 8px;
}

.settings-row-control-stack {
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
}

.settings-row-hint {
    font-size: 11px;
    color: color-mix(in srgb, var(--text-color) 50%, transparent);
}

/* Инлайн-select */
.settings-select-inline {
    min-width: 140px;
    max-width: 200px;
    padding: 8px 32px 8px 12px;
    border: 1px solid color-mix(in srgb, var(--input-border) 70%, transparent);
    border-radius: 10px;
    background: var(--input-bg);
    color: var(--text-color);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    background-image:
        linear-gradient(45deg, transparent 50%, color-mix(in srgb, var(--text-color) 60%, transparent) 50%),
        linear-gradient(135deg, color-mix(in srgb, var(--text-color) 60%, transparent) 50%, transparent 50%);
    background-position:
        calc(100% - 16px) center,
        calc(100% - 11px) center;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.settings-select-inline:hover {
    border-color: var(--button-bg);
}

.settings-select-inline:focus {
    outline: none;
    border-color: var(--button-bg);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--button-bg) 20%, transparent);
}

/* ============================================
   Кастомный современный select
   ============================================ */
.native-select-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
    opacity: 0 !important;
    pointer-events: none !important;
}

.custom-select {
    position: relative;
    width: 100%;
    min-width: 160px;
    max-width: 260px;
    font-size: 13px;
    color: var(--text-color);
}

.custom-select-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    padding: 9px 14px;
    border: 1px solid color-mix(in srgb, var(--input-border) 70%, transparent);
    border-radius: 12px;
    background: none;
    color: var(--text-color);
    font-size: 13px;
    font-weight: 500;
    line-height: 1.3;
    cursor: pointer;
    text-align: left;
    transition:
        border-color 0.18s ease,
        box-shadow 0.18s ease,
        background 0.18s ease,
        transform 0.12s ease;
    box-shadow: none;
}

.custom-select-trigger:hover {
    border-color: color-mix(in srgb, var(--button-bg) 55%, transparent);
    background: none;
    box-shadow: none;
}

.custom-select-trigger:focus {
    outline: none;
    border-color: var(--button-bg);
    background: none;
    box-shadow: none;
}

.custom-select-trigger:active {
    transform: scale(0.99);
}

.custom-select.is-open .custom-select-trigger {
    border-color: var(--button-bg);
    background: none;
    box-shadow: none;
}

.custom-select-value {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.custom-select-flag {
    font-size: 16px;
    line-height: 1;
    flex-shrink: 0;
}

.custom-select-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 7px;
    background: color-mix(in srgb, var(--button-bg) 12%, transparent);
    color: var(--button-bg);
    font-size: 11px;
    flex-shrink: 0;
    transition: background 0.18s ease, color 0.18s ease;
}

.custom-select.is-open .custom-select-icon {
    background: color-mix(in srgb, var(--button-bg) 20%, transparent);
}

.custom-select-option-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 8px;
    background: color-mix(in srgb, var(--button-bg) 10%, transparent);
    color: var(--button-bg);
    font-size: 12px;
    flex-shrink: 0;
}

.custom-select-option.is-selected .custom-select-option-icon {
    background: color-mix(in srgb, var(--button-bg) 22%, transparent);
}

.custom-select-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.custom-select-chevron {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 8px;
    color: color-mix(in srgb, var(--text-color) 65%, transparent);
    background: color-mix(in srgb, var(--button-bg) 8%, transparent);
    transition: transform 0.22s cubic-bezier(0.4, 0, 0.2, 1), background 0.18s ease;
    flex-shrink: 0;
}

.custom-select-chevron i {
    font-size: 10px;
    transition: transform 0.22s ease;
}

.custom-select.is-open .custom-select-chevron {
    background: color-mix(in srgb, var(--button-bg) 18%, transparent);
    color: var(--button-bg);
}

.custom-select.is-open .custom-select-chevron i {
    transform: rotate(180deg);
}

/* ============================================
   Модалка кастомного select
   ============================================ */
.custom-select-modal .custom-select-modal-content {
    max-width: 460px;
    width: 100%;
    max-height: min(80vh, 640px);
    display: flex;
    flex-direction: column;
    padding: 20px 18px 14px;
    /* ВАЖНО: у .modal-content по умолчанию overflow-y:auto, но нам нужна
       отдельная прокручиваемая область между header и footer, поэтому
       отключаем общий скролл контейнера */
    overflow: hidden;
}

.custom-select-modal-title {
    margin: 0 0 14px 0;
    padding-right: 36px; /* место под крестик */
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-color, #0f172a);
    letter-spacing: -0.01em;
    flex-shrink: 0;
}

.custom-select-modal-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 9px;
    background: color-mix(in srgb, var(--button-bg) 14%, transparent);
    color: var(--button-bg);
    font-size: 13px;
    flex-shrink: 0;
}

.custom-select-modal-icon:empty {
    display: none;
}

.custom-select-modal-search {
    position: relative;
    margin-bottom: 10px;
    flex-shrink: 0;
}

.custom-select-modal-search i {
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 12px;
    color: color-mix(in srgb, var(--text-color) 50%, transparent);
    pointer-events: none;
}

.custom-select-modal-search-input {
    width: 100%;
    padding: 10px 12px 10px 34px;
    border: 1px solid color-mix(in srgb, var(--input-border) 70%, transparent);
    border-radius: 12px;
    background: var(--input-bg, #fff);
    color: var(--text-color);
    font-size: 14px;
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}

.custom-select-modal-search-input::placeholder {
    color: color-mix(in srgb, var(--text-color) 45%, transparent);
}

.custom-select-modal-search-input:focus {
    border-color: var(--button-bg);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--button-bg) 18%, transparent);
}

.custom-select-modal-options {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 4px;
    margin: 0 -4px;
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--text-color) 25%, transparent) transparent;
    -webkit-overflow-scrolling: touch;
}

.custom-select-modal-options::-webkit-scrollbar {
    width: 6px;
}

.custom-select-modal-options::-webkit-scrollbar-track {
    background: transparent;
}

.custom-select-modal-options::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--text-color) 22%, transparent);
    border-radius: 3px;
}

.custom-select-modal-footer {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid color-mix(in srgb, var(--input-border) 50%, transparent);
    display: flex;
    justify-content: flex-end;
    flex-shrink: 0;
}

.custom-select-modal-footer .modal-btn {
    min-width: 96px;
    padding: 8px 18px;
    border-radius: 10px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    border: 1px solid transparent;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.1s ease;
}

.custom-select-modal-footer .modal-btn-cancel {
    background: color-mix(in srgb, var(--button-bg) 10%, transparent);
    color: var(--button-bg);
    border-color: color-mix(in srgb, var(--button-bg) 18%, transparent);
}

.custom-select-modal-footer .modal-btn-cancel:hover {
    background: color-mix(in srgb, var(--button-bg) 18%, transparent);
}

.custom-select-modal-footer .modal-btn:active {
    transform: scale(0.98);
}

.custom-select-modal-close {
    top: 14px;
    right: 14px;
}

.custom-select-group-title {
    padding: 10px 10px 4px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: color-mix(in srgb, var(--text-color) 50%, transparent);
    position: sticky;
    top: 0;
    background: var(--us-bg, #fff);
    z-index: 1;
    margin: 0 -4px;
    padding-left: 14px;
    padding-right: 14px;
}

body.dark-theme .custom-select-group-title {
    background: var(--us-bg, #1f1f23);
}

.custom-select-option {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 12px;
    border-radius: 10px;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-color);
    cursor: pointer;
    user-select: none;
    transition: background 0.12s ease, color 0.12s ease, transform 0.1s ease;
    min-height: 42px;
}

.custom-select-option:hover,
.custom-select-option.is-highlighted {
    background: color-mix(in srgb, var(--button-bg) 10%, transparent);
}

.custom-select-option.is-selected {
    background: color-mix(in srgb, var(--button-bg) 14%, transparent);
    color: var(--button-bg);
    font-weight: 600;
}

.custom-select-option.is-highlighted.is-selected {
    background: color-mix(in srgb, var(--button-bg) 20%, transparent);
}

.custom-select-option .custom-select-flag {
    font-size: 18px;
    line-height: 1;
    flex-shrink: 0;
}

.custom-select-option .custom-select-option-label {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.custom-select-option .custom-select-option-check {
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--button-bg);
    opacity: 0;
    flex-shrink: 0;
    transition: opacity 0.12s ease;
    font-size: 12px;
}

.custom-select-option.is-selected .custom-select-option-check {
    opacity: 1;
}

.custom-select-empty {
    padding: 28px 12px;
    text-align: center;
    color: color-mix(in srgb, var(--text-color) 50%, transparent);
    font-size: 14px;
}

/* Тёмная тема */
.dark-theme .custom-select-trigger {
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--input-bg) 100%, transparent) 0%,
        color-mix(in srgb, var(--input-bg) 90%, transparent) 100%);
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.2),
        inset 0 1px 0 rgba(255, 255, 255, 0.04);
}

.dark-theme .custom-select-modal-options::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--text-color) 35%, transparent);
}

/* Адаптив: на узких экранах */
@media (max-width: 480px) {
    .custom-select {
        min-width: 0;
        max-width: 100%;
    }
    .custom-select-modal .custom-select-modal-content {
        max-width: 100%;
        max-height: 90vh;
    }
    .custom-select-modal-options {
        /* На мобильных оставляем чуть больше места для тач-скролла */
        padding-bottom: 8px;
    }
}

/* ID + кнопка копирования */
.user-id-display {
    display: flex;
    align-items: center;
    gap: 8px;
}

.user-id-pill {
    display: inline-flex;
    align-items: center;
    padding: 6px 12px;
    background: color-mix(in srgb, var(--button-bg) 12%, transparent);
    color: var(--button-bg);
    border-radius: 999px;
    font-size: 13px;
    font-weight: 600;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    max-width: 180px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.settings-icon-btn {
    width: 34px;
    height: 34px;
    border-radius: 10px;
    border: 1px solid color-mix(in srgb, var(--input-border) 60%, transparent);
    background: var(--input-bg);
    color: var(--text-color);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    transition: all 0.15s ease;
}

.settings-icon-btn:hover {
    background: color-mix(in srgb, var(--button-bg) 12%, transparent);
    border-color: var(--button-bg);
    color: var(--button-bg);
    transform: scale(1.05);
}

.settings-icon-btn:active {
    transform: scale(0.95);
}

/* Кнопки-«плитки» в карточках */
.settings-card-actions {
    padding: 0 12px 12px 12px;
}

.settings-card-actions-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2px;
}

.settings-tile-btn {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    margin: 4px 0;
    padding: 12px 14px;
    border: 1px solid color-mix(in srgb, var(--input-border) 50%, transparent);
    background: color-mix(in srgb, var(--input-bg) 70%, transparent);
    color: var(--text-color);
    border-radius: 12px;
    cursor: pointer;
    font-size: 13.5px;
    font-weight: 500;
    text-align: left;
    transition: all 0.15s ease;
    position: relative;
}

.settings-tile-btn:hover {
    background: color-mix(in srgb, var(--button-bg) 8%, var(--input-bg));
    border-color: color-mix(in srgb, var(--button-bg) 50%, transparent);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--button-bg) 15%, transparent);
}

.settings-tile-btn:active {
    transform: translateY(0);
}

.settings-tile-icon {
    width: 32px;
    height: 32px;
    border-radius: 8px;
    background: color-mix(in srgb, var(--button-bg) 12%, transparent);
    color: var(--button-bg);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    flex-shrink: 0;
}

.settings-tile-text {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.settings-tile-chevron {
    color: color-mix(in srgb, var(--text-color) 40%, transparent);
    font-size: 12px;
    transition: transform 0.15s ease, color 0.15s ease;
}

.settings-tile-btn:hover .settings-tile-chevron {
    transform: translateX(2px);
    color: var(--button-bg);
}

/* Карточка-панель (для каналов) */
.settings-card-panel {
    border: 1px solid color-mix(in srgb, var(--button-bg) 30%, transparent);
}

/* Адаптив: на узких экранах — одна колонка */
@media (max-width: 480px) {
    .settings-card-actions-grid {
        grid-template-columns: 1fr;
    }
    .settings-select-inline {
        min-width: 120px;
        max-width: 160px;
    }
    .settings-hero-text h2 {
        font-size: 18px;
    }
}

/* Тёмная тема */
.dark-theme .settings-card {
    border-color: color-mix(in srgb, var(--input-border) 40%, transparent);
}

.dark-theme .settings-row-label i {
    color: color-mix(in srgb, var(--text-color) 55%, transparent);
}

.dark-theme .user-id-pill {
    background: color-mix(in srgb, var(--button-bg) 22%, transparent);
}

.dark-theme .settings-tile-btn {
    background: color-mix(in srgb, var(--input-bg) 60%, transparent);
}

.dark-theme .settings-tile-btn.settings-tile-btn--blue,
.dark-theme .settings-tile-btn.settings-tile-btn--blue:hover:not(:disabled) {
    background:
        linear-gradient(180deg,
            var(--tile-blue-from) 0%,
            var(--tile-blue-to) 100%);
}

.dark-theme .settings-select-inline {
    background-color: var(--input-bg);
}

.invite-status {
    text-align: center;
    padding: 16px 0;
    color: var(--text-color-secondary, #666);
    font-size: 14px;
}

.invite-error {
    margin-top: 12px;
    padding: 10px 12px;
    border-radius: 6px;
    background-color: rgba(220, 53, 69, 0.1);
    color: #dc3545;
    font-size: 13px;
    line-height: 1.4;
}

.dark-theme .invite-error {
    background-color: rgba(220, 53, 69, 0.18);
    color: #ff6b7a;
}

.invite-result {
    margin-top: 12px;
}

.invite-link-box {
    display: flex;
    gap: 8px;
    align-items: stretch;
}

.invite-link-box input {
    flex: 1 1 auto;
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid var(--input-border);
    border-radius: 6px;
    background-color: var(--input-bg);
    color: var(--text-color);
    font-size: 13px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    word-break: break-all;
    text-overflow: ellipsis;
}

.invite-link-box input:focus {
    outline: none;
    border-color: var(--button-bg);
}

.invite-link-box .copy-btn {
    flex: 0 0 auto;
    white-space: nowrap;
    padding: 8px 14px;
}

.invite-meta {
    margin-top: 10px;
    font-size: 12px;
    color: var(--text-color-secondary, #666);
}

.invite-help {
    margin: 12px 0 0 0;
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-color);
    opacity: 0.85;
}

.invite-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-top: 8px;
    max-height: 50vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

.invite-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 12px;
    border: 1px solid var(--input-border);
    border-radius: 8px;
    background-color: var(--card-bg);
}

.invite-card-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1 1 auto;
}

.invite-card-status {
    font-size: 13px;
    font-weight: 600;
    color: var(--button-bg);
}

.invite-card-id {
    font-size: 12px;
    color: var(--text-color-secondary, #666);
}

.invite-card-expires {
    font-size: 12px;
    color: var(--text-color-secondary, #666);
}

.invite-card-actions {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 6px;
}

.invite-revoke-btn {
    width: 30px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background-color: #dc3545;
    color: #fff;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 13px;
    transition: background-color 0.2s, transform 0.15s;
    flex: 0 0 auto;
}

.invite-revoke-btn:hover {
    background-color: #c82333;
}

.invite-revoke-btn:active {
    transform: scale(0.92);
}

.invite-revoke-btn:focus-visible {
    outline: 2px solid #dc3545;
    outline-offset: 2px;
}

.invite-revoke-btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.invite-open-btn {
    width: 30px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background-color: #6c757d;
    color: #fff;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 13px;
    transition: background-color 0.2s, transform 0.15s;
    flex: 0 0 auto;
    text-decoration: none;
}

.invite-open-btn:hover {
    background-color: #5a6268;
    color: #fff;
    text-decoration: none;
}

.invite-open-btn:active {
    transform: scale(0.92);
}

.invite-open-btn:focus-visible {
    outline: 2px solid #6c757d;
    outline-offset: 2px;
}

.invite-copy-btn {
    width: 30px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background-color: var(--button-bg, #007bff);
    color: #fff;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 13px;
    transition: background-color 0.2s, transform 0.15s;
    flex: 0 0 auto;
}

.invite-copy-btn:hover {
    background-color: var(--button-hover, #0056b3);
}

.invite-copy-btn:active {
    transform: scale(0.92);
}

.invite-copy-btn:focus-visible {
    outline: 2px solid var(--button-bg, #007bff);
    outline-offset: 2px;
}

.invite-copy-btn--success {
    background-color: #28a745;
}

.invite-copy-btn--success:hover {
    background-color: #218838;
}

.invite-empty {
    margin-top: 8px;
    padding: 16px 12px;
    text-align: center;
    color: var(--text-color-secondary, #666);
    font-size: 14px;
    background-color: var(--input-bg);
    border-radius: 8px;
}

/* ============================================================
 * Bot Invite card (постоянная реферальная ссылка в Настройках)
 * ============================================================ */
.bot-invite-link-row {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-top: 8px;
}
.bot-invite-link-row input {
    flex: 1 1 auto;
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid var(--border-color, #d0d7de);
    border-radius: 8px;
    background: var(--input-bg, #fff);
    color: var(--text-color-primary, #111);
    font-family: ui-monospace, "SF Mono", "Cascadia Mono", "Roboto Mono", Menlo, Consolas, monospace;
    font-size: 9px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.bot-invite-link-row input:focus {
    outline: none;
    border-color: var(--widget-accent, #7c3aed);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--widget-accent, #7c3aed) 18%, transparent);
}
.bot-invite-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
}
.bot-invite-stat-line {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 12px;
    margin-top: 10px;
    border-radius: 10px;
    background: var(--widget-accent-soft, rgba(124, 58, 237, 0.10));
    border: 1px solid color-mix(in srgb, var(--widget-accent, #7c3aed) 25%, transparent);
    font-size: 14px;
    color: var(--text-color-primary, #111);
}
.bot-invite-stat-value {
    font-weight: 600;
    color: var(--widget-accent, #7c3aed);
}
.bot-invite-recent {
    margin-top: 10px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.bot-invite-recent-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 8px;
    background: var(--input-bg, #f5f6f8);
    font-size: 13px;
}
.bot-invite-recent-row .bot-invite-recent-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-color-primary, #111);
}
.bot-invite-recent-row .bot-invite-recent-time {
    flex: 0 0 auto;
    color: var(--text-color-secondary, #666);
    font-size: 12px;
}
.bot-invite-help {
    margin-top: 10px;
    font-size: 12px;
    color: var(--text-color-secondary, #666);
    line-height: 1.45;
}
.bot-invite-error {
    margin-top: 8px;
    padding: 10px 12px;
    border-radius: 8px;
    background-color: rgba(239, 68, 68, 0.12);
    border: 1px solid rgba(239, 68, 68, 0.3);
    color: #b91c1c;
    font-size: 13px;
}
.bot-invite-meta {
    margin-top: 8px;
    font-size: 12px;
    color: var(--text-color-secondary, #666);
}
.bot-invite-loading {
    padding: 10px 12px;
    color: var(--text-color-secondary, #666);
    font-size: 13px;
}
/* [v1.16] Бонусная плитка в виджете «Пригласить в бот» */
.bot-invite-bonus-card {
    margin-top: 4px;
    margin-bottom: 12px;
    padding: 12px 14px;
    border-radius: 12px;
    background: linear-gradient(135deg,
        rgba(251, 191, 36, 0.18) 0%,
        rgba(245, 158, 11, 0.12) 100%);
    border: 1px solid rgba(245, 158, 11, 0.35);
}
.bot-invite-bonus-card .bot-invite-bonus-label {
    font-size: 14px;
    font-weight: 600;
    color: #92400e;
    line-height: 1.4;
}
.bot-invite-bonus-card .bot-invite-bonus-desc {
    margin-top: 4px;
    font-size: 12px;
    color: #78350f;
    line-height: 1.45;
    opacity: 0.92;
}

.balance-info {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.balance-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 12px;
    border-bottom: 1px solid var(--input-border);
}

.balance-row:last-child {
    border-bottom: none;
}

.balance-row span:first-child {
    color: var(--text-color);

    padding-left: 4px;

    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.balance-row span:last-child {
    font-weight: bold;
    color: var(--button-bg);
}

.balance-row-hint {
    font-size: 0.78em;
    line-height: 1.35;
    color: var(--text-color);
    opacity: 0.65;
    padding: 0 12px 4px;
    white-space: pre-line;
}

/* [v1.15] Подстрока разбивки баланса: «От бота» / «Куплено».
   Визуально чуть мельче и светлее основного баланса, без нижней
   границы — это «детализация», а не отдельная секция. */
.balance-row-sub {
    padding-top: 4px;
    padding-bottom: 4px;
    font-size: 0.92em;
    border-bottom: none;
    opacity: 0.85;
}

.balance-row-sub span:first-child {
    color: var(--text-color-secondary, #777);
    font-weight: normal;
}

.balance-row-sub span:last-child {
    font-weight: normal;
}

/* [v1.15] При достижении EARNED_BALANCE_CAP цифра earned-остатка
   и значение cap подсвечиваются красным — это индикатор «лимит
   исчерпан, квесты приостановлены». */
.earned-balance-capped {
    color: #e53935 !important;
    font-weight: bold;
}

.balance-row-hint-earned {
    /* По умолчанию — спокойная серая подсказка (наследует
       .balance-row-hint), при заморозке квестов подкрашиваем
       красноватым через .balance-row-hint-frozen. */
}

.balance-row-hint-frozen {
    color: #c62828;
    opacity: 1;
    background: rgba(229, 57, 53, 0.08);
    border-left: 3px solid #e53935;
    padding: 8px 12px;
    border-radius: 4px;
    margin-top: 4px;
}

.recent-topups-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.recent-topups-empty {
    color: var(--text-secondary, #888);
    font-style: italic;
    padding: 8px 0;
    text-align: center;
}

/* Эффект кликабельности виджета «Последние пополнения» —
   открывает модальное окно с расширенной историей (30 записей). */
.recent-topups-clickable {
    cursor: pointer;
    outline: none;
}

.recent-topups-clickable:hover {
    background: var(--card-bg-hover, rgba(255, 255, 255, 0.04));
    border-radius: 8px;
    transition: background 0.15s ease;
}

.recent-topups-clickable:focus-visible {
    box-shadow: 0 0 0 2px var(--accent-color, #2ea043);
    border-radius: 8px;
}

.recent-topups-expand-hint {
    color: var(--text-secondary, #888);
    font-size: 12px;
    text-align: center;
    padding-top: 4px;
    opacity: 0.8;
}

.recent-topups-expand-hint i {
    margin-right: 4px;
}

/* Список пополнений в модальном окне — отдельный класс, чтобы
   можно было при необходимости подстроить отступы/прокрутку
   независимо от inline-виджета. Зеркало .recent-debits-modal-list. */
.recent-topups-modal-list {
    max-height: 60vh;
    overflow-y: auto;
    padding-right: 4px;
}

.recent-topup-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 12px;
    border: 1px solid var(--input-border, #e0e0e0);
    border-radius: 8px;
    background: var(--card-bg, #fafafa);
    gap: 12px;
}

.recent-topup-date {
    color: var(--text-color, #333);
    font-size: 14px;
    white-space: nowrap;
}

.recent-topup-source {
    color: var(--text-secondary, #888);
    font-size: 12px;
    flex: 1;
    text-align: center;
    /* Названия достижений (например «Полиглот», «Weekend Warrior»)
       могут быть достаточно длинными, чтобы не поместиться в одну
       строку между датой и суммой. Разрешаем перенос на несколько
       строк с компактным межстрочным интервалом, чтобы строка
       пополнения не разрасталась по высоте. */
    white-space: normal;
    overflow-wrap: anywhere;
    word-break: break-word;
    line-height: 1.2;
    /* Слегка ограничиваем максимальную ширину, чтобы текст не
       «расползался» на всю ширину, когда строк немного. */
    min-width: 0;
}

.recent-topup-amount {
    font-weight: bold;
    color: var(--accent-color, #2ea043);
    font-size: 16px;
    white-space: nowrap;
}

/* ----------------------------------------------------------
 * Виджет «Последние списания» в разделе «Баланс» miniapp.
 * Зеркало .recent-topups-*, но визуально подчёркивает списание:
 * - красноватый оттенок amount (var(--danger-color))
 * - эффект кликабельности (cursor: pointer, hover)
 * - подсказка «развернуть» снизу виджета
 * ---------------------------------------------------------- */
.recent-debits-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.recent-debits-clickable {
    cursor: pointer;
    outline: none;
    /* Чтобы курсор и hover работали на самом контейнере,
       но не на пустом placeholder — отдельный класс на нём не нужен. */
}

.recent-debits-clickable:hover {
    /* Лёгкая подсветка контейнера при наведении — намёк на кликабельность */
    background: var(--card-bg-hover, rgba(255, 255, 255, 0.04));
    border-radius: 8px;
    transition: background 0.15s ease;
}

.recent-debits-clickable:focus-visible {
    box-shadow: 0 0 0 2px var(--accent-color, #2ea043);
    border-radius: 8px;
}

.recent-debits-empty {
    color: var(--text-secondary, #888);
    font-style: italic;
    padding: 8px 0;
    text-align: center;
}

.recent-debit-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 12px;
    border: 1px solid var(--input-border, #e0e0e0);
    border-radius: 8px;
    background: var(--card-bg, #fafafa);
    gap: 12px;
}

.recent-debit-date {
    color: var(--text-color, #333);
    font-size: 14px;
    white-space: nowrap;
}

.recent-debit-source {
    color: var(--text-secondary, #888);
    font-size: 12px;
    flex: 1;
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.recent-debit-amount {
    font-weight: bold;
    color: var(--danger-color, #d9534f);
    font-size: 16px;
    white-space: nowrap;
}

.recent-debits-expand-hint {
    color: var(--text-secondary, #888);
    font-size: 12px;
    text-align: center;
    padding-top: 4px;
    opacity: 0.8;
}

.recent-debits-expand-hint i {
    margin-right: 4px;
}

/* Список в модальном окне — отдельный класс, чтобы можно было
   при необходимости подстроить отступы/прокрутку независимо от
   inline-виджета. */
.recent-debits-modal-list {
    max-height: 60vh;
    overflow-y: auto;
    padding-right: 4px;
}

#watchingList {
    text-align: center;
    color: #666;
    padding: 24px;
}

.watching-item {
    background: var(--card-bg);
    border-radius: 8px;
    padding: 12px 16px;
    margin-bottom: 8px;
    box-shadow: 0 1px 4px var(--card-shadow);
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
}

.watching-user-info {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1 1 auto;
    min-width: 0;
}

.watching-user-id {
    font-weight: bold;
    color: var(--text-color);
}

.watching-user-alias {
    font-size: 12px;
    color: #666;
}

/* Аватарка в карточке наблюдаемого пользователя (стиль как us-avatar на карте). */
.watching-avatar {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    overflow: hidden;
    background: var(--card-bg);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

.watching-avatar img {
    display: block;
    border-radius: 50%;
    object-fit: cover;
}

.watching-avatar.watching-avatar-fallback {
    color: #fff;
    font-weight: 600;
    user-select: none;
}

.watching-avatar-letter {
    font-size: 16px;
    line-height: 1;
}

.section-actions {
    display: flex;
    gap: 8px;
    margin-top: 8px;
    margin-bottom: 16px;
    flex-wrap: wrap;
}

.action-btn-sm {
    padding: 8px 12px;
    background-color: var(--button-bg);
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 12px;
    font-weight: 500;
    margin: 0;
    width: auto;
}

.action-btn-sm:hover {
    background-color: var(--button-hover);
}

.action-btn-sm.active {
    background-color: #28a745;
}

.action-btn-sm.active:hover {
    background-color: #218838;
}

.izone-item {
    background: var(--card-bg, #fff);
    border: 1px solid var(--input-border, #e0e0e0);
    border-radius: 8px;
    padding: 12px;
    margin-bottom: 10px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    word-wrap: break-word;
    overflow-wrap: anywhere;
}
.izone-item-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 8px;
}
.izone-item-title {
    font-weight: 600;
    font-size: 15px;
    color: var(--text-color, #222);
    word-break: break-word;
}
.izone-item-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    font-size: 12px;
    color: var(--hint-color, #6c757d);
}
.izone-item-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 6px;
}
.izone-item-actions .action-btn-sm {
    flex: 0 0 auto;
}

.izone-option-badge {
    align-items: center;
    gap: 6px;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 12px;
    font-weight: 500;
    line-height: 1.3;
}
.izone-option-active {
    color: #2e7d32;
    background: rgba(46, 125, 50, 0.08);
}
.izone-option-paused {
    color: #c62828;
    background: rgba(198, 40, 40, 0.08);
}
.izone-show-paused-hint {
    font-size: 11px;
    color: #c62828;
    margin-top: 2px;
    opacity: 0.9;
}

#izoneSubscriptionsModal .modal-content {
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 40px);
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
}
#izoneSubscriptionsList {
    flex: 1 1 auto;
    min-height: 0;
}

#guideSubscriptionsModal .modal-content {
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 40px);
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
}
#guideSubscriptionsList {
    flex: 1 1 auto;
    min-height: 0;
}
.guide-subs-progress {
    display: inline-block;
    margin-top: 2px;
    font-size: 12px;
    opacity: 0.75;
}

.panel-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--input-border);
}

.panel-header h3 {
    margin: 0;
    font-size: 16px;
    color: var(--text-color);
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.close-panel-btn {
    background: none;
    border: none;
    font-size: 24px;
    color: #888;
    cursor: pointer;
    padding: 0;
    margin: 0;
    width: auto;
    line-height: 1;
}

.close-panel-btn:hover {
    color: #333;
    background: none;
}

.dark-theme .close-panel-btn {
    color: #aaa;
}

.dark-theme .close-panel-btn:hover {
    color: #fff;
    background: none;
}

.user-list-for-edit {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 16px;
}

.user-list-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 12px 16px;
    background-color: var(--input-bg);
    border: 1px solid var(--input-border);
    border-radius: 8px;
    cursor: pointer;
    transition: border-color 0.2s, background-color 0.2s;
}

.user-list-item:hover {
    border-color: var(--button-bg);
    background-color: rgba(74, 144, 226, 0.05);
}

.user-list-item.selected {
    border-color: var(--button-bg);
    background-color: rgba(74, 144, 226, 0.1);
}

.user-list-item .user-name {
    font-weight: 500;
    color: var(--text-color);
    flex: 1 1 auto;
    min-width: 0;
    font-size: 12px;
}

/* Аватарка слева в строке .user-list-item (панели "Имена" / "Лимит" / "Уведомления"). */
.user-list-item .user-list-avatar {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    overflow: hidden;
    background: var(--card-bg);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

.user-list-item .user-list-avatar img {
    display: block;
    border-radius: 50%;
    object-fit: cover;
}

.user-list-item .user-list-avatar.user-list-avatar-fallback {
    color: #fff;
    font-weight: 600;
    user-select: none;
}

.user-list-item .user-list-avatar-letter {
    font-size: 13px;
    line-height: 1;
}

.user-list-item .user-limit {
    font-size: 12px;
    color: #666;
}

.user-list-item .user-limit-info {
    font-size: 12px;
    color: #666;
}

/* FEATURE feature/public-route-frozen-points:
   Бейдж «❄ N заморожено» под основной строкой лимита.
   Компактнее, чем в виджете хранилища, потому что места
   в лимит-редакторе меньше. */
.user-list-item .user-frozen-info {
    display: block;
    width: 100%;
    flex-basis: 100%;
    font-size: 11px;
    color: #0288d1;
    background-color: rgba(2, 136, 209, 0.08);
    border-radius: 4px;
    padding: 6px 8px;
    margin-top: 6px;
    cursor: help;
    box-sizing: border-box;
}

.dark-theme .user-frozen-info {
    color: #4fc3f7;
    background-color: rgba(79, 195, 247, 0.10);
}

.limit-description.limit-frozen-description {
    margin-top: 6px;
    color: #0288d1;
    background-color: rgba(2, 136, 209, 0.06);
    border-color: rgba(2, 136, 209, 0.25);
}

.limit-description.limit-frozen-description .limit-frozen-icon {
    margin-right: 4px;
}

.dark-theme .limit-description.limit-frozen-description {
    color: #4fc3f7;
    background-color: rgba(79, 195, 247, 0.08);
    border-color: rgba(79, 195, 247, 0.30);
}

.limit-description {
    font-size: 12px;
    color: #888;
    margin-top: 12px;
    padding: 10px;
    background-color: var(--input-bg);
    border-radius: 6px;
    border: 1px solid var(--input-border);
}

.dark-theme .limit-description {
    background-color: var(--card-bg);
    color: #aaa;
}

.user-list-item.user-notif-enabled {
    border-left: 3px solid #28a745;
}

.no-users-msg {
    text-align: center;
    color: #888;
    padding: 20px;
    font-size: 14px;
}

.edit-user-name {
    font-weight: bold;
    color: var(--button-bg);
    margin-bottom: 12px;
    font-size: 16px;
}

.settings-input {
    width: 100%;
    padding: 12px 16px;
    border: 1px solid var(--input-border);
    border-radius: 8px;
    background-color: var(--input-bg);
    color: var(--text-color);
    font-size: 14px;
    margin-bottom: 12px;
}

.settings-input:focus {
    outline: none;
    border-color: var(--button-bg);
    box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
}

.button-row {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.action-btn {
    padding: 10px 16px;
    background-color: var(--button-bg);
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    margin: 0;
    width: auto;
}

.action-btn:hover {
    background-color: var(--button-hover);
}

.action-btn-secondary {
    background-color: #6c757d;
}

.action-btn-secondary:hover {
    background-color: #5a6268;
}

.action-btn-cancel {
    background-color: #dc3545;
}

.action-btn-cancel:hover {
    background-color: #c82333;
}

.limit-options {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.limit-option {
    padding: 12px 16px;
    background-color: var(--input-bg);
    border: 1px solid var(--input-border);
    border-radius: 8px;
    cursor: pointer;
    transition: border-color 0.2s, background-color 0.2s;
}

.limit-option:hover {
    border-color: var(--button-bg);
}

.limit-option.selected {
    border-color: var(--button-bg);
    background-color: rgba(74, 144, 226, 0.1);
}

.notification-settings-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--input-border);
}

.notification-settings-header h4 {
    margin: 0;
    font-size: 16px;
    color: var(--text-color);
}

.toggle-btn {
    padding: 10px 16px;
    background-color: #6c757d;
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    margin: 0;
    width: auto;
}

.toggle-btn:hover {
    background-color: #5a6268;
}

.toggle-btn-active {
    background-color: #28a745;
}

.toggle-btn-active:hover {
    background-color: #218838;
}

.toggle-btn-sm {
    padding: 6px 12px;
    background-color: #6c757d;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 12px;
    font-weight: 500;
    margin: 0;
    width: auto;
}

.toggle-btn-sm:hover {
    background-color: #5a6268;
}

.toggle-btn-sm.toggle-btn-active {
    background-color: #28a745;
}

.toggle-btn-sm.toggle-btn-active:hover {
    background-color: #218838;
}

.zone-list {
    margin-bottom: 8px;
}

.zone-list .zone-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 6px 0;
    font-size: 12px;
    gap: 8px;
}

.zone-list .zone-item-name {
    font-weight: 600;
    color: #007bff;
    margin-right: 4px;
}

.zone-list .zone-item-radius {
    flex-shrink: 0;
}

.zone-list .zone-item-status {
    font-size: 10px;
    color: #666;
    flex-shrink: 0;
}

.setting-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 0;
    border-bottom: 1px solid var(--input-border);
}

.setting-row:last-child {
    border-bottom: none;
}

.setting-row span {
    color: var(--text-color);
    font-size: 14px;
}

.setting-row .settings-select {
    width: auto;
    min-width: 120px;
    margin: 0;
    padding: 8px 12px;
}

.setting-row .custom-select {
    min-width: 140px;
    max-width: 200px;
    width: auto;
    flex-shrink: 0;
}

.setting-row .custom-select.custom-select-sm {
    min-width: 130px;
    max-width: 180px;
}

.custom-select.custom-select-sm .custom-select-trigger {
    padding: 7px 12px;
    font-size: 13px;
    border-radius: 10px;
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.04),
        inset 0 1px 0 rgba(255, 255, 255, 0.4);
}

.custom-select.custom-select-sm .custom-select-icon {
    width: 20px;
    height: 20px;
    font-size: 10px;
    border-radius: 6px;
}

.custom-select.custom-select-sm .custom-select-chevron {
    width: 20px;
    height: 20px;
    border-radius: 7px;
}

.custom-select.custom-select-sm .custom-select-chevron i {
    font-size: 9px;
}

.setting-row .toggle-btn-sm {
    margin-right: 16px;
    flex-shrink: 0;
}

.setting-row .toggle-btn-sm span {
    color: #fff;
}

.zone-monitoring-section {
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--input-border);
}

.zone-monitoring-header {
    margin-bottom: 12px;
}

.zone-monitoring-header h4 {
    margin: 0;
    font-size: 16px;
    color: var(--text-color);
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.section-description {
    display: block;
    font-size: 12px;
    color: var(--text-secondary);
    margin-top: 4px;
    font-weight: normal;
}

.zone-monitoring-toggle {
    margin-bottom: 12px;
}

.zone-monitoring-options {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.zone-monitoring-options.hidden {
    display: none;
}

.zone-coords-display {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    background-color: var(--input-bg);
    border: 1px solid var(--input-border);
    border-radius: 8px;
}

.zone-coords-display + .zone-coords-display {
    margin-top: 12px;
}

.zone-coords-header {
    font-size: 16px;
    font-weight: 600;
    color: var(--text-color);
    margin-bottom: 4px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--input-border);
}

.zone-coords-header {
    display: flex;
    align-items: center;
    gap: 8px;
}

.zone-coords-header .fa-location-dot,
.zone-coords-header .fa-route {
    margin-right: 6px;
}

.zone-list .zone-item .fa-bell,
.zone-list .zone-item .fa-bell-slash {
    margin-right: 6px;
}

.zone-status-icon {
    font-size: 16px;
}

.zone-coord-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.zone-coord-row span:first-child {
    font-size: 14px;
    color: var(--text-color);
}

.zone-coord-row span:last-child {
    font-weight: 500;
    color: var(--button-bg);
    font-size: 14px;
}

.zone-map-preview-container {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.zone-map-preview {
    height: 150px;
    border-radius: 8px;
    border: 1px solid var(--input-border);
    background-color: var(--input-bg);
}

#zoneMapEditor,
.zone-map-editor {
    height: 350px !important;
    width: 100% !important;
    min-height: 350px;
    border-radius: 8px;
    border: 1px solid var(--input-border);
    margin-bottom: 12px;
    background-color: #e8e8e8;
    overflow: hidden;
    z-index: 1;
    position: relative;
}

#zoneMapEditor .leaflet-map-pane,
#zoneMapEditor .maplibregl-map,
.zone-map-editor .leaflet-map-pane,
.zone-map-editor .maplibregl-map {
    position: relative !important;
}

.modal-content-wide {
    width: 95%;
    max-width: 500px;
    max-height: calc(100vh - 40px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    position: relative;
    z-index: 2001;
}

/* ===== Модалка детализации блока «💎 Поддержка проекта» =====
   Широкая модалка, в которую клонируется сетка премиум-ачивок.
   Шапка (заголовок, подзаголовок, прогресс-бар) заполняется
   JS-функцией openPremiumAchievementsModal() из data-* на
   корневом элементе карточки. Все 7 премиум-ачивок показываются
   сразу, без вложенного скролла. */
.modal-content-premium-achievements {
    max-width: 720px;
    width: 95%;
    max-height: calc(100vh - 32px);
    padding: 22px 22px 18px;
}
.premium-achievements-modal-sub {
    margin: -6px 0 4px 0;
    font-size: 12.5px;
    color: color-mix(in srgb, #b45309 65%, var(--us-text-muted, #64748b));
    font-weight: 600;
}
body.dark-theme .premium-achievements-modal-sub {
    color: color-mix(in srgb, #f59e0b 60%, #cbd5e1);
}
.premium-achievements-modal-progress {
    height: 8px;
    border-radius: 999px;
    background: color-mix(in srgb, #b45309 14%, transparent);
    overflow: hidden;
    box-shadow: inset 0 1px 2px color-mix(in srgb, #b45309 20%, transparent);
}
.premium-achievements-modal-progress-fill {
    height: 100%;
    width: var(--quests-progress, 0%);
    background: linear-gradient(90deg, #b45309, #f59e0b);
    border-radius: 999px;
    box-shadow: 0 0 6px color-mix(in srgb, #f59e0b 60%, transparent);
    transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.premium-achievements-modal-progress-text {
    margin: 6px 0 12px 0;
    font-size: 11px;
    text-align: right;
    color: color-mix(in srgb, #b45309 70%, var(--us-text, #0f172a));
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}
.premium-achievements-modal-body {
    /* Сетка .achievement-grid-premium внутри body получает естественную
       высоту и display:grid (см. переопределение выше). Здесь просто
       контейнер без собственного скролла — скролл делает сам
       .modal-content. */
}
@media (max-width: 720px) {
    .modal-content-premium-achievements {
        max-width: 100%;
        padding: 16px 14px 14px;
    }
}

/* ===== Dwell-модалки (детализация "Время пребывания в зонах (24ч)"
   и "Время пребывания на маршрутах (24ч)") =====
   Контейнер с per-user разбивкой: каждая зона/маршрут — отдельная
   "карточка", внутри которой список наблюдаемых пользователей и
   их индивидуальное время пребывания. */
.dwell-modal-list {
    display: block;
    margin-top: 4px;
}

.dwell-modal-empty {
    padding: 18px 8px;
    text-align: center;
    color: var(--us-text-muted, #64748b);
    font-size: 14px;
    line-height: 1.4;
}

.dwell-modal-groups {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.dwell-modal-group {
    border: 1px solid var(--us-border, rgba(15, 23, 42, 0.08));
    border-radius: 12px;
    background: var(--us-surface, rgba(15, 23, 42, 0.025));
    overflow: hidden;
}

body.dark-theme .dwell-modal-group {
    background: rgba(255, 255, 255, 0.04);
    border-color: var(--us-border-strong, rgba(255, 255, 255, 0.14));
}

.dwell-modal-group-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 12px;
    background: var(--us-surface-2, rgba(15, 23, 42, 0.04));
    border-bottom: 1px solid var(--us-border, rgba(15, 23, 42, 0.08));
}

body.dark-theme .dwell-modal-group-header {
    background: rgba(255, 255, 255, 0.05);
    border-bottom-color: var(--us-border-strong, rgba(255, 255, 255, 0.14));
}

.dwell-modal-group-header .widget-badge {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dwell-modal-group-meta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    font-size: 12px;
    color: var(--us-text-muted, #64748b);
}

.dwell-modal-group-total {
    font-weight: 700;
    color: var(--us-text, #0f172a);
    font-variant-numeric: tabular-nums;
}

body.dark-theme .dwell-modal-group-total {
    color: var(--us-text, #f1f5f9);
}

.dwell-modal-group-count {
    font-size: 11px;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--us-surface-3, rgba(15, 23, 42, 0.06));
    color: var(--us-text-muted, #64748b);
}

body.dark-theme .dwell-modal-group-count {
    background: rgba(255, 255, 255, 0.08);
    color: var(--us-text-muted, #cbd5e1);
}

.dwell-modal-group-body {
    padding: 6px 4px;
}

.dwell-modal-users {
    list-style: none;
    margin: 0;
    padding: 0;
}

.dwell-modal-user {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 7px 10px;
    border-radius: 8px;
    transition: background-color 120ms ease;
}

.dwell-modal-user + .dwell-modal-user {
    margin-top: 2px;
}

.dwell-modal-user:hover {
    background: var(--us-surface-3, rgba(15, 23, 42, 0.04));
}

body.dark-theme .dwell-modal-user:hover {
    background: rgba(255, 255, 255, 0.05);
}

.dwell-modal-user-name {
    flex: 1 1 auto;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 500;
    color: var(--us-text, #0f172a);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dwell-modal-user-name > i {
    font-size: 11px;
    color: var(--us-text-muted, #64748b);
    flex-shrink: 0;
}

body.dark-theme .dwell-modal-user-name {
    color: var(--us-text, #f1f5f9);
}

.dwell-modal-user-dwell {
    flex-shrink: 0;
    font-size: 12px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--widget-accent, var(--button-bg));
}

.dwell-modal-users-empty {
    padding: 10px 12px;
    font-size: 12px;
    font-style: italic;
    color: var(--us-text-muted, #64748b);
    text-align: center;
}

/* Кликабельные виджеты на дашборде: лёгкий hover/active-feedback,
   курсор pointer, focus-ring для клавиатурной навигации. */
.dashboard-widget.widget-clickable {
    cursor: pointer;
    transition:
        transform 140ms cubic-bezier(0.22, 0.61, 0.36, 1),
        box-shadow 140ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.dashboard-widget.widget-clickable:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 14px -6px rgba(15, 23, 42, 0.18);
}

.dashboard-widget.widget-clickable:active {
    transform: translateY(0);
    box-shadow: none;
}

.dashboard-widget.widget-clickable:focus-visible {
    outline: 2px solid var(--button-bg, #3b82f6);
    outline-offset: 2px;
}

body.dark-theme .dashboard-widget.widget-clickable:hover {
    box-shadow: 0 4px 14px -6px rgba(0, 0, 0, 0.5);
}

.zone-editor-controls {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: 12px;
}

#zoneMapEditor.leaflet-container,
#zoneMapEditor.maplibregl-map {
    background: #e8e8e8 !important;
}

.zone-editor-coords {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.zone-editor-coord-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.zone-editor-coord-row span {
    min-width: 80px;
    font-size: 14px;
    color: var(--text-color);
}

.zone-editor-coord-row input {
    flex: 1;
    margin: 0;
    padding: 8px 12px;
    font-size: 14px;
}

.zone-editor-radius {
    display: flex;
    align-items: center;
    gap: 8px;
}

.zone-editor-radius span {
    font-size: 14px;
    color: var(--text-color);
}

.zone-editor-radius select {
    flex: 1;
    margin: 0;
    padding: 8px 12px;
    font-size: 14px;
}
.zone-toggle-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 0;
    margin-bottom: 8px;
    border-bottom: 1px solid var(--input-border);
}

.zone-toggle-row span {
    font-size: 14px;
}

.toggle-switch {
    position: relative;
    display: inline-block;
    width: 44px;
    height: 24px;
}

.toggle-switch input {
    opacity: 0;
    width: 0;
    height: 0;
}

.toggle-slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #ccc;
    transition: 0.3s;
    border-radius: 24px;
}

.toggle-slider:before {
    position: absolute;
    content: "";
    height: 18px;
    width: 18px;
    left: 3px;
    bottom: 3px;
    background-color: white;
    transition: 0.3s;
    border-radius: 50%;
}

.toggle-switch input:checked + .toggle-slider {
    background-color: #28a745;
}

.toggle-switch input:checked + .toggle-slider:before {
    transform: translateX(20px);
}

.help-sections {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.help-sections {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.help-item {
    position: relative;
    background: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: 14px;
    overflow: hidden;
    box-shadow: 0 1px 2px var(--card-shadow);
    transition: box-shadow 0.25s ease, border-color 0.25s ease, transform 0.25s ease;
}

.help-item:hover {
    box-shadow: 0 4px 16px var(--card-shadow);
    border-color: color-mix(in srgb, var(--accent-color, #2ea043) 35%, var(--border-color));
}

.help-item.expanded {
    border-color: color-mix(in srgb, var(--accent-color, #2ea043) 45%, var(--border-color));
    box-shadow: 0 6px 22px var(--card-shadow);
}

.help-button {
    display: flex;
    align-items: center;
    width: 100%;
    padding: 14px 16px;
    background: transparent;
    border: none;
    cursor: pointer;
    text-align: left;
    color: var(--text-color);
    transition: background-color 0.2s ease, color 0.2s ease;
    margin: 0;
    gap: 14px;
    font-family: inherit;
    position: relative;
}

.help-button::after {
    content: "";
    position: absolute;
    left: 16px;
    right: 16px;
    bottom: 0;
    height: 1px;
    background: var(--border-color);
    opacity: 0;
    transition: opacity 0.2s ease;
}

.help-button:hover {
    background-color: color-mix(in srgb, var(--accent-color, #2ea043) 6%, transparent);
}

.help-button:focus-visible {
    outline: 2px solid var(--accent-color, #2ea043);
    outline-offset: -2px;
}

.help-icon {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px !important;
    height: 38px;
    border-radius: 10px;
    font-size: 17px;
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--accent-color, #2ea043) 22%, transparent),
        color-mix(in srgb, var(--accent-color, #2ea043) 6%, transparent));
    color: var(--accent-color, #2ea043);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-color, #2ea043) 18%, transparent);
    transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.help-button:hover .help-icon {
    transform: scale(1.05);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent-color, #2ea043) 28%, transparent);
}

.help-title {
    flex: 1;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.35;
    letter-spacing: -0.01em;
}

.help-arrow {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    font-size: 11px;
    background: color-mix(in srgb, var(--text-color) 6%, transparent);
    color: color-mix(in srgb, var(--text-color) 70%, transparent);
    transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1),
                background-color 0.2s ease,
                color 0.2s ease;
}

.help-button:hover .help-arrow {
    background: color-mix(in srgb, var(--accent-color, #2ea043) 12%, transparent);
    color: var(--accent-color, #2ea043);
}

.help-button.expanded .help-arrow {
    transform: rotate(180deg);
    background: var(--accent-color, #2ea043);
    color: #fff;
}

.help-content {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.35s cubic-bezier(0.4, 0, 0.2, 1);
    overflow: hidden;
}

.help-content.hidden {
    display: none;
}

.help-content > .help-content-inner {
    min-height: 0;
    overflow: hidden;
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity 0.25s ease, transform 0.25s ease;
}

.help-content.expanded {
    grid-template-rows: 1fr;
}

.help-content.expanded > .help-content-inner {
    opacity: 1;
    transform: translateY(0);
    transition-delay: 0.05s;
}

.help-content-text {
    font-size: 14px;
    line-height: 1.65;
    color: color-mix(in srgb, var(--text-color) 88%, transparent);
    white-space: pre-wrap;
    padding: 4px 16px 16px 68px;
}

.help-faq-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 0 12px 12px 12px;
}

.help-faq-item {
    background: color-mix(in srgb, var(--text-color) 4%, transparent);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    overflow: hidden;
    transition: background-color 0.2s ease, border-color 0.2s ease;
}

.help-faq-item:hover {
    background: color-mix(in srgb, var(--accent-color, #2ea043) 5%, transparent);
    border-color: color-mix(in srgb, var(--accent-color, #2ea043) 25%, var(--border-color));
}

.help-faq-item.expanded {
    background: color-mix(in srgb, var(--accent-color, #2ea043) 7%, transparent);
    border-color: color-mix(in srgb, var(--accent-color, #2ea043) 35%, var(--border-color));
}

.help-faq-button {
    display: flex;
    align-items: center;
    width: 100%;
    padding: 11px 12px;
    background: transparent;
    border: none;
    cursor: pointer;
    text-align: left;
    color: var(--text-color);
    font-size: 14px;
    font-weight: 500;
    margin: 0;
    gap: 10px;
    font-family: inherit;
}

.help-faq-button .help-icon {
    width: 30px;
    height: 30px;
    font-size: 14px;
    border-radius: 8px;
}

.help-faq-button .help-title {
    font-size: 14px;
    font-weight: 500;
}

.help-faq-button .help-arrow {
    width: 24px;
    height: 24px;
    font-size: 10px;
}

.help-faq-button:focus-visible {
    outline: 2px solid var(--accent-color, #2ea043);
    outline-offset: -2px;
}

@media (prefers-reduced-motion: reduce) {
    .help-item,
    .help-button,
    .help-icon,
    .help-arrow,
    .help-content,
    .help-content > .help-content-inner,
    .help-faq-item {
        transition: none;
    }
}

.realtime-map {
    height: 350px;
    width: 100%;
    border-radius: 8px;
    margin: 10px 0;
}

.realtime-info {
    margin: 10px 0;
    font-size: 14px;
    line-height: 1.4;
    color: var(--text-color);
}

.realtime-info.route-info-grid {
    grid-template-columns: 1fr;
}

.route-info-block--coords  .route-info-block__icon { background: linear-gradient(135deg, #6366f1, #4338ca); }
.route-info-block--address .route-info-block__icon { background: linear-gradient(135deg, #f59e0b, #d97706); }
.route-info-block--time    .route-info-block__icon { background: linear-gradient(135deg, #10b981, #047857); }

.realtime-relative {
    color: #888;
    font-size: 0.85em;
    font-weight: 500;
    margin-left: 4px;
}

.dark-theme .realtime-relative {
    color: #aaa;
}

.realtime-marker {
    background: none;
}

.realtime-marker-dot {
    width: 16px;
    height: 16px;
    background: #1a3c5e;
    border-radius: 50%;
    box-shadow: 0 0 0 0 rgba(26, 60, 94, 0.7);
    animation: realtime-pulse 2s ease-out infinite;
}

@keyframes realtime-pulse {
    0% {
        box-shadow: 0 0 0 0 rgba(26, 60, 94, 0.7);
        transform: scale(1);
    }
    70% {
        box-shadow: 0 0 0 15px rgba(26, 60, 94, 0);
        transform: scale(1.1);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(26, 60, 94, 0);
        transform: scale(1);
    }
}

#realtimeButton {
    background-color: #28a745;
    margin-bottom: 10px;
}

#realtimeButton:hover {
    background-color: #218838;
}

.dark-theme #realtimeButton {
    background-color: #28a745;
}

.dark-theme #realtimeButton:hover {
    background-color: #218838;
}

.all-users-map-container {
    position: relative;
    width: 100%;
    height: 380px;
}

.all-users-map {
    height: 100%;
    width: 100%;
    border-radius: 8px;
    margin: 10px 0;
    transition: height 0.3s ease;
}

/* Полноэкранный режим карты «Показать всех пользователей».
   Раньше контейнер карты вырывался из модального окна через
   position: fixed — клики по карте и её drag-область оказывались
   за пределами видимой части модалки. Теперь модальное окно
   само становится flex-контейнером во весь экран, а контейнер
   карты растягивается внутри него. */
.all-users-map-fullscreen {
    /* Класс оставлен для совместимости с JS, который его
       включает/выключает. Никаких визуальных эффектов он
       не даёт — позиционирование делает родительское модальное
       окно. */
}

.modal-content-all-users.modal-content-fullscreen-map {
    /* См. комментарий к .top-places-modal-layout.modal-content-fullscreen-map */
    position: fixed;
    inset: 0;
    width: 100vw;
    max-width: 100vw;
    height: 100vh;
    max-height: 100vh;
    border-radius: 0;
    padding: 0;
    margin: 0;
    /* Сбрасываем ограничения базового .modal-content */
    overflow: hidden;
    /* Растягиваем карту по высоте через flex */
    display: flex;
    flex-direction: column;
    z-index: 2100;
}

.modal-content-all-users.modal-content-fullscreen-map > h3,
.modal-content-all-users.modal-content-fullscreen-map > .top-places-modal-hint,
.modal-content-all-users.modal-content-fullscreen-map > p {
    flex: 0 0 auto;
    margin: 0;
    padding: 12px 18px 0;
}

.modal-content-all-users.modal-content-fullscreen-map .all-users-map-container {
    flex: 1 1 auto;
    min-height: 0; /* важно для flex-чайлда с overflow внутри */
    height: auto;
    margin: 10px 0;
    border-radius: 0;
}

.modal-content-all-users.modal-content-fullscreen-map .all-users-map {
    height: 100%;
    border-radius: 0;
}

.modal-content-all-users.modal-content-fullscreen-map .all-users-info {
    display: none;
}

.modal-content-all-users.modal-content-fullscreen-map .modal-close {
    z-index: 10;
}

.all-users-fullscreen-btn {
    position: absolute;
    top: 15px;
    right: 15px;
    z-index: 1000;
    background: var(--card-bg);
    border: 1px solid var(--input-border);
    border-radius: 6px;
    padding: 6px 12px;
    font-size: 12px;
    cursor: pointer;
    color: var(--text-color);
    box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}

.all-users-fullscreen-btn:hover {
    background: var(--button-hover);
    color: #fff;
    border-color: var(--button-hover);
}

.all-users-fit-btn {
    position: absolute;
    top: 50px;
    right: 15px;
    z-index: 1000;
    background: var(--card-bg);
    border: 1px solid var(--input-border);
    border-radius: 6px;
    padding: 6px 12px;
    font-size: 12px;
    cursor: pointer;
    color: var(--text-color);
    box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}

.all-users-fit-btn:hover {
    background: var(--button-hover);
    color: #fff;
    border-color: var(--button-hover);
}

/* ============================================================
   Heatmap fullscreen modal
   ============================================================ */
.modal-content-heatmap-fullscreen {
    max-width: 900px;
    width: 95vw;
}

/* ============================================================
   Mini-map fullscreen modal (карта наблюдаемых на весь экран)
   ============================================================ */
.modal-content-map-fullscreen {
    max-width: 1100px;
    width: 95vw;
    max-height: 90vh;
    height: 90vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.mini-map-fullscreen-hint {
    font-size: 12px;
    color: var(--us-text-muted, #64748b);
    opacity: 0.85;
    margin: 4px 0 12px;
}

body.dark-theme .mini-map-fullscreen-hint {
    color: var(--us-text-muted, #94a3b8);
}

.mini-map-fullscreen-map {
    flex: 1 1 auto;
    width: 100%;
    min-height: 0;
    border-radius: 12px;
    overflow: hidden;
    background: #e8e8e8;
}

/* Маркер «точка + подпись» для полноразмерной мини-карты дашборда.
   Подпись всегда видна над точкой, чтобы однозначно подписывать
   нескольких отслеживаемых пользователей. */
.mini-map-marker {
    position: relative;
    width: 12px !important;
    height: 12px !important;
    pointer-events: none;
}

.mini-map-marker .mini-map-marker__dot {
    position: absolute;
    left: 0;
    top: 0;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: #3388ff;
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.85), 0 1px 4px rgba(15, 23, 42, 0.45);
    pointer-events: auto;
    cursor: pointer;
}

body.dark-theme .mini-map-marker .mini-map-marker__dot {
    box-shadow: 0 0 0 2px rgba(15, 23, 42, 0.85), 0 1px 4px rgba(0, 0, 0, 0.6);
}

.mini-map-marker .mini-map-marker__dot--own {
    background: #ff7043;
}

.mini-map-marker .mini-map-marker__label {
    position: absolute;
    left: 50%;
    bottom: 100%;
    transform: translate(-50%, -6px);
    white-space: nowrap;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.2;
    color: #0f172a;
    background: rgba(255, 255, 255, 0.92);
    padding: 3px 8px;
    border-radius: 6px;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.18);
    pointer-events: none;
    user-select: none;
}

body.dark-theme .mini-map-marker .mini-map-marker__label {
    color: #f1f5f9;
    background: rgba(15, 23, 42, 0.85);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}

.heatmap-fullscreen-toolbar {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 4px 0 12px;
}

.heatmap-fullscreen-hint {
    font-size: 12px;
    color: var(--us-text-muted, #64748b);
    opacity: 0.85;
}

body.dark-theme .heatmap-fullscreen-hint {
    color: var(--us-text-muted, #94a3b8);
}

.heatmap-fullscreen-map {
    width: 100%;
    height: min(70vh, 560px);
    min-height: 360px;
    border-radius: 12px;
    overflow: hidden;
    background: #e8e8e8;
}

.heatmap-fullscreen-map .leaflet-control-zoom {
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 4px 14px rgba(15, 23, 42, 0.18);
}

/* Кликабельный виджет тепловой карты */
.dashboard-widget.widget-heatmap .widget-body-clickable {
    position: relative;
    cursor: zoom-in;
    transition: box-shadow 160ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.dashboard-widget.widget-heatmap .widget-body-clickable:hover {
    box-shadow: inset 0 0 0 2px rgba(255, 87, 34, 0.45);
}

.dashboard-widget.widget-heatmap .widget-body-clickable:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px rgba(255, 87, 34, 0.65);
}

.widget-expand-hint {
    position: absolute;
    right: 8px;
    bottom: 8px;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(15, 23, 42, 0.55);
    color: #fff;
    border-radius: 8px;
    font-size: 13px;
    pointer-events: none;
    opacity: 0.85;
}

body.dark-theme .widget-expand-hint {
    background: rgba(255, 255, 255, 0.15);
    color: #f1f5f9;
}

.all-users-info {
    padding: 12px 16px;
    background: var(--input-bg);
    border: 1px solid var(--input-border);
    border-radius: 8px;
    font-size: 13px;
    line-height: 1.6;
    color: var(--text-color);
    max-height: 150px;
    overflow-y: auto;
}

.all-users-loading,
.all-users-error {
    text-align: center;
    padding: 20px;
    color: var(--text-color);
}

.all-users-error {
    color: #dc3545;
}

.all-users-content {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.all-users-info-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
    padding: 4px 0;
    border-bottom: 1px solid var(--input-border);
}

.all-users-info-row:last-child {
    border-bottom: none;
}

.all-users-info-row--clickable {
    cursor: pointer;
    padding: 6px 8px;
    margin: 0 -8px;
    border-radius: 6px;
    border-bottom: 1px solid transparent;
    transition: background-color 0.15s ease, transform 0.08s ease;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
}

.all-users-info-row--clickable:hover {
    background: rgba(0, 123, 255, 0.08);
}

.all-users-info-row--clickable:active {
    transform: scale(0.99);
    background: rgba(0, 123, 255, 0.14);
}

.all-users-info-row--clickable:focus-visible {
    outline: 2px solid var(--button-bg, #007bff);
    outline-offset: 2px;
    background: rgba(0, 123, 255, 0.08);
}

.dark-theme .all-users-info-row--clickable:hover,
.dark-theme .all-users-info-row--clickable:focus-visible {
    background: rgba(120, 170, 255, 0.14);
}

.all-users-info-action {
    margin-left: auto;
    font-size: 14px;
    line-height: 1;
    opacity: 0.55;
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.all-users-info-row--clickable:hover .all-users-info-action,
.all-users-info-row--clickable:focus-visible .all-users-info-action {
    opacity: 1;
    transform: scale(1.15);
}

.all-users-marker-flash .all-users-marker-dot {
    animation: all-users-marker-flash-anim 0.8s ease-out 2;
}

@keyframes all-users-marker-flash-anim {
    0% {
        box-shadow: 0 0 0 0 rgba(255, 193, 7, 0.9);
        transform: scale(1);
    }
    50% {
        box-shadow: 0 0 0 18px rgba(255, 193, 7, 0);
        transform: scale(1.35);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(255, 193, 7, 0);
        transform: scale(1);
    }
}

.all-users-info-name {
    font-weight: 500;
    min-width: 60px;
}

.all-users-info-coords {
    font-family: monospace;
    font-size: 12px;
    color: var(--text-secondary);
}

.all-users-info-time {
    font-size: 11px;
    color: #888;
}

.all-users-no-data {
    text-align: center;
    color: #888;
    padding: 20px;
}

.dark-theme .all-users-info-time {
    color: #aaa;
}

.all-users-marker {
    background: none;
}

.all-users-marker-dot {
    width: 16px;
    height: 16px;
    background: var(--button-bg);
    border-radius: 50%;
    box-shadow: 0 0 0 0 rgba(0, 123, 255, 0.7);
    animation: all-users-pulse 2s ease-out infinite;
    position: absolute;
    top: 7px;
    left: 32px;
}

.all-users-marker-label {
    position: absolute;
    top: 0;
    left: 0;
    background: var(--button-bg);
    border: 1px solid var(--button-bg);
    border-radius: 4px;
    padding: 2px 6px;
    font-size: 11px;
    white-space: nowrap;
    color: #fff;
    box-shadow: 0 1px 4px rgba(0,0,0,0.2);
}

@keyframes all-users-pulse {
    0% {
        box-shadow: 0 0 0 0 rgba(0, 123, 255, 0.7);
        transform: scale(1);
    }
    70% {
        box-shadow: 0 0 0 15px rgba(0, 123, 255, 0);
        transform: scale(1.1);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(0, 123, 255, 0);
        transform: scale(1);
    }
}

#showAllUsersButton {
    margin-bottom: 10px;
}

.app-toast {
    position: fixed;
    top: 24px;
    left: 50%;
    transform: translateX(-50%) translateY(-20px);
    background: #323232;
    color: #fff;
    padding: 10px 18px;
    border-radius: 8px;
    font-size: 14px;
    line-height: 1.4;
    z-index: 20000;
    opacity: 0;
    pointer-events: none;
    transition: opacity 220ms ease, transform 220ms ease;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
    max-width: 90vw;
    word-break: break-word;
}
.app-toast.app-toast-show {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}
.app-toast.app-toast-success { background: #2e7d32; }
.app-toast.app-toast-error   { background: #c62828; }
.app-toast.app-toast-info    { background: #323232; }
/* [GAM-RECO §3.3] Тёплый оранжево-золотой тинт для «streak-бонуса»
   за ежедневный визит при streak≥7. Согласован с streak-виджетом
   (.widget-streak.widget-tint-orange). */
.app-toast.app-toast-streak  {
    background: linear-gradient(135deg, #f97316, #f59e0b);
    color: #fff7ed;
    font-weight: 700;
    box-shadow: 0 8px 24px color-mix(in srgb, #f97316 35%, transparent);
}

.app-modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 25000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
}
.app-modal {
    background: var(--card-bg, #fff);
    color: var(--text-color, #333);
    padding: 22px 22px 16px;
    border-radius: 12px;
    width: 100%;
    max-width: 360px;
    box-shadow: 0 12px 36px rgba(0, 0, 0, 0.35);
    font-family: inherit;
}
.app-modal h3 {
    margin: 0 0 8px;
    font-size: 16px;
    font-weight: 600;
}
.app-modal-hint {
    margin: 0 0 14px;
    font-size: 13px;
    color: var(--text-muted, #666);
}
.top-places-modal-hint {
    margin: -8px 0 14px;
    font-size: 12px;
    line-height: 1.4;
    color: var(--text-muted, #666);
    font-weight: 400;
}
.app-modal-input {
    width: 100%;
    box-sizing: border-box;
    padding: 10px 12px;
    border: 1px solid var(--input-border, #ccc);
    border-radius: 6px;
    background: var(--input-bg, #fff);
    color: var(--text-color, #333);
    font-size: 15px;
    margin-bottom: 16px;
}
.app-modal-input:focus {
    outline: 2px solid var(--button-bg, #007bff);
    outline-offset: 1px;
}
.app-modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}
.app-modal-btn {
    padding: 8px 16px;
    border: 0;
    border-radius: 6px;
    font-size: 12px;
    cursor: pointer;
    font-family: inherit;
}
.app-modal-btn-cancel {
    background: transparent;
    color: var(--text-muted, #666);
}
.app-modal-btn-ok {
    background: var(--button-bg, #007bff);
    color: #fff;
}
.app-modal-btn-ok:hover { background: var(--button-hover, #0056b3); }
.app-modal-btn-danger {
    background: var(--danger-bg, #c62828);
    color: #fff;
}
.app-modal-btn-danger:hover { background: var(--danger-hover, #8e1f1f); }

.address-line {
    font-size: 12px;
    color: #6b7280;
    line-height: 1.35;
    margin-top: 2px;
    word-break: break-word;

    min-height: 1em;
}
.address-line--loading {
    color: #9ca3af;
    font-style: italic;
}
.address-line--error {
    color: #9ca3af;
    font-style: italic;
    opacity: 0.7;
}
.dark-theme .address-line { color: #9ca3af; }
.dark-theme .address-line--loading,
.dark-theme .address-line--error { color: #6b7280; }

.all-users-info-row .address-line {
    flex: 1 1 100%;
    margin-top: 2px;
    margin-left: 0;
}

.zone-item-coords + .address-line {
    margin-top: 2px;
}

.edit-zone-name-address {
    margin: -4px 0 12px;
}
.app-modal-btn-cancel:hover { background: rgba(0, 0, 0, 0.05); }

.izone-stats-modal {
    position: relative;
    max-width: 520px;
    width: calc(100vw - 32px);
    max-height: 86vh;
    overflow-y: auto;
    text-align: left;
}
.izone-stats-modal-close {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: 8px;
    color: var(--text-muted, #6c757d);
    cursor: pointer;
    font-size: 16px;
    line-height: 1;
    transition: background-color 0.15s, color 0.15s;
    z-index: 2;
}
.izone-stats-modal-close:hover,
.izone-stats-modal-close:focus-visible {
    background: rgba(0, 0, 0, 0.06);
    color: var(--text-color, #222);
    outline: none;
}
.izone-stats-modal-close:active {
    transform: scale(0.92);
}

.izone-stats-modal > h3 {
    padding-right: 40px;
}
.izone-stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: 10px;
    margin: 8px 0 16px;
}
.izone-stats-card {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border-color, #e3e6ea);
    border-radius: 10px;
    background: var(--card-bg, #fff);
}
.izone-stats-card-icon {
    width: 32px;
    height: 32px;
    flex: 0 0 auto;
    border-radius: 8px;
    background: rgba(13, 110, 253, 0.10);
    color: var(--button-bg, #0d6efd);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
}
.izone-stats-card-body { min-width: 0; }
.izone-stats-card-label {
    font-size: 12px;
    color: var(--text-muted, #6c757d);
    line-height: 1.2;
    margin-bottom: 2px;
}
.izone-stats-card-value {
    font-size: 14px;
    font-weight: 700;
    line-height: 1.1;
}
.izone-stats-card-sub {
    margin-top: 4px;
    font-size: 12px;
    color: var(--text-muted, #6c757d);
    font-weight: 400;
    line-height: 1.3;
}
.izone-stats-section-title {
    margin: 4px 0 8px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-color, #222);
}
.izone-stats-table-wrap {
    margin: 0 0 14px;
    overflow-x: auto;
}
.izone-stats-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}
.izone-stats-table th,
.izone-stats-table td {
    padding: 8px 6px;
    border-bottom: 1px solid var(--border-color, #eef0f3);
    text-align: left;
    vertical-align: middle;
}
.izone-stats-table th {
    font-weight: 600;
    color: var(--text-muted, #6c757d);
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.izone-stats-seq {
    width: 28px;
    color: var(--text-muted, #6c757d);
    text-align: center;
}
.izone-stats-content {
    width: 60px;
    text-align: center;
    color: var(--text-muted, #6c757d);
}
.izone-stats-content .fa-paperclip { color: #198754; }
.izone-stats-content .fa-circle-xmark { color: #dc3545; }
.izone-stats-subs { min-width: 160px; }
.izone-stats-subs-num { font-weight: 600; margin-bottom: 4px; }
.izone-stats-inside { color: var(--text-muted, #6c757d); font-weight: 400; font-size: 12px; }
.izone-stats-subs-uniq {
    font-size: 12px;
    color: var(--text-muted, #6c757d);
    font-weight: 400;
    margin-top: 1px;
    margin-bottom: 4px;
}
.izone-stats-uniq-label { opacity: 0.85; }
.izone-stats-bar {
    height: 6px;
    background: rgba(13, 110, 253, 0.10);
    border-radius: 4px;
    overflow: hidden;
}
.izone-stats-bar-fill {
    height: 100%;
    background: linear-gradient(90deg, #0d6efd, #4dabf7);
    border-radius: 4px;
    transition: width 0.3s ease;
}

/* ============================================================
 * Статистика путеводителей (по образцу .izone-stats-*)
 * Используется модалкой, открываемой кнопкой «Статистика»
 * в разделе «Путеводители». Структура DOM-узлов полностью
 * повторяет izone-stats-modal, чтобы можно было опираться
 * на те же CSS-правила без дублирования.
 * ============================================================ */
.guide-stats-modal {
    position: relative;
    max-width: 520px;
    width: calc(100vw - 32px);
    max-height: 86vh;
    overflow-y: auto;
    text-align: left;
}
.guide-stats-modal-close {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: 8px;
    color: var(--text-muted, #6c757d);
    cursor: pointer;
    font-size: 16px;
    line-height: 1;
    transition: background-color 0.15s, color 0.15s;
    z-index: 2;
}
.guide-stats-modal-close:hover,
.guide-stats-modal-close:focus-visible {
    background: rgba(0, 0, 0, 0.06);
    color: var(--text-color, #222);
    outline: none;
}
.guide-stats-modal-close:active {
    transform: scale(0.92);
}
.guide-stats-modal > h3 {
    padding-right: 40px;
}
.guide-stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: 10px;
    margin: 8px 0 16px;
}
.guide-stats-card {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border-color, #e3e6ea);
    border-radius: 10px;
    background: var(--card-bg, #fff);
}
.guide-stats-card-icon {
    width: 32px;
    height: 32px;
    flex: 0 0 auto;
    border-radius: 8px;
    background: rgba(13, 110, 253, 0.10);
    color: var(--button-bg, #0d6efd);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
}
.guide-stats-card-body { min-width: 0; }
.guide-stats-card-label {
    font-size: 12px;
    color: var(--text-muted, #6c757d);
    line-height: 1.2;
    margin-bottom: 2px;
}
.guide-stats-card-value {
    font-size: 14px;
    font-weight: 700;
    line-height: 1.1;
}
.guide-stats-card-sub {
    margin-top: 4px;
    font-size: 12px;
    color: var(--text-muted, #6c757d);
    font-weight: 400;
    line-height: 1.3;
}
.guide-stats-section-title {
    margin: 4px 0 8px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-color, #222);
}
.guide-stats-table-wrap {
    margin: 0 0 14px;
    overflow-x: auto;
}
.guide-stats-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}
.guide-stats-table th,
.guide-stats-table td {
    padding: 8px 6px;
    border-bottom: 1px solid var(--border-color, #eef0f3);
    text-align: left;
    vertical-align: middle;
}
.guide-stats-table th {
    font-weight: 600;
    color: var(--text-muted, #6c757d);
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.guide-stats-seq {
    width: 28px;
    color: var(--text-muted, #6c757d);
    text-align: center;
}
.guide-stats-content {
    width: 60px;
    text-align: center;
    color: var(--text-muted, #6c757d);
}
.guide-stats-content .fa-paperclip { color: #198754; }
.guide-stats-content .fa-circle-xmark { color: #dc3545; }
.guide-stats-subs { min-width: 160px; }
.guide-stats-subs-num { font-weight: 600; margin-bottom: 4px; }
.guide-stats-inside { color: var(--text-muted, #6c757d); font-weight: 400; font-size: 12px; }
.guide-stats-subs-uniq {
    font-size: 12px;
    color: var(--text-muted, #6c757d);
    font-weight: 400;
    margin-top: 1px;
    margin-bottom: 4px;
}
.guide-stats-uniq-label { opacity: 0.85; }
.guide-stats-bar {
    height: 6px;
    background: rgba(13, 110, 253, 0.10);
    border-radius: 4px;
    overflow: hidden;
}
.guide-stats-bar-fill {
    height: 100%;
    background: linear-gradient(90deg, #0d6efd, #4dabf7);
    border-radius: 4px;
    transition: width 0.3s ease;
}

.top-places-map-container {
    position: relative;
    width: 100%;
    height: 380px;
}

.top-places-map {
    height: 100%;
    width: 100%;
    border-radius: 8px;
    margin: 10px 0;
    transition: height 0.3s ease;
}

/* Полноэкранный режим карты «Топ мест пребывания».
   Аналогично карте «Показать всех пользователей»: раньше контейнер
   карты становился position: fixed и выходил за границы модального
   окна (клик/drag по карте уходили за пределы видимой части модалки).
   Теперь растягиваем модальное окно на весь экран и через flex
   отдаём всю доступную высоту контейнеру карты внутри. */
.top-places-map-fullscreen {
    /* Класс оставлен для совместимости с JS. Реальное
       позиционирование делает родительское модальное окно. */
}

.top-places-modal-layout.modal-content-fullscreen-map {
    /* Полностью растягиваем модальное окно на весь viewport.
       position: fixed выводит его из контекста родительского
       .modal (с его padding/flex-центрированием), а высокий
       z-index гарантирует, что карта окажется поверх других
       модалок (.modal=2000, shareLive и др. до 2100). */
    position: fixed;
    inset: 0;
    width: 100vw;
    max-width: 100vw;
    height: 100vh;
    max-height: 100vh;
    border-radius: 0;
    padding: 0;
    margin: 0;
    /* Сбрасываем ограничения базового .modal-content */
    overflow: hidden;
    /* Растягиваем карту по высоте через flex */
    display: flex;
    flex-direction: column;
    z-index: 2100;
}

.top-places-modal-layout.modal-content-fullscreen-map > h3,
.top-places-modal-layout.modal-content-fullscreen-map > .top-places-modal-hint,
.top-places-modal-layout.modal-content-fullscreen-map > p {
    flex: 0 0 auto;
    margin: 0;
    padding: 12px 18px 0;
}

.top-places-modal-layout.modal-content-fullscreen-map .top-places-map-container {
    flex: 1 1 auto;
    min-height: 0;
    height: auto;
    margin: 10px 0;
    border-radius: 0;
}

.top-places-modal-layout.modal-content-fullscreen-map .top-places-map {
    height: 100%;
    border-radius: 0;
}

.top-places-modal-layout.modal-content-fullscreen-map .top-places-info {
    display: none;
}

.top-places-modal-layout.modal-content-fullscreen-map .modal-close {
    z-index: 10;
}

.top-places-fullscreen-btn,
.top-places-fit-btn {
    position: absolute;
    right: 15px;
    z-index: 1000;
    background: var(--card-bg);
    border: 1px solid var(--input-border);
    border-radius: 6px;
    padding: 6px 12px;
    font-size: 12px;
    cursor: pointer;
    color: var(--text-color);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}

.top-places-fullscreen-btn { top: 15px; }
.top-places-fit-btn { top: 50px; }

.top-places-fullscreen-btn:hover,
.top-places-fit-btn:hover {
    background: var(--button-hover);
    color: #fff;
    border-color: var(--button-hover);
}

.top-places-info {
    padding: 12px 16px;
    background: var(--input-bg);
    border: 1px solid var(--input-border);
    border-radius: 8px;
    font-size: 13px;
    line-height: 1.6;
    color: var(--text-color);
    max-height: 360px;
    overflow-y: auto;
    margin-top: 8px;
}

.top-places-item {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px;
    margin: 0 -8px;
    border-radius: 8px;
    border-bottom: 1px solid var(--input-border, rgba(127,127,127,0.15));
    cursor: pointer;
    transition: background-color 0.15s ease;
    outline: none;
}
.top-places-item:hover,
.top-places-item:focus-visible {
    background-color: rgba(127,127,127,0.12);
}
.top-places-item:focus-visible {
    box-shadow: 0 0 0 2px var(--button-bg, #007bff);
}
.top-places-item--active,
.top-places-item--active:hover,
.top-places-item--active:focus-visible {
    background-color: rgba(0,123,255,0.15);
}
.top-places-item:last-child {
    border-bottom: none;
    padding-bottom: 0;
}
.top-places-item:first-child {
    padding-top: 0;
}
.top-places-item__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.top-places-item__badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: var(--button-bg, #007bff);
    color: #fff;
    border-radius: 999px;
    padding: 2px 10px;
    font-weight: 600;
    font-size: 12px;
}
.top-places-item__count {
    font-size: 12px;
    color: var(--text-color-secondary, #888);
    white-space: nowrap;
}
.top-places-item__dwell {
    font-size: 12px;
    color: var(--text-color-secondary, #888);
}
.top-places-item__address {
    font-size: 13px;
    color: var(--text-color);
    word-break: break-word;
}

.top-places-marker {
    background: transparent;
    border: none;
    position: relative;
    width: 34px;
    height: 46px;
}
.top-places-marker__pin {
    position: absolute;
    top: 0;
    left: 0;
    width: 26px;
    height: 26px;
    border-radius: 50% 50% 50% 0;
    transform: rotate(-45deg);
    background: var(--button-bg, #007bff);
    box-shadow: 0 1px 4px rgba(0,0,0,0.3);
}
.top-places-marker__num {
    position: absolute;
    top: 5px;
    left: 9px;
    width: 18px;
    height: 18px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 700;
    font-size: 13px;
    line-height: 1;
}
.top-places-marker__num::after {
    content: attr(data-num);
}
.top-places-marker__count {
    position: absolute;
    bottom: 0;
    right: 0;
    background: var(--card-bg, #fff);
    color: var(--text-color, #222);
    border: 1px solid var(--input-border, #ccc);
    border-radius: 999px;
    padding: 1px 6px;
    font-size: 10px;
    font-weight: 600;
    white-space: nowrap;
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}

.top-places-popup {
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-color, #222);
    /* Отступ сверху, чтобы заголовок не налезал на кнопку
       закрытия в правом верхнем углу. */
    padding-right: 18px;
}
.top-places-popup-title {
    font-weight: 700;
    margin-bottom: 4px;
}
.top-places-popup-count {
    color: var(--text-color-secondary, #666);
    margin-bottom: 2px;
}
.top-places-popup-dwell {
    color: var(--text-color-secondary, #666);
    margin-bottom: 4px;
}
.top-places-popup-address {
    word-break: break-word;
}

/* Кнопка закрытия popup — явно фиксируем позицию в правом
   верхнем углу. В проекте Leaflet заменён шимом
   (public/leaflet-maplibre-shim.js), и popup реализован через
   maplibregl.Popup — поэтому стилизуем именно класс
   .maplibregl-popup-close-button. Дополнительно оставляем
   .leaflet-popup-close-button на случай, если в каких-то
   ситуациях popup всё же создаётся настоящим Leaflet. */
.top-places-modal-layout .maplibregl-popup-close-button,
.top-places-modal-layout .leaflet-popup-close-button {
    position: absolute !important;
    top: 4px !important;
    right: 6px !important;
    width: 22px !important;
    height: 22px !important;
    line-height: 22px !important;
    padding: 0 !important;
    margin: 0 !important;
    text-align: center !important;
    font: 700 18px/22px Tahoma, Verdana, sans-serif !important;
    color: var(--text-color-secondary, #888) !important;
    background: transparent !important;
    border: none !important;
    text-decoration: none !important;
    cursor: pointer !important;
    z-index: 10 !important;
}
.top-places-modal-layout .maplibregl-popup-close-button:hover,
.top-places-modal-layout .leaflet-popup-close-button:hover {
    color: var(--text-color, #222) !important;
    background: rgba(127,127,127,0.12) !important;
    border-radius: 4px !important;
}
/* MapLibre Popup рендерит контент внутри .maplibregl-popup-content,
   а кнопка закрытия — на одном уровне с ним внутри
   .maplibregl-popup-content-wrapper. Поправим позиционирование
   контейнера и расположим кнопку поверх контента. */
.top-places-modal-layout .maplibregl-popup {
    position: absolute !important;
    z-index: 1000 !important;
}
.top-places-modal-layout .maplibregl-popup-content-wrapper {
    position: relative !important;
    padding: 0 !important;
    /* Тема popup-а: фон и цвет берём из CSS-переменных темы,
       чтобы popup автоматически переключался между светлой и
       тёмной темой. */
    background-color: var(--card-bg, #fff) !important;
    color: var(--text-color, #333) !important;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
    border-radius: 8px;
}
.top-places-modal-layout .maplibregl-popup-content {
    padding: 10px 14px !important;
    padding-right: 32px !important;
    font-family: inherit !important;
    position: relative !important;
    line-height: 1.4 !important;
    /* Цвет текста popup-а — наследуется из обёртки,
       заданной через --text-color. */
    color: var(--text-color, #333) !important;
    background-color: var(--card-bg, #fff) !important;
}
/* «Носик» (tip) popup-а — закрашиваем в цвет фона карточки,
   чтобы он сливался с обёрткой при смене темы. */
.top-places-modal-layout .maplibregl-popup-tip {
    border-top-color: var(--card-bg, #fff) !important;
    border-bottom-color: var(--card-bg, #fff) !important;
    border-left-color: var(--card-bg, #fff) !important;
    border-right-color: var(--card-bg, #fff) !important;
}

.top-places-loading {
    color: var(--text-color-secondary, #888);
    text-align: center;
    padding: 16px;
}

.top-places-error {
    color: #d9534f;
    text-align: center;
    padding: 16px;
}

.top-places-content {
    padding: 4px 0;
}

.fa,
.fas,
.far,
.fal,
.fab {
    font-family: "Font Awesome 6 Free", "Font Awesome 6 Brands";
    font-weight: 900;
    font-style: normal;
    display: inline-block;
    line-height: 1;
    text-rendering: auto;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
.far { font-weight: 400; }
.fab { font-family: "Font Awesome 6 Brands"; font-weight: 400; }

button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
}
button > .fa,
button > .fas,
button > .far,
button > .fab {
    font-size: 0.95em;
    line-height: 1;
}

.nav-icon .fa { font-size: 20px; line-height: 1; }
.nav-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
}

.help-icon .fa {
    font-size: 18px;
    line-height: 1;
    color: var(--button-bg, #007bff);
}
.help-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
}

.impersonate-banner-icon .fa { font-size: 18px; line-height: 1; }

.map-hint-icon .fa { font-size: 18px; line-height: 1; color: #f0a020; }

button.legend-close,
button.collapse-button,
button.close-panel-btn,
button.modal-close,
button.player-button {
    gap: 0;
}

#exportCsvButton {
    gap: 14px;
}
button.legend-close .fa,
button.collapse-button .fa,
button.close-panel-btn .fa,
button.modal-close .fa {
    font-size: 18px;
    line-height: 1;
}

.channel-section {
    margin-top: 12px;
    padding: 12px;
    background: var(--bg-secondary, #f7f7f7);
    border-radius: 8px;
    border: 1px solid var(--border-color, #e0e0e0);
}
.channel-section h4 {
    margin: 0 0 8px 0;
    font-size: 14px;
    font-weight: 600;
}
.channel-empty-hint {
    margin: 0 0 8px 0;
    color: var(--text-muted);
    font-size: 13px;
}
.channel-current {
    display: flex;
    flex-direction: column;
    margin-bottom: 8px;
    padding: 8px;
    background: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    font-size: 13px;
}
.channel-current-label {
    color: var(--text-muted);
    font-size: 12px;
}
.channel-current-value {
    font-weight: 500;
    color: var(--text-color);
    margin-top: 2px;
}
.channel-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 12px;
}
.channel-item {
    background: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 10px 12px;
    font-size: 13px;
    color: var(--text-color);
}
.channel-item.channel-inactive {
    border-color: var(--warning-border);
    background: var(--warning-bg);
}
.channel-item-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 4px;
    font-weight: 500;
    color: var(--text-color);
}
.channel-item-status {
    font-size: 11px;
    padding: 2px 6px;
    border-radius: 4px;
    background: rgba(0, 200, 0, 0.15);
    color: var(--success-color);
}
.channel-inactive .channel-item-status {
    background: rgba(220, 80, 0, 0.15);
    color: var(--warning-color);
}
.channel-item-meta {
    font-size: 11px;
    color: var(--text-muted);
    margin-bottom: 4px;
}
.channel-item-error {
    font-size: 11px;
    color: var(--danger-color);
    margin-bottom: 6px;
    word-break: break-word;
}
.channel-item-actions {
    display: flex;
    gap: 6px;
    margin-top: 6px;
}
.channel-item-actions .btn-small {
    padding: 8px 10px;
    font-size: 12px;
}
.channel-intro {
    margin: 0 0 12px 0;
    font-size: 13px;
    color: var(--text-muted);
}
.channel-empty {
    padding: 12px;
    background: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    text-align: center;
    color: var(--text-muted);
    font-size: 13px;
}

.dark-theme .channel-item-status {
    background: rgba(111, 207, 111, 0.18);
}
.dark-theme .channel-inactive .channel-item-status {
    background: rgba(240, 198, 116, 0.18);
}

.channel-picker-modal {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10000;
    padding: 16px;
}
.channel-picker-box {
    background: var(--bg-primary, #fff);
    border-radius: 12px;
    padding: 16px;
    max-width: 420px;
    width: 100%;
    max-height: 80vh;
    overflow-y: auto;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
.channel-picker-box h4 {
    margin: 0 0 12px 0;
    font-size: 15px;
}
.channel-picker-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 12px;
}
.channel-picker-item {
    text-align: left;
    padding: 10px 12px;
    background: var(--bg-secondary, #f7f7f7);
    border: 1px solid var(--border-color, #e0e0e0);
    border-radius: 8px;
    font-size: 14px;
    cursor: pointer;
    transition: background 0.15s;
}
.channel-picker-item:hover {
    background: var(--bg-hover, #eee);
}
.channel-picker-item.selected {
    background: rgba(0, 122, 255, 0.1);
    border-color: #007aff;
}
.channel-picker-empty {
    color: var(--text-muted);
    font-size: 13px;
    margin: 8px 0;
}
.dark-theme .channel-picker-box h4 {
    color: var(--text-color);
}
.dark-theme .channel-picker-item {
    color: var(--text-color);
}
.dark-theme .channel-picker-item.selected {
    background: rgba(13, 123, 255, 0.18);
    border-color: #0d7bff;
}

.zones-form-enabled-toggle,
.zones-form-extend-info {
 display: inline-flex;
 align-items: center;
 gap:8px;
 flex-wrap: wrap;
}

.zones-form-enabled-toggle .btn,
.zones-form-extend-info .btn {
 min-width:110px;
}

.zones-form-extend-info #zonesFormExpiresText {
 color: var(--text-muted, #6c757d);
 font-size:14px;
}

.nav-tab {
    position: relative;
}

.nav-badge {
    position: absolute;
    top: 4px;
    right: 12px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: #e53935;
    color: #fff;
    font-size: 10px;
    font-weight: 600;
    line-height: 18px;
    text-align: center;
    box-sizing: border-box;
}

/* ============================================
   Сводка — современный карточный дизайн
   ============================================ */

.dashboard-hero {
    background: linear-gradient(135deg, #06b6d4 0%, #6366f1 60%, #8b5cf6 100%);
    box-shadow: 0 8px 24px rgba(99, 102, 241, 0.32);
    border-radius: 18px;
}

.dashboard-hero .settings-hero-icon {
    background: rgba(255, 255, 255, 0.22);
}

/* Разноцветные варианты hero для остальных разделов */
/*
 * [Hero/Green] Карта перемещений (Геотрекер) — зелёно-бирюзовый
 * градиент в тон иконки fa-map-location-dot и самой идеи «маршрута
 * на карте» (природа, навигация, outdoor). Раньше тут по ошибке
 * висел оранжево-красный градиент (#f59e0b → #ef4444), хотя в
 * комментарии выше уже было задокументировано «#0ea5e9 → #10b981»
 * — привели реализацию в соответствие с документацией.
 *
 * ВАЖНО: класс .geotracker-hero также висит на hero раздела
 * «Достижения» (там DOM содержит
 *   class="settings-hero geotracker-hero achievements-hero").
 * Чтобы смена фона карты НЕ затронула достижения, ниже отдельным
 * правилом .achievements-hero принудительно возвращаем оранжево-
 * красный градиент. Сам базовый класс .geotracker-hero остаётся
 * зелёным, чтобы новые разделы, которые его используют, тоже
 * получали «картографический» цвет.
 */
.geotracker-hero {
    background: linear-gradient(135deg, #0ea5e9 0%, #10b981 100%);
    box-shadow: 0 8px 24px rgba(16, 185, 129, 0.30);
    border-radius: 18px;
}

/* [Hero/Green] Сохраняем исторический оранжево-красный градиент
 * ТОЛЬКО для раздела «Достижения». См. подробный комментарий выше
 * у .geotracker-hero — порядок селекторов одинаковый по
 * специфичности (1 класс), но .achievements-hero объявлен позже,
 * поэтому его background выигрывает каскад. */
.achievements-hero {
    background: linear-gradient(135deg, #f59e0b 0%, #ef4444 100%);
    box-shadow: 0 8px 24px rgba(245, 158, 11, 0.30);
}

.watching-hero {
    background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
    box-shadow: 0 8px 24px rgba(139, 92, 246, 0.32);
    border-radius: 18px;
}

.balance-hero {
    background: linear-gradient(135deg, #f59e0b 0%, #ef4444 100%);
    box-shadow: 0 8px 24px rgba(245, 158, 11, 0.30);
    border-radius: 18px;
}

.help-hero {
    background: linear-gradient(135deg, #06b6d4 0%, #6366f1 100%);
    box-shadow: 0 8px 24px rgba(99, 102, 241, 0.30);
    border-radius: 18px;
}

.geotracker-hero .settings-hero-icon,
.watching-hero .settings-hero-icon,
.balance-hero .settings-hero-icon,
.help-hero .settings-hero-icon {
    background: rgba(255, 255, 255, 0.22);
}

/* ============================================================
   [P0 #1] Hero-обёртка для раздела «Достижения» с вертикальной
   раскладкой (иконка+заголовок сверху, 4 stat-карточки снизу).
   Применяется ТОЛЬКО к hero достижений — общий .geotracker-hero
   используется ещё в разделе «Карта перемещений» с горизонтальным
   layout, поэтому модифицируем через отдельный класс, а не
   переписываем базовый.

   Карточки лежат ВНУТРИ hero — на ярком градиенте (#0ea5e9 →
   #10b981), иначе белый текст на полупрозрачном белом стекле
   был бы не виден на светлом/тёмном фоне страницы в светлой
   теме. Внутри hero-блока z-index: 1 у иконки/текста
   не мешает сетке (см. .settings-hero-text { z-index: 1 }) —
   nav.achievements-hero-stats идёт после .settings-hero-text
   в DOM, поэтому рисуется поверх декоративного ::after.
   ============================================================ */
.achievements-hero {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    position: relative;
}

.settings-hero-content {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
    position: relative;
    z-index: 1;
}

/* ============================================================
   [P0 #1] Hero stat-капсула (Material 3 style) раздела
   «Достижения» (#sectionGeotracker). Пять кликабельных чипов
   внутри одной стеклянной пилюли с тонкими вертикальными
   разделителями между ними:
     • ⭐ Player Level     → #widget-player-level
     • 🔥 Серия            → #widget-streak
     • 🏅 Прогресс         → #widget-achievements
     • №  Место в топе     → #widget-leaderboard
     • ✦  Глобальная карма → #widget-achievements (попап)

   Структура каждого чипа:
     <span class="achievements-hero-chip-value">🔥 12</span>   ← крупное значение (value)
     <span class="achievements-hero-chip-label">дней</span>   ← мелкая подпись (label)
   value + label подставляются в JS через I18n.t() с параметрами
   (translateStatic() плейсхолдеры не подставляет, поэтому при
   смене локали renderAchievementsHeroStats() перерисовывает
   капсулу из кеша dashboardData).

   Тема: фон/границы/focus-ring подтягиваются через
   CSS-переменные --achv-stat-* (определены в :root,
   переопределены в .dark-theme), капсула автоматически
   адаптируется к активной теме без дублирования media/селекторов.
   Цвет текста (--achv-stat-fg) в обеих темах остаётся белым —
   капсула лежит поверх фиксированного яркого hero-градиента.

   ─── [style/hero-stats-mobile-scroll] Layout ────────────────────
   В mobile-first miniapp 5 чипов никогда не помещаются в один
   ряд на типичной ширине viewport (360-430px) — streak-чип с
   shield-pill и progress-чип с дельтой «▲+N» физически шире
   60px. Решение: горизонтальный scroll-snap с фиксированной
   мин. шириной чипа 92px и edge-fade градиентами в обёртке
   .achievements-hero-stats-wrap, намекающими «свайпай →».
   На десктопе (>600px) капсула остаётся в один ряд с равной
   шириной чипов (flex: 1 1 0) — старое поведение сохранено.
   ============================================================ */

/* Обёртка вокруг nav нужна для позиционирования edge-fade
   градиентов относительно СТАТИЧНОГО контейнера (а не
   scrollable-нава — иначе градиенты «уезжали» бы вместе
   с контентом при свайпе). Также служит якорем для JS
   updateHeroStatsScrollFades() — toggle классов
   .has-scroll-start / .has-scroll-end. */
.achievements-hero-stats-wrap {
    position: relative;
    /* Горизонтальный scroll внутри капсулы может
       «выпрыгивать» за пределы hero-блока на маленьких
       экранах. Безопаснее клипать всё лишнее, чтобы не
       сломать border-radius стеклянной пилюли. */
    overflow: hidden;
    border-radius: 18px;
    /* Плавное появление fade-градиентов (CSS-only fallback,
       когда JS не успел переключить классы). */
    --hero-fade-opacity: 0;
}

/* Edge-fade градиенты по бокам капсулы. Скрыты по умолчанию
   (CSS-only fallback без JS). JS добавляет .has-scroll-start
   и/или .has-scroll-end на обёртку — тогда соответствующий
   fade становится видимым. Плавный transition уважает
   prefers-reduced-motion (см. ниже). */
.achievements-hero-stats-wrap::before,
.achievements-hero-stats-wrap::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    width: 28px;
    pointer-events: none;
    z-index: 3;
    opacity: var(--hero-fade-opacity, 0);
    transition: opacity 0.22s ease;
    border-radius: 0;
}

.achievements-hero-stats-wrap::before {
    left: 0;
    background: linear-gradient(
        to right,
        rgba(14, 165, 233, 0.55) 0%,
        rgba(14, 165, 233, 0.18) 60%,
        transparent 100%
    );
}

.achievements-hero-stats-wrap::after {
    right: 0;
    background: linear-gradient(
        to left,
        rgba(16, 185, 129, 0.55) 0%,
        rgba(16, 185, 129, 0.18) 60%,
        transparent 100%
    );
}

.achievements-hero-stats-wrap.has-scroll-start::before {
    opacity: 1;
}

.achievements-hero-stats-wrap.has-scroll-end::after {
    opacity: 1;
}

/* [style/hero-stats-mobile-scroll] «Маяк» — пульсирующий
   edge-fade справа. Ставится на обёртку .is-hint-pulse на
   ~4 секунды сразу после первой загрузки раздела, чтобы
   привлечь внимание пользователя к скроллируемому меню.

   Pulse построен на двух осях:
     • opacity 1 → 0.45 → 1   — fade «дышит» (хочется взглянуть);
     • transform scaleX 1 → 1.6 → 1 — fade визуально вытягивается
       вправо, как бы «указывая» за край капсулы, создавая
       иллюзию «здесь что-то есть».

   Keyframes НЕ используют filter/box-shadow, потому что
   transform/opacity не вызывают layout и не «дёргают»
   scroll-snap (свойство, на которое мы опираемся).
   ============================================================ */
@keyframes hero-stats-hint-pulse {
    0%, 100% {
        opacity: 0.55;
        transform: scaleX(1);
    }
    50% {
        opacity: 1;
        transform: scaleX(1.55);
    }
}

.achievements-hero-stats-wrap.is-hint-pulse.has-scroll-end::after {
    /* Только правый край — пользователь должен свайпать туда
       (на Восток — это привычное направление «дальше» в LTR). */
    animation: hero-stats-hint-pulse 1.1s ease-in-out 3;
    transform-origin: right center;
}

/* Узкая вариация: на очень маленьких экранах (320-360px)
   делаем «маяк» чуть заметнее — у пользователя ещё меньше
   контекста, что за fade'ом что-то есть. */
@media (max-width: 360px) {
    .achievements-hero-stats-wrap.is-hint-pulse.has-scroll-end::after {
        animation-duration: 0.95s;
    }
}

.achievements-hero-stats {
    display: flex;
    align-items: stretch;
    margin: 0;
    padding: 4px;
    gap: 0;
    border-radius: 16px;
    background: var(--achv-stat-bg, rgba(255, 255, 255, 0.18));
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    border: 1px solid var(--achv-stat-border, rgba(255, 255, 255, 0.22));
    /* Soft-shadow Material 3: малая тень близко + широкая мягкая
       внизу. Цвет приглушённый, чтобы не выглядел чужеродно на
       ярком hero-градиенте. */
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.08),
        0 6px 20px -4px rgba(0, 0, 0, 0.18);
    position: relative;
    z-index: 1;
    /* [style/hero-stats-mobile-scroll] overflow-x: auto на
       ВСЕХ ширинах — критично для desktop-режима. Без этого
       при узком окне (Telegram sidebar / split-screen) чипы
       «вываливаются» за пределы nav без scroll: scrollWidth
       становится > clientWidth, но scrollLeft = N ничего
       не двигает (нет overflow:auto). Drag-handler в JS
       устанавливает scrollLeft, но визуально ничего не
       меняется → пользователь видит, что drag «не работает».
       С overflow-x:auto scroll реально работает, и drag-handler
       (см. enableHeroStatsDesktopDrag) корректно смещает
       содержимое. */
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    /* scroll-snap-type: x proximity — мягкий snap. На desktop
       при drag с плавным движением snap «помогает» прицелиться
       к началу чипа, но не блокирует свободное движение
       (как mandatory на mobile, где snap «щёлкает» по чипам). */
    scroll-snap-type: x proximity;
    scroll-padding-inline: 4px;
    scroll-behavior: smooth;
    /* Скрываем нативный scrollbar во ВСЕХ браузерах — он
       портит glassmorphism-эстетику капсулы. */
    scrollbar-width: none;
    -ms-overflow-style: none;
}
.achievements-hero-stats::-webkit-scrollbar {
    display: none;
    width: 0;
    height: 0;
}

.achievements-hero-chip {
    flex: 1 1 0;
    /* [style/hero-stats-mobile-scroll] min-width: 92px ВСЕГДА
       (а не только в mobile media-query). Это ключ к рабочему
       drag на desktop: при узком окне чипы не могут сжаться
       меньше 92px → overflow реально появляется → scroll
       работает. min-width: 0 в предыдущей версии давал
       бесконечное сжатие чипов без overflow. */
    min-width: 92px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 9px 8px;
    border-radius: 12px;
    color: var(--achv-stat-fg, #fff);
    text-decoration: none;
    text-align: center;
    position: relative;
    transition: background 0.18s ease, transform 0.18s ease,
        box-shadow 0.18s ease;
    scroll-behavior: smooth;
    text-underline-offset: 0;
    /* user-select отключён, чтобы случайный лонг-тап по чипу
       не копировал «🔥 1 · 🛡 1» в буфер обмена на iOS. */
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    /* [style/hero-stats-mobile-scroll] scroll-snap-align:
       при scroll-snap-type: x proximity (на desktop) snap
       «помогает» прицелиться к началу чипа, не блокируя
       свободное движение. На mobile (mandatory + always)
       жёстко щёлкает по чипам. */
    scroll-snap-align: start;
}

/* Тонкий вертикальный разделитель между чипами (НЕ после
   последнего). Используем ::after на всех, кроме :last-child —
   это надёжнее, чем :not(:last-child) с дополнительным классом,
   и легко поддаётся темизации через переменные. */
.achievements-hero-chip:not(:last-child)::after {
    content: "";
    position: absolute;
    right: 0;
    top: 22%;
    bottom: 22%;
    width: 1px;
    background: var(--achv-stat-border, rgba(255, 255, 255, 0.22));
    pointer-events: none;
    transition: background 0.18s ease;
}

.achievements-hero-chip:hover,
.achievements-hero-chip:focus-visible {
    background: var(--achv-stat-bg-hover, rgba(255, 255, 255, 0.28));
    transform: translateY(-1px);
    outline: none;
}

.achievements-hero-chip:hover::after,
.achievements-hero-chip:focus-visible::after {
    background: var(--achv-stat-border-hover, rgba(255, 255, 255, 0.45));
}

.achievements-hero-chip:focus-visible {
    box-shadow: inset 0 0 0 2px var(--achv-stat-focus-ring, rgba(255, 255, 255, 0.6));
}

.achievements-hero-chip-value {
    display: block;
    font-variant-numeric: tabular-nums;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
    color: inherit;
}

.achievements-hero-chip-label {
    display: block;
    font-size: 11px;
    font-weight: 500;
    line-height: 1;
    opacity: 0.85;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
    color: inherit;
    /* Локализованный лейбл на ТЗ-платформе часто длинный
       (например, исп. «en el top», нем. «in den Top»). Если он
       не помещается — обрезаем многоточием, а не переносим,
       чтобы капсула оставалась в одну строку. */
}

/* ============================================================
   [style/hero-stats-mobile-scroll] Мобильная раскладка
   (≤ 600px). На mobile scroll ВСЕГДА есть (базовое правило
   выше уже включило overflow-x: auto). Здесь мы делаем
   поведение «мобильным»:

     • scroll-snap-type: x mandatory (вместо proximity) —
       snap жёстко «щёлкает» по чипам при свайпе, как в
       iOS App Store. mandatory блокирует остановку
       scrollLeft между чипами.
     • scroll-snap-stop: always — каждый свайп «перепрыгивает»
       ровно на один чип (а не на 2-3 через snap-proximity).
     • flex: 0 0 92px — фиксированная ширина чипа вместо
       flex-stretch, чтобы все 5 чипов были одинакового
       размера и помещались целиком (icon + value + label
       без ellipsis).
     • touch-action: pan-x — горизонтальный свайп уходит
       в scroll, а вертикальный свайп страницы не блокируется.
       Без него на Android свайп по чипу иногда «съедался»
       системой как pull-to-refresh.
     • Уменьшаем padding и шрифт — на узких экранах
       каждый пиксель важен.

   Почему 600px, а не 420/360px (бывшие брейкпоинты):
   миниапп на 2026 год работает в Telegram WebApp (Chromium
   WebView) на широком спектре устройств — от iPhone SE 1st
   (320px) до Galaxy Fold (280px в сложенном виде). Узкие
   viewport-ы бывают и на 480px (split-screen Android), и
   на 414px (iPhone 11). Единый брейкпоинт 600px покрывает
   ВСЕ мобильные кейсы и избавляет от «двух ступеней»
   сжатия шрифта.
   ============================================================ */
@media (max-width: 600px) {
    .achievements-hero-stats {
        /* Жёсткий snap: каждый свайп «щёлкает» ровно по
           одному чипу. На desktop snap-proximity оставлен,
           чтобы drag ощущался свободным. */
        scroll-snap-type: x mandatory;
    }
    .achievements-hero-chip {
        /* Жёстко фиксированная ширина на mobile: 5 чипов
           одинакового размера, scroll между ними предсказуемый. */
        flex: 0 0 92px;
        scroll-snap-stop: always;
        /* Компактнее, чем на desktop — экономит высоту. */
        padding: 8px 6px;
        /* touch-action: pan-x → горизонтальный жест отдаётся
           в scroll, вертикальный свайп страницы не блокируется. */
        touch-action: pan-x;
    }
    /* Разделители между чипами оставляем — они работают
       и в scroll-режиме, помогают глазу отделить секции
       при частичном просмотре. */
    .achievements-hero-chip-value {
        font-size: 14px;
    }
    .achievements-hero-chip-label {
        font-size: 10.5px;
    }
}

/* Очень узкие экраны (iPhone SE 1st gen, 320px): сужаем
   чип до 84px, чтобы 2 чипа гарантированно помещались
   в кадр одновременно. Иначе пользователь видит один чип
   + кусок второго — непонятно, что дальше есть контент. */
@media (max-width: 360px) {
    .achievements-hero-chip {
        flex-basis: 84px;
        min-width: 84px;
    }
    .achievements-hero-chip-value {
        font-size: 13px;
    }
}

/* ============================================================
   [style/hero-stats-mobile-scroll] Десктопный drag-to-scroll.
   На desktop (601+px) touch-action: pan-x бесполезен —
   пользователь с мышью не получает нативный горизонтальный
   скролл. Подключаем ручной drag через JS (см.
   enableHeroStatsDesktopDrag в app.js) и индикаторы через
   CSS-курсоры.

   Курсоры:
     • grab        — на пустых зонах nav (между чипами и по
                    краям): сигнал «можно схватить»;
     • pointer     — на самих чипах (это <a>, на desktop
                    кликабельность важнее drag-аффорданса;
                    drag всё равно начнётся с любой точки);
     • grabbing    — при активном drag, перекрывает pointer
                    на чипах, чтобы курсор не «дёргался»
                    между grab и pointer.

   user-select: none во время drag — иначе при движении
   мыши по чипам выделяется текст «🔥 1 · 🛡 1» (Firefox
   выделяет даже под pointer-events:none, если не
   отключить select).
   ============================================================ */
.achievements-hero-stats {
    cursor: grab;
    /* Блокируем выделение текста при drag на desktop.
       user-select: none на parent надёжно отключает выделение
       для <a>-потомков (у которых по умолчанию user-select: text
       в некоторых браузерах не перекрывается родительским none).
       Метрики в чипах — статичные ярлыки «🔥 12», «🏅 18/64»,
       их копировать не нужно. */
    -webkit-user-select: none;
    user-select: none;
}

.achievements-hero-stats .achievements-hero-chip {
    /* Перекрываем grab родителя — <a> на десктопе должны
       «выглядеть кликабельными». Drag по чипу начинается
       ровно так же, как drag по пустому месту nav, потому
       что JS слушает mousedown на nav-уровне. */
    cursor: pointer;
}

/* Активный drag — JS добавляет .is-dragging на mousedown,
   снимает на mouseup. Курсор «схвачено», текст не
   выделяется, vertical-страница не скроллится. */
.achievements-hero-stats.is-dragging {
    cursor: grabbing;
    user-select: none;
    -webkit-user-select: none;
    /* Отключаем scroll-snap на время drag — иначе snap
       «перетягивает» scrollLeft к ближайшему чипу посреди
       ручного движения мыши, и drag ощущается «резиновым». */
    scroll-snap-type: none;
    /* Не даём браузеру показать context menu / drag-image
       на текстовых span'ах внутри чипов. */
    -webkit-touch-callout: none;
}

.achievements-hero-stats.is-dragging .achievements-hero-chip {
    cursor: grabbing;
}

/* На touch-устройствах курсоры не рендерятся, grab/grabbing
   избыточны — оставляем auto, чтобы не подсказывать
   «несуществующую» интерактивность курсором. */
@media (max-width: 600px) {
    .achievements-hero-stats,
    .achievements-hero-stats.is-dragging,
    .achievements-hero-stats .achievements-hero-chip,
    .achievements-hero-stats.is-dragging .achievements-hero-chip {
        cursor: auto;
    }
}

/* a11y: для пользователей на десктопе без мыши (тач-экран)
   и при reduced-motion — отдаём pointer-events на чипы
   как обычно, но drag остаётся доступным через
   нативный scroll (стрелками клавиатуры, например).
   Дополнительной стилизации тут не нужно — focus-visible
   уже подсвечивается существующим правилом. */

/* [P0 #1] A11y: пользователи с системной настройкой
   «уменьшить анимацию» не должны видеть translateY-подъём
   чипа и плавный transition фона. Согласуется с практикой
   других виджетов проекта (.streak-current, .widget-achievements). */
@media (prefers-reduced-motion: reduce) {
    .achievements-hero-chip {
        transition: none;
    }
    .achievements-hero-chip:not(:last-child)::after {
        transition: none;
    }
    .achievements-hero-chip:hover,
    .achievements-hero-chip:focus-visible {
        transform: none;
    }
    /* [style/hero-stats-mobile-scroll] Edge-fade градиенты
       тоже должны появляться мгновенно (без плавного
       opacity-transition) — иначе при свайпе с включённой
       настройкой «уменьшить анимацию» они «догоняют»
       контент с заметной задержкой. */
    .achievements-hero-stats-wrap::before,
    .achievements-hero-stats-wrap::after {
        transition: none;
    }
    /* Плавный scroll-snap по умолчанию — отключаем,
       snap переходит в «instant»-режим. */
    .achievements-hero-stats {
        scroll-behavior: auto;
    }
    /* «Маяк» pulse-анимация — отключается у пользователей с
       reduce-motion. Сам swipe в JS тоже не запускается
       (см. playHeroStatsHintSwipe). Эстетика fade'ов
       сохраняется — opacity просто без анимации. */
    .achievements-hero-stats-wrap.is-hint-pulse::after {
        animation: none;
    }
}

/* Отступ сверху при якорном скролле к виджету — чтобы ссылка
   не упиралась в системную/фиксированную шапку miniapp. */
#widget-streak,
#widget-quests,
#widget-achievements,
#widget-leaderboard {
    scroll-margin-top: 12px;
}


.settings-refresh-btn {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 16px;
    background: rgba(255, 255, 255, 0.22);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 12px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    position: relative;
    z-index: 1;
    transition: background 0.15s ease, transform 0.15s ease;
}

.settings-refresh-btn:hover {
    background: rgba(255, 255, 255, 0.32);
    transform: translateY(-1px);
}

.settings-refresh-btn:active {
    transform: translateY(0);
}

.settings-refresh-btn i {
    font-size: 13px;
    transition: transform 0.6s ease;
}

.settings-refresh-btn.is-spinning i {
    transform: rotate(360deg);
}

/* Сетка виджетов */
.dashboard-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 20px;
}

@media (max-width: 720px) {
    .dashboard-grid {
        grid-template-columns: 1fr;
    }
}

/* Виджет-карточка */
.dashboard-widget {
    background: var(--card-bg, #fff);
    border-radius: 16px;
    padding: 14px 14px 12px 14px;
    box-shadow:
        0 1px 2px var(--card-shadow, rgba(0, 0, 0, 0.06)),
        0 4px 14px color-mix(in srgb, var(--card-shadow, rgba(0,0,0,0.06)) 60%, transparent);
    border: 1px solid color-mix(in srgb, var(--input-border, #eaecef) 55%, transparent);
    display: flex;
    flex-direction: column;
    min-height: 130px;
    overflow: hidden;
    position: relative;
    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

.dashboard-widget::before {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 3px;
    background: var(--widget-accent, var(--button-bg));
    opacity: 0.85;
}

.dashboard-widget:hover {
    transform: translateY(-1px);
    box-shadow:
        0 2px 4px var(--card-shadow, rgba(0, 0, 0, 0.06)),
        0 8px 22px color-mix(in srgb, var(--card-shadow, rgba(0,0,0,0.06)) 70%, transparent);
    border-color: color-mix(in srgb, var(--widget-accent, var(--button-bg)) 30%, var(--input-border, #eaecef));
}

.dashboard-widget-wide {
    grid-column: 1 / -1;
}

/* =========================================================
   Вертикальные промежутки между виджетами вне grid-контейнера.

   Внутри .dashboard-grid между виджетами работает gap (см. выше).
   Но в разделах вроде «Достижения» (#sectionGeotracker) после
   grid-блока идут ещё wide-виджеты (leaderboard / heropath /
   activity), которые раньше прилипали друг к другу и к нижней
   строке grid-а без отступов. Эти правила дают им ровный
   промежуток 16px сверху — но только если виджет стоит вне grid;
   для виджетов внутри .dashboard-grid margin-top принудительно
   обнуляется, чтобы не дублировать gap.
   ========================================================= */
.dashboard-grid + .dashboard-widget,
.dashboard-widget + .dashboard-widget {
    margin-top: 16px;
}

/* Сброс margin-top для виджетов внутри grid (там работает gap). */
.dashboard-grid > .dashboard-widget {
    margin-top: 0;
}

/* Цветовые акценты виджетов */
.widget-tint-green   { --widget-accent: #10b981; --widget-accent-soft: rgba(16, 185, 129, 0.14); }
.widget-tint-emerald { --widget-accent: #059669; --widget-accent-soft: rgba(5, 150, 105, 0.14); }
.widget-tint-indigo  { --widget-accent: #6366f1; --widget-accent-soft: rgba(99, 102, 241, 0.14); }
.widget-tint-cyan    { --widget-accent: #06b6d4; --widget-accent-soft: rgba(6, 182, 212, 0.14); }
.widget-tint-blue    { --widget-accent: #3b82f6; --widget-accent-soft: rgba(59, 130, 246, 0.14); }

/* [Exploration 2026-07-06] Тёмно-бирюзовый акцент (#064a53)
 * для виджета «Исследование местности» (.widget-exploration).
 * Заменил ранее использовавшийся .widget-tint-cyan (#06b6d4),
 * чтобы отделить визуально от остальных cyan-виджетов (activity,
 * channels, user-stats, watchers-of-me) и подчеркнуть «глубину»
 * раздела (карта OSM / OSM-сегменты). */
.widget-tint-exploration { --widget-accent: #064a53; --widget-accent-soft: rgba(6, 74, 83, 0.14); }
.widget-tint-teal    { --widget-accent: #14b8a6; --widget-accent-soft: rgba(20, 184, 166, 0.14); }
.widget-tint-orange  { --widget-accent: #f97316; --widget-accent-soft: rgba(249, 115, 22, 0.14); }
.widget-tint-rose    { --widget-accent: #f43f5e; --widget-accent-soft: rgba(244, 63, 94, 0.14); }
.widget-tint-purple  { --widget-accent: #8b5cf6; --widget-accent-soft: rgba(139, 92, 246, 0.14); }
.widget-tint-pink    { --widget-accent: #94a3b8; --widget-accent-soft: rgba(148, 163, 184, 0.14); }
.widget-tint-slate   { --widget-accent: #94a3b8; --widget-accent-soft: rgba(148, 163, 184, 0.14); }
.widget-tint-amber   { --widget-accent: #f59e0b; --widget-accent-soft: rgba(245, 158, 11, 0.14); }
.widget-tint-red     { --widget-accent: #ef4444; --widget-accent-soft: rgba(239, 68, 68, 0.14); }
.widget-tint-violet  { --widget-accent: #7c3aed; --widget-accent-soft: rgba(124, 58, 237, 0.14); }
/* [Hero 2.1] «Золотой» tint — отдельный тон для Player Level,
   чтобы не пересекаться со streak (.widget-tint-orange).
   Чуть ярче и холоднее amber, чтобы визуально читалось как
   «награда/прогресс», а не «предупреждение/серия». */
.widget-tint-gold    { --widget-accent: #facc15; --widget-accent-soft: rgba(250, 204, 21, 0.16); }

/* Шапка виджета */
.widget-header {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
}

.widget-icon {
    width: 32px;
    height: 32px;
    border-radius: 10px;
    background: var(--widget-accent-soft, rgba(0, 123, 255, 0.14));
    color: var(--widget-accent, var(--button-bg));
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    flex-shrink: 0;
    transition: transform 0.2s ease;
}

.dashboard-widget:hover .widget-icon {
    transform: scale(1.06);
}

.widget-header h3 {
    margin: 0;
    font-size: 13px;
    color: var(--text-color, #222);
    display: inline;
    font-weight: 600;
    letter-spacing: -0.1px;
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.widget-header h3 i {
    display: none; /* перенесено в .widget-icon */
}

/* Счётчик — мягкая pill с амбер-градиентом */
.widget-counter {
    min-width: 24px;
    height: 24px;
    padding: 0 9px;
    border-radius: 12px;
    background: linear-gradient(135deg, #b45309, #f59e0b);
    color: #f8f8f8;
    font-size: 10px;
    font-weight: 700;
    line-height: 24px;
    text-align: center;
    flex-shrink: 0;
    transition: transform 0.15s ease;
}

.widget-counter.is-pulse {
    animation: widget-counter-pulse 0.6s ease;
}

@keyframes widget-counter-pulse {
    0%   { transform: scale(1); }
    50%  { transform: scale(1.25); }
    100% { transform: scale(1); }
}

/* ===== [P2 #11] Toggle «Только с прогрессом» в виджете достижений =====
   Компактный переключатель в шапке виджета, рядом со счётчиком.
   По умолчанию ВЫКЛ — показываются ВСЕ ачивки, чтобы новичок видел
   «вот сколько есть». При включении скрывает категории с progress=0
   и оставляет только разблокированные / с реальным прогрессом.
   Состояние сохраняется в localStorage (`achievement.filter.progressOnly`).
   Использует существующую механику .toggle-switch/.toggle-slider для
   визуальной консистентности с настройками (зоны, маршруты). */
.achievement-filter-toggle {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: 8px;
    padding: 3px 8px 3px 6px;
    border-radius: 14px;
    background: color-mix(in srgb, var(--widget-accent, #f59e0b) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #f59e0b) 22%, transparent);
    color: var(--text-color, #222);
    cursor: pointer;
    user-select: none;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    transition: background-color 0.18s ease,
                border-color 0.18s ease,
                color 0.18s ease,
                transform 0.12s ease;
    /* touch-friendly на мобильных (Telegram WebApp) */
    min-height: 24px;
}
.achievement-filter-toggle:hover {
    background: color-mix(in srgb, var(--widget-accent, #f59e0b) 18%, transparent);
    border-color: color-mix(in srgb, var(--widget-accent, #f59e0b) 36%, transparent);
}
.achievement-filter-toggle:active {
    transform: scale(0.97);
}
.achievement-filter-toggle:focus-within {
    outline: 2px solid color-mix(in srgb, var(--widget-accent, #f59e0b) 45%, transparent);
    outline-offset: 2px;
}
/* В активном состоянии делаем плашку более насыщенной —
   визуальный feedback, что фильтр работает. */
.achievement-filter-toggle.is-active {
    background: color-mix(in srgb, var(--widget-accent, #f59e0b) 22%, transparent);
    border-color: color-mix(in srgb, var(--widget-accent, #f59e0b) 55%, transparent);
    color: var(--text-color, #222);
}
/* Кастомный switch внутри плашки — переиспользуем стили .toggle-slider
   из настроек (зоны/маршруты), но с уменьшенным размером под компактный
   header. */
.achievement-filter-toggle .toggle-slider {
    position: relative;
    width: 26px;
    height: 14px;
    border-radius: 14px;
    background-color: #c8c8c8;
    transition: background-color 0.2s ease;
    flex: 0 0 auto;
}
.achievement-filter-toggle .toggle-slider::before {
    content: "";
    position: absolute;
    height: 10px;
    width: 10px;
    left: 2px;
    top: 2px;
    background-color: #fff;
    border-radius: 50%;
    transition: transform 0.2s ease;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
}
.achievement-filter-toggle-input {
    /* Скрытый нативный чекбокс; вся визуальная часть делегирована
       на .toggle-slider (стандартный паттерн a11y). */
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    pointer-events: none;
}
.achievement-filter-toggle-input:checked + .toggle-slider {
    background-color: var(--widget-accent, #f59e0b);
}
.achievement-filter-toggle-input:checked + .toggle-slider::before {
    transform: translateX(12px);
}
.achievement-filter-toggle-label {
    /* Текст «Только с прогрессом» — сжимается, если шапка узкая. */
    font-size: 11px;
    line-height: 1;
}
@media (max-width: 480px) {
    /* На очень узких экранах убираем длинный текст, оставляем только
       switch + иконку-подсказку через title. Экономим ~80px в header. */
    .achievement-filter-toggle-label {
        display: none;
    }
    .achievement-filter-toggle {
        padding: 3px 6px;
    }
}

/* ===== Таймер «⏰ до конца квестов» =====
   [P0 #4] Переработан: теперь это sticky-плашка под шапкой виджета
   «Квесты дня» с SVG-кольцом прогресса дня. Показывает, сколько
   осталось до обновления ежедневных квестов в TZ пользователя
   (FOMO-эффект: пользователь возвращается забрать награду до конца
   дня). Визуальный стиль единый с .widget-quests-summary: амбер-
   градиент в тон виджету, мягкая тень, декоративный блик в правом
   верхнем углу. Цвет текста — основной (var(--text-color)), чтобы
   читался на нежной амбер-подложке, как label в сводке. */
.widget-quests-timer {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 12px 0;
    padding: 8px 14px 8px 8px;
    border-radius: 14px;
    background: linear-gradient(135deg,
        color-mix(in srgb, #b45309 14%, var(--card-bg, #ffffff)) 0%,
        color-mix(in srgb, #f59e0b 8%,  var(--card-bg, #ffffff)) 100%);
    border: 1px solid color-mix(in srgb, #b45309 25%, transparent);
    box-shadow: 0 2px 10px color-mix(in srgb, #b45309 15%, transparent),
                inset 0 1px 0 color-mix(in srgb, #ffffff 50%, transparent);
    color: var(--text-color, #222);
    font-size: 12px;
    font-weight: 600;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
    align-self: flex-start;
    overflow: hidden;
    transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
/* Декоративный блик в правом верхнем углу — единый с .widget-quests-summary. */
.widget-quests-timer::before {
    content: "";
    position: absolute;
    top: -50%;
    right: -20%;
    width: 70%;
    height: 200%;
    background: radial-gradient(circle,
        color-mix(in srgb, #f59e0b 35%, transparent) 0%,
        transparent 65%);
    pointer-events: none;
    opacity: 0.4;
    z-index: 0;
}
/* Контент поверх декоративного блика. */
.widget-quests-timer > * {
    position: relative;
    z-index: 1;
}
/* SVG-кольцо прогресса дня (24ч). */
.widget-quests-timer-ring {
    width: 32px;
    height: 32px;
    flex: 0 0 auto;
    transform: rotate(-90deg);
}
.widget-quests-timer-ring-track {
    fill: none;
    stroke: color-mix(in srgb, #b45309 18%, transparent);
    stroke-width: 3;
}
.widget-quests-timer-ring-fill {
    fill: none;
    stroke: #b45309;
    stroke-width: 3;
    stroke-linecap: round;
    transition: stroke-dashoffset 0.6s ease, stroke 0.3s ease;
}
.widget-quests-timer-text {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
    gap: 1px;
}
.widget-quests-timer-text .widget-quests-timer-label {
    font-size: 9.5px;
    opacity: 0.7;
    text-transform: uppercase;
    letter-spacing: 0.4px;
}
.widget-quests-timer-text .widget-quests-timer-value {
    /* Значение («5 ч 32 мин») выделяем чуть сильнее, чем префикс
       («До конца квестов:»), чтобы взгляд цеплялся за цифры. */
    font-size: 13px;
    font-weight: 800;
    letter-spacing: 0.2px;
    color: #b45309;
}
/* Срочное состояние (< 60 мин до конца) — насыщенный янтарь +
   мягкая пульсация для привлечения внимания. */
.widget-quests-timer.is-urgent {
    background: linear-gradient(135deg,
        color-mix(in srgb, #b45309 24%, var(--card-bg, #ffffff)) 0%,
        color-mix(in srgb, #ef4444 14%, var(--card-bg, #ffffff)) 100%);
    border-color: color-mix(in srgb, #ef4444 40%, transparent);
    color: #b91c1c;
    animation: quest-timer-urgent-pulse 1.8s ease-in-out infinite;
}
@keyframes quest-timer-urgent-pulse {
    0%   { transform: scale(1);    box-shadow: 0 2px 10px color-mix(in srgb, #b45309 15%, transparent),
                                                inset 0 1px 0 color-mix(in srgb, #ffffff 50%, transparent),
                                                0 0 0 0   rgba(239, 68, 68, 0.0); }
    50%  { transform: scale(1.04); box-shadow: 0 2px 10px color-mix(in srgb, #b45309 15%, transparent),
                                                inset 0 1px 0 color-mix(in srgb, #ffffff 50%, transparent),
                                                0 0 0 6px rgba(239, 68, 68, 0.15); }
    100% { transform: scale(1);    box-shadow: 0 2px 10px color-mix(in srgb, #b45309 15%, transparent),
                                                inset 0 1px 0 color-mix(in srgb, #ffffff 50%, transparent),
                                                0 0 0 0   rgba(239, 68, 68, 0.0); }
}
/* Предупреждение (< 4ч до конца) — оранжевый акцент без пульсации. */
.widget-quests-timer.is-warning .widget-quests-timer-ring-fill {
    stroke: #f97316;
}
/* Критично (< 1ч до конца) — красный. */
.widget-quests-timer.is-urgent .widget-quests-timer-ring-fill {
    stroke: #ef4444;
}
/* Тёмная тема: чуть ярче и контрастнее. */
body.dark-theme .widget-quests-timer {
    background: linear-gradient(135deg,
        color-mix(in srgb, #b45309 22%, var(--card-bg, #1f2024)) 0%,
        color-mix(in srgb, #f59e0b 14%, var(--card-bg, #1f2024)) 100%);
    border-color: color-mix(in srgb, #f59e0b 35%, transparent);
    color: #fcd34d;
}
body.dark-theme .widget-quests-timer.is-urgent {
    background: linear-gradient(135deg,
        color-mix(in srgb, #b45309 28%, var(--card-bg, #1f2024)) 0%,
        color-mix(in srgb, #ef4444 18%, var(--card-bg, #1f2024)) 100%);
    color: #fde68a;
}
body.dark-theme .widget-quests-timer-text .widget-quests-timer-value {
    color: #f59e0b;
}

/* Тело виджета */
.widget-body {
    flex: 1;
    overflow-y: auto;
    max-height: 240px;
    margin: 0 -4px;
    padding: 0 4px;
}

/* Пустое состояние — с иконкой */
.widget-empty {
    color: color-mix(in srgb, var(--text-color, #222) 50%, transparent);
    font-size: 12.5px;
    margin: 0;
    padding: 8px 0 4px 0;
    text-align: center;
    line-height: 1.4;
    position: relative;
}

.widget-empty::before {
    content: "\f05e"; /* fa-circle-info */
    font-family: "Font Awesome 6 Free", "Font Awesome 6 Pro", "FontAwesome";
    font-weight: 900;
    display: block;
    font-size: 18px;
    margin-bottom: 4px;
    color: color-mix(in srgb, var(--text-color, #222) 25%, transparent);
}

/* Кнопка-переключатель (heatmap и др.) */
.widget-toggle-btn {
    width: 30px;
    height: 30px;
    border-radius: 9px;
    border: 1px solid color-mix(in srgb, var(--input-border, #eaecef) 60%, transparent);
    background: var(--input-bg, #fff);
    color: var(--text-color, #222);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    margin-left: auto;
    flex-shrink: 0;
    transition: all 0.15s ease;
}

.widget-toggle-btn:hover {
    background: var(--widget-accent-soft, rgba(0, 123, 255, 0.14));
    border-color: var(--widget-accent, var(--button-bg));
    color: var(--widget-accent, var(--button-bg));
}

.widget-toggle-btn.is-active {
    background: var(--widget-accent, var(--button-bg));
    color: #fff;
    border-color: var(--widget-accent, var(--button-bg));
}

/* Адаптив для маленьких экранов */
@media (max-width: 480px) {
    .settings-refresh-btn span {
        display: none;
    }
    .settings-refresh-btn {
        padding: 9px 12px;
    }
    .dashboard-hero {
        padding: 14px;
    }
    .dashboard-hero .settings-hero-text h2 {
        font-size: 18px;
    }
}

/* Тёмная тема */
.dark-theme .dashboard-widget {
    border-color: color-mix(in srgb, var(--input-border) 40%, transparent);
}

.dark-theme .dashboard-widget::before {
    opacity: 0.7;
}

.dark-theme .widget-empty::before {
    color: color-mix(in srgb, var(--text-color) 35%, transparent);
}

/* FEATURE (2026-07-04, feature/exploration-progress):
   блок загрузки виджета «Исследование местности» с прогресс-баром
   и процентом. Используется вместо обычного .widget-empty при
   длительной загрузке OSM-данных (Overpass может отвечать до
   90 с для крупных регионов). */
.widget-exploration-loading {
    color: color-mix(in srgb, var(--text-color, #222) 55%, transparent);
    font-size: 12.5px;
    margin: 0;
    padding: 12px 16px 8px 16px;
    text-align: center;
    line-height: 1.4;
}
.widget-exploration-loading-label {
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 4px;
}
.widget-exploration-loading-spinner {
    font-size: 13px;
    line-height: 1;
    color: color-mix(in srgb, var(--widget-accent, #064a53) 90%, transparent);
    animation: widget-exploration-spin 1.05s linear infinite;
    /* fa-arrows-rotate выглядит одинаково при любом числе
       оборотов — добавляем transform-origin на всякий случай. */
    transform-origin: 50% 50%;
}
.widget-exploration-loading-text {
    flex: 0 1 auto;
}
.widget-exploration-loading-pct {
    font-weight: 600;
    color: var(--text-color, #222);
    font-variant-numeric: tabular-nums;
    flex: 0 0 auto;
}
.widget-exploration-loading-dots {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-left: 2px;
    flex: 0 0 auto;
}
.widget-exploration-loading-dots > span {
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--text-color, #222) 55%, transparent);
    display: inline-block;
    animation: widget-exploration-pulse 1.2s ease-in-out infinite;
}
.widget-exploration-loading-dots > span:nth-child(2) {
    animation-delay: 0.18s;
}
.widget-exploration-loading-dots > span:nth-child(3) {
    animation-delay: 0.36s;
}
.widget-exploration-progress {
    height: 4px;
    background: color-mix(in srgb, var(--input-border, #eaecef) 60%, transparent);
    border-radius: 2px;
    overflow: hidden;
    position: relative;
}
.widget-exploration-progress-fill {
    height: 100%;
    background: color-mix(in srgb, var(--widget-accent, #064a53) 80%, transparent);
    transition: width 280ms ease-out;
    position: relative;
    overflow: hidden;
}
.widget-exploration-progress-shimmer {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 35%;
    left: -35%;
    background: linear-gradient(
        90deg,
        transparent 0%,
        color-mix(in srgb, #ffffff 65%, transparent) 50%,
        transparent 100%
    );
    animation: widget-exploration-shimmer 1.4s linear infinite;
    pointer-events: none;
}
/* Если прогресс-бар 0% — заливки нет, и shimmer некуда ставить;
   оставляем анимацию только если fill > 0. */
.widget-exploration-progress-fill[style*="width:0%"] .widget-exploration-progress-shimmer,
.widget-exploration-progress-fill[style*="width: 0%"] .widget-exploration-progress-shimmer {
    display: none;
}
.dark-theme .widget-exploration-loading {
    color: color-mix(in srgb, var(--text-color) 65%, transparent);
}
.dark-theme .widget-exploration-progress {
    background: color-mix(in srgb, var(--input-border, #2a2a2a) 80%, transparent);
}
.dark-theme .widget-exploration-progress-shimmer {
    background: linear-gradient(
        90deg,
        transparent 0%,
        color-mix(in srgb, #ffffff 35%, transparent) 50%,
        transparent 100%
    );
}

@keyframes widget-exploration-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}
@keyframes widget-exploration-pulse {
    0%, 60%, 100% {
        transform: translateY(0);
        opacity: 0.45;
    }
    30% {
        transform: translateY(-3px);
        opacity: 1;
    }
}
@keyframes widget-exploration-shimmer {
    0%   { left: -35%; }
    100% { left: 100%; }
}

/* Уважение к пользователям с включённым reduced-motion —
   отключаем все анимации в loading-блоке, чтобы избежать
   дискомфорта (головокружение, тошнота). Прогресс-бар
   продолжает работать, просто без shimmer. */
@media (prefers-reduced-motion: reduce) {
    .widget-exploration-loading-spinner,
    .widget-exploration-loading-dots > span,
    .widget-exploration-progress-shimmer {
        animation: none !important;
    }
    .widget-exploration-loading-spinner {
        opacity: 0.7;
    }
    .widget-exploration-loading-dots > span {
        opacity: 0.6;
    }
}

.dark-theme .widget-toggle-btn {
    background: var(--input-bg, #3a3a3a);
}

@media (max-width: 720px) {
    .dashboard-grid {
        grid-template-columns: 1fr;
    }
}

.widget-list-item {
    padding: 8px 0;
    border-bottom: 1px solid var(--input-border, #eaecef);
    cursor: pointer;
    transition: background 0.15s;
}

.widget-list-item:last-child {
    border-bottom: none;
}

.widget-list-item:hover {
    background: var(--hover-bg, rgba(51, 144, 236, 0.06));
}

.widget-user-card {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.widget-user-line1 {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
}

.widget-user-line2 {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 11px;
    color: var(--text-muted, #888);
    padding-left: 16px;
}

.widget-user-alias {
    font-weight: 500;
}

.widget-user-time {
    color: var(--text-muted, #888);
}

.widget-user-speed {
    color: var(--text-muted, #888);
}

.widget-user-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding-left: 16px;
    margin-top: 2px;
}

.widget-status {
    font-size: 10px;
    width: 12px;
    text-align: center;
}

.widget-status-online {
    color: #43a047;
}

.widget-status-offline {
    color: #e53935;
}

.widget-user-card-offline {
    opacity: 0.75;
}

.widget-user-card-offline .widget-user-alias {
    color: var(--text-muted, #888);
    font-weight: 400;
}

.widget-user-card-offline .widget-user-time,
.widget-user-card-offline .widget-user-speed {
    color: var(--text-muted, #888);
}

.widget-user-card-offline:hover {
    opacity: 0.85;
}

/* ============================================================
 * Виджет «Активные наблюдаемые» — современный карточный дизайн.
 * Стили скоупнуты к .widget-active-users, чтобы не ломать
 * другие места, где используются базовые классы .widget-list-item
 * и .widget-user-card (например, .my-watcher-row).
 * ============================================================ */
.widget-active-users .widget-body {
    margin: 0 -2px;
    padding: 2px;
}

.widget-active-users .widget-list-item {
    position: relative;
    padding: 0;
    margin: 0 0 8px 0;
    border: 0;
    background: transparent;
    cursor: pointer;
    transition: transform 0.18s ease;
}

.widget-active-users .widget-list-item:last-child {
    margin-bottom: 0;
}

.widget-active-users .widget-user-card {
    display: grid;
    grid-template-columns: auto 1fr auto;
    grid-template-areas:
        "avatar info trailing"
        "avatar meta  meta";
    column-gap: 12px;
    row-gap: 2px;
    align-items: center;
    padding: 10px 12px 10px 10px;
    background: var(--card-bg, #fff);
    border: 1px solid color-mix(in srgb, var(--input-border, #eaecef) 70%, transparent);
    border-radius: 14px;
    box-shadow:
        0 1px 0 color-mix(in srgb, var(--widget-accent, #10b981) 0%, transparent),
        0 1px 2px color-mix(in srgb, var(--card-shadow, rgba(0,0,0,0.04)) 80%, transparent);
    transition:
        transform 0.2s cubic-bezier(.2,.8,.2,1),
        box-shadow 0.2s ease,
        border-color 0.2s ease,
        background 0.2s ease;
    overflow: hidden;
}

.widget-active-users .widget-user-card::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 3px;
    background: transparent;
    border-radius: 14px 0 0 14px;
    transition: background 0.2s ease;
}

.widget-active-users .widget-list-item:hover .widget-user-card {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--widget-accent, #10b981) 35%, var(--input-border, #eaecef));
    box-shadow:
        0 1px 0 color-mix(in srgb, var(--widget-accent, #10b981) 8%, transparent),
        0 6px 18px color-mix(in srgb, var(--card-shadow, rgba(0,0,0,0.06)) 90%, transparent);
}

.widget-active-users .widget-list-item:active .widget-user-card {
    transform: translateY(0);
    box-shadow:
        0 1px 2px color-mix(in srgb, var(--card-shadow, rgba(0,0,0,0.04)) 80%, transparent);
}

/* Аватар с кольцом статуса */
.widget-active-users .widget-user-avatar {
    grid-area: avatar;
    position: relative;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 600;
    font-size: 14px;
    letter-spacing: 0.2px;
    flex-shrink: 0;
    background: linear-gradient(135deg, #94a3b8 0%, #64748b 100%);
    box-shadow:
        0 0 0 2px var(--card-bg, #fff),
        0 0 0 3px color-mix(in srgb, var(--input-border, #eaecef) 80%, transparent);
    user-select: none;
    transition: box-shadow 0.2s ease, transform 0.2s ease;
}

.widget-active-users .widget-user-avatar::after {
    content: "";
    position: absolute;
    right: -2px;
    bottom: -2px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: #94a3b8;
    border: 2px solid var(--card-bg, #fff);
    box-sizing: border-box;
    transition: background 0.2s ease;
}

.widget-active-users .widget-user-card:not(.widget-user-card-offline) .widget-user-avatar {
    background: linear-gradient(135deg, #34d399 0%, #059669 100%);
    box-shadow:
        0 0 0 2px var(--card-bg, #fff),
        0 0 0 3px color-mix(in srgb, #10b981 40%, transparent),
        0 4px 10px color-mix(in srgb, #10b981 22%, transparent);
}

.widget-active-users .widget-user-card:not(.widget-user-card-offline) .widget-user-avatar::after {
    background: #10b981;
    animation: wau-pulse 1.8s ease-in-out infinite;
}

.widget-active-users .widget-list-item:hover .widget-user-avatar {
    transform: scale(1.04);
}

/* Информационный блок (имя + мета) */
.widget-active-users .widget-user-info {
    grid-area: info;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 6px;
    line-height: 1.25;
}

.widget-active-users .widget-user-meta {
    grid-area: meta;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 11.5px;
    color: color-mix(in srgb, var(--text-color, #222) 55%, transparent);
    padding-left: 0;
    line-height: 1.2;
}

.widget-active-users .widget-user-meta .widget-user-speed {
    color: color-mix(in srgb, var(--widget-accent, #10b981) 90%, transparent);
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: 3px;
}

.widget-active-users .widget-user-alias {
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text-color, #222);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
    flex: 1 1 auto;
    letter-spacing: -0.1px;
}

/* Стрелка направления рядом с именем */
.widget-active-users .widget-bearing,
.widget-active-users .widget-user-bearing {
    color: color-mix(in srgb, var(--widget-accent, #10b981) 85%, transparent);
    font-size: 12px;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--widget-accent, #10b981) 12%, transparent);
    filter: none;
}

/* Правая колонка (бэйджи/метка времени) */
.widget-active-users .widget-user-trailing {
    grid-area: trailing;
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    flex-shrink: 0;
    font-size: 11px;
    color: color-mix(in srgb, var(--text-color, #222) 55%, transparent);
}

.widget-active-users .widget-user-card:not(.widget-user-card-offline) .widget-user-trailing {
    color: #059669;
    font-weight: 600;
}

.widget-active-users .widget-user-trailing .fa-circle {
    margin-right: 4px;
    font-size: 7px;
    vertical-align: middle;
}

/* Бэйджи (зона / маршрут) */
.widget-active-users .widget-user-badges {
    grid-column: 2 / -1;
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 2px;
    padding-left: 0;
}

.widget-active-users .widget-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 10.5px;
    font-weight: 600;
    line-height: 1.4;
    letter-spacing: 0.1px;
    border: 1px solid transparent;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.widget-active-users .widget-badge-zone {
    background: color-mix(in srgb, #10b981 14%, transparent);
    color: #047857;
    border-color: color-mix(in srgb, #10b981 28%, transparent);
}

.widget-active-users .widget-badge-route {
    background: color-mix(in srgb, #6366f1 14%, transparent);
    color: #4338ca;
    border-color: color-mix(in srgb, #6366f1 28%, transparent);
}

.dark-theme .widget-active-users .widget-badge-zone {
    background: color-mix(in srgb, #10b981 22%, transparent);
    color: #6ee7b7;
    border-color: color-mix(in srgb, #10b981 40%, transparent);
}

.dark-theme .widget-active-users .widget-badge-route {
    background: color-mix(in srgb, #818cf8 20%, transparent);
    color: #c7d2fe;
    border-color: color-mix(in srgb, #818cf8 40%, transparent);
}

/* Оффлайн-вариант: приглушаем карточку */
.widget-active-users .widget-user-card-offline .widget-user-avatar {
    background: linear-gradient(135deg, #cbd5e1 0%, #94a3b8 100%);
    box-shadow:
        0 0 0 2px var(--card-bg, #fff),
        0 0 0 3px color-mix(in srgb, var(--input-border, #eaecef) 80%, transparent);
}

.widget-active-users .widget-user-card-offline .widget-user-avatar::after {
    background: #94a3b8;
    animation: none;
}

.widget-active-users .widget-user-card-offline::before {
    background: color-mix(in srgb, #94a3b8 50%, transparent);
    opacity: 0.6;
}

.widget-active-users .widget-user-card-offline .widget-user-alias {
    color: color-mix(in srgb, var(--text-color, #222) 65%, transparent);
    font-weight: 500;
}

.widget-active-users .widget-user-card-offline .widget-user-meta,
.widget-active-users .widget-user-card-offline .widget-user-trailing {
    color: color-mix(in srgb, var(--text-color, #222) 45%, transparent);
    font-weight: 400;
}

.widget-active-users .widget-user-card-offline .widget-user-time {
    color: inherit;
}

/* Анимация пульсации точки статуса (только для онлайн) */
@keyframes wau-pulse {
    0%, 100% {
        box-shadow:
            0 0 0 2px var(--card-bg, #fff),
            0 0 0 0 color-mix(in srgb, #10b981 50%, transparent);
    }
    50% {
        box-shadow:
            0 0 0 2px var(--card-bg, #fff),
            0 0 0 5px color-mix(in srgb, #10b981 0%, transparent);
    }
}

/* Скрываем старые мелкие элементы статуса, теперь всё в аватаре */
.widget-active-users .widget-status {
    display: none;
}

/* Уменьшенный размер карточки на узких экранах */
@media (max-width: 480px) {
    .widget-active-users .widget-user-card {
        padding: 8px 10px;
        column-gap: 10px;
    }
    .widget-active-users .widget-user-avatar {
        width: 34px;
        height: 34px;
        font-size: 13px;
    }
    .widget-active-users .widget-user-alias {
        font-size: 13px;
    }
    .widget-active-users .widget-user-meta {
        font-size: 11px;
    }
}

/* Тёмная тема — карточка */
.dark-theme .widget-active-users .widget-user-card {
    background: color-mix(in srgb, var(--card-bg, #1f2937) 92%, #000 8%);
    border-color: color-mix(in srgb, var(--input-border) 40%, transparent);
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.25);
}

.dark-theme .widget-active-users .widget-user-card:not(.widget-user-card-offline) {
    box-shadow:
        0 0 0 1px color-mix(in srgb, #10b981 18%, transparent) inset,
        0 4px 14px color-mix(in srgb, #10b981 10%, transparent);
}

.dark-theme .widget-active-users .widget-list-item:hover .widget-user-card:not(.widget-user-card-offline) {
    box-shadow:
        0 0 0 1px color-mix(in srgb, #10b981 28%, transparent) inset,
        0 8px 22px color-mix(in srgb, #10b981 14%, transparent);
}

.dark-theme .widget-active-users .widget-user-alias {
    color: var(--text-color, #e5e7eb);
}

.dark-theme .widget-active-users .widget-user-card-offline .widget-user-alias {
    color: color-mix(in srgb, var(--text-color, #e5e7eb) 65%, transparent);
}

/* ============================================================
 * Виджет «Мои наблюдатели» в разделе «Настройки» miniapp.
 * ============================================================ */
.settings-card-body {
    padding: 8px 16px 16px 16px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.my-watchers-empty {
    margin: 0;
    padding: 14px 4px;
    color: var(--text-muted, #888);
    font-size: 13px;
    text-align: center;
}

.my-watchers-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    /*
     * Если наблюдателей больше четырёх, контейнер не должен
     * растягивать виджет на всю высоту списка — включаем
     * вертикальную прокрутку. Высота одной строки ~60px
     * (аватар 40px + padding 10px сверху/снизу) плюс gap 8px
     * между строками: 4 * 60 + 3 * 8 = 264px.
     */
    max-height: 264px;
    overflow-y: auto;
    overscroll-behavior: contain;
    /* Firefox */
    scrollbar-width: thin;
    scrollbar-color: var(--input-border, #c0c0c0) transparent;
    -webkit-overflow-scrolling: touch;
}

/* Webkit-скроллбар (Telegram WebApp на iOS/Android). */
.my-watchers-list::-webkit-scrollbar {
    width: 6px;
}

.my-watchers-list::-webkit-scrollbar-track {
    background: transparent;
}

.my-watchers-list::-webkit-scrollbar-thumb {
    background: var(--input-border, #c0c0c0);
    border-radius: 3px;
}

.my-watchers-list::-webkit-scrollbar-thumb:hover {
    background: var(--text-muted, #888);
}

.my-watcher-row {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    background: var(--card-bg, #fff);
    border: 1px solid var(--input-border, #e0e0e0);
    border-radius: 12px;
    transition: border-color 0.15s, transform 0.15s;
}

/*
 * В карточке наблюдателя мы также используем общий класс
 * .widget-user-card (для единого оформления с другими виджетами),
 * но он задаёт flex-direction: column. Переопределяем здесь
 * с более специфичным селектором, чтобы карточка оставалась
 * в одну строку.
 */
.my-watcher-row.widget-user-card {
    flex-direction: row;
}

.my-watcher-row:hover {
    border-color: var(--hover-border, #b0b0b0);
}

.my-watcher-row.my-watcher-removing {
    opacity: 0.4;
    transform: scale(0.98);
}

.my-watcher-avatar {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    flex-shrink: 0;
    background: linear-gradient(135deg, #06b6d4 0%, #2563eb 100%);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 15px;
    overflow: hidden;
    user-select: none;
}

.my-watcher-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.my-watcher-info {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: baseline;
    gap: 8px;
    overflow: hidden;
}

.my-watcher-name {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-color);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 0 1 auto;
}

.my-watcher-id-inline {
    font-size: 11px;
    color: var(--text-muted, #888);
    white-space: nowrap;
    flex: 0 0 auto;
}

.my-watcher-remove-btn {
    flex-shrink: 0;
    margin-left: auto;
    background: transparent;
    border: 1px solid var(--input-border, #e0e0e0);
    color: var(--text-color);
    width: 30px;
    height: 30px;
    border-radius: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.my-watcher-remove-btn:hover {
    background: rgba(239, 68, 68, 0.1);
    border-color: #ef4444;
    color: #ef4444;
}

.my-watcher-remove-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.my-watcher-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 4px 2px 4px;
    font-size: 12px;
    color: var(--text-muted, #888);
}

.my-watchers-error {
    color: #ef4444;
    font-size: 13px;
    margin: 0;
    padding: 8px 4px;
}

.widget-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 10px;
    font-weight: 500;
    white-space: nowrap;
    max-width: 180px;
    overflow: hidden;
    text-overflow: ellipsis;
}

.widget-badge-zone {
    background: rgba(51, 144, 236, 0.12);
    color: #1976d2;
}
body.dark-theme .widget-badge-zone {
    background: rgb(79 210 231 / 20%);
    color: #44c8df;
}

.widget-badge-route {
    background: rgba(0, 150, 136, 0.12);
    color: #00897b;
}
body.dark-theme .widget-badge-route {
    background: rgba(0, 150, 136, 0.20);
    color: #4dd0c1;
}

.widget-badge-active {
    background: rgba(67, 160, 71, 0.12);
    color: #2e7d32;
}

.widget-badge-inactive {
    background: rgba(0, 0, 0, 0.06);
    color: #757575;
}

.widget-badge-new {
    background: #e53935;
    color: #fff;
}

.widget-bearing {
    font-size: 12px;
    color: var(--text-muted, #888);
}

.widget-event-item {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
}

.widget-event-type {
    padding: 2px 6px;
    border-radius: 6px;
    font-size: 9px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    white-space: nowrap;
    line-height: 1.3;
}

.widget-event-enter {
    background: rgba(67, 160, 71, 0.15);
    color: #2e7d32;
}

.widget-event-exit {
    background: rgba(229, 57, 53, 0.15);
    color: #c62828;
}

.widget-event-route-exit {
    background: rgba(229, 57, 53, 0.15);
    color: #c62828;
}

.widget-event-return {
    background: rgba(13, 123, 255, 0.15);
    color: #0d7bff;
}

.widget-event-other {
    background: rgba(0, 0, 0, 0.06);
    color: #555;
}

.widget-event-alias {
    flex: 1;
    font-weight: 500;
}

.widget-event-time {
    color: var(--text-muted, #888);
    font-size: 11px;
    white-space: nowrap;
}

.widget-summary-line {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 0;
    font-size: 12px;
}

.widget-headline {
    font-size: 11px;
    line-height: 1.35;
    color: var(--text-muted, #888);
    margin: 0 0 6px 0;
}

.widget-meta {
    color: var(--text-muted, #888);
    font-size: 11px;
    font-weight: normal;
    margin-left: 2px;
}
body.dark-theme .widget-meta {
    color: var(--text-muted, #a0a0a0);
}

.widget-badge-self {
    background: var(--button-bg, #3390ec);
    color: #fff;
    font-size: 10px;
    padding: 1px 6px;
    border-radius: 8px;
    margin-left: 4px;
}

.widget-summary-label {
    color: var(--text-muted, #888);
}

.widget-summary-value {
    font-weight: 600;
}

/* Стиль CTA-кнопки под списком виджета «Каналы» —
 * совпадает со структурой .widget-stat-cta (градиент,
 * тень, hover/active), но фон жёстко задан как #06b6d4
 * (cyan-500), чтобы кнопка визуально оставалась
 * в циановой палитре виджета вне зависимости от того,
 * в каком tint-родителе она окажется. */
.widget-link-btn {
    margin-top: 10px;
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 12px;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.2;
    color: #fff;
    background: linear-gradient(135deg,
        #06b6d4 0%,
        color-mix(in srgb, #06b6d4 60%, #0f172a) 100%);
    border: 1px solid color-mix(in srgb, #06b6d4 50%, transparent);
    border-radius: 10px;
    cursor: pointer;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.18),
        0 2px 8px -2px color-mix(in srgb, #06b6d4 45%, transparent);
    transition:
        transform 0.15s ease,
        box-shadow 0.18s ease,
        filter 0.18s ease;
}

.widget-link-btn:hover {
    transform: translateY(-1px);
    filter: brightness(1.05);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.22),
        0 6px 16px -4px color-mix(in srgb, #06b6d4 55%, transparent);
}

.widget-link-btn:active {
    transform: translateY(0);
    filter: brightness(0.97);
}

.widget-link-btn i {
    font-size: 11px;
    transition: transform 0.18s ease;
}

.widget-link-btn:hover i {
    transform: translateX(2px);
}

.widget-izone-line1,
.widget-trip-line1 {
    font-size: 13px;
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 6px;
}

.widget-izone-line2,
.widget-trip-line2 {
    font-size: 11px;
    color: var(--text-muted, #888);
    margin-top: 2px;
}

.widget-dot {
    color: var(--text-muted, #bdbdbd);
    margin: 0 2px;
}

/* Подзаголовки внутри виджета (например, разделы «Зоны интереса» /
   «Путеводители» в виджете «Подписки»). */
.widget-subsection-title {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted, #888);
    margin: 6px 0 4px 0;
    padding: 6px 0 4px 0;
    border-bottom: 1px solid var(--input-border, #eaecef);
}
.widget-subsection-title:first-child {
    padding-top: 0;
    margin-top: 0;
}

.storage-row {
    padding: 8px 0;
    border-bottom: 1px solid var(--input-border, #eaecef);
}

.storage-row:last-child {
    border-bottom: none;
}

.storage-line1 {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 12px;
    margin-bottom: 4px;
}

.storage-label {
    font-weight: 500;
}

/* FEATURE feature/public-route-frozen-points:
   Стиль строки «заморожено N точек» под прогресс-баром.
   Неброский, дискретный цвет и курсор-help, чтобы было видно,
   что это пояснение, а не ошибка. */
.storage-frozen-line {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    color: #0288d1;
    margin-top: 6px;
    padding: 4px 6px;
    background-color: rgba(2, 136, 209, 0.08);
    border-radius: 4px;
    cursor: help;
}

.storage-frozen-icon {
    font-size: 12px;
    line-height: 1;
}

.storage-frozen-text {
    line-height: 1.4;
}

.dark-theme .storage-frozen-line {
    color: #4fc3f7;
    background-color: rgba(79, 195, 247, 0.10);
}

.storage-value {
    color: var(--text-muted, #888);
    font-size: 11px;
}

.storage-bar {
    position: relative;
    height: 6px;
    background: rgba(0, 0, 0, 0.06);
    border-radius: 3px;
    overflow: hidden;
}

.storage-bar-fill {
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    border-radius: 3px;
    transition: width 0.3s;
}

/* FEATURE feature/public-route-frozen-points:
   Голубой сегмент прогресс-бара — замороженные точки (используются
   в активной публичной ссылке на маршрут и защищены от удаления).
   Расположен сразу после незамороженной части и до свободного
   остатка лимита. */
.storage-bar-fill-frozen {
    position: absolute;
    top: 0;
    height: 100%;
    background: linear-gradient(
        90deg,
        #4fc3f7 0%,
        #29b6f6 100%
    );
    border-radius: 0 3px 3px 0;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.25);
    transition: left 0.3s, width 0.3s;
}

.dark-theme .storage-bar-fill-frozen {
    background: linear-gradient(
        90deg,
        #29b6f6 0%,
        #039be5 100%
    );
}

.widget-mini-map .widget-body {
    height: 180px;
    padding: 0;
}

/* Кликабельный виджет мини-карты */
.dashboard-widget.widget-mini-map .widget-body-clickable {
    position: relative;
    cursor: zoom-in;
    transition: box-shadow 160ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.dashboard-widget.widget-mini-map .widget-body-clickable:hover {
    box-shadow: inset 0 0 0 2px rgba(20, 184, 166, 0.45);
}

.dashboard-widget.widget-mini-map .widget-body-clickable:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px rgba(20, 184, 166, 0.65);
}

.widget-mini-map-body .widget-empty {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.widget-balance {
    min-height: 0;
    overflow: visible;
    margin-bottom: 16px;
}

.widget-balance .widget-body {
    flex: 0 0 auto;
    max-height: none;
    overflow: visible;
}

#dashMiniMapContainer {
    width: 100%;
    height: 100%;
    min-height: 180px;
    border-radius: 8px;
    overflow: hidden;
}

.dashboard-mini-map-tooltip {
    background: rgba(33, 37, 41, 0);
    color: #fff;
    border: none;
    border-radius: 6px;
    padding: 12px 8px;
    font-size: 12px;
    font-weight: 500;
    line-height: 1.3;
    box-shadow: none;
    white-space: nowrap;
    pointer-events: none;
}

.dashboard-mini-map-tooltip::before {
    border-top-color: rgba(33, 37, 41, 0);
}

/* MapLibre popup used inside miniapp "Сводка" section */
.maplibregl-popup-content {
    background: #313539;
    border-radius: 3px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .1);
    padding: 5px 10px;
    pointer-events: auto;
    position: relative;
}

.maplibregl-popup-anchor-top .maplibregl-popup-tip {
    align-self: center;
    border-bottom-color: #3390ec00;
    border-top: none;
    display: none !important;
}

.maplibregl-popup-anchor-bottom .maplibregl-popup-tip {
    align-self: center;
    border-bottom: none;
    border-top-color: #ffffff00;
    display: none !important;
}

/* Полностью скрываем «хвостик» (tip) у всех MapLibre-попапов на trip.html. */
.maplibregl-popup .maplibregl-popup-tip,
.maplibregl-popup-tip {
    display: none !important;
}

.dashboard-widget .loading-msg {
    color: var(--text-muted, #888);
    font-size: 12px;
    padding: 6px 0;
}

/* === Timeline-стиль для ленты событий дашборда === */
#dashboardFeedList .feed-timeline {
    --rail-x: 62px;
    position: relative;
    margin: 4px 0 4px 0;
    padding: 4px 0 4px 0;
}

#dashboardFeedList .feed-timeline::before {
    content: '';
    position: absolute;
    left: var(--rail-x);
    top: 14px;
    bottom: 14px;
    width: 2px;
    border-radius: 2px;
    background: linear-gradient(
        to bottom,
        transparent 0,
        var(--input-border, #e5e7eb) 12px,
        var(--input-border, #e5e7eb) calc(100% - 12px),
        transparent 100%
    );
}

#dashboardFeedList .feed-event {
    --feed-accent: #6b7280;
    --feed-accent-bg: rgba(107, 114, 128, 0.12);
    --feed-accent-soft: rgba(107, 114, 128, 0.06);
    position: relative;
    display: grid;
    grid-template-columns: var(--rail-x) 1fr;
    align-items: flex-start;
    column-gap: 14px;
    padding: 8px 10px 8px 4px;
    border-radius: 10px;
    transition: background-color 160ms ease;
}

#dashboardFeedList .feed-event + .feed-event {
    margin-top: 2px;
}

#dashboardFeedList .feed-event:hover {
    background: var(--feed-accent-soft);
}

#dashboardFeedList .feed-event:hover .feed-event__dot {
    transform: translateX(-50%) scale(1.08);
    box-shadow: 0 0 0 5px color-mix(in srgb, var(--feed-accent) 18%, transparent);
}

#dashboardFeedList .feed-event--enter {
    --feed-accent: #16a34a;
    --feed-accent-bg: rgba(22, 163, 74, 0.12);
    --feed-accent-soft: rgba(22, 163, 74, 0.06);
}

#dashboardFeedList .feed-event--exit {
    --feed-accent: #dc2626;
    --feed-accent-bg: rgba(220, 38, 38, 0.12);
    --feed-accent-soft: rgba(220, 38, 38, 0.06);
}

#dashboardFeedList .feed-event--route-exit {
    --feed-accent: #ea580c;
    --feed-accent-bg: rgba(234, 88, 12, 0.12);
    --feed-accent-soft: rgba(234, 88, 12, 0.06);
}

#dashboardFeedList .feed-event--return {
    --feed-accent: #2563eb;
    --feed-accent-bg: rgba(37, 99, 235, 0.12);
    --feed-accent-soft: rgba(37, 99, 235, 0.06);
}

#dashboardFeedList .feed-event--other {
    --feed-accent: #6b7280;
    --feed-accent-bg: rgba(107, 114, 128, 0.12);
    --feed-accent-soft: rgba(107, 114, 128, 0.06);
}

#dashboardFeedList .feed-event__rail-col {
    position: relative;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: 4px;
}

#dashboardFeedList .feed-event__dot {
    position: relative;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--input-bg, #ffffff);
    border: 2px solid var(--feed-accent);
    color: var(--feed-accent);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    line-height: 1;
    z-index: 1;
    transition: transform 160ms ease, box-shadow 160ms ease;
    box-shadow: 0 0 0 4px var(--input-bg, #ffffff);
    cursor: help;
}

#dashboardFeedList .feed-event__body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 1px 0 6px 0;
}

#dashboardFeedList .feed-event__header {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    line-height: 1.2;
}

#dashboardFeedList .feed-event__badge {
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 9.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    line-height: 1.4;
    white-space: nowrap;
    background: var(--feed-accent-bg);
    color: var(--feed-accent);
}

#dashboardFeedList .feed-event__name {
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text-color, #222);
}

#dashboardFeedList .feed-event__time-abs {
    margin-left: auto;
    font-size: 11px;
    color: var(--text-muted, #888);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

#dashboardFeedList .feed-event__details {
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-color-secondary, #555);
    word-break: break-word;
    white-space: normal;
}

#dashboardFeedList .feed-event__details code {
    background: rgba(127, 127, 127, 0.14);
    border-radius: 4px;
    padding: 0 4px;
    font-size: 0.92em;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

#dashboardFeedList .feed-event__details a {
    color: var(--accent-color, #2563eb);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* Тёмная тема */
.dark-theme #dashboardFeedList .feed-timeline::before {
    background: linear-gradient(
        to bottom,
        transparent 0,
        #2a3441 12px,
        #2a3441 calc(100% - 12px),
        transparent 100%
    );
}

.dark-theme #dashboardFeedList .feed-event__dot {
    background: var(--input-bg, #1f2937);
    box-shadow: 0 0 0 4px var(--input-bg, #1f2937);
}

.dark-theme #dashboardFeedList .feed-event__name {
    color: var(--text-color, #f3f4f6);
}

.dark-theme #dashboardFeedList .feed-event__details {
    color: color-mix(in srgb, var(--text-color, #f3f4f6) 75%, transparent);
}

.dark-theme #dashboardFeedList .feed-event__details code {
    background: rgba(255, 255, 255, 0.08);
}

.dark-theme #dashboardFeedList .feed-event:hover .feed-event__dot {
    box-shadow: 0 0 0 5px color-mix(in srgb, var(--feed-accent) 22%, transparent);
}

/* Адаптив: на узких экранах сжимаем колонку рельса */
@media (max-width: 480px) {
    #dashboardFeedList .feed-timeline {
        --rail-x: 48px;
    }
    #dashboardFeedList .feed-event {
        column-gap: 10px;
    }
    #dashboardFeedList .feed-event__dot {
        width: 22px;
        height: 22px;
        font-size: 10px;
    }
    #dashboardFeedList .feed-event__time-abs {
        font-size: 10px;
    }
}

.dashboard-widget-priority { order: -1; }
.balance-top {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin-bottom: 4px;
}
.balance-amount {
    font-size: 24px;
    font-weight: 700;
}

.balance-amount-positive { color: inherit; }

.balance-amount-zero    { color: #c62828; }
.dark-theme .balance-amount-zero { color: #ff6b6b; }
.balance-currency i {
    color: #fb8c00;
    font-size: 14px;
}
.balance-eta {
    font-size: 11px;
    color: var(--text-muted, #888);
    margin-bottom: 8px;
}
.balance-warning {
    background: rgba(229, 57, 53, 0.10);
    color: inherit;
    border-radius: 8px;
    padding: 6px 8px;
    font-size: 11px;
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    gap: 6px;
}
.balance-section {
    margin-top: 8px;
}
.balance-section-title {
    font-size: 10px;
    text-transform: uppercase;
    color: var(--text-muted, #888);
    margin-bottom: 4px;
    letter-spacing: 0.3px;
}
.balance-service-row {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    padding: 3px 0;
}
.balance-service-on      { color: inherit; }
.balance-service-off     { color: var(--text-muted, #888); }
.balance-service-disabled{ color: inherit; }

.widget-channels .widget-body { padding-top: 4px; }

/* ============================================================
 * Виджет «Каналы уведомлений» переиспользует визуальный язык
 * карточек из виджета «Истекающие публикации»
 * (widget-expiring-list / widget-expiring-item).
 *
 * Акцент --wex-stripe наследуется от родительского
 * .widget-tint-cyan (см. .widget-tint-cyan { --widget-accent: #06b6d4 }).
 * Здесь лишь задаются варианты статусного чипа справа и
 * строка ошибки под заголовком канала.
 * ============================================================ */

/* Статусный чип (правый столбец карточки канала).
 * Базовый вид совпадает с widget-expiring-countdown,
 * но с одной крупной строкой и без лейбла "истекает". */
.widget-expiring-countdown.widget-expiring-status-active,
.widget-expiring-countdown.widget-expiring-status-inactive {
    min-width: 64px;
    padding: 4px 10px;
}
.widget-expiring-countdown.widget-expiring-status-active {
    background: var(--wex-stripe-soft);
    color: var(--wex-stripe);
    border-color: color-mix(in srgb, var(--wex-stripe) 22%, transparent);
}
.widget-expiring-countdown.widget-expiring-status-inactive {
    background: rgba(148, 163, 184, 0.14);
    color: var(--text-muted, #64748b);
    border-color: rgba(148, 163, 184, 0.28);
}

/* Небольшая строка с текстом последней ошибки под именем канала. */
.widget-expiring-error {
    display: block;
    margin-top: 2px;
    font-size: 11px;
    line-height: 1.25;
    color: #c62828;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dark-theme .widget-expiring-error {
    color: #fca5a5;
}

/* Метаданные под заголовком карточки (просмотры, км и т. п.).
 * Тот же тонкий приглушённый стиль, что и widget-expiring-error,
 * но без красного цвета. */
.widget-expiring-meta {
    display: block;
    margin-top: 2px;
    font-size: 11px;
    line-height: 1.25;
    color: var(--text-muted, #64748b);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.widget-expiring-meta .widget-dot {
    margin: 0 2px;
    color: var(--text-muted, #bdbdbd);
}

/* Блок с маршрутами внутри карточки состояния маршрутов.
 * Сохраняем визуальный ряд в виде чипов widget-badge-route,
 * но даём ему перенос на новую строку под основной информацией. */
.widget-expiring-routes {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 6px;
    margin-top: 4px;
}

/* Дополнительные варианты статусного чипа (для izone/guide/izone-subs).
 * Базовый стиль — у widget-expiring-countdown, ниже — цветовые
 * варианты для конкретных статусов. */
.widget-expiring-countdown.widget-expiring-status-active {
    background: var(--wex-stripe-soft);
    color: var(--wex-stripe);
    border-color: color-mix(in srgb, var(--wex-stripe) 22%, transparent);
}
.widget-expiring-countdown.widget-expiring-status-inactive {
    background: rgba(148, 163, 184, 0.14);
    color: var(--text-muted, #64748b);
    border-color: rgba(148, 163, 184, 0.28);
}
.widget-expiring-countdown.widget-expiring-status-expired {
    background: rgba(239, 68, 68, 0.14);
    color: #c62828;
    border-color: rgba(239, 68, 68, 0.32);
}
.dark-theme .widget-expiring-countdown.widget-expiring-status-expired {
    color: #fca5a5;
}
.widget-expiring-countdown.widget-expiring-status-new {
    background: #e53935;
    color: #fff;
    border-color: #c62828;
}

/* ============================================================
 * Виджет «Сработавшие уведомления» — карточки событий
 * используют ту же базовую структуру widget-expiring-item,
 * но иконка и лейбл типа подсвечиваются цветом, отражающим
 * категорию события (вход/выход/возврат/маршрут).
 * ============================================================ */

/* Цветной лейбл типа события (под именем пользователя).
 * Компактный inline-tag с тоном, согласованным с иконкой. */
.widget-event-type-label {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 8px;
    font-weight: 600;
    line-height: 1.4;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    margin-top: 2px;
    width: fit-content;
    background: rgba(15, 23, 42, 0.06);
    color: #475569;
}
.dark-theme .widget-event-type-label {
    background: rgba(255, 255, 255, 0.08);
    color: #cbd5e1;
}
.widget-event-type-label.widget-event-type-enter {
    background: rgba(67, 160, 71, 0.14);
    color: #2e7d32;
}
.widget-event-type-label.widget-event-type-exit {
    background: rgba(229, 57, 53, 0.14);
    color: #c62828;
}
.widget-event-type-label.widget-event-type-route-exit {
    background: rgba(229, 57, 53, 0.14);
    color: #c62828;
}
.widget-event-type-label.widget-event-type-return {
    background: rgba(13, 123, 255, 0.14);
    color: #0d7bff;
}
.widget-event-type-label.widget-event-type-other {
    background: rgba(15, 23, 42, 0.06);
    color: #475569;
}
.dark-theme .widget-event-type-label.widget-event-type-enter {
    color: #81c784;
}
.dark-theme .widget-event-type-label.widget-event-type-exit,
.dark-theme .widget-event-type-label.widget-event-type-route-exit {
    color: #fca5a5;
}
.dark-theme .widget-event-type-label.widget-event-type-return {
    color: #7ab8ff;
}

/* Цветной фон иконки события. Перекрываем --wex-stripe
 * (который по умолчанию берётся из --widget-accent родительского
 * .widget-tint-slate) на категорию события. */
.widget-expiring-icon.widget-event-icon {
    --wex-stripe: #94a3b8;
    --wex-stripe-soft: rgba(148, 163, 184, 0.18);
}
.widget-expiring-icon.widget-event-icon-enter {
    --wex-stripe: #43a047;
    --wex-stripe-soft: rgba(67, 160, 71, 0.18);
}
.widget-expiring-icon.widget-event-icon-exit,
.widget-expiring-icon.widget-event-icon-route-exit {
    --wex-stripe: #94a3b8;
    --wex-stripe-soft: rgba(148, 163, 184, 0.18);
}
.widget-expiring-icon.widget-event-icon-return {
    --wex-stripe: #0d7bff;
    --wex-stripe-soft: rgba(13, 123, 255, 0.18);
}

/* Внутри виджета событий .widget-events переопределяем красные
 * акценты категорий exit / route-exit на нейтральную slate-палитру,
 * согласованную с .widget-tint-slate (#94a3b8 / #64748b) родительского
 * блока «Активные маршруты». Это даёт визуально единый стиль
 * дашборда: события больше не «кричат» красным, а читаются в
 * той же спокойной серой гамме, что и блок маршрутов. */
.dashboard-widget.widget-events .widget-event-item-exit,
.dashboard-widget.widget-events .widget-event-item-route-exit,
.dashboard-widget.widget-events .widget-event-icon-exit,
.dashboard-widget.widget-events .widget-event-icon-route-exit {
    --wex-stripe: #94a3b8;
    --wex-stripe-soft: rgba(148, 163, 184, 0.18);
}
.dashboard-widget.widget-events .widget-event-type-exit,
.dashboard-widget.widget-events .widget-event-type-route-exit {
    background: rgba(148, 163, 184, 0.14);
    color: #64748b;
}
.dark-theme .dashboard-widget.widget-events .widget-event-type-exit,
.dark-theme .dashboard-widget.widget-events .widget-event-type-route-exit {
    color: #cbd5e1;
}

/* Внутри виджета событий .widget-events переопределяем синие
 * акценты категории return на изумрудную палитру,
 * согласованную с .widget-tint-emerald (#059669) блока
 * «Мои путеводители». Это распространяется на:
 *   - фон карточки (через --wex-stripe-soft на уровне item),
 *   - цвет иконки (через --wex-stripe),
 *   - цвет каундауна (наследует --wex-stripe),
 *   - цвет лейбла типа события. */
.dashboard-widget.widget-events .widget-event-item-return,
.dashboard-widget.widget-events .widget-event-icon-return {
    --wex-stripe: #059669;
    --wex-stripe-soft: rgba(5, 150, 105, 0.18);
}
.dashboard-widget.widget-events .widget-event-type-return {
    background: rgba(5, 150, 105, 0.14);
    color: #047857;
}
.dark-theme .dashboard-widget.widget-events .widget-event-type-return {
    color: #6ee7b7;
}

/* Правый чип с возрастом события — оставляем базовый стиль
 * widget-expiring-countdown, но уменьшаем min-width, чтобы
 * короткие значения («5 мин») хорошо смотрелись. */
.widget-event-countdown {
    min-width: 60px;
}

/* ============================================================
 * Виджет «Истекающие публикации» — современный дизайн карточек
 * ============================================================
 * Каждая публикация — компактная карточка с цветной вертикальной
 * полосой слева (задаёт urgency-бакет), круглой иконкой типа
 * публикации, заголовком, чипом-каундауном справа.
 *
 * Бакеты (по убыванию срочности):
 *   critical — менее 6 часов   (красный)
 *   warning  — менее 24 часов  (оранжевый)
 *   soon     — менее 3 дней    (синий)
 *   far      — более 3 дней    (нейтральный)
 */
.widget-expiring-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.widget-expiring-item {
    --wex-radius: 12px;
    --wex-stripe: var(--widget-accent, #f97316);
    --wex-stripe-soft: var(--widget-accent-soft, rgba(249, 115, 22, 0.16));
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px 10px 14px;
    border-radius: var(--wex-radius);
    background:
        linear-gradient(135deg,
            var(--wex-stripe-soft) 0%,
            rgba(255, 255, 255, 0) 60%),
        var(--input-bg, #fff);
    border: 1px solid var(--input-border, #eaecef);
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.04),
        0 4px 12px -6px rgba(15, 23, 42, 0.08);
    cursor: pointer;
    overflow: hidden;
    transition:
        transform 0.18s ease,
        box-shadow 0.18s ease,
        border-color 0.18s ease;
}

.widget-expiring-item::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 4px;
    background: var(--wex-stripe);
    border-top-left-radius: var(--wex-radius);
    border-bottom-left-radius: var(--wex-radius);
}

.widget-expiring-item:hover {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--wex-stripe) 35%, var(--input-border, #eaecef));
    box-shadow:
        0 2px 4px rgba(15, 23, 42, 0.06),
        0 10px 22px -10px color-mix(in srgb, var(--wex-stripe) 45%, transparent);
}

.widget-expiring-item:active {
    transform: translateY(0);
}

/* Бакеты — задают цвет полосы и мягкий акцент фона.
 * .widget-expiring-critical намеренно НЕ переопределяет
 * --wex-stripe / --wex-stripe-soft, чтобы наследовать цвета
 * от дефолтного .widget-expiring-item (то есть от --widget-accent
 * родительского виджета) — визуально не выделяется ярко-красным. */
.widget-expiring-item.widget-expiring-warning {
    --wex-stripe: #f97316;
    --wex-stripe-soft: rgba(249, 115, 22, 0.14);
}
.widget-expiring-item.widget-expiring-soon {
    --wex-stripe: #3b82f6;
    --wex-stripe-soft: rgba(59, 130, 246, 0.12);
}
.widget-expiring-item.widget-expiring-far {
    --wex-stripe: #94a3b8;
    --wex-stripe-soft: rgba(148, 163, 184, 0.10);
}

.widget-expiring-icon {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    color: #fff;
    background: linear-gradient(135deg, var(--wex-stripe) 0%, color-mix(in srgb, var(--wex-stripe) 65%, #0f172a) 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.18),
        0 2px 6px color-mix(in srgb, var(--wex-stripe) 35%, transparent);
}

.widget-expiring-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.widget-expiring-title {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 10px;
    color: var(--text-muted, #64748b);
    line-height: 1.2;
}

.widget-expiring-title-text {
    display: block;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-color, #0f172a);
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.widget-expiring-kind {
    font-size: 10px;
    color: var(--text-muted, #64748b);
    text-transform: uppercase;
    letter-spacing: 0.4px;
    font-weight: 600;
}

.widget-expiring-countdown {
    flex-shrink: 0;
    display: inline-flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    padding: 4px 8px;
    border-radius: 8px;
    background: var(--wex-stripe-soft);
    color: var(--wex-stripe);
    font-size: 11px;
    font-weight: 600;
    line-height: 1.15;
    text-align: right;
    min-width: 56px;
    border: 1px solid color-mix(in srgb, var(--wex-stripe) 22%, transparent);
}

.widget-expiring-countdown-when {
    font-size: 9.5px;
    font-weight: 500;
    opacity: 0.75;
    color: var(--text-muted, #64748b);
}

.widget-expiring-countdown.is-expired {
    background: rgba(239, 68, 68, 0.18);
    color: #c62828;
    border-color: rgba(239, 68, 68, 0.35);
}

/* Тёмная тема */
.dark-theme .widget-expiring-item {
    background:
        linear-gradient(135deg,
            var(--wex-stripe-soft) 0%,
            rgba(255, 255, 255, 0) 60%),
        var(--input-bg, #1f2937);
    border-color: var(--input-border, rgba(255, 255, 255, 0.08));
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.35),
        0 4px 14px -6px rgba(0, 0, 0, 0.55);
}
.dark-theme .widget-expiring-item:hover {
    border-color: color-mix(in srgb, var(--wex-stripe) 45%, var(--input-border, rgba(255, 255, 255, 0.08)));
    box-shadow:
        0 2px 4px rgba(0, 0, 0, 0.4),
        0 10px 24px -10px color-mix(in srgb, var(--wex-stripe) 50%, transparent);
}
.dark-theme .widget-expiring-title-text {
    color: var(--text-color, #f1f5f9);
}
.dark-theme .widget-expiring-countdown-when {
    color: var(--text-muted, #94a3b8);
}

/* Компактный режим на узких экранах */
@media (max-width: 480px) {
    .widget-expiring-item {
        padding: 9px 10px 9px 12px;
        gap: 8px;
    }
    .widget-expiring-icon {
        width: 30px;
        height: 30px;
        font-size: 13px;
    }
    .widget-expiring-countdown {
        min-width: 50px;
        padding: 3px 6px;
        font-size: 10.5px;
    }
}

/* ============================================================
 * Виджет «Кто меня смотрит»: в слоте иконки теперь не fa-eye,
 * а реальная аватарка наблюдателя из Telegram. Стилизуем тот же
 * 34×34 квадрат так, чтобы <img> заполнял его, а фолбэк
 * показывал градиент с инициалом (как user-select).
 * ============================================================ */
.widget-expiring-icon.widget-expiring-avatar {
    padding: 0;
    overflow: hidden;
    background: transparent;
    box-shadow:
        inset 0 0 0 1px rgba(255, 255, 255, 0.35),
        0 2px 6px color-mix(in srgb, var(--wex-stripe) 35%, transparent);
}

.widget-expiring-avatar-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: inherit;
}

.widget-expiring-avatar-fallback {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    border-radius: inherit;
    color: #fff;
    font-size: 14px;
    font-weight: 700;
    line-height: 1;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
    user-select: none;
}

.widget-expiring-avatar-letter {
    display: inline-block;
}

/* Старые классы бакетов — оставлены как алиасы, чтобы не ломать
 * другие места, где они могли использоваться (например, в уведомлениях
 * о цветах). Сами карточки их больше не используют. */
.widget-expiring-critical { color: #c62828; }
.widget-expiring-warning  { color: #ef6c00; }
.widget-expiring-soon     { color: #1976d2; }
.widget-expiring-far      { color: #64748b; }

.widget-activity .widget-body {
    max-height: 240px;
    padding-top: 6px;
}

/* ============================================================
 * Карточки метрик активности (локации / события)
 * ============================================================ */
.activity-totals {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin: 0 0 10px;
    padding: 0;
}
.activity-total-item {
    --ati-accent: var(--widget-accent, #3b82f6);
    --ati-accent-soft: var(--widget-accent-soft, rgba(59, 130, 246, 0.14));
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px 8px 8px;
    border-radius: 12px;
    background:
        linear-gradient(135deg,
            var(--ati-accent-soft) 0%,
            color-mix(in srgb, var(--ati-accent-soft) 30%, transparent) 70%,
            transparent 100%),
        var(--input-bg, #fff);
    border: 1px solid color-mix(in srgb, var(--ati-accent) 18%, var(--input-border, #eaecef));
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.03),
        0 4px 12px -8px color-mix(in srgb, var(--ati-accent) 30%, transparent);
    overflow: hidden;
    transition:
        transform 0.18s ease,
        box-shadow 0.18s ease,
        border-color 0.18s ease;
}
.activity-total-item::after {
    content: "";
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 3px;
    background: linear-gradient(180deg,
        var(--ati-accent) 0%,
        color-mix(in srgb, var(--ati-accent) 60%, transparent) 100%);
    border-top-left-radius: 12px;
    border-bottom-left-radius: 12px;
    opacity: 0.85;
}
.activity-total-item:hover {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--ati-accent) 38%, var(--input-border, #eaecef));
    box-shadow:
        0 2px 4px rgba(15, 23, 42, 0.05),
        0 8px 18px -8px color-mix(in srgb, var(--ati-accent) 40%, transparent);
}
.activity-total-item-evt {
    --ati-accent: #f97316;
    --ati-accent-soft: rgba(249, 115, 22, 0.14);
}
.activity-total-icon {
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 9px;
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--ati-accent) 22%, transparent) 0%,
        color-mix(in srgb, var(--ati-accent) 10%, transparent) 100%);
    color: var(--ati-accent);
    font-size: 13px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.5),
        0 2px 6px -2px color-mix(in srgb, var(--ati-accent) 50%, transparent);
}
.activity-total-value {
    font-size: 18px;
    font-weight: 700;
    line-height: 1.1;
    color: var(--text-color, #1f2937);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}
.activity-total-label {
    font-size: 10.5px;
    color: var(--text-muted, #64748b);
    text-transform: lowercase;
    letter-spacing: 0.01em;
    margin-top: 1px;
}
.activity-total-item > .activity-total-value,
.activity-total-item > .activity-total-label {
    display: block;
}
.activity-total-value + .activity-total-label {
    margin-top: 1px;
}

/* Обёртка sparkline + tooltip — relative для позиционирования tooltip */
.activity-spark-wrap {
    position: relative;
    width: 100%;
}

/* ============================================================
 * SVG Sparkline — современный вид с градиентной заливкой
 * ============================================================ */
.activity-spark {
    width: 100%;
    height: 86px;
    display: block;
    overflow: visible;
    /* Сглаживание */
    -webkit-font-smoothing: antialiased;
}
.activity-spark-grid-line {
    stroke: var(--input-border, #eaecef);
    stroke-width: 1;
    stroke-dasharray: 2 3;
    opacity: 0.7;
}
.activity-spark-loc {
    fill: none;
    stroke: var(--widget-accent, #3b82f6);
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
    shape-rendering: geometricPrecision;
    filter: drop-shadow(0 1px 2px color-mix(in srgb, var(--widget-accent, #3b82f6) 40%, transparent));
    transition: stroke-width 0.2s ease;
}
.activity-spark-evt {
    fill: none;
    stroke: #f97316;
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
    shape-rendering: geometricPrecision;
    filter: drop-shadow(0 1px 2px rgba(249, 115, 22, 0.45));
    transition: stroke-width 0.2s ease;
}
.activity-spark-area {
    opacity: 0.85;
    transition: opacity 0.2s ease;
}
.activity-spark-area-stop-top { stop-opacity: 0.55; }
.activity-spark-area-stop-bot { stop-opacity: 0; }
.activity-spark-area-stop-loc { stop-color: var(--widget-accent, #3b82f6); }
.activity-spark-area-stop-evt { stop-color: #f97316; }

.activity-x-label {
    font-size: 9px;
    fill: var(--text-muted, #94a3b8);
    font-weight: 500;
    letter-spacing: 0.02em;
}

/* Точки на вершинах — интерактивные */
.activity-spark-dot {
    fill: var(--input-bg, #fff);
    stroke-width: 2;
    cursor: pointer;
    transition: r 0.18s ease, stroke-width 0.18s ease, opacity 0.18s ease;
    opacity: 0;
}
.activity-spark-dot-loc {
    stroke: var(--widget-accent, #3b82f6);
}
.activity-spark-dot-evt {
    stroke: #f97316;
}
/* Показываем точки при наведении на любую из них (через JS-класс) */
.activity-spark-wrap:hover .activity-spark-dot,
.activity-spark-dot:focus {
    opacity: 1;
    outline: none;
}
.activity-spark-dot:hover,
.activity-spark-dot.is-active,
.activity-spark-dot:focus {
    opacity: 1;
    r: 5;
    stroke-width: 3;
}

/* ============================================================
 * Tooltip активности
 * ============================================================ */
.activity-tooltip {
    position: absolute;
    z-index: 5;
    min-width: 130px;
    padding: 8px 10px;
    background: color-mix(in srgb, var(--input-bg, #fff) 92%, transparent);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #3b82f6) 22%, var(--input-border, #eaecef));
    border-radius: 10px;
    box-shadow:
        0 4px 8px rgba(15, 23, 42, 0.08),
        0 16px 32px -10px color-mix(in srgb, var(--widget-accent, #3b82f6) 35%, transparent);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    pointer-events: none;
    opacity: 0;
    transform: translateY(-2px);
    transition: opacity 0.15s ease, transform 0.15s ease;
}
.activity-tooltip.is-visible {
    opacity: 1;
    transform: translateY(0);
}
.activity-tooltip[hidden] {
    display: none;
}
.activity-tooltip-date {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-color, #1f2937);
    margin-bottom: 6px;
    padding-bottom: 5px;
    border-bottom: 1px solid color-mix(in srgb, var(--widget-accent, #3b82f6) 14%, transparent);
}
.activity-tooltip-row {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    line-height: 1.5;
    color: var(--text-color, #1f2937);
}
.activity-tooltip-row + .activity-tooltip-row {
    margin-top: 3px;
}
.activity-tooltip-dot {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    box-shadow: 0 0 0 2px color-mix(in srgb, currentColor 22%, transparent);
}
.activity-tooltip-dot-loc {
    background: var(--widget-accent, #3b82f6);
    color: var(--widget-accent, #3b82f6);
}
.activity-tooltip-dot-evt {
    background: #f97316;
    color: #f97316;
}
.activity-tooltip-label {
    flex: 1 1 auto;
    color: var(--text-muted, #64748b);
}
.activity-tooltip-value {
    flex: 0 0 auto;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text-color, #1f2937);
}

/* ============================================================
 * Тёмная тема
 * ============================================================ */
@media (prefers-color-scheme: dark) {
    .activity-total-item {
        background:
            linear-gradient(135deg,
                var(--ati-accent-soft) 0%,
                color-mix(in srgb, var(--ati-accent-soft) 30%, transparent) 70%,
                transparent 100%),
            color-mix(in srgb, var(--input-bg, #1e293b) 100%, transparent);
        border-color: color-mix(in srgb, var(--ati-accent) 26%, transparent);
    }
    .activity-total-icon {
        box-shadow:
            inset 0 1px 0 rgba(255, 255, 255, 0.06),
            0 2px 6px -2px color-mix(in srgb, var(--ati-accent) 50%, transparent);
    }
    .activity-total-value {
        color: #f1f5f9;
    }
    .activity-tooltip {
        background: color-mix(in srgb, #1e293b 92%, transparent);
        border-color: color-mix(in srgb, var(--widget-accent, #3b82f6) 30%, transparent);
    }
    .activity-tooltip-date {
        color: #f1f5f9;
        border-bottom-color: color-mix(in srgb, var(--widget-accent, #3b82f6) 22%, transparent);
    }
    .activity-tooltip-value {
        color: #f1f5f9;
    }
    .activity-spark-grid-line {
        stroke: rgba(148, 163, 184, 0.18);
    }
    .activity-spark-dot {
        fill: #1e293b;
    }
}

/* ============================================================
 * Адаптивность для маленьких экранов
 * ============================================================ */
@media (max-width: 480px) {
    .activity-totals {
        gap: 6px;
    }
    .activity-total-item {
        padding: 7px 9px 7px 7px;
        gap: 6px;
    }
    .activity-total-icon {
        width: 28px;
        height: 28px;
        font-size: 12px;
    }
    .activity-total-value {
        font-size: 16px;
    }
    .activity-total-label {
        font-size: 10px;
    }
    .activity-spark {
        height: 78px;
    }
}

.widget-heatmap .widget-body {
    height: 180px;
    padding: 0;
}
#dashHeatmapContainer {
    width: 100%;
    height: 100%;
    min-height: 180px;
    border-radius: 8px;
    overflow: hidden;
}

/* ============================================================
 * Универсальный набор «summary» для summary-виджетов дашборда
 * (статистика поездок, активные маршруты, активные геозоны)
 * ============================================================
 *
 * Структура одной строки-карточки:
 *   .widget-stat-grid
 *     .widget-stat-card              — карточка метрики
 *       .widget-stat-icon            — градиентная иконка слева
 *       .widget-stat-body            — flex-обёртка value + label
 *         .widget-stat-value         — значение (число + единица)
 *         .widget-stat-label         — подпись метрики (справа)
 *     .widget-stat-cta               — CTA-кнопка под списком
 *
 * Цвет акцента берётся из --widget-accent / --widget-accent-soft,
 * которые задаются родительским widget-tint-* (amber/pink/purple),
 * поэтому все три виджета автоматически получают свой цвет.
 */
.widget-stat-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 6px;
    margin: 0;
    padding: 0;
}

.widget-stat-card {
    --wst-radius: 12px;
    --wst-stripe: var(--widget-accent, #f59e0b);
    --wst-stripe-soft: var(--widget-accent-soft, rgba(245, 158, 11, 0.14));
    --wst-icon-bg: linear-gradient(135deg, var(--wst-stripe) 0%, color-mix(in srgb, var(--wst-stripe) 60%, #0f172a) 100%);
    --wst-icon-shadow: 0 2px 6px color-mix(in srgb, var(--wst-stripe) 35%, transparent);

    position: relative;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 12px;
    padding: 8px 12px 8px 14px;
    border-radius: var(--wst-radius);
    background:
        linear-gradient(135deg,
            var(--wst-stripe-soft) 0%,
            rgba(255, 255, 255, 0) 65%),
        var(--input-bg, #fff);
    border: 1px solid var(--input-border, #eaecef);
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.04),
        0 4px 12px -6px rgba(15, 23, 42, 0.06);
    overflow: hidden;
    transition:
        transform 0.18s ease,
        box-shadow 0.18s ease,
        border-color 0.18s ease;
}

.widget-stat-card::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 3px;
    background: var(--wst-stripe);
    border-top-left-radius: var(--wst-radius);
    border-bottom-left-radius: var(--wst-radius);
}

.widget-stat-card:hover {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--wst-stripe) 35%, var(--input-border, #eaecef));
    box-shadow:
        0 2px 4px rgba(15, 23, 42, 0.06),
        0 10px 22px -10px color-mix(in srgb, var(--wst-stripe) 40%, transparent);
}

.widget-stat-icon {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    color: #fff;
    background: var(--wst-icon-bg);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.18),
        var(--wst-icon-shadow);
}

.widget-stat-body {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.widget-stat-value {
    font-size: 16px;
    font-weight: 700;
    line-height: 1.1;
    color: var(--text-color, #0f172a);
    letter-spacing: -0.01em;
    display: inline-flex;
    align-items: baseline;
    gap: 3px;
    flex-wrap: wrap;
}

.widget-stat-unit {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-muted, #64748b);
    text-transform: lowercase;
    letter-spacing: 0;
}

.widget-stat-label {
    font-size: 11px;
    line-height: 1.25;
    color: var(--text-muted, #64748b);
    text-align: right;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* CTA-кнопка виджета */
.widget-stat-cta {
    margin-top: 10px;
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 12px;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.2;
    color: #fff;
    background: linear-gradient(135deg,
        var(--widget-accent, #f59e0b) 0%,
        color-mix(in srgb, var(--widget-accent, #f59e0b) 60%, #0f172a) 100%);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #f59e0b) 50%, transparent);
    border-radius: 10px;
    cursor: pointer;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.18),
        0 2px 8px -2px color-mix(in srgb, var(--widget-accent, #f59e0b) 45%, transparent);
    transition:
        transform 0.15s ease,
        box-shadow 0.18s ease,
        filter 0.18s ease;
}

.widget-stat-cta:hover {
    transform: translateY(-1px);
    filter: brightness(1.05);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.22),
        0 6px 16px -4px color-mix(in srgb, var(--widget-accent, #f59e0b) 55%, transparent);
}

.widget-stat-cta:active {
    transform: translateY(0);
    filter: brightness(0.97);
}

.widget-stat-cta i {
    font-size: 11px;
    transition: transform 0.18s ease;
}

.widget-stat-cta:hover i {
    transform: translateX(2px);
}

/* Тёмная тема */
body.dark-theme .widget-stat-card {
    background:
        linear-gradient(135deg,
            var(--wst-stripe-soft) 0%,
            rgba(255, 255, 255, 0) 65%),
        var(--input-bg, #1f2937);
    border-color: var(--input-border, rgba(255, 255, 255, 0.08));
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.30),
        0 4px 12px -6px rgba(0, 0, 0, 0.40);
}

body.dark-theme .widget-stat-card:hover {
    border-color: color-mix(in srgb, var(--wst-stripe) 45%, var(--input-border, rgba(255, 255, 255, 0.08)));
    box-shadow:
        0 2px 4px rgba(0, 0, 0, 0.36),
        0 10px 22px -10px color-mix(in srgb, var(--wst-stripe) 50%, transparent);
}

body.dark-theme .widget-stat-value {
    color: var(--text-color, #f1f5f9);
}

body.dark-theme .widget-stat-unit,
body.dark-theme .widget-stat-label {
    color: var(--text-muted, #94a3b8);
}

/* Адаптив для очень узких виджетов */
@media (max-width: 360px) {
    .widget-stat-card {
        padding: 7px 10px 7px 12px;
        gap: 10px;
    }
    .widget-stat-icon {
        width: 26px;
        height: 26px;
        font-size: 12px;
    }
    .widget-stat-value {
        font-size: 15px;
    }
    .widget-stat-label {
        font-size: 10px;
    }
}

/* ============================================================
 * Виджет «Статистика пользователя (24ч)»
 * ============================================================ */

/* Темы (светлая по умолчанию) — задаются на самом виджете, чтобы
 * переменные каскадировали во все дочерние блоки статистики,
 * списки пребывания и популярных мест (а не только в us-wrapper). */
.widget-user-stats {
    --wus-bg: #ffffff;
    --wus-bg-elev: #ffffff;
    --wus-bg-soft: rgba(6, 182, 212, 0.10);
    --wus-border: rgba(15, 23, 42, 0.08);
    --wus-border-strong: rgba(15, 23, 42, 0.14);
    --wus-text: #0f172a;
    --wus-text-muted: #64748b;
    --wus-icon-color: #ffffff;
    --wus-shadow:
        0 1px 2px rgba(15, 23, 42, 0.04),
        0 6px 18px -8px rgba(15, 23, 42, 0.10);
}
body.dark-theme .widget-user-stats {
    --wus-bg: #1f1f23;
    --wus-bg-elev: #2a2a31;
    --wus-bg-soft: rgba(6, 182, 212, 0.20);
    --wus-border: rgba(255, 255, 255, 0.08);
    --wus-border-strong: rgba(255, 255, 255, 0.16);
    --wus-text: #f1f5f9;
    --wus-text-muted: #94a3b8;
    --wus-icon-color: #ffffff;
    --wus-shadow:
        0 1px 2px rgba(0, 0, 0, 0.35),
        0 8px 24px -10px rgba(0, 0, 0, 0.55);
}

/* Высота виджета в ~1.875 раза больше стандартной
 * (стандартный .widget-body имеет max-height: 240px, здесь — 450px). */
.widget-user-stats .widget-body.widget-user-stats-body {
    max-height: 450px;
    min-height: 244px;
}
.widget-user-stats .widget-user-stats-body {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding-top: 4px;
}
.widget-user-stats-select-wrap {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--wus-bg);
    /* Лёгкая нижняя «тень»-граница, визуально отделяющая
     * зафиксированную шапку с селектом пользователя от прокручивающегося
     * контента виджета (списки dwell, популярные места). */
    box-shadow: 0 1px 0 var(--wus-border);
    border-radius: 50%;
    margin: 0;
}
.widget-user-stats-select-wrap .us-wrapper {
    margin-bottom: 0;
}
/* Глобальное правило `input, select, button { margin: 10px 0 }`
 * (строки 104 и 504) применяется и к кастомной кнопке селекта
 * (<button class="us-button">), создавая лишний отступ внутри виджета.
 * Перебиваем его индивидуально только для этого случая. */
.widget-user-stats-select-wrap .us-button {
    margin: 0;
}

/* Сетка блоков статистики.
 * На десктопе — до 3 колонок (как и было),
 * на планшетах — 2 колонки,
 * на мобильных экранах (включая большие) — всегда по одному блоку в ряд. */
.widget-user-stats-blocks {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px;
}
@media (max-width: 900px) {
    .widget-user-stats-blocks {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}
/* На мобильных экранах всегда по одному блоку в ряд,
 * независимо от ширины (исключает «схлопывание» в 2 колонки
 * даже на больших смартфонах). */
@media (max-width: 720px) {
    .widget-user-stats-blocks {
        grid-template-columns: 1fr;
    }
}

.widget-user-stats-blocks .route-info-block {
    background: var(--wus-bg-soft);
    border: 1px solid var(--wus-border);
    border-radius: 12px;
    padding: 10px 12px;
    min-width: 0;
    color: var(--wus-text);
    box-shadow: var(--wus-shadow);
}
.widget-user-stats-blocks .route-info-block__label {
    font-size: 11px;
    color: var(--wus-text-muted);
    line-height: 1.2;
    margin-bottom: 2px;
}
.widget-user-stats-blocks .route-info-block__value {
    font-size: 14px;
    font-weight: 600;
    color: var(--wus-text);
    line-height: 1.3;
    word-break: break-word;
}
/* Иконки блоков статистики — белые на градиентной подложке,
 * но в дневной теме делаем чуть мягче контраст. */
.widget-user-stats-blocks .route-info-block__icon {
    color: var(--wus-icon-color);
}
.widget-user-stats-subhead {
    font-size: 12px;
    font-weight: 600;
    color: var(--wus-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin: 30px 0 0 0;
}
/* Контейнер списка топ-мест: компактные «карточки-медальоны». */
.widget-user-stats-places {
    display: flex;
    flex-direction: column;
    gap: 8px;
    /* Прокрутка, если мест сильно много и виджет переполнен. */
    overflow-y: auto;
    scrollbar-gutter: stable;
}

/* Сама карточка: flex-row «иконка | тело | шеврон», мягкие тени,
 * плавные переходы и аккуратный hover с лёгким «приподниманием». */
.widget-user-stats-place {
    position: relative;
    display: flex;
    flex-direction: row;
    align-items: stretch;
    gap: 12px;
    padding: 10px 12px;
    border: 1px solid var(--wus-border);
    border-radius: 14px;
    background: var(--wus-bg-elev);
    color: var(--wus-text);
    box-shadow: var(--wus-shadow);
    cursor: pointer;
    overflow: hidden;
    transition:
        transform 160ms ease,
        box-shadow 160ms ease,
        border-color 160ms ease,
        background 160ms ease;
    /* Тонкая декоративная полоска слева — акцент в стиле «место». */
    --place-accent: linear-gradient(180deg, #67e8f9 0%, #0891b2 100%);
}
.widget-user-stats-place::before {
    content: "";
    position: absolute;
    left: 0;
    top: 8px;
    bottom: 8px;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--place-accent);
    opacity: 0.85;
}
.widget-user-stats-place:hover {
    transform: translateY(-1px);
    border-color: var(--wus-border-strong);
    box-shadow:
        0 2px 4px rgba(15, 23, 42, 0.06),
        0 12px 28px -10px rgba(15, 23, 42, 0.18);
}
.widget-user-stats-place:active {
    transform: translateY(0);
}
body.dark-theme .widget-user-stats-place:hover {
    box-shadow:
        0 2px 4px rgba(0, 0, 0, 0.40),
        0 14px 32px -10px rgba(0, 0, 0, 0.65);
}

/* Левый блок: круглая иконка с градиентом и мини-индексом места. */
.widget-user-stats-place__icon {
    position: relative;
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    background: var(--place-accent);
    box-shadow:
        0 4px 10px -4px rgba(8, 145, 178, 0.45),
        inset 0 0 0 1px rgba(255, 255, 255, 0.18);
    align-self: center;
}
.widget-user-stats-place__icon > i {
    font-size: 12px;
    line-height: 1;
    /* Сдвигаем влево, чтобы цифра ранга не накладывалась на иконку. */
    transform: translateX(-3px);
}
.widget-user-stats-place__rank {
    position: absolute;
    right: -2px;
    bottom: -2px;
    min-width: 1px;
    height: 10px;
    padding: 0 5px;
    border-radius: 999px;
    background: #ffffff;
    color: #155e75;
    font-size: 9px;
    font-weight: 700;
    line-height: 12px;
    text-align: center;
    box-shadow:
        0 0 0 2px var(--wus-bg-elev),
        0 1px 3px rgba(15, 23, 42, 0.15);
    font-variant-numeric: tabular-nums;
}
body.dark-theme .widget-user-stats-place__rank {
    background: #1f1f23;
    color: #67e8f9;
    box-shadow:
        0 0 0 2px var(--wus-bg-elev),
        0 1px 3px rgba(0, 0, 0, 0.5);
}

/* Центральный блок: заголовок + адрес. */
.widget-user-stats-place__body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
    justify-content: center;
}
.widget-user-stats-place__header {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

/* Pill со счётчиком точек: компактный, с лёгкой подсветкой. */
.widget-user-stats-place__count {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px 2px 6px;
    border-radius: 999px;
    background: var(--wus-bg-soft);
    color: var(--wus-text);
    font-size: 9px;
    font-weight: 600;
    line-height: 1.4;
    white-space: nowrap;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    font-variant-numeric: tabular-nums;
}
.widget-user-stats-place__count > i {
    font-size: 9px;
    opacity: 0.75;
}
.widget-user-stats-place__count-value {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Шеврон справа — визуальный аффорданс «карточка кликабельна». */
.widget-user-stats-place__chevron {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    align-self: center;
    color: var(--wus-text-muted);
    font-size: 12px;
    width: 16px;
    transition: transform 160ms ease, color 160ms ease;
}
.widget-user-stats-place:hover .widget-user-stats-place__chevron {
    color: var(--wus-text);
    transform: translateX(2px);
}

/* Бейдж «Место N» — обновляем под новую палитру. */
.widget-badge-place {
    background: rgb(230 248 251);
    color: #333333;
    font-weight: 600;
    letter-spacing: 0.01em;
}
body.dark-theme .widget-badge-place {
    background: rgb(35 70 81);
    color: #dadada;
}

/* Адрес: под карточкой — отдельная строка с хорошей читаемостью. */
.widget-place-address {
    font-size: 13px;
    line-height: 1.4;
    color: var(--wus-text);
    margin: 0;
    word-break: break-word;
    /* Чтобы длинные адреса аккуратно обрезались в 2 строки. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.widget-place-address.address-line--loading {
    color: var(--wus-text-muted);
    font-style: italic;
    /* Лёгкий shimmer-плейсхолдер пока грузится обратный геокодинг. */
    position: relative;
    background: linear-gradient(
        90deg,
        var(--wus-text-muted) 0%,
        var(--wus-text-muted) 40%,
        rgba(148, 163, 184, 0.45) 50%,
        var(--wus-text-muted) 60%,
        var(--wus-text-muted) 100%
    );
    background-size: 200% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
    animation: widget-place-shimmer 1.4s linear infinite;
}
.widget-place-address.address-line--error {
    color: #b91c1c;
    font-style: italic;
}
body.dark-theme .widget-place-address.address-line--error {
    color: #fca5a5;
}
@keyframes widget-place-shimmer {
    0%   { background-position: 100% 0; }
    100% { background-position: -100% 0; }
}

/* Уважаем пользователей с reduce-motion: отключаем shimmer/hover-анимации. */
@media (prefers-reduced-motion: reduce) {
    .widget-user-stats-place,
    .widget-user-stats-place__chevron {
        transition: none;
    }
    .widget-place-address.address-line--loading {
        animation: none;
    }
}

/* Адаптивность: на очень узких экранах сжимаем отступы и иконку. */
@media (max-width: 380px) {
    .widget-user-stats-place {
        gap: 10px;
        padding: 9px 10px;
    }
    .widget-user-stats-place__icon {
        width: 32px;
        height: 32px;
    }
    .widget-user-stats-place__icon > i {
        font-size: 11px;
    }
    .widget-user-stats-place__chevron {
        display: none;
    }
}

/* ============================================================
 * Карточки dwell (пребывание в зоне/маршруте) в блоке
 * «Пребывание в зонах/маршрутах» (24ч).
 *
 * Единый визуальный язык с карточками places: медальон-иконка
 * слева, основной блок по центру, акцентный pill справа.
 * ============================================================ */

.widget-user-stats-dwell-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.widget-dwell-24h-item {
    position: relative;
    display: flex;
    flex-direction: row;
    align-items: stretch;
    gap: 12px;
    padding: 10px 12px;
    border: 1px solid var(--wus-border);
    border-radius: 14px;
    background: var(--wus-bg-elev);
    color: var(--wus-text);
    box-shadow: var(--wus-shadow);
    overflow: hidden;
    transition:
        transform 160ms ease,
        box-shadow 160ms ease,
        border-color 160ms ease,
        background 160ms ease;
    /* Дефолтный акцент — для зон (циан). Переопределяется ниже
     * модификатором --route (изумрудный). */
    --dwell-accent: linear-gradient(180deg, #67e8f9 0%, #0891b2 100%);
}
.widget-dwell-24h-item::before {
    content: "";
    position: absolute;
    left: 0;
    top: 8px;
    bottom: 8px;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--dwell-accent);
    opacity: 0.85;
}
.widget-dwell-24h-item--route {
    --dwell-accent: linear-gradient(180deg, #34d399 0%, #059669 100%);
}
.widget-dwell-24h-item:hover {
    transform: translateY(-1px);
    border-color: var(--wus-border-strong);
    box-shadow:
        0 2px 4px rgba(15, 23, 42, 0.06),
        0 12px 28px -10px rgba(15, 23, 42, 0.18);
}
body.dark-theme .widget-dwell-24h-item:hover {
    box-shadow:
        0 2px 4px rgba(0, 0, 0, 0.40),
        0 14px 32px -10px rgba(0, 0, 0, 0.65);
}

/* Левый медальон: круглая иконка с градиентом в тон акценту. */
.widget-dwell-24h-item__icon {
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    background: var(--dwell-accent);
    box-shadow:
        0 4px 10px -4px rgba(37, 99, 235, 0.45),
        inset 0 0 0 1px rgba(255, 255, 255, 0.18);
    align-self: center;
}
.widget-dwell-24h-item__icon > i {
    font-size: 13px;
    line-height: 1;
}
.widget-dwell-24h-item--route .widget-dwell-24h-item__icon {
    box-shadow:
        0 4px 10px -4px rgba(5, 150, 105, 0.45),
        inset 0 0 0 1px rgba(255, 255, 255, 0.18);
}

/* Центральный блок с бейджем названия. */
.widget-dwell-24h-item__body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 6px;
}
.widget-dwell-24h-item__body .widget-badge {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    /* Чуть более «весомый» бейдж для имён зон/маршрутов. */
    font-weight: 600;
    letter-spacing: 0.01em;
}

/* Правый pill с длительностью — компактный, моноширинные цифры. */
.widget-dwell-24h-item__dwell {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px 4px 8px;
    border-radius: 999px;
    background: var(--wus-bg-soft);
    color: var(--wus-text);
    font-size: 9px;
    font-weight: 700;
    line-height: 1.2;
    white-space: nowrap;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    font-variant-numeric: tabular-nums;
    align-self: center;
}
.widget-dwell-24h-item__dwell > i {
    font-size: 9px;
    opacity: 0.75;
}
.widget-dwell-24h-item__dwell-value {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Респект reduce-motion для dwell-карточек. */
@media (prefers-reduced-motion: reduce) {
    .widget-dwell-24h-item {
        transition: none;
    }
}

/* Адаптивность dwell-карточек на узких экранах. */
@media (max-width: 380px) {
    .widget-dwell-24h-item {
        gap: 10px;
        padding: 9px 10px;
    }
    .widget-dwell-24h-item__icon {
        width: 32px;
        height: 32px;
    }
    .widget-dwell-24h-item__icon > i {
        font-size: 12px;
    }
    .widget-dwell-24h-item__dwell {
        font-size: 9px;
        padding: 3px 8px 3px 6px;
    }
}

.status-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    height: 20px;
    background: #f4f4f4;
    color: #222;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 10px;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 11px;
    line-height: 20px;
    z-index: 999;
    box-sizing: border-box;
    user-select: none;
    white-space: nowrap;
    overflow: hidden;
    gap: 8px;
}

.status-bar-user,
.status-bar-time {
    overflow: hidden;
    text-overflow: ellipsis;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.2px;
}

.status-bar-user {
    font-weight: 400;
    flex: 1 1 auto;
    min-width: 0;
}

.status-bar-user [data-i18n="webapp_status_bar_user"] {
    font-weight: 700;
}

.status-bar-user-id {
    opacity: 0.75;
}

.status-bar-time {
    font-weight: 600;
    flex: 0 0 auto;
}

body.dark-theme .status-bar {
    background: #2b2b2b;
    color: #f0f0f0;
}

body.fullscreen-app .status-bar {
    display: none;
}

/* ============================================================
   UserSelect — современный кастомный dropdown с аватарками
   ============================================================ */

/* Цветовые токены (светлая тема по умолчанию) */
.us-wrapper,
.us-popover {
    --us-bg: #ffffff;
    --us-bg-elev: #ffffff;
    --us-border: rgba(15, 23, 42, 0.08);
    --us-border-strong: rgba(15, 23, 42, 0.14);
    --us-text: #0f172a;
    --us-text-muted: #64748b;
    --us-accent: #2481cc;
    --us-accent-soft: rgba(36, 129, 204, 0.10);
    --us-hover: rgba(15, 23, 42, 0.045);
    --us-active: rgba(36, 129, 204, 0.12);
    --us-shadow:
        0 1px 2px rgba(15, 23, 42, 0.04),
        0 10px 30px -10px rgba(15, 23, 42, 0.18),
        0 20px 50px -20px rgba(15, 23, 42, 0.18);
    --us-radius: 14px;
    --us-radius-sm: 10px;
    --us-ring: 0 0 0 4px rgba(36, 129, 204, 0.18);
    --us-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

body.dark-theme .us-wrapper,
body.dark-theme .us-popover {
    --us-bg: #1f1f23;
    --us-bg-elev: #2a2a31;
    --us-border: rgba(255, 255, 255, 0.08);
    --us-border-strong: rgba(255, 255, 255, 0.16);
    --us-text: #f1f5f9;
    --us-text-muted: #94a3b8;
    --us-accent: #5eb1ff;
    --us-accent-soft: rgba(94, 177, 255, 0.16);
    --us-hover: rgba(255, 255, 255, 0.06);
    --us-active: rgba(94, 177, 255, 0.18);
    --us-shadow:
        0 1px 2px rgba(0, 0, 0, 0.4),
        0 10px 30px -10px rgba(0, 0, 0, 0.6),
        0 20px 50px -20px rgba(0, 0, 0, 0.5);
    --us-ring: 0 0 0 4px rgba(94, 177, 255, 0.28);
}

.us-wrapper {
    position: relative;
    width: 100%;
    margin-bottom: 12px;
    font: inherit;
    color: var(--us-text);
    -webkit-tap-highlight-color: transparent;
}

/* ----- Кнопка-триггер ----- */
.us-button {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 10px 8px 12px;
    background: var(--us-bg);
    border: 1px solid var(--us-border-strong);
    border-radius: var(--us-radius);
    cursor: pointer;
    text-align: left;
    font: inherit;
    color: var(--us-text);
    min-height: 48px;
    box-shadow: 0 1px 0 rgba(15, 23, 42, 0.02);
    transition:
        border-color 160ms var(--us-ease),
        box-shadow 200ms var(--us-ease),
        background 160ms var(--us-ease),
        transform 160ms var(--us-ease);
    -webkit-appearance: none;
    appearance: none;
}

.us-button:hover {
    border-color: var(--us-accent);
    background: var(--us-bg);
}

.us-button:focus-visible {
    outline: none;
    border-color: var(--us-accent);
    box-shadow: var(--us-ring);
}

.us-button.us-button-open {
    border-color: var(--us-accent);
    box-shadow: var(--us-ring);
}

.us-button.us-button-placeholder {
    color: var(--us-text-muted);
}

.us-button-inner {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 1 1 auto;
    min-width: 0;
}

.us-button-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 15px;
    font-weight: 500;
    letter-spacing: -0.005em;
}

.us-caret {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    color: var(--us-text-muted);
    transition:
        transform 220ms var(--us-ease),
        background 160ms var(--us-ease),
        color 160ms var(--us-ease);
}

.us-button:hover .us-caret,
.us-button.us-button-open .us-caret {
    color: var(--us-accent);
    background: var(--us-accent-soft);
}

.us-button.us-button-open .us-caret {
    transform: rotate(180deg);
}

/* ----- Аватарка ----- */
.us-avatar {
    flex: 0 0 auto;
    border-radius: 50%;
    overflow: hidden;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: #eee;
    position: relative;
    box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.05);
}

.us-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

body.dark-theme .us-avatar {
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}

.us-avatar-letter {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    color: #fff;
    font-weight: 600;
    font-size: 13px;
    line-height: 1;
    user-select: none;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
}

/* ----- Backdrop ----- */
.us-backdrop {
    position: fixed;
    inset: 0;
    z-index: 9998;
    background: rgba(15, 23, 42, 0.32);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    opacity: 0;
    transition: opacity 180ms var(--us-ease);
}

.us-backrop-open,
.us-backdrop.us-backdrop-open {
    opacity: 1;
}

body.dark-theme .us-backdrop {
    background: rgba(0, 0, 0, 0.55);
}

/* ----- Popover (контейнер дропдауна) ----- */
.us-popover {
    position: fixed;
    z-index: 9999;
    background: var(--us-bg-elev);
    border: 1px solid var(--us-border);
    border-radius: var(--us-radius);
    box-shadow: var(--us-shadow);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    max-height: min(360px, calc(100vh - 24px));
    transform-origin: top center;
    opacity: 0;
    transform: translateY(-6px) scale(0.98);
    transition:
        opacity 160ms var(--us-ease),
        transform 180ms var(--us-ease);
    -webkit-tap-highlight-color: transparent;
}

.us-popover.us-popover-up {
    transform-origin: bottom center;
    transform: translateY(6px) scale(0.98);
}

.us-popover.us-popover-open {
    opacity: 1;
    transform: translateY(0) scale(1);
}

body.dark-theme .us-popover {
    background: var(--us-bg-elev);
    border-color: var(--us-border-strong);
}

/* ----- Поиск ----- */
.us-search {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 10px 10px 12px;
    border-bottom: 1px solid var(--us-border);
    background: var(--us-bg-elev);
    flex: 0 0 auto;
}

.us-search-icon {
    color: var(--us-text-muted);
    flex: 0 0 auto;
}

.us-search-input {
    flex: 1 1 auto;
    border: 0;
    outline: 0;
    background: transparent;
    color: var(--us-text);
    font: inherit;
    font-size: 14px;
    padding: 6px 0;
    min-width: 0;
}

.us-search-input::placeholder {
    color: var(--us-text-muted);
}

.us-search-clear {
    border: 0;
    background: transparent;
    color: var(--us-text-muted);
    width: 22px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    cursor: pointer;
    flex: 0 0 auto;
    opacity: 0;
    pointer-events: none;
    transition: opacity 140ms var(--us-ease), background 140ms var(--us-ease), color 140ms var(--us-ease);
}

.us-search-clear:hover {
    background: var(--us-hover);
    color: var(--us-text);
}

/* ----- Список ----- */
.us-list {
    overflow-y: auto;
    overflow-x: hidden;
    padding: 6px;
    flex: 1 1 auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: var(--us-border-strong) transparent;
}

.us-list::-webkit-scrollbar {
    width: 8px;
}

.us-list::-webkit-scrollbar-thumb {
    background: var(--us-border-strong);
    border-radius: 8px;
}

.us-list::-webkit-scrollbar-track {
    background: transparent;
}

/* ----- Пункт списка ----- */
.us-option {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 10px;
    border-radius: var(--us-radius-sm);
    cursor: pointer;
    user-select: none;
    color: var(--us-text);
    transition: background 120ms var(--us-ease), color 120ms var(--us-ease), transform 120ms var(--us-ease);
    position: relative;
}

.us-option.us-option-active,
.us-option:hover {
    background: var(--us-hover);
}

.us-option.us-option-selected {
    background: var(--us-active);
    color: var(--us-text);
}

.us-option.us-option-selected .us-label {
    font-weight: 600;
}

.us-option.us-option-placeholder {
    color: var(--us-text-muted);
}

.us-option-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.us-option .us-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 14px;
}

.us-check {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--us-accent);
    width: 18px;
    height: 18px;
    opacity: 0;
    transform: scale(0.6);
    transition: opacity 140ms var(--us-ease), transform 160ms var(--us-ease);
}

.us-option.us-option-selected .us-check {
    opacity: 1;
    transform: scale(1);
}

.us-check-spacer {
    visibility: hidden;
}

/* ----- Empty state ----- */
.us-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 28px 16px;
    color: var(--us-text-muted);
    font-size: 14px;
    flex: 1 1 auto;
    text-align: center;
}

/* ----- Адаптив ----- */
@media (max-width: 480px) {
    .us-button {
        min-height: 44px;
    }
    .us-button-label {
        font-size: 14px;
    }
    .us-popover {
        max-height: min(70vh, 420px);
    }
}

/* ----- Снижение движения ----- */
@media (prefers-reduced-motion: reduce) {
    .us-button,
    .us-caret,
    .us-popover,
    .us-backdrop,
    .us-option,
    .us-check,
    .us-search-clear {
        transition: none !important;
    }
}

/* ============================================================
   Pushable buttons (Uiverse.io by PriyanshuGupta28)
   Применяется ко всем кнопкам раздела «Геотрекер» miniapp,
   кроме тех, что расположены непосредственно на карте.
   ============================================================ */
.pushable {
    position: relative;
    background: transparent;
    background-color: transparent;
    padding: 0px;
    border: none;
    cursor: pointer;
    outline-offset: 4px;
    outline-color: #007bff;
    transition: filter 250ms;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    font: inherit;
}

.pushable .shadow {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    background: hsl(211, 60%, 60%);
    border-radius: 8px;
    filter: blur(2px);
    will-change: transform;
    transform: translateY(2px);
    transition: transform 600ms cubic-bezier(0.3, 0.7, 0.4, 1);
    pointer-events: none;
}

body.dark-theme .pushable .shadow {
    background: hsl(211deg 38.51% 14.55%);
}

.pushable .edge {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    border-radius: 8px;
    background: linear-gradient(
        to right,
        hsl(211, 100%, 30%) 0%,
        hsl(211, 100%, 40%) 8%,
        hsl(211, 100%, 30%) 92%,
        hsl(211, 100%, 22%) 100%
    );
    pointer-events: none;
}

.pushable .front {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    position: relative;
    border-radius: 8px;
    background: #007bff;
    padding: 14px 26px;
    color: white;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 1.2px;
    font-size: 0.9rem;
    line-height: 1.2;
    transform: translateY(-4px);
    transition: transform 600ms cubic-bezier(0.3, 0.7, 0.4, 1);
    width: 100%;
    box-sizing: border-box;
}

.pushable:hover {
    filter: brightness(110%);
}

.pushable:hover .front {
    transform: translateY(-6px);
    transition: transform 250ms cubic-bezier(0.3, 0.7, 0.4, 1.5);
}

.pushable:active .front {
    transform: translateY(-2px);
    transition: transform 34ms;
}

.pushable:hover .shadow {
    transform: translateY(4px);
    transition: transform 250ms cubic-bezier(0.3, 0.7, 0.4, 1.5);
}

.pushable:active .shadow {
    transform: translateY(1px);
    transition: transform 34ms;
}

.pushable:focus:not(:focus-visible) {
    outline: none;
}

.pushable:focus-visible {
    outline: 2px solid #66b0ff;
    outline-offset: 4px;
}

/* --- Полноширинная кнопка по умолчанию (Топ мест, Экспорт и т.п.) --- */
.pushable {
    display: block;
    width: 100%;
    margin: 10px 0;
}

/* --- Кнопки-даты (startDateBtn, endDateBtn) — стиль как у us-button
   в свернутом состоянии (белый фон, бордер, скругление, аватарка слева,
   label по центру, шеврон справа). Pushable-эффект для этих кнопок
   отключён: shadow/edge скрыты, .front прозрачна. */
.filter-controls .pushable {
    margin: 0;
    width: 100%;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 10px 8px 12px;
    background: var(--us-bg, #ffffff);
    border: 1px solid var(--us-border-strong, rgba(15, 23, 42, 0.14));
    border-radius: var(--us-radius, 14px);
    cursor: pointer;
    text-align: left;
    font: inherit;
    color: var(--us-text, #0f172a);
    min-height: 48px;
    box-shadow: 0 1px 0 rgba(15, 23, 42, 0.02);
    transition:
        border-color 160ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
        box-shadow 200ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
        background 160ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
        transform 160ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
    -webkit-appearance: none;
    appearance: none;
}

body.dark-theme .filter-controls .pushable {
    background: var(--us-bg, #1f1f23);
    border-color: var(--us-border-strong, rgba(255, 255, 255, 0.16));
    color: var(--us-text, #f1f5f9);
}

/* Скрываем pushable-эффекты для кнопок-дат */
.filter-controls .pushable .shadow,
.filter-controls .pushable .edge {
    display: none;
}

.filter-controls .pushable .front {
    position: static;
    transform: none;
    background: transparent;
    color: inherit;
    padding: 0;
    width: auto;
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 12px;
    text-transform: none;
    letter-spacing: 0;
    font-size: inherit;
    font-weight: inherit;
    line-height: inherit;
    border-radius: 0;
    transition: none;
    box-sizing: border-box;
}

.filter-controls .pushable .front,
.filter-controls .pushable:hover .front,
.filter-controls .pushable:active .front,
.filter-controls .pushable:focus .front {
    background: transparent;
    color: inherit;
    transform: none;
}

/* Состояние hover/focus — как у us-button */
.filter-controls .pushable:hover {
    border-color: var(--us-accent, #2481cc);
    background: var(--us-bg, #ffffff);
    filter: none;
}

.filter-controls .pushable:focus-visible {
    outline: none;
    border-color: var(--us-accent, #2481cc);
    box-shadow: var(--us-ring, 0 0 0 4px rgba(36, 129, 204, 0.18));
}

.filter-controls .pushable:active {
    transform: none;
}

/* Внутренние элементы (label / value) — стек-вертикально как в us-button-inner */
.filter-controls .pushable .date-button-content {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 1px;
    text-align: left;
}

.filter-controls .pushable .date-button-label {
    font-size: 12px;
    color: var(--us-text-muted, #64748b);
    font-weight: 500;
    letter-spacing: 0.01em;
    line-height: 1.2;
}

body.dark-theme .filter-controls .pushable .date-button-label {
    color: var(--us-text-muted, #94a3b8);
}

.filter-controls .pushable .date-button-value {
    font-size: 15px;
    font-weight: 500;
    color: var(--us-text, #0f172a);
    letter-spacing: -0.005em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
    line-height: 1.2;
}

body.dark-theme .filter-controls .pushable .date-button-value {
    color: var(--us-text, #f1f5f9);
}

/* Иконка календаря слева — стиль как us-avatar (32x32, скруглённая) */
.filter-controls .pushable .date-button-icon {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background-color: var(--us-accent-soft, rgba(36, 129, 204, 0.10));
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232481cc' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='18' rx='3'/><path d='M16 2v4M8 2v4M3 10h18'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 18px 18px;
    box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.05);
}

body.dark-theme .filter-controls .pushable .date-button-icon {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235eb1ff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='18' rx='3'/><path d='M16 2v4M8 2v4M3 10h18'/></svg>");
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}

/* Шеврон справа — стиль как us-caret (28x28, иконка стрелки вниз) */
.filter-controls .pushable .date-button-chevron {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    color: var(--us-text-muted, #64748b);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='18' height='18' fill='none' stroke='currentColor' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='m6 9 6 6 6-6'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 18px 18px;
    opacity: 1;
    margin-left: auto;
    transition:
        transform 220ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
        background 160ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
        color 160ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
}

body.dark-theme .filter-controls .pushable .date-button-chevron {
    color: var(--us-text-muted, #94a3b8);
}

.filter-controls .pushable:hover .date-button-chevron {
    color: var(--us-accent, #2481cc);
    background-color: var(--us-accent-soft, rgba(36, 129, 204, 0.10));
}

body.dark-theme .filter-controls .pushable:hover .date-button-chevron {
    background-color: var(--us-accent-soft, rgba(94, 177, 255, 0.16));
}

/* Состояние .has-value — подсвечиваем как us-button.us-button-open */
.pushable.date-button.has-value {
    border-color: var(--us-accent, #2481cc);
    box-shadow: var(--us-ring, 0 0 0 4px rgba(36, 129, 204, 0.18));
}

.pushable.date-button.has-value .date-button-icon {
    background-color: var(--us-accent-soft, rgba(36, 129, 204, 0.10));
}

.pushable.date-button.has-value .date-button-value {
    color: var(--us-accent, #2481cc);
    font-weight: 600;
}

body.dark-theme .pushable.date-button.has-value .date-button-value {
    color: var(--us-accent, #5eb1ff);
}

/* --- Кнопки в одной строке (shareTrip, myTrips) — компактные --- */
#tripShareRow .pushable {
    flex: 1 1 0;
    min-width: 140px;
    margin: 0;
}

#tripShareRow .pushable .front {
    padding: 10px 14px;
    font-size: 10px;
    letter-spacing: 0.5px;
    min-height: 44px;
}

/* --- Зелёный вариант для «В реальном времени» --- */
.pushable--success .front {
    background: hsl(134, 53%, 48%);
}
.pushable--success .edge {
    background: linear-gradient(
        to right,
        hsl(134, 39%, 30%) 0%,
        hsl(134, 39%, 40%) 8%,
        hsl(134, 39%, 30%) 92%,
        hsl(134, 39%, 22%) 100%
    );
}
.pushable--success .shadow {
    background: hsl(134, 25%, 55%);
}

body.dark-theme .pushable--success .shadow {
    background: hsl(134deg 19.4% 15.96%);
}

/* --- Адаптив --- */
@media (max-width: 480px) {
    .pushable .front {
        padding: 12px 18px;
        font-size: 0.7rem;
    }
    .filter-controls .pushable .front {
        min-height: 44px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .pushable,
    .pushable .front,
    .pushable .shadow,
    .pushable .edge {
        transition: none !important;
    }
    .pushable:hover .front,
    .pushable:hover .shadow {
        transform: none !important;
    }
}

/* Сброс старых стилей, которые могли применяться к id кнопок,
   ставших pushable. Эти правила должны иметь большую
   специфичность, чем старые селекторы по id. */
.pushable#exportCsvButton,
.pushable#realtimeButton,
.pushable#showAllUsersButton,
.pushable#topPlacesButton {
    background-color: transparent;
    background: transparent;
    border: none;
    box-shadow: none;
    color: inherit;
    padding: 0;
    margin: 10px 0;
    font: inherit;
    display: block;
    width: 100%;
}

.pushable#exportCsvButton:hover,
.pushable#exportCsvButton:active,
.pushable#realtimeButton:hover,
.pushable#realtimeButton:active,
.pushable#showAllUsersButton:hover,
.pushable#showAllUsersButton:active,
.pushable#topPlacesButton:hover,
.pushable#topPlacesButton:active {
    background-color: transparent;
    background: transparent;
    transform: none;
}

/* Сброс старых стилей для кнопок раздела «Настройки» перенесён в конец файла
   (см. блок «Settings pushable buttons override»). Там же используется
   более высокая специфичность + !important, чтобы исключить перебитие
   глобальными правилами .pushable / .action-btn / .copy-btn. */
/* Глобальный сброс базовых стилей кнопок для всех .pushable,
   чтобы глобальное `button { background-color }` и
   `button:active { transform: scale }` не ломали анимацию. */
button.pushable,
button.pushable:hover,
button.pushable:active,
button.pushable:focus {
    background: transparent;
    background-color: transparent;
    border: none;
    box-shadow: none;
    color: inherit;
    transform: none;
}

/* ============================================================
   Modern select — современный стиль для нативных <select>.
   Применяется к #shareTripExpiry и может переиспользоваться
   для других модальных селектов.
   ============================================================ */
.modern-select {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    display: block;
    width: 100%;
    box-sizing: border-box;
    padding: 10px 38px 10px 14px;
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--us-text, #0f172a);
    background-color: var(--us-bg, #ffffff);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='18' height='18' fill='none' stroke='%2364748b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='m6 9 6 6 6-6'/></svg>");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 18px 18px;
    border: 1px solid var(--us-border-strong, rgba(15, 23, 42, 0.14));
    border-radius: var(--us-radius, 14px);
    cursor: pointer;
    min-height: 44px;
    box-shadow: 0 1px 0 rgba(15, 23, 42, 0.02);
    transition:
        border-color 160ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
        box-shadow 200ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
        background-color 160ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
    -webkit-tap-highlight-color: transparent;
}

.modern-select:hover {
    border-color: var(--us-accent, #2481cc);
    background-color: var(--us-bg, #ffffff);
}

.modern-select:focus {
    outline: none;
    border-color: var(--us-accent, #2481cc);
    box-shadow: var(--us-ring, 0 0 0 4px rgba(36, 129, 204, 0.18));
}

.modern-select:disabled {
    opacity: 0.6;
    cursor: not-allowed;
    background-color: var(--us-bg, #f7f7f7);
}

/* Тёмная тема */
body.dark-theme .modern-select {
    color: var(--us-text, #f1f5f9);
    background-color: var(--us-bg, #1f1f23);
    border-color: var(--us-border-strong, rgba(255, 255, 255, 0.16));
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='18' height='18' fill='none' stroke='%2394a3b8' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='m6 9 6 6 6-6'/></svg>");
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
}

body.dark-theme .modern-select:hover,
body.dark-theme .modern-select:focus {
    border-color: var(--us-accent, #5eb1ff);
    background-color: var(--us-bg, #1f1f23);
}

body.dark-theme .modern-select:focus {
    box-shadow: 0 0 0 4px rgba(94, 177, 255, 0.28);
}

/* ============================================================
   Стили раскрытой (popup) части нативного <select> через
   современный CSS-стандарт ::picker(select) и ::picker-icon.
   Поддерживается в Chromium 120+ и Safari 17+. В остальных
   браузерах будет нативный popup, адаптированный через
   color-scheme (см. ниже).
   ============================================================ */
@supports (appearance: base-select) {
    .modern-select {
        appearance: base-select;
    }

    /* Сам контейнер раскрытого списка */
    .modern-select::picker(select) {
        appearance: base-select;
        background: var(--us-bg-elev, #ffffff);
        color: var(--us-text, #0f172a);
        border: 1px solid var(--us-border-strong, rgba(15, 23, 42, 0.14));
        border-radius: var(--us-radius, 14px);
        box-shadow:
            0 12px 32px rgba(15, 23, 42, 0.18),
            0 2px 8px rgba(15, 23, 42, 0.08);
        padding: 6px;
        margin-top: 6px;
        min-width: 100%;
        max-height: 320px;
        overflow-y: auto;
        -webkit-backdrop-filter: saturate(180%) blur(8px);
        backdrop-filter: saturate(180%) blur(8px);
    }

    body.dark-theme .modern-select::picker(select) {
        background: var(--us-bg-elev, #2a2a31);
        border-color: var(--us-border-strong, rgba(255, 255, 255, 0.16));
        box-shadow:
            0 12px 32px rgba(0, 0, 0, 0.55),
            0 2px 8px rgba(0, 0, 0, 0.35);
    }

    /* Иконка-шеврон в раскрытом состоянии — поворачивается вверх */
    .modern-select::picker-icon {
        display: none;
    }

    /* Каждая опция в раскрытом списке */
    .modern-select option {
        padding: 10px 14px;
        border-radius: 10px;
        margin: 1px 0;
        background: transparent;
        color: var(--us-text, #0f172a);
        font-weight: 500;
        font-size: 14px;
        line-height: 1.4;
        cursor: pointer;
        transition:
            background-color 140ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
            color 140ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
    }

    .modern-select option:hover,
    .modern-select option:focus-visible {
        background: var(--us-accent-soft, rgba(36, 129, 204, 0.10));
        color: var(--us-text, #0f172a);
        outline: none;
    }

    .modern-select option:checked,
    .modern-select option[aria-selected="true"] {
        background: var(--us-accent, #2481cc);
        color: #ffffff;
        font-weight: 600;
    }

    body.dark-theme .modern-select option {
        color: var(--us-text, #f1f5f9);
    }

    body.dark-theme .modern-select option:hover,
    body.dark-theme .modern-select option:focus-visible {
        background: var(--us-accent-soft, rgba(94, 177, 255, 0.16));
        color: var(--us-text, #f1f5f9);
    }

    body.dark-theme .modern-select option:checked,
    body.dark-theme .modern-select option[aria-selected="true"] {
        background: var(--us-accent, #5eb1ff);
        color: #0f172a;
    }

    /* Анимация открытия */
    .modern-select::picker(select) {
        transition:
            opacity 160ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
            transform 160ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
    }

    @media (prefers-reduced-motion: reduce) {
        .modern-select::picker(select),
        .modern-select option {
            transition: none !important;
        }
    }
}

/* color-scheme — чтобы нативный popup в старых браузерах
   корректно подстраивался под тёмную тему. */
.modern-select {
    color-scheme: light;
}

body.dark-theme .modern-select {
    color-scheme: dark;
}

@media (prefers-reduced-motion: reduce) {
    .modern-select {
        transition: none !important;
    }
}

/* ============================================================
   Modern input — стиль «Uiverse Na3ar-17».
   Используется для текстовых инпутов в модалках (например,
   поле заголовка публикации маршрута).
   ============================================================ */
.modern-input {
    position: relative;
    display: flex;
    align-items: center;
    width: 100%;
    box-sizing: border-box;
    padding: 12px 44px 12px 14px;
    border: 2px solid var(--us-border-strong, rgba(15, 23, 42, 0.22));
    border-radius: 6px;
    background: var(--us-bg, #ffffff);
    color: var(--us-text, #0f172a);
    text-align: left;
    cursor: text;
    transition:
        border-color 200ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
        box-shadow 200ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
        background-color 200ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
    -webkit-tap-highlight-color: transparent;
}

.modern-input:hover {
    border-color: #007bff;
}

.modern-input:focus-within {
    border-color: #007bff;
    box-shadow: 0 0 0 4px rgba(0, 123, 255, 0.18);
}

.modern-input-icon {
    position: absolute;
    top: 50%;
    right: 14px;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    color: #9ca3af;
    font-size: 14px;
    line-height: 1;
    transition:
        color 200ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1)),
        transform 200ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
    pointer-events: none;
}

.modern-input:hover .modern-input-icon {
    color: #007bff;
}

.modern-input:focus-within .modern-input-icon {
    color: #007bff;
    transform: translateY(-50%) scale(1.08);
}

.modern-input-field {
    flex: 1 1 auto;
    min-width: 0;
    background: transparent;
    outline: none;
    border: none;
    padding: 0;
    margin: 0;
    color: inherit;
    font: inherit;
    font-size: 16px;
    line-height: 1.4;
}

.modern-input-field::placeholder {
    color: #9ca3af;
    opacity: 1;
    transition: color 200ms var(--us-ease, cubic-bezier(0.22, 0.61, 0.36, 1));
}

.modern-input-field:focus::placeholder {
    color: #6b7280;
}

/* Тёмная тема */
body.dark-theme .modern-input {
    background: var(--us-bg, #1f1f23);
    border-color: rgba(255, 255, 255, 0.18);
    color: var(--us-text, #f1f5f9);
}

body.dark-theme .modern-input:hover,
body.dark-theme .modern-input:focus-within {
    border-color: #66b0ff;
}

body.dark-theme .modern-input:focus-within {
    box-shadow: 0 0 0 4px rgba(102, 176, 255, 0.28);
}

body.dark-theme .modern-input-icon {
    color: #6b7280;
}

body.dark-theme .modern-input:hover .modern-input-icon,
body.dark-theme .modern-input:focus-within .modern-input-icon {
    color: #66b0ff;
}

body.dark-theme .modern-input-field::placeholder {
    color: #6b7280;
}

body.dark-theme .modern-input-field:focus::placeholder {
    color: #94a3b8;
}

@media (prefers-reduced-motion: reduce) {
    .modern-input,
    .modern-input-icon,
    .modern-input-field::placeholder {
        transition: none !important;
    }
    .modern-input:focus-within .modern-input-icon {
        transform: translateY(-50%);
    }
}

/* ============================================================
   Settings pushable buttons override
   Применяется к кнопкам раздела «Настройки» (#openChannelManagerBtn,
   .button-row .copy-btn с классами pushable). Помещено в конец файла
   и использует !important + максимально специфичные селекторы,
   чтобы исключить перебитие глобальными правилами
   .pushable { display:block; width:100% } и
   .action-btn/.copy-btn { background, padding, border-radius, ... }.
   ============================================================ */

/* --- Сброс наследуемых стилей .action-btn / .copy-btn для .pushable --- */
.settings-group button.pushable.action-btn,
.settings-group button.pushable.action-btn:hover,
.settings-group button.pushable.action-btn:active,
.settings-group button.pushable.action-btn:focus,
.settings-group button.pushable.copy-btn,
.settings-group button.pushable.copy-btn:hover,
.settings-group button.pushable.copy-btn:active,
.settings-group button.pushable.copy-btn:focus {
    background: transparent !important;
    background-color: transparent !important;
    border: none !important;
    box-shadow: none !important;
    color: inherit !important;
    transform: none !important;
    text-align: center !important;
}

/* --- Полноширинная кнопка «Каналы» (#openChannelManagerBtn) ---
   Полностью повторяет логику сброса для #topPlacesButton. */
.settings-group #openChannelManagerBtn.pushable,
.settings-group #openChannelManagerBtn.pushable:hover,
.settings-group #openChannelManagerBtn.pushable:active,
.settings-group #openChannelManagerBtn.pushable:focus {
    background: transparent !important;
    background-color: transparent !important;
    border: none !important;
    box-shadow: none !important;
    color: inherit !important;
    padding: 0 !important;
    margin: 10px 0 !important;
    font: inherit !important;
    display: block !important;
    width: 100% !important;
    text-align: center !important;
    overflow: hidden !important;
    line-height: 1 !important;
}

.settings-group #openChannelManagerBtn.pushable:hover,
.settings-group #openChannelManagerBtn.pushable:active {
    background: transparent !important;
    background-color: transparent !important;
    transform: none !important;
}

/* --- Кнопки внутри .button-row раздела «Настройки» — компактный вариант.
   Перебиваем глобальное .pushable { display:block; width:100%; margin:10px 0 },
   чтобы кнопки жили в flex-строке и делили ширину поровну. */
.settings-group .button-row button.pushable.copy-btn,
.settings-group .button-row button.pushable.copy-btn:hover,
.settings-group .button-row button.pushable.copy-btn:active,
.settings-group .button-row button.pushable.copy-btn:focus {
    flex: 1 1 0 !important;
    min-width: 140px !important;
    margin: 0 !important;
    display: block !important;
    width: auto !important;
    max-width: 100% !important;
    background: transparent !important;
    background-color: transparent !important;
    border: none !important;
    box-shadow: none !important;
    text-align: center !important;
    /* Чтобы transform на .front работал — сам button не трансформируем. */
    transform: none !important;
    padding: 0 !important;
    /* .shadow имеет filter:blur(2px) и transform:translateY(2px),
       .edge — те же размеры, что и кнопка. Без overflow:hidden blur
       выходит за границы кнопки и попадает в gap соседних кнопок
       (визуально — тёмные полосы сверху/снизу). */
    overflow: hidden !important;
    line-height: 1 !important;
    border-radius: 8px !important;
}

/* Чуть компактнее, чем у дефолтного .pushable .front, чтобы две
   кнопки в строке не были слишком громоздкими. АНИМАЦИЮ НЕ ТРОГАЕМ —
   transform:translateY(-4px) нужен для 3D-эффекта. Чтобы убрать
   тёмную полосу СВЕРХУ (где .front не достаёт до края кнопки),
   синхронно сдвигаем .edge и .shadow на ту же величину — тогда
   .edge начинается ровно от верха кнопки, а тёмная «тень» остаётся
   только снизу (это и есть 3D-эффект, как у эталона «Топ мест»). */
.settings-group .button-row button.pushable .front {
    padding: 10px 14px !important;
    font-size: 12px !important;
    letter-spacing: 0.8px !important;
    min-height: 44px !important;
    text-transform: none !important;
}

.settings-group .button-row button.pushable .edge {
    /* Синхронизируем с .front: тот же translateY, что у .front,
       чтобы .edge начинался ровно от верха кнопки и не оставлял
       тёмную полосу сверху. */
    transform: translateY(-4px) !important;
}

.settings-group .button-row button.pushable .shadow {
    /* Аналогично: сдвигаем на -2px (тот же сдвиг, что у .front -4px,
       плюс родной translateY(2px) = -2px). */
    transform: translateY(-2px) !important;
}

/* ============================================
   Панель «Каналы для уведомлений» — современный стиль
   ============================================ */

.settings-card-panel {
    border: 1px solid color-mix(in srgb, var(--button-bg) 28%, transparent);
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--button-bg) 4%, var(--card-bg)) 0%,
        var(--card-bg) 60%);
    box-shadow:
        0 1px 2px var(--card-shadow),
        0 8px 28px color-mix(in srgb, var(--button-bg) 14%, transparent);
}

.settings-card-panel::before {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 3px;
    background: linear-gradient(90deg, #0ea5e9 0%, #2563eb 100%);
    border-radius: var(--settings-card-radius, 18px) var(--settings-card-radius, 18px) 0 0;
    opacity: 0.95;
}

.panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 0;
    padding: 16px 16px 14px 16px;
    border-bottom: 1px solid color-mix(in srgb, var(--input-border) 50%, transparent);
    background: color-mix(in srgb, var(--button-bg) 5%, transparent);
}

.panel-header h3 {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    color: var(--text-color);
    display: inline-flex;
    align-items: center;
    gap: 10px;
    letter-spacing: -0.1px;
}

.panel-header h3 i {
    width: 32px;
    height: 32px;
    border-radius: 10px;
    background: linear-gradient(135deg, #0ea5e9 0%, #2563eb 100%);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    box-shadow: 0 4px 10px rgba(14, 165, 233, 0.30);
}

.close-panel-btn {
    width: 34px;
    height: 34px;
    border-radius: 10px;
    border: 1px solid color-mix(in srgb, var(--input-border) 50%, transparent);
    background: var(--input-bg);
    color: color-mix(in srgb, var(--text-color) 65%, transparent);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    padding: 0;
    line-height: 1;
    transition: all 0.15s ease;
    flex-shrink: 0;
}

.close-panel-btn:hover {
    background: color-mix(in srgb, #ef4444 12%, var(--input-bg));
    border-color: #ef4444;
    color: #ef4444;
    transform: scale(1.05);
}

.close-panel-btn:active {
    transform: scale(0.95);
}

.panel-content {
    padding: 14px 16px 16px 16px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.channel-intro {
    margin: 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: color-mix(in srgb, var(--text-color) 75%, transparent);
    padding: 10px 12px;
    background: color-mix(in srgb, var(--button-bg) 8%, transparent);
    border-left: 3px solid var(--button-bg);
    border-radius: 8px;
}

.channel-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 16px 0 0 0;
}

.channel-item {
    background: var(--input-bg);
    border: 1px solid color-mix(in srgb, var(--input-border) 55%, transparent);
    border-radius: 12px;
    padding: 12px 14px;
    font-size: 13px;
    color: var(--text-color);
    transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
    position: relative;
}

.channel-item:hover {
    border-color: color-mix(in srgb, var(--button-bg) 40%, var(--input-border));
    transform: translateY(-1px);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--card-shadow) 70%, transparent);
}

.channel-item.channel-inactive {
    border-color: color-mix(in srgb, #f59e0b 40%, var(--input-border));
    background: color-mix(in srgb, #f59e0b 6%, var(--input-bg));
}

.channel-item-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    margin-bottom: 6px;
    font-weight: 500;
    color: var(--text-color);
}

.channel-item-title {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 13.5px;
    font-weight: 600;
}

.channel-item-title i {
    width: 20px;
    height: 20px;
    border-radius: 6px;
    background: color-mix(in srgb, #10b981 15%, transparent);
    color: #10b981;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 10px;
    flex-shrink: 0;
}

.channel-inactive .channel-item-title i {
    background: color-mix(in srgb, #f59e0b 18%, transparent);
    color: #f59e0b;
}

.channel-item-status {
    font-size: 11px;
    font-weight: 600;
    padding: 4px 10px;
    border-radius: 999px;
    background: color-mix(in srgb, #10b981 14%, transparent);
    color: #059669;
    flex-shrink: 0;
    letter-spacing: 0.2px;
}

.channel-inactive .channel-item-status {
    background: color-mix(in srgb, #f59e0b 16%, transparent);
    color: #d97706;
}

.channel-item-meta {
    font-size: 11.5px;
    color: color-mix(in srgb, var(--text-color) 55%, transparent);
    margin: 0 0 8px 0;
    line-height: 1.4;
}

.channel-item-error {
    font-size: 11.5px;
    color: #ef4444;
    margin: 0 0 8px 0;
    word-break: break-word;
    padding: 6px 8px;
    background: color-mix(in srgb, #ef4444 8%, transparent);
    border-radius: 6px;
}

.channel-item-actions {
    display: flex;
    gap: 6px;
    margin-top: 8px;
    flex-wrap: wrap;
}

.channel-item-actions .btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 4px 0;
    padding: 7px 12px;
    font-size: 12px;
    font-weight: 500;
    border-radius: 8px;
    border: 1px solid color-mix(in srgb, var(--input-border) 60%, transparent);
    background: var(--card-bg);
    color: var(--text-color);
    cursor: pointer;
    transition: all 0.15s ease;
}

.channel-item-actions .btn:hover {
    background: color-mix(in srgb, var(--button-bg) 8%, var(--card-bg));
    border-color: var(--button-bg);
    color: var(--button-bg);
    transform: translateY(-1px);
}

.channel-item-actions .btn.btn-secondary:hover {
    background: color-mix(in srgb, var(--button-bg) 10%, var(--card-bg));
    color: var(--button-bg);
}

.channel-item-actions .btn.btn-danger {
    border-color: color-mix(in srgb, #ef4444 30%, var(--input-border));
    color: #ef4444;
}

.channel-item-actions .btn.btn-danger:hover {
    background: #ef4444;
    border-color: #ef4444;
    color: #fff;
}

.channel-item-actions .btn i {
    font-size: 11px;
}

.channel-empty {
    padding: 16px 12px;
    background: color-mix(in srgb, var(--input-bg) 60%, transparent);
    border: 1px dashed color-mix(in srgb, var(--input-border) 70%, transparent);
    border-radius: 10px;
    text-align: center;
    color: color-mix(in srgb, var(--text-color) 55%, transparent);
    font-size: 12.5px;
    line-height: 1.4;
}

.channel-empty::before {
    content: "\f4e1"; /* fa-bullhorn */
    font-family: "Font Awesome 6 Free", "Font Awesome 6 Pro", "FontAwesome";
    font-weight: 900;
    display: block;
    font-size: 20px;
    margin-bottom: 6px;
    color: color-mix(in srgb, var(--text-color) 30%, transparent);
}

.panel-actions {
    display: flex;
    justify-content: flex-end;
    padding-top: 12px;
    border-top: 1px solid color-mix(in srgb, var(--input-border) 50%, transparent);
    margin-top: 2px;
}

.panel-actions .action-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 16px;
    font-size: 13px;
    font-weight: 600;
    background: linear-gradient(135deg, var(--button-bg) 0%, color-mix(in srgb, var(--button-bg) 70%, #6366f1) 100%);
    color: #fff;
    border: none;
    border-radius: 10px;
    cursor: pointer;
    box-shadow: 0 4px 12px color-mix(in srgb, var(--button-bg) 30%, transparent);
    transition: all 0.15s ease;
}

.panel-actions .action-btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 16px color-mix(in srgb, var(--button-bg) 40%, transparent);
}

.panel-actions .action-btn:active {
    transform: translateY(0);
}

/* Тёмная тема */
.dark-theme .settings-card-panel {
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--button-bg) 6%, var(--card-bg)) 0%,
        var(--card-bg) 60%);
}

.dark-theme .channel-item-title i {
    background: color-mix(in srgb, #10b981 22%, transparent);
}

.dark-theme .channel-inactive .channel-item-title i {
    background: color-mix(in srgb, #f59e0b 25%, transparent);
}

.dark-theme .close-panel-btn {
    background: var(--input-bg);
}

/* Кнопка выбора канала публикации — уменьшенный шрифт */
#notificationChannelSection .btn.btn-primary {
    font-size: 13px;
    padding: 8px 14px;
}

/* ============================================
   Buy Stars (Telegram Stars / XTR) для раздела «Баланс»
   ============================================ */

.settings-group-hint {
    font-size: 12px;
    color: var(--text-secondary, #888);
    margin: -4px 0 12px 0;
    line-height: 1.4;
}

.stars-packages-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 4px;
}

/* Кнопки пакетов Stars используют глобальный стиль `.pushable`
   (фон #007bff, светлое тиснение, hover/active анимация),
   поэтому здесь мы НЕ переопределяем фон/цвет/hover — это
   делает .pushable / .pushable .front. Дополнительный класс
   `.stars-package-btn` оставлен для возможных точечных
   переопределений ниже и для контекстных селекторов
   (.stars-package-points и т.п.).

   Применяем тот же сброс базовых стилей кнопки, что и для
   остальных pushable в settings-group, чтобы случайные правила
   .modal-btn / .modal-btn-apply / .action-btn / .copy-btn не
   "просочились" в каскад. */
.settings-group button.pushable.stars-package-btn,
.settings-group button.pushable.stars-package-btn:hover,
.settings-group button.pushable.stars-package-btn:active,
.settings-group button.pushable.stars-package-btn:focus {
    background: transparent;
    background-color: transparent;
    color: inherit;
    border: none;
    box-shadow: none;
    padding: 0;
    text-align: center;
}

/* Чуть компактнее для списка пакетов, чтобы 4 кнопки
   не занимали слишком много вертикального пространства. */
.settings-group .stars-packages-list button.pushable.stars-package-btn {
    margin: 0;
}

.settings-group .stars-packages-list button.pushable.stars-package-btn .front {
    padding: 12px 18px;
    font-size: 0.85rem;
    letter-spacing: 0.8px;
    text-transform: none;
    gap: 10px;
}

/* Состояние disabled для кнопки пакета (например, во время
   открытия Telegram-инвойса). */
.stars-package-btn:disabled,
.stars-package-btn[disabled] {
    opacity: 0.6;
    cursor: not-allowed;
    filter: none;
}

/* Название пакета внутри кнопки */
.stars-package-name {
    font-weight: 600;
    text-transform: initial;
}

/* Количество покупаемых stars — лёгкий полупрозрачный
   бейдж справа от названия, чтобы было видно «размер»
   пакета без утяжеления кнопки. */
.stars-package-points {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.22);
    font-size: 13px;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: 0.1px;
    white-space: nowrap;
}

/* ============================================
   Единый стиль для всех пакетов Stars.
   Фон #007bff и текст #ffffff одинаковы
   для светлой и тёмной темы — поэтому
   здесь НЕТ ни переопределений по
   [data-package-id], ни правил для
   body.dark-theme.
   ============================================ */

.stars-custom-topup-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
}

.modal-text {
    font-size: 14px;
    color: var(--text-color, #333);
    margin: 0 0 12px 0;
    line-height: 1.45;
}

.modal-form-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 14px;
}

.modal-form-row label {
    font-size: 13px;
    color: var(--text-secondary, #888);
}

/* Убираем лишний нижний margin у input внутри modal-form-row,
   чтобы он не съезжал вниз. */
.modal-form-row .settings-input {
    margin-bottom: 0;
}

/* ============================================================
 * ВИДЖЕТ «ДОСТИЖЕНИЯ» (A1)
 * ============================================================
 *
 * Сетка бейджей 3×N. Каждый бейдж:
 *   - Разблокированный: цветной фон/рамка по тиру (bronze/silver/
 *     gold/platinum), светящийся при is-new.
 *   - Заблокированный: серый, с иконкой замка и tooltip'ом
 *     «Заблокировано».
 *
 * Тёмная тема: подложки чуть приглушаются, текст остаётся
 * контрастным.
 * ============================================================ */
.widget-achievements-body {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* ============================================================
 * Виджет «Достижения» — фиксированная высота с прокручиваемой
 * сеткой, summary всегда видна.
 *
 * Проблема: при большом числе ачивок (3×N в сетке) сводка
 * .widget-achievements-summary уезжала за нижнюю границу виджета
 * и обрезалась внутренним скроллом .widget-body.
 *
 * Решение (по аналогии с .dashboard-widget.widget-quests):
 *   1. Фиксируем «потолок» на самом виджете.
 *   2. .widget-body становится flex-распределителем без overflow.
 *   3. .achievement-grid занимает всё свободное место (flex:1 +
 *      min-height:0) и прокручивается.
 *   4. .widget-achievements-summary — flex:0 0 auto, всегда виден.
 *
 * Высота сетки в 1.5 раза больше базовой (было ~250px baseline,
 * стало ~375px). Достигается за счёт увеличения max-height
 * виджета и явного min-height на самой сетке на случай, если
 * родительский потолок не сработает (например, narrow viewport).
 * ============================================================ */
.dashboard-widget.widget-achievements {
    max-height: 880px;
    /* .achievement-premium-group рендерится внутри этого виджета,
       но свисает ниже его границ. Без overflow:visible она
       обрезается базовым overflow:hidden на .dashboard-widget. */
    overflow: visible;
}

/* Сбрасываем базовый overflow/max-height на body виджета —
   теперь это просто flex-распределитель места. */
.dashboard-widget.widget-achievements .widget-body.widget-achievements-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: visible;
    max-height: none;
    margin: 0;
    padding: 4px 0 0 0;
    /* [fix/achievements-summary-overlap] Сводка больше не лежит внутри
       body (она переехала прямым ребёнком виджета, см. achievements.js
       → renderAchievementsWidget). Остался только .achievement-grid,
       поэтому gap не нужен; оставшийся от базового правила
       .widget-achievements-body { gap:12px } сбрасываем явно, чтобы
       случайный будущий ребёнок body не получил лишний отступ. */
    gap: 0;
}

/* Защита от flex-сжатия: header, near-complete и summary должны
   занимать свою естественную высоту всегда. Сжиматься должна
   только сетка ачивок (через min-height:0 на .widget-body), иначе
   пользователь видит только часть near-complete (~30px) —
   см. также .achievement-near-complete { flex:0 0 auto; }. */
.dashboard-widget.widget-achievements > .widget-header,
.dashboard-widget.widget-achievements > .achievement-near-complete {
    flex: 0 0 auto;
}

/* Сетка ачивок — единственная прокручиваемая часть. Высота
   сетки увеличена в ~1.5 раза относительно прежней ~250px, чтобы
   пользователь видел больше ачивок до скролла. min-height:375px
   — нижняя граница; flex:1 1 auto растянет выше, если есть
   запас; иначе сетка всё равно будет минимум 375px высотой
   (overscroll через overflow-y:auto). */
.dashboard-widget.widget-achievements .achievement-grid {
    flex: 1 1 auto;
    min-height: 375px;
    overflow-x: hidden;
    overflow-y: auto;
    /* Тонкий акцентный скроллбар в амбер-палитре виджета. */
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, #b45309 35%, transparent) transparent;
}
.dashboard-widget.widget-achievements .achievement-grid::-webkit-scrollbar {
    width: 6px;
}
.dashboard-widget.widget-achievements .achievement-grid::-webkit-scrollbar-track {
    background: transparent;
}
.dashboard-widget.widget-achievements .achievement-grid::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, #b45309 35%, transparent);
    border-radius: 999px;
}
.dashboard-widget.widget-achievements .achievement-grid::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, #b45309 55%, transparent);
}

/* Сводка — статична внизу body, не участвует в скролле. */
.dashboard-widget.widget-achievements .widget-achievements-summary {
    flex: 0 0 auto;
}

/* Сводка внизу виджета достижений — единый стиль с .widget-quests-summary.
   Все правила ниже (13001+) применяются через selector list
   (.widget-quests-summary, .widget-achievements-summary), поэтому
   дополнительных правил для .widget-achievements-summary не нужно. */

/* Сетка бейджей */
.achievement-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px;
}
@media (max-width: 720px) {
    .achievement-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* Бейдж */
.achievement-badge {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 12px 8px 10px 8px;
    border-radius: 12px;
    border: 1px solid var(--input-border, #eaecef);
    background: var(--card-bg, #fff);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
    cursor: default;
    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
    min-height: 130px;
    overflow: hidden;
}
/* [P0 #4] Бейджи с popover'ом (data-achv-popover="1") —
   кликабельные. Меняем курсор и focus-ring для accessibility. */
.achievement-badge[data-achv-popover="1"] {
    cursor: pointer;
}
.achievement-badge[data-achv-popover="1"]:focus-visible {
    outline: 2px solid var(--widget-accent, #f59e0b);
    outline-offset: 2px;
}
.achievement-badge:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08);
}
.achievement-badge .achievement-icon {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    margin-bottom: 6px;
    background: var(--ach-bg, rgba(0, 0, 0, 0.04));
    color: var(--ach-fg, #888);
    transition: transform 0.2s ease;
}
.achievement-badge:hover .achievement-icon {
    transform: scale(1.06);
}
.achievement-badge .achievement-title {
    font-size: 12px;
    font-weight: 600;
    line-height: 1.25;
    color: var(--text-color, #222);
    margin-bottom: 2px;
    word-break: break-word;
}
.achievement-badge .achievement-desc {
    font-size: 10.5px;
    line-height: 1.3;
    color: var(--text-muted, #888);
    word-break: break-word;
}

/* ===== P2 #13: Подсказка-«намёк» под описанием =====
   Маленькая строка с иконкой-лампочкой, объясняющая как
   получить заблокированную ачивку. Для секретных — общий
   «✨ Секретное достижение», чтобы пользователь знал о
   их существовании. */
.achievement-badge .achievement-hint {
    width: 100%;
    margin-top: 5px;
    padding: 4px 6px;
    border-radius: 6px;
    background: color-mix(in srgb, #f59e0b 10%, transparent);
    border: 1px dashed color-mix(in srgb, #f59e0b 35%, transparent);
    font-size: 9.5px;
    line-height: 1.25;
    color: #92400e;
    text-align: center;
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
}
.achievement-badge .achievement-hint i {
    font-size: 10px;
    opacity: 0.85;
}
body.dark-theme .achievement-badge .achievement-hint {
    background: color-mix(in srgb, #f59e0b 18%, transparent);
    color: #fcd34d;
}

/* [P0 #4] Пульсация намёка после клика на «Как получить»
   в popover'е ачивки. Привлекает внимание к подсказке
   внутри бейджа. */
@keyframes achievement-hint-pulse {
    0%, 100% {
        transform: scale(1);
        box-shadow: 0 0 0 0 rgba(245, 158, 11, 0);
    }
    50% {
        transform: scale(1.06);
        box-shadow: 0 0 0 6px rgba(245, 158, 11, 0.25);
    }
}
.achievement-badge .achievement-hint.is-pulse {
    animation: achievement-hint-pulse 0.4s ease-in-out 3;
}

/* Заблокированный бейдж */
.achievement-badge.is-locked {
    opacity: 0.55;
    filter: grayscale(0.7);
}
.achievement-badge.is-locked .achievement-icon {
    background: rgba(0, 0, 0, 0.06);
    color: #aaa;
}
.achievement-badge.is-locked .achievement-title,
.achievement-badge.is-locked .achievement-desc {
    color: #aaa;
}

/* ===== P0 #2: «Почти готово» (≥75% прогресса) =====
   Подсвечиваем рамку и иконку карточки мягкой пульсацией, чтобы
   взгляд цеплялся за почти завершённые достижения. Перебиваем
   серый фильтр заблокированной карточки, чтобы текст оставался
   читаемым. */
@keyframes achievement-near-pulse {
    0%, 100% {
        box-shadow: 0 0 0 0 var(--ach-fg, #f59e0b),
                    0 0 0 0 transparent;
        border-color: var(--ach-fg, #f59e0b);
    }
    50% {
        box-shadow: 0 0 0 4px color-mix(in srgb, var(--ach-fg, #f59e0b) 25%, transparent),
                    0 0 12px 0 color-mix(in srgb, var(--ach-fg, #f59e0b) 35%, transparent);
        border-color: color-mix(in srgb, var(--ach-fg, #f59e0b) 80%, transparent);
    }
}
.achievement-badge.is-locked.is-near-complete {
    opacity: 1;
    filter: none;
    animation: achievement-near-pulse 2.2s ease-in-out infinite;
}
.achievement-badge.is-locked.is-near-complete .achievement-icon {
    color: var(--ach-fg, #f59e0b);
    background: color-mix(in srgb, var(--ach-fg, #f59e0b) 14%, transparent);
}
.achievement-badge.is-locked.is-near-complete .achievement-title,
.achievement-badge.is-locked.is-near-complete .achievement-desc {
    color: var(--text-color, #222);
}
/* При наведении — пауза пульсации, чтобы карточка не дёргалась под курсором. */
.achievement-badge.is-near-complete:hover {
    animation-play-state: paused;
}
.achievement-badge .achievement-lock {
    position: absolute;
    top: 6px;
    right: 6px;
    font-size: 11px;
    color: rgba(0, 0, 0, 0.45);
}
body.dark-theme .achievement-badge .achievement-lock {
    color: rgba(255, 255, 255, 0.45);
}

/* Бейдж «NEW» — для только что разблокированных */
.achievement-badge .achievement-new-badge {
    position: absolute;
    top: 6px;
    left: 6px;
    background: linear-gradient(135deg, #ef4444, #f59e0b);
    color: #fff;
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.4px;
    padding: 2px 5px;
    border-radius: 6px;
    box-shadow: 0 2px 6px rgba(239, 68, 68, 0.35);
}

/* Бейдж награды (+N★) */
.achievement-badge .achievement-reward {
    margin-top: 6px;
    font-size: 10.5px;
    font-weight: 700;
    color: var(--ach-fg, #b45309);
    background: var(--ach-bg, rgba(245, 158, 11, 0.12));
    padding: 2px 8px;
    border-radius: 999px;
}

/* ===== Прогресс-бар у заблокированных достижений =====
   Сервер возвращает {progress, progressMax} в items[] →
   /dashboard/summary → achievements (см. evaluateForUser в
   bot/services/achievements.js). Фронт использует эти данные,
   чтобы показать «следующий шаг» — например, 32/100 для
   Следопыта, 5/25 для Крепости.
   Размещаем под .achievement-desc, над .achievement-reward,
   чтобы не ломать существующий ритм бейджа. */
.achievement-badge .achievement-progress {
    width: 100%;
    margin-top: 8px;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 3px;
}
.achievement-badge .achievement-progress-track {
    position: relative;
    height: 6px;
    width: 100%;
    border-radius: 999px;
    background: var(--ach-track-bg, rgba(0, 0, 0, 0.08));
    overflow: hidden;
}
.achievement-badge .achievement-progress-fill {
    height: 100%;
    width: 0;
    border-radius: 999px;
    background: var(--ach-fg, #b45309);
    /* Лёгкий градиент тира → воспринимается как «прогресс к
       золоту/платине», а не как плоская заливка. */
    background-image: linear-gradient(
        90deg,
        color-mix(in srgb, var(--ach-fg, #b45309) 70%, transparent) 0%,
        var(--ach-fg, #b45309) 100%
    );
    transition: width 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.achievement-badge .achievement-progress-fill.is-complete {
    /* Готовое достижение — сплошная заливка тира, без градиента
       «незавершённости». */
    background-image: none;
    background: var(--ach-fg, #b45309);
}
.achievement-badge .achievement-progress-text {
    font-size: 9.5px;
    font-weight: 600;
    color: var(--text-muted, #888);
    text-align: center;
    letter-spacing: 0.2px;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}
.achievement-badge .achievement-progress.is-complete .achievement-progress-text {
    color: var(--ach-fg, #b45309);
    font-weight: 700;
}

/* Тёмная тема: чуть светлее фон дорожки, чтобы контраст
   с заливкой сохранялся на тёмном карточном фоне. */
body.dark-theme .achievement-badge .achievement-progress-track {
    background: rgba(255, 255, 255, 0.08);
}
body.dark-theme .achievement-badge .achievement-progress-text {
    color: rgba(255, 255, 255, 0.55);
}

/* ===== Тиры ===== */

/* Bronze */
.achievement-badge.achievement-tier-bronze {
    --ach-bg: rgba(180, 83, 9, 0.10);
    --ach-fg: #b45309;
    border-color: rgba(180, 83, 9, 0.35);
}
.achievement-badge.achievement-tier-bronze.is-unlocked {
    background: linear-gradient(180deg,
        color-mix(in srgb, #b45309 10%, var(--card-bg, #fff)),
        var(--card-bg, #fff));
}

/* Silver */
.achievement-badge.achievement-tier-silver {
    --ach-fg: #6b6b6b;
}
.achievement-badge.achievement-tier-silver.is-unlocked {
    background: linear-gradient(180deg,
        color-mix(in srgb, #6b7280 12%, var(--card-bg, #fff)),
        var(--card-bg, #fff));
}

/* Gold */
.achievement-badge.achievement-tier-gold {
    --ach-bg: rgba(245, 158, 11, 0.14);
    --ach-fg: #b45309;
    border-color: rgba(245, 158, 11, 0.5);
}
.achievement-badge.achievement-tier-gold.is-unlocked {
    background: linear-gradient(180deg,
        color-mix(in srgb, #f59e0b 16%, var(--card-bg, #fff)),
        var(--card-bg, #fff));
    box-shadow: 0 1px 2px rgba(245, 158, 11, 0.15),
                0 4px 14px rgba(245, 158, 11, 0.10);
}

/* Platinum */
.achievement-badge.achievement-tier-platinum {
    --ach-bg: rgba(139, 92, 246, 0.16);
    --ach-fg: #6d28d9;
    border-color: rgba(139, 92, 246, 0.55);
}
.achievement-badge.achievement-tier-platinum.is-unlocked {
    background: linear-gradient(180deg,
        color-mix(in srgb, #8b5cf6 18%, var(--card-bg, #fff)),
        var(--card-bg, #fff));
    box-shadow: 0 1px 2px rgba(139, 92, 246, 0.20),
                0 4px 18px rgba(139, 92, 246, 0.12);
}

/* Special (особые) */
.achievement-badge.achievement-tier-special {
    --ach-bg: rgba(236, 72, 153, 0.14);
    --ach-fg: #be185d;
    border-color: rgba(236, 72, 153, 0.5);
}
.achievement-badge.achievement-tier-special.is-unlocked {
    background: linear-gradient(180deg,
        color-mix(in srgb, #ec4899 16%, var(--card-bg, #fff)),
        var(--card-bg, #fff));
}

/* ===== Тёмная тема ===== */
body.dark-theme .achievement-badge {
    background: var(--card-bg, #1f2024);
    border-color: color-mix(in srgb, var(--input-border, #2c2e33) 80%, transparent);
}
body.dark-theme .achievement-badge .achievement-title {
    color: var(--text-color, #eee);
}
body.dark-theme .achievement-badge .achievement-desc {
    color: rgba(255, 255, 255, 0.55);
}
body.dark-theme .achievement-badge.is-locked .achievement-title,
body.dark-theme .achievement-badge.is-locked .achievement-desc {
    color: rgba(255, 255, 255, 0.35);
}
body.dark-theme .achievement-badge.achievement-tier-bronze.is-unlocked {
    background: linear-gradient(180deg,
        color-mix(in srgb, #b45309 22%, var(--card-bg, #1f2024)),
        var(--card-bg, #1f2024));
}
body.dark-theme .achievement-badge.achievement-tier-silver.is-unlocked {
    background: linear-gradient(180deg,
        color-mix(in srgb, #9ca3af 20%, var(--card-bg, #1f2024)),
        var(--card-bg, #1f2024));
}
body.dark-theme .achievement-badge.achievement-tier-gold.is-unlocked {
    background: linear-gradient(180deg,
        color-mix(in srgb, #f59e0b 24%, var(--card-bg, #1f2024)),
        var(--card-bg, #1f2024));
}
body.dark-theme .achievement-badge.achievement-tier-platinum.is-unlocked {
    background: linear-gradient(180deg,
        color-mix(in srgb, #8b5cf6 26%, var(--card-bg, #1f2024)),
        var(--card-bg, #1f2024));
}
body.dark-theme .achievement-badge.achievement-tier-special.is-unlocked {
    background: linear-gradient(180deg,
        color-mix(in srgb, #ec4899 24%, var(--card-bg, #1f2024)),
        var(--card-bg, #1f2024));
}

/* Анимация «празднования» для только что разблокированных.
   [P1 #9] Усилена: 3 повтора (вместо 2), более выраженное свечение
   с меняющимся цветом тира, лёгкое «дыхание» в финале. */
@keyframes achievement-celebrate {
    0%   { transform: scale(1)    rotate(0deg);
           box-shadow: 0 1px 2px rgba(0,0,0,0.06),
                       0 0 0 0 rgba(245, 158, 11, 0); }
    20%  { transform: scale(1.10) rotate(-2deg);
           box-shadow: 0 0 0 8px rgba(245, 158, 11, 0.22),
                       0 0 24px 4px rgba(245, 158, 11, 0.18); }
    40%  { transform: scale(0.98) rotate(2deg);
           box-shadow: 0 0 0 14px rgba(245, 158, 11, 0.10),
                       0 0 32px 6px rgba(245, 158, 11, 0.22); }
    60%  { transform: scale(1.05) rotate(-1deg);
           box-shadow: 0 0 0 18px rgba(245, 158, 11, 0.06),
                       0 0 28px 4px rgba(245, 158, 11, 0.16); }
    80%  { transform: scale(1.01) rotate(0.5deg);
           box-shadow: 0 0 0 20px rgba(245, 158, 11, 0.02); }
    100% { transform: scale(1)    rotate(0deg);
           box-shadow: 0 1px 2px rgba(0,0,0,0.06); }
}
.achievement-badge.is-celebrating {
    animation: achievement-celebrate 1.8s ease-out 0s 3;
    z-index: 2;
}
/* Контейнер сетки должен позволять свечению выходить за края. */
.achievement-grid {
    overflow: visible;
}

/* ===== P2 #14: Отдельный блок «Поддержка проекта» =====
   Кликабельная карточка для премиум-ачивок (покупка пакетов,
   пополнение баланса). В сводке показывает заголовок, подзаголовок
   и прогресс-бар; клик открывает модалку с полным списком
   премиум-ачивок. Визуально отделяется от основной сетки, чтобы
   не выглядело как pay-to-win — пользователь видит, что это
   отдельная категория, завязанная на поддержку.

   Цветовая схема единая с .widget-quests-summary /
   .widget-achievements-summary: амбер-градиент + декоративный
   блик + эмодзи-иконка в заголовке + прогресс-бар разблокировки.

   Раньше это был <details>, но раскрытие inline-контента ломалось
   в браузере из-за перебития браузерного скрытия вложенных
   элементов. Карточка переведена на обычный контейнер + модалку —
   см. public/app.js → openPremiumAchievementsModal. */
.achievement-premium-group {
    position: relative;
    margin-top: 16px;
    padding: 12px 14px;
    border-radius: 14px;
    background: linear-gradient(135deg,
        color-mix(in srgb, #b45309 14%, var(--card-bg, #ffffff)) 0%,
        color-mix(in srgb, #f59e0b 8%,  var(--card-bg, #ffffff)) 100%);
    border: 1px solid color-mix(in srgb, #b45309 25%, transparent);
    box-shadow: 0 2px 10px color-mix(in srgb, #b45309 15%, transparent),
                inset 0 1px 0 color-mix(in srgb, #ffffff 50%, transparent);
}
.achievement-premium-group::before {
    /* Декоративный блик в правом верхнем углу — единый с
       .widget-quests-summary / .widget-achievements-summary.
       clip-path обрезает блик по скруглённым углам группы. */
    content: "";
    position: absolute;
    top: -50%;
    right: -20%;
    width: 70%;
    height: 200%;
    background: radial-gradient(circle,
        color-mix(in srgb, #f59e0b 35%, transparent) 0%,
        transparent 65%);
    pointer-events: none;
    opacity: 0.4;
    z-index: 0;
    clip-path: inset(0 round 14px);
}
/* Контент поверх декоративного блика. */
.achievement-premium-group > * {
    position: relative;
    z-index: 1;
}

/* Шапка карточки — заголовок, подзаголовок и иконка «открыть»
   выстраиваются в одну строку через flex. */
.achievement-premium-group-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 4px 0;
    font-size: 12.5px;
    user-select: none;
}
.achievement-premium-group-title {
    flex: 0 0 auto;
    font-size: 12.5px;
    font-weight: 800;
    color: color-mix(in srgb, #b45309 75%, var(--text-color, #222));
    letter-spacing: 0.2px;
}
.achievement-premium-group-sub {
    flex: 1;
    font-size: 10.5px;
    color: color-mix(in srgb, #b45309 55%, var(--text-muted, #888));
    font-weight: 600;
    text-align: right;
}
/* Иконка «открыть» в правой части шапки. Раньше это был chevron
   <details>, теперь — иконка «expand» fa-up-right-from-square. */
.achievement-premium-group-chevron {
    margin-left: auto;
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    color: color-mix(in srgb, #b45309 75%, #ffffff);
    background: color-mix(in srgb, #b45309 12%, transparent);
    border-radius: 8px;
    transition:
        transform 0.2s ease,
        background 0.2s ease,
        color 0.2s ease;
}

/* Прогресс-бар разблокировки премиум-ачивок (тот же класс, что
   у summary-виджетов, для единого визуала). */
.achievement-premium-group-progress {
    margin-top: 10px;
    height: 6px;
    border-radius: 999px;
    background: color-mix(in srgb, #b45309 14%, transparent);
    overflow: hidden;
    box-shadow: inset 0 1px 2px color-mix(in srgb, #b45309 20%, transparent);
}
.achievement-premium-group-progress-fill {
    height: 100%;
    width: var(--quests-progress, 0%);
    background: linear-gradient(90deg, #b45309, #f59e0b);
    border-radius: 999px;
    box-shadow: 0 0 6px color-mix(in srgb, #f59e0b 60%, transparent);
    transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.achievement-premium-group-progress-text {
    margin-top: 5px;
    font-size: 10.5px;
    color: color-mix(in srgb, #b45309 70%, var(--text-color, #222));
    text-align: right;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

body.dark-theme .achievement-premium-group {
    background: linear-gradient(135deg,
        color-mix(in srgb, #b45309 22%, var(--card-bg, #1f2024)) 0%,
        color-mix(in srgb, #f59e0b 14%, var(--card-bg, #1f2024)) 100%);
}
body.dark-theme .achievement-premium-group-title {
    color: #fcd34d;
}
body.dark-theme .achievement-premium-group-sub {
    color: color-mix(in srgb, #f59e0b 50%, #cbd5e1);
}
body.dark-theme .achievement-premium-group-chevron {
    color: #fcd34d;
    background: color-mix(in srgb, #f59e0b 18%, transparent);
}
body.dark-theme .achievement-premium-group-progress {
    background: color-mix(in srgb, #b45309 25%, transparent);
}

/* ===== Кликабельная карточка «Поддержка проекта» =====
   В сводке дашборда карточка показывает шапку + прогресс-бар;
   сетка 7 премиум-ачивок скрыта (она показывается в модалке).
   Hover/focus подсвечивают карточку, чтобы было понятно, что
   по ней можно кликнуть. */
.achievement-premium-group-clickable {
    cursor: pointer;
    transition:
        transform 0.18s ease,
        box-shadow 0.18s ease,
        border-color 0.18s ease,
        background 0.18s ease;
}
.achievement-premium-group-clickable:hover {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, #b45309 45%, transparent);
    box-shadow:
        0 4px 16px color-mix(in srgb, #b45309 22%, transparent),
        inset 0 1px 0 color-mix(in srgb, #ffffff 50%, transparent);
}
.achievement-premium-group-clickable:active {
    transform: translateY(0);
}
.achievement-premium-group-clickable:focus-visible {
    outline: 2px solid color-mix(in srgb, #b45309 70%, transparent);
    outline-offset: 2px;
}
.achievement-premium-group-clickable:hover .achievement-premium-group-chevron {
    background: color-mix(in srgb, #b45309 24%, transparent);
    transform: scale(1.06);
}
.achievement-premium-group-clickable:hover .achievement-premium-group-chevron i {
    transform: translate(1px, -1px);
}
.achievement-premium-group-chevron i {
    transition: transform 0.2s ease;
}

/* Скрываем сетку ачивок в сводке — она показывается только в
   модалке #premiumAchievementsModal (см. .premium-achievements-modal-body). */
.dashboard-widget.widget-achievements
    .achievement-premium-group-clickable
    .achievement-grid-premium {
    display: none;
}

/* Премиум-сетка в модалке: естественная высота, без вложенного
   скролла — все 7 ачивок видны сразу. */
.premium-achievements-modal-body .achievement-grid-premium {
    display: grid;
    flex: 0 0 auto;
    overflow: visible;
    max-height: none;
    min-height: 0;
    margin-top: 4px;
}

/* ============================================================
 * Daily Quests (A3) — стили виджета «Квесты дня» в «Сводке».
 * ============================================================ */

/* Тонировка виджета переиспользует уже объявленный
   .widget-tint-amber (см. выше, около строки 6887) — единая
   янтарная палитра с виджетом «Достижения», чтобы .widget-icon
   и .widget-counter у обоих виджетов выглядели одинаково. */

.widget-quests .widget-body {
    padding-top: 4px;
    /* Сбрасываем базовый max-height:240px/overflow-y:auto от
       .widget-body — квестовый виджет должен расти на всю высоту
       своего контента без внутреннего скролла (по аналогии с
       .widget-daily-bonus). */
    max-height: none;
    overflow: visible;
}
.widget-quests-body {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* ============================================================
 * Виджет «Квесты дня» — растягивается на всю высоту контента.
 *
 * Раньше виджет был ограничен max-height: 640px, а .quest-list
 * имел overflow-y: auto и flex:1 — это прятало часть списка
 * квестов + welcome-блок за внутренним скроллом и делало
 * невозможным «увидеть всё одним взглядом». Теперь ограничения
 * сняты: виджет растёт по контенту, скроллбар внутри .quest-list
 * не появляется, вся страница продолжает скроллиться как обычно.
 *
 * Реализация:
 *   1. .dashboard-widget.widget-quests — без max-height.
 *   2. .widget-quests-body — flex-колонка, БЕЗ overflow,
 *      распределяет место между quest-list и summary.
 *   3. .quest-list — естественная высота контента, без скролла.
 *   4. .widget-quests-summary — flex:0 0 auto, всегда виден
 *      внизу body сразу под списком квестов.
 * ============================================================ */
.dashboard-widget.widget-quests {
    /* Без max-height — виджет растёт на всю высоту контента. */
    max-height: none;
}

/* Body больше не скроллится — он лишь flex-распределитель. */
.dashboard-widget.widget-quests .widget-body.widget-quests-body {
    flex: 1 1 auto;
    min-height: 0;
    /* Сбрасываем базовый overflow-y:auto и max-height:240px
       от .widget-body / .widget-quests .widget-body. */
    overflow: visible;
    max-height: none;
    /* Сбрасываем компенсационные padding/margin, чтобы
       прокручиваемая область точно совпадала с контентом. */
    margin: 0;
    padding: 4px 0 0 0;
}

/* Список квестов — естественная высота, БЕЗ внутреннего скролла.
   Контент: обычно 3–4 карточки квестов + опциональный welcome-блок.
   На всю страницу скролл работает снаружи .dashboard-widget. */
.dashboard-widget.widget-quests .quest-list {
    flex: 0 0 auto;
    min-height: 0;
    overflow: visible;
}

/* Сводка — статична внизу body, не участвует в скролле. */
.dashboard-widget.widget-quests .widget-quests-summary {
    flex: 0 0 auto;
}

/* Список квестов: вертикальный, по одному элементу на квест. */
.quest-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* Одна карточка квеста. */
.quest-card {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 12px 12px 12px;
    border-radius: 12px;
    border: 1px solid var(--input-border, #eaecef);
    background: var(--card-bg, #fff);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;

    /* Единая янтарная палитра для всех квестов — совпадает с
       .widget-tint-amber и achievement-tier-gold. Все акценты
       карточки (иконка, прогресс, кнопка Claim, звёзды,
       завершённая подсветка) тянутся из этих трёх переменных. */
    --quest-bg: rgba(245, 158, 11, 0.14);
    --quest-fg: #f59e0b;
    --quest-border: rgba(245, 158, 11, 0.40);
}
.quest-card:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08);
}

/* Категорийный акцент на левой границе карточки. */
.quest-card .quest-icon {
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    background: var(--quest-bg, rgba(139, 92, 246, 0.10));
    color: var(--quest-fg, #6d28d9);
    border: 1px solid var(--quest-border, rgba(139, 92, 246, 0.30));
}
.quest-card .quest-info {
    flex: 1 1 auto;
    min-width: 0;
}
.quest-card .quest-title {
    font-size: 12px;
    font-weight: 600;
    line-height: 1.25;
    color: var(--text-color, #222);
    margin-bottom: 4px;
    word-break: break-word;
}
.quest-card .quest-progress {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 11.5px;
    color: var(--text-muted, #888);
}

/* [GAM-RECO §2.5] Описание под прогрессом (был inline
   style="font-size:10.5px" в HTML, что ниже WCAG-минимума
   для мобильных). Вынесено в CSS, размер поднят до 12px.
   Цвет и отступ — из прежнего inline. */
.quest-card .quest-desc {
    font-size: 12px;
    color: var(--text-muted, #888);
    margin-top: 4px;
    line-height: 1.35;
}
.quest-card .quest-progress-bar {
    flex: 1 1 auto;
    height: 6px;
    background: rgba(0, 0, 0, 0.06);
    border-radius: 999px;
    overflow: hidden;
    position: relative;
}
.quest-card .quest-progress-fill {
    position: absolute;
    inset: 0;
    width: 0;
    /* Градиент от сильного цвета тира к его же, но смешанному
       с белым — повторяет приём из achievement-виджета, где
       фон карточки тонируется тем же тиром. */
    background: linear-gradient(90deg, #f59e0b 0%, #b45309 100%);
    border-radius: inherit;
    transition: width 0.4s ease, background 0.3s ease;
}

/* [GAM-RECO §2.2] Динамический цвет прогресс-бара по статусу.
   Применяется как к .quest-progress-fill в player-level-карточках,
   так и к .widget-quests-summary-progress-fill (в сводке уровня).
   • .is-near     — оранжевый при ≥80% (вот-вот level-up);
   • .is-complete — зелёный при ≥100% (level-up достигнут).
   Без модификаторов остаётся дефолтный янтарный (#f59e0b → #b45309).
   Для dark-theme чуть приглушаем зелёный, чтобы не «выжигал»
   глаза ночью. */
.quest-card .quest-progress-fill.is-near,
.widget-quests-summary-progress-fill.is-near {
    background: linear-gradient(90deg, #fb923c 0%, #ea580c 100%);
}
.quest-card .quest-progress-fill.is-complete,
.widget-quests-summary-progress-fill.is-complete {
    background: linear-gradient(90deg, #10b981 0%, #047857 100%);
}
body.dark-theme .quest-card .quest-progress-fill.is-near,
body.dark-theme .widget-quests-summary-progress-fill.is-near {
    background: linear-gradient(90deg, #f97316 0%, #c2410c 100%);
}
body.dark-theme .quest-card .quest-progress-fill.is-complete,
body.dark-theme .widget-quests-summary-progress-fill.is-complete {
    background: linear-gradient(90deg, #34d399 0%, #059669 100%);
}
body.dark-theme .quest-card .quest-progress-bar {
    background: rgba(255, 255, 255, 0.10);
}

/* Правая колонка: награда + кнопка Claim. */
.quest-card .quest-reward {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
}
.quest-card .quest-reward-stars {
    font-size: 12px;
    font-weight: 800;
    /* Цвет бейджа «+N★» — тир-окрашенный, как у achievement-reward. */
    color: var(--quest-fg);
    background: var(--quest-bg);
    padding: 2px 8px;
    border-radius: 999px;
    white-space: nowrap;
}
.quest-card .quest-claim-btn {
    font-size: 12px;
    font-weight: 700;
    color: #fff;
    /* Кнопка «Забрать» — янтарный градиент #f59e0b → #b45309. */
    background: linear-gradient(135deg, #f59e0b 0%, #b45309 100%);
    border: none;
    border-radius: 999px;
    padding: 6px 12px;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.quest-card .quest-claim-btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(180, 83, 9, 0.45);
}
.quest-card .quest-claim-btn:disabled {
    background: #aaa;
    cursor: not-allowed;
    box-shadow: none;
}

/* Бейджи состояния (выполнено / забрано). */
.quest-card .quest-state-badge {
    position: absolute;
    top: 6px;
    right: 8px;
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: 0.3px;
    padding: 2px 6px;
    border-radius: 6px;
    line-height: 1;
}
.quest-card.is-completed .quest-state-badge {
    background: linear-gradient(135deg, #10b981, #059669);
    color: #fff;
}
.quest-card.is-claimed .quest-state-badge {
    background: linear-gradient(135deg, #f59e0b, #d97706);
    color: #fff;
}
.quest-card.is-claimed .quest-claim-btn {
    display: none;
}
.quest-card.is-completed:not(.is-claimed) .quest-claim-btn {
    animation: quest-pulse 1.4s ease-in-out infinite;
}
@keyframes quest-pulse {
    /* Свечение кнопки «Забрать» в янтарной палитре (#f59e0b / #b45309). */
    0%, 100% {
        box-shadow: 0 4px 12px rgba(245, 158, 11, 0.40);
    }
    50% {
        box-shadow: 0 4px 22px rgba(245, 158, 11, 0.65);
    }
}

/* ===== Категорийные акценты =====
   [P1 #6] Раньше палитра виджета «Квесты» была единая янтарная
   для всех категорий. Теперь у каждой категории — свой акцентный
   цвет (через CSS-переменные на корневой .quest-card.quest-cat-*),
   чтобы взгляд сразу различал «гео» / «социалку» / «продукт» /
   «исследования» и пользователь легче ориентировался в 4 квестах.
   Цвета подобраны в тон существующим виджетам дашборда. */

/* GEO — фиолетовый (как у achievement-tier-platinum) */
.quest-card.quest-cat-geo {
    --quest-bg: rgba(139, 92, 246, 0.14);
    --quest-fg: #7c3aed;
    --quest-border: rgba(139, 92, 246, 0.40);
}
/* SOCIAL — синий (как у achievement-tier-silver) */
.quest-card.quest-cat-social {
    --quest-bg: rgba(59, 130, 246, 0.14);
    --quest-fg: #2563eb;
    --quest-border: rgba(59, 130, 246, 0.40);
}
/* PRODUCT — янтарный (как у achievement-tier-gold) — основной тон виджета */
.quest-card.quest-cat-product {
    --quest-bg: rgba(245, 158, 11, 0.14);
    --quest-fg: #f59e0b;
    --quest-border: rgba(245, 158, 11, 0.40);
}
/* EXPLORE — розовый (как у achievement-tier-special) */
.quest-card.quest-cat-explore {
    --quest-bg: rgba(236, 72, 153, 0.14);
    --quest-fg: #db2777;
    --quest-border: rgba(236, 72, 153, 0.40);
}
/* Дополнительный маленький бейдж категории в правом верхнем углу. */
.quest-card .quest-cat-badge {
    position: absolute;
    top: 6px;
    left: 8px;
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    padding: 2px 6px;
    border-radius: 6px;
    background: var(--quest-bg);
    color: var(--quest-fg);
    line-height: 1;
    opacity: 0.85;
}

/* Полностью завершённые/забранные — лёгкая прозрачность для акцента. */
.quest-card.is-completed {
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--quest-fg) 6%, var(--card-bg, #fff)),
        var(--card-bg, #fff));
}
.quest-card.is-claimed {
    opacity: 0.78;
}

/* ===== Базовые фоны карточек квестов =====
   Авторитетные правила фона (с !important), чтобы единый вид
   карточек не «плавал» в зависимости от порядка подключения
   стилей и состояний. Используем градиенты в тон тиру:
     • обычный квест         — нейтральный серый #6b7280
     • забранный (is-claimed) — янтарный #f59e0b, opacity 1
       (отменяет старую 0.78 — забранный квест должен выглядеть
       «полным», а не блёклым). */
.quest-card {
    background: linear-gradient(180deg,
        color-mix(in srgb, #6b7280 12%, var(--card-bg, #fff)),
        var(--card-bg, #fff)) !important;
}
.quest-card.is-claimed {
    opacity: 1;
    background: linear-gradient(180deg,
        color-mix(in srgb, #f59e0b 16%, var(--card-bg, #fff)),
        var(--card-bg, #fff)) !important;
}

/* ===== Тёмная тема ===== */
body.dark-theme .quest-card {
    background: var(--card-bg, #1f2024);
    border-color: color-mix(in srgb, var(--input-border, #2c2e33) 80%, transparent);
}
body.dark-theme .quest-card .quest-title {
    color: var(--text-color, #eee);
}
body.dark-theme .quest-card .quest-progress {
    color: rgba(255, 255, 255, 0.55);
}
body.dark-theme .quest-card.is-completed {
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--quest-fg) 14%, var(--card-bg, #1f2024)),
        var(--card-bg, #1f2024));
}

/* Сводная строка внизу виджета (по аналогии с achievements). */

/* ===== P2 #11: Welcome-back баннер и бейдж ×2 =====
   Показывается, если пользователь «вернулся» (streak==0 &&
   longest≥3 && последняя активность ≥3 дней назад). Баннер
   крупный, в фирменном розовом, чтобы сразу бросался в глаза.
   Бейдж «×2» рядом с наградой — компактное напоминание о бонусе. */
.widget-quests-welcome {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 10px 0;
    padding: 10px 14px;
    border-radius: 12px;
    background: linear-gradient(135deg,
        color-mix(in srgb, #ec4899 22%, var(--card-bg, #fff)),
        color-mix(in srgb, #f97316 16%, var(--card-bg, #fff)));
    border: 1px solid color-mix(in srgb, #ec4899 35%, transparent);
    color: #be185d;
    box-shadow: 0 2px 10px color-mix(in srgb, #ec4899 18%, transparent);
}
.widget-quests-welcome > i {
    font-size: 22px;
    color: #ec4899;
    flex: 0 0 auto;
}
.widget-quests-welcome-text {
    flex: 1 1 auto;
    min-width: 0;
    line-height: 1.25;
}
.widget-quests-welcome-title {
    font-size: 13px;
    font-weight: 800;
    letter-spacing: 0.1px;
}
.widget-quests-welcome-sub {
    font-size: 11px;
    font-weight: 600;
    opacity: 0.85;
    margin-top: 2px;
}
body.dark-theme .widget-quests-welcome {
    background: linear-gradient(135deg,
        color-mix(in srgb, #ec4899 30%, var(--card-bg, #1f2024)),
        color-mix(in srgb, #f97316 24%, var(--card-bg, #1f2024)));
    color: #fbcfe8;
}

/* [GAM-RECO §2.5] Превью «Завтра» — баннер со списком
   квестов на следующий день. Показывается за 1ч до полуночи
   в TZ пользователя. Использует синюю/индиго палитру, чтобы
   отличаться от welcome-back (розовый) и обычных карточек. */
.widget-quests-tomorrow {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0 0 12px 0;
    padding: 10px 12px 12px 12px;
    border-radius: 12px;
    background: linear-gradient(135deg,
        color-mix(in srgb, #6366f1 18%, var(--card-bg, #fff)),
        color-mix(in srgb, #8b5cf6 14%, var(--card-bg, #fff)));
    border: 1px solid color-mix(in srgb, #6366f1 32%, transparent);
    color: #4338ca;
    box-shadow: 0 2px 8px color-mix(in srgb, #6366f1 14%, transparent);
}
.widget-quests-tomorrow-header {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 800;
    letter-spacing: 0.1px;
}
.widget-quests-tomorrow-header > i {
    font-size: 18px;
    color: #6366f1;
    flex: 0 0 auto;
}
.widget-quests-tomorrow-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    list-style: none;
    margin: 0;
    padding: 0;
}
.widget-quests-tomorrow-item {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    line-height: 1.3;
    color: var(--text-color, #1f2937);
}
.widget-quests-tomorrow-item > i {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-size: 11px;
    color: #4338ca;
    background: color-mix(in srgb, #6366f1 12%, var(--card-bg, #fff));
    border: 1px solid color-mix(in srgb, #6366f1 28%, transparent);
}
.widget-quests-tomorrow-item .widget-quests-tomorrow-reward {
    margin-left: auto;
    font-size: 11.5px;
    font-weight: 800;
    color: #4338ca;
    background: color-mix(in srgb, #6366f1 14%, var(--card-bg, #fff));
    padding: 2px 8px;
    border-radius: 999px;
    white-space: nowrap;
}
.widget-quests-tomorrow-title {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
body.dark-theme .widget-quests-tomorrow {
    background: linear-gradient(135deg,
        color-mix(in srgb, #6366f1 28%, var(--card-bg, #1f2024)),
        color-mix(in srgb, #8b5cf6 22%, var(--card-bg, #1f2024)));
    color: #c7d2fe;
}
body.dark-theme .widget-quests-tomorrow-item {
    color: var(--text-color, #e5e7eb);
}
body.dark-theme .widget-quests-tomorrow-item > i,
body.dark-theme .widget-quests-tomorrow-item .widget-quests-tomorrow-reward {
    color: #c7d2fe;
    background: color-mix(in srgb, #6366f1 22%, var(--card-bg, #1f2024));
}

/* Маленький бейдж «×2» рядом с наградой в карточке. */
.quest-reward-double {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 999px;
    background: linear-gradient(135deg, #ec4899, #f97316);
    color: #fff;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.4px;
    vertical-align: middle;
    box-shadow: 0 2px 6px color-mix(in srgb, #ec4899 30%, transparent);
}

/* ============================================================
 * Сводка виджета «Квесты дня».
 *
 * Структура (рендерится из public/app.js → renderQuests):
 *   <div class="widget-quests-summary">
 *     <div class="widget-summary-line" data-icon="🎯">
 *       <span class="widget-summary-label">Всего за сегодня</span>
 *       <span class="widget-summary-value">38★</span>
 *     </div>
 *     <div class="widget-summary-line" data-icon="✅">
 *       <span class="widget-summary-label">Получено</span>
 *       <span class="widget-summary-value">12★</span>
 *     </div>
 *     <div class="widget-quests-summary-progress"><div class="widget-quests-summary-progress-fill" style="--quests-progress:32%"></div></div>
 *     <div class="widget-quests-summary-progress-text">32%</div>
 *   </div>
 *
 * Внешний вид: амбер-градиент в тон виджету, мягкая тень, иконка
 * слева у каждой строки, value в виде капсулы-чипа с белым текстом
 * на амбер-фоне, тонкий прогресс-бар и подпись с процентом.
 * Цвет фона/границы завязан на --card-bg через color-mix, чтобы
 * корректно адаптироваться к светлой/тёмной теме.
 * ============================================================ */
.widget-quests-summary,
.widget-achievements-summary {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0;
    padding: 12px 14px;
    margin-top: 10px;
    border-radius: 14px;
    background: linear-gradient(135deg,
        color-mix(in srgb, #b45309 14%, var(--card-bg, #ffffff)) 0%,
        color-mix(in srgb, #f59e0b 8%,  var(--card-bg, #ffffff)) 100%);
    border: 1px solid color-mix(in srgb, #b45309 25%, transparent);
    box-shadow: 0 2px 10px color-mix(in srgb, #b45309 15%, transparent),
                inset 0 1px 0 color-mix(in srgb, #ffffff 50%, transparent);
    overflow: hidden;
}

.widget-quests-summary::before,
.widget-achievements-summary::before {
    /* Декоративный блик в правом верхнем углу. */
    content: "";
    position: absolute;
    top: -50%;
    right: -20%;
    width: 70%;
    height: 200%;
    background: radial-gradient(circle,
        color-mix(in srgb, #f59e0b 35%, transparent) 0%,
        transparent 65%);
    pointer-events: none;
    opacity: 0.4;
    z-index: 0;
}

/* Контент поверх декоративного блика. */
.widget-quests-summary > *,
.widget-achievements-summary > * {
    position: relative;
    z-index: 1;
}

.widget-quests-summary .widget-summary-line,
.widget-achievements-summary .widget-summary-line {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 7px 0;
    font-size: 12.5px;
}

.widget-quests-summary .widget-summary-line + .widget-summary-line,
.widget-achievements-summary .widget-summary-line + .widget-summary-line {
    border-top: 1px solid color-mix(in srgb, #b45309 14%, transparent);
}

/* FA-иконка слева от label (fa-bullseye / fa-circle-check /
   fa-trophy / fa-coins). Рендерится как отдельный <i>-элемент
   в JS вместо ::before, чтобы корректно работать со шрифтом
   FontAwesome 6 Solid. */
.widget-quests-summary .widget-summary-icon,
.widget-achievements-summary .widget-summary-icon {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    line-height: 1;
    color: color-mix(in srgb, #b45309 75%, #ffffff);
    filter: drop-shadow(0 1px 1px color-mix(in srgb, #b45309 30%, transparent));
    transition: transform 0.2s ease;
}

.widget-quests-summary .widget-summary-line:hover .widget-summary-icon,
.widget-achievements-summary .widget-summary-line:hover .widget-summary-icon {
    transform: scale(1.08);
}

.widget-quests-summary .widget-summary-label,
.widget-achievements-summary .widget-summary-label {
    flex: 1;
    color: var(--text-color, #222);
    font-weight: 500;
}

.widget-quests-summary .widget-summary-value,
.widget-achievements-summary .widget-summary-value {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 3px 10px;
    border-radius: 999px;
    font-weight: 700;
    font-size: 11.5px;
    color: #ffffff;
    background: linear-gradient(135deg, #b45309, #f59e0b);
    box-shadow: 0 2px 4px color-mix(in srgb, #b45309 30%, transparent),
                inset 0 1px 0 color-mix(in srgb, #ffffff 30%, transparent);
}

.widget-quests-summary-progress {
    margin-top: 10px;
    height: 6px;
    border-radius: 999px;
    background: color-mix(in srgb, #b45309 14%, transparent);
    overflow: hidden;
    box-shadow: inset 0 1px 2px color-mix(in srgb, #b45309 20%, transparent);
}

.widget-quests-summary-progress-fill {
    height: 100%;
    width: var(--quests-progress, 0%);
    background: linear-gradient(90deg, #b45309, #f59e0b);
    border-radius: 999px;
    box-shadow: 0 0 6px color-mix(in srgb, #f59e0b 60%, transparent);
    transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1),
        background 0.3s ease, box-shadow 0.3s ease;
}

.widget-quests-summary-progress-text {
    margin-top: 5px;
    font-size: 10.5px;
    color: color-mix(in srgb, #b45309 70%, var(--text-color, #222));
    text-align: right;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* ============================================================
 * Единая палитра иконок виджета «Квесты дня».
 *
 * Все иконки внутри .widget-quests (заголовочная, на карточках
 * квестов, welcome-баннер и кольцо таймера) красятся в единый
 * амбер-градиент на основе #b45309 (Tailwind amber-700) →
 * #f59e0b (amber-500). Это перекрывает категорийные акценты
 * (quest-cat-*) и розовый welcome-баннер, чтобы блок выглядел
 * целостно.
 * ============================================================ */
.widget-quests .widget-icon {
    background: linear-gradient(135deg, #b45309, #f59e0b);
    color: #ffffff;
    box-shadow: 0 2px 8px color-mix(in srgb, #b45309 35%, transparent);
}
.widget-quests .quest-card .quest-icon {
    background: linear-gradient(135deg, #b45309, #f59e0b);
    color: #ffffff;
    border-color: color-mix(in srgb, #b45309 35%, transparent);
    box-shadow: 0 2px 6px color-mix(in srgb, #b45309 25%, transparent);
}
.widget-quests .quest-card .quest-icon > i {
    /* Иконка внутри бейджа — белая, чтобы читалась на амбер-фоне. */
    color: #ffffff;
    background: none;
    -webkit-background-clip: initial;
    background-clip: initial;
    -webkit-text-fill-color: #ffffff;
}
.widget-quests .quest-card .quest-reward-stars {
    /* Бейдж «+N★» — тот же амбер-градиент, что и иконки,
       через background-clip:text, чтобы цифры и звезда
       были залиты градиентом, а не лежали на цветной плашке. */
    color: transparent;
    background: linear-gradient(135deg, #b45309, #f59e0b);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    /* Лёгкая полупрозрачная плашка для читаемости на любом фоне. */
    padding: 2px 8px;
    border-radius: 999px;
    background-color: color-mix(in srgb, #b45309 10%, transparent);
}
.widget-quests .quest-card .quest-reward-stars > .quest-reward-double {
    /* Бейдж «×2» рядом с наградой — белая обводка и тон
       амбер-градиента через color, чтобы не терялся на
       полупрозрачной плашке. */
    color: #b45309;
    -webkit-text-fill-color: #b45309;
}
.widget-quests .widget-quests-welcome > i {
    /* Welcome-иконка красится тем же амбер-градиентом через
       background-clip:text, чтобы блок выглядел целостно. */
    background: linear-gradient(135deg, #b45309, #f59e0b);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}
.widget-quests .widget-quests-timer-ring-fill {
    /* SVG stroke принимает только сплошной цвет; используем
       базовый амбер-700 #b45309 (один из концов общего градиента). */
    stroke: #b45309;
}
.widget-quests .widget-quests-timer.is-warning .widget-quests-timer-ring-fill {
    stroke: #b45309;
}
.widget-quests .widget-quests-timer.is-urgent .widget-quests-timer-ring-fill {
    stroke: #b45309;
}

/* ============================================================
 * [P0 #3] Streak-виджет («🔥 N дней подряд»)
 * ============================================================ */

.widget-streak .widget-body {
    padding-top: 4px;
    max-height: 320px;
    overflow-y: auto;
}

.dashboard-widget.widget-streak .widget-body.widget-streak-body {
    display: flex;
    flex-direction: column;
    gap: 14px;
    /* Сбрасываем дефолтный .widget-body { max-height: 240px;
       overflow-y: auto } — иначе streak-виджет целиком обрезается
       по высоте, и блок streak-shield (добавленный в [P1 #12])
       частично не виден. Контент streak-виджета фиксированный
       (streak-current + week + next + upcoming + meta + shield),
       без необходимости скролла внутри виджета.

       Специфичность (0,4,0) намеренно выше, чем у
       .widget-streak .widget-body (0,2,0) — иначе «сброс»
       не перебивает правило с overflow-y:auto, и нижняя
       часть виджета (включая .streak-shield) обрезается. */
    max-height: none;
    overflow: visible;
}

/* Текущая серия: крупная цифра + иконка огня. */
.streak-current {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 14px 16px;
    border-radius: 14px;
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--widget-accent, #f97316) 16%, var(--card-bg, #fff)),
        var(--card-bg, #fff));
    border: 1px solid color-mix(in srgb, var(--widget-accent, #f97316) 30%, transparent);
    position: relative;
    overflow: hidden;
    min-height: 3rem;
}
.streak-current::after {
    /* Тёплый «свет» от огня. */
    content: "";
    position: absolute;
    top: -50%;
    right: -20%;
    width: 60%;
    height: 200%;
    background: radial-gradient(circle,
        color-mix(in srgb, var(--widget-accent, #f97316) 22%, transparent) 0%,
        transparent 60%);
    pointer-events: none;
}
.streak-flame {
    flex: 0 0 auto;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 28px;
    color: #fff;
    background: linear-gradient(135deg, #f97316, #ef4444);
    box-shadow: 0 4px 14px color-mix(in srgb, #f97316 40%, transparent),
                inset 0 -2px 6px rgba(0, 0, 0, 0.18);
    z-index: 1;
}
.streak-current-info {
    flex: 1 1 auto;
    min-width: 0;
    z-index: 1;
}
.streak-current-value {
    font-size: 32px;
    font-weight: 900;
    line-height: 1;
    color: var(--text-color, #222);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.5px;
}
.streak-current-label {
    font-size: 12px;
    color: var(--text-muted, #888);
    margin-top: 4px;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    font-weight: 600;
}

/* [GAM-RECO §3.1] Бейдж «🏆 рекорд: N» рядом с цифрой streak.
   Маленькая плашка с тёплым золотым акцентом — визуально отделяется
   от крупной цифры серии, но при этом не конкурирует с ней за
   внимание. Класс .is-record-run (когда текущая серия >= рекорда)
   добавляет лёгкую пульсацию и более насыщенный фон. */
.streak-best-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-top: 6px;
    padding: 3px 10px;
    border-radius: 999px;
    background: color-mix(in srgb, #fbbf24 16%, transparent);
    color: #b45309;
    font-size: 12px;
    font-weight: 700;
    line-height: 1.2;
    border: 1px solid color-mix(in srgb, #fbbf24 50%, transparent);
    align-self: flex-start;
    white-space: nowrap;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}
.streak-best-badge.is-record-run {
    background: linear-gradient(135deg,
        color-mix(in srgb, #fbbf24 28%, transparent),
        color-mix(in srgb, #f97316 22%, transparent));
    color: #7c2d12;
    border-color: color-mix(in srgb, #f59e0b 70%, transparent);
    box-shadow: 0 0 0 0 color-mix(in srgb, #fbbf24 60%, transparent);
    animation: streak-best-pulse 2.2s ease-out infinite;
}
@keyframes streak-best-pulse {
    0%   { box-shadow: 0 0 0 0   color-mix(in srgb, #fbbf24 50%, transparent); }
    60%  { box-shadow: 0 0 0 8px color-mix(in srgb, #fbbf24 0%, transparent); }
    100% { box-shadow: 0 0 0 0   color-mix(in srgb, #fbbf24 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
    .streak-best-badge.is-record-run {
        animation: none;
    }
}

/* [GAM-AUDIT #1.4] Тонкий текст-пояснение правила «активного дня»
   прямо в карточке streak-current, под лейблом «дней подряд».
   Цель — чтобы 90% пользователей узнали правило без клика по
   info-кнопке, которая визуально терялась в углу .widget-header.
   Полная версия по-прежнему доступна через popover (info-кнопка). */
.streak-current-hint {
    font-size: 11px;
    line-height: 1.35;
    color: color-mix(in srgb, var(--text-muted, #888) 92%, transparent);
    margin-top: 6px;
    max-width: 100%;
    /* Не даём переносу строки ломать подпись на узких экранах:
       разрешаем перенос по словам, но без переноса в середине
       равенства «квест или ачивка». */
    overflow-wrap: break-word;
    /* Тонкая левая «рельса», чтобы визуально привязать пояснение
       к правилу, а не к цифре streak'а. */
    border-left: 2px solid color-mix(in srgb, var(--widget-accent, #f97316) 45%, transparent);
    padding-left: 8px;
}

/* [P0 #7] Горизонтальная streak-дорожка «как в Duolingo / Strava»:
   7 кружочков по дням недели. Рендерится ОТДЕЛЬНОЙ СТРОКОЙ между
   .streak-current и .streak-next (не внутри streak-current), чтобы:
     • не конкурировать за место с цифрой серии на узких экранах;
     • не попадать под псевдоэлемент .streak-current::after
       (радиальный «тёплый свет»), который иначе рендерится поверх;
     • явно читаться как визуальный якорь всей недели на всю ширину.
   Внутри каждого <li>: .streak-week-dot (кружок) и .streak-week-label
   (подпись дня недели под ним).
   Состояния:
     • .is-active  — кружок залит градиентом огня;
     • .is-today   — пульсирующая обводка + лёгкое свечение;
     • .is-future  — приглушённый цвет (защита от кривых данных). */
.streak-week {
    list-style: none;
    margin: 0;
    padding: 10px 4px 6px;
    display: flex;
    gap: 8px;
    align-items: flex-end;
    justify-content: space-between;
    width: 100%;
    box-sizing: border-box;
    /* Безопасный z-index: гарантированно выше любых соседних
       псевдоэлементов и ::after блоков с position:absolute. */
    position: relative;
    z-index: 1;
}
.streak-week-day {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    font-size: 10px;
    line-height: 1;
    color: var(--text-muted, #888);
    user-select: none;
    cursor: default;
}
.streak-week-dot {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--widget-accent, #f97316) 14%, var(--card-bg, #fff));
    border: 2px solid color-mix(in srgb, var(--widget-accent, #f97316) 45%, transparent);
    box-sizing: border-box;
    transition: transform 0.18s ease, box-shadow 0.18s ease,
        background 0.18s ease, border-color 0.18s ease;
}
.streak-week-day.is-active .streak-week-dot {
    background: linear-gradient(135deg, #f97316, #ef4444);
    border-color: transparent;
    box-shadow: 0 0 0 2px color-mix(in srgb, #f97316 25%, transparent);
}
.streak-week-day.is-today .streak-week-dot {
    /* Пульсирующая обводка вокруг сегодняшнего кружка. */
    animation: streak-week-today-pulse 1.6s ease-in-out infinite;
}
.streak-week-day.is-today.is-active .streak-week-dot {
    box-shadow: 0 0 0 2px color-mix(in srgb, #f97316 30%, transparent),
                0 0 12px color-mix(in srgb, #f97316 60%, transparent);
}
.streak-week-day.is-future .streak-week-dot {
    opacity: 0.45;
}
.streak-week-label {
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    font-size: 10px;
    color: var(--text-muted, #888);
    white-space: nowrap;
}
.streak-week-day.is-active .streak-week-label,
.streak-week-day.is-today .streak-week-label {
    color: color-mix(in srgb, var(--widget-accent, #f97316) 80%, var(--text-color, #222));
}
/* Когда вся неделя пустая — подписи делаем чуть бледнее,
   чтобы визуально «дорожка» читалась как чистый старт. */
.streak-week.is-empty .streak-week-label {
    opacity: 0.7;
}
@keyframes streak-week-today-pulse {
    0%, 100% {
        box-shadow: 0 0 0 2px color-mix(in srgb, var(--widget-accent, #f97316) 22%, transparent);
    }
    50% {
        box-shadow: 0 0 0 5px color-mix(in srgb, var(--widget-accent, #f97316) 12%, transparent);
    }
}
/* Hover — лёгкое поднятие, чтобы дорожка ощущалась интерактивной
   (на тач-устройствах hover не сработает, ничего не сломается). */
.streak-week-day:hover .streak-week-dot {
    transform: scale(1.18);
}
@media (prefers-reduced-motion: reduce) {
    .streak-week-day.is-today .streak-week-dot,
    .streak-flame,
    .streak-current {
        animation: none !important;
    }
}
/* Доп. нижний отступ, чтобы дорожка не «упиралась» в border-radius
   виджета на любых экранах. */
.widget-streak-body .streak-week {
    margin-bottom: 2px;
}
/* Пульсация огня, когда streak > 0. */
.streak-flame {
    animation: streak-flame-pulse 2.2s ease-in-out infinite;
}
@keyframes streak-flame-pulse {
    0%, 100% {
        transform: scale(1) rotate(0deg);
        box-shadow: 0 4px 14px color-mix(in srgb, #f97316 40%, transparent);
    }
    50% {
        transform: scale(1.06) rotate(-2deg);
        box-shadow: 0 6px 22px color-mix(in srgb, #f97316 60%, transparent),
                    0 0 0 6px color-mix(in srgb, #f97316 18%, transparent);
    }
}

/* Блок «до следующей награды». */
.streak-next {
    padding: 10px 14px;
    border-radius: 12px;
    background: var(--widget-accent-soft, rgba(249, 115, 22, 0.14));
    border: 1px solid color-mix(in srgb, var(--widget-accent, #f97316) 20%, transparent);
}
.streak-next-label {
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted, #888);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 6px;
}
.streak-next-progress {
    display: flex;
    align-items: center;
    gap: 8px;
}
.streak-next-progress-track {
    flex: 1 1 auto;
    height: 8px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.08);
    overflow: hidden;
}
.streak-next-progress-fill {
    height: 100%;
    width: 0;
    background: linear-gradient(90deg, #f97316, #ef4444);
    border-radius: 999px;
    transition: width 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.streak-next-progress-text {
    flex: 0 0 auto;
    font-size: 11.5px;
    font-weight: 700;
    color: var(--text-color, #222);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
body.dark-theme .streak-next-progress-track {
    background: rgba(255, 255, 255, 0.10);
}

/* Метаданные: «рекорд: 12 дней», «последний активный: ...». */
.streak-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    font-size: 11px;
    color: var(--text-muted, #888);
}
.streak-meta .streak-meta-item {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.04);
}
body.dark-theme .streak-meta .streak-meta-item {
    background: rgba(255, 255, 255, 0.06);
}
/* Состояние «streak сломан» — подсветим иконку серым. */

/* [GAM-AUDIT #1.3] CTA-полоса для подавленного состояния
   «streak=0 + streak-week.is-empty». Заменяет собой пустоту
   дорожки первым онбординговым якорем «куда нажать». Появляется
   сразу под streak-week, чтобы визуально «отвечать» на пустые
   кружочки. Цвет — тёплый gold/amber, в тон streak-виджету;
   градиент + лёгкое свечение делают её заметнее .streak-meta,
   но без шумовой перегрузки. */
.streak-cta {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 10px;
    margin-bottom: 6px;
    padding: 12px 14px;
    border-radius: 14px;
    text-decoration: none;
    color: #6b3a00;
    background: linear-gradient(135deg,
        rgba(255, 196, 71, 0.28) 0%,
        rgba(255, 154, 71, 0.28) 100%);
    border: 1px solid rgba(255, 154, 71, 0.42);
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.55) inset,
        0 8px 18px -10px rgba(255, 154, 71, 0.55);
    transition:
        transform 0.18s ease,
        box-shadow 0.18s ease,
        background 0.18s ease,
        border-color 0.18s ease;
    cursor: pointer;
    position: relative;
    overflow: hidden;
}
.streak-cta::before {
    /* Лёгкий «световой луч» слева — даёт CTA ощущение
       энергии/старта, но не отвлекает от основного числа
       streak. Скрывается при prefers-reduced-motion. */
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        90deg,
        rgba(255, 255, 255, 0.0) 0%,
        rgba(255, 255, 255, 0.35) 50%,
        rgba(255, 255, 255, 0.0) 100%
    );
    transform: translateX(-100%);
    animation: streak-cta-shine 2.8s ease-in-out infinite;
    pointer-events: none;
}
@keyframes streak-cta-shine {
    0%   { transform: translateX(-100%); }
    60%  { transform: translateX(120%); }
    100% { transform: translateX(120%); }
}
.streak-cta:hover,
.streak-cta:focus-visible {
    transform: translateY(-1px);
    border-color: rgba(255, 154, 71, 0.7);
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.55) inset,
        0 12px 22px -10px rgba(255, 154, 71, 0.7);
    background: linear-gradient(135deg,
        rgba(255, 196, 71, 0.36) 0%,
        rgba(255, 154, 71, 0.36) 100%);
    outline: none;
}
.streak-cta:focus-visible {
    /* Контрастный focus-ring для клавиатурной навигации. */
    box-shadow:
        0 0 0 3px rgba(255, 154, 71, 0.45),
        0 1px 0 rgba(255, 255, 255, 0.55) inset,
        0 12px 22px -10px rgba(255, 154, 71, 0.7);
}
.streak-cta-icon {
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 22px;
    line-height: 1;
    border-radius: 50%;
    background: linear-gradient(135deg, #ffd166 0%, #ff9a47 100%);
    color: #4a2700;
    box-shadow:
        0 4px 10px -4px rgba(255, 154, 71, 0.7),
        0 0 0 3px rgba(255, 255, 255, 0.4);
}
.streak-cta-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    line-height: 1.3;
}
.streak-cta-title {
    font-size: 13.5px;
    font-weight: 600;
    color: #4a2700;
}
.streak-cta-reward {
    font-size: 12px;
    font-weight: 500;
    color: #7a3e00;
    opacity: 0.92;
}
.streak-cta-arrow {
    flex: 0 0 auto;
    font-size: 18px;
    color: #7a3e00;
    opacity: 0.85;
    transition: transform 0.18s ease;
}
.streak-cta:hover .streak-cta-arrow,
.streak-cta:focus-visible .streak-cta-arrow {
    transform: translateX(3px);
}
.streak-cta[hidden] {
    display: none !important;
}

/* Тёмная тема: инвертируем контраст, но сохраняем
   «тёплую энергию» amber-палитры. */
body.dark-theme .streak-cta {
    color: #ffe8c8;
    background: linear-gradient(135deg,
        rgba(255, 168, 76, 0.22) 0%,
        rgba(255, 122, 47, 0.22) 100%);
    border-color: rgba(255, 168, 76, 0.55);
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.07) inset,
        0 10px 22px -12px rgba(255, 122, 47, 0.55);
}
body.dark-theme .streak-cta:hover,
body.dark-theme .streak-cta:focus-visible {
    border-color: rgba(255, 168, 76, 0.8);
    background: linear-gradient(135deg,
        rgba(255, 168, 76, 0.30) 0%,
        rgba(255, 122, 47, 0.30) 100%);
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.07) inset,
        0 14px 26px -12px rgba(255, 122, 47, 0.7);
}
body.dark-theme .streak-cta-title {
    color: #fff1d8;
}
body.dark-theme .streak-cta-reward,
body.dark-theme .streak-cta-arrow {
    color: #ffd5a1;
}

/* prefers-reduced-motion: убираем shine-анимацию и подъём
   на hover (см. также tier 6.9 основного tech-debt). */
@media (prefers-reduced-motion: reduce) {
    .streak-cta::before {
        animation: none;
    }
    .streak-cta,
    .streak-cta-arrow {
        transition: none;
    }
    .streak-cta:hover,
    .streak-cta:focus-visible {
        transform: none;
    }
    .streak-cta:hover .streak-cta-arrow,
    .streak-cta:focus-visible .streak-cta-arrow {
        transform: none;
    }
}

/* [GAM-AUDIT #1.3] Подсветка виджета-квестов на 2 секунды после
   клика по CTA — пользователь должен физически увидеть, куда
   «приземлился» якорь, а не гадать «оно проскроллило или нет». */
#widget-quests[data-streak-cta-target="1"] {
    animation: streak-cta-target-flash 1.6s ease-out 0s 1;
    scroll-margin-top: 80px;
}
@keyframes streak-cta-target-flash {
    0% {
        box-shadow: 0 0 0 0 rgba(255, 168, 76, 0);
    }
    20% {
        box-shadow: 0 0 0 4px rgba(255, 168, 76, 0.55);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(255, 168, 76, 0);
    }
}

/* Иконка-подсказка «?» в шапке виджета: правило активного дня.
   h3 имеет flex:1, поэтому кнопка естественно прижимается
   справа к счётчику .widget-counter. */
.streak-info-btn {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--text-muted, #888);
    font-size: 14px;
    cursor: help;
    padding: 0;
    transition: color 0.15s ease, background 0.15s ease;
    /* Подсветка-кольцо под кнопкой для пульсирующей анимации.
       По умолчанию прозрачная, проявляется в keyframes. */
    position: relative;
    will-change: transform, box-shadow;
}
.streak-info-btn:hover,
.streak-info-btn:focus-visible {
    color: var(--widget-accent, #f97316);
    background: color-mix(in srgb, var(--widget-accent, #f97316) 14%, transparent);
    outline: none;
}

/* Пульсирующая анимация: мягкое кольцо-свечение вокруг кнопки,
   привлекающее внимание к подсказке. Запускается с задержкой 1.5s
   после загрузки, чтобы не отвлекать на первых секундах.
   Когда popover открыт — анимация приостановлена, чтобы не
   раздражать пользователя, который читает текст. */
.streak-info-btn:not([aria-expanded="true"]):not(:hover):not(:focus-visible) {
    animation: streak-info-pulse 2.4s ease-in-out 1.5s infinite;
}
.streak-info-btn:hover,
.streak-info-btn:focus-visible {
    animation: streak-info-pulse 1.2s ease-in-out infinite;
}
.streak-info-btn[aria-expanded="true"] {
    /* Popover открыт — останавливаем пульсацию. */
    animation: none !important;
    color: var(--widget-accent, #f97316);
    background: color-mix(in srgb, var(--widget-accent, #f97316) 14%, transparent);
}

@keyframes streak-info-pulse {
    0%, 100% {
        transform: scale(1);
        box-shadow:
            0 0 0 0 color-mix(in srgb, var(--widget-accent, #f97316) 45%, transparent);
        color: var(--text-muted, #888);
    }
    50% {
        transform: scale(1.12);
        box-shadow:
            0 0 0 6px color-mix(in srgb, var(--widget-accent, #f97316) 0%, transparent);
        color: var(--widget-accent, #f97316);
    }
}

/* Уважаем prefers-reduced-motion: без анимаций. */
@media (prefers-reduced-motion: reduce) {
    .streak-info-btn {
        animation: none !important;
    }
}

/* Заголовок строки + награда в блоке «до следующей награды». */
.streak-next-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 6px;
}

/* Размер награды за ближайший milestone: «Награда: +25 ★». */
.streak-next-reward {
    flex: 0 0 auto;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.1px;
    padding: 2px 8px;
    border-radius: 999px;
    background: linear-gradient(135deg, #fde68a, #f59e0b);
    color: #7c2d12;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    box-shadow: 0 1px 4px color-mix(in srgb, #f59e0b 30%, transparent);
}
.streak-next-reward[hidden] {
    display: none;
}
body.dark-theme .streak-next-reward {
    background: linear-gradient(135deg, #fbbf24, #d97706);
    color: #1f1300;
    box-shadow: 0 1px 6px color-mix(in srgb, #f59e0b 40%, transparent);
}

/* Список ближайших streak-наград (чипы). */
.streak-upcoming {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.streak-upcoming[hidden] {
    display: none;
}
.streak-upcoming-label {
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted, #888);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.streak-upcoming-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.streak-upcoming-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11.5px;
    font-weight: 700;
    padding: 4px 9px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.04);
    color: var(--text-color, #222);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #f97316) 20%, transparent);
    font-variant-numeric: tabular-nums;
    transition: background 0.18s ease, transform 0.18s ease;
}
.streak-upcoming-chip i {
    color: #f59e0b;
    font-size: 10px;
}
/* Следующая по счёту награда — ярче, чтобы мотивировать. */
.streak-upcoming-chip.is-next {
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--widget-accent, #f97316) 18%, var(--card-bg, #fff)),
        var(--card-bg, #fff));
    border-color: color-mix(in srgb, var(--widget-accent, #f97316) 45%, transparent);
    box-shadow: 0 1px 6px color-mix(in srgb, var(--widget-accent, #f97316) 22%, transparent);
}
/* Уже полученная награда — зачёркнуто / приглушённо. */
.streak-upcoming-chip.is-done {
    opacity: 0.55;
    text-decoration: line-through;
}
body.dark-theme .streak-upcoming-chip {
    background: rgba(255, 255, 255, 0.06);
}
body.dark-theme .streak-upcoming-chip.is-next {
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--widget-accent, #f97316) 28%, transparent),
        rgba(255, 255, 255, 0.04));
}

/* Поздравление, когда все streak-ачивки получены. */
.streak-upcoming-empty {
    font-size: 12px;
    font-weight: 700;
    color: #f59e0b;
    padding: 4px 0;
}

/* Скрытый текст для screen-reader'ов (правило активного дня). */
.sr-only {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

/* Popover с правилом «активного дня».
   Раскрывается по клику на .streak-info-btn.
   Позиционируется через position:fixed (top/left вычисляются
   в JS через getBoundingClientRect), потому что .dashboard-widget
   имеет overflow:hidden ради скруглённых углов — это обрезало бы
   любой «внутренний» absolute-popover. */
.streak-info-popover {
    position: fixed;
    z-index: 9999;
    min-width: 260px;
    max-width: min(320px, calc(100vw - 32px));
    padding: 12px 14px;
    border-radius: 12px;
    background: var(--card-bg, #fff);
    color: var(--text-color, #222);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #f97316) 30%, transparent);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18),
                0 2px 6px rgba(0, 0, 0, 0.08);
    text-align: left;
    font-size: 12px;
    line-height: 1.45;
    /* По умолчанию скрыт + плавная анимация появления.
       Координаты top/left выставляются из JS. */
    opacity: 0;
    transform: translateY(-6px) scale(0.98);
    pointer-events: none;
    transition: opacity 0.16s ease, transform 0.16s ease;
}
.streak-info-popover[aria-hidden="false"] {
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: auto;
}

/* Стрелочка popover, указывает вверх на кнопку «?».
   По умолчанию стрелка сверху-справа (popover под кнопкой
   с right-alignment). JS переставляет её влево, если popover
   оказался у левого края кнопки. */
.streak-info-popover-arrow {
    position: absolute;
    top: -7px;
    width: 12px;
    height: 12px;
    background: var(--card-bg, #fff);
    border-top: 1px solid color-mix(in srgb, var(--widget-accent, #f97316) 30%, transparent);
    border-left: 1px solid color-mix(in srgb, var(--widget-accent, #f97316) 30%, transparent);
    transform: rotate(45deg);
}
.streak-info-popover-arrow.is-left {
    /* Используется, когда popover выравнивается по левому краю
       кнопки (например, на узких экранах). */
    left: 18px !important;
    right: auto !important;
}

.streak-info-popover-title {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 800;
    color: var(--widget-accent, #f97316);
    margin-bottom: 6px;
    text-transform: none;
    letter-spacing: 0;
}
.streak-info-popover-title i {
    font-size: 13px;
}
.streak-info-popover-body {
    color: var(--text-color, #222);
}

/* Dark theme — чуть более тёмный фон, чтобы не слепил ночью. */
body.dark-theme .streak-info-popover {
    background: #1f2937;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5),
                0 2px 6px rgba(0, 0, 0, 0.3);
}
body.dark-theme .streak-info-popover-arrow {
    background: #1f2937;
}

/* ============================================================
 * [P0 #4] Кастомный popover для бейджей ачивок.
 * Заменил нативный HTML title=... (медленный, не работает на
 * тапе в мобильном WebApp) на реактивный popover. По
 * структуре повторяет .streak-info-popover (position:fixed +
 * перенос в <body> при открытии), но шире — чтобы вместить
 * описание + блок «Награда / Дата» + 1-2 кнопки действия.
 * ============================================================ */
.achievement-badge-popover {
    position: fixed;
    z-index: 9999;
    /* popover бывает разной ширины: для 1-2 строк описания
       достаточно ~260, для длинных подсказок расширяемся до 340,
       но не шире viewport - 16 (по 8px отступы). */
    width: min(340px, calc(100vw - 16px));
    max-width: calc(100vw - 16px);
    padding: 14px 16px 12px 16px;
    border-radius: 14px;
    background: var(--card-bg, #fff);
    color: var(--text-color, #222);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #f59e0b) 32%, transparent);
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.20),
                0 2px 6px rgba(0, 0, 0, 0.10);
    text-align: left;
    font-size: 13px;
    line-height: 1.45;
    /* По умолчанию скрыт + плавная анимация появления.
       Координаты top/left выставляются из JS. */
    opacity: 0;
    transform: translateY(-6px) scale(0.98);
    pointer-events: none;
    transition: opacity 0.16s ease, transform 0.16s ease;
}
.achievement-badge-popover[aria-hidden="false"] {
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: auto;
}

/* Стрелочка popover — такая же логика, как у
   .streak-info-popover-arrow: по умолчанию сверху, при
   перевороте вниз. JS задаёт inline-стили для нижнего
   положения, чтобы не плодить классы. */
.achievement-badge-popover-arrow {
    position: absolute;
    top: -7px;
    width: 12px;
    height: 12px;
    background: var(--card-bg, #fff);
    border-top: 1px solid color-mix(in srgb, var(--widget-accent, #f59e0b) 32%, transparent);
    border-left: 1px solid color-mix(in srgb, var(--widget-accent, #f59e0b) 32%, transparent);
    transform: rotate(45deg);
}

.achievement-badge-popover-header {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px;
}
.achievement-badge-popover-icon {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--widget-accent, #f59e0b) 14%, transparent);
    color: var(--widget-accent, #f59e0b);
    font-size: 16px;
    flex-shrink: 0;
}
.achievement-badge-popover-title-wrap {
    min-width: 0;
    flex: 1;
}
.achievement-badge-popover-title {
    font-size: 14px;
    font-weight: 800;
    color: var(--text-color, #222);
    line-height: 1.25;
    word-break: break-word;
}
.achievement-badge-popover-tier {
    font-size: 11px;
    font-weight: 700;
    color: var(--widget-accent, #f59e0b);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-top: 2px;
}

.achievement-badge-popover-body {
    color: var(--text-color, #222);
    font-size: 12.5px;
    line-height: 1.5;
    margin-bottom: 8px;
    word-break: break-word;
}

.achievement-badge-popover-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 8px;
    font-size: 11.5px;
}
.achievement-badge-popover-meta > span {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--widget-accent, #f59e0b) 10%, transparent);
    color: var(--text-color, #222);
    font-weight: 600;
}
.achievement-badge-popover-reward i {
    color: #f59e0b;
}
.achievement-badge-popover-date i {
    color: var(--widget-accent, #f59e0b);
}

.achievement-badge-popover-hint {
    margin-bottom: 10px;
    padding: 8px 10px;
    border-radius: 10px;
    background: color-mix(in srgb, #fbbf24 12%, transparent);
    color: var(--text-color, #222);
    font-size: 12px;
    line-height: 1.4;
    display: flex;
    gap: 6px;
    align-items: flex-start;
}
.achievement-badge-popover-hint i {
    color: #f59e0b;
    margin-top: 2px;
    flex-shrink: 0;
}

/* Блок действий: 1-2 кнопки в ряд. На узких экранах
   перестраиваются в колонку. */
.achievement-badge-popover-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}
.achievement-badge-popover-btn {
    flex: 1;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 10px;
    border: 1px solid color-mix(in srgb, var(--widget-accent, #f59e0b) 32%, transparent);
    border-radius: 10px;
    background: var(--card-bg, #fff);
    color: var(--widget-accent, #f59e0b);
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.14s ease, transform 0.14s ease;
    -webkit-tap-highlight-color: transparent;
}
.achievement-badge-popover-btn:hover,
.achievement-badge-popover-btn:focus-visible {
    background: color-mix(in srgb, var(--widget-accent, #f59e0b) 10%, transparent);
    outline: none;
}
.achievement-badge-popover-btn:active {
    transform: scale(0.97);
}
.achievement-badge-popover-btn--share {
    background: var(--widget-accent, #f59e0b);
    color: #fff;
    border-color: transparent;
}
.achievement-badge-popover-btn--share:hover,
.achievement-badge-popover-btn--share:focus-visible {
    background: color-mix(in srgb, var(--widget-accent, #f59e0b) 88%, #000 12%);
    color: #fff;
}

/* Кнопка-крестик в углу popover — закрывает его. Не критично,
   клик вне / Esc тоже работает, но для UX явный close полезен. */
.achievement-badge-popover-close {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 26px;
    height: 26px;
    border: 0;
    background: transparent;
    color: color-mix(in srgb, var(--text-color, #222) 60%, transparent);
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.achievement-badge-popover-close:hover,
.achievement-badge-popover-close:focus-visible {
    background: color-mix(in srgb, var(--text-color, #222) 10%, transparent);
    color: var(--text-color, #222);
    outline: none;
}

/* Dark theme — чуть более тёмный фон, чтобы не слепил ночью. */
body.dark-theme .achievement-badge-popover {
    background: #1f2937;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.55),
                0 2px 6px rgba(0, 0, 0, 0.35);
}
body.dark-theme .achievement-badge-popover-arrow {
    background: #1f2937;
}
body.dark-theme .achievement-badge-popover-btn {
    background: #1f2937;
}
body.dark-theme .achievement-badge-popover-btn--share {
    background: var(--widget-accent, #f59e0b);
    color: #111;
}

/* ============================================================
 * [P2 #10] Timeline-виджет «Лента событий»
 * ============================================================
 * Вертикальная лента с цветными точками-маркерами для типов
 * событий: 🏆 ачивка, ⚡ квест. Дата справа, мелким шрифтом.
 */

.widget-activity .widget-body {
    padding-top: 4px;
    max-height: 360px;
    overflow-y: auto;
}

/* [fix/daily-bonus-widget-full-height] Ограничиваем высоту виджета
   «Лента событий» вдвое (360px → 180px): при 10+ событиях лента
   занимала ~340px и вытесняла соседние блоки. С 180px виден стартовый
   блок событий + работает вертикальный скролл внутри виджета.
   Специфичность (0,4,0) перебивает .widget-activity .widget-body (0,2,0). */
.dashboard-widget.widget-activity .widget-body.widget-activity-body {
    max-height: 180px;
    overflow-y: auto;
}

.activity-timeline {
    list-style: none;
    margin: 0;
    padding: 0;
    position: relative;
}
/* Вертикальная линия ленты. */
.activity-timeline::before {
    content: "";
    position: absolute;
    left: 15px;
    top: 6px;
    bottom: 6px;
    width: 2px;
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--widget-accent, #94a3b8) 30%, transparent),
        color-mix(in srgb, var(--widget-accent, #94a3b8) 8%, transparent));
    border-radius: 1px;
}

.activity-event {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 8px 8px 4px;
    border-radius: 10px;
    transition: background 0.18s ease;
}
.activity-event:hover {
    background: var(--widget-accent-soft, rgba(148, 163, 184, 0.10));
}
.activity-event + .activity-event {
    margin-top: 2px;
}

.activity-event-marker {
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    color: #fff;
    background: var(--widget-accent, #94a3b8);
    box-shadow: 0 0 0 3px var(--card-bg, #fff);
    z-index: 1;
}
.activity-event.is-achievement .activity-event-marker {
    background: linear-gradient(135deg, #f59e0b, #ef4444);
}
.activity-event.is-quest .activity-event-marker {
    background: linear-gradient(135deg, #8b5cf6, #3b82f6);
}

.activity-event-body {
    flex: 1 1 auto;
    min-width: 0;
    line-height: 1.25;
}
.activity-event-title {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-color, #222);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.activity-event-reward {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--widget-accent-soft, rgba(245, 158, 11, 0.14));
    color: var(--widget-accent, #f59e0b);
    font-size: 10px;
    font-weight: 800;
    vertical-align: middle;
}

.activity-event-time {
    flex: 0 0 auto;
    font-size: 10.5px;
    color: var(--text-muted, #888);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.activity-empty {
    text-align: center;
    color: color-mix(in srgb, var(--text-color, #222) 50%, transparent);
    font-size: 12.5px;
    padding: 16px 0 8px 0;
}
.activity-empty i {
    display: block;
    font-size: 22px;
    margin-bottom: 6px;
    opacity: 0.6;
}

/* ============================================================
 * [P2 #15] Weekly Leaderboard — топ-10 по ★ за 7 дней
 * ============================================================
 * Список-пьедестал: 1-3 место с цветными «медалями», остальные
 * с цифрами. Текущий пользователь выделен отдельным классом.
 */

.widget-leaderboard .widget-body {
    padding-top: 4px;
    max-height: 360px;
    overflow-y: auto;
}

.leaderboard-list {
    list-style: none;
    margin: 0;
    padding: 0;
    counter-reset: lb;
}

.leaderboard-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border-radius: 12px;
    border: 1px solid color-mix(in srgb, var(--widget-accent, #f69a00) 12%, transparent);
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--widget-accent, #f69a00) 4%, var(--card-bg, #fff)) 0%,
        var(--card-bg, #fff) 100%);
    transition: background 0.18s ease, border-color 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease;
    counter-increment: lb;
}
.leaderboard-item + .leaderboard-item {
    margin-top: 6px;
}
.leaderboard-item:hover {
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--widget-accent, #f69a00) 12%, var(--card-bg, #fff)) 0%,
        color-mix(in srgb, var(--widget-accent, #f69a00) 6%,  var(--card-bg, #fff)) 100%);
    border-color: color-mix(in srgb, var(--widget-accent, #f69a00) 28%, transparent);
    transform: translateX(2px);
}
.leaderboard-item.is-me {
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--widget-accent, #f69a00) 18%, var(--card-bg, #fff)) 0%,
        color-mix(in srgb, var(--widget-accent, #f69a00) 8%,  var(--card-bg, #fff)) 100%);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #f69a00) 40%, transparent);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--widget-accent, #f69a00) 20%, transparent);
}

.leaderboard-rank {
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 900;
    background: rgba(0, 0, 0, 0.06);
    color: var(--text-muted, #888);
    font-variant-numeric: tabular-nums;
}
/* Топ-3 — медальные цвета. */
.leaderboard-item:nth-child(1) .leaderboard-rank {
    background: linear-gradient(135deg, #fbbf24, #f59e0b);
    color: #fff;
    box-shadow: 0 2px 8px color-mix(in srgb, #f69a00 40%, transparent);
}
.leaderboard-item:nth-child(2) .leaderboard-rank {
    background: linear-gradient(135deg, #d1d5db, #9ca3af);
    color: #fff;
    box-shadow: 0 2px 6px color-mix(in srgb, #9ca3af 35%, transparent);
}
.leaderboard-item:nth-child(3) .leaderboard-rank {
    background: linear-gradient(135deg, #f59e0b, #b45309);
    color: #fff;
    box-shadow: 0 2px 6px color-mix(in srgb, #b45309 35%, transparent);
}
.leaderboard-item:nth-child(1) .leaderboard-rank::before { content: "🥇"; }
.leaderboard-item:nth-child(2) .leaderboard-rank::before { content: "🥈"; }
.leaderboard-item:nth-child(3) .leaderboard-rank::before { content: "🥉"; }
.leaderboard-item:nth-child(1) .leaderboard-rank,
.leaderboard-item:nth-child(2) .leaderboard-rank,
.leaderboard-item:nth-child(3) .leaderboard-rank {
    font-size: 0;        /* цифру прячем, оставляем эмодзи */
    line-height: 1;
}
.leaderboard-item:nth-child(1) .leaderboard-rank::before,
.leaderboard-item:nth-child(2) .leaderboard-rank::before,
.leaderboard-item:nth-child(3) .leaderboard-rank::before {
    font-size: 14px;
}

.leaderboard-name {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-color, #222);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.leaderboard-name .leaderboard-me-tag {
    margin-left: 6px;
    display: inline-flex;
    align-items: center;
    height: 16px;
    padding: 0 7px;
    font-size: 9.5px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    color: #fff;
    background: linear-gradient(135deg, #f69a00, #d97706);
    border-radius: 999px;
    box-shadow: 0 1px 3px color-mix(in srgb, #f69a00 35%, transparent);
}

.leaderboard-stars {
    flex: 0 0 auto;
    font-size: 12.5px;
    font-weight: 800;
    color: #f69a00;
    font-variant-numeric: tabular-nums;
}

.leaderboard-empty {
    text-align: center;
    color: color-mix(in srgb, var(--text-color, #222) 50%, transparent);
    font-size: 12.5px;
    padding: 16px 0;
}
.leaderboard-empty i {
    display: block;
    font-size: 22px;
    margin-bottom: 6px;
    opacity: 0.6;
}

/* ============================================================
 * [P0 #1 REC] Тоггл периода в виджете лидерборда (Неделя /
 * Месяц / Всё время). Материал-3 стиль: капсула с
 * подсвеченной активной кнопкой. Не ломает узкую тему.
 * ============================================================ */
.widget-leaderboard-toolbar {
    padding: 0 4px 8px 4px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
    flex-wrap: wrap;
}
.widget-leaderboard-period {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 0px 16px;
    margin: 0 auto;
    border-radius: 12px;
    background: linear-gradient(180deg,
        color-mix(in srgb, #6b7280 12%, var(--card-bg, #fff)), var(--card-bg, #fff)) !important;
    border: 1px solid color-mix(in srgb, var(--widget-accent, #f69a00) 18%, transparent);
    box-shadow: inset 0 1px 2px color-mix(in srgb, #000 6%, transparent);
}
.widget-leaderboard-period-btn {
    appearance: none;
    -webkit-appearance: none;
    border: 0;
    background: transparent;
    color: var(--text-color, #222);
    font: inherit;
    font-size: 11.5px;
    font-weight: 700;
    line-height: 1;
    padding: 7px 12px;
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.18s ease, color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
    white-space: nowrap;
    /* Подсветка касания на мобильном */
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}
.widget-leaderboard-period-btn:hover {
    background: color-mix(in srgb, var(--widget-accent, #f69a00) 12%, transparent);
}
.widget-leaderboard-period-btn.is-active {
    background: linear-gradient(135deg, #f69a00, #d97706);
    color: #fff;
    box-shadow: 0 2px 6px color-mix(in srgb, #f69a00 35%, transparent);
}
.widget-leaderboard-period-btn:focus-visible {
    outline: 2px solid var(--widget-accent, #f69a00);
    outline-offset: 2px;
}
.widget-leaderboard-period-btn:active {
    transform: scale(0.97);
}
/* Когда виджет узкий — пусть кнопки растягиваются поровну */
@media (max-width: 360px) {
    .widget-leaderboard-period { width: 100%; }
    .widget-leaderboard-period-btn { flex: 1 1 0; text-align: center; }
}

/* ============================================================
 * [P0 #1 REC] Сводка «Вы на N из M ▲+K» под списком.
 * При скрытии — .is-hidden (display:none).
 * ============================================================ */
.leaderboard-my-position {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
    padding: 10px 12px;
    border-radius: 12px;
    border: 1px solid color-mix(in srgb, var(--widget-accent, #f69a00) 18%, transparent);
    background: linear-gradient(135deg,
        color-mix(in srgb, #b45309 14%, var(--card-bg, #ffffff)) 0%,
        color-mix(in srgb, #f59e0b 8%, var(--card-bg, #ffffff)) 100%);
    font-size: 12.5px;
    color: var(--text-color, #222);
    font-variant-numeric: tabular-nums;
}
.leaderboard-my-position.is-hidden { display: none; }
.leaderboard-my-position-text {
    font-weight: 600;
}
.leaderboard-my-position-text strong {
    color: var(--widget-accent, #f69a00);
    font-weight: 800;
}
.leaderboard-trend {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 800;
    line-height: 1.2;
    background: color-mix(in srgb, var(--text-color, #222) 8%, transparent);
    color: color-mix(in srgb, var(--text-color, #222) 75%, transparent);
}
.leaderboard-trend--up {
    background: color-mix(in srgb, #16a34a 18%, transparent);
    color: #15803d;
}
.leaderboard-trend--down {
    background: color-mix(in srgb, #dc2626 18%, transparent);
    color: #b91c1c;
}
.leaderboard-trend--same {
    /* остаётся нейтральным */
}
.leaderboard-trend.is-hidden { display: none; }
.leaderboard-trend-arrow { font-size: 12px; line-height: 1; }

/* ============================================================
 * [GAM-AUDIT §2.4] Мини-аватарка в строке лидерборда.
 * Круг 28×28, как ранг-бэйдж рядом. По умолчанию img внутри
 * контейнера; если img не загрузился (onerror добавляет класс
 * is-letter на родителя) — показываем первую букву имени.
 * Размер совпадает с .leaderboard-rank, чтобы не ломать grid.
 * ============================================================ */
.leaderboard-avatar {
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    position: relative;
    overflow: hidden;
    background: linear-gradient(135deg, #d1d5db, #9ca3af);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 800;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.06);
}
.leaderboard-avatar-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.leaderboard-avatar-letter {
    position: relative;
    z-index: 0;
    line-height: 1;
    pointer-events: none;
}
/* Когда картинка не загрузилась — прячем её, оставляем букву.
   onerror ставит .is-letter на .leaderboard-avatar. */
.leaderboard-avatar.is-letter .leaderboard-avatar-img { display: none; }
.leaderboard-avatar.is-letter .leaderboard-avatar-letter { z-index: 1; }

/* ============================================================
 * [GAM-AUDIT §2.4] Skeleton-плейсхолдер лидерборда во время
 * переключения периода. Серые блоки повторяют геометрию
 * реальных строк (rank-бэйдж + 2 «линии» имени/награды).
 * Шиммер на 1.4s, отключается при prefers-reduced-motion.
 * ============================================================ */
.leaderboard-list.is-loading .leaderboard-item { pointer-events: none; }
.leaderboard-skeleton {
    /* Уменьшаем визуальный «шум» — скелетон без рамки/ховеров */
    border-color: transparent !important;
    background: transparent !important;
    box-shadow: none !important;
}
.leaderboard-skeleton:hover {
    background: transparent !important;
    transform: none !important;
}
.leaderboard-skeleton-block {
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--text-color, #222) 8%, transparent),
        color-mix(in srgb, var(--text-color, #222) 14%, transparent),
        color-mix(in srgb, var(--text-color, #222) 8%, transparent)) !important;
    background-size: 200% 100% !important;
    animation: leaderboard-shimmer 1.4s ease-in-out infinite !important;
}
.leaderboard-skeleton-line {
    height: 10px;
    border-radius: 6px;
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--text-color, #222) 8%, transparent),
        color-mix(in srgb, var(--text-color, #222) 14%, transparent),
        color-mix(in srgb, var(--text-color, #222) 8%, transparent));
    background-size: 200% 100%;
    animation: leaderboard-shimmer 1.4s ease-in-out infinite;
}
.leaderboard-skeleton-line--name {
    flex: 1 1 auto;
    min-width: 80px;
}
.leaderboard-skeleton-line--stars {
    flex: 0 0 56px;
}
@keyframes leaderboard-shimmer {
    0%   { background-position: 100% 0; }
    100% { background-position: -100% 0; }
}
@media (prefers-reduced-motion: reduce) {
    .leaderboard-skeleton-block,
    .leaderboard-skeleton-line {
        animation: none;
        background: color-mix(in srgb, var(--text-color, #222) 12%, transparent);
    }
}

/* ============================================================
 * [P2 #17] «Путь героя» — карта прогресса по категориям
 * ============================================================
 * Сетка карточек-ветвей. Каждая карточка = категория ачивок
 * (Исследователь / Наблюдатель / Зоны и маршруты / Контент /
 * Активность). Внутри — горизонтальные чипы по тирам
 * (bronze / silver / gold / platinum) с прогрессом
 * «разблокировано / всего».
 */

.widget-heropath .widget-body {
    padding: 6px 2px 2px;
    max-height: 560px;
    overflow-y: auto;
}
.widget-heropath .widget-body::-webkit-scrollbar { width: 6px; }
.widget-heropath .widget-body::-webkit-scrollbar-thumb {
    background: rgba(0, 0, 0, 0.12);
    border-radius: 999px;
}

/* ===== HEROPATH GRID — современный glass / gradient дизайн ===== */

.heropath-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 12px;
    padding: 4px 2px;
}

.heropath-branch {
    --branch-radius: 16px;
    position: relative;
    padding: 14px 14px 12px;
    border-radius: var(--branch-radius);
    background:
        linear-gradient(135deg, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0.7)) ,
        var(--card-bg, #fff);
    border: 1px solid var(--input-border, rgba(0, 0, 0, 0.06));
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.6) inset,
        0 6px 18px -8px rgba(15, 23, 42, 0.08),
        0 2px 4px -2px rgba(15, 23, 42, 0.04);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    transition:
        transform 0.25s cubic-bezier(0.22, 0.61, 0.36, 1),
        box-shadow 0.25s ease,
        border-color 0.25s ease;
    overflow: hidden;
    isolation: isolate;
    animation: heropath-fade-up 0.45s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.heropath-branch::before {
    /* Тонкий акцентный градиент сверху карточки в цвете категории. */
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: linear-gradient(90deg, var(--branch-fg, #6366f1), transparent 70%);
    opacity: 0.85;
    pointer-events: none;
    z-index: 0;
}
.heropath-branch::after {
    /* Мягкая подсветка-аура в углу карточки. */
    content: "";
    position: absolute;
    top: -40px;
    right: -40px;
    width: 120px;
    height: 120px;
    border-radius: 50%;
    background: var(--branch-bg, rgba(99, 102, 241, 0.18));
    filter: blur(24px);
    opacity: 0.7;
    pointer-events: none;
    z-index: 0;
    transition: opacity 0.3s ease, transform 0.3s ease;
}
.heropath-branch:hover {
    transform: translateY(-2px);
    border-color: var(--branch-fg, rgba(99, 102, 241, 0.4));
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.7) inset,
        0 14px 30px -10px rgba(15, 23, 42, 0.18),
        0 4px 10px -4px rgba(15, 23, 42, 0.08);
}
.heropath-branch:hover::after {
    opacity: 1;
    transform: scale(1.1);
}
.heropath-branch > * { position: relative; z-index: 1; }

@keyframes heropath-fade-up {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}
.heropath-branch:nth-child(1) { animation-delay: 0.02s; }
.heropath-branch:nth-child(2) { animation-delay: 0.06s; }
.heropath-branch:nth-child(3) { animation-delay: 0.10s; }
.heropath-branch:nth-child(4) { animation-delay: 0.14s; }
.heropath-branch:nth-child(5) { animation-delay: 0.18s; }
.heropath-branch:nth-child(6) { animation-delay: 0.22s; }
.heropath-branch:nth-child(7) { animation-delay: 0.26s; }

.heropath-branch-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
    /* [P1 #10] Кликабельный заголовок ветки — открывает модалку
       со всеми ачивками ветки (mode='all'). */
    cursor: pointer;
    user-select: none;
    border-radius: 8px;
    padding: 4px 6px;
    margin-left: -6px;
    margin-right: -6px;
    transition: background 0.15s ease;
}
.heropath-branch-head:hover,
.heropath-branch-head:focus-visible {
    background: rgba(250, 204, 21, 0.08);
    outline: none;
}

/* ===== HEROPATH COLLAPSIBLE — сворачиваемые ветки ===== */
/* Шеврон-индикатор раскрытости в правой части шапки. В свернутом
   состоянии слегка пульсирует — это визуальная подсказка, что
   блок можно развернуть для получения подробной информации. */
.heropath-branch-toggle {
    flex: 0 0 auto;
    margin-left: auto;
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    color: var(--branch-fg, #6366f1);
    background: rgba(99, 102, 241, 0.08);
    font-size: 12px;
    transition: transform 0.3s cubic-bezier(0.22, 0.61, 0.36, 1),
                background 0.2s ease,
                color 0.2s ease;
}
.heropath-branch-toggle i {
    transition: transform 0.3s cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* В развёрнутом состоянии шеврон поворачивается вверх. */
.heropath-branch.is-expanded .heropath-branch-toggle i {
    transform: rotate(180deg);
}
/* В свёрнутом состоянии шеврон мягко пульсирует — приглашение
   «нажмите, чтобы развернуть». */
.heropath-branch.is-collapsed .heropath-branch-toggle {
    animation: heropath-toggle-pulse 2.2s ease-in-out infinite;
}
@keyframes heropath-toggle-pulse {
    0%, 100% {
        background: rgba(99, 102, 241, 0.08);
        box-shadow: 0 0 0 0 rgba(99, 102, 241, 0.0);
    }
    50% {
        background: rgba(99, 102, 241, 0.18);
        box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.10);
    }
}
/* При hover по свёрнутой ветке — чуть более насыщенная подсветка. */
.heropath-branch.is-collapsed:hover .heropath-branch-toggle {
    animation: none;
    background: rgba(99, 102, 241, 0.25);
    color: var(--branch-fg, #4f46e5);
}

/* Контейнер тела ветки. По умолчанию скрыт (is-collapsed),
   разворачивается плавной max-height анимацией. Для свёрнутого
   состояния блок схлопывается до нуля; padding внутри body
   сохраняется, чтобы не «прыгал» фон карточки. */
.heropath-branch-body {
    overflow: hidden;
    transition: max-height 0.35s cubic-bezier(0.22, 0.61, 0.36, 1),
                opacity 0.25s ease,
                margin-top 0.3s ease;
}
.heropath-branch.is-collapsed .heropath-branch-body {
    max-height: 0;
    opacity: 0;
    margin-top: 0;
    pointer-events: none;
}
.heropath-branch.is-expanded .heropath-branch-body {
    max-height: 1200px; /* достаточно для вложенных блоков */
    opacity: 1;
    margin-top: 0;
}
/* В свёрнутом состоянии у шапки убираем нижний отступ — он
   больше не нужен, так как тело не отображается. */
.heropath-branch.is-collapsed .heropath-branch-head {
    margin-bottom: 0;
}

/* Кольцевой индикатор прогресса вокруг иконки. */
.heropath-branch-icon {
    position: relative;
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    background:
        conic-gradient(var(--branch-fg, #6366f1) calc(var(--branch-pct, 0) * 1%), rgba(0, 0, 0, 0.08) 0);
    color: var(--branch-fg, #555);
    transition: background 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.heropath-branch-icon::before {
    content: "";
    position: absolute;
    inset: 3px;
    border-radius: 50%;
    background: var(--card-bg, #fff);
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06) inset;
}
.heropath-branch-icon i {
    position: relative;
    z-index: 1;
}

.heropath-branch-title {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text-color, #1f2937);
    letter-spacing: -0.01em;
    line-height: 1.3;
    /* Название должно отображаться полностью даже на узких
       экранах: разрешаем перенос, длинные слова разбиваем,
       ограничиваем до 2 строк через line-clamp — этого хватает
       для всех имеющихся локализаций ("🗺️ Исследователь",
       "Контент-мейкер" и т.п.) в колонке грида 240px. */
    white-space: normal;
    overflow-wrap: anywhere;
    word-break: break-word;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}
.heropath-branch-count {
    flex: 0 0 auto;
    font-size: 11px;
    font-weight: 700;
    color: var(--branch-fg, #555);
    font-variant-numeric: tabular-nums;
    padding: 3px 8px;
    border-radius: 999px;
    background: var(--branch-bg, rgba(0, 0, 0, 0.06));
    letter-spacing: 0.02em;
}

.heropath-branch-tiers {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 2px;
}

/* Каждый тир — pill-чип. */
.heropath-tier {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px 8px 5px 5px;
    border-radius: 999px;
    font-size: 10.5px;
    color: var(--text-muted, #64748b);
    background: rgba(15, 23, 42, 0.025);
    border: 1px solid rgba(15, 23, 42, 0.04);
    transition: background 0.2s ease, border-color 0.2s ease;
}
.heropath-tier:hover {
    background: rgba(15, 23, 42, 0.045);
    border-color: rgba(15, 23, 42, 0.08);
}

.heropath-tier-dot {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--tier-color, #94a3b8);
    box-shadow:
        0 0 0 2px rgba(255, 255, 255, 0.9),
        0 0 0 3px var(--tier-color-soft, rgba(148, 163, 184, 0.25));
    position: relative;
}
.heropath-tier.is-complete .heropath-tier-dot::after {
    content: "\f00c";
    font-family: "Font Awesome 6 Free";
    font-weight: 900;
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 8px;
}

.heropath-tier-label {
    flex: 0 0 auto;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    min-width: 44px;
    text-align: left;
    color: var(--text-color, #334155);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 10px;
}

.heropath-tier-track {
    flex: 1 1 auto;
    height: 6px;
    border-radius: 999px;
    background: rgba(15, 23, 42, 0.06);
    overflow: hidden;
    position: relative;
}
.heropath-tier-fill {
    height: 100%;
    width: 0;
    border-radius: 999px;
    background: var(--tier-color, #94a3b8);
    background-image: linear-gradient(90deg,
        var(--tier-color-soft, rgba(148, 163, 184, 0.5)),
        var(--tier-color, #94a3b8));
    box-shadow: 0 0 8px var(--tier-color-glow, rgba(148, 163, 184, 0.4));
    transition: width 0.7s cubic-bezier(0.22, 0.61, 0.36, 1);
    position: relative;
    /* Клиппим ::after-шиммер по заполненной части: без этого
       блик при translateX > 100% выходит за правый край fill и
       становится виден на пустой части трека. */
    overflow: hidden;
    animation: heropath-fill-pulse 2.8s ease-in-out infinite;
}
.heropath-tier-fill::after {
    /* Бегущий shimmer-блик по заполненной части. */
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 60%;
    background: linear-gradient(90deg,
        transparent 0%,
        rgba(255, 255, 255, 0.55) 50%,
        transparent 100%);
    border-radius: inherit;
    animation: heropath-shimmer 2.4s linear infinite;
    will-change: transform;
}
@keyframes heropath-shimmer {
    0%   { transform: translateX(-120%); }
    100% { transform: translateX(220%); }
}
@keyframes heropath-fill-pulse {
    0%, 100% {
        box-shadow: 0 0 6px var(--tier-color-glow, rgba(148, 163, 184, 0.35));
        filter: brightness(1);
    }
    50% {
        box-shadow: 0 0 14px var(--tier-color-glow, rgba(148, 163, 184, 0.6));
        filter: brightness(1.08);
    }
}
.heropath-tier.is-complete .heropath-tier-fill {
    /* Завершённые тиры — чуть ярче и стабильнее (без ярко-выраженного
       pulse, чтобы не «мигал» рядом с галочкой). */
    animation-duration: 4s;
}

.heropath-tier-count {
    flex: 0 0 auto;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    font-size: 10.5px;
    color: var(--text-color, #334155);
    min-width: 32px;
    text-align: right;
    letter-spacing: 0.01em;
}
.heropath-tier.is-complete {
    background: var(--tier-color-soft, rgba(148, 163, 184, 0.08));
    border-color: var(--tier-color-soft, rgba(148, 163, 184, 0.2));
}
.heropath-tier.is-complete .heropath-tier-count {
    color: var(--tier-color, #475569);
}

/* ============================================================
 * [HeroPath+] Блок «Следующая цель» внутри карточки категории
 * ============================================================
 * Компактный список ближайших к разблокировке достижений (до 2).
 * В стиле «квестового журнала»: иконка, название, мини-полоска
 * прогресса и награда в виде +N★. Цвет тира подхватывается из
 * класса tier-* на элементе, поэтому выглядит консистентно с
 * pill-чипами тиров выше.
 */
.heropath-branch-next {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px dashed var(--input-border, rgba(15, 23, 42, 0.10));
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.heropath-branch-next-label {
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted, #64748b);
    opacity: 0.85;
    display: flex;
    align-items: center;
    gap: 5px;
}
.heropath-branch-next-label::before {
    /* Крошечный квест-маркер слева от заголовка. */
    content: "";
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--branch-fg, #6366f1);
    box-shadow: 0 0 6px var(--branch-fg, #6366f1);
}
.heropath-branch-next-list {
    display: flex;
    flex-direction: column;
    gap: 5px;
}

/* Одна запись «следующей цели». */
.heropath-next-item {
    --next-color: #94a3b8;
    --next-color-soft: rgba(148, 163, 184, 0.18);
    --next-color-glow: rgba(148, 163, 184, 0.4);
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px 6px 6px;
    border-radius: 10px;
    background: linear-gradient(135deg,
        var(--next-color-soft, rgba(148, 163, 184, 0.12)),
        transparent 70%);
    border: 1px solid color-mix(in srgb, var(--next-color, #94a3b8) 28%, transparent);
    transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
    overflow: hidden;
}
.heropath-next-item::before {
    /* Тонкий акцентный градиент в стиле «квестовой карточки». */
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 3px;
    background: linear-gradient(180deg, var(--next-color, #94a3b8), transparent);
    opacity: 0.85;
}
.heropath-next-item:hover {
    transform: translateX(2px);
    border-color: color-mix(in srgb, var(--next-color, #94a3b8) 55%, transparent);
    box-shadow: 0 4px 12px -6px var(--next-color-glow, rgba(148, 163, 184, 0.6));
}
.heropath-next-item.tier-bronze {
    --next-color: #f59e0b;
    --next-color-soft: rgba(245, 158, 11, 0.14);
    --next-color-glow: rgba(245, 158, 11, 0.45);
}
.heropath-next-item.tier-silver {
    --next-color: #94a3b8;
    --next-color-soft: rgba(148, 163, 184, 0.18);
    --next-color-glow: rgba(148, 163, 184, 0.4);
}
.heropath-next-item.tier-gold {
    --next-color: #eab308;
    --next-color-soft: rgba(234, 179, 8, 0.16);
    --next-color-glow: rgba(234, 179, 8, 0.5);
}
.heropath-next-item.tier-platinum {
    --next-color: #b5b2ac;
    --next-color-soft: rgba(181, 178, 172, 0.18);
    --next-color-glow: rgba(181, 178, 172, 0.45);
}
.heropath-next-item.tier-special {
    --next-color: #26a198;
    --next-color-soft: rgba(38, 161, 152, 0.18);
    --next-color-glow: rgba(38, 161, 152, 0.5);
}

.heropath-next-icon {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    color: var(--next-color, #94a3b8);
    background: var(--next-color-soft, rgba(148, 163, 184, 0.15));
    box-shadow:
        0 0 0 1px color-mix(in srgb, var(--next-color, #94a3b8) 30%, transparent) inset,
        0 0 8px var(--next-color-glow, rgba(148, 163, 184, 0.4));
    position: relative;
    z-index: 1;
}
.heropath-next-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
}
.heropath-next-title {
    font-size: 11.5px;
    font-weight: 700;
    color: var(--text-color, #1f2937);
    letter-spacing: -0.005em;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.heropath-next-progress {
    display: flex;
    align-items: center;
    gap: 6px;
}
.heropath-next-progress-track {
    flex: 1 1 auto;
    height: 4px;
    border-radius: 999px;
    background: rgba(15, 23, 42, 0.08);
    overflow: hidden;
    position: relative;
}
.heropath-next-progress-fill {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg,
        var(--next-color-soft, rgba(148, 163, 184, 0.5)),
        var(--next-color, #94a3b8));
    box-shadow: 0 0 6px var(--next-color-glow, rgba(148, 163, 184, 0.4));
    transition: width 0.7s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.heropath-next-progress-text {
    flex: 0 0 auto;
    font-size: 9.5px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted, #64748b);
    letter-spacing: 0.02em;
}
.heropath-next-reward {
    flex: 0 0 auto;
    font-size: 10px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: var(--next-color, #94a3b8);
    background: var(--next-color-soft, rgba(148, 163, 184, 0.15));
    padding: 3px 6px;
    border-radius: 6px;
    letter-spacing: 0.02em;
    white-space: nowrap;
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--next-color, #94a3b8) 22%, transparent) inset;
}

/* Состояние «ветка полностью пройдена» — мягкое сияние. */
.heropath-branch-done {
    margin-top: 10px;
    padding: 10px 12px;
    border-radius: 10px;
    background:
        linear-gradient(135deg,
            rgba(234, 179, 8, 0.14),
            rgba(38, 161, 152, 0.10)),
        var(--card-bg, #fff);
    border: 1px solid rgba(234, 179, 8, 0.35);
    font-size: 11.5px;
    font-weight: 800;
    color: #b45309;
    text-align: center;
    letter-spacing: 0.01em;
    box-shadow: 0 0 18px -6px rgba(234, 179, 8, 0.5);
    animation: heropath-done-glow 3s ease-in-out infinite;
}
@keyframes heropath-done-glow {
    0%, 100% { box-shadow: 0 0 12px -6px rgba(234, 179, 8, 0.4); }
    50%      { box-shadow: 0 0 22px -4px rgba(234, 179, 8, 0.6); }
}

/* ============================================================
 * [HeroPath+] Блок «Получено»: чипы разблокированных ачивок
 * ============================================================
 * Компактная «лента» иконок-бейджей того, что игрок уже собрал в
 * этой категории. Иконки выстроены в один-два ряда и подсвечены
 * цветом тира — тактильно похоже на инвентарь в RPG. Ограничиваем
 * 12 чипами (см. EARNED_CHIPS_MAX в app.js); при переполнении
 * показывается мини-бейдж «+N».
 */
.heropath-branch-earned {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px dashed var(--input-border, rgba(15, 23, 42, 0.10));
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.heropath-branch-earned-label {
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted, #64748b);
    opacity: 0.85;
}
.heropath-branch-earned-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    align-items: center;
}
.heropath-earned-chip {
    --chip-color: #94a3b8;
    --chip-color-soft: rgba(148, 163, 184, 0.18);
    --chip-color-glow: rgba(148, 163, 184, 0.4);
    position: relative;
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    border-radius: 7px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 10.5px;
    color: var(--chip-color, #94a3b8);
    background: linear-gradient(135deg,
        var(--chip-color-soft, rgba(148, 163, 184, 0.18)),
        rgba(255, 255, 255, 0.6));
    border: 1px solid color-mix(in srgb, var(--chip-color, #94a3b8) 35%, transparent);
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.6) inset,
        0 2px 6px -2px var(--chip-color-glow, rgba(148, 163, 184, 0.45));
    transition: transform 0.18s ease, box-shadow 0.18s ease;
    cursor: help;
}
.heropath-earned-chip:hover {
    transform: translateY(-2px) scale(1.08);
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.7) inset,
        0 4px 10px -2px var(--chip-color-glow, rgba(148, 163, 184, 0.6)),
        0 0 8px var(--chip-color-glow, rgba(148, 163, 184, 0.4));
    z-index: 2;
}
.heropath-earned-chip.tier-bronze {
    --chip-color: #f59e0b;
    --chip-color-soft: rgba(245, 158, 11, 0.20);
    --chip-color-glow: rgba(245, 158, 11, 0.45);
}
.heropath-earned-chip.tier-silver {
    --chip-color: #94a3b8;
    --chip-color-soft: rgba(148, 163, 184, 0.22);
    --chip-color-glow: rgba(148, 163, 184, 0.45);
}
.heropath-earned-chip.tier-gold {
    --chip-color: #eab308;
    --chip-color-soft: rgba(234, 179, 8, 0.20);
    --chip-color-glow: rgba(234, 179, 8, 0.55);
}
.heropath-earned-chip.tier-platinum {
    --chip-color: #b5b2ac;
    --chip-color-soft: rgba(181, 178, 172, 0.22);
    --chip-color-glow: rgba(181, 178, 172, 0.5);
}
.heropath-earned-chip.tier-special {
    --chip-color: #26a198;
    --chip-color-soft: rgba(38, 161, 152, 0.22);
    --chip-color-glow: rgba(38, 161, 152, 0.55);
}
.heropath-earned-overflow {
    flex: 0 0 auto;
    font-size: 10px;
    font-weight: 800;
    color: var(--text-muted, #64748b);
    background: rgba(15, 23, 42, 0.06);
    padding: 2px 6px;
    border-radius: 6px;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
}

/* Тёмная тема: чуть ярче glow и контраст для блоков next/earned. */
body.dark-theme .heropath-branch-next {
    border-top-color: rgba(255, 255, 255, 0.08);
}
body.dark-theme .heropath-branch-earned {
    border-top-color: rgba(255, 255, 255, 0.08);
}
body.dark-theme .heropath-earned-chip {
    background: linear-gradient(135deg,
        var(--chip-color-soft, rgba(148, 163, 184, 0.18)),
        rgba(15, 23, 42, 0.6));
}
body.dark-theme .heropath-earned-overflow {
    background: rgba(255, 255, 255, 0.06);
    color: var(--text-muted, #94a3b8);
}
body.dark-theme .heropath-next-progress-track {
    background: rgba(255, 255, 255, 0.08);
}

/* ============================================================
 * [HeroPath+] Кликабельность блоков «Получено» / «Следующая цель»
 * ============================================================
 * Оба блока внутри карточки ветки теперь открывают детальную
 * модалку. Делаем их визуально интерактивными: pointer + лёгкий
 * hover-аплифт + тонкий outline. Крошечная иконка-«нажми»
 * подсказывает, что блок кликабельный.
 */
.heropath-branch-earned,
.heropath-branch-next {
    position: relative;
    cursor: pointer;
    border-radius: 12px;
    transition:
        background-color 0.2s ease,
        transform 0.2s cubic-bezier(0.22, 0.61, 0.36, 1),
        box-shadow 0.2s ease;
}
.heropath-branch-earned:hover,
.heropath-branch-next:hover {
    background-color: rgba(15, 23, 42, 0.035);
    transform: translateX(2px);
    box-shadow: 0 2px 10px -6px rgba(15, 23, 42, 0.15);
}
.heropath-branch-earned:focus-visible,
.heropath-branch-next:focus-visible {
    outline: 2px solid var(--branch-fg, #6366f1);
    outline-offset: 2px;
}
body.dark-theme .heropath-branch-earned:hover,
body.dark-theme .heropath-branch-next:hover {
    background-color: rgba(255, 255, 255, 0.05);
}
/* Маленькая подсказка в правом верхнем углу — «можно кликнуть».
   Через ::after не конфликтует с существующими ::after карточки. */
.heropath-branch-earned::after,
.heropath-branch-next::after {
    content: "\f0f6"; /* fa-up-right-from-square */
    font-family: "Font Awesome 6 Free";
    font-weight: 900;
    position: absolute;
    top: 8px;
    right: 8px;
    font-size: 8px;
    color: var(--text-muted, #64748b);
    opacity: 0;
    transition: opacity 0.2s ease;
}
.heropath-branch-earned:hover::after,
.heropath-branch-next:hover::after,
.heropath-branch-earned:focus-visible::after,
.heropath-branch-next:focus-visible::after {
    opacity: 0.55;
}

/* ============================================================
 * [HeroPath+] Модалка детальной информации по ветке
 * ============================================================
 * Шапка: иконка категории + заголовок + подзаголовок + 2
 * счётчика (разблокировано/всего + количество в текущем
 * списке). Тело: вертикальный список карточек с прогрессом,
 * наградой и условием. Цвет тира на каждой карточке — через
 * CSS-переменные --tier-color, согласованные с остальным
 * виджетом «Путь героя».
 */
.heropath-modal-content {
    max-width: 460px;
}
.heropath-modal-content h3 {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.heropath-modal-content h3 i {
    font-size: 18px;
    color: var(--widget-accent, #f69a00);
    filter: drop-shadow(0 0 6px rgba(246, 154, 0, 0.35));
}
.heropath-modal-subtitle {
    margin: -8px 0 14px 0;
    font-size: 12.5px;
    line-height: 1.4;
    color: var(--text-muted, #64748b);
}
.heropath-modal-meta {
    display: flex;
    gap: 8px;
    margin-bottom: 12px;
}
.heropath-modal-stat {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 8px 10px;
    border-radius: 10px;
    background:
        linear-gradient(135deg,
            rgba(15, 23, 42, 0.04),
            rgba(15, 23, 42, 0.02));
    border: 1px solid rgba(15, 23, 42, 0.06);
}
.heropath-modal-stat-value {
    font-size: 12px;
    font-weight: 800;
    color: var(--text-color, #0f172a);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
    line-height: 1.1;
}
.heropath-modal-stat-label {
    font-size: 9px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted, #64748b);
}
body.dark-theme .heropath-modal-stat {
    background: linear-gradient(135deg,
        rgba(255, 255, 255, 0.05),
        rgba(255, 255, 255, 0.02));
    border-color: rgba(255, 255, 255, 0.08);
}

.heropath-modal-body {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: calc(100vh - 320px);
    min-height: 80px;
    overflow-y: auto;
    padding-right: 4px;
    scrollbar-width: thin;
}
.heropath-modal-body::-webkit-scrollbar { width: 5px; }
.heropath-modal-body::-webkit-scrollbar-thumb {
    background: rgba(0, 0, 0, 0.18);
    border-radius: 999px;
}
body.dark-theme .heropath-modal-body::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.18);
}

/* Секционный заголовок внутри модалки (например «Платина», «Золото»).
   Разделяет длинный список карточек на группы по тиру — так проще
   ориентироваться, где «дорогие» цели, а где начальные. */
.heropath-modal-section {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 6px 2px 2px;
    padding: 12px 2px;
    position: sticky;
    top: 0;
    background: linear-gradient(180deg, var(--card-bg, #ffffff) 70%, transparent);
    z-index: 1;
}
.heropath-modal-section:first-child {
    margin-top: 2px;
}
.heropath-modal-section-dot {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--tier-color, #94a3b8);
    box-shadow:
        0 0 0 2px color-mix(in srgb, var(--tier-color, #94a3b8) 25%, transparent),
        0 0 8px var(--tier-color-glow, rgba(148, 163, 184, 0.4));
}
.heropath-modal-section-label {
    flex: 1 1 auto;
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--tier-color, #94a3b8);
    opacity: 0.95;
}
.heropath-modal-section-count {
    flex: 0 0 auto;
    font-size: 10.5px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted, #64748b);
    padding: 2px 7px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--tier-color, #94a3b8) 14%, transparent);
    letter-spacing: 0.02em;
}
body.dark-theme .heropath-modal-section {
    background: linear-gradient(180deg,
        var(--card-bg, #0f172a) 70%,
        transparent);
}

/* Контейнер карточек внутри одной секции (для будущих расширений,
   пока просто гарантирует, что карточки внутри секции идут друг
   за другом без дополнительных отступов сверху/снизу). */
.heropath-modal-section-body {
    display: flex;
    flex-direction: column;
    gap: 7px;
}

/* Цвета секций по тиру — согласованы с `.heropath-tier.tier-*`
   из основного виджета «Путь героя». */
.heropath-modal-section.tier-bronze {
    --tier-color: #f59e0b;
    --tier-color-soft: rgba(245, 158, 11, 0.20);
    --tier-color-glow: rgba(245, 158, 11, 0.45);
}
.heropath-modal-section.tier-silver {
    --tier-color: #94a3b8;
    --tier-color-soft: rgba(148, 163, 184, 0.22);
    --tier-color-glow: rgba(148, 163, 184, 0.45);
}
.heropath-modal-section.tier-gold {
    --tier-color: #eab308;
    --tier-color-soft: rgba(234, 179, 8, 0.20);
    --tier-color-glow: rgba(234, 179, 8, 0.55);
}
.heropath-modal-section.tier-platinum {
    --tier-color: #b5b2ac;
    --tier-color-soft: rgba(181, 178, 172, 0.22);
    --tier-color-glow: rgba(181, 178, 172, 0.5);
}
.heropath-modal-section.tier-special {
    --tier-color: #26a198;
    --tier-color-soft: rgba(38, 161, 152, 0.22);
    --tier-color-glow: rgba(38, 161, 152, 0.55);
}

/* Пустое состояние модалки. */
.heropath-modal-empty {
    padding: 28px 16px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    color: var(--text-muted, #64748b);
    font-size: 13px;
    text-align: center;
}
.heropath-modal-empty i {
    font-size: 28px;
    opacity: 0.5;
}

/* Карточка ачивки внутри модалки. */
.heropath-modal-card {
    --tier-color: #94a3b8;
    --tier-color-soft: rgba(148, 163, 184, 0.18);
    --tier-color-glow: rgba(148, 163, 184, 0.4);
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 7px;
    padding: 9px 11px 10px;
    border-radius: 12px;
    background:
        linear-gradient(135deg,
            var(--tier-color-soft, rgba(148, 163, 184, 0.10)),
            rgba(255, 255, 255, 0.5));
    border: 1px solid color-mix(in srgb, var(--tier-color, #94a3b8) 25%, transparent);
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.6) inset,
        0 4px 14px -8px rgba(15, 23, 42, 0.12);
    overflow: hidden;
    isolation: isolate;
}
.heropath-modal-card::before {
    /* Акцентная полоска слева в цвете тира. */
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 3px;
    background: linear-gradient(180deg, var(--tier-color, #94a3b8), transparent);
    opacity: 0.85;
}
.heropath-modal-card.tier-bronze {
    --tier-color: #f59e0b;
    --tier-color-soft: rgba(245, 158, 11, 0.12);
    --tier-color-glow: rgba(245, 158, 11, 0.45);
}
.heropath-modal-card.tier-silver {
    --tier-color: #94a3b8;
    --tier-color-soft: rgba(148, 163, 184, 0.16);
    --tier-color-glow: rgba(148, 163, 184, 0.4);
}
.heropath-modal-card.tier-gold {
    --tier-color: #eab308;
    --tier-color-soft: rgba(234, 179, 8, 0.14);
    --tier-color-glow: rgba(234, 179, 8, 0.5);
}
.heropath-modal-card.tier-platinum {
    --tier-color: #b5b2ac;
    --tier-color-soft: rgba(181, 178, 172, 0.16);
    --tier-color-glow: rgba(181, 178, 172, 0.45);
}
.heropath-modal-card.tier-special {
    --tier-color: #26a198;
    --tier-color-soft: rgba(38, 161, 152, 0.14);
    --tier-color-glow: rgba(38, 161, 152, 0.5);
}
.heropath-modal-card.is-locked {
    /* ВАЖНО: сохраняем оттенок tier-цвета даже для заблокированных,
       чтобы карточки разных тиров визуально различались в длинном
       списке модалки. Без этого все locked-карточки сливаются
       в одно серое месиво. Используем color-mix, чтобы сохранить
       общий нейтральный фон (~10% mix) с лёгким намёком на тир. */
    background:
        linear-gradient(135deg,
            color-mix(in srgb, var(--tier-color, #94a3b8) 10%, transparent),
            color-mix(in srgb, var(--tier-color, #94a3b8) 4%, transparent));
    border-color: color-mix(in srgb, var(--tier-color, #94a3b8) 22%, transparent);
}
.heropath-modal-card.is-locked::before {
    /* Акцентная полоска слева остаётся в цвете тира — но приглушённая. */
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--tier-color, #94a3b8) 70%, transparent),
        transparent);
    opacity: 0.7;
}
body.dark-theme .heropath-modal-card {
    background:
        linear-gradient(135deg,
            var(--tier-color-soft, rgba(148, 163, 184, 0.10)),
            rgba(15, 23, 42, 0.6));
    border-color: color-mix(in srgb, var(--tier-color, #94a3b8) 30%, transparent);
}
body.dark-theme .heropath-modal-card.is-locked {
    background:
        linear-gradient(135deg,
            color-mix(in srgb, var(--tier-color, #94a3b8) 8%, rgba(15, 23, 42, 0.5)),
            color-mix(in srgb, var(--tier-color, #94a3b8) 3%, rgba(15, 23, 42, 0.7)));
    border-color: color-mix(in srgb, var(--tier-color, #94a3b8) 24%, transparent);
}

.heropath-modal-card-head {
    display: flex;
    align-items: center;
    gap: 10px;
}
.heropath-modal-card-icon {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    border-radius: 9px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    color: var(--tier-color, #94a3b8);
    background: var(--tier-color-soft, rgba(148, 163, 184, 0.18));
    box-shadow:
        0 0 0 1px color-mix(in srgb, var(--tier-color, #94a3b8) 30%, transparent) inset,
        0 0 10px var(--tier-color-glow, rgba(148, 163, 184, 0.4));
    position: relative;
    z-index: 1;
}
.heropath-modal-card.is-locked .heropath-modal-card-icon {
    /* Иконка в locked-карточке чуть приглушённая, но всё ещё в
       цвете тира — чтобы визуально отличать platinum/gold/silver. */
    color: color-mix(in srgb, var(--tier-color, #94a3b8) 75%, var(--text-muted, #94a3b8));
    background: color-mix(in srgb, var(--tier-color, #94a3b8) 8%, transparent);
    box-shadow:
        0 0 0 1px color-mix(in srgb, var(--tier-color, #94a3b8) 18%, transparent) inset;
}
.heropath-modal-card-title {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}
.heropath-modal-card-name {
    font-size: 13px;
    font-weight: 700;
    color: var(--text-color, #0f172a);
    letter-spacing: -0.005em;
    line-height: 1.2;
}
.heropath-modal-card.is-locked .heropath-modal-card-name {
    color: var(--text-color, #1f2937);
    opacity: 0.92;
}
.heropath-modal-card-tier {
    font-size: 8.5px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--tier-color, #94a3b8);
    opacity: 0.9;
}
.heropath-modal-lock {
    flex: 0 0 auto;
    font-size: 12px;
    color: var(--text-muted, #94a3b8);
    opacity: 0.55;
}

/* Бейджи рядом с названием карточки: «Не начато», «Почти готово». */
.heropath-modal-badge {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 8.5px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 2px 6px;
    border-radius: 999px;
    margin-left: 6px;
    white-space: nowrap;
}
.heropath-modal-badge.is-not-started {
    color: #64748b;
    background: rgba(15, 23, 42, 0.06);
    border: 1px dashed rgba(15, 23, 42, 0.18);
}
.heropath-modal-badge.is-near {
    color: #b45309;
    background: linear-gradient(135deg, rgba(234, 179, 8, 0.18), rgba(234, 179, 8, 0.08));
    border: 1px solid rgba(234, 179, 8, 0.40);
    box-shadow: 0 0 8px -2px rgba(234, 179, 8, 0.4);
}
body.dark-theme .heropath-modal-badge.is-not-started {
    color: #94a3b8;
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(255, 255, 255, 0.15);
}

.heropath-modal-card-body {
    display: flex;
    flex-direction: column;
    gap: 5px;
    padding-left: 2px;
}
.heropath-modal-detail-row {
    display: flex;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 6px;
    font-size: 11.5px;
    line-height: 1.35;
    color: var(--text-color, #1f2937);
}
.heropath-modal-detail-row i {
    flex: 0 0 auto;
    margin-top: 2px;
    font-size: 10px;
    color: var(--text-muted, #64748b);
    width: 12px;
    text-align: center;
    align-self: center;
}
.heropath-modal-detail-row .fa-lightbulb {
    color: #f59e0b;
}
.heropath-modal-detail-row .fa-star {
    color: #f59e0b;
}
.heropath-modal-detail-row .fa-calendar-check {
    color: #26a198;
}
.heropath-modal-detail-label {
    flex: 0 0 auto;
    margin-top: 3px;
    font-weight: 700;
    color: var(--text-muted, #64748b);
}
.heropath-modal-detail-value {
    flex: 1 1 auto;
    min-width: 0;
    word-break: break-word;
    margin-top: 2px;
}
.heropath-modal-reward {
    /* Не растягиваем на всю ширину: бейдж должен быть компактным,
       иначе во flex-row-контейнере `.heropath-modal-detail-row`
       он «съедает» иконку ★ и лейбл «Награда:», и они
       оказываются перекрыты этой длинной плашкой.
       flex: 0 0 auto блокирует поведение `flex: 1 1 auto`,
       которое бейдж неявно наследует от `.heropath-modal-detail-value`. */
    display: inline-block;
    flex: 0 0 auto;
    padding: 1px 7px;
    border-radius: 6px;
    background: linear-gradient(135deg, rgba(245, 158, 11, 0.16), rgba(245, 158, 11, 0.08));
    color: #b45309;
    font-weight: 800;
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    border: 1px solid rgba(245, 158, 11, 0.35);
    box-shadow: 0 0 8px -2px rgba(245, 158, 11, 0.4);
    white-space: nowrap;
    align-self: center;
}
body.dark-theme .heropath-modal-reward {
    background: linear-gradient(135deg, rgba(245, 158, 11, 0.20), rgba(245, 158, 11, 0.08));
    color: #fbbf24;
}

.heropath-modal-progress {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 2px;
}
.heropath-modal-progress-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
}
.heropath-modal-progress-label {
    font-size: 10px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted, #64748b);
}
.heropath-modal-progress-text {
    font-size: 11px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: var(--tier-color, #94a3b8);
}
.heropath-modal-progress-track {
    height: 6px;
    border-radius: 999px;
    background: rgba(15, 23, 42, 0.08);
    overflow: hidden;
    position: relative;
}
.heropath-modal-progress-fill {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg,
        var(--tier-color-soft, rgba(148, 163, 184, 0.5)),
        var(--tier-color, #94a3b8));
    box-shadow: 0 0 8px var(--tier-color-glow, rgba(148, 163, 184, 0.4));
    transition: width 0.7s cubic-bezier(0.22, 0.61, 0.36, 1);
}
body.dark-theme .heropath-modal-progress-track {
    background: rgba(255, 255, 255, 0.08);
}

/* Адаптив: на очень узких экранах — почти во весь экран. */
@media (max-width: 480px) {
    .heropath-modal-content {
        max-width: 100%;
    }
    .heropath-modal-meta {
        flex-direction: row;
    }
    .heropath-modal-body {
        max-height: calc(100vh - 360px);
    }
}

/* Цвета тиров: задаём основной, мягкий и glow-вариант. */
.heropath-tier.tier-bronze {
    --tier-color: #f59e0b;
    --tier-color-soft: rgba(245, 158, 11, 0.18);
    --tier-color-glow: rgba(245, 158, 11, 0.45);
}
.heropath-tier.tier-silver {
    --tier-color: #94a3b8;
    --tier-color-soft: rgba(148, 163, 184, 0.20);
    --tier-color-glow: rgba(148, 163, 184, 0.4);
}
.heropath-tier.tier-gold {
    --tier-color: #eab308;
    --tier-color-soft: rgba(234, 179, 8, 0.20);
    --tier-color-glow: rgba(234, 179, 8, 0.5);
}
.heropath-tier.tier-platinum {
    --tier-color: #b5b2ac;
    --tier-color-soft: rgba(181, 178, 172, 0.22);
    --tier-color-glow: rgba(181, 178, 172, 0.45);
}
.heropath-tier.tier-special {
    --tier-color: #26a198;
    --tier-color-soft: rgba(38, 161, 152, 0.20);
    --tier-color-glow: rgba(38, 161, 152, 0.5);
}

/* Цвета ветвей по категории. */
.heropath-branch.cat-explorer {
    --branch-bg: rgba(139, 92, 246, 0.18);
    --branch-fg: #7c3aed;
}
.heropath-branch.cat-watcher {
    --branch-bg: rgba(59, 130, 246, 0.18);
    --branch-fg: #2563eb;
}
.heropath-branch.cat-config {
    --branch-bg: rgba(245, 158, 11, 0.18);
    --branch-fg: #d97706;
}
.heropath-branch.cat-content {
    --branch-bg: rgba(236, 72, 153, 0.18);
    --branch-fg: #db2777;
}
.heropath-branch.cat-activity {
    --branch-bg: rgba(249, 115, 22, 0.18);
    --branch-fg: #ea580c;
}
.heropath-branch.cat-special {
    --branch-bg: rgba(168, 85, 247, 0.18);
    --branch-fg: #a855f7;
}
.heropath-branch.cat-premium {
    --branch-bg: rgba(234, 179, 8, 0.16);
    --branch-fg: #b45309;
}

/* Акцентный цвет виджета «Путь героя»: оранжевый #f69a00.
   Перебивает зелёный из класса widget-tint-emerald в index.html. */
.widget-heropath {
    --widget-accent: #f69a00;
    --widget-accent-soft: rgba(246, 154, 0, 0.14);
}

/* Акцентный цвет виджета «Топ недели»: тот же оранжевый #f69a00,
   что и у widget-heropath. Перебивает фиолетовый из widget-tint-purple
   в index.html — обе «достиженческие» поверхности (Путь героя + Лидерборд)
   теперь визуально рифмуются и читаются как единый блок. */
.widget-leaderboard {
    --widget-accent: #f69a00;
    --widget-accent-soft: rgba(246, 154, 0, 0.14);
}

/* Динамические состояния ветви по текущему достижению.
   Перебивают cat-* цвета в зависимости от наивысшего
   разблокированного (или прогрессируемого) тира. */
.heropath-branch.tier-state-bronze {
    --branch-bg: rgba(249, 115, 22, 0.18);
    --branch-fg: #f69a00;
}
.heropath-branch.tier-state-silver {
    --branch-bg: rgb(148 163 184 / 28%);
    --branch-fg: #94a3b8;
}
.heropath-branch.tier-state-gold {
    --branch-bg: rgba(234, 179, 8, 0.16);
    --branch-fg: #e4ae05;
}
.heropath-branch.tier-state-platinum {
    --branch-bg: #b5b2ac59;
    --branch-fg: #b5b2ac;
}
.heropath-branch.tier-state-special {
    --branch-bg: #26a19833;
    --branch-fg: #26a198;
}
.heropath-branch.tier-state-none {
    --branch-bg: rgba(100, 116, 139, 0.12);
    --branch-fg: #64748b;
}

/* Тёмная тема: подстраиваем фон и контраст. */
body.dark-theme .heropath-branch {
    background: #3a3a3a;
    border-color: rgba(255, 255, 255, 0.06);
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.04) inset,
        0 6px 18px -8px rgba(0, 0, 0, 0.6),
        0 2px 4px -2px rgba(0, 0, 0, 0.4);
}
body.dark-theme .heropath-branch-icon::before {
    background: var(--card-bg, #0f172a);
}
body.dark-theme .heropath-tier {
    background: rgba(255, 255, 255, 0.04);
    border-color: rgba(255, 255, 255, 0.06);
}
body.dark-theme .heropath-tier-dot {
    box-shadow:
        0 0 0 2px var(--card-bg, #0f172a),
        0 0 0 3px var(--tier-color-soft, rgba(148, 163, 184, 0.25));
}
body.dark-theme .heropath-tier-track {
    background: rgba(255, 255, 255, 0.06);
}

/* Дополнительные правки тёмной темы для виджета «Путь героя»:
   подсветка scrollbar, hover-состояния тиров/чипов и финальный
   экран полностью пройденной ветки. */
body.dark-theme .widget-heropath .widget-body::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.12);
}
body.dark-theme .heropath-tier:hover {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.10);
}
body.dark-theme .heropath-earned-chip:hover {
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.04) inset,
        0 4px 10px -2px var(--chip-color-glow, rgba(148, 163, 184, 0.6)),
        0 0 8px var(--chip-color-glow, rgba(148, 163, 184, 0.4));
}
body.dark-theme .heropath-branch-done {
    background:
        linear-gradient(135deg,
            rgba(234, 179, 8, 0.18),
            rgba(38, 161, 152, 0.14)),
        var(--card-bg, #0f172a);
    color: #fcd34d;
    border-color: rgba(234, 179, 8, 0.45);
}

/* Адаптив для узких колонок. */
@media (max-width: 600px) {
    .heropath-grid {
        grid-template-columns: 1fr;
    }
}

/* Уважаем prefers-reduced-motion: отключаем зацикленные
   анимации прогресс-баров для пользователей с включённой
   настройкой уменьшения движения. */
@media (prefers-reduced-motion: reduce) {
    .heropath-tier-fill,
    .heropath-tier-fill::after,
    .heropath-branch-done {
        animation: none !important;
    }
    .heropath-branch-earned,
    .heropath-branch-next,
    .heropath-modal-progress-fill {
        transition: none !important;
    }
}
.widget-streak.is-broken .streak-flame {
    background: linear-gradient(135deg, #9ca3af, #6b7280);
    animation: none;
}
.widget-streak.is-broken .streak-current-value {
    color: var(--text-muted, #888);
}
/* [STREAK-FIX] Промежуточное состояние «pending-today»: серия
   жива, но сегодня ещё не активен. Не демотивируем серым, а
   оставляем тёплый оранжевый тон и анимацию пламени, чтобы
   пользователь видел «огонёк ещё горит — просто отметься». */
.widget-streak.is-pending-today .streak-flame {
    background: linear-gradient(135deg, #f59e0b, #ea580c);
    animation: streak-flame-pulse 1.4s ease-in-out infinite;
    opacity: 0.85;
}
.widget-streak.is-pending-today .streak-current-value {
    color: #b45309;
    opacity: 0.6;
}
.streak-meta-item--pending {
    color: #b45309;
    font-weight: 500;
}
.streak-meta-item--pending i {
    color: #f59e0b;
}
@keyframes quest-celebrate {
    0%   { transform: scale(1); }
    30%  { transform: scale(1.03); }
    60%  { transform: scale(0.99); }
    100% { transform: scale(1); }
}
.quest-card.is-just-claimed {
    animation: quest-celebrate 1.2s ease-out 0s 1;
}

/* Тосты о статусе оплаты (paid / cancelled / failed) */
.stars-toast {
    position: fixed;
    left: 50%;
    bottom: 88px;
    transform: translate(-50%, 20px);
    background: var(--card-bg, #ffffff);
    color: var(--text-color, #222);
    border: 1px solid var(--input-border, #e0e0e0);
    border-radius: 12px;
    padding: 12px 18px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
    font-size: 14px;
    z-index: 12000;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease, transform 0.2s ease;
    max-width: calc(100vw - 32px);
    text-align: center;
}

.stars-toast.show {
    opacity: 1;
    transform: translate(-50%, 0);
}

.stars-toast-success {
    border-color: rgba(46, 160, 67, 0.4);
    background: rgba(46, 160, 67, 0.08);
}

.stars-toast-error {
    border-color: rgba(220, 50, 50, 0.4);
    background: rgba(220, 50, 50, 0.08);
}

.stars-toast-info {
    border-color: var(--input-border, #e0e0e0);
}

body.dark-theme .stars-toast {
    background: var(--card-bg, #1f2024);
    color: var(--text-color, #eee);
}

/* =========================================================
   Floating Geotracker FAB — pulsating amber star.

   Показывается на страницах «Сводка», «Карта», «Наблюдаемые»,
   «Баланс» и «Настройки». По клику открывает раздел Достижений
   (новая секция sectionGeotracker, куда перенесены виджеты
   достижений / квестов из Сводки).

   Архитектура: FAB лежит внутри фиксированного контейнера
   `.geotracker-fab-stack` и пульсирует независимо.

   Позиционирование — фиксированный «парящий» кластер в правом
   нижнем углу, над bottom-nav (учтены safe-area-inset-*).
   ========================================================= */
.geotracker-fab-stack {
    position: fixed;
    right: calc(16px + max(0px, env(safe-area-inset-right)));
    /* bottom-nav сидит на bottom: calc(20px + max(12px, env(safe-area-inset-bottom)))
       и имеет высоту ~52px; поднимаем FAB-кластер над ним с запасом. */
    bottom: calc(92px + max(12px, env(safe-area-inset-bottom)));
    z-index: 1010;
    display: none;
    /* Размеры подгоняются под содержимое (FAB). */
    width: 56px;
    height: 56px;
}

.geotracker-fab-stack.show {
    display: block;
}

.geotracker-fab {
    /* Относительный внутри стека — НЕ position: fixed */
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.35);
    background:
        radial-gradient(circle at 30% 28%, #fde68a 0%, #f59e0b 38%, #b45309 100%);
    color: #fff8e7;
    font-size: 26px;
    line-height: 1;
    cursor: pointer;
    box-shadow:
        0 10px 24px -6px rgba(245, 158, 11, 0.55),
        0 4px 10px rgba(0, 0, 0, 0.25),
        inset 0 1px 0 rgba(255, 255, 255, 0.45);
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    font-family: inherit;
    padding: 0;
    /* Пульсирующая анимация — теперь влияет ТОЛЬКО на саму
       кнопку и её звезду. Бейдж — сосед в стеке и не наследует
       этот transform. */
    animation: geotracker-fab-pulse 1.6s ease-in-out infinite;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.geotracker-fab:hover {
    transform: translateY(-2px) scale(1.04);
    box-shadow:
        0 14px 28px -6px rgba(245, 158, 11, 0.65),
        0 6px 12px rgba(0, 0, 0, 0.3),
        inset 0 1px 0 rgba(255, 255, 255, 0.5);
}

.geotracker-fab:active {
    transform: scale(0.94);
}

.geotracker-fab:focus-visible {
    outline: 2px solid #fbbf24;
    outline-offset: 3px;
}

/* Иконка звезды внутри FAB — лёгкий «поворот» в пульсе. */
.geotracker-fab .geotracker-fab-icon {
    display: inline-block;
    animation: geotracker-fab-spin 6s linear infinite;
    filter: drop-shadow(0 1px 1px rgba(120, 53, 15, 0.5));
}

/* Дополнительный «ореол», чтобы пульс был заметнее на светлой теме. */
.geotracker-fab::after {
    content: "";
    position: absolute;
    inset: -6px;
    border-radius: 50%;
    pointer-events: none;
    box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.55);
    animation: geotracker-fab-ring 1.6s ease-out infinite;
}

@keyframes geotracker-fab-pulse {
    0%, 100% {
        transform: scale(1);
        box-shadow:
            0 10px 24px -6px rgba(245, 158, 11, 0.55),
            0 4px 10px rgba(0, 0, 0, 0.25),
            inset 0 1px 0 rgba(255, 255, 255, 0.45);
    }
    50% {
        transform: scale(1.08);
        box-shadow:
            0 14px 28px -6px rgba(245, 158, 11, 0.75),
            0 6px 14px rgba(0, 0, 0, 0.3),
            inset 0 1px 0 rgba(255, 255, 255, 0.55);
    }
}

@keyframes geotracker-fab-ring {
    0% {
        box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.55);
    }
    100% {
        box-shadow: 0 0 0 18px rgba(245, 158, 11, 0);
    }
}

@keyframes geotracker-fab-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

/* Reduced motion: оставляем функциональный вид, отключаем анимации. */
@media (prefers-reduced-motion: reduce) {
    .geotracker-fab,
    .geotracker-fab .geotracker-fab-icon,
    .geotracker-fab::after {
        animation: none !important;
        transition: none !important;
    }
}

@media (max-width: 480px) {
    .geotracker-fab-stack {
        width: 52px;
        height: 52px;
        right: calc(24px + max(0px, env(safe-area-inset-right)));
        /* Поднимаем FAB-стек выше, чтобы бейдж "Сегодня +N ★",
           свисающий вниз от FAB, не упирался в bottom-nav и
           системный home-indicator (iOS safe-area-inset-bottom). */
        bottom: calc(127px + max(12px, env(safe-area-inset-bottom)));
    }
    .geotracker-fab {
        width: 52px;
        height: 52px;
        font-size: 24px;
    }
}

/* На fullscreen-карте и в fullscreen-app FAB прячем.
   В JS (toggleFullscreen) класс fullscreen-app ставится на #app,
   а не на body — поэтому проверяем оба варианта для совместимости.
   Селектор #app.fullscreen-app #geotrackerFabStack — основной:
   #geotrackerFabStack находится внутри #app как прямой потомок,
   поэтому правило надёжно срабатывает при разворачивании карты.
   Селектор body.fullscreen-app .geotracker-fab-stack оставлен для
   совместимости со страницами, где fullscreen-app ставится на body.
   Селектор .fullscreen-map ~ .geotracker-fab-stack срабатывает
   на страницах с модальными картами, где .fullscreen-map идёт
   ПЕРЕД fab-stack в DOM (например, public-interest-zone). */
body.fullscreen-app .geotracker-fab-stack,
#app.fullscreen-app #geotrackerFabStack,
.fullscreen-map ~ .geotracker-fab-stack {
    display: none !important;
}

/* На самой странице Геотрекера FAB не нужна — кнопка открывает
   ту же секцию, в которой юзер уже находится. */
body.geotracker-active .geotracker-fab-stack {
    display: none !important;
}

/* На странице Геотрекера отключаем нижний отступ #app.
   По умолчанию #app { padding: 16px; padding-bottom: 100px; } —
   100px снизу зарезервированы под bottom-nav. На странице
   Геотрекера нужен индивидуальный padding-bottom: 0px,
   чтобы контент/фон секции прилегал к нижней границе экрана. */
body.geotracker-active #app {
    padding-bottom: 0;
}

/* =========================================================
   Индивидуальный padding для раздела Достижений (#sectionGeotracker).

   Базовый .section имеет padding: 16px со всех сторон, из-за чего
   между hero-блоком и верхней границей экрана появляется лишний
   отступ. Здесь обнуляем вертикальные отступы (0 сверху/снизу),
   оставляя горизонтальные 16px — так hero визуально прилегает к
   верхней кромке, а контент не «липнет» к краям экрана.
   ========================================================= */
#sectionGeotracker {
    padding: 0px 32px;
}

/* ============================================================
   Бейдж «Заработано сегодня» (в FAB-стеке).

   Современный glassmorphism-pill с тёплым янтарным градиентом,
   мягким свечением, тонкой «стеклянной» границей и pulse-анимацией
   иконки звезды. Адаптируется под светлую/тёмную тему.

   Структура:
     .today-stars-badge        — основной pill
     .today-stars-badge--empty — нейтральный «пустой» стиль (0 ★)
     .today-stars-badge--hidden — display:none

   Позиционирование: под FAB по центру снизу (не вбок), чтобы не
   обрезаться границами `.geotracker-fab-stack` (56×56) и не
   вылезать за safe-area. Бейдж «свисает» вниз от FAB.
   ========================================================= */

/* CSS-переменные бейджа (можно переопределить в dark-theme) */
.geotracker-fab-stack .today-stars-badge {
    /* Цвета активного состояния */
    --tsb-grad-from: #FFB347;       /* светлый янтарь */
    --tsb-grad-to:   #FF6F00;       /* насыщенный оранжевый */
    --tsb-glow:      rgba(255, 138, 0, 0.55);
    --tsb-border:    rgba(255, 255, 255, 0.6);
    --tsb-text:      #fff;
    --tsb-ring:      var(--card-bg, #fff);

    /* Цвета «пустого» состояния (0 ★) */
    --tsb-empty-from: #c8ccd1;
    --tsb-empty-to:   #8a9097;
    --tsb-empty-glow: rgba(0, 0, 0, 0.18);
    --tsb-empty-text: #fff;
}

body.dark-theme .geotracker-fab-stack .today-stars-badge {
    --tsb-grad-from: #FFC971;
    --tsb-grad-to:   #FF8A00;
    --tsb-glow:      rgba(255, 153, 51, 0.65);
    --tsb-border:    rgba(255, 255, 255, 0.28);
    --tsb-ring:      var(--card-bg, #3a3a3a);
    --tsb-empty-from: #6a6f76;
    --tsb-empty-to:   #4a4f55;
    --tsb-empty-glow: rgba(0, 0, 0, 0.35);
}

.geotracker-fab-stack {
    /* Контейнер должен вмещать бейдж, торчащий вверх. */
    overflow: visible;
}

.geotracker-fab-stack .today-stars-badge {
    position: absolute;
    left: 50%;
    /* Бейдж свисает вниз от FAB (не сверху) */
    top: calc(100% + 10px);
    transform: translateX(-50%);
    z-index: 2;
    height: 30px;
    padding: 0 14px 0 11px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;

    /* Glassmorphism: полупрозрачный градиент + размытие подложки
       (для областей, где под бейджем видно содержимое). */
    background:
        linear-gradient(135deg,
            var(--tsb-grad-from) 0%,
            var(--tsb-grad-to) 100%);
    color: var(--tsb-text);
    font-size: 12.5px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.2px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;

    /* Тонкая «стеклянная» граница поверх градиента */
    border: 1px solid var(--tsb-border);
    -webkit-backdrop-filter: blur(8px) saturate(140%);
    backdrop-filter: blur(8px) saturate(140%);

    /* Многослойная тень: мягкий glow + drop + кольцо вокруг бейджа
       (кольцо сливается с фоном страницы, отделяя бейдж от FAB). */
    box-shadow:
        0 0 0 2px var(--tsb-ring),
        0 6px 18px var(--tsb-glow),
        0 1px 0 rgba(255, 255, 255, 0.4) inset,
        0 -1px 0 rgba(0, 0, 0, 0.08) inset;

    user-select: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;

    /* Плавные переходы для интерактивных состояний */
    transition:
        transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1),
        box-shadow 0.2s ease,
        background 0.25s ease,
        opacity 0.25s ease;
    pointer-events: auto;

    /* Появление: slide-up (снизу) + fade-in + лёгкий overshoot.
       Бейдж "выскакивает" из-под FAB. */
    animation: tsb-pop-in 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) both;
    will-change: transform, opacity;
}

@keyframes tsb-pop-in {
    0% {
        opacity: 0;
        transform: translateX(-50%) translateY(-6px) scale(0.6);
    }
    60% {
        opacity: 1;
        transform: translateX(-50%) translateY(2px) scale(1.05);
    }
    100% {
        opacity: 1;
        transform: translateX(-50%) translateY(0) scale(1);
    }
}

.geotracker-fab-stack .today-stars-badge:hover {
    transform: translateX(-50%) translateY(1px) scale(1.04);
    box-shadow:
        0 0 0 2px var(--tsb-ring),
        0 10px 24px var(--tsb-glow),
        0 1px 0 rgba(255, 255, 255, 0.45) inset,
        0 -1px 0 rgba(0, 0, 0, 0.08) inset;
}

.geotracker-fab-stack .today-stars-badge:active {
    transform: translateX(-50%) translateY(0) scale(0.94);
    transition-duration: 0.08s;
}

.geotracker-fab-stack .today-stars-badge:focus-visible {
    outline: 2px solid var(--tsb-grad-to);
    outline-offset: 3px;
}

/* Иконка звезды — мягкое свечение и лёгкий pulse,
   чтобы привлекать внимание, когда есть награды. */
.geotracker-fab-stack .today-stars-badge i {
    font-size: 13px;
    line-height: 1;
    color: var(--tsb-text);
    /* Эффект свечения вокруг иконки */
    filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.85))
            drop-shadow(0 0 8px var(--tsb-glow));
    animation: tsb-star-pulse 2.4s ease-in-out infinite;
    transform-origin: center;
}

@keyframes tsb-star-pulse {
    0%, 100% {
        transform: scale(1) rotate(0deg);
        filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.85))
                drop-shadow(0 0 8px var(--tsb-glow));
    }
    50% {
        transform: scale(1.18) rotate(-6deg);
        filter: drop-shadow(0 0 6px rgba(255, 255, 255, 1))
                drop-shadow(0 0 14px var(--tsb-glow));
    }
}

.geotracker-fab-stack .today-stars-badge span {
    line-height: 1;
    /* Лёгкий текстовый glow для лучшей читаемости на градиенте */
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.18);
}

/* Скрытие бейджа без !important, чтобы не конфликтовать
   с другими правилами. */
.geotracker-fab-stack .today-stars-badge--hidden {
    display: none;
}

/* «Пустое» состояние (0 ★) — спокойный серый pill с blur,
   без pulse-анимации звезды — чтобы не отвлекал, когда наград нет. */
.geotracker-fab-stack .today-stars-badge--empty {
    background: linear-gradient(135deg,
        var(--tsb-empty-from) 0%,
        var(--tsb-empty-to) 100%);
    color: var(--tsb-empty-text);
    box-shadow:
        0 0 0 2px var(--tsb-ring),
        0 4px 12px var(--tsb-empty-glow),
        0 1px 0 rgba(255, 255, 255, 0.18) inset,
        0 -1px 0 rgba(0, 0, 0, 0.06) inset;
    border-color: rgba(255, 255, 255, 0.22);
}

.geotracker-fab-stack .today-stars-badge--empty i {
    animation: none;
    filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.15));
    opacity: 0.85;
}

.geotracker-fab-stack .today-stars-badge--empty span {
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.12);
}

/* Уважаем prefers-reduced-motion: отключаем pulse и pop-in */
@media (prefers-reduced-motion: reduce) {
    .geotracker-fab-stack .today-stars-badge {
        animation: none;
    }
    .geotracker-fab-stack .today-stars-badge i {
        animation: none;
    }
}

/* ============================================================
   Адаптивные размеры бейджа.

   Базовый размер (десктоп >1024px): font-size 12.5px, height 30px.
   Уменьшаем пропорционально для меньших экранов. Все размеры
   связаны единым коэффициентом (≈0.78 для планшетов, ≈0.68 для
   средних телефонов, ≈0.68 для маленьких — по требованию дизайна).
   ========================================================= */

/* Планшеты (большие) */
@media (max-width: 1024px) {
    .geotracker-fab-stack .today-stars-badge {
        top: calc(100% + 9px);
        height: 27px;
        padding: 0 12px 0 10px;
        font-size: 11px;
        gap: 5px;
    }
    .geotracker-fab-stack .today-stars-badge i {
        font-size: 11.5px;
    }
}

/* Планшеты (маленькие) / большие телефоны */
@media (max-width: 768px) {
    .geotracker-fab-stack .today-stars-badge {
        top: calc(100% + 8px);
        height: 23px;
        padding: 0 10px 0 8px;
        font-size: 9.5px;
        gap: 4px;
        letter-spacing: 0.1px;
    }
    .geotracker-fab-stack .today-stars-badge i {
        font-size: 10px;
    }
}

/* Телефоны (стандарт) */
@media (max-width: 480px) {
    .geotracker-fab-stack .today-stars-badge {
        top: calc(100% + 7px);
        height: 21px;
        padding: 0 9px 0 7px;
        font-size: 8.5px;
        gap: 4px;
        letter-spacing: 0.05px;
        /* Тонкая тень чуть меньше — соответствует уменьшенному размеру */
        box-shadow:
            0 0 0 1.5px var(--tsb-ring),
            0 4px 12px var(--tsb-glow),
            0 1px 0 rgba(255, 255, 255, 0.4) inset,
            0 -1px 0 rgba(0, 0, 0, 0.08) inset;
    }
    .geotracker-fab-stack .today-stars-badge:hover {
        transform: translateX(-50%) translateY(1px) scale(1.05);
        box-shadow:
            0 0 0 1.5px var(--tsb-ring),
            0 6px 16px var(--tsb-glow),
            0 1px 0 rgba(255, 255, 255, 0.45) inset,
            0 -1px 0 rgba(0, 0, 0, 0.08) inset;
    }
    .geotracker-fab-stack .today-stars-badge i {
        font-size: 9px;
    }
}

/* Очень маленькие экраны (≤360px — старые Android, iPhone SE 1st gen) */
@media (max-width: 360px) {
    .geotracker-fab-stack .today-stars-badge {
        top: calc(100% + 6px);
        height: 19px;
        padding: 0 8px 0 6px;
        font-size: 7.5px;
        gap: 3px;
    }
    .geotracker-fab-stack .today-stars-badge i {
        font-size: 8px;
    }
}

/* ============================================================
   Таймлайн пользователя.
   Используется в модальном окне детального таймлайна на дашборде
   (см. #timelineDetailModal). Стили разметки `.widget-timeline`
   / `.widget-timeline-item` объявлены на самом классе, без
   привязки к контейнеру `.widget-user-stats`, чтобы одинаково
   работать в любом месте, где такой список может понадобиться.

   Визуально — современная «rail»-хронология: непрерывная
   вертикальная линия слева, на ней — круглые иконки-бейджи
   разного цвета в зависимости от типа события, справа — карточка
   с цветным градиентным фоном (оттенок по типу), «пилюлей»
   времени и текстом события. При наведении карточка
   приподнимается и получает мягкую тень.
   ============================================================ */

/* Общие токены цветов типов событий. Используются ниже и в
   псевдоэлементах. */
:root {
    --tl-color-broadcast: #614385;
    --tl-color-broadcast-soft: rgba(97, 67, 133, 0.10);
    --tl-color-zone-in: #16a34a;
    --tl-color-zone-in-soft: rgba(22, 163, 74, 0.10);
    --tl-color-zone-out: #ea580c;
    --tl-color-zone-out-soft: rgba(234, 88, 12, 0.10);
    --tl-color-route-in: #2563eb;
    --tl-color-route-in-soft: rgba(37, 99, 235, 0.10);
    --tl-color-route-out: #1d4ed8;
    --tl-color-route-out-soft: rgba(29, 78, 216, 0.10);
    --tl-color-stop: #d97706;
    --tl-color-stop-soft: rgba(217, 119, 6, 0.12);
    --tl-color-move: #db2777;
    --tl-color-move-soft: rgba(219, 39, 119, 0.10);
}
body.dark-theme {
    --tl-color-broadcast-soft: rgba(167, 139, 250, 0.16);
    --tl-color-zone-in-soft: rgba(74, 222, 128, 0.16);
    --tl-color-zone-out-soft: rgba(251, 146, 60, 0.16);
    --tl-color-route-in-soft: rgba(96, 165, 250, 0.16);
    --tl-color-route-out-soft: rgba(59, 130, 246, 0.16);
    --tl-color-stop-soft: rgba(251, 191, 36, 0.16);
    --tl-color-move-soft: rgba(244, 114, 182, 0.16);
}

.widget-timeline {
    position: relative;
    list-style: none;
    margin: 0;
    padding: 6px 4px 6px 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: 360px;
    overflow-y: auto;
    /* Скроллбар в стиле дашборда */
    scrollbar-width: thin;
    scrollbar-color: var(--wus-border-strong) transparent;
}
.widget-timeline::-webkit-scrollbar {
    width: 6px;
}
.widget-timeline::-webkit-scrollbar-thumb {
    background: var(--wus-border-strong);
    border-radius: 3px;
}
/* Непрерывная вертикальная «rail»-линия, соединяющая все
   события. Тонкая, с лёгким градиентом прозрачности по краям,
   чтобы «тонула» в фоне у первого и последнего события. */
.widget-timeline::before {
    content: '';
    position: absolute;
    left: 25px;
    top: 24px;
    bottom: 24px;
    width: 2px;
    background: linear-gradient(
        to bottom,
        transparent 0%,
        var(--wus-border-strong) 14%,
        var(--wus-border-strong) 86%,
        transparent 100%
    );
    border-radius: 2px;
    pointer-events: none;
    z-index: 0;
}

.widget-timeline-item {
    position: relative;
    display: block;
    padding: 12px 14px 12px 56px;
    border: 1px solid var(--wus-border);
    border-radius: 12px;
    background: var(--wus-bg-elev);
    color: var(--wus-text);
    font-size: 13px;
    line-height: 1.45;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
    transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
    z-index: 1;
}
.widget-timeline-item:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 18px -8px rgba(15, 23, 42, 0.18);
    border-color: var(--wus-border-strong);
}
/* Цветной градиент-акцент по типу события (мягкая «подсветка»
   верхней части карточки). На тёмной теме усиливается через
   переопределённые --tl-color-*-soft переменные выше. */
.widget-timeline-item[data-ev-type="broadcast_started"],
.widget-timeline-item[data-ev-type="broadcast_stopped"] {
    background-image: linear-gradient(135deg, var(--tl-color-broadcast-soft), transparent 65%);
}
.widget-timeline-item[data-ev-type="entered_zone"] {
    background-image: linear-gradient(135deg, var(--tl-color-zone-in-soft), transparent 65%);
}
.widget-timeline-item[data-ev-type="left_zone"] {
    background-image: linear-gradient(135deg, var(--tl-color-zone-out-soft), transparent 65%);
}
.widget-timeline-item[data-ev-type="entered_route"] {
    background-image: linear-gradient(135deg, var(--tl-color-route-in-soft), transparent 65%);
}
.widget-timeline-item[data-ev-type="left_route"] {
    background-image: linear-gradient(135deg, var(--tl-color-route-out-soft), transparent 65%);
}
.widget-timeline-item[data-ev-type="stopped_at"] {
    background-image: linear-gradient(135deg, var(--tl-color-stop-soft), transparent 65%);
}
.widget-timeline-item[data-ev-type="moved_segment"] {
    background-image: linear-gradient(135deg, var(--tl-color-move-soft), transparent 65%);
}

/* Круглый бейдж-иконка слева, поверх rail-линии.
   Используется ::before элемента списка: цвет и иконка
   задаются через data-ev-type. */
.widget-timeline-item::before {
    content: '\f04b'; /* fa-play, fallback */
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    position: absolute;
    left: 11px;
    top: 14px;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--us-bg, #ffffff);
    color: var(--tl-color-broadcast);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    line-height: 1;
    z-index: 2;
    box-shadow:
        0 0 0 4px var(--us-bg, #ffffff),
        0 2px 6px rgba(15, 23, 42, 0.12);
}
body.dark-theme .widget-timeline-item::before {
    background: var(--us-bg, #1f2937);
    box-shadow:
        0 0 0 4px var(--us-bg, #1f2937),
        0 2px 6px rgba(0, 0, 0, 0.45);
}

/* Иконка и цвет бейджа по типу события. Unicode-коды — это
   codepoints из Font Awesome 6 Free (solid). */
.widget-timeline-item[data-ev-type="broadcast_started"]::before {
    content: '\f144'; /* fa-circle-play */
    color: var(--tl-color-broadcast);
}
.widget-timeline-item[data-ev-type="broadcast_stopped"]::before {
    content: '\f28b'; /* fa-circle-pause */
    color: var(--tl-color-broadcast);
}
.widget-timeline-item[data-ev-type="entered_zone"]::before {
    content: '\f3c5'; /* fa-location-dot */
    color: var(--tl-color-zone-in);
}
.widget-timeline-item[data-ev-type="left_zone"]::before {
    content: '\f3c5'; /* fa-location-dot */
    color: var(--tl-color-zone-out);
}
.widget-timeline-item[data-ev-type="entered_route"]::before {
    content: '\f4d7'; /* fa-route */
    color: var(--tl-color-route-in);
}
.widget-timeline-item[data-ev-type="left_route"]::before {
    content: '\f4d7'; /* fa-route */
    color: var(--tl-color-route-out);
}
.widget-timeline-item[data-ev-type="stopped_at"]::before {
    content: '\f276'; /* fa-map-pin */
    color: var(--tl-color-stop);
}
.widget-timeline-item[data-ev-type="moved_segment"]::before {
    content: '\f554'; /* fa-person-walking */
    color: var(--tl-color-move);
}

/* Время события — компактная «пилюля» сверху карточки. */
.widget-timeline-time {
    display: inline-block;
    font-variant-numeric: tabular-nums;
    color: var(--wus-text-muted);
    font-weight: 600;
    font-size: 11px;
    letter-spacing: 0.02em;
    background: var(--wus-bg, transparent);
    border: 1px solid var(--wus-border);
    border-radius: 999px;
    padding: 2px 9px;
    margin-bottom: 2px;
    vertical-align: middle;
}
.widget-timeline-text {
    display: block;
    color: var(--wus-text);
    word-break: break-word;
    font-size: 14px;
    line-height: 1.25;
}
.widget-timeline-item[data-ev-type="stopped_at"][data-addr-state="pending"] .widget-timeline-text {
    color: var(--wus-text-muted);
    font-style: italic;
}
.widget-timeline-item[data-ev-type="stopped_at"][data-addr-state="error"] .widget-timeline-text,
.widget-timeline-item[data-ev-type="stopped_at"][data-addr-state="unknown"] .widget-timeline-text {
    color: var(--wus-text-muted);
}

@media (max-width: 540px) {
    .widget-timeline {
        max-height: 260px;
        gap: 6px;
    }
    .widget-timeline-item {
        padding: 10px 12px 10px 50px;
        font-size: 12px;
    }
    .widget-timeline-item::before {
        left: 9px;
        top: 12px;
        width: 24px;
        height: 24px;
        font-size: 11px;
    }
    .widget-timeline::before {
        left: 21px;
    }
}

/* ============================================================
 * Кнопка «Таймлайн (24ч)» на дашборде.
 *
 * Использует стандартный 3D-pushable стиль (`.pushable`) из
 * общей секции «Pushable buttons» (Uiverse-стиль):
 * синий фон, объёмная кромка через `.edge` и тень через
 * `.shadow`, приподнимающийся `.front` при hover.
 * Внутри `.front` — иконка `fa-timeline` и текст подписи.
 *
 * Подробный таймлайн показывается в модальном окне
 * `#timelineDetailModal` (см. ниже), а сама кнопка открывает
 * его по клику.
 * ============================================================ */
.widget-user-stats-subhead--button {
    /* Кнопка полностью наследует стиль `.pushable`. Здесь
       оставляем только ширину и сброс базовых стилей
       дашбордных subhead-классов, чтобы `.pushable` мог
       спокойно отрисовать свою 3D-хромографию. */
    width: 100%;
    margin: 20px 0 0 0;
    /* Небольшой компактный вариант: уменьшаем паддинги/шрифт,
       чтобы кнопка-«subhead» не занимала слишком много
       вертикали по сравнению с обычными текстовыми subhead. */
}
.widget-user-stats-subhead--button .front {
    padding: 10px 18px;
    font-size: 0.78rem;
    letter-spacing: 0.9px;
    gap: 8px;
}
.widget-user-stats-subhead--button .widget-user-stats-subhead-label {
    /* Обычный текст подписи внутри `.front`. */
    font-weight: 600;
}

/* Подробный таймлайн внутри модалки. Базовая разметка
 * `.widget-timeline` / `.widget-timeline-item` уже оформлена
 * выше (без привязки к `.widget-user-stats`). Здесь только
 * снимаем искусственное ограничение высоты 360px: в модалке
 * скролл обеспечивает сам `.modal-content`. */
.timeline-detail-modal-body {
    margin-top: 4px;
}
.timeline-detail-modal-body .widget-timeline {
    max-height: none;
    overflow: visible;
}

/* ============================================================
 * Виджет «Исследование местности» (Исследование местности).
 *
 * Карточки районов / городов с прогресс-баром, пройденным
 * путём и % исследования от суммарной длины дорог OSM.
 *
 * Современный дизайн: glassmorphism, мягкие тени, градиентные
 * прогресс-бары со «shimmer»-анимацией, тонкие иконки и
 * адаптивная сетка статистики. Только CSS — HTML виджета не
 * меняется, разметка остаётся прежней.
 * ============================================================ */

/* Локальные токены виджета — наследуются от родителя .dashboard-widget */
.dashboard-widget.widget-exploration {
    /* Базовый .dashboard-widget имеет min-height: 130px.
       Виджет исследования содержит шапку + два заголовка секций +
       две карусели (города / районы) с точками индикатора — для
       корректного размещения без наслоения и без вертикальной
       прокрутки body требуется бóльшая высота. 640px достаточно
       для обеих каруселей на десктопе при компактных карточках. */
    min-height: 640px;
    --expl-radius-sm: 8px;
    --expl-radius-md: 14px;
    --expl-radius-lg: 18px;
    /* Тени/фон/граница завязаны на семантические переменные темы,
       объявленные в :root/.dark-theme, — это позволяет виджету
       одинаково выглядеть в обеих темах без дублирования селекторов. */
    --expl-shadow-sm: var(--expl-surface-shadow-sm);
    --expl-shadow-md: var(--expl-surface-shadow-md);
    --expl-bg: color-mix(in srgb,
        var(--widget-accent, #064a53) 6%,
        var(--expl-surface-bg, #ffffff));
    --expl-border: color-mix(in srgb,
        var(--widget-accent, #064a53) 18%,
        var(--expl-surface-border, transparent));
    --expl-border-strong: color-mix(in srgb,
        var(--widget-accent, #064a53) 32%,
        var(--expl-surface-border-strong, transparent));
    --expl-track: color-mix(in srgb,
        var(--widget-accent, #064a53) 12%,
        var(--expl-surface-track, rgba(15, 23, 42, 0.05)));
}

.dashboard-widget.widget-exploration .widget-body {
    display: flex;
    flex-direction: column;
    gap: 10px;
    /* Растягиваем body на всю доступную высоту виджета,
       чтобы контент заполнял родительский контейнер, а не
       "висел" сверху при растяжении grid-ячейки. */
    flex: 1 1 auto;
    min-height: 0;
    /* Базовый .widget-body ограничен max-height: 240px — сбрасываем
       его, чтобы виджет мог занимать всю свою min-height (640px)
       без обрезания контента. overflow-y: auto включает единый
       вертикальный скролл для всего содержимого виджета, когда
       оно не помещается: шапка секции + обе карусели скроллятся
       как единое целое, а не каждая карточка отдельно. overflow-x:
       hidden — чтобы peek-эффект следующей карточки не порождал
       горизонтальный скроллбар на уровне body. */
    max-height: none;
    overflow-x: hidden;
    overflow-y: auto;
    /* Тонкий акцентный скроллбар — единый на весь виджет. */
    scrollbar-width: thin;
}

/* ---------- Шапка виджета ---------------------------------------- */
.widget-exploration-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 12px;
    font-size: 12px;
    color: var(--text-muted, #6b7280);
    padding: 0 2px;
}

.widget-exploration-header-source {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-weight: 600;
    font-size: 12.5px;
    color: var(--widget-accent);
    padding: 5px 10px;
    border-radius: 999px;
    background: color-mix(in srgb,
        var(--widget-accent, #064a53) 10%,
        transparent);
    border: 1px solid color-mix(in srgb,
        var(--widget-accent, #064a53) 22%,
        transparent);
    letter-spacing: 0.01em;
}

.widget-exploration-header-source i {
    font-size: 13px;
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.06));
}

.widget-exploration-header-meta {
    font-size: 11.5px;
    opacity: 0.9;
    font-variant-numeric: tabular-nums;
}

/* ---------- Предупреждение --------------------------------------- */
.widget-exploration-warning {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    background: linear-gradient(135deg,
        rgba(249, 115, 22, 0.14),
        rgba(249, 115, 22, 0.06));
    color: #c2410c;
    border: 1px solid rgba(249, 115, 22, 0.22);
    border-radius: var(--expl-radius-md);
    font-size: 12.5px;
    line-height: 1.45;
}

.widget-exploration-warning i {
    flex: 0 0 auto;
    font-size: 14px;
}

/* ---------- Заголовки секций ------------------------------------ */
.widget-exploration-section-title {
    position: relative;
    font-size: 10.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted, #6b7280);
    padding: 2px 2px 0;
    display: flex;
    align-items: center;
    gap: 8px;
}

.widget-exploration-section-title::after {
    content: '';
    flex: 1 1 auto;
    height: 1px;
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--text-muted, #6b7280) 22%, transparent),
        transparent);
    border-radius: 1px;
}

/* ---------- Каскадная фильтрация (FEATURE 2026-07-04
 *             feature/exploration-cascading-filters) -------------
 *
 * Подсказка под заголовком секции: «Выбрана область: Минская —
 * отображаются её города» / «Отображаются все города».
 * Мягкий текст muted, чтобы не конкурировать с карточками.
 *
 * Также сообщение о пустом результате фильтра («Нет городов в
 * этой области»). Показывается вместо карусели. */
.widget-exploration-filter-hint {
    font-size: 11.5px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--text-muted, #64748b);
    padding: 4px 2px 6px;
    display: flex;
    align-items: center;
    gap: 6px;
    /* Лёгкий акцент-чип слева, чтобы подсказка визуально
     * выделялась среди обычного meta-текста, но не выглядела
     * как ошибка/предупреждение. */
    border-left: 2px solid
        color-mix(in srgb, var(--widget-accent, #064a53) 45%, transparent);
    padding-left: 8px;
    margin: 4px 0 6px;
}

.widget-exploration-filter-hint::before {
    content: '\f0b0';
    /* fa-solid/fa-filter — иконка-подсказка «применён фильтр».
     * Подгружается из FontAwesome (уже подключён глобально). */
    font-family: 'Font Awesome 6 Free', 'FontAwesome';
    font-weight: 900;
    font-size: 11px;
    color: var(--widget-accent, #064a53);
    flex: 0 0 auto;
    opacity: 0.85;
}

.widget-exploration-filter-empty {
    font-size: 12px;
    line-height: 1.45;
    color: var(--text-muted, #64748b);
    padding: 10px 12px;
    margin: 4px 0 8px;
    background: color-mix(in srgb,
        var(--widget-accent, #064a53) 6%,
        transparent);
    border: 1px dashed color-mix(in srgb,
        var(--widget-accent, #064a53) 28%,
        transparent);
    border-radius: 10px;
}

body.dark-theme .widget-exploration-filter-hint {
    color: var(--text-muted, #94a3b8);
}

body.dark-theme .widget-exploration-filter-empty {
    color: var(--text-muted, #94a3b8);
}

/* ---------- Dropdown-селект секции (FEATURE 2026-07-04
 *             feature/exploration-dropdown-select) -------------
 *
 * Компактный «прыжок к карточке»: список областей / городов /
 * районов в стиле .us-button (как у #dashUserStatsSelect). Связан
 * с каруселью через __explorationCarouselApi: выбор пункта
 * прокручивает карусель к нужному слайду; ручная прокрутка
 * карусели — синхронно подтягивает select. */
.widget-exploration-select-wrap {
    /* Локальный override цветовой схемы us-button под акцент виджета
     * (тёмно-бирюзовый в widget-tint-exploration, см.
     * .widget-tint-exploration { --widget-accent: #064a53 }).
     * Стили us-button берут значения из --us-* — переопределяем
     * именно их, чтобы вся кнопка/popover перекрасились без
     * дополнительных правил. */
    --us-accent: var(--widget-accent, #064a53);
    --us-accent-soft: color-mix(in srgb,
        var(--widget-accent, #064a53) 12%, transparent);
    --us-active: color-mix(in srgb,
        var(--widget-accent, #064a53) 14%, transparent);
    --us-ring: 0 0 0 4px color-mix(in srgb,
        var(--widget-accent, #064a53) 22%, transparent);
    /* Уменьшаем кнопку относительно дефолтного us-button, чтобы
     * визуально соответствовать компактному списку секции (далее
     * идут карточки). Min-height уменьшен до 40px. */
    position: relative;
}

.widget-exploration-select-wrap .us-wrapper {
    margin: 0;
}

/* Сбрасываем дефолтные margin-top/bottom у кастомной кнопки,
 * иначе глобальный `input, select, button { margin: 10px 0 }`
 * добавит лишние 10px сверху/снизу между заголовком секции и
 * каруселью. */
.widget-exploration-select-wrap .us-button {
    margin: 0;
    min-height: 40px;
    padding: 6px 10px 6px 14px;
    font-size: 13.5px;
    /* Делаем границу чуть тоньше под акцент виджета — основной
     * us-button использует --us-border-strong, для этих селектов
     * берём более мягкий --us-border. */
    border-color: color-mix(in srgb,
        var(--widget-accent, #06b6d4) 22%,
        var(--us-border, rgba(15, 23, 42, 0.08)));
}

.widget-exploration-select-wrap .us-button-label {
    font-size: 13.5px;
    font-weight: 500;
    color: var(--text-primary, #0f172a);
}

.widget-exploration-select-wrap .us-button-placeholder .us-button-label {
    color: var(--text-muted, #64748b);
}

/* Тёмная тема — наследуется от body.dark-theme .us-wrapper,
 * но явно скорректируем label. */
body.dark-theme .widget-exploration-select-wrap .us-button-label {
    color: var(--text-primary, #f1f5f9);
}
body.dark-theme .widget-exploration-select-wrap
    .us-button-placeholder .us-button-label {
    color: var(--text-muted, #94a3b8);
}

/* В выпадающих списках секций исследования бывает много пунктов
 * (например, 12 городов). Дефолтная max-height попавера (360px)
 * показывает 6-7 пунктов за раз и скрывает остальные за тонким
 * scrollbar'ом, который трудно заметить. Расширяем попавер и
 * делаем scrollbar более заметным.
 *
 * Попавер при создании помечается атрибутом
 * `data-exploration-popover="1"` (см. _initExplorationSectionSelects
 * в app.js), а вложенный .us-list — атрибутом
 * `data-expedition-list="1"`. CSS-правила ниже опираются именно
 * на эти атрибуты, потому что сам попавер выносится в <body>
 * (компонентом UserSelect), а не лежит внутри
 * .widget-exploration-select-wrap. */
.us-popover[data-exploration-popover="1"] {
    /* Ограничиваем высоту попавера так, чтобы было видно ровно
     * 6 пунктов списка (≈44px каждый, включая padding) + строка
     * поиска (~48px) + рамка/паддинги. Итого 280px. Если пунктов
     * больше — внутри списка включается overflow-y: auto с
     * явным скроллбаром и градиентной подсказкой снизу.
     *
     * ВАЖНО: компонент UserSelect (user-select.js, open())
     * ставит попаверу inline `style.display = 'block'`, который
     * без `!important` бьёт CSS-правило `.us-popover { display:
     * flex }`. Без flex-контейнера дочерний .us-list теряет
     * `flex: 1 1 auto` и растёт по содержимому — прокрутка не
     * включается, потому что overflow-y:auto у list активируется
     * только когда у list есть фиксированная высота от родителя.
     * Поэтому принудительно восстанавливаем flex-раскладку
     * именно для попаверов исследования через `!important`. */
    display: flex !important;
    flex-direction: column !important;
    max-height: min(280px, calc(100vh - 24px)) !important;
    overflow: hidden !important;
}

/* Прокручиваемый список внутри попавера.
 *
 * Критично: parent (.us-popover) теперь явно display:flex (см.
 * правило выше), и list должен занимать всё свободное место по
 * вертикали через `flex: 1 1 auto`. `min-height: 0` нужен,
 * потому что у flex-child по умолчанию min-height: auto, что
 * не позволяет сжиматься меньше содержимого — без этого
 * overflow-y:auto у list не сработает даже при наличии
 * фиксированной высоты родителя. */
.us-list[data-expedition-list="1"] {
    flex: 1 1 auto !important;
    min-height: 0 !important;
    overflow-y: auto !important;
    overflow-x: hidden !important;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: var(--us-border-strong) transparent;
    /* Градиентная подсказка «прокрутите дальше» внизу списка.
     * mask-image на самом списке работает во всех браузерах и не
     * зависит от позиционирования псевдоэлементов внутри скролл-
     * контейнера. Верхний край не подсвечиваем — список открывается
     * сверху и верхний пункт всегда виден. */
    -webkit-mask-image: linear-gradient(180deg,
        #000 0,
        #000 calc(100% - 28px),
        transparent 100%);
    mask-image: linear-gradient(180deg,
        #000 0,
        #000 calc(100% - 28px),
        transparent 100%);
}
.us-list[data-expedition-list="1"]::-webkit-scrollbar {
    width: 8px;
}
.us-list[data-expedition-list="1"]::-webkit-scrollbar-thumb {
    background: var(--us-border-strong);
    border-radius: 8px;
    border: 2px solid transparent;
    background-clip: padding-box;
    min-height: 24px;
}
.us-list[data-expedition-list="1"]::-webkit-scrollbar-thumb:hover {
    background: var(--us-accent);
    background-clip: padding-box;
    border: 2px solid transparent;
}
.us-list[data-expedition-list="1"]::-webkit-scrollbar-track {
    background: transparent;
}

/* ---------- Список карточек ------------------------------------- */
.widget-exploration-cards {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* ---------- Карточка -------------------------------------------- */
.widget-exploration-card {
    position: relative;
    background: var(--expl-bg);
    border: 1px solid var(--expl-border);
    border-radius: var(--expl-radius-lg);
    /* Компактные внутренние отступы — две карусели (города/районы)
       должны уместиться в виджете без наслоения. */
    padding: 16px 18px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    /* overflow: hidden — карточка не имеет собственного вертикального
       скролла. Если контента больше, чем помещается в виджет, скролл
       появляется единый на уровне .widget-body (см. .dashboard-widget
       .widget-exploration .widget-body). overflow-x: hidden сохраняем,
       чтобы декоративные ::before/::after не порождали горизонтальный
       скроллбар. */
    overflow: hidden;
    isolation: isolate;
    transition: transform 0.25s ease,
                border-color 0.25s ease;
    backdrop-filter: saturate(140%) blur(2px);
    -webkit-backdrop-filter: saturate(140%) blur(2px);
    /* Высота карточки определяется её собственным контентом. Слайд
       (flex-родитель) подстраивается под карточку — это позволяет
       карточкам иметь разную высоту (например, когда у одного района
       длинное название), и всё прокручивается единым скроллом виджета. */
    height: auto;
}

/* Тонкая акцентная полоска сверху карточки */
.widget-exploration-card::before {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 2px;
    background: linear-gradient(90deg,
        transparent 0%,
        var(--widget-accent) 50%,
        transparent 100%);
    opacity: 0.55;
    pointer-events: none;
    z-index: 1;
}

/* Декоративный «glow» в правом верхнем углу */
.widget-exploration-card::after {
    content: '';
    position: absolute;
    top: -40px;
    right: -40px;
    width: 140px;
    height: 140px;
    background: radial-gradient(circle,
        color-mix(in srgb, var(--widget-accent) 35%, transparent) 0%,
        transparent 70%);
    pointer-events: none;
    opacity: 0.55;
    z-index: 0;
}

.widget-exploration-card:hover {
    transform: translateY(-1px);
    border-color: var(--expl-border-strong);
}

.widget-exploration-card > * {
    position: relative;
    z-index: 1;
}

/* Тонкий акцентный скроллбар для всего виджета — единый, появляется
   только когда содержимое (шапка секции + обе карусели + точки) не
   помещается в min-height виджета. */
.dashboard-widget.widget-exploration .widget-body::-webkit-scrollbar {
    width: 8px;
}
.dashboard-widget.widget-exploration .widget-body::-webkit-scrollbar-track {
    background: transparent;
}
.dashboard-widget.widget-exploration .widget-body::-webkit-scrollbar-thumb {
    background: color-mix(in srgb,
        var(--widget-accent) 28%, transparent);
    border-radius: 999px;
}
.dashboard-widget.widget-exploration .widget-body::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb,
        var(--widget-accent) 48%, transparent);
}

.widget-exploration-card-title {
    font-size: 17px;
    font-weight: 650;
    letter-spacing: -0.005em;
    /* --text-color определена в :root (.dark-theme), поэтому
       заголовок карточки читается на обеих темах: тёмный текст на
       светлой подложке и светлый на тёмной. */
    color: var(--text-color, #111827);
    word-break: break-word;
    line-height: 1.2;
}

.widget-exploration-card-subtitle {
    font-size: 11.5px;
    font-weight: 500;
    color: var(--text-muted, #6b7280);
    margin-top: -4px;
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    gap: 5px;
    padding: 2px 8px;
    border-radius: 999px;
    background: color-mix(in srgb,
        var(--widget-accent) 7%,
        transparent);
    border: 1px solid color-mix(in srgb,
        var(--widget-accent) 14%,
        transparent);
}

.widget-exploration-card-subtitle::before {
    content: '';
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--widget-accent);
    flex: 0 0 auto;
}

/* ---------- Процент исследования ------------------------------- */
.widget-exploration-card-progress {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: 22px;
    font-weight: 750;
    letter-spacing: -0.02em;
    color: var(--widget-accent);
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    /* --expl-progress-hi: светлый край градиента (белый по умолчанию).
       Через переменную при необходимости можно затемнить светлый край
       на тёмной теме, чтобы сохранить контраст с подложкой. */
    background: linear-gradient(135deg,
        var(--widget-accent) 0%,
        color-mix(in srgb, var(--widget-accent) 55%, var(--expl-progress-hi, #ffffff)) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
}

.widget-exploration-card-progress-label {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted, #6b7280);
    margin-left: 2px;
    -webkit-text-fill-color: var(--text-muted, #6b7280);
}

/* ---------- Прогресс-бар ---------------------------------------- */
.widget-exploration-card-bar {
    position: relative;
    width: 100%;
    height: 8px;
    background: var(--expl-track);
    border-radius: 999px;
    overflow: hidden;
}

.widget-exploration-card-bar-fill {
    height: 100%;
    /* финальная ширина приходит из инлайн style="width:…%" в HTML */
    /* --expl-bar-hi: светлый край градиента заполнения (белый по
       умолчанию). На тёмной теме светлый край оставляем белым — он
       делает акцентный цвет ярче на тёмной подложке. */
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--widget-accent) 75%, var(--expl-bar-hi, #ffffff)) 0%,
        var(--widget-accent) 50%,
        color-mix(in srgb, var(--widget-accent) 85%, #000000) 100%);
    border-radius: 999px;
    transition: width 0.6s cubic-bezier(0.22, 1, 0.36, 1);
    position: relative;
    overflow: hidden;
}

/* Анимация блика на заполненной части прогресс-бара */
.widget-exploration-card-bar-fill::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg,
        transparent 0%,
        rgba(255, 255, 255, 0.45) 50%,
        transparent 100%);
    transform: translateX(-100%);
    animation: widget-exploration-shimmer 2.6s ease-in-out infinite;
}

@keyframes widget-exploration-shimmer {
    0%   { transform: translateX(-100%); }
    60%  { transform: translateX(160%); }
    100% { transform: translateX(160%); }
}

/* ---------- Блок статистики ------------------------------------- */
.widget-exploration-card-stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
    margin-top: auto;          /* прижать блок статистики к низу карточки */
    padding-top: 10px;
    border-top: 1px dashed color-mix(in srgb,
        var(--text-muted, #6b7280) 22%,
        transparent);
}

.widget-exploration-card-stat {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    padding: 6px 8px;
    border-radius: 10px;
    background: color-mix(in srgb,
        var(--widget-accent) 4%,
        transparent);
    transition: background 0.2s ease;
}

.widget-exploration-card-stat:hover {
    background: color-mix(in srgb,
        var(--widget-accent) 9%,
        transparent);
}

.widget-exploration-card-stat-label {
    font-size: 9.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted, #6b7280);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

/* Мини-иконки для подписей статистики через ::before.
   Используем CSS mask — наследует цвет от родителя. */
.widget-exploration-card-stat-label::before {
    content: '';
    width: 11px;
    height: 11px;
    flex: 0 0 auto;
    background-color: var(--widget-accent);
    -webkit-mask-position: center;
            mask-position: center;
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
    -webkit-mask-size: contain;
            mask-size: contain;
    opacity: 0.85;
}

/* Пройдено — иконка маршрута */
.widget-exploration-card-stat:nth-child(1) .widget-exploration-card-stat-label::before {
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><circle cx='6' cy='19' r='2.5'/><circle cx='18' cy='5' r='2.5'/><path d='M8.2 17.5h7.6a3 3 0 0 0 0-6H8.2a3 3 0 0 1 0-6h7.6'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><circle cx='6' cy='19' r='2.5'/><circle cx='18' cy='5' r='2.5'/><path d='M8.2 17.5h7.6a3 3 0 0 0 0-6H8.2a3 3 0 0 1 0-6h7.6'/></svg>");
}

/* Всего дорог — иконка дороги */
.widget-exploration-card-stat:nth-child(2) .widget-exploration-card-stat-label::before {
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><path d='M4 22 9 2h6l5 20'/><path d='M12 6v2M12 12v2M12 18v2'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><path d='M4 22 9 2h6l5 20'/><path d='M12 6v2M12 12v2M12 18v2'/></svg>");
}

.widget-exploration-card-stat-value {
    font-size: 17px;
    font-weight: 700;
    /* --text-color определена в :root (.dark-theme), поэтому
       значение статистики читается на обеих темах. */
    color: var(--text-color, #111827);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

/* FEATURE (2026-07-04, feature/exploration-progress):
   вариант stat-value для бабблов «уточняется… NN%». Снимаем
   nowrap и ellipsis, чтобы баббл с pct-суффиксом мог
   переноситься на две строки внутри узкой ячейки (~80px)
   и не обрезался. overflow убираем тоже, но min-width: 0 на
   родительской ячейке (grid minmax(0, 1fr)) не даёт бабблу
   растянуть карточку. */
.widget-exploration-card-stat-value--pending {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    line-height: 1.2;
}

/* Состояние «данные OSM ещё не пришли или недоступны» —
   показываем «уточняется…» в приглушённом цвете. */
.widget-exploration-card-pending {
    display: inline-flex;
    align-items: center;
    /* flex-wrap: разрешаем перенос pct на новую строку, если в
       stat-value не хватает места (узкая карточка на мобиле). */
    flex-wrap: wrap;
    gap: 4px;
    color: var(--text-muted, #6b7280);
    font-weight: 500;
    font-size: 12px;
    opacity: 0.95;
    padding: 3px 8px;
    border-radius: 999px;
    background: color-mix(in srgb,
        var(--text-muted, #6b7280) 10%,
        transparent);
    /* Не даём бабблу вылезать за границы stat-value: */
    max-width: 100%;
    /* И разрешаем перенос текста «уточняется…» при сильной
       нехватке места, чтобы pct всегда был виден. */
    line-height: 1.25;
}

@keyframes widget-exploration-pending-pulse {
    0%, 100% { opacity: 0.5; }
    50%      { opacity: 0.95; }
}
.widget-exploration-card-pending::before {
    content: '';
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    vertical-align: middle;
    flex: 0 0 auto;
    animation: widget-exploration-pending-pulse 1.4s ease-in-out infinite;
}

/* FEATURE (2026-07-04, feature/exploration-progress):
   вариант «уточняется… N%» — добавляет процент загрузки данных
   внутрь существующего баббла, чтобы сохранить пульсирующую
   точку и общий стиль. Чтобы «уточняется… NN%» помещался в
   узкую ячейку карточки (≈80px на десктопе и ≈60px на мобиле):
     - никакого border-left: раньше он «съедал» 1px + 6px padding-left;
     - только margin-left + чуть более тёмный текст + bold — визуальный
       разделитель через font-weight, без потери места;
     - tabular-nums — чтобы NN% не «прыгал» при изменении;
     - min-width: 0 на родителе .widget-exploration-card-stat
       гарантирует, что баббл не вылезает за ячейку (см. grid
       minmax(0, 1fr) ниже). */
.widget-exploration-card-pending-pct {
    margin-left: 2px;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    /* Чуть темнее базового цвета баббла, чтобы визуально
       отделить число от «уточняется…» без рамки. */
    color: color-mix(in srgb, var(--text-color, #111827) 75%, transparent);
    opacity: 1;
    flex: 0 0 auto;
}

/* ---------- Адаптив --------------------------------------------- */
@media (max-width: 540px) {
    .dashboard-widget.widget-exploration .widget-body {
        gap: 12px;
    }
    .widget-exploration-cards {
        gap: 10px;
    }
    .widget-exploration-card {
        padding: 12px 14px;
        border-radius: var(--expl-radius-md);
    }
    .widget-exploration-card-stats {
        grid-template-columns: 1fr 1fr;
        gap: 6px;
    }
    .widget-exploration-card-progress {
        font-size: 19px;
    }
    .widget-exploration-card-title {
        font-size: 14.5px;
    }
    .widget-exploration-header-source {
        font-size: 12px;
        padding: 4px 9px;
    }
    .widget-exploration-header-meta {
        font-size: 11px;
    }
}

/* ---------- Тёмная тема ---------------------------------------- */
body.dark-theme .dashboard-widget.widget-exploration {
    /* Акцент #064a53 (light theme) — очень тёмный, на тёмной подложке
       контраст ~1.1:1 — фактически невидим. Подменяем на светлый
       бирюзовый #5eead4 (teal-300): сохраняет «бирюзовое» ощущение
       виджета (карта OSM / сегменты), контраст с #expl-surface-bg
       (~#2e2e2e) ≈ 8.5:1 — отлично читается на тёмном фоне и в
       градиентах прогресса, и в иконках stats, и в активных точках
       карусели. Все дочерние правила, наследующие --widget-accent
       (subtitles, dots, bars, nav-кнопки, gradient «X% исследовано»,
       track-fill, OSM-чип, dropdown select и т.п.) автоматически
       перекрашиваются — без дублирования media/селекторов. */
    --widget-accent: #5eead4;
    --expl-bg: color-mix(in srgb,
        var(--widget-accent, #064a53) 9%,
        rgba(255, 255, 255, 0.03));
    --expl-border: color-mix(in srgb,
        var(--widget-accent, #064a53) 22%,
        rgba(255, 255, 255, 0.05));
    --expl-border-strong: color-mix(in srgb,
        var(--widget-accent, #064a53) 38%,
        rgba(255, 255, 255, 0.08));
    --expl-track: color-mix(in srgb,
        var(--widget-accent, #064a53) 18%,
        rgba(255, 255, 255, 0.04));
    --expl-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.30),
                      0 4px 14px rgba(0, 0, 0, 0.22);
    --expl-shadow-md: 0 1px 2px rgba(0, 0, 0, 0.30),
                      0 12px 28px -10px rgba(0, 0, 0, 0.45),
                      0 20px 48px -20px rgba(0, 0, 0, 0.50);
}

body.dark-theme .widget-exploration-card {
    backdrop-filter: saturate(140%) blur(8px);
    -webkit-backdrop-filter: saturate(140%) blur(8px);
}
body.dark-theme .widget-exploration-warning {
    background: linear-gradient(135deg,
        rgba(249, 115, 22, 0.20),
        rgba(249, 115, 22, 0.08));
    color: #fdba74;
    border-color: rgba(249, 115, 22, 0.30);
}
body.dark-theme .widget-exploration-card-progress {
    background: linear-gradient(135deg,
        var(--widget-accent) 0%,
        color-mix(in srgb, var(--widget-accent) 55%, #ffffff) 100%);
    -webkit-background-clip: text;
            background-clip: text;
}
body.dark-theme .widget-exploration-card-stat {
    background: color-mix(in srgb,
        var(--widget-accent) 6%,
        rgba(255, 255, 255, 0.02));
}
body.dark-theme .widget-exploration-card-stat:hover {
    background: color-mix(in srgb,
        var(--widget-accent) 12%,
        rgba(255, 255, 255, 0.03));
}

/* Уважаем системную настройку «уменьшить движение». */
@media (prefers-reduced-motion: reduce) {
    .widget-exploration-card,
    .widget-exploration-card-bar-fill,
    .widget-exploration-track,
    .widget-exploration-slide,
    .widget-exploration-nav {
        transition: none;
    }
    .widget-exploration-card-bar-fill::after,
    .widget-exploration-card-pending::before {
        animation: none;
    }
}

/* ============================================================
 * Карусель карточек исследования.
 *
 * Структура:
 *   .widget-exploration-carousel
 *     ├─ .widget-exploration-nav × 2 (prev / next)
 *     └─ .widget-exploration-track   (scroll-snap контейнер)
 *         └─ .widget-exploration-slide × N
 *
 * На широких экранах «peek» — виден кусочек следующей карточки,
 * на узких — по одной, с нативным свайпом.
 * ============================================================ */
.widget-exploration-carousel {
    position: relative;
    /* Без дополнительного отступа сверху — карточка и так имеет
       собственный padding, а лишний margin съедает драгоценную
       высоту в ограниченном виджете. */
    margin-top: 0;
    --expl-peek: 0px; /* смещение peek-эффекта для теней */
    /* Карусели идут друг за другом по контенту — НЕ делят высоту
       пополам. Когда обе карусели не помещаются в виджет, единый
       вертикальный скролл включается на уровне .widget-body. */
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
}

.widget-exploration-track {
    display: flex;
    gap: 20px;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    /* Скрываем системный скроллбар — навигация через кнопки/точки */
    scrollbar-width: none;            /* Firefox */
    -ms-overflow-style: none;          /* IE / Edge legacy */
    padding: 4px 2px 14px;             /* место под тень карточки */
    margin: 0 -2px;                    /* компенсация padding */
    scroll-padding-left: 2px;
    /* Высота track определяется контентом (карточками). Когда
       карточки не помещаются в виджет, скроллится весь
       .widget-body, а не отдельные карусели. */
    flex: 0 0 auto;
    min-height: 0;
    /* Подсказка: карточки можно тащить мышью (drag-to-swipe).
       На touch-устройствах работает нативный pan + scroll-snap. */
    cursor: grab;
    /* Разрешаем нативный pan в обоих направлениях — иначе
       touch-action: pan-y запрещает браузеру горизонтальный pan
       и scroll-snap на тач-устройствах не работает. */
    touch-action: pan-x pan-y;
}
.widget-exploration-track::-webkit-scrollbar {
    display: none;                     /* Chrome / Safari */
}
.widget-exploration-track:focus-visible {
    outline: 2px solid color-mix(in srgb,
        var(--widget-accent) 50%, transparent);
    outline-offset: 4px;
    border-radius: 14px;
}

/* Состояние «пользователь тащит слайд» — визуальная обратная связь */
.widget-exploration-carousel.is-dragging .widget-exploration-track {
    cursor: grabbing;
    scroll-snap-type: none;            /* отключаем snap, чтобы не дёргало */
    scroll-behavior: auto;
}
.widget-exploration-carousel.is-dragging .widget-exploration-slide {
    /* слегка уменьшаем анимации во время drag, чтобы не лагало */
    transition: none;
}
.widget-exploration-carousel.is-dragging .widget-exploration-card {
    transform: scale(0.99);
}

.widget-exploration-slide {
    /* По умолчанию — одна карточка на всю ширину карусели. */
    flex: 0 0 100%;
    min-width: 0;
    /* Высота слайда определяется его собственной карточкой
       (height: auto у .widget-exploration-card). Это позволяет
       карточкам иметь разную высоту внутри одной карусели и
       прокручиваться единым вертикальным скроллом виджета. */
    height: auto;
    scroll-snap-align: start;
    scroll-snap-stop: always;
    /* Лёгкая анимация появления при первом рендере. */
    animation: widget-exploration-slide-in 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.widget-exploration-slide:nth-child(2) { animation-delay: 0.04s; }
.widget-exploration-slide:nth-child(3) { animation-delay: 0.08s; }
.widget-exploration-slide:nth-child(4) { animation-delay: 0.12s; }
.widget-exploration-slide:nth-child(5) { animation-delay: 0.16s; }
.widget-exploration-slide:nth-child(6) { animation-delay: 0.20s; }

@keyframes widget-exploration-slide-in {
    0% {
        opacity: 0;
        transform: translate3d(18px, 0, 0) scale(0.985);
    }
    100% {
        opacity: 1;
        transform: translate3d(0, 0, 0) scale(1);
    }
}

/* На широких экранах показываем «peek» следующей карточки. */
@media (min-width: 900px) {
    .widget-exploration-slide {
        /* карточка занимает 78% ширины, оставшиеся 22% — peek */
        flex-basis: 78%;
        scroll-snap-align: start;
    }
    .widget-exploration-carousel {
        --expl-peek: 22%;
    }
}
@media (min-width: 1200px) {
    .widget-exploration-slide {
        flex-basis: 70%;
    }
    .widget-exploration-carousel {
        --expl-peek: 30%;
    }
}

/* Кнопки навигации (prev / next) -------------------------- */
.widget-exploration-nav {
    position: absolute;
    top: 50%;
    z-index: 6;
    width: 34px;
    height: 34px;
    margin-top: -6px; /* компенсация под высоту dots ниже */
    border-radius: 50%;
    border: 1px solid color-mix(in srgb,
        var(--widget-accent) 32%, transparent);
    /* --expl-surface-bg определена в :root/.dark-theme — на светлой
       теме белая подложка, на тёмной — тёмная (без неё был бы белый
       круг на тёмном фоне, ломающий весь контраст карусели). */
    background: color-mix(in srgb,
        var(--widget-accent) 6%, var(--expl-surface-bg, #ffffff));
    color: var(--widget-accent);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    /* --expl-nav-shadow определена в :root/.dark-theme — парные
       тени под обе темы. */
    box-shadow: var(--expl-nav-shadow);
    backdrop-filter: saturate(160%) blur(10px);
    -webkit-backdrop-filter: saturate(160%) blur(10px);
    opacity: 0;
    transform: translateY(-50%) scale(0.92);
    transition:
        opacity 0.22s ease,
        transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1),
        background 0.18s ease,
        color 0.18s ease,
        box-shadow 0.22s ease;
}
.widget-exploration-carousel:hover .widget-exploration-nav:not(:disabled),
.widget-exploration-carousel:focus-within .widget-exploration-nav:not(:disabled) {
    opacity: 1;
    transform: translateY(-50%) scale(1);
}
.widget-exploration-nav:not(:disabled):hover {
    background: var(--widget-accent);
    /* --expl-on-accent-fg: на светлой теме белый, на тёмной —
       тёмный (контраст к светлому акцентному фону). */
    color: var(--expl-on-accent-fg, #ffffff);
    transform: translateY(-50%) scale(1.08);
    box-shadow:
        0 2px 6px rgba(15, 23, 42, 0.10),
        0 14px 30px -10px color-mix(in srgb, var(--widget-accent) 50%, transparent);
}
.widget-exploration-nav:not(:disabled):active {
    transform: translateY(-50%) scale(0.94);
}
.widget-exploration-nav:disabled {
    cursor: default;
    pointer-events: none;
    /* FIX (fix/exploration-carousel-select-conflict):
       Делаем disabled-кнопки nav ВИДИМЫМИ, но приглушёнными, а не
       полностью прозрачными. Иначе после выбора региона в dropdown
       одна из кнопок (prev/next) становится невидимой, и пользователь
       воспринимает это как «кнопки пропали / перелистывание сломано»
       (fix/exploration-carousel-select-conflict).
       pointer-events: none остаётся — клики по disabled не должны
       срабатывать. opacity 0.25 — заметно, но визуально «отключено».
       На touch-устройствах @media (hover:none) переопределяет opacity
       на 0.75 для enabled, но disabled остаётся 0.25 благодаря
       более специфичному селектору :disabled. */
    opacity: 0.25;
}
.widget-exploration-nav:disabled:hover {
    /* На hover disabled-кнопка остаётся приглушённой, не «оживает» —
       её селектор :not(:disabled) в hover-правиле выше не совпадает,
       а это правило явно держит 0.25. */
    opacity: 0.25;
}
.widget-exploration-nav-prev {
    left: 4px;
}
.widget-exploration-nav-next {
    right: 4px;
}

/* На тач-устройствах кнопки видны всегда (нет hover). */
@media (hover: none) {
    .widget-exploration-nav {
        opacity: 0.75;
        transform: translateY(-50%) scale(1);
    }
    .widget-exploration-nav:not(:disabled):hover {
        transform: translateY(-50%) scale(1.08);
    }
}

/* Активный слайд — лёгкий glow и приподнятость.
   На остальных — мягкое «затухание», чтобы фокус был на активной. */
.widget-exploration-slide {
    opacity: 0.6;
    transform: scale(0.97);
    transition:
        opacity 0.35s ease,
        transform 0.45s cubic-bezier(0.22, 1, 0.36, 1),
        filter 0.35s ease;
    filter: saturate(0.9);
}
.widget-exploration-slide.is-active {
    opacity: 1;
    transform: scale(1);
    filter: saturate(1);
    z-index: 2;
}
.widget-exploration-slide.is-active .widget-exploration-card {
    border-color: color-mix(in srgb, var(--widget-accent) 38%, transparent);
}

/* Адаптив для карусели ------------------------------------- */
@media (max-width: 540px) {
    .widget-exploration-track {
        gap: 12px;
        padding: 8px 0 20px;
        margin: 0;
        scroll-padding-left: 0;
    }
    .widget-exploration-slide {
        flex-basis: 100%;
    }
    .widget-exploration-card {
        padding: 22px 18px;
        gap: 16px;
    }
    .widget-exploration-card-progress {
        font-size: 26px;
    }
    .widget-exploration-card-title {
        font-size: 18px;
    }
    .widget-exploration-card-stat {
        padding: 9px 10px;
    }
    .widget-exploration-card-stat-value {
        font-size: 16px;
    }
    .widget-exploration-nav {
        width: 32px;
        height: 32px;
        font-size: 10px;
    }
    .widget-exploration-nav-prev { left: 2px; }
    .widget-exploration-nav-next { right: 2px; }
}

/* Тёмная тема для карусели --------------------------------- */
body.dark-theme .widget-exploration-nav {
    background: color-mix(in srgb,
        var(--widget-accent) 10%, rgba(20, 20, 24, 0.65));
    border-color: color-mix(in srgb, var(--widget-accent) 36%, rgba(255,255,255,0.06));
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.40),
        0 8px 24px -8px rgba(0, 0, 0, 0.55);
}
body.dark-theme .widget-exploration-nav:not(:disabled):hover {
    background: var(--widget-accent);
    color: #0b1220;
    box-shadow:
        0 2px 6px rgba(0, 0, 0, 0.50),
        0 14px 30px -10px color-mix(in srgb, var(--widget-accent) 60%, transparent);
}
body.dark-theme .widget-exploration-slide {
    filter: saturate(0.85) brightness(0.95);
}
body.dark-theme .widget-exploration-slide.is-active {
    filter: saturate(1) brightness(1);
}

/* ============================================================
   [P1 #11] Player Level — RPG-карточка уровня игрока.
   Реализована в стиле виджета «Квесты дня» (тот же
   .widget-tint-amber, тот же паттерн .widget-header +
   .widget-counter + .quest-card + .widget-quests-summary).
   Ниже — только дельта к этому общему стилю:
     1) Чип в hero (то же, что раньше);
     2) Категорийные акценты для карточек уровня (current / next);
     3) Описание под прогрессом в карточке;
     4) Кнопка «Поделиться уровнем» (вынесена под сводку);
     5) Toast-подтверждение шаринга;
     6) Адаптивные правки.
   ============================================================ */

/* Чип в hero — единый layout с другими чипами, но с
   «золотой» подложкой, чтобы визуально выделялся как
   «главная характеристика» игрока. Палитра согласована
   с .widget-tint-gold (#facc15, см. .widget-tint-gold),
   которая визуально отличается от streak-чипа (widget-tint-orange
   родительской .widget-streak). */
.achievements-hero-chip--level {
    background: linear-gradient(135deg,
        rgba(250, 204, 21, 0.34),
        rgba(202, 138, 4, 0.28) 60%,
        rgba(133, 77, 14, 0.22));
    position: relative;
    overflow: hidden;
}

.achievements-hero-chip--level::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.32),
        inset 0 -1px 0 rgba(0, 0, 0, 0.18);
}

.achievements-hero-chip--level:hover,
.achievements-hero-chip--level:focus-visible {
    background: linear-gradient(135deg,
        rgba(250, 204, 21, 0.48),
        rgba(202, 138, 4, 0.40) 60%,
        rgba(133, 77, 14, 0.32));
}

/* [Hero 2.1] Streak-чип — тёплый оранжевый, чтобы визуально
   отличаться от «золотого» уровня (#facc15) и не сливаться
   с ним. Палитра согласована с .widget-tint-orange (#f97316)
   виджета #widget-streak, чтобы на странице streak и его
   hero-якорь читались одной метой. По умолчанию streak>0 —
   для streak=0 ставятся приглушённые тона через .is-zero
   (см. ниже). */
.achievements-hero-chip--streak {
    background: linear-gradient(135deg,
        rgba(249, 115, 22, 0.32),
        rgba(194, 65, 12, 0.26) 60%,
        rgba(124, 45, 18, 0.20));
    position: relative;
    overflow: hidden;
}

.achievements-hero-chip--streak::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.30),
        inset 0 -1px 0 rgba(0, 0, 0, 0.18);
}

.achievements-hero-chip--streak:hover,
.achievements-hero-chip--streak:focus-visible {
    background: linear-gradient(135deg,
        rgba(249, 115, 22, 0.46),
        rgba(194, 65, 12, 0.38) 60%,
        rgba(124, 45, 18, 0.30));
}

/* [Hero 2.1] Streak=0 — нейтральная («приглушённая») окраска.
   Класс ставится из JS (renderAchievementsHeroStats) на чип
   streak, когда ach.streak.current === 0. Тона приглушены
   по насыщенности и контрасту с progress-чипом, чтобы
   «мёртвый» стейт не выглядел ярче активных соседей.
   Дополнительно — пунктирная внутренняя рамка, чтобы
   подчеркнуть «потенциальный, но не начатый» статус. */
.achievements-hero-chip--streak.is-zero {
    background: linear-gradient(135deg,
        rgba(255, 255, 255, 0.10),
        rgba(255, 255, 255, 0.06) 60%,
        rgba(255, 255, 255, 0.04));
}

.achievements-hero-chip--streak.is-zero::before {
    box-shadow: inset 0 0 0 1px dashed rgba(255, 255, 255, 0.32),
        inset 0 1px 0 rgba(255, 255, 255, 0.20);
}

.achievements-hero-chip--streak.is-zero:hover,
.achievements-hero-chip--streak.is-zero:focus-visible {
    background: linear-gradient(135deg,
        rgba(255, 255, 255, 0.18),
        rgba(255, 255, 255, 0.10) 60%,
        rgba(255, 255, 255, 0.06));
}

/* [Hero 2.1, GAM-1.1] Нейтральный якорь для streak-чипа при
   current=0 && longest=0 && ownedShields=0 (полностью «пустой»
   пользователь). В этом состоянии value рендерится как «⭐ 0»
   вместо «🔥 0» — звезда согласуется с Player Level-чипом
   (⭐ {stars}) и не несёт негативной коннотации «прерванной
   серии». Чтобы ⭐ читался как «потенциал», а не как «серая
   пустота», добавляем тонкий золотистый тинт и убираем пунктир
   (визуально отличаем «ещё ничего не было» от «прервано»).
   Класс .is-neutral ставится из JS рядом с .is-zero и
   комбинируется с ним. */
.achievements-hero-chip--streak.is-neutral {
    background: linear-gradient(135deg,
        rgba(253, 224, 71, 0.18),
        rgba(250, 204, 21, 0.12) 60%,
        rgba(202, 138, 4, 0.08));
}

.achievements-hero-chip--streak.is-neutral::before {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22),
        inset 0 -1px 0 rgba(0, 0, 0, 0.10);
}

.achievements-hero-chip--streak.is-neutral:hover,
.achievements-hero-chip--streak.is-neutral:focus-visible {
    background: linear-gradient(135deg,
        rgba(253, 224, 71, 0.30),
        rgba(250, 204, 21, 0.20) 60%,
        rgba(202, 138, 4, 0.14));
}

.achievements-hero-chip--streak.is-neutral .achievements-hero-chip-value {
    color: var(--dash-color-star, #fde047);
}

/* [P1 #6 / feat-hero-streak-shield-counter] Pill щита внутри
   streak-чипа: маленькая капсула с эмодзи-щитом и счётчиком.
   Золотой ободок подчёркивает «премиальность» shield-валюты
   (голда за achievement-warmup ★) и согласован с Player Level-чипом
   (#facc15). Появляется только если data-shield-count на чипе
   > 0 (JS setChip выставляет атрибут в renderAchievementsHeroStats).
   Без щитов — обычный текст «🔥 N». */

/* Контейнер, который JS вставляет вместо обычного text в
   .achievements-hero-chip-value. Внутри — два span'а (огонь
   и shield-pill) + разделитель «·». Используем
   display:inline-flex, чтобы дочерние span'ы выстроились в одну
   строку и корректно центрировались относительно друг друга. */
.achievements-hero-chip-value-inner {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    max-width: 100%;
    min-width: 0;
    vertical-align: middle;
}

.achievements-hero-chip-value-fire {
    /* Сохраняем шрифт/цвет родительского .achievements-hero-chip-value,
       но делаем font-variant-numeric:tabular-nums, чтобы цифры не
       «прыгали» при обновлении (1 → 10 → 100). */
    font-variant-numeric: tabular-nums;
}

.achievements-hero-chip-value-sep {
    opacity: 0.6;
    margin: 0 1px;
}

.achievements-hero-chip-shield {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-left: 2px;
    padding: 1px 6px 1px 5px;
    border-radius: 999px;
    background: rgba(250, 204, 21, 0.18);
    border: 1px solid rgba(250, 204, 21, 0.55);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
    color: #92400e;
    font-size: 0.78em;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    /* Без transition на background — мгновенный hover-эффект
       важен для popover с counter "M/3" (хочется сразу видеть
       отклик на наведение, иначе пользователь думает, что
       элемент не интерактивный). */
    transition: background 0.15s ease, border-color 0.15s ease,
        transform 0.15s ease;
}

.achievements-hero-chip-shield:hover,
.achievements-hero-chip-shield:focus-visible {
    background: rgba(250, 204, 21, 0.32);
    border-color: rgba(217, 119, 6, 0.80);
    outline: none;
    transform: translateY(-1px);
}

.achievements-hero-chip-shield:active {
    transform: translateY(0);
}

/* Иконка щита — отдельный <span> с золотым ободком. Размер
   уменьшен относительно стандартного, чтобы не доминировать над
   основным «🔥 N» в value. Лёгкий filter:drop-shadow даёт
   «металлический» отблеск, согласованный с общим «achievements»
   стилем (см. .achievement-badge). */
.achievements-hero-chip-shield-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.1em;
    height: 1.1em;
    font-size: 0.92em;
    line-height: 1;
    filter: drop-shadow(0 0 1px rgba(217, 119, 6, 0.55));
}

.achievements-hero-chip-shield-count {
    font-variant-numeric: tabular-nums;
    margin-left: 1px;
    /* Чуть жирнее, чем у основного значения — чтобы взгляд на
       streak-чипе сначала цеплялся за счётчик щитов (это и есть
       «продающая» единица по P1 #6). */
    font-weight: 800;
}

/* Когда у пользователя 0 щитов — pill вообще не рендерится, но
   класс .is-shielded на чипе можно использовать для других
   эффектов (например, добавить лёгкое свечение справа от value).
   Сейчас не используется, оставлен как точка расширения. */
.achievements-hero-chip--streak:not([data-shield-count])::after,
.achievements-hero-chip--streak[data-shield-count="0"]::after {
    content: none;
}

/* ────────────────────────────────────────────────────────────────────
   [P1 #6 / feat-hero-streak-shield-counter] Popover с пояснением
   «У тебя M щитов …». Позиционируется через position:fixed в JS
   (см. positionStreakShieldsPopover), чтобы избежать clipping от
   overflow:hidden у любых предков. Стрелка указывает на pill
   (вниз — popover под чипом; вверх — popover над чипом при
   дефиците места, см. data-placement).
   ──────────────────────────────────────────────────────────────────── */
.achievements-hero-chip-popover {
    position: fixed;
    z-index: 9999;
    max-width: min(280px, calc(100vw - 24px));
    padding: 10px 12px 11px;
    border-radius: 12px;
    background: var(--card-bg, #ffffff);
    color: var(--text-color, #1f2937);
    border: 1px solid color-mix(in srgb,
        var(--widget-accent-streak, #f97316) 35%, transparent);
    box-shadow: 0 8px 22px rgba(15, 23, 42, 0.18),
        0 2px 6px rgba(15, 23, 42, 0.08);
    font-size: 12.5px;
    line-height: 1.45;
    text-align: left;
    opacity: 0;
    transform: translateY(-4px) scale(0.98);
    pointer-events: none;
    transition: opacity 0.16s ease, transform 0.16s ease;
    /* По умолчанию скрыт; JS снимает атрибут при показе. */
}

.achievements-hero-chip-popover[aria-hidden="false"] {
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: auto;
}

/* Иконка-щит слева от текста — согласована с pill в hero-чипе.
   Небольшой золотой акцент даже внутри popover, чтобы визуально
   «стянуть» связку pill ↔ popover. */
.achievements-hero-chip-popover-icon {
    display: inline-block;
    margin-right: 6px;
    font-size: 13px;
    line-height: 1;
    filter: drop-shadow(0 0 1px rgba(217, 119, 6, 0.55));
    vertical-align: -1px;
}

.achievements-hero-chip-popover-body {
    /* display:inline для корректного расположения иконки и текста
       в одной строке (icon теперь инлайновый <span> перед body). */
    display: inline;
}

/* Стрелочка popover. По умолчанию — сверху (popover под чипом).
   JS переключает data-placement="top" если popover вылезает за
   нижнюю границу viewport — тогда стрелка окажется снизу. */
.achievements-hero-chip-popover-arrow {
    position: absolute;
    top: -6px;
    width: 12px;
    height: 12px;
    background: var(--card-bg, #ffffff);
    border-top: 1px solid color-mix(in srgb,
        var(--widget-accent-streak, #f97316) 35%, transparent);
    border-left: 1px solid color-mix(in srgb,
        var(--widget-accent-streak, #f97316) 35%, transparent);
    transform: rotate(45deg);
}

.achievements-hero-chip-popover[data-placement="top"]
    .achievements-hero-chip-popover-arrow {
    top: auto;
    bottom: -6px;
    border-top: 0;
    border-left: 0;
    border-bottom: 1px solid color-mix(in srgb,
        var(--widget-accent-streak, #f97316) 35%, transparent);
    border-right: 1px solid color-mix(in srgb,
        var(--widget-accent-streak, #f97316) 35%, transparent);
}

/* Когда JS двигает стрелку влево (popover прижат к правому краю
   экрана), визуально её положение меняется через inline-стиль
   left. Класс .is-left оставлен как точка расширения, если в
   будущем понадобится специальная стилизация. */
.achievements-hero-chip-popover-arrow.is-left {
    /* left уже выставлен inline из JS; стилизация самого
       треугольника та же, никаких transform тут не нужно. */
}

/* Dark theme — приглушённый фон popover. Используем уже
   знакомую гамму streak-виджета (тёмно-серый с золотистым
   акцентом). */
body.dark-theme .achievements-hero-chip-popover {
    background: #1f2937;
    color: #f3f4f6;
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.5),
        0 2px 6px rgba(0, 0, 0, 0.3);
}

body.dark-theme .achievements-hero-chip-popover-arrow {
    background: #1f2937;
}

body.dark-theme .achievements-hero-chip-shield {
    background: rgba(250, 204, 21, 0.14);
    border-color: rgba(250, 204, 21, 0.45);
    color: #fde68a;
}

/* prefers-reduced-motion — отключаем плавные transform на pill
   и popover (важно для пользователей с вестибулярными
   нарушениями). */
@media (prefers-reduced-motion: reduce) {
    .achievements-hero-chip-shield,
    .achievements-hero-chip-popover {
        transition: none;
    }
    .achievements-hero-chip-shield:hover,
    .achievements-hero-chip-shield:focus-visible {
        transform: none;
    }
}

/* [Hero 2.1] Rank-чип — единственный из 4-х, который ведёт
   «вовне» (на лидерборд). Без подсказки было неочевидно, что
   чип кликабельный: визуально он не отличается от чипов,
   ведущих к другим виджетам на той же странице. Добавляем
   тонкую подчёркивающую нижнюю линию у label + chevron в
   правом верхнем углу (отдельный HTML-элемент, чтобы не
   конфликтовать с ::after-разделителем между чипами).
   Согласовано с Material-3 «вызываемые» индикаторы
   (underline + trailing icon). */
.achievements-hero-chip--rank .achievements-hero-chip-label {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    text-decoration-color: rgba(255, 255, 255, 0.55);
}

.achievements-hero-chip-chevron {
    position: absolute;
    top: 4px;
    right: 6px;
    font-size: 14px;
    line-height: 1;
    color: rgba(255, 255, 255, 0.7);
    font-weight: 700;
    pointer-events: none;
    transform: translateX(0);
    transition: transform 0.18s ease, color 0.18s ease;
}

.achievements-hero-chip--rank:hover .achievements-hero-chip-chevron,
.achievements-hero-chip--rank:focus-visible .achievements-hero-chip-chevron {
    color: #fff;
    transform: translateX(2px);
}

/* prefers-reduced-motion — отключаем плавный сдвиг chevron. */
@media (prefers-reduced-motion: reduce) {
    .achievements-hero-chip-chevron {
        transition: none;
    }
    .achievements-hero-chip--rank:hover .achievements-hero-chip-chevron,
    .achievements-hero-chip--rank:focus-visible .achievements-hero-chip-chevron {
        transform: none;
    }
}

/* ====================================================================
 * [GAM-RECO #18] «Глобальная карма» — пятый чип в hero-капсуле.
 * Считается на бэкенде GET /dashboard/karma (см. bot/api/routes/karma.js)
 * как взвешенная сумма 5 метрик (streak ×0.3 + achievements ×0.3 +
 * quests ×0.2 + social ×0.1 + premium ×0.1). Источник — существующие
 * таблицы, без миграций БД.
 *
 * Визуально чип выделяется «магическим» фиолетово-розовым градиентом,
 * чтобы не конфликтовать с уже существующими цветами (level — золотой,
 * streak — оранжевый, progress — голубой, rank — серый). Тонкая «капля»
 * в правом нижнем углу (.achievements-hero-chip-karma-dot) подсказывает,
 * что внутри живёт detail-popover с разложением по 5 метрикам (см.
 * .karma-popover ниже).
 *
 * Layout — внутри .achievements-hero-stats (flex-wrap), точно так
 * же как остальные 4 чипа. Ничего не ломает, если /dashboard/karma
 * недоступен: чип просто покажет «—» (как и rank-чип до загрузки).
 * ==================================================================== */
.achievements-hero-chip--karma {
    position: relative;
    --widget-accent-karma: #f2743e;
    --widget-accent-karma-2: #facc15;
    background: linear-gradient(135deg, #f3773d 0%, #facc15 100%);
    color: #fff;
    overflow: visible;
}

.achievements-hero-chip--karma::before {
    /* ::before у chipa занят «символом категории» в общем правиле
       .achievements-hero-chip::before (см. .achievements-hero-chip
       чуть выше). Karma это фиолетовая капля, чтобы не дублировать
       уже занятый ::before — переопределяем контент на «✦».
       Хотя стилистически ✦ = «магический компас», хорошо вяжется
       с «кармой» как агрегатом удачи/активности. */
    background: var(--widget-accent-karma, #a855f7);
    color: #fff;
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.35);
    content: '✦';
}

.achievements-hero-chip--karma:hover,
.achievements-hero-chip--karma:focus-visible {
    /* Поднимаем насыщенность на hover — визуально активный
       interactive-affordance, как у других чипов. */
    filter: saturate(1.15) brightness(1.05);
}

/* «Капля» в правом нижнем углу — индикатор того, что у чипа
   есть развёрнутый popover с breakdown'ом по 5 метрикам.
   Рисуется псевдо-pill (без интерактива), чтобы не дублировать
   логику .achievements-hero-chip-shield для streak-чипа. */
.achievements-hero-chip-karma-dot {
    position: absolute;
    right: 6px;
    bottom: 5px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.85);
    box-shadow: 0 0 0 2px rgba(168, 85, 247, 0.55);
    pointer-events: none;
    animation: karma-dot-pulse 2.4s ease-in-out infinite;
}

@keyframes karma-dot-pulse {
    0%, 100% { transform: scale(1);   opacity: 0.95; }
    50%      { transform: scale(1.4); opacity: 0.55; }
}

@media (prefers-reduced-motion: reduce) {
    .achievements-hero-chip-karma-dot {
        animation: none;
    }
}

/* === Karma Popover =============================================
 * Открывается на hover/focus/touch по чипу. Показывает breakdown
 * по 5 метрикам с прогресс-барами и финальным score.
 *
 * Используем тот же .achievements-hero-chip-popover (уже
 * присутствует в CSS выше для streak-shield) — это позволяет
 * переиспользовать:
 *   - позиционирование (positionStreakShieldsPopover),
 *   - стили (фон, бордер, стрелка),
 *   - dark-theme оверрайды.
 *
 * Контент внутри попавера — отдельная разметка .karma-popover-body
 * с 5 строками и итогом внизу.
 *
 * ВАЖНО: popover сидит на стандартном светлом/тёмном фоне
 * `.achievements-hero-chip-popover` (белый в light theme,
 * тёмно-серый в dark theme). Все цвета текста ДОЛЖНЫ наследовать
 * `color: var(--text-color, #1f2937)` — НЕ переопределяйте
 * на rgba(255,255,255,…), иначе текст станет невидимым на
 * светлом фоне (это была регрессия первой итерации).
 * =============================================================== */
.karma-popover {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 220px;
    max-width: 280px;
    color: inherit;
}

.karma-popover-title {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.7;
    margin: 0 0 2px 0;
}

.karma-popover-score {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin: 0 0 4px 0;
    font-variant-numeric: tabular-nums;
}

.karma-popover-score-value {
    font-size: 26px;
    font-weight: 700;
    line-height: 1;
    color: inherit;
}

.karma-popover-score-max {
    font-size: 12px;
    font-weight: 500;
    opacity: 0.55;
}

.karma-popover-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 4px 0 0 0;
    padding: 0;
    list-style: none;
}

.karma-popover-row {
    display: grid;
    grid-template-columns: 70px 1fr 36px;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    line-height: 1.2;
}

.karma-popover-row-label {
    color: inherit;
    opacity: 0.82;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.karma-popover-row-bar {
    position: relative;
    height: 5px;
    background: color-mix(in srgb,
        currentColor 12%, transparent);
    border-radius: 999px;
    overflow: hidden;
}

.karma-popover-row-bar-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: var(--karma-fill, 0%);
    background: linear-gradient(90deg,
        var(--widget-accent-karma, #a855f7) 0%,
        var(--widget-accent-karma-2, #ec4899) 100%);
    border-radius: inherit;
    transition: width 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}

.karma-popover-row-weight {
    color: inherit;
    opacity: 0.55;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.karma-popover-foot {
    font-size: 11px;
    line-height: 1.4;
    color: inherit;
    opacity: 0.7;
    margin: 4px 0 0 0;
    padding: 6px 8px;
    background: color-mix(in srgb,
        currentColor 6%, transparent);
    border-radius: 6px;
    word-break: break-word;
}

@media (prefers-reduced-motion: reduce) {
    .karma-popover-row-bar-fill {
        transition: none;
    }
}

/* Karma chip в «нулевом» состоянии (до /dashboard/karma ответил
   или вернул error: 'unavailable'): приглушённая капля вместо
   градиента, чтобы не врать «у тебя 999». */
.achievements-hero-chip--karma.is-zero {
    background: rgba(255, 255, 255, 0.15);
    color: rgba(255, 255, 255, 0.65);
}

.achievements-hero-chip--karma.is-zero::before {
    background: rgba(255, 255, 255, 0.25);
    box-shadow: none;
}

.achievements-hero-chip--karma.is-zero .achievements-hero-chip-karma-dot {
    display: none;
}

/* Mobile: на узких экранах капсула чипов уже переходит в wrap;
   чип сам по себе достаточно компактный. Ничего специального
   не делаем — стандартный flex-wrap справится. */

/* [Hero 2.1] Тонкая подпись «▲+N за неделю» под hero-чипом прогресса.
   Показывается, если в .achievements-hero-chip--progress есть
   заполненный [data-week-delta] (JS пишет туда число при deltaWeek>0).
   Пустое значение — ничего не отображаем (без «▲+0 за неделю»). */
.achievements-hero-chip--progress {
    position: relative;
}

.achievements-hero-chip-delta {
    display: none;
    position: absolute;
    left: 50%;
    bottom: -16px;
    transform: translateX(-50%);
    font-size: 10px;
    font-weight: 600;
    line-height: 1;
    padding: 2px 6px;
    border-radius: 999px;
    background: rgba(16, 185, 129, 0.85);
    color: #fff;
    letter-spacing: 0.01em;
    box-shadow: 0 2px 6px rgba(16, 185, 129, 0.35);
    pointer-events: none;
    white-space: nowrap;
    max-width: 140px;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Когда data-week-delta содержит положительное число —
   показываем плашку. data-week-delta-hide используется
   для случая, когда значение есть, но плашку надо скрыть
   (например, delta === 0 — зарезервировано для будущих
   фич принудительного скрытия). */
.achievements-hero-chip--progress[data-week-delta]:not([data-week-delta=""]):not([data-week-delta="0"])
    .achievements-hero-chip-delta {
    display: inline-block;
}

/* [P1 #8] Блок «Близко к разблокировке» (achievement-near-complete):
   слайдер с горизонтальной прокруткой (3-5 КОМПАКТНЫХ карточек),
   поднятый над основной сеткой ачивок (между .widget-header и
   .widget-body). Цель — мотивировать пользователя добрать
   последние проценты до ачивки (goal proximity effect, Locke &
   Latham, 2002).

   Структура:
     .achievement-near-complete       (контейнер)
       .achievement-near-complete-title
         .achievement-near-complete-title-text
         .achievement-near-complete-controls
           .achievement-near-complete-arrow (prev/next)
       .achievement-near-complete-viewport   (overflow:hidden)
         .achievement-near-complete-track    (transform:translateX)
           .achievement-near-complete-card[] (×3-5 + 2 клона)

   Управление:
     - Клик по карточке → прокрутка к бейджу в основной сетке
       + .is-near-pulse (1.5s).
     - Стрелки prev/next — навигация по слайдеру с циклом.
     - Drag (pointer events: мышь + touch + перо) — слайдер тянется
       пальцем / указателем, snap на ближайший слайд при отпускании.
     - Бесконечная прокрутка через клоны первой и последней карточки
       в track (см. initNearCompleteSlider в app.js). */
 .achievement-near-complete {
     margin: 0 12px 14px;
     padding: 10px 12px 12px;
     border-radius: 14px;
     background: linear-gradient(135deg,
         rgba(250, 204, 21, 0.10),
         rgba(251, 146, 60, 0.05));
     border: 1px solid rgba(250, 204, 21, 0.28);
     position: relative;
     overflow: hidden;
     /* Внутри .dashboard-widget (display:flex column) этот блок —
        flex item. По умолчанию flex:0 1 auto, и при нехватке
        высоты (max-height:640px на виджете) всё, что не имеет
        явного flex-shrink:0, схлопывается — у нас оставалось ~30px
        высоты. Жёстко фиксируем размер, чтобы блок всегда
        показывался целиком. */
     flex: 0 0 auto;
     align-self: stretch;
 }
.achievement-near-complete-title {
    margin: 0 0 8px;
    font-size: 13px;
    font-weight: 700;
    color: #b45309;
    display: flex;
    /* align-items: flex-start — когда заголовок переносится на 2
       строки (узкие экраны / длинные локали вроде немецкой),
       стрелки prev/next остаются прижаты сверху, а текст
       свободно переносится вниз и не выходит за рамки. */
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px;
    letter-spacing: 0.01em;
    flex-wrap: wrap;
}
.achievement-near-complete-title-text {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: 1 1 auto;
    min-width: 0;
    /* Разрешаем перенос строк — раньше стоял nowrap + ellipsis,
       из-за чего на узких экранах часть текста уходила за
       границы и обрезалась. */
    overflow-wrap: anywhere;
    word-break: break-word;
    line-height: 1.3;
}
.achievement-near-complete-controls {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
    /* Если места нет, controls уезжают на новую строку под
       заголовком, а не вылезают за край виджета. */
    margin-top: 1px;
}
.achievement-near-complete-arrow {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 1px solid rgba(250, 204, 21, 0.35);
    background: rgba(255, 255, 255, 0.85);
    color: #b45309;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
    font-size: 11px;
    transition: background 0.15s ease, transform 0.15s ease,
        box-shadow 0.15s ease, border-color 0.15s ease;
    -webkit-tap-highlight-color: transparent;
}
.achievement-near-complete-arrow:hover,
.achievement-near-complete-arrow:focus-visible {
    background: rgba(255, 255, 255, 1);
    box-shadow: 0 2px 8px rgba(250, 204, 21, 0.25);
    border-color: rgba(250, 204, 21, 0.55);
    outline: none;
}
.achievement-near-complete-arrow:active {
    transform: scale(0.92);
}
.achievement-near-complete-viewport {
    width: 100%;
    overflow: hidden;
    position: relative;
    border-radius: 10px;
    /* Курсор «grab» показывает, что блок можно тащить. */
    cursor: grab;
}
.achievement-near-complete.is-near-dragging .achievement-near-complete-viewport,
.achievement-near-complete.is-near-dragging {
    cursor: grabbing;
    user-select: none;
}
.achievement-near-complete-track {
    display: flex;
    flex-direction: row;
    gap: 8px;
    width: max-content;
    padding: 2px 0 4px;
    /* will-change подсказывает браузеру держать трек на GPU
       слое, чтобы drag и анимация не дёргались. */
    will-change: transform;
}
.achievement-near-complete-card {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
    min-width: 0;
    /* Компактная «таблетка» ~ 150-180px на узких экранах,
       растягивается на широких за счёт flex-basis ниже. */
    width: calc(100vw - 80px);
    max-width: 200px;
    padding: 6px 10px;
    background: rgba(255, 255, 255, 0.78);
    border: 1px solid rgba(250, 204, 21, 0.25);
    border-radius: 999px;
    text-decoration: none;
    color: inherit;
    transition: transform 0.15s ease, background 0.15s ease,
        box-shadow 0.15s ease;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
@media (min-width: 480px) {
    .achievement-near-complete-card {
        max-width: 180px;
    }
}
.achievement-near-complete-card:hover,
.achievement-near-complete-card:focus-visible {
    background: rgba(255, 255, 255, 0.98);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(250, 204, 21, 0.25);
    outline: none;
}
.achievement-near-complete-card-icon {
    width: 26px;
    height: 26px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    font-size: 14px;
}
.achievement-near-complete-card-icon.achievement-tier-gold {
    background: linear-gradient(135deg, #fde68a, #f59e0b);
    color: #fff;
}
.achievement-near-complete-card-icon.achievement-tier-silver {
    background: linear-gradient(135deg, #e5e7eb, #9ca3af);
    color: #fff;
}
.achievement-near-complete-card-icon.achievement-tier-bronze {
    background: linear-gradient(135deg, #fed7aa, #c2410c);
    color: #fff;
}
.achievement-near-complete-card-icon.achievement-tier-platinum {
    background: linear-gradient(135deg, #e0e7ff, #6366f1);
    color: #fff;
}
.achievement-near-complete-card-icon.achievement-tier-special {
    background: linear-gradient(135deg, #fbcfe8, #be185d);
    color: #fff;
}
.achievement-near-complete-card-body {
    flex: 1;
    min-width: 0;
}
.achievement-near-complete-card-title {
    font-size: 12px;
    font-weight: 600;
    line-height: 1.15;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: #1f2937;
}
.achievement-near-complete-card-pct {
    font-size: 11px;
    font-weight: 700;
    color: #b45309;
    flex-shrink: 0;
    padding-left: 2px;
}

/* Dark theme — нейтральные тёмные поверхности, чтобы карточки
   не светились как в светлой теме, и не теряли контраст с
   фоном виджета. */
body.dark-theme .achievement-near-complete {
    background: linear-gradient(135deg,
        rgba(250, 204, 21, 0.08),
        rgba(251, 146, 60, 0.04));
    border-color: rgba(250, 204, 21, 0.22);
}
body.dark-theme .achievement-near-complete-title {
    color: #fcd34d;
}
body.dark-theme .achievement-near-complete-arrow {
    background: rgba(30, 41, 59, 0.85);
    border-color: rgba(250, 204, 21, 0.3);
    color: #fcd34d;
}
body.dark-theme .achievement-near-complete-arrow:hover,
body.dark-theme .achievement-near-complete-arrow:focus-visible {
    background: rgba(30, 41, 59, 1);
    border-color: rgba(250, 204, 21, 0.55);
}
body.dark-theme .achievement-near-complete-card {
    background: rgba(30, 41, 59, 0.85);
    border-color: rgba(250, 204, 21, 0.22);
}
body.dark-theme .achievement-near-complete-card:hover,
body.dark-theme .achievement-near-complete-card:focus-visible {
    background: rgba(30, 41, 59, 1);
}
body.dark-theme .achievement-near-complete-card-title {
    color: #f1f5f9;
}
body.dark-theme .achievement-near-complete-card-pct {
    color: #fcd34d;
}
@media (prefers-reduced-motion: reduce) {
    .achievement-near-complete-track {
        transition: none !important;
    }
    .achievement-near-complete-arrow,
    .achievement-near-complete-card {
        transition: none;
    }
}

/* Подсветка основного бейджа после клика по near-complete карточке. */
@keyframes achievement-near-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(250, 204, 21, 0); }
    50% { box-shadow: 0 0 0 6px rgba(250, 204, 21, 0.6); }
}
.achievement-badge.is-near-pulse {
    animation: achievement-near-pulse 1.5s ease-in-out;
}
@media (prefers-reduced-motion: reduce) {
    .achievement-badge.is-near-pulse {
        animation: none;
    }
}

/* [P1 #12] Единая «mission toast» система. Контейнер
   фиксируется в нижней центральной части экрана (Material 3
   style). Тосты стекаются снизу вверх (новые внизу). */
.mission-toasts {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%);
    z-index: 9999;
    display: flex;
    flex-direction: column-reverse;
    gap: 8px;
    pointer-events: none;
    max-width: calc(100vw - 32px);
    width: 360px;
}
.mission-toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    background: var(--dash-color-surface, #ffffff);
    border: 1px solid rgba(148, 163, 184, 0.25);
    border-radius: 12px;
    box-shadow: 0 10px 30px -8px rgba(0, 0, 0, 0.18),
                0 2px 6px rgba(0, 0, 0, 0.08);
    color: var(--dash-color-text, #1e293b);
    opacity: 0;
    transform: translateY(20px);
    transition: opacity 0.25s ease, transform 0.25s ease;
}
.mission-toast.is-visible {
    opacity: 1;
    transform: translateY(0);
}
.mission-toast.is-leaving {
    opacity: 0;
    transform: translateY(20px);
}
.mission-toast-icon {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    background: rgba(99, 102, 241, 0.12);
    color: #6366f1;
    font-size: 16px;
}
.mission-toast--achievement_unlocked .mission-toast-icon,
.mission-toast--achievement .mission-toast-icon {
    background: rgba(250, 204, 21, 0.18);
    color: #d97706;
}
.mission-toast--streak_extend .mission-toast-icon,
.mission-toast--streak .mission-toast-icon {
    background: rgba(251, 146, 60, 0.18);
    color: #ea580c;
}
.mission-toast--quest_completed .mission-toast-icon,
.mission-toast--quest .mission-toast-icon {
    background: rgba(16, 185, 129, 0.18);
    color: #059669;
}
.mission-toast--daily_bonus_claimed .mission-toast-icon,
.mission-toast--daily_bonus .mission-toast-icon {
    background: rgba(168, 85, 247, 0.18);
    color: #9333ea;
}
.mission-toast--level_up .mission-toast-icon,
.mission-toast--level .mission-toast-icon {
    background: rgba(236, 72, 153, 0.18);
    color: #db2777;
}
/* [P1 #12] Тип «streak_shield» (покупка / ошибка щита, инвентарь
   полон и т.п.). Иконка в голубых тонах — перекликается с виджетом
   streak-shield (shield/щит) и легко отличима от «огненных» streak-
   milestone-уведомлений. */
.mission-toast--streak_shield .mission-toast-icon {
    background: rgba(59, 130, 246, 0.18);
    color: #2563eb;
}
/* [P1 #12] Тип «success» — универсальный зелёный (используется
   когда конкретный категориальный тип не подходит). */
.mission-toast--success .mission-toast-icon {
    background: rgba(16, 185, 129, 0.18);
    color: #059669;
}
/* [P1 #12] Тип «error» — красный (network-ошибки, ошибки claim
   daily-bonus и т.п.). Чуть жирнее обводка иконки — внимание
   пользователя должно падать в первую очередь на ошибки. */
.mission-toast--error .mission-toast-icon {
    background: rgba(239, 68, 68, 0.18);
    color: #dc2626;
    box-shadow: 0 0 0 1px rgba(239, 68, 68, 0.25) inset;
}
/* [P1 #12] Тип «info» — нейтральный серо-голубой. */
.mission-toast--info .mission-toast-icon {
    background: rgba(99, 102, 241, 0.14);
    color: #4f46e5;
}
.mission-toast-body {
    flex: 1;
    min-width: 0;
}
.mission-toast-title {
    font-size: 14px;
    font-weight: 700;
    line-height: 1.25;
    margin-bottom: 2px;
}
.mission-toast-text {
    font-size: 13px;
    line-height: 1.3;
    color: var(--dash-color-text-muted, #64748b);
}
.mission-toast-close {
    flex: 0 0 auto;
    width: auto;
    min-width: 0;
    align-self: flex-start;
    background: none;
    border: none;
    font-size: 20px;
    line-height: 1;
    color: var(--dash-color-text-muted, #94a3b8);
    cursor: pointer;
    padding: 4px 6px;
}
.mission-toast-close:hover {
    color: var(--dash-color-text, #1e293b);
}
@media (prefers-reduced-motion: reduce) {
    .mission-toast {
        transition: opacity 0.15s ease;
        transform: none;
    }
    .mission-toast.is-visible,
    .mission-toast.is-leaving {
        transform: none;
    }
}
body.dark-theme .mission-toast {
    background: #1e293b;
    color: #e2e8f0;
    border-color: rgba(148, 163, 184, 0.18);
}
body.dark-theme .mission-toast-text {
    color: #94a3b8;
}

/* [P0 #1] Состояние is-empty для hero-чипов: когда данные
   есть (например, каталог ачивок загружен), но пользователь
   ещё не получил ничего. Применяется к .achievements-hero-chip
   через JS (renderAchievementsHeroStats). Стиль приглушает чип
   (низкая непрозрачность), чтобы он не доминировал над активными
   соседями. hidden уже скрывает элемент полностью. */
.achievements-hero-chip.is-empty {
    opacity: 0.55;
}
.achievements-hero-chip.is-empty .achievements-hero-chip-value {
    color: var(--dash-color-text-muted, #94a3b8);
}
.achievements-hero-chip.is-empty .achievements-hero-chip-label {
    color: var(--dash-color-text-muted, #94a3b8);
    font-style: italic;
}

/* [P0 #3] Pulse-glow для кнопки Daily Bonus, когда награда
   доступна (canClaimToday=true). Анимация привлекает внимание
   в первые секунды после открытия дашборда — аналог Strava /
   Coin Master. Длительность 2 с, easing ease-in-out. */
@keyframes daily-bonus-pulse-glow {
    0% {
        box-shadow: 0 0 0 0 rgba(255, 200, 60, 0.6),
                    0 4px 12px rgba(0, 0, 0, 0.2);
        transform: scale(1);
    }
    50% {
        box-shadow: 0 0 0 12px rgba(255, 200, 60, 0),
                    0 6px 16px rgba(255, 200, 60, 0.3);
        transform: scale(1.03);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(255, 200, 60, 0),
                    0 4px 12px rgba(0, 0, 0, 0.2);
        transform: scale(1);
    }
}
.daily-bonus-claim-btn:not(:disabled):not(.is-loading).is-pulsing,
button.daily-bonus-claim-btn:not(:disabled):not(.is-loading).is-pulsing {
    animation: daily-bonus-pulse-glow 2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .daily-bonus-claim-btn:not(:disabled):not(.is-loading).is-pulsing,
    button.daily-bonus-claim-btn:not(:disabled):not(.is-loading).is-pulsing {
        animation: none;
    }
    .daily-bonus-claim-btn.is-shaking,
    button.daily-bonus-claim-btn.is-shaking {
        animation: none;
    }
}

/* [GAM-RECO §3] Shake-feedback на тап по CTA-кнопке Daily Bonus.
   Триггерится из public/app.js (bindDailyBonusClaim →
   pointerdown) — класс .is-shaking добавляется на ~300мс.
   Лёгкая горизонтальная вибрация +scale-down для tactile feel. */
@keyframes daily-bonus-claim-shake {
    0%   { transform: translateX(0)    scale(1); }
    20%  { transform: translateX(-4px) scale(0.97); }
    40%  { transform: translateX(4px)  scale(0.98); }
    60%  { transform: translateX(-3px) scale(0.98); }
    80%  { transform: translateX(2px)  scale(0.99); }
    100% { transform: translateX(0)    scale(1); }
}
.daily-bonus-claim-btn.is-shaking,
button.daily-bonus-claim-btn.is-shaking {
    animation: daily-bonus-claim-shake 0.3s ease-in-out;
}

/* [GAM-RECO §3] Бейдж ⭐ рядом с CTA-кнопкой, если сегодняшняя
   награда ≥ 25★. Контейнер .daily-bonus-claim-wrap группирует
   кнопку с бейджем (inline-flex), сам бейдж — corner-метка. */
.daily-bonus-claim-wrap {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    position: relative;
}
.daily-bonus-stars-badge {
    /* Базовый селектор не выставляет display: чтобы при [hidden]
       (UA-стиль) элемент реально скрывался, а не светился с
       дефолтным `display: inline`. Видимый стиль применяется
       ниже через :not([hidden]). */
    align-items: center;
    gap: 4px;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    line-height: 1.2;
    color: #92400e;
    background: linear-gradient(135deg, #fef3c7, #fde68a);
    border: 1px solid #f59e0b;
    box-shadow: 0 2px 6px -2px rgba(245, 158, 11, 0.5);
    white-space: nowrap;
}
/* Видимое состояние: когда JS снял атрибут hidden (большая награда ≥25★). */
.daily-bonus-stars-badge:not([hidden]) {
    display: inline-flex;
    /* Лёгкий «дышащий» эффект синхронно с pulse-glow, чтобы
       CTA-пара (кнопка + бейдж) привлекала внимание как единое
       целое. Экономим ресурс: только opacity, без scale. */
    animation: daily-bonus-badge-breathe 2s ease-in-out infinite;
}
.daily-bonus-stars-badge .star-icon {
    font-size: 12px;
    line-height: 1;
}
.daily-bonus-claim-wrap:not(.is-pulsing) .daily-bonus-stars-badge,
.daily-bonus-stars-badge[hidden] {
    animation: none;
}
@keyframes daily-bonus-badge-breathe {
    0%, 100% { opacity: 0.85; }
    50%      { opacity: 1; }
}
body.dark-theme .daily-bonus-stars-badge {
    color: #fde68a;
    background: linear-gradient(135deg, rgba(245, 158, 11, 0.22), rgba(251, 191, 36, 0.28));
    border-color: rgba(251, 191, 36, 0.55);
    box-shadow: 0 2px 8px -2px rgba(251, 191, 36, 0.35);
}
@media (prefers-reduced-motion: reduce) {
    .daily-bonus-stars-badge {
        animation: none;
    }
}

/* [P0 #2] Streak reset warning — двухступенчатый:
   • is-warning (orange) — 2..6 часов до сброса
   • is-urgent (red, pulse) — <2 часов до сброса
   Цвета согласованы с .streak-reset-warning (уже есть). */
.streak-reset-warning.is-warning {
    background: linear-gradient(135deg,
        rgba(251, 146, 60, 0.15),
        rgba(251, 146, 60, 0.05));
    border-color: rgba(251, 146, 60, 0.4);
    color: #ea580c;
}
@keyframes streak-warning-pulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.02); }
}
.streak-reset-warning.is-urgent {
    background: linear-gradient(135deg,
        rgba(239, 68, 68, 0.18),
        rgba(239, 68, 68, 0.05));
    border-color: rgba(239, 68, 68, 0.55);
    color: #dc2626;
    animation: streak-warning-pulse 1.5s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .streak-reset-warning.is-urgent {
        animation: none;
    }
}

/* [Hero 2.1] Onboarding-burst: подсветка 3 виджетов-«звёздных
   якорей» при level=1. Карточка пульсирует золотой рамкой, а
   в углу появляется плашка «Старт» (локаль — webapp_hero_onboarding_burst_pill).
   Используется на #widget-quests и #widget-achievements. */
.dashboard-widget.is-onboarding-burst {
    position: relative;
    border-color: rgba(250, 204, 21, 0.45);
    box-shadow:
        0 0 0 1px rgba(250, 204, 21, 0.20),
        0 8px 24px -8px rgba(250, 204, 21, 0.35);
    animation: achievements-onboarding-burst-pulse 2.4s ease-in-out infinite;
}

@keyframes achievements-onboarding-burst-pulse {
    0%, 100% {
        box-shadow:
            0 0 0 1px rgba(250, 204, 21, 0.20),
            0 8px 24px -8px rgba(250, 204, 21, 0.35);
    }
    50% {
        box-shadow:
            0 0 0 2px rgba(250, 204, 21, 0.40),
            0 12px 32px -6px rgba(250, 204, 21, 0.55);
    }
}

/* Плашка «Старт» в правом верхнем углу виджета. Позиционируется
   абсолютно на родителе .dashboard-widget.is-onboarding-burst,
   чтобы не влиять на текущую разметку .widget-header. */
.dashboard-widget.is-onboarding-burst::after {
    content: attr(data-burst-pill);
    position: absolute;
    top: -8px;
    right: 12px;
    padding: 2px 10px;
    border-radius: 999px;
    background: linear-gradient(135deg, #facc15, #ca8a04);
    color: #1f1500;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    box-shadow: 0 4px 10px rgba(202, 138, 4, 0.45);
    pointer-events: none;
    z-index: 2;
}

/* [Hero 2.1] Конкретные карточки ачивок внутри burst-виджета:
   выделяем .first_steps и .onboarded чуть более ярким золотым
   кантом и призывным значком «🎯». Применяется только если
   ачивка ещё НЕ разблокирована (разблокированные не трогаем —
   они и так в фокусе внимания через бейдж). */
.achievement-badge.is-onboarding-target {
    outline: 2px solid rgba(250, 204, 21, 0.65);
    outline-offset: 2px;
    box-shadow: 0 0 0 4px rgba(250, 204, 21, 0.12);
    position: relative;
    z-index: 1;
}

.achievement-badge.is-onboarding-target::before {
    content: "🎯";
    position: absolute;
    top: -8px;
    right: -8px;
    width: 22px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: #facc15;
    font-size: 12px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
    z-index: 2;
}

/* Уважаем prefers-reduced-motion: анимация пульса выключается,
   остаётся только статичная золотая рамка как визуальный маркер. */
@media (prefers-reduced-motion: reduce) {
    .dashboard-widget.is-onboarding-burst {
        animation: none;
    }
}

/* Тело виджета: вертикальный стек карточек уровней,
   как у .widget-quests-body → .quest-list. Переиспользуем
   .quest-card / .quest-icon / .quest-info / .quest-progress
   / .quest-reward / .quest-reward-stars, объявленные
   выше в разделе Daily Quests.
   Сбрасываем базовый .widget-body { max-height: 240px;
   overflow-y: auto; }, чтобы карточки уровня + сводка
   + кнопка шаринга помещались без внутреннего скролла:
   их суммарная высота ~ 230-280px, что не превышает
   естественный размер виджета. */
.widget-player-level-body {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding-top: 4px;
    flex: 1 1 auto;
    min-height: 0;
    overflow: visible;
    max-height: none;
    margin: 0;
}

/* Категорийные акценты для level-карточек. Текущий уровень
   (current) получает зелёный акцент («достигнуто»), следующий
   (next) — янтарный («в процессе»). Палитра согласована с
   .widget-tint-amber и .quest-cat-product/.quest-cat-geo. */
.level-card.level-cat-current {
    --quest-bg: rgba(16, 185, 129, 0.14);
    --quest-fg: #059669;
    --quest-border: rgba(16, 185, 129, 0.40);
}
.level-card.level-cat-next {
    --quest-bg: rgba(245, 158, 11, 0.14);
    --quest-fg: #b45309;
    --quest-border: rgba(245, 158, 11, 0.40);
}

/* Полностью «готовые» карточки (current) — мягкий градиент,
   как у .quest-card.is-completed, чтобы не конкурировать
   с активной «next» карточкой за внимание. */
.level-card.level-cat-current.is-completed {
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--quest-fg) 8%, var(--card-bg, #fff)),
        var(--card-bg, #fff)) !important;
}

/* Описание под прогрессом в карточке уровня: «Прогресс
   до уровня 3 · 48%» / «осталось 10 ★». Шрифт мелкий,
   как у .quest-card .quest-desc (определён в Daily Quests
   через инлайн-стиль; здесь — отдельный класс, чтобы
   не зависеть от инлайна в HTML). */
.level-card .level-card-desc {
    font-size: 10.5px;
    color: var(--text-muted, #888);
    margin-top: 4px;
    line-height: 1.3;
}

/* Сводка внизу виджета (стиль .widget-quests-summary).
   Делаем чуть компактнее за счёт уменьшенных отступов —
   у widget-player-level уже есть две карточки выше,
   и сводка должна «дышать», не выталкивая виджет
   за пределы max-height родителя .dashboard-widget. */
.widget-player-level-summary {
    margin-top: 6px;
}

/* Кнопка «Поделиться уровнем» — вынесена под сводку
   (не внутри .widget-body, чтобы не уезжать в скролл).
   Стиль согласован с .quest-card .quest-claim-btn:
   янтарный градиент #f59e0b → #b45309. По умолчанию
   на всю ширину виджета, чтобы выделяться как
   «основное действие» карточки уровня. */
.player-level-share-btn {
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin-top: 10px;
    padding: 10px 14px;
    border-radius: 999px;
    border: none;
    background: linear-gradient(135deg, #f59e0b 0%, #b45309 100%);
    color: #fff;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.01em;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.18s ease;
}

.player-level-share-btn:hover,
.player-level-share-btn:focus-visible {
    outline: none;
    transform: translateY(-1px);
    box-shadow: 0 4px 14px rgba(180, 83, 9, 0.45);
}

.player-level-share-btn:active {
    transform: translateY(0);
}

.player-level-share-btn i {
    font-size: 14px;
}

/* Toast — короткое подтверждение «Отправлено в Telegram».
   Фиксированно внизу экрана над клавиатурой iOS/Android
   (с учётом safe-area-inset-bottom на iOS 16+). */
.player-level-share-toast {
    position: fixed;
    left: 50%;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    transform: translate(-50%, 14px);
    background: rgba(20, 20, 28, 0.94);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    padding: 10px 18px;
    border-radius: 999px;
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.30),
        0 12px 32px -8px rgba(0, 0, 0, 0.50);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    opacity: 0;
    pointer-events: none;
    z-index: 9999;
    transition: opacity 0.22s ease, transform 0.22s ease;
}

.player-level-share-toast.is-visible {
    opacity: 1;
    transform: translate(-50%, 0);
}

/* Уважаем prefers-reduced-motion — отключаем анимацию
   кнопки шаринга и toast (валидация с другими виджетами). */
@media (prefers-reduced-motion: reduce) {
    .player-level-share-btn,
    .player-level-share-toast {
        transition: none !important;
    }
}

/* Тёмная тема — фон сводки берётся из .widget-quests-summary
   body.dark-theme правил, которые уже определены в разделе
   Daily Quests. Здесь — только локальная подстройка карточек
   уровня, чтобы янтарный и зелёный акценты не «горели»
   слишком ярко на тёмном фоне. */
body.dark-theme .level-card.level-cat-current {
    --quest-bg: rgba(16, 185, 129, 0.10);
    --quest-fg: #10b981;
    --quest-border: rgba(16, 185, 129, 0.32);
}
body.dark-theme .level-card.level-cat-next {
    --quest-bg: rgba(245, 158, 11, 0.10);
    --quest-fg: #f59e0b;
    --quest-border: rgba(245, 158, 11, 0.32);
}

/* ============================================================
 * [P1 #12] STREAK SHIELD — блок защиты streak'а за ★
 * ============================================================
 * Располагается внутри widget-streak, сразу под streak-meta.
 * Стилизован под «RPG-карточку» с фиолетово-голубым градиентом
 * (отличается от оранжевого streak-виджета, чтобы привлечь
 * внимание как отдельная механика).
 *
 * Архитектура:
 *   .streak-shield           — основной контейнер (grid: иконка /
 *                              инфо / кнопка);
 *   .streak-shield-icon      — большой щит с пульсирующим свечением;
 *   .streak-shield-buy       — основная кнопка покупки;
 *   .streak-shield-active    — баннер «щит активен» с таймером;
 *   .streak-shield-pill      — компактные чипы «N/3» и «50 ★»;
 *   state: .is-active        — shield активен (emerald-акцент).
 *
 * Цветовая схема:
 *   primary:  emerald #059669 и его оттенки (защита);
 *   accent:   золотой (стоимость в ★, остаётся янтарным — валюта);
 *   success:  тот же emerald в усиленном виде (активирован).
 *
 * Использует CSS-переменные темы виджета (--widget-streak-*),
 * заданные выше в файле — единый источник для светлой/тёмной темы.
 * ============================================================ */
.streak-shield {
    position: relative;
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 14px;
    align-items: center;
    padding: 14px 16px;
    margin-top: 12px;
    border-radius: 18px;
    /* Основной цвет — emerald #059669 и его оттенки:
       #059669 (emerald-600) → #10b981 (emerald-500) → #34d399 (emerald-400). */
    background:
        linear-gradient(135deg,
            rgba(5, 150, 105, 0.10) 0%,
            rgba(16, 185, 129, 0.10) 50%,
            rgba(52, 211, 153, 0.08) 100%);
    border: 1px solid rgba(5, 150, 105, 0.32);
    box-shadow:
        0 4px 16px rgba(5, 150, 105, 0.10),
        inset 0 1px 0 rgba(255, 255, 255, 0.30);
    overflow: hidden;
    isolation: isolate;
    transition:
        transform 180ms ease-out,
        box-shadow 220ms ease-out,
        border-color 220ms ease-out;
}

/* Лёгкое «дыхание» контейнера — ненавязчивое. Отключается через
   prefers-reduced-motion в самом конце файла (см. ниже). */
@keyframes streak-shield-breathe {
    0%, 100% { box-shadow:
        0 4px 16px rgba(5, 150, 105, 0.10),
        inset 0 1px 0 rgba(255, 255, 255, 0.30); }
    50%      { box-shadow:
        0 6px 22px rgba(16, 185, 129, 0.22),
        inset 0 1px 0 rgba(255, 255, 255, 0.40); }
}
.streak-shield::before {
    /* Тонкая светящаяся «аура» сверху, чтобы блок не сливался с
       streak-виджетом. */
    content: '';
    position: absolute;
    inset: -1px -1px auto -1px;
    height: 1px;
    background: linear-gradient(90deg,
        transparent, rgba(5, 150, 105, 0.60) 50%, transparent);
    pointer-events: none;
}

/* Состояние «щит активен» — успешный emerald-акцент, обводка
   более выраженная, добавляется мягкая пульсация свечения. */
.streak-shield.is-active {
    background:
        linear-gradient(135deg,
            rgba(5, 150, 105, 0.12) 0%,
            rgba(16, 185, 129, 0.10) 50%,
            rgba(52, 211, 153, 0.08) 100%);
    border-color: rgba(5, 150, 105, 0.50);
    box-shadow:
        0 4px 18px rgba(5, 150, 105, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.30);
    animation: streak-shield-breathe 2.4s ease-in-out infinite;
}

/* [GAM-AUDIT #2.3] Визуальная срочность активного щита: зелёный
   → жёлтый → красный по мере истечения TTL. Классы выставляются
   в renderStreakShield на основе elapsedRatio:
     elapsed < 33%  → .is-fresh    (зелёный, всё ок);
     elapsed 33-66% → .is-warning  (жёлтый, пора готовиться);
     elapsed > 66%  → .is-critical (красный, срочно).
   Приоритет в каскаде: .streak-shield.is-active.is-{fresh|warning|critical}
   перебивает базовый .streak-shield.is-active. */
.streak-shield.is-active.is-fresh {
    background:
        linear-gradient(135deg,
            rgba(5, 150, 105, 0.14) 0%,
            rgba(16, 185, 129, 0.12) 50%,
            rgba(52, 211, 153, 0.10) 100%);
    border-color: rgba(5, 150, 105, 0.55);
    box-shadow:
        0 4px 18px rgba(5, 150, 105, 0.20),
        inset 0 1px 0 rgba(255, 255, 255, 0.30);
}
.streak-shield.is-active.is-warning {
    background:
        linear-gradient(135deg,
            rgba(217, 119, 6, 0.14) 0%,
            rgba(245, 158, 11, 0.12) 50%,
            rgba(252, 211, 77, 0.10) 100%);
    border-color: rgba(217, 119, 6, 0.55);
    box-shadow:
        0 4px 18px rgba(245, 158, 11, 0.22),
        inset 0 1px 0 rgba(255, 255, 255, 0.30);
    animation: streak-shield-breathe 1.8s ease-in-out infinite;
}
.streak-shield.is-active.is-critical {
    background:
        linear-gradient(135deg,
            rgba(220, 38, 38, 0.14) 0%,
            rgba(239, 68, 68, 0.12) 50%,
            rgba(248, 113, 113, 0.10) 100%);
    border-color: rgba(220, 38, 38, 0.55);
    box-shadow:
        0 4px 18px rgba(239, 68, 68, 0.24),
        inset 0 1px 0 rgba(255, 255, 255, 0.30);
    animation: streak-shield-breathe 1.2s ease-in-out infinite;
}

/* [GAM-AUDIT #2.3] Прогресс-бар активного щита перекрашивается
   в тон urgency-состояния. */
.streak-shield.is-active.is-warning .streak-shield-active-progress-fill {
    background: linear-gradient(90deg,
        #d97706 0%, #f59e0b 60%, #fcd34d 100%);
    box-shadow: 0 0 8px rgba(245, 158, 11, 0.55);
}
.streak-shield.is-active.is-critical .streak-shield-active-progress-fill {
    background: linear-gradient(90deg,
        #dc2626 0%, #ef4444 60%, #f87171 100%);
    box-shadow: 0 0 10px rgba(239, 68, 68, 0.65);
}
.streak-shield.is-active.is-warning .streak-shield-active-timer {
    color: #b45309;
}
.streak-shield.is-active.is-critical .streak-shield-active-timer {
    color: #b91c1c;
}

/* Тёмная тема — те же три состояния, чуть приглушённые. */
body.dark-theme .streak-shield.is-active.is-warning {
    background:
        linear-gradient(135deg,
            rgba(217, 119, 6, 0.22) 0%,
            rgba(245, 158, 11, 0.18) 50%,
            rgba(252, 211, 77, 0.14) 100%);
    border-color: rgba(245, 158, 11, 0.55);
    box-shadow:
        0 4px 18px rgba(245, 158, 11, 0.26),
        inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
body.dark-theme .streak-shield.is-active.is-critical {
    background:
        linear-gradient(135deg,
            rgba(220, 38, 38, 0.22) 0%,
            rgba(239, 68, 68, 0.18) 50%,
            rgba(248, 113, 113, 0.14) 100%);
    border-color: rgba(239, 68, 68, 0.55);
    box-shadow:
        0 4px 18px rgba(239, 68, 68, 0.28),
        inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
body.dark-theme .streak-shield.is-active.is-warning .streak-shield-active-row {
    color: #fcd34d;
}
body.dark-theme .streak-shield.is-active.is-critical .streak-shield-active-row {
    color: #fca5a5;
}
body.dark-theme .streak-shield.is-active.is-warning .streak-shield-active-timer {
    background: rgba(0, 0, 0, 0.30);
    color: #fcd34d;
}
body.dark-theme .streak-shield.is-active.is-critical .streak-shield-active-timer {
    background: rgba(0, 0, 0, 0.30);
    color: #fca5a5;
}

/* Состояние «только что куплено» — короткая вспышка-кольцо вокруг
   иконки. Не блокирует UI, длится ~1.2 с. */
.streak-shield.is-purchasing {
    transform: scale(0.99);
}

.streak-shield-icon {
    position: relative;
    width: 56px;
    height: 56px;
    border-radius: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    /* Светлый emerald сверху → основной #059669 → прозрачный.
       Имитирует «огранку» щита. */
    background:
        radial-gradient(circle at 30% 25%,
            rgba(110, 231, 183, 0.55) 0%,
            rgba(5, 150, 105, 0.22) 60%,
            transparent 100%);
    color: #fff;
    font-size: 26px;
    text-shadow: 0 2px 8px rgba(5, 150, 105, 0.55);
    box-shadow:
        inset 0 -3px 0 rgba(6, 78, 59, 0.45),
        0 4px 14px rgba(5, 150, 105, 0.32);
}
.streak-shield-icon i {
    z-index: 2;
    position: relative;
}
.streak-shield-icon-glow {
    position: absolute;
    inset: 6px;
    border-radius: 12px;
    background: radial-gradient(circle,
        rgba(255, 255, 255, 0.55) 0%,
        transparent 70%);
    opacity: 0.7;
    pointer-events: none;
    animation: streak-shield-glow-pulse 2.4s ease-in-out infinite;
}
.streak-shield-icon-ring {
    position: absolute;
    inset: -4px;
    border-radius: 18px;
    border: 1px solid rgba(5, 150, 105, 0.32);
    pointer-events: none;
    animation: streak-shield-ring-pulse 2.4s ease-out infinite;
}
@keyframes streak-shield-glow-pulse {
    0%, 100% { opacity: 0.55; transform: scale(1); }
    50%      { opacity: 0.85; transform: scale(1.08); }
}
@keyframes streak-shield-ring-pulse {
    0%   { opacity: 0.8;  transform: scale(1); }
    100% { opacity: 0;    transform: scale(1.5); }
}

/* Иконка при активном щите — переключаем на emerald. */
.streak-shield.is-active .streak-shield-icon {
    background:
        radial-gradient(circle at 30% 25%,
            rgba(110, 231, 183, 0.60) 0%,
            rgba(5, 150, 105, 0.28) 60%,
            transparent 100%);
    box-shadow:
        inset 0 -3px 0 rgba(6, 78, 59, 0.55),
        0 4px 14px rgba(5, 150, 105, 0.36);
}
.streak-shield.is-active .streak-shield-icon-ring {
    border-color: rgba(5, 150, 105, 0.45);
}

.streak-shield-info {
    min-width: 0; /* важно для ellipsis */
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.streak-shield-title {
    font-size: 14px;
    font-weight: 700;
    color: #064e3b;
    letter-spacing: 0.01em;
    display: flex;
    align-items: center;
    gap: 6px;
}
.streak-shield-desc {
    font-size: 12.5px;
    line-height: 1.4;
    color: rgba(6, 95, 70, 0.78);
}
.streak-shield-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 4px;
}
.streak-shield-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 600;
    line-height: 1;
}
.streak-shield-pill--owned {
    background: rgba(5, 150, 105, 0.14);
    color: #047857;
    border: 1px solid rgba(5, 150, 105, 0.28);
}
.streak-shield.is-active .streak-shield-pill--owned {
    background: rgba(5, 150, 105, 0.18);
    color: #065f46;
    border-color: rgba(5, 150, 105, 0.36);
}
.streak-shield-pill--cost {
    background: rgba(250, 204, 21, 0.18);
    color: #92400e;
    border: 1px solid rgba(250, 204, 21, 0.40);
}
.streak-shield-pill i {
    font-size: 10px;
}

/* Кнопка покупки. Стилизована под «pushable» из общего
   дизайн-кита виджетов (тот же подход, что и у .stars-package-btn).
   Кнопка перенесена в нижнюю строку grid'а (под .streak-shield-info):
   растягивается на всю ширину карточки и центрирует контент —
   так она визуально читается как основное действие и не толкает
   info-блок на узких экранах с длинными переводами. */
.streak-shield-buy {
    --shield-buy-bg-from: #059669;
    --shield-buy-bg-to: #10b981;
    position: relative;
    grid-column: 1 / -1;
    justify-self: stretch;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 10px 14px;
    border: 0;
    border-radius: 14px;
    font-size: 13px;
    font-weight: 700;
    color: #fff;
    cursor: pointer;
    background:
        linear-gradient(180deg,
            var(--shield-buy-bg-from) 0%,
            var(--shield-buy-bg-to) 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.30),
        0 4px 10px rgba(5, 150, 105, 0.35),
        0 6px 14px rgba(16, 185, 129, 0.20);
    transition: transform 120ms ease-out, box-shadow 120ms ease-out, opacity 200ms;
    white-space: nowrap;
}
.streak-shield-buy i {
    font-size: 12px;
}
.streak-shield-buy:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.40),
        0 6px 14px rgba(5, 150, 105, 0.48),
        0 10px 22px rgba(16, 185, 129, 0.28);
}
.streak-shield-buy:active:not(:disabled) {
    transform: translateY(1px);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.20),
        0 2px 6px rgba(5, 150, 105, 0.32);
}
.streak-shield-buy:disabled,
.streak-shield-buy[aria-disabled='true'] {
    cursor: not-allowed;
    opacity: 0.6;
    filter: grayscale(35%);
}
.streak-shield-buy.is-loading {
    pointer-events: none;
}
.streak-shield-buy.is-loading::after {
    /* spinner через ::after */
    content: '';
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, 0.45);
    border-top-color: #fff;
    animation: streak-shield-spin 0.7s linear infinite;
    margin-left: 4px;
}
@keyframes streak-shield-spin {
    to { transform: rotate(360deg); }
}

/* Синий модификатор для .settings-tile-btn.
   Визуально повторяет "pushable"-стиль .streak-shield-buy,
   но на фирменном синем (#0d7bff). Применяется к кнопкам-«плиткам»,
   которые должны выглядеть как основное действие. */
.settings-tile-btn.settings-tile-btn--blue {
    --tile-blue-from: #0a5fcc;
    --tile-blue-to:   #0d7bff;
    padding: 6px 14px;
    background:
        linear-gradient(180deg,
            var(--tile-blue-from) 0%,
            var(--tile-blue-to) 100%);
    border: 0;
    color: #fff;
    font-weight: 700;
    text-align: center;
    justify-content: center;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.30),
        0 4px 10px rgba(13, 123, 255, 0.35),
        0 6px 14px rgba(13, 123, 255, 0.20);
    transition: transform 120ms ease-out, box-shadow 120ms ease-out, opacity 200ms;
}
.settings-tile-btn.settings-tile-btn--blue .settings-tile-icon {
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
}
.settings-tile-btn.settings-tile-btn--blue:hover:not(:disabled) {
    background:
        linear-gradient(180deg,
            var(--tile-blue-from) 0%,
            var(--tile-blue-to) 100%);
    border-color: transparent;
    transform: translateY(-1px);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.40),
        0 6px 14px rgba(13, 123, 255, 0.48),
        0 10px 22px rgba(13, 123, 255, 0.28);
}
.settings-tile-btn.settings-tile-btn--blue:active:not(:disabled) {
    transform: translateY(1px);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.20),
        0 2px 6px rgba(13, 123, 255, 0.32);
}
.settings-tile-btn.settings-tile-btn--blue:disabled,
.settings-tile-btn.settings-tile-btn--blue[aria-disabled='true'] {
    cursor: not-allowed;
    opacity: 0.6;
    filter: grayscale(35%);
}

/* Баннер «щит активен»: расширяет основной грид на 4-ю строку,
   не сжимая кнопку. */
.streak-shield-active {
    grid-column: 1 / -1;
    margin-top: 10px;
    padding: 10px 14px;
    border-radius: 12px;
    background:
        linear-gradient(135deg,
            rgba(5, 150, 105, 0.16) 0%,
            rgba(16, 185, 129, 0.12) 100%);
    border: 1px solid rgba(5, 150, 105, 0.36);
}
.streak-shield-active-row {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: #065f46;
    font-weight: 600;
}
.streak-shield-active-label {
    flex: 1;
}
.streak-shield-active-timer {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: #047857;
    background: rgba(255, 255, 255, 0.50);
    border-radius: 8px;
    padding: 2px 8px;
}
.streak-shield-active-progress {
    margin-top: 6px;
    height: 6px;
    border-radius: 4px;
    background: rgba(5, 150, 105, 0.16);
    overflow: hidden;
}
.streak-shield-active-progress-fill {
    height: 100%;
    width: 0%;
    /* Чистый emerald-градиент без янтарного «хвоста»:
       #059669 → #10b981 → #34d399. */
    background: linear-gradient(90deg,
        #059669 0%, #10b981 60%, #34d399 100%);
    box-shadow: 0 0 8px rgba(5, 150, 105, 0.55);
    transition: width 800ms linear;
}

/* ====== Тёмная тема ====== */
body.dark-theme .streak-shield {
    background:
        linear-gradient(135deg,
            rgba(5, 150, 105, 0.24) 0%,
            rgba(16, 185, 129, 0.22) 50%,
            rgba(52, 211, 153, 0.18) 100%);
    border-color: rgba(5, 150, 105, 0.46);
    box-shadow:
        0 4px 18px rgba(5, 150, 105, 0.24),
        inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
body.dark-theme .streak-shield.is-active {
    background:
        linear-gradient(135deg,
            rgba(5, 150, 105, 0.26) 0%,
            rgba(16, 185, 129, 0.22) 50%,
            rgba(52, 211, 153, 0.18) 100%);
    border-color: rgba(5, 150, 105, 0.58);
    box-shadow:
        0 4px 18px rgba(5, 150, 105, 0.28),
        inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
body.dark-theme .streak-shield-title {
    color: #a7f3d0;
}
body.dark-theme .streak-shield-desc {
    color: rgba(167, 243, 208, 0.78);
}
body.dark-theme .streak-shield-pill--owned {
    background: rgba(5, 150, 105, 0.24);
    color: #a7f3d0;
    border-color: rgba(5, 150, 105, 0.50);
}
body.dark-theme .streak-shield.is-active .streak-shield-pill--owned {
    background: rgba(5, 150, 105, 0.28);
    color: #a7f3d0;
    border-color: rgba(5, 150, 105, 0.55);
}
body.dark-theme .streak-shield-pill--cost {
    background: rgba(250, 204, 21, 0.18);
    color: #fcd34d;
    border-color: rgba(250, 204, 21, 0.40);
}
body.dark-theme .streak-shield-active-row {
    color: #a7f3d0;
}
body.dark-theme .streak-shield-active-timer {
    background: rgba(0, 0, 0, 0.30);
    color: #6ee7b7;
}
body.dark-theme .streak-shield-active {
    background:
        linear-gradient(135deg,
            rgba(5, 150, 105, 0.22) 0%,
            rgba(16, 185, 129, 0.16) 100%);
}

/* ====== Адаптив: ранее здесь был @media (max-width: 380px),
   который переносил кнопку покупки на отдельную строку только
   на узких экранах. Теперь это поведение дефолтное для всех
   размеров (см. .streak-shield-buy), чтобы карточка выглядела
   единообразно и кнопка читалась как основное действие. ====== */

/* ====== Тоггл «щит активирован сегодня» для кружочка в
   streak-week — золотой ободок вместо оранжевого. ====== */
.streak-week-day.is-shielded .streak-week-dot {
    background: linear-gradient(135deg, #f59e0b 0%, #fcd34d 100%);
    box-shadow:
        0 0 0 2px rgba(250, 204, 21, 0.40),
        0 0 12px rgba(250, 204, 21, 0.30);
}
.streak-week-day.is-shielded .streak-week-label {
    color: #b45309;
}
body.dark-theme .streak-week-day.is-shielded .streak-week-label {
    color: #fcd34d;
}

/* Уважаем prefers-reduced-motion: отключаем все «дышащие»
   анимации и spinner. */
@media (prefers-reduced-motion: reduce) {
    .streak-shield.is-active,
    .streak-shield.is-active.is-fresh,
    .streak-shield.is-active.is-warning,
    .streak-shield.is-active.is-critical,
    .streak-shield-icon-glow,
    .streak-shield-icon-ring {
        animation: none !important;
    }
    .streak-shield-buy.is-loading::after {
        animation-duration: 1.6s;
    }
}

/* [P1 #12] Старые стили .streak-shield-toast удалены: всё,
   что раньше показывалось через отдельный мини-toast уведомления
   streak-shield, теперь идёт через единый .mission-toast API
   (showMissionToast в app.js). См. блок выше (.mission-toasts /
   .mission-toast). Локальный #streakShieldToast div больше не
   создаётся — стили не нужны. */

/* ====== [GAM-AUDIT #2.2] Streak-widget UX improvements ====== */

/* [GAM-AUDIT #2.2] Расширенная подпись для пилюли Streak Shield
   «N/3». Аудит зафиксировал, что одна цифра «0/3» без объяснения
   путает пользователя: «владение или макс на сессию». Решение —
   через .streak-shield-pill-tooltip (появляется по hover/focus и
   через aria-label/title для screen-reader'ов) выводим три числа
   в явном виде: «в наличии», «макс. недельных», «цена покупки».
   Тултип использует существующую стилистику chip'ов streak-виджета
   (тёплый янтарь/изумруд, согласно классу пилюли). */
.streak-shield-pill-tooltip {
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    background: var(--card-bg, #fff);
    color: var(--text-color, #222);
    font-size: 11px;
    line-height: 1.45;
    font-weight: 500;
    padding: 8px 10px;
    border-radius: 8px;
    box-shadow:
        0 4px 14px rgba(0, 0, 0, 0.18),
        0 1px 3px rgba(0, 0, 0, 0.08);
    border: 1px solid color-mix(in srgb, var(--text-muted, #888) 18%, transparent);
    pointer-events: none;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.18s ease, visibility 0.18s ease;
    z-index: 5;
    min-width: 200px;
    max-width: 260px;
    text-align: left;
    white-space: normal;
}
.streak-shield-pill-tooltip::after {
    /* Стрелка под тултипом. */
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
    border-top-color: var(--card-bg, #fff);
}
.streak-shield-pill:hover .streak-shield-pill-tooltip,
.streak-shield-pill:focus-within .streak-shield-pill-tooltip,
.streak-shield-pill--show-tip .streak-shield-pill-tooltip {
    opacity: 1;
    visibility: visible;
}
.streak-shield-pill {
    /* Чтобы .streak-shield-pill-tooltip позиционировался
       относительно пилюли. */
    position: relative;
}
.streak-shield-pill-tooltip-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}
.streak-shield-pill-tooltip-row + .streak-shield-pill-tooltip-row {
    margin-top: 3px;
}
.streak-shield-pill-tooltip-label {
    color: var(--text-muted, #888);
    font-weight: 500;
}
.streak-shield-pill-tooltip-value {
    font-weight: 700;
    color: var(--text-color, #222);
    font-variant-numeric: tabular-nums;
}
.streak-shield-pill--owned .streak-shield-pill-tooltip-value {
    color: #047857;
}
.streak-shield-pill--cost .streak-shield-pill-tooltip-value {
    color: #92400e;
}

/* [GAM-AUDIT #2.2] Блок предупреждения «streak сбросится через X
   часов». Появляется только при streak≥3 и когда до конца
   «активного дня» в TZ пользователя осталось меньше 6 часов
   (P0 #2 — снижено с 12 до 6 часов; аналог Duolingo +14% D7).
   Содержит SVG-кольцо обратного отсчёта и поясняющий текст.
   Стилистика — янтарь/оранж, в тон streak-виджету; пульсация
   кольца при <2ч до конца. */
.streak-reset-warning {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 10px;
    padding: 10px 12px;
    border-radius: 12px;
    background: linear-gradient(135deg,
        rgba(251, 146, 60, 0.18) 0%,
        rgba(249, 115, 22, 0.12) 100%);
    border: 1px solid color-mix(in srgb, #f97316 36%, transparent);
    color: #9a3412;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.35;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
/* Атрибут hidden в HTML — это display:none по умолчанию, но
   правило выше с display:flex его перебивает. Возвращаем
   приоритет атрибуту, иначе пустая оранжевая плашка видна
   при первом рендере до того, как JS наполнит её текстом
   (или навсегда — если streak<3 / до полуночи > 12ч). */
.streak-reset-warning[hidden] {
    display: none;
}
.streak-reset-warning-ring {
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    transform: rotate(-90deg);
}
.streak-reset-warning-ring-track {
    fill: none;
    stroke: color-mix(in srgb, #f97316 22%, transparent);
    stroke-width: 3;
}
.streak-reset-warning-ring-fill {
    fill: none;
    stroke: #f97316;
    stroke-width: 3;
    stroke-linecap: round;
    /* Плавный переход offset (аудит: «обновлять каждые 60 с»). */
    transition: stroke-dashoffset 0.6s ease, stroke 0.3s ease;
}
.streak-reset-warning.is-urgent .streak-reset-warning-ring-fill {
    stroke: #ef4444;
}
.streak-reset-warning.is-urgent {
    background: linear-gradient(135deg,
        rgba(239, 68, 68, 0.20) 0%,
        rgba(249, 115, 22, 0.14) 100%);
    border-color: color-mix(in srgb, #ef4444 44%, transparent);
    color: #b91c1c;
    animation: streak-reset-warning-pulse 1.8s ease-in-out infinite;
}
@keyframes streak-reset-warning-pulse {
    0%   { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18),
                                   0 0 0 0 rgba(239, 68, 68, 0); }
    50%  { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18),
                                   0 0 0 6px rgba(239, 68, 68, 0.16); }
    100% { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18),
                                   0 0 0 0 rgba(239, 68, 68, 0); }
}
.streak-reset-warning-text {
    flex: 1 1 auto;
    min-width: 0;
}
/* Тёмная тема: чуть ярче. */
body.dark-theme .streak-reset-warning {
    background: linear-gradient(135deg,
        rgba(251, 146, 60, 0.28) 0%,
        rgba(249, 115, 22, 0.18) 100%);
    border-color: color-mix(in srgb, #fb923c 50%, transparent);
    color: #fdba74;
}
body.dark-theme .streak-reset-warning.is-urgent {
    color: #fca5a5;
}
/* Прибьём prefers-reduced-motion: убираем пульсацию, оставляем
   только изменение цвета через class. */
@media (prefers-reduced-motion: reduce) {
    .streak-reset-warning.is-urgent {
        animation: none;
    }
    .streak-reset-warning-ring-fill {
        transition: none;
    }
}

/* [GAM-AUDIT #2.2] «Engaging» состояние streak-meta для streak=0,
   longest=0. В отличие от пассивного pill, эта строка показывает
   светло-янтарный чип с эмодзи ⚡ и призывом начать серию. */
.streak-meta-item--engage {
    background: linear-gradient(135deg,
        rgba(252, 211, 77, 0.28) 0%,
        rgba(251, 146, 60, 0.20) 100%) !important;
    color: #92400e !important;
    font-weight: 600;
    border: 1px solid color-mix(in srgb, #f59e0b 38%, transparent);
}
body.dark-theme .streak-meta-item--engage {
    color: #fcd34d !important;
    border-color: color-mix(in srgb, #f59e0b 50%, transparent);
}

/* [GAM-AUDIT #2.2] Развёрнутая подпись «shield в наличии» для
   стрелки button-streak-shield-buy. Текст берётся из i18n и
   показывается через атрибут title + tooltip из текущей
   title-строки (см. renderStreakShield). Чтобы при hover
   tooltip выглядел аккуратно, делаем чуть более тонкий фон и
   мелкий шрифт, чем у streak-shield-pill-tooltip (они расположены
   рядом и не должны визуально сливаться). */
.streak-shield-buy[title]:hover::before,
.streak-shield-buy[title]:focus-visible::before {
    /* Просто подсказка через title — нативная, дополнительный
       стиль не нужен, оставлено как маркер для будущей кастомной
       подсказки, если придётся отказаться от title=. */
}

/* ============================================================
   [Tier 3.1 GAM-AUDIT] DAILY LOGIN BONUS WIDGET
   ============================================================
   Виджет .widget-daily-bonus — 30-дневный календарь с наградой
   за заход в приложение каждый день. Цикл — календарный месяц
   по TZ пользователя. Подробная механика и схема наград — в
   bot/services/dailyBonus.js (REWARD_TABLE) и в
   GAMIFICATION_AUDIT_2026_06_29.md → Tier 3.1.

   Цвета акцентов берутся из .widget-tint-emerald (зелёный,
   «награда»), чтобы не конкурировать со streak (.widget-tint-orange)
   и player-level (.widget-tint-gold).

   Все анимации уважают prefers-reduced-motion (см. ниже).
   ============================================================ */

.widget-daily-bonus-body {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Виджет ежедневного бонуса — фиксированная сетка 31 ячейка
   (6 колонок × 6 рядов с одной лишней, либо 5×7 на мобиле),
   которая целиком должна быть видна без внутреннего скролла.
   Базовый .widget-body { max-height: 240px; overflow-y: auto }
   обрезает виджет по высоте ~240px и добавляет скроллбар —
   пользователь видит только 2–3 ряда календаря и должен
   скроллить, чтобы дойти до CTA-кнопки. Сбрасываем эти
   ограничения с более высокой специфичностью (0,4,0), по
   аналогии с .dashboard-widget.widget-streak / .widget-quests /
   .widget-exploration — все они переопределяют базовый max-height. */
.widget-daily-bonus .widget-body {
    max-height: none;
    overflow: visible;
}

.dashboard-widget.widget-daily-bonus .widget-body.widget-daily-bonus-body {
    max-height: none;
    overflow: visible;
}

/* Top-bar: «День 5 из 30 · сегодня». */
.daily-bonus-today {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    font-size: 12px;
    color: var(--text-muted, #6b7280);
    line-height: 1.3;
    min-height: 18px;
}
.daily-bonus-today strong {
    color: var(--widget-accent, #059669);
    font-weight: 700;
}
.daily-bonus-today.is-claimed strong {
    color: var(--text-color, #222);
}

/* Календарь 6 колонок × 5 рядов на десктопе, 5×6 на мобиле.
   Ячейки квадратные, скруглённые, с понятными состояниями. */
.daily-bonus-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 6px;
    padding: 4px;
    border-radius: 12px;
    background: color-mix(in srgb, var(--widget-accent, #059669) 6%, transparent);
}
@media (max-width: 480px) {
    .daily-bonus-grid {
        grid-template-columns: repeat(5, 1fr);
    }
}

/* ============================================================
   [GAM-AUDIT #1.6] Collapsed-режим календаря бонусов.
   На дашборде показываем только текущую и следующую неделю
   (10 ячеек = 5×2), всё остальное скрыто. По клику открывается
   модалка с полным месяцем (30 дней, .daily-bonus-grid--modal).

   • grid-template-columns: 5 колонок. 7 столбцов на узких
     экранах (≤ 320 px) выглядели слишком сжато (ячейка
     ~30 px, цифра дня не помещалась) — поэтому остановились
     на 5: 2 строки × 5 = 10 дней, ячейка ≈ 44 px в типичном
     виджете ~240 px.
   • max-height рассчитывается так, чтобы были видны ровно 2
     строки + 1 gap. Для ширины виджета 240..320 px высота
     ячейки ≈ 38–48 px (aspect-ratio: 1/1), поэтому 2 строки
     с запасом укладываются в ~96 px.
   • overflow: hidden обрезает 3-ю строку (11..30) визуально.
   • Ячейки data-day > 10 жёстко скрываются display:none —
     это не даёт им «торчать» из-под overflow, и при клике
     невидимые ячейки не попадают под aria/click.
   • Курсор pointer + hover-подсветка подсказывают, что
     календарь интерактивный.
   ============================================================ */
.daily-bonus-grid--collapsed {
    grid-template-columns: repeat(5, minmax(0, 1fr));
    /* [FIX 2026-07-09, daily-bonus-collapsed-rows-clip + row-gap]
       Раньше max-height рассчитывался как
         calc(2 * var(--daily-bonus-cell-size, 40px) + 6px + 8px)
       и в предположении, что --daily-bonus-cell-size где-то
       объявлен. На практике переменная нигде не задаётся (fallback
       40px), а реальный размер ячейки определяется её собственной
       aspect-ratio: 1/1 + шириной колонки (grid-template-columns:
       repeat(5, 1fr) → ширина колонки = (ширина виджета − padding
       − gaps) / 5).

       На типичной ширине дашборд-виджета 280–360 px ячейка получается
       50–65 px, и 2 ряда требуют 100–130 px контента + 6 px gap +
       8 px padding = 114–144 px. Старый max-height = 94 px не
       вмещал второй ряд → overflow:hidden обрезал его на полпути,
       и пользователь видел только первый ряд + «расщеплённую»
       ячейку (например, зелёный Day 4 сверху и кусок светлого
       Day 9 снизу под ним).

       Текущий фикс: grid-template-rows repeat(2, auto) + увеличенный
       row-gap 14px для визуального разделения «текущая неделя /
       следующая неделя». Высота сетки = сумма высот ячеек (auto
       подчиняется aspect-ratio 1/1) + row-gap + padding. Aspect-ratio
       не используем — на широких виджетах (>400 px) он обрезал
       нижний ряд. max-height 240px оставлен как safety-cap. */
    grid-template-rows: repeat(2, auto);
    row-gap: 14px;
    max-height: 240px;
    overflow: hidden;
    cursor: pointer;
    position: relative;
    transition: box-shadow 0.18s ease, transform 0.18s ease;
}
/* В collapsed-режиме убираем min-height: 36px с ячейки, чтобы она
   честно подчинялась aspect-ratio 1/1 + aspect-ratio сетки 5/2
   (иначе на узких виджетах ячейка 36px высотой не помещалась бы
   в ряд и выпирала за overflow:hidden). */
.daily-bonus-grid--collapsed .daily-bonus-cell {
    min-height: 0;
}
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="11"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="12"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="13"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="14"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="15"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="16"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="17"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="18"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="19"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="20"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="21"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="22"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="23"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="24"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="25"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="26"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="27"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="28"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="29"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="30"],
.daily-bonus-grid--collapsed .daily-bonus-cell[data-day="31"] {
    display: none;
}
/* «Лупа-индикатор» кликабельности: маленький шеврон в правом
   нижнем углу collapsed-сетки. Углубляет аффорданс «можно
   открыть полный календарь». */
.daily-bonus-grid--collapsed::after {
    content: '⤢';
    position: absolute;
    right: 6px;
    bottom: 6px;
    width: 22px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: color-mix(in srgb, var(--widget-accent, #059669) 18%, transparent);
    color: var(--widget-accent, #059669);
    font-size: 13px;
    line-height: 1;
    pointer-events: none;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
}
.daily-bonus-grid--collapsed:hover {
    box-shadow: 0 4px 14px -4px color-mix(in srgb, var(--widget-accent, #059669) 55%, transparent);
    transform: translateY(-1px);
}
.daily-bonus-grid--collapsed:focus-visible {
    outline: 2px solid var(--widget-accent, #059669);
    outline-offset: 2px;
}

/* ============================================================
   Модальный режим календаря. Используется внутри
   .daily-bonus-calendar-modal (.app-modal.daily-bonus-calendar-modal).
   Раскладка — как у обычной сетки (6×5 на десктопе, 5×6 на
   мобиле), но в более просторном контейнере. Ячейки больше.
   ============================================================ */
.daily-bonus-calendar-modal {
    max-width: 460px;
    width: calc(100vw - 32px);
    max-height: 86vh;
    overflow-y: auto;
    text-align: left;
}
.daily-bonus-calendar-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 4px;
}
.daily-bonus-calendar-modal-title {
    margin: 0;
    font-size: 16px;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.daily-bonus-calendar-modal-close {
    /* Компактная квадратная кнопка ~28×28 px — не выпирает
       в шапке модалки, легко попадает тачем, но остаётся
       достаточно крупной для WCAG 2.5.5 (target size ≥ 24px). */
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--text-color, #222) 18%, transparent);
    color: var(--text-muted, #6b7280);
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
    width: 28px;
    height: 28px;
    min-width: 28px;
    min-height: 28px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s ease, color 0.15s ease,
        border-color 0.15s ease, transform 0.15s ease;
}
.daily-bonus-calendar-modal-close:hover,
.daily-bonus-calendar-modal-close:focus-visible {
    background: rgba(0, 0, 0, 0.05);
    color: var(--text-color, #222);
    border-color: color-mix(in srgb, var(--text-color, #222) 36%, transparent);
    outline: none;
    transform: scale(1.05);
}
.daily-bonus-calendar-modal-subtitle {
    margin: 0 0 12px;
    font-size: 12px;
    color: var(--text-muted, #6b7280);
    line-height: 1.4;
}
.daily-bonus-calendar-modal-grid {
    /* Тот же .daily-bonus-grid, но без --collapsed. Ячейки
       крупнее за счёт более широкого контейнера. */
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 8px;
    padding: 8px;
    border-radius: 12px;
    background: color-mix(in srgb, var(--widget-accent, #059669) 6%, transparent);
    max-height: none;
    overflow: visible;
    cursor: default;
}
.daily-bonus-calendar-modal-grid::after {
    content: none;
}
.daily-bonus-calendar-modal-grid .daily-bonus-cell {
    min-height: 48px;
    font-size: 13px;
}
.daily-bonus-calendar-modal-grid .daily-bonus-cell-reward {
    font-size: 10px;
}
@media (max-width: 480px) {
    .daily-bonus-calendar-modal-grid {
        grid-template-columns: repeat(5, minmax(0, 1fr));
    }
}

/* Тёмная тема для новых элементов. */
body.dark-theme .daily-bonus-calendar-modal-grid {
    background: color-mix(in srgb, var(--widget-accent, #059669) 14%, transparent);
}
body.dark-theme .daily-bonus-calendar-modal-close {
    border-color: color-mix(in srgb, var(--text-color, #e5e7eb) 22%, transparent);
    color: #9ca3af;
}
body.dark-theme .daily-bonus-calendar-modal-close:hover,
body.dark-theme .daily-bonus-calendar-modal-close:focus-visible {
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-color, #e5e7eb);
    border-color: color-mix(in srgb, var(--text-color, #e5e7eb) 42%, transparent);
}
body.dark-theme .daily-bonus-grid--collapsed::after {
    background: color-mix(in srgb, var(--widget-accent, #059669) 32%, transparent);
    color: #d1fae5;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.45);
}

/* prefers-reduced-motion: убираем hover-трансформации. */
@media (prefers-reduced-motion: reduce) {
    .daily-bonus-grid--collapsed {
        transition: none;
    }
    .daily-bonus-grid--collapsed:hover {
        transform: none;
    }
}

.daily-bonus-cell {
    aspect-ratio: 1 / 1;
    min-height: 36px;
    border-radius: 8px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    background: rgba(255, 255, 255, 0.55);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #059669) 14%, transparent);
    color: var(--text-color, #222);
    font-size: 12px;
    font-weight: 600;
    position: relative;
    transition: transform 0.15s ease, background 0.2s ease, border-color 0.2s ease;
    cursor: default;
}
.daily-bonus-cell:hover {
    transform: translateY(-1px);
}

.daily-bonus-cell-num {
    line-height: 1;
}
.daily-bonus-cell-reward {
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.2px;
    color: var(--widget-accent, #059669);
    line-height: 1;
}

/* Будущие дни — серые, без подсветки. */
.daily-bonus-cell.is-future {
    opacity: 0.45;
    background: transparent;
}

/* «Пустые» visit-only дни (4, 6, 8–13, 15–29) — без reward-числа. */
.daily-bonus-cell.is-visit-only .daily-bonus-cell-reward {
    visibility: hidden;
}

/* Забранные дни — заливка акцентом + белая цифра. */
.daily-bonus-cell.is-claimed {
    background: var(--widget-accent, #059669);
    color: #fff;
    border-color: var(--widget-accent, #059669);
}
.daily-bonus-cell.is-claimed .daily-bonus-cell-reward {
    color: rgba(255, 255, 255, 0.9);
}

/* Сегодняшняя ячейка — пульсирующая рамка. */
.daily-bonus-cell.is-today {
    border-color: var(--widget-accent, #059669);
    box-shadow:
        0 0 0 2px color-mix(in srgb, var(--widget-accent, #059669) 45%, transparent),
        0 6px 16px -8px color-mix(in srgb, var(--widget-accent, #059669) 80%, transparent);
    animation: daily-bonus-today-pulse 1.8s ease-in-out infinite;
}
@keyframes daily-bonus-today-pulse {
    0%, 100% {
        box-shadow:
            0 0 0 2px color-mix(in srgb, var(--widget-accent, #059669) 45%, transparent),
            0 6px 16px -8px color-mix(in srgb, var(--widget-accent, #059669) 80%, transparent);
    }
    50% {
        box-shadow:
            0 0 0 3px color-mix(in srgb, var(--widget-accent, #059669) 65%, transparent),
            0 10px 22px -8px color-mix(in srgb, var(--widget-accent, #059669) 90%, transparent);
    }
}

/* ============================================================
   [GAM-RECO #15 / P2 #15] «Набор новичка» — удвоенный 1-й цикл.
   Визуальные стили для бейджа «🚀 Стартовый буст» в шапке
   виджета, баннера «осталось N дн.» и ячеек календаря,
   рассчитанных с учётом ×2 (boosted).
   ============================================================ */

/* Бейдж «🚀 Стартовый буст» — компактная плашка в шапке виджета,
   привлекающая внимание к тому, что награда сегодня удвоена.
   Селектор `:not([hidden])` сохраняет видимость бейджа только
   тогда, когда JS явно снял атрибут `hidden` (renderDailyBonusWidget).
   Без этого правило `display: inline-flex` от базового селектора
   перебивает UA-стиль `[hidden] { display: none }`, и бейдж светится
   даже при `starterPack.active=false`. */
.daily-bonus-boost-badge:not([hidden]) {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    margin-left: 8px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.2px;
    background: linear-gradient(135deg, #f97316 0%, #ef4444 100%);
    color: #fff;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
    box-shadow: 0 2px 8px -2px rgba(239, 68, 68, 0.55);
    animation: daily-bonus-boost-glow 2.4s ease-in-out infinite;
}
.daily-bonus-boost-badge[hidden] {
    display: none !important;
}

@keyframes daily-bonus-boost-glow {
    0%, 100% {
        box-shadow: 0 2px 8px -2px rgba(239, 68, 68, 0.55);
        transform: scale(1);
    }
    50% {
        box-shadow: 0 4px 14px -2px rgba(239, 68, 68, 0.85);
        transform: scale(1.04);
    }
}

/* Баннер «осталось N дн.» — появляется в верхней части тела виджета.
   Селектор намеренно использует :not([hidden]) чтобы CSS-правило НЕ
   перебивало UA-стиль `[hidden] { display: none }`. Без этого ветка
   «Календарь недоступен» / «стартовый буст не активен» показывала бы
   пустой блок в 8px высотой между счётчиком и календарём, потому что
   JS выставляет `hidden=true`, но каскад продолжает применять
   `display: block` от базового селектора. */
.daily-bonus-starter-pack-banner:not([hidden]) {
    display: block;
    margin: 0 0 8px;
    padding: 8px 12px;
    border-radius: 8px;
    font-size: 12px;
    line-height: 1.35;
    background: linear-gradient(135deg,
        rgba(249, 115, 22, 0.12) 0%,
        rgba(239, 68, 68, 0.10) 100%);
    color: #c2410c;
    border: 1px solid rgba(249, 115, 22, 0.35);
}
/* Страховка на случай, если кто-то в новом коде поставит `display:flex`
   или подобное поверх — `hidden` всё равно должен скрывать элемент. */
.daily-bonus-starter-pack-banner[hidden] {
    display: none !important;
}

body.dark-theme .daily-bonus-starter-pack-banner {
    background: linear-gradient(135deg,
        rgba(249, 115, 22, 0.18) 0%,
        rgba(239, 68, 68, 0.16) 100%);
    color: #fed7aa;
    border-color: rgba(249, 115, 22, 0.45);
}

/* Ячейка календаря с boosted-наградой — лёгкий оранжевый акцент,
   чтобы было видно «удвоенный день». */
.daily-bonus-cell.is-boosted {
    background: linear-gradient(135deg,
        rgba(249, 115, 22, 0.10) 0%,
        rgba(239, 68, 68, 0.06) 100%);
    border-color: rgba(249, 115, 22, 0.55);
}
.daily-bonus-cell.is-boosted.is-claimed {
    background: linear-gradient(135deg, #f97316 0%, #ef4444 100%);
    border-color: rgba(239, 68, 68, 0.7);
    color: #fff;
}
.daily-bonus-cell.is-boosted.is-claimed .daily-bonus-cell-reward {
    color: rgba(255, 255, 255, 0.95);
}
.daily-bonus-cell.is-boosted.is-today {
    box-shadow:
        0 0 0 2px rgba(249, 115, 22, 0.55),
        0 8px 18px -8px rgba(239, 68, 68, 0.7);
}

/* Иконка «×2» рядом с числом ★ в ячейке. */
.daily-bonus-cell-reward.is-boosted {
    color: #ea580c;
    font-weight: 800;
}
.daily-bonus-cell-boost-mark {
    display: inline-block;
    margin-left: 3px;
    padding: 0 4px;
    border-radius: 6px;
    font-size: 9px;
    font-weight: 800;
    background: #ef4444;
    color: #fff;
    vertical-align: middle;
    letter-spacing: 0;
}

/* Reduced motion: убираем анимации glow/pulse, чтобы
   не раздражать чувствительных пользователей (WCAG 2.3.3). */
@media (prefers-reduced-motion: reduce) {
    .daily-bonus-boost-badge,
    .daily-bonus-cell.is-today,
    .daily-bonus-cell.is-boosted.is-today {
        animation: none;
    }
}

/* Сегодня + забрано — спокойная зелёная заливка без пульсации. */
.daily-bonus-cell.is-today.is-claimed {
    animation: none;
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--widget-accent, #059669) 35%, transparent);
}

/* Milestone-дни (3, 5, 7, 14, 30) — небольшая иконка подарка. */
.daily-bonus-cell.is-milestone::after {
    content: "";
    position: absolute;
    top: 2px;
    right: 3px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: linear-gradient(135deg, #fbbf24, #f59e0b);
    box-shadow: 0 0 0 1.5px #fff;
}
.daily-bonus-cell.is-milestone.is-claimed::after {
    background: #fff;
    box-shadow: 0 0 0 1.5px var(--widget-accent, #059669);
}

/* Кнопка «Забрать сегодня» — стилизована идентично
   .streak-shield-buy (тот же «pushable» подход из общего
   дизайн-кита виджетов). Спиннер loading, модификаторы .is-done,
   .is-pulsing и .is-shaking сохраняются ниже без изменений.

   Селектор намеренно использует `button.daily-bonus-claim-btn`
   (специфичность 0,1,1) вместо `.daily-bonus-claim-btn` (0,1,0),
   чтобы гарантированно перебить глобальное правило
   `button { background-color: var(--button-bg); ... }` (0,0,1),
   объявленное ранее в файле (строки 597/617). Без повышения
   специфичности базовый `button` мог проявиться в Telegram WebView
   из-за агрессивного кеширования CSS и порядка каскада. */
button.daily-bonus-claim-btn {
    --shield-buy-bg-from: #059669;
    --shield-buy-bg-to: #10b981;
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 10px 14px;
    border: 0;
    border-radius: 14px;
    font-size: 13px;
    font-weight: 700;
    color: #fff;
    cursor: pointer;
    background:
        linear-gradient(180deg,
            var(--shield-buy-bg-from) 0%,
            var(--shield-buy-bg-to) 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.30),
        0 4px 10px rgba(5, 150, 105, 0.35),
        0 6px 14px rgba(16, 185, 129, 0.20);
    transition: transform 120ms ease-out, box-shadow 120ms ease-out, opacity 200ms;
    white-space: nowrap;
    /* Полный сброс наследуемых базовых button-стилей,
       чтобы var(--button-bg) / color / font-weight из
       глобального `button { }` не просочились. */
    background-color: transparent;
    margin: 0;
    width: auto;
    text-align: center;
    line-height: 1.2;
}
button.daily-bonus-claim-btn i {
    font-size: 12px;
}
button.daily-bonus-claim-btn:hover:not(:disabled),
button.daily-bonus-claim-btn:focus-visible:not(:disabled) {
    transform: translateY(-1px);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.40),
        0 6px 14px rgba(5, 150, 105, 0.48),
        0 10px 22px rgba(16, 185, 129, 0.28);
    outline: none;
}
button.daily-bonus-claim-btn:active:not(:disabled) {
    transform: translateY(1px);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.20),
        0 2px 6px rgba(5, 150, 105, 0.32);
}
button.daily-bonus-claim-btn:disabled,
button.daily-bonus-claim-btn[aria-disabled='true'] {
    cursor: not-allowed;
    opacity: 0.6;
    filter: grayscale(35%);
}
button.daily-bonus-claim-btn.is-loading {
    pointer-events: none;
}
button.daily-bonus-claim-btn.is-loading::after {
    content: '';
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, 0.45);
    border-top-color: #fff;
    animation: daily-bonus-spin 0.7s linear infinite;
    margin-left: 4px;
}
@keyframes daily-bonus-spin {
    to { transform: rotate(360deg); }
}

/* Статусное сообщение. */
.daily-bonus-status {
    min-height: 18px;
    font-size: 12px;
    line-height: 1.3;
    color: var(--text-muted, #6b7280);
    text-align: center;
}
.daily-bonus-status.is-success {
    color: var(--widget-accent, #059669);
    font-weight: 600;
}
.daily-bonus-status.is-error {
    color: #ef4444;
}

/* ============================================================
   [v2.4 GAM-AUDIT] DAILY BONUS PROGRESS BAR + POPOVER
   ============================================================
   Прогресс-бар цикла: «осталось N дней до конца месяца».
   Popover для истории за 7 дней (открывается по клику на
   «Уже забрано ✓»). Контент и позиционирование — в
   renderDailyBonusWidget (public/app.js).
   ============================================================ */

.daily-bonus-progress {
    width: 100%;
    height: 6px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--widget-accent, #059669) 14%, transparent);
    overflow: hidden;
    position: relative;
    margin-top: -4px;
}
.daily-bonus-progress-bar {
    height: 100%;
    width: 0%;
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--widget-accent, #059669) 70%, #14b8a6),
        var(--widget-accent, #059669));
    border-radius: inherit;
    transition: width 0.4s ease;
}
.daily-bonus-progress.is-complete .daily-bonus-progress-bar {
    background: linear-gradient(90deg, #f59e0b, #fbbf24);
}
.daily-bonus-progress-text {
    font-size: 10px;
    color: var(--text-muted, #6b7280);
    margin-top: 2px;
    text-align: right;
    line-height: 1.2;
}
.daily-bonus-progress-text strong {
    color: var(--widget-accent, #059669);
    font-weight: 700;
}

/* Popover с историей за неделю. Контент заполняется JS,
   но позиционируется относительно CTA-кнопки через JS (fixed). */
.daily-bonus-popover {
    position: fixed;
    z-index: 9999;
    max-width: 320px;
    min-width: 240px;
    padding: 14px 16px;
    border-radius: 14px;
    background: color-mix(in srgb, var(--card-bg, #fff) 96%, transparent);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #059669) 22%, transparent);
    box-shadow:
        0 16px 36px -12px rgba(0, 0, 0, 0.24),
        0 2px 6px rgba(0, 0, 0, 0.06);
    color: var(--text-color, #222);
    font-size: 12px;
    line-height: 1.4;
}
.daily-bonus-popover[hidden] {
    display: none !important;
}
.daily-bonus-popover-title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 8px;
    font-weight: 700;
    font-size: 13px;
    color: var(--widget-accent, #059669);
}
.daily-bonus-popover-close {
    appearance: none;
    border: 0;
    background: transparent;
    cursor: pointer;
    color: var(--text-muted, #6b7280);
    font-size: 16px;
    line-height: 1;
    padding: 4px;
    border-radius: 6px;
    transition: background 0.15s ease;
}
.daily-bonus-popover-close:hover {
    background: color-mix(in srgb, var(--widget-accent, #059669) 12%, transparent);
    color: var(--text-color, #222);
}
.daily-bonus-popover-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 220px;
    overflow-y: auto;
    margin: 0;
    padding: 0;
    list-style: none;
}
.daily-bonus-popover-day {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 10px;
    border-radius: 8px;
    background: color-mix(in srgb, var(--widget-accent, #059669) 6%, transparent);
}
.daily-bonus-popover-day.is-empty {
    opacity: 0.6;
    background: color-mix(in srgb, var(--text-muted, #6b7280) 8%, transparent);
}
.daily-bonus-popover-date {
    font-weight: 600;
    color: var(--text-color, #222);
}
.daily-bonus-popover-reward {
    color: var(--widget-accent, #059669);
    font-weight: 700;
    text-align: right;
    white-space: nowrap;
}
.daily-bonus-popover-empty {
    text-align: center;
    color: var(--text-muted, #6b7280);
    padding: 12px 8px;
    font-style: italic;
}
.daily-bonus-popover-hint {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed color-mix(in srgb, var(--text-muted, #6b7280) 24%, transparent);
    font-size: 11px;
    color: var(--text-muted, #6b7280);
}

/* Кнопка в состоянии «уже забрано ✓» — теперь активна и
   показывает popover. Чуть более приглушённый фон, чем у
   нового claim, чтобы не конкурировать с основным flow. */
.daily-bonus-claim-btn.is-done,
button.daily-bonus-claim-btn.is-done {
    background: color-mix(in srgb, var(--widget-accent, #059669) 22%, var(--card-bg, #fff));
    color: var(--widget-accent, #059669);
    box-shadow: none;
    border: 1.5px dashed color-mix(in srgb, var(--widget-accent, #059669) 55%, transparent);
}
.daily-bonus-claim-btn.is-done:hover:not(:disabled),
.daily-bonus-claim-btn.is-done:focus-visible:not(:disabled),
button.daily-bonus-claim-btn.is-done:hover:not(:disabled),
button.daily-bonus-claim-btn.is-done:focus-visible:not(:disabled) {
    background: color-mix(in srgb, var(--widget-accent, #059669) 30%, var(--card-bg, #fff));
    transform: none;
}
.daily-bonus-claim-btn.is-done .check-mark,
button.daily-bonus-claim-btn.is-done .check-mark {
    font-weight: 700;
    margin-right: 4px;
}

/* [v2.4] Streak-синергия-чип в top-bar/сводке. */
.daily-bonus-streak-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    margin-left: 6px;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.2px;
    background: color-mix(in srgb, #f59e0b 18%, transparent);
    color: #b45309;
    border: 1px solid color-mix(in srgb, #f59e0b 40%, transparent);
}
body.dark-theme .daily-bonus-streak-chip {
    color: #fbbf24;
}
.daily-bonus-streak-chip .icon {
    font-size: 10px;
}

/* [v2.4] Бейдж «Суперпетля» — после начисления +750★. */
.daily-bonus-super-loop-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    background: linear-gradient(135deg, #f59e0b, #fbbf24);
    color: #fff;
    margin-left: 6px;
}

/* Сводка по циклу: «Получено X★ · Следующая: день Y, +Z★». */
.daily-bonus-summary {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    font-size: 11px;
    color: var(--text-muted, #6b7280);
}
.daily-bonus-summary-item {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--widget-accent, #059669) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #059669) 18%, transparent);
}
.daily-bonus-summary-item i {
    color: var(--widget-accent, #059669);
    font-size: 11px;
}
.daily-bonus-summary-item strong {
    color: var(--text-color, #222);
    font-weight: 700;
}

/* Тёмная тема: инвертируем фон ячеек и подсветку. */
body.dark-theme .daily-bonus-grid {
    background: color-mix(in srgb, var(--widget-accent, #059669) 12%, transparent);
}
body.dark-theme .daily-bonus-cell {
    background: rgba(255, 255, 255, 0.04);
    border-color: color-mix(in srgb, var(--widget-accent, #059669) 28%, transparent);
    color: var(--text-color, #e5e7eb);
}
body.dark-theme .daily-bonus-cell.is-claimed {
    background: var(--widget-accent, #059669);
    color: #06281e;
    border-color: var(--widget-accent, #059669);
}
body.dark-theme .daily-bonus-cell.is-claimed .daily-bonus-cell-reward {
    color: rgba(6, 40, 30, 0.8);
}
body.dark-theme .daily-bonus-summary-item {
    background: color-mix(in srgb, var(--widget-accent, #059669) 18%, transparent);
}

/* prefers-reduced-motion: убираем пульсацию и анимацию спиннера. */
@media (prefers-reduced-motion: reduce) {
    .daily-bonus-cell.is-today {
        animation: none;
    }
    .daily-bonus-claim-btn.is-loading::after,
    button.daily-bonus-claim-btn.is-loading::after {
        animation-duration: 2s;
    }
    .daily-bonus-cell,
    .daily-bonus-claim-btn,
    button.daily-bonus-claim-btn {
        transition: none;
    }
    .daily-bonus-cell:hover,
    .daily-bonus-claim-btn:hover:not(:disabled),
    .daily-bonus-claim-btn:focus-visible:not(:disabled),
    button.daily-bonus-claim-btn:hover:not(:disabled),
    button.daily-bonus-claim-btn:focus-visible:not(:disabled) {
        transform: none;
    }
}

/* =========================================================
   Celebration-stack (GAM-AUDIT §3.4)

   Полный пайплайн празднования:
     1. .celebration-toast — «+N ★» с летящей звездой в hero-chip.
     2. canvas-confetti (используется launchConfetti).
     3. .celebration-modal — две разновидности:
        • .celebration-modal--achievement — «🎉 Новое достижение»
        • .celebration-modal--levelup — анимированный level-up.

   Доступность:
     • .celebration-fly-star — всплывающая звезда, летит из
       исходного элемента (кнопка claim / бейдж) в hero-chip
       уровня; на prefers-reduced-motion сразу растворяется.
     • Контейнеры #celebrationLayer и #celebrationModalRoot
       создаются JS-ом (нет в HTML, чтобы не блокировать FCP).
   ========================================================= */

#celebrationLayer {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 19500;
    overflow: visible;
}

.celebration-toast {
    position: fixed;
    left: 50%;
    top: 88px;
    transform: translate(-50%, -16px);
    background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 50%, #d97706 100%);
    color: #1a1306;
    border-radius: 14px;
    padding: 14px 22px;
    box-shadow: 0 10px 32px rgba(245, 158, 11, 0.45),
                0 2px 8px rgba(0, 0, 0, 0.15);
    font-size: 18px;
    font-weight: 700;
    z-index: 19600;
    pointer-events: none;
    opacity: 0;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    transition: opacity 0.25s ease, transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
    max-width: calc(100vw - 32px);
}

.celebration-toast.show {
    opacity: 1;
    transform: translate(-50%, 0);
}

.celebration-toast-star {
    font-size: 22px;
    animation: celebration-toast-pulse 1.4s ease-in-out infinite;
}

.celebration-toast-amount {
    font-size: 20px;
    letter-spacing: 0.5px;
}

@keyframes celebration-toast-pulse {
    0%, 100% { transform: scale(1); }
    50%      { transform: scale(1.18); }
}

.celebration-fly-star {
    position: fixed;
    z-index: 19700;
    pointer-events: none;
    font-size: 28px;
    color: #fbbf24;
    text-shadow: 0 0 16px rgba(251, 191, 36, 0.8),
                 0 2px 6px rgba(0, 0, 0, 0.35);
    transform: translate(-50%, -50%) scale(1);
    will-change: transform, opacity;
    transition: transform 0.85s cubic-bezier(0.55, 0.0, 0.45, 1.0),
                opacity 0.85s ease-in;
}

.celebration-fly-star.flying {
    /* Конкретные координаты задаются через inset в JS */
    transform: translate(-50%, -50%) scale(0.5);
    opacity: 0;
}

.achievements-hero-chip--level.is-pulsing {
    animation: hero-chip-pulse 1.1s ease-out 0s 1;
}

@keyframes hero-chip-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0.7); }
    60%  { box-shadow: 0 0 0 18px rgba(251, 191, 36, 0); }
    100% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0); }
}

.celebration-modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(8, 10, 20, 0.72);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    z-index: 25000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    opacity: 0;
    transition: opacity 0.28s ease;
}

.celebration-modal-overlay.show {
    opacity: 1;
}

.celebration-modal {
    position: relative;
    background: var(--card-bg, #ffffff);
    color: var(--text-color, #1f2937);
    border-radius: 20px;
    width: 100%;
    max-width: 380px;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35),
                0 0 0 1px rgba(255, 255, 255, 0.05) inset;
    padding: 28px 24px 22px;
    text-align: center;
    overflow: hidden;
    transform: translateY(24px) scale(0.95);
    transition: transform 0.32s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.celebration-modal-overlay.show .celebration-modal {
    transform: translateY(0) scale(1);
}

body.dark-theme .celebration-modal {
    background: var(--card-bg, #1f2024);
    color: var(--text-color, #eee);
}

/* Лёгкий «луч» из центра — атмосфера праздника */
.celebration-modal::before {
    content: "";
    position: absolute;
    inset: -50%;
    background: conic-gradient(
        from 0deg,
        rgba(251, 191, 36, 0.12) 0deg,
        transparent 60deg,
        rgba(139, 92, 246, 0.10) 180deg,
        transparent 240deg,
        rgba(236, 72, 153, 0.10) 300deg,
        rgba(251, 191, 36, 0.12) 360deg
    );
    animation: celebration-modal-rays 14s linear infinite;
    pointer-events: none;
    z-index: 0;
}

.celebration-modal > * {
    position: relative;
    z-index: 1;
}

@keyframes celebration-modal-rays {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

.celebration-modal-emoji {
    font-size: 56px;
    line-height: 1;
    margin-bottom: 8px;
    display: inline-block;
    animation: celebration-modal-emoji-pop 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) 0.15s both;
}

@keyframes celebration-modal-emoji-pop {
    0%   { transform: scale(0.4) rotate(-12deg); opacity: 0; }
    70%  { transform: scale(1.15) rotate(4deg); opacity: 1; }
    100% { transform: scale(1) rotate(0deg); opacity: 1; }
}

.celebration-modal-title {
    font-size: 18px;
    font-weight: 700;
    margin: 6px 0 4px;
}

.celebration-modal-subtitle {
    font-size: 14px;
    color: var(--text-muted, #6b7280);
    margin: 0 0 16px;
}

.celebration-modal-reward {
    display: inline-block;
    background: linear-gradient(135deg, #fde68a 0%, #fbbf24 100%);
    color: #78350f;
    border-radius: 999px;
    padding: 6px 14px;
    font-weight: 700;
    font-size: 14px;
    margin: 4px 0 14px;
}

.celebration-modal-buttons {
    display: flex;
    gap: 10px;
    justify-content: center;
    margin-top: 16px;
    flex-wrap: wrap;
}

.celebration-modal-btn {
    appearance: none;
    border: 1px solid var(--input-border, #e0e0e0);
    background: var(--card-bg, #ffffff);
    color: var(--text-color, #1f2937);
    border-radius: 12px;
    padding: 10px 18px;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.12s ease, background 0.15s ease;
    min-height: 40px;
}

body.dark-theme .celebration-modal-btn {
    background: rgba(255, 255, 255, 0.06);
    color: var(--text-color, #eee);
    border-color: rgba(255, 255, 255, 0.12);
}

.celebration-modal-btn:hover,
.celebration-modal-btn:focus-visible {
    transform: translateY(-1px);
    outline: none;
}

.celebration-modal-btn--primary {
    background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
    color: #1a1306;
    border-color: transparent;
}

.celebration-modal-btn--primary:hover,
.celebration-modal-btn--primary:focus-visible {
    box-shadow: 0 6px 18px rgba(245, 158, 11, 0.35);
}

/* Level-up вариант: показываем обе шкалы и переход */
.celebration-modal--levelup {
    max-width: 420px;
}

.celebration-modal-level-transition {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    margin: 14px 0 6px;
    perspective: 600px;
}

.celebration-modal-level-block {
    background: var(--card-bg, #ffffff);
    border: 1px solid var(--input-border, #e0e0e0);
    border-radius: 14px;
    padding: 12px 16px;
    min-width: 88px;
    transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1),
                opacity 0.5s ease,
                background 0.4s ease,
                border-color 0.4s ease;
}

body.dark-theme .celebration-modal-level-block {
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(255, 255, 255, 0.1);
}

.celebration-modal-level-block-value {
    font-size: 22px;
    font-weight: 800;
    line-height: 1;
}

.celebration-modal-level-block-label {
    font-size: 11px;
    color: var(--text-muted, #6b7280);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-top: 2px;
}

.celebration-modal-level-block--old {
    opacity: 0.85;
}

.celebration-modal-level-block--new {
    background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
    color: #f59e0b;
    border-color: transparent;
    transform: scale(1.15);
    box-shadow: 0 6px 20px rgba(245, 158, 11, 0.4);
}

.celebration-modal-level-block--new .celebration-modal-level-block-label {
    color: rgba(245, 158, 11, 0.85);
}

.celebration-modal-level-arrow {
    font-size: 22px;
    color: #fbbf24;
    opacity: 0;
    animation: celebration-modal-arrow-slide 0.7s ease 0.4s forwards;
}

@keyframes celebration-modal-arrow-slide {
    0%   { opacity: 0; transform: translateX(-8px); }
    100% { opacity: 1; transform: translateX(0); }
}

.celebration-modal-unlocks {
    margin-top: 14px;
    padding: 12px 14px;
    background: rgba(251, 191, 36, 0.10);
    border: 1px solid rgba(245, 158, 11, 0.3);
    border-radius: 12px;
    font-size: 13px;
    text-align: left;
    line-height: 1.5;
}

body.dark-theme .celebration-modal-unlocks {
    background: rgba(251, 191, 36, 0.08);
}

.celebration-modal-unlocks-title {
    font-weight: 700;
    margin-bottom: 6px;
    font-size: 13px;
    color: #b45309;
}

body.dark-theme .celebration-modal-unlocks-title {
    color: #fcd34d;
}

.celebration-modal-unlocks-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.celebration-modal-unlocks-list li {
    background: rgba(255, 255, 255, 0.6);
    padding: 4px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
}

body.dark-theme .celebration-modal-unlocks-list li {
    background: rgba(255, 255, 255, 0.08);
}

.celebration-modal-stack {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* prefers-reduced-motion: отключаем анимации celebration. */
@media (prefers-reduced-motion: reduce) {
    .celebration-toast,
    .celebration-fly-star,
    .celebration-modal,
    .celebration-modal-emoji,
    .celebration-modal-level-block,
    .celebration-modal-arrow,
    .celebration-modal::before,
    .achievements-hero-chip--level.is-pulsing {
        animation: none !important;
        transition: none !important;
    }
    .celebration-fly-star {
        /* Скрываем сразу, чтобы не висела неподвижная звезда */
        display: none !important;
    }
    .celebration-modal {
        transform: none !important;
    }
}

/* ======================================================================
   [Tier 5] UI-полировка gamification (аудит 2026-06-29)
   ----------------------------------------------------------------------
   Блок инкапсулирует 9 из 12 пунктов Tier 5, которые не требуют
   изменения разметки виджетов (только CSS + i18n + JS):
     5.2  — расширенный CTA-placeholder «Начни серию»
     5.4  — empty-state блоки (streak=0, achievements=0, leaderboard=0)
     5.5  — skeleton на geotrackerLoading
     5.6  — touch-target >= 44px на achievements-hero-chip
     5.7  — focus-trap визуал (focus ring внутри popovers)
     5.9  — усиление .leaderboard-item.is-me (glow, border-radius, halo)
     5.10 — анимированный shine для achievement-tier-platinum
     5.11 — визуальное отличие .heropath-tier.is-not-started
     5.12 — вариант прогресс-бара со шкалой XP-кривой
   Правило: всегда использовать существующие CSS-переменные
   (--widget-accent, --card-bg, --text-color, --input-border),
   чтобы темизация (light/dark) работала автоматически.
   ====================================================================== */

/* --- 5.6 Touch-target на achievements-hero-chip ---------------------------- */
/* Размер тач-таргета по Apple HIG и WCAG 2.5.5 — минимум 44×44.
   Внешний вид (padding) не меняем — расширяем за счёт невидимой
   «safe-area» зоны вокруг, чтобы радиус нажатия соответствовал
   норме, но визуально капсула оставалась компактной. */
.achievements-hero-chip {
    /* min-width/min-height 44px, чтобы гарантировать WCAG 2.5.5 */
    min-width: 44px;
    min-height: 44px;
    box-sizing: border-box;
}
@media (max-width: 420px) {
    /* На самых узких экранах капсула уже меньше — сохраняем только
       вертикальный min-height, чтобы при горизонтальном скролле
       ширина не блокировалась. */
    .achievements-hero-chip {
        min-width: 0;
    }
}

/* --- 5.9 .leaderboard-item.is-me — усиление ------------------------------ */
/* Текущий .is-me использует только плоский border и bg-tint.
   Добавляем: ярче border, gradient-обводку, мягкий glow, маленький
   пилл-тэг «ВЫ» (уже есть в HTML, переиспользуем).
   Селектор :not(:hover) важен, чтобы на hover-state рамка
   оставалась «родной», без двойного наложения. */
.leaderboard-item.is-me {
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--widget-accent, #f69a00) 26%, var(--card-bg, #fff)) 0%,
        color-mix(in srgb, var(--widget-accent, #f69a00) 12%, var(--card-bg, #fff)) 100%);
    border: 1.5px solid color-mix(in srgb, var(--widget-accent, #f69a00) 70%, transparent);
    box-shadow:
        0 0 0 1px color-mix(in srgb, var(--widget-accent, #f69a00) 28%, transparent) inset,
        0 4px 14px color-mix(in srgb, var(--widget-accent, #f69a00) 35%, transparent),
        0 0 22px color-mix(in srgb, var(--widget-accent, #f69a00) 22%, transparent);
    position: relative;
}
.leaderboard-item.is-me::before {
    /* Тонкий gradient-strip слева — мгновенно читается как «моя
       строка», даже в длинном списке без скролла. */
    content: "";
    position: absolute;
    left: 0; top: 6px; bottom: 6px;
    width: 4px;
    border-radius: 999px;
    background: linear-gradient(180deg,
        var(--widget-accent, #f69a00),
        color-mix(in srgb, var(--widget-accent, #f69a00) 60%, #ef4444));
    box-shadow: 0 0 6px color-mix(in srgb, var(--widget-accent, #f69a00) 55%, transparent);
}
.leaderboard-item.is-me:hover {
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--widget-accent, #f69a00) 32%, var(--card-bg, #fff)) 0%,
        color-mix(in srgb, var(--widget-accent, #f69a00) 18%, var(--card-bg, #fff)) 100%);
    transform: translateX(2px);
}
@media (prefers-reduced-motion: reduce) {
    .leaderboard-item.is-me::before { animation: none !important; }
}

/* --- 5.10 .achievement-tier-platinum — анимированный shine --------------- */
/* Перебиваем gold look: добавлен sweep-blink по фону + усиленное
   outline-glow. Бегущий блик сделан через ::before (без conflict с
   tier-bronze/silver/gold, которые ::before не используют). */
.achievement-badge.achievement-tier-platinum.is-unlocked {
    position: relative;
    overflow: hidden;
    box-shadow:
        0 1px 2px rgba(139, 92, 246, 0.28),
        0 6px 22px rgba(139, 92, 246, 0.20),
        inset 0 0 0 1px color-mix(in srgb, #8b5cf6 38%, transparent);
}
.achievement-badge.achievement-tier-platinum.is-unlocked::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(115deg,
        transparent 25%,
        rgba(255, 255, 255, 0.45) 45%,
        rgba(255, 255, 255, 0.65) 50%,
        rgba(255, 255, 255, 0.45) 55%,
        transparent 75%);
    background-size: 250% 250%;
    background-position: -120% -120%;
    animation: platinum-shine 4.2s ease-in-out infinite;
    mix-blend-mode: screen;
    z-index: 0;
}
.achievement-badge.achievement-tier-platinum.is-unlocked > * {
    /* Поднимаем контент над shine-overlay, иначе блик
       будет перекрывать текст/иконку. */
    position: relative;
    z-index: 1;
}
@keyframes platinum-shine {
    0%   { background-position: -120% -120%; }
    45%  { background-position: -120% -120%; }
    55%  { background-position: 120% 120%; }
    100% { background-position: 120% 120%; }
}
body.dark-theme .achievement-badge.achievement-tier-platinum.is-unlocked {
    box-shadow:
        0 1px 2px rgba(139, 92, 246, 0.40),
        0 6px 22px rgba(139, 92, 246, 0.30),
        inset 0 0 0 1px color-mix(in srgb, #8b5cf6 50%, transparent);
}
@media (prefers-reduced-motion: reduce) {
    .achievement-badge.achievement-tier-platinum.is-unlocked::before {
        animation: none !important;
        opacity: 0.25;
    }
}

/* --- 5.11 .heropath-tier.is-not-started ------------------------------------ */
/* Отличаем «ещё не начат» от «в процессе»:
   • В процессе  — есть border + заполненный/частично .heropath-tier-fill
   • Не начат   — пунктирный border + opacity 0.55 + без .heropath-tier-fill
   Это явный визуальный сигнал «можно начать», в отличие от «уже
   идёшь к цели». Тоггл состояния — из JS (renderHeroPath). */
.heropath-tier.is-not-started {
    border-style: dashed;
    border-color: color-mix(in srgb, var(--text-muted, #64748b) 30%, transparent);
    opacity: 0.6;
}
.heropath-tier.is-not-started .heropath-tier-fill {
    /* Полностью скрываем шкалу прогресса, чтобы не вводить
       в заблуждение: «0 / 0» — это не цель, это «даже не
       ступал на тропу». */
    display: none;
}
.heropath-tier.is-not-started .heropath-tier-track {
    /* Оставляем «пустую» дорожку, чтобы карточка имела
       тот же размер и не дёргалась при старте. */
    background: rgba(15, 23, 42, 0.025);
    opacity: 0.7;
}
.heropath-tier.is-not-started .heropath-tier-dot {
    /* Контурная, не залитая точка — «пустой флажок на карте». */
    background: transparent;
    border: 1.5px dashed color-mix(in srgb, var(--text-muted, #64748b) 55%, transparent);
    box-shadow: none;
}
.heropath-tier.is-not-started:hover {
    opacity: 0.95;
}
body.dark-theme .heropath-tier.is-not-started {
    border-color: color-mix(in srgb, var(--text-muted, #94a3b8) 35%, transparent);
}
body.dark-theme .heropath-tier.is-not-started .heropath-tier-track {
    background: rgba(255, 255, 255, 0.025);
}

/* --- 5.4 Empty-state блоки ----------------------------------------------- */
/* Общий каркас: карточка-CTA по центру виджета с иконкой, заголовком,
   подсказкой и кнопкой. Стили применяются к:
     .widget-empty-state                — контейнер
     .widget-empty-state-icon           — большая иконка/эмодзи
     .widget-empty-state-title          — заголовок
     .widget-empty-state-body           — поясняющий текст
     .widget-empty-state-cta            — кнопка-CTA
   Цвета берём из widget-tint-* (override через CSS-переменные). */
.widget-empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    text-align: center;
    padding: 22px 16px;
    margin: 8px 0;
    border-radius: 14px;
    border: 1.5px dashed color-mix(in srgb, var(--widget-accent, #94a3b8) 35%, transparent);
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--widget-accent, #94a3b8) 6%, var(--card-bg, #fff)),
        var(--card-bg, #fff));
}
.widget-empty-state-icon {
    font-size: 30px;
    line-height: 1;
    /* Лёгкая пружинка появления, чтобы карточка не «выскакивала» резко. */
    animation: widget-empty-state-pop 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) 1;
}
.widget-empty-state-title {
    font-size: 14px;
    font-weight: 700;
    color: var(--text-color, #1e293b);
    margin: 0;
}
.widget-empty-state-body {
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--text-muted, #64748b);
    max-width: 36ch;
    margin: 0;
}
.widget-empty-state-cta {
    margin-top: 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 44px;
    padding: 9px 18px;
    border-radius: 999px;
    border: none;
    font-size: 12.5px;
    font-weight: 700;
    color: #fff;
    text-decoration: none;
    cursor: pointer;
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--widget-accent, #94a3b8) 95%, #fff),
        color-mix(in srgb, var(--widget-accent, #94a3b8) 75%, #000));
    box-shadow: 0 2px 8px color-mix(in srgb, var(--widget-accent, #94a3b8) 35%, transparent);
    transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.widget-empty-state-cta:hover,
.widget-empty-state-cta:focus-visible {
    transform: translateY(-1px);
    box-shadow: 0 4px 14px color-mix(in srgb, var(--widget-accent, #94a3b8) 45%, transparent);
    outline: none;
}
.widget-empty-state-cta:focus-visible {
    box-shadow:
        0 4px 14px color-mix(in srgb, var(--widget-accent, #94a3b8) 45%, transparent),
        inset 0 0 0 2px rgba(255, 255, 255, 0.7);
}
@keyframes widget-empty-state-pop {
    0%   { transform: scale(0.6); opacity: 0; }
    60%  { transform: scale(1.08); opacity: 1; }
    100% { transform: scale(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .widget-empty-state-icon {
        animation: none !important;
    }
}

/* Streak-week.is-empty дополняем «дорожкой-приглашением»: каждый
   кружок чуть ярче и pulse, чтобы подчеркнуть «жми на квест» (Tier 5.2). */
.streak-week.is-empty .streak-week-day .streak-week-dot {
    background: color-mix(in srgb, var(--widget-accent, #f97316) 22%, var(--card-bg, #fff));
    border-color: color-mix(in srgb, var(--widget-accent, #f97316) 60%, transparent);
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--widget-accent, #f97316) 35%, transparent);
    animation: streak-empty-cta-pulse 2.4s ease-in-out infinite;
}
.streak-week.is-empty .streak-week-day:hover .streak-week-dot {
    /* Усиленный hover в empty-режиме — это «призыв», а не просто
       декоративный hover. */
    transform: scale(1.28);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--widget-accent, #f97316) 35%, transparent);
}
@keyframes streak-empty-cta-pulse {
    0%, 100% {
        box-shadow: 0 0 0 0 color-mix(in srgb, var(--widget-accent, #f97316) 35%, transparent);
    }
    50% {
        box-shadow: 0 0 0 6px color-mix(in srgb, var(--widget-accent, #f97316) 8%, transparent);
    }
}
@media (prefers-reduced-motion: reduce) {
    .streak-week.is-empty .streak-week-day .streak-week-dot {
        animation: none !important;
    }
}

/* --- 5.5 Skeleton для widget-body (loading) ------------------------------ */
/* Применяется к:
   .widget-body.is-loading → всё тело виджета превращается в 3-4 серых
   «полосы», имитирующих контент до получения data.
   Параллельно:
   .skeleton-line (базовый блок) с shimmer-анимацией.
   ВАЖНО: используем готовый .widget-place-shimmer pattern (line 10389)
   для согласованности с другими skeleton в проекте. */
.widget-body.is-loading {
    /* Отключаем любые дочерние взаимодействия. */
    pointer-events: none;
    user-select: none;
}
.widget-body.is-loading > *:not(.widget-skeleton):not(.widget-body-skeleton) {
    /* Скрываем реальный контент, оставляем только .widget-skeleton. */
    visibility: hidden;
}
.widget-skeleton {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px 14px;
}
.widget-skeleton-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 6px 0;
}
.widget-skeleton-line {
    flex: 1 1 auto;
    height: 12px;
    border-radius: 6px;
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--text-muted, #94a3b8) 16%, var(--card-bg, #fff)) 0%,
        color-mix(in srgb, var(--text-muted, #94a3b8) 28%, var(--card-bg, #fff)) 50%,
        color-mix(in srgb, var(--text-muted, #94a3b8) 16%, var(--card-bg, #fff)) 100%);
    background-size: 200% 100%;
    animation: widget-skeleton-shimmer 1.4s ease-in-out infinite;
}
.widget-skeleton-circle {
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--text-muted, #94a3b8) 18%, var(--card-bg, #fff)) 0%,
        color-mix(in srgb, var(--text-muted, #94a3b8) 32%, var(--card-bg, #fff)) 50%,
        color-mix(in srgb, var(--text-muted, #94a3b8) 18%, var(--card-bg, #fff)) 100%);
    background-size: 200% 100%;
    animation: widget-skeleton-shimmer 1.4s ease-in-out infinite;
}
.widget-skeleton-line--short { flex: 0 0 35%; }
.widget-skeleton-line--mid   { flex: 0 0 55%; }
.widget-skeleton-line--pill  {
    height: 22px;
    border-radius: 999px;
    flex: 0 0 70px;
}
.widget-skeleton-line--hero  {
    height: 32px;
    flex: 0 0 60%;
    border-radius: 8px;
}
@keyframes widget-skeleton-shimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
    .widget-skeleton-line,
    .widget-skeleton-circle {
        animation: none !important;
    }
}

/* --- 5.12 Player-level XP-кривая ----------------------------------------- */
/* Прогресс-бар в .widget-player-level-summary получает вариант
   .is-xp-curve: вместо одного столбика — сегменты «0 → 100 → 225 → 375 …»
   (квадратичная формула level² × K, K=25). Сегменты показаны
   тонкими tick-метками, а прогресс — заполненной частью.
   Markup: см. JS renderPlayerLevelWidgetXpCurve. */
.player-level-xp-curve {
    position: relative;
    margin-top: 10px;
    padding: 6px 0 0;
}
.player-level-xp-curve-track {
    position: relative;
    height: 8px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--widget-accent, #f59e0b) 14%, var(--card-bg, #fff));
    overflow: visible;
}
.player-level-xp-curve-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: var(--xp-curve-fill, 0%);
    border-radius: inherit;
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--widget-accent, #f59e0b) 70%, #fff),
        var(--widget-accent, #f59e0b));
    box-shadow: 0 0 8px color-mix(in srgb, var(--widget-accent, #f59e0b) 45%, transparent);
    transition: width 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.player-level-xp-curve-tick {
    /* Tick-метки на пороге каждого уровня. */
    position: absolute;
    top: -2px;
    width: 1px;
    height: 12px;
    background: color-mix(in srgb, var(--text-muted, #64748b) 35%, transparent);
    pointer-events: none;
}
.player-level-xp-curve-tick.is-passed {
    background: color-mix(in srgb, var(--widget-accent, #f59e0b) 75%, #fff);
    height: 14px;
    top: -3px;
}
.player-level-xp-curve-label {
    position: absolute;
    top: 14px;
    transform: translateX(-50%);
    font-size: 9px;
    font-weight: 700;
    color: var(--text-muted, #64748b);
    font-variant-numeric: tabular-nums;
    pointer-events: none;
    white-space: nowrap;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.player-level-xp-curve-label.is-passed {
    color: color-mix(in srgb, var(--widget-accent, #f59e0b) 80%, var(--text-color, #1e293b));
}
.player-level-xp-curve-caption {
    margin-top: 18px;
    font-size: 11.5px;
    color: var(--text-muted, #64748b);
    font-weight: 500;
    line-height: 1.35;
}
.player-level-xp-curve-caption strong {
    color: var(--text-color, #1e293b);
    font-weight: 700;
}

/* --- 5.7 Popover focus-trap визуал --------------------------------------- */
/* Когда JS устанавливает data-focus-trapped="true" на popover —
   показываем мягкий focus-ring вокруг всего контейнера.
   Это не требует изменения JS — только визуальный сигнал. */
[data-focus-trapped="true"] {
    outline: none;
}
.streak-info-popover[data-focus-trapped="true"],
.achievement-badge-popover[data-focus-trapped="true"] {
    box-shadow:
        0 16px 48px rgba(0, 0, 0, 0.32),
        0 4px 14px rgba(0, 0, 0, 0.20),
        0 0 0 3px color-mix(in srgb, var(--widget-accent, #f69a00) 55%, transparent);
}
.achievement-badge-popover[data-focus-trapped="true"] {
    box-shadow:
        0 16px 48px rgba(0, 0, 0, 0.32),
        0 4px 14px rgba(0, 0, 0, 0.20),
        0 0 0 3px color-mix(in srgb, #8b5cf6 55%, transparent);
}

/* ============================================================
   [GAM-RECO §3.2] Weekly / Monthly challenges widget
   ============================================================ */
.widget-weekly-challenges-body {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.wc-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.wc-group-title {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--widget-accent, #6366f1);
    margin: 4px 0 0;
}
.wc-group-title i {
    font-size: 11px;
    opacity: 0.8;
}
.wc-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}
.wc-card {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: 12px;
    background: var(--widget-accent-soft, rgba(99, 102, 241, 0.10));
    border: 1px solid color-mix(in srgb,
        var(--widget-accent, #6366f1) 22%, transparent);
}
.wc-card.is-completed {
    border-color: color-mix(in srgb, #10b981 55%, transparent);
    background: color-mix(in srgb, #10b981 12%, transparent);
}
.wc-card.is-claimed {
    opacity: 0.65;
    background: color-mix(in srgb, #10b981 6%, transparent);
}
.wc-card-icon {
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--widget-accent, #6366f1);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    box-shadow: 0 2px 8px color-mix(in srgb,
        var(--widget-accent, #6366f1) 35%, transparent);
}
.wc-card.is-completed .wc-card-icon {
    background: #10b981;
    box-shadow: 0 2px 8px color-mix(in srgb, #10b981 35%, transparent);
}
.wc-card-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.wc-card-title {
    font-size: 14px;
    font-weight: 700;
    line-height: 1.25;
    color: var(--text-color, #222);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.wc-card-desc {
    font-size: 12px;
    line-height: 1.35;
    color: var(--text-muted, #666);
    overflow: hidden;
    text-overflow: ellipsis;
}
.wc-card-progress {
    position: relative;
    height: 6px;
    border-radius: 999px;
    background: color-mix(in srgb,
        var(--widget-accent, #6366f1) 14%, transparent);
    overflow: hidden;
    margin-top: 4px;
}
.wc-card-progress-fill {
    position: absolute;
    inset: 0;
    width: 0%;
    background: var(--widget-accent, #6366f1);
    border-radius: 999px;
    transition: width .35s ease;
}
.wc-card.is-completed .wc-card-progress-fill {
    background: #10b981;
}
.wc-card-progress-text {
    font-size: 11px;
    color: var(--text-muted, #888);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    margin-top: 2px;
}
.wc-card-reward {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: 12px;
    font-weight: 700;
    color: #b45309;
    white-space: nowrap;
}
.wc-card-reward i {
    color: #f59e0b;
}
.wc-card-claim {
    flex: 0 0 auto;
    border: 0;
    padding: 6px 12px;
    border-radius: 999px;
    background: #10b981;
    color: #fff;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    transition: transform .15s ease, box-shadow .15s ease, opacity .15s ease;
    min-height: 32px;
}
.wc-card-claim:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px color-mix(in srgb, #10b981 40%, transparent);
}
.wc-card-claim:disabled {
    background: color-mix(in srgb, #10b981 35%, transparent);
    cursor: default;
    opacity: 0.7;
}
.wc-card.is-claimed .wc-card-claim {
    background: color-mix(in srgb, #10b981 22%, transparent);
}
.wc-empty {
    margin: 4px 0;
    color: var(--text-muted, #888);
    font-size: 13px;
    text-align: center;
    padding: 12px 8px;
}

/* ============================================================
   Balance section: «Spend calculator» button + modal.

   Кнопка использует общий класс `.pushable.stars-package-btn`
   (как и кнопки пакетов Stars в настройках — тот же фон, типография,
   hover/active-анимация). Размещается под виджетом «Баланс» и
   занимает всю ширину контейнера.

   Модальное окно построено по образцу `.celebration-modal-*` —
   с поддержкой тёмной/светлой темы через CSS-переменные
   `--card-bg` / `--text-color` / `--text-muted`, которые
   переопределяются в `body.dark-theme`.

   Сетка полей использует те же `--widget-accent` тона, что и
   остальные виджеты дашборда.
   ============================================================ */

.balance-calculator-wrap {
    /* Контейнер под виджетом Баланса, чтобы кнопка была на всю
       ширину карточки виджета. Поля добавляются через
       margin-top — сам виджет не трогаем. */
    display: block;
    width: 100%;
    margin-top: -8px;
    margin-bottom: 16px;
}

.balance-calculator-wrap .pushable.balance-calculator-btn {
    width: 100%;
    box-sizing: border-box;
}

.balance-calculator-wrap .pushable.balance-calculator-btn .front {
    /* Уменьшаем паддинг относительно stars-package-btn, чтобы
       кнопка визуально читалась как «второстепенное действие»
       под виджетом Баланса, а не как пакет Stars. */
    padding: 12px 18px;
    font-size: 0.9rem;
    letter-spacing: 0.6px;
}

.balance-calculator-wrap .balance-calculator-btn-points {
    /* Лёгкий полупрозрачный бейдж справа от названия — единый
       стиль с .stars-package-points, чтобы кнопка выглядела
       как «часть» семейства pushable-кнопок. */
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.22);
    font-size: 13px;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: 0.1px;
    white-space: nowrap;
    gap: 4px;
}

/* ----- Модалка калькулятора ----- */

.balance-calculator-overlay {
    position: fixed;
    inset: 0;
    background: rgba(8, 10, 20, 0.72);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    z-index: 25000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    opacity: 0;
    transition: opacity 0.28s ease;
}

.balance-calculator-overlay.show {
    opacity: 1;
}

.balance-calculator-modal {
    position: relative;
    background: var(--card-bg, #ffffff);
    color: var(--text-color, #1f2937);
    border-radius: 20px;
    width: 100%;
    max-width: 460px;
    max-height: calc(100vh - 32px);
    overflow-y: auto;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35),
                0 0 0 1px rgba(255, 255, 255, 0.05) inset;
    padding: 22px 22px 18px;
    text-align: left;
    transform: translateY(24px) scale(0.95);
    transition: transform 0.32s cubic-bezier(0.34, 1.56, 0.64, 1);
    /* Скроллбар — нейтральный, чтобы не конфликтовать с темой */
    scrollbar-width: thin;
    scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
}

.balance-calculator-overlay.show .balance-calculator-modal {
    transform: translateY(0) scale(1);
}

.balance-calculator-overlay .balance-calculator-modal::-webkit-scrollbar {
    width: 6px;
}
.balance-calculator-overlay .balance-calculator-modal::-webkit-scrollbar-thumb {
    background: rgba(0, 0, 0, 0.25);
    border-radius: 3px;
}

body.dark-theme .balance-calculator-modal {
    background: var(--card-bg, #1f2024);
    color: var(--text-color, #eee);
}
body.dark-theme .balance-calculator-modal::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.18);
}
body.dark-theme .balance-calculator-modal {
    scrollbar-color: rgba(255, 255, 255, 0.18) transparent;
}

.balance-calculator-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 6px;
}

.balance-calculator-modal-title {
    margin: 0;
    font-size: 17px;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--text-color, #1f2937);
}

.balance-calculator-modal-subtitle {
    margin: 0 0 14px;
    font-size: 13px;
    color: var(--text-muted, #6b7280);
    line-height: 1.4;
}

.balance-calculator-modal-close {
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--text-color, #222) 18%, transparent);
    color: var(--text-muted, #6b7280);
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
    width: 32px;
    height: 32px;
    min-width: 32px;
    min-height: 32px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s ease, color 0.15s ease,
        border-color 0.15s ease, transform 0.15s ease;
}

.balance-calculator-modal-close:hover,
.balance-calculator-modal-close:focus-visible {
    background: rgba(0, 0, 0, 0.05);
    color: var(--text-color, #222);
    border-color: color-mix(in srgb, var(--text-color, #222) 36%, transparent);
    outline: none;
    transform: scale(1.05);
}

body.dark-theme .balance-calculator-modal-close {
    border-color: color-mix(in srgb, var(--text-color, #e5e7eb) 22%, transparent);
    color: #9ca3af;
}
body.dark-theme .balance-calculator-modal-close:hover,
body.dark-theme .balance-calculator-modal-close:focus-visible {
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-color, #e5e7eb);
    border-color: color-mix(in srgb, var(--text-color, #e5e7eb) 42%, transparent);
}

/* ----- Секции и поля ----- */

.balance-calculator-section {
    margin: 14px 0 0;
    padding: 12px 12px 10px;
    border-radius: 14px;
    background: color-mix(in srgb, var(--widget-accent, #14b8a6) 6%, transparent);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #14b8a6) 16%, transparent);
}

body.dark-theme .balance-calculator-section {
    background: color-mix(in srgb, var(--widget-accent, #14b8a6) 12%, transparent);
    border-color: color-mix(in srgb, var(--widget-accent, #14b8a6) 24%, transparent);
}

.balance-calculator-section-title {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--widget-accent, #14b8a6) 78%, var(--text-color, #1f2937));
    margin: 0 0 10px;
}

.balance-calculator-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 10px;
}

.balance-calculator-field:last-child {
    margin-bottom: 0;
}

.balance-calculator-field-label {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-color, #1f2937);
}

.balance-calculator-field-help {
    font-size: 11px;
    color: var(--text-muted, #6b7280);
    line-height: 1.35;
}

.balance-calculator-input-row {
    display: flex;
    align-items: center;
    gap: 8px;
    /* Контейнер селекта — relative, чтобы выпадающая панель
       позиционировалась относительно него. */
    position: relative;
}

/* ============================================================
   Кастомный селект (.bc-select).
   Полностью стилизованная выпадающая зона в духе современных
   дизайн-систем: glass-эффект (backdrop-filter), мягкие тени,
   анимация открытия/закрытия, чек-маркер у выбранного значения,
   hover/focus-состояния, корректная работа в тёмной теме.
   ============================================================ */

.bc-select {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-color, #1f2937);
}

/* Триггер-кнопка — то, что видит пользователь, когда меню закрыто.
   По стилю похож на .balance-calculator-input, но с тонким
   акцентным кольцом при открытии/фокусе. */
.bc-select-trigger {
    appearance: none;
    -webkit-appearance: none;
    width: 100%;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    background: var(--input-bg, #ffffff);
    color: var(--text-color, #1f2937);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #14b8a6) 22%, var(--input-border, #e0e0e0));
    border-radius: 10px;
    padding: 8px 12px;
    font: inherit;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    transition: border-color 0.18s ease, box-shadow 0.18s ease,
        background-color 0.18s ease;
}
.bc-select-trigger:hover {
    border-color: color-mix(in srgb, var(--widget-accent, #14b8a6) 40%, transparent);
    background: color-mix(in srgb, var(--widget-accent, #14b8a6) 4%, var(--input-bg, #ffffff));
}
.bc-select-trigger:focus-visible {
    outline: none;
    border-color: var(--widget-accent, #14b8a6);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--widget-accent, #14b8a6) 28%, transparent);
}
body.dark-theme .bc-select-trigger {
    background: rgba(255, 255, 255, 0.06);
    border-color: color-mix(in srgb, var(--widget-accent, #14b8a6) 32%, transparent);
    color: var(--text-color, #eee);
}
body.dark-theme .bc-select-trigger:hover {
    background: rgba(255, 255, 255, 0.10);
}

/* При открытом меню — акцентная рамка и лёгкая тень */
.bc-select.is-open .bc-select-trigger {
    border-color: var(--widget-accent, #14b8a6);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--widget-accent, #14b8a6) 22%, transparent);
}

/* Значение внутри триггера — моноширинный шрифт, чтобы цифры
   не прыгали при выборе. */
.bc-select-label {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Шеврон-стрелка справа — SVG-псевдоэлемент для масштабируемости
   и тематизации через currentColor. */
.bc-select-caret {
    flex: 0 0 12px;
    width: 12px;
    height: 12px;
    position: relative;
    transition: transform 0.22s cubic-bezier(0.4, 0.0, 0.2, 1);
    /* Цвет стрелки — на 30% темнее основного текста, чтобы
       приглушить без потери контраста. */
    color: color-mix(in srgb, var(--text-color, #1f2937) 70%, transparent);
}
.bc-select-caret::before {
    content: "";
    position: absolute;
    inset: 0;
    border-left: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: translate(-1px, -3px) rotate(-45deg);
    border-radius: 1px;
}
.bc-select.is-open .bc-select-caret {
    transform: rotate(180deg);
}

/* ----- Выпадающая зона (.bc-select-menu) ----- */

.bc-select-menu {
    /* По умолчанию скрыта; :is-open родителя делает её видимой. */
    visibility: hidden;
    opacity: 0;
    transform: translateY(-6px) scale(0.98);
    pointer-events: none;
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    z-index: 30;
    max-height: 240px;
    overflow-y: auto;
    /* Лёгкий glass-эффект + тень. В тёмной теме меняется на
       более насыщенный фон для читаемости. */
    background: var(--card-bg, #ffffff);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #14b8a6) 24%, transparent);
    border-radius: 12px;
    box-shadow:
        0 10px 30px -8px rgba(0, 0, 0, 0.25),
        0 2px 6px -2px rgba(0, 0, 0, 0.12),
        0 0 0 1px rgba(255, 255, 255, 0.04) inset;
    padding: 4px;
    /* Небольшой blur для glass-эффекта (где поддерживается). */
    backdrop-filter: blur(8px) saturate(140%);
    -webkit-backdrop-filter: blur(8px) saturate(140%);
    transition:
        opacity 0.18s cubic-bezier(0.4, 0.0, 0.2, 1),
        transform 0.22s cubic-bezier(0.4, 0.0, 0.2, 1),
        visibility 0s linear 0.18s;
    /* Красивый скроллбар на webkit */
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--widget-accent, #14b8a6) 40%, transparent) transparent;
}
.bc-select-menu::-webkit-scrollbar {
    width: 6px;
}
.bc-select-menu::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--widget-accent, #14b8a6) 40%, transparent);
    border-radius: 3px;
}

.bc-select.is-open .bc-select-menu {
    visibility: visible;
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: auto;
    transition:
        opacity 0.18s cubic-bezier(0.4, 0.0, 0.2, 1),
        transform 0.22s cubic-bezier(0.4, 0.0, 0.2, 1),
        visibility 0s linear 0s;
}

body.dark-theme .bc-select-menu {
    background: color-mix(in srgb, #1f2024 92%, transparent);
    border-color: color-mix(in srgb, var(--widget-accent, #14b8a6) 36%, transparent);
    box-shadow:
        0 12px 32px -8px rgba(0, 0, 0, 0.55),
        0 4px 8px -2px rgba(0, 0, 0, 0.35),
        0 0 0 1px rgba(255, 255, 255, 0.06) inset;
}

/* ----- Опция в выпадающем списке ----- */

.bc-select-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 12px;
    border-radius: 8px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-color, #1f2937);
    cursor: pointer;
    user-select: none;
    transition: background-color 0.12s ease, color 0.12s ease;
    font-variant-numeric: tabular-nums;
}
body.dark-theme .bc-select-option {
    color: var(--text-color, #eee);
}

.bc-select-option:hover,
.bc-select-option:focus-visible {
    background: color-mix(in srgb, var(--widget-accent, #14b8a6) 12%, transparent);
    outline: none;
}

/* Выбранная опция — фон-акцент (но не полная заливка, чтобы
   сохранять иерархию с hover) + чек-маркер справа. */
.bc-select-option.is-selected {
    background: color-mix(in srgb, var(--widget-accent, #14b8a6) 18%, transparent);
    color: color-mix(in srgb, var(--widget-accent, #14b8a6) 92%, var(--text-color, #1f2937));
}
body.dark-theme .bc-select-option.is-selected {
    color: color-mix(in srgb, var(--widget-accent, #14b8a6) 90%, var(--text-color, #eee));
}

.bc-select-option-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bc-select-option-check {
    flex: 0 0 14px;
    width: 14px;
    height: 14px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 700;
    color: var(--widget-accent, #14b8a6);
    opacity: 0;
    transform: scale(0.4);
    transition: opacity 0.18s ease, transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.bc-select-option.is-selected .bc-select-option-check {
    opacity: 1;
    transform: scale(1);
}

/* prefers-reduced-motion: убираем анимации. */
@media (prefers-reduced-motion: reduce) {
    .bc-select-trigger,
    .bc-select-caret,
    .bc-select-menu,
    .bc-select-option,
    .bc-select-option-check {
        transition: none;
    }
    .bc-select.is-open .bc-select-caret {
        transform: rotate(180deg);
    }
}

/* Range-стилизация удалена: range-инпуты заменены на кастомные
   селекты (см. .bc-select ниже в этом же блоке). */

.balance-calculator-unit {
    font-size: 12px;
    color: var(--text-muted, #6b7280);
    white-space: nowrap;
}

/* Toggle «switch» для daily login.
   Структура:
     <label class="balance-calculator-toggle-row">
       <input type="checkbox" class="balance-calculator-toggle-input">
       <span class="toggle-slider"></span>
       <span class="balance-calculator-toggle-label">…</span>
     </label>

   IMPORTANT: вход скрывается через `position: absolute; opacity: 0`
   БЕЗ `pointer-events: none`. Последнее блокирует нативный
   forward click от `<label>` к `<input>` в некоторых браузерах,
   из-за чего клик по label не переключает чекбокс. */
.balance-calculator-toggle-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 4px 0;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    /* Контейнер для абсолютно-позиционированного .balance-calculator-toggle-input.
       Без этого input резолвится относительно .balance-calculator-modal
       (position: relative; overflow-y: auto) — браузер при фокусе чекбокса
       скроллит модалку к своему top:0, и она «прыгает» наверх при клике. */
    position: relative;
}

.balance-calculator-toggle-input {
    /* Абсолютно-позиционированный «сжатый» чекбокс: невидим, но
       кликабелен. Не задаём pointer-events: none — иначе в Safari/
       некоторых Chromium-версиях клик по label не доходит до input
       (input перестаёт переключаться). */
    position: absolute;
    top: 0;
    left: 0;
    width: 1px;
    height: 1px;
    opacity: 0;
    padding: 0;
    margin: -1px;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Фокус-кольцо показываем на slider'е, когда input в фокусе
   с клавиатуры — это a11y-стандарт для скрытых чекбоксов. */
.balance-calculator-toggle-input:focus-visible + .toggle-slider {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--widget-accent, #14b8a6) 35%, transparent);
}

/* Кастомный slider — перекрываем глобальный .toggle-slider,
   который рассчитан на 44×24 (для monitoring-zones). Здесь
   используем 40×22 для более компактного вида в модалке. */
.balance-calculator-toggle-row .toggle-slider {
    position: relative;
    flex: 0 0 40px;
    width: 40px;
    height: 22px;
    border-radius: 22px;
    background-color: color-mix(in srgb, var(--text-color, #1f2937) 22%, transparent);
    transition: background-color 0.25s ease;
    cursor: pointer;
}
.balance-calculator-toggle-row .toggle-slider::before {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background-color: #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
    transition: transform 0.25s cubic-bezier(0.4, 0.0, 0.2, 1);
}
.balance-calculator-toggle-input:checked + .toggle-slider {
    background-color: var(--widget-accent, #14b8a6);
}
.balance-calculator-toggle-input:checked + .toggle-slider::before {
    transform: translateX(18px);
}
body.dark-theme .balance-calculator-toggle-row .toggle-slider {
    background-color: color-mix(in srgb, var(--text-color, #eee) 26%, transparent);
}

.balance-calculator-toggle-label {
    font-size: 13px;
    color: var(--text-color, #1f2937);
    flex: 1 1 auto;
    min-width: 0;
    cursor: pointer;
}

/* ----- Результат ----- */

.balance-calculator-result {
    margin-top: 14px;
    padding: 14px 14px 12px;
    border-radius: 14px;
    background: var(--card-bg, #ffffff);
    border: 1px solid color-mix(in srgb, var(--widget-accent, #14b8a6) 22%, transparent);
}

body.dark-theme .balance-calculator-result {
    background: rgba(255, 255, 255, 0.04);
}

.balance-calculator-result-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    font-size: 13px;
    color: var(--text-color, #1f2937);
    padding: 4px 0;
}

.balance-calculator-result-row + .balance-calculator-result-row {
    border-top: 1px dashed color-mix(in srgb, var(--widget-accent, #14b8a6) 18%, transparent);
}

.balance-calculator-result-row .label {
    color: var(--text-muted, #6b7280);
}

.balance-calculator-result-row .value {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.balance-calculator-result-row.is-cost .value {
    color: #ef4444;
}

.balance-calculator-result-row.is-earn .value {
    color: #10b981;
}

.balance-calculator-result-row.is-gap .value {
    color: #f59e0b;
}

.balance-calculator-result-row.is-gap.is-positive .value {
    color: #f59e0b;
}

.balance-calculator-result-row.is-gap.is-negative .value {
    color: #10b981;
}

.balance-calculator-result-row.is-gap.is-zero .value {
    color: var(--text-muted, #6b7280);
}

body.dark-theme .balance-calculator-result-row.is-cost .value {
    color: #f87171;
}
body.dark-theme .balance-calculator-result-row.is-earn .value {
    color: #34d399;
}
body.dark-theme .balance-calculator-result-row.is-gap .value {
    color: #fbbf24;
}
body.dark-theme .balance-calculator-result-row.is-gap.is-positive .value {
    color: #fbbf24;
}
body.dark-theme .balance-calculator-result-row.is-gap.is-negative .value {
    color: #34d399;
}

.balance-calculator-note {
    margin: 8px 0 0;
    font-size: 11px;
    color: var(--text-muted, #6b7280);
    line-height: 1.4;
}

.balance-calculator-buttons {
    display: flex;
    gap: 2px;
    margin-top: 16px;
    flex-wrap: wrap;
}

.balance-calculator-action {
    appearance: none;
    -webkit-appearance: none;
    flex: 1 1 auto;
    min-width: 0;
    margin: 5px 0;
    background: transparent;
    color: var(--text-color, #1f2937);
    border: 1px solid color-mix(in srgb, var(--text-color, #1f2937) 22%, transparent);
    border-radius: 12px;
    padding: 10px 14px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease,
        transform 0.12s ease;
}

.balance-calculator-action:hover,
.balance-calculator-action:focus-visible {
    background: rgba(0, 0, 0, 0.04);
    border-color: color-mix(in srgb, var(--text-color, #1f2937) 42%, transparent);
    outline: none;
    transform: translateY(-1px);
}

.balance-calculator-action--primary {
    background: linear-gradient(135deg, #14b8a6 0%, #0d9488 100%);
    color: #ffffff;
    border-color: transparent;
}

.balance-calculator-action--primary:hover,
.balance-calculator-action--primary:focus-visible {
    background: linear-gradient(135deg, #0d9488 0%, #0f766e 100%);
    border-color: transparent;
    color: #ffffff;
}

body.dark-theme .balance-calculator-action {
    border-color: color-mix(in srgb, var(--text-color, #eee) 22%, transparent);
}
body.dark-theme .balance-calculator-action:hover,
body.dark-theme .balance-calculator-action:focus-visible {
    background: rgba(255, 255, 255, 0.06);
    border-color: color-mix(in srgb, var(--text-color, #eee) 42%, transparent);
}

/* prefers-reduced-motion: убираем hover-трансформации */
@media (prefers-reduced-motion: reduce) {
    .balance-calculator-overlay,
    .balance-calculator-modal,
    .balance-calculator-modal-close,
    .balance-calculator-action {
        transition: none;
    }
    .balance-calculator-modal-close:hover,
    .balance-calculator-action:hover {
        transform: none;
    }
}

/* На очень узких экранах сжимаем отступы модалки */
@media (max-width: 360px) {
    .balance-calculator-modal {
        padding: 18px 14px 14px;
        border-radius: 16px;
    }
    /* На самых узких экранах делаем кастомный селект чуть
       компактнее — меньше горизонтальных паддингов. */
    .bc-select-trigger {
        padding: 7px 10px;
    }
}

/* ================================================================
   Pushable-стиль (3D-кнопка) для кнопок-действий в разделе
   «Настройки». Приводит кнопки-плитки (приглашения, зоны интереса,
   путеводители, приглашение в бот) к единому виду с синей
   pushable-кнопкой .balance-calculator-btn.
   Базовые правила .pushable / .pushable .front / .shadow / .edge
   определены выше в секции .pushable.
   ================================================================ */
.settings-card-actions-grid .pushable.settings-tile-pushable,
.bot-invite-actions .pushable.settings-tile-pushable {
    display: block;
    width: 100%;
    margin: 6px 0;
    box-sizing: border-box;
}

/* В блоке приглашения в бот кнопки живут в flex-строке и делят
   ширину поровну. */
.bot-invite-actions .pushable.settings-tile-pushable {
    flex: 1 1 140px;
    width: auto;
    margin: 0;
}

.settings-card-actions-grid .pushable.settings-tile-pushable .front,
.bot-invite-actions .pushable.settings-tile-pushable .front {
    padding: 12px 14px;
    font-size: 0.82rem;
    letter-spacing: 0.4px;
    text-transform: none;
    gap: 8px;
    white-space: normal;
    text-align: center;
    line-height: 1.25;
}

.settings-card-actions-grid .pushable.settings-tile-pushable .front i,
.bot-invite-actions .pushable.settings-tile-pushable .front i {
    font-size: 0.95rem;
    flex-shrink: 0;
}

/* Отключённое состояние (напр. кнопка «Новый код» во время
   перегенерации инвайта): гасим hover-анимацию и подсвечиваем
   недоступность. */
.settings-card-actions-grid .pushable.settings-tile-pushable:disabled,
.bot-invite-actions .pushable.settings-tile-pushable:disabled {
    opacity: 0.6;
    cursor: not-allowed;
    filter: none;
}

.settings-card-actions-grid .pushable.settings-tile-pushable:disabled:hover .front,
.bot-invite-actions .pushable.settings-tile-pushable:disabled:hover .front {
    transform: translateY(-4px);
}

.settings-card-actions-grid .pushable.settings-tile-pushable:disabled:hover .shadow,
.bot-invite-actions .pushable.settings-tile-pushable:disabled:hover .shadow {
    transform: translateY(2px);
}

/* ============================================================
   FEATURE (2026-07-06, feature/exploration-map-modal):
   Кнопка «Карта исследования» под виджетом
   «Исследование местности» + стили модальной карты.
   ============================================================ */

/* Контейнер кнопки — используем те же правила, что и у
   .balance-calculator-wrap, чтобы кнопка растягивалась на
   всю ширину виджета «Исследование местности». */
.widget-exploration-map-btn-wrap {
    display: block;
    width: 100%;
    margin-top: 12px;
    margin-bottom: 4px;
}

.widget-exploration-map-btn-wrap .pushable.widget-exploration-map-btn {
    width: 100%;
    box-sizing: border-box;
}

.widget-exploration-map-btn-wrap .pushable.widget-exploration-map-btn .front {
    padding: 12px 18px;
    font-size: 0.9rem;
    letter-spacing: 0.6px;
}

.widget-exploration-map-btn-wrap .balance-calculator-btn-points {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.22);
    font-size: 13px;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: 0.1px;
    white-space: nowrap;
    gap: 4px;
}

/* Модальная карта — fullscreen, без padding, без рамок.
   Карта занимает всю площадь модалки, кнопка закрытия
   плавает поверх карты в левом верхнем углу. */
.modal-content-exploration-map {
    width: 100vw;
    max-width: 100vw;
    height: 100vh;
    max-height: 100vh;
    padding: 0;
    border-radius: 0;
    background: #000;
    overflow: hidden;
}

/* Кнопка закрытия в fullscreen-модалке карты —
   поверх карты, слева сверху, на полупрозрачной подложке
   для контраста с тайлами. */
.modal-content-exploration-map .modal-close {
    top: 12px;
    left: 12px;
    right: auto;
    width: 36px;
    height: 36px;
    font-size: 18px;
    color: #1f2937;
    background: rgba(255, 255, 255, 0.92);
    border-radius: 50%;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
    z-index: 1000;
}

.modal-content-exploration-map .modal-close:hover {
    background: #ffffff;
    color: #0f172a;
}

body.dark-theme .modal-content-exploration-map .modal-close {
    color: #f1f5f9;
    background: rgba(15, 23, 42, 0.78);
}

body.dark-theme .modal-content-exploration-map .modal-close:hover {
    background: rgba(15, 23, 42, 0.95);
    color: #ffffff;
}

/* FEATURE (2026-07-06, feature/exploration-parallel-dedupe):
   Контролы модалки — выбор порога «параллельности» и кнопка
   «Применить» для перерасчёта без перезагрузки страницы.
   Расположены в один ряд под легендой, яркая подсветка чтобы
   пользователь их точно заметил (отзыв 2026-07-06: «ничего
   не менялось» оказалось в т.ч. потому что контролы терялись
   среди легенды). */
.exploration-map-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 10px 8px;
    margin: 8px 0 0 0;
    font-size: 0.9rem;
    color: var(--text-default, #1f2937);
    background: linear-gradient(135deg, rgba(59,130,246,0.10), rgba(59,130,246,0.04));
    border: 1px solid rgba(59,130,246,0.25);
    border-radius: 8px;
}
.exploration-map-control-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    user-select: none;
    font-weight: 500;
}
.exploration-map-control-select {
    padding: 6px 8px;
    border-radius: 6px;
    border: 1px solid #3b82f6;
    background: var(--bg-control, #ffffff);
    color: var(--text-default, #1f2937);
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    min-width: 140px;
}
.exploration-map-control-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px;
    border-radius: 6px;
    border: 1px solid #1d4ed8;
    background: #1d4ed8;
    color: #ffffff;
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    box-shadow: 0 1px 3px rgba(0,0,0,0.18);
}
.exploration-map-control-btn:hover {
    background: #1e40af;
    border-color: #1e40af;
}
.exploration-map-control-btn:active {
    transform: translateY(1px);
}
.exploration-map-control-btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* Контейнер карты — занимает всю площадь fullscreen-модалки
   без скруглений и бордера (карта прижата к краям). */
.exploration-map-container {
    position: relative;
    width: 100%;
    height: 100%;
    border-radius: 0;
    overflow: hidden;
    border: 0;
    background: #eef3f7;
}

.exploration-map-inner {
    position: absolute;
    inset: 0;
}

.exploration-map-loading,
.exploration-map-error {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 8px;
    z-index: 500;
    background: rgba(255, 255, 255, 0.85);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    text-align: center;
    padding: 16px;
    transition: opacity 240ms ease-out;
}

/* FEATURE (2026-07-06, fix/exploration-map-loading-stuck):
   Полностью отключаем кастомный спиннер загрузки в модалке
   карты исследования. MapLibre сам показывает состояние
   загрузки тайлов; собственный оверлей с z-index:500 и
   полупрозрачным фоном поверх карты приводил к:
     - "карта не отображается" (оверлей закрывал canvas);
     - залипанию при зависании JS (тяжёлый Overpass, парсинг);
     - блокировке кликов по карте.
   Делаем спиннер невидимым/неинтерактивным по умолчанию.
   `!important` нужен на случай, если CSS-кэш браузера отдаёт
   старую версию с display:flex. */
.exploration-map-loading {
    display: none !important;
    pointer-events: none;
    opacity: 0;
}

/* HTML-атрибут hidden="" должен реально прятать оверлей.
   Специфичность `[hidden]` (0,1,0) равна специфичности
   `.exploration-map-loading` (0,1,0), поэтому без явного правила
   ниже display: flex побеждает — оверлей виден даже при hidden="".
   Для error оставляем только этот фолбэк. */
.exploration-map-error[hidden] {
    display: none;
}

.exploration-map-error {
    color: #b91c1c;
    font-weight: 600;
    background: rgba(254, 242, 242, 0.92);
}

.exploration-map-error i {
    font-size: 1.6rem;
}

/* Мягкий warning (overpass недоступен, fallback отработал). */
.exploration-map-error--warning {
    color: #92400e;
    background: rgba(254, 249, 195, 0.92);
}

body.dark-theme .exploration-map-error--warning {
    background: rgba(120, 53, 15, 0.85);
    color: #fef3c7;
}

body.dark-theme .exploration-map-container {
    background: #0f172a;
    border-color: rgba(255, 255, 255, 0.08);
}

body.dark-theme .exploration-map-loading {
    background: rgba(15, 23, 42, 0.85);
    color: #e5e7eb;
}

body.dark-theme .exploration-map-error {
    background: rgba(60, 16, 16, 0.92);
    color: #fecaca;
}

/* FEATURE (2026-07-09, feat/exploration-map-route-preloader):
   Полупрозрачный тёмный оверлей «Подготовка карты…» для модалки
   карты исследования. Накладывается поверх #explorationMapInner
   сразу при открытии модалки и скрывается, как только маршрут
   пользователя отрисован (или пришёл пустой/ошибочный ответ).
   - z-index выше, чем у Leaflet/MapLibre (по умолчанию 400),
     но НЕ перекрывает navigation-контролы карты, т.к. pointer-events: none.
   - Высокий контраст текста на тёмном фоне — работает и в
     светлой, и в тёмной теме. */
.exploration-map-preparing {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 12px;
    z-index: 450;
    background: rgba(15, 23, 42, 0.55);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    text-align: center;
    padding: 16px;
    pointer-events: none;
    transition: opacity 240ms ease-out;
    opacity: 1;
}

/* HTML-атрибут hidden="" должен реально прятать оверлей —
   иначе display:flex выше побеждает специфичность [hidden]. */
.exploration-map-preparing[hidden] {
    display: none;
}

.exploration-map-preparing-label {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 12px 20px;
    background: rgba(15, 23, 42, 0.78);
    color: #f8fafc;
    border-radius: 10px;
    font-size: 1rem;
    font-weight: 500;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
}

.exploration-map-preparing-spinner {
    display: inline-block;
    font-size: 1.15rem;
    animation: exploration-map-preparing-spin 1.1s linear infinite;
}

/* Fallback для браузеров без поддержки CSS animations на
   иконочных шрифтах — крутим через opacity-пульсацию. */
@keyframes exploration-map-preparing-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .exploration-map-preparing-spinner {
        animation-duration: 3s;
    }
}

body.dark-theme .exploration-map-preparing {
    background: rgba(2, 6, 23, 0.6);
}
body.dark-theme .exploration-map-preparing-label {
    background: rgba(2, 6, 23, 0.82);
    color: #e2e8f0;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.55);
}

body.dark-theme .exploration-map-controls {
    color: #e2e8f0;
}
body.dark-theme .exploration-map-control-select {
    background: #1f2937;
    border-color: #475569;
    color: #e2e8f0;
}

/* Модалка карты уже fullscreen на всех ширинах —
   дополнительных переопределений не требуется. */
