﻿/* =====================================================================
   Календарь студии "ВерЮ" — единая тёмная тема (Telegram-like)
   Применяется ко всем страницам, включая календарь.
   ===================================================================== */

:root {
    /* Палитра — фон (RTSPstream: графитовый тёмный) */
    --bg-app:        #14171c;
    --bg-surface:    #1c2128;
    --bg-surface-2:  #222831;
    --bg-surface-3:  #262d36;
    --bg-card:       #1c2128;
    --bg-modal:      #1c2128;
    --bg-input:      #262d36;
    --bg-hover:      #303843;

    /* Палитра — акцент (RTSPstream: синий) */
    --accent:         #3b82f6;
    --accent-hover:   #2563eb;
    --accent-pressed: #1d4ed8;
    --accent-soft:    rgba(59,130,246,0.16);

    /* Палитра — состояния */
    --success: #10b981;
    --success-soft: rgba(16,185,129,0.16);
    --warning: #f59e0b;
    --warning-soft: rgba(245,158,11,0.16);
    --danger:  #ef4444;
    --danger-soft: rgba(239,68,68,0.16);
    --info:    #38bdf8;

    /* Текст */
    --text-primary:   #e6e8eb;
    --text-secondary: #8b95a3;
    --text-muted:     #6b7280;
    --text-disabled:  #4b5563;

    /* Бордеры — тонкие */
    --border:        #2e3742;
    --border-soft:   #262d36;
    --border-strong: #3a4452;

    /* Тени */
    --shadow-sm: 0 1px 2px rgba(0,0,0,0.3);
    --shadow-md: 0 8px 24px rgba(0,0,0,0.45);
    --shadow-lg: 0 20px 60px rgba(0,0,0,0.5);

    /* Радиусы — строгие, как в RTSPstream */
    --radius-sm: 3px;
    --radius-md: 6px;
    --radius-lg: 8px;
    --radius-xl: 12px;
    --radius-pill: 999px;

    /* Прочее */
    --transition: all 0.12s ease;
    --font-stack: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Tahoma, sans-serif;

    /* =================================================================
       ШКАЛА ОТСТУПОВ. До неё поля набивались вручную (0.2/0.3/0.4/0.55/
       0.65/0.7rem вперемешку), из-за чего одинаковые по смыслу блоки на
       разных страницах имели разные поля. Новый код берёт отступы ТОЛЬКО
       отсюда; старые значения переводятся покомпонентно.
       ================================================================= */
    --space-1: 0.25rem;   /*  4px — иконка↔текст, микрозазор  */
    --space-2: 0.5rem;    /*  8px — внутри чипа, между строк  */
    --space-3: 0.75rem;   /* 12px — паддинг компактной кнопки */
    --space-4: 1rem;      /* 16px — паддинг карточки          */
    --space-5: 1.5rem;    /* 24px — между карточками          */
    --space-6: 2rem;      /* 32px — между секциями            */
    --space-7: 3rem;      /* 48px — крупные разделители       */
    --space-8: 4rem;      /* 64px — отбивка блоков витрины    */

    /* =================================================================
       ТИПОГРАФИКА. Кегли подобраны по фактическим кластерам в этом файле,
       чтобы переход на токены не сдвигал вёрстку: 0.75/0.78/0.8/0.82 →
       --fs-xs, 0.9/0.95 → --fs-md и т.д.
       ================================================================= */
    --fs-2xs:  0.70rem;   /* бейджи, подписи-мелочь           */
    --fs-xs:   0.78rem;   /* вторичный текст, даты            */
    --fs-sm:   0.85rem;   /* лейблы форм, кнопки sm           */
    --fs-md:   0.95rem;   /* базовый текст интерфейса         */
    --fs-lg:   1.10rem;   /* заголовок карточки               */
    --fs-xl:   1.25rem;   /* заголовок секции                 */
    --fs-2xl:  1.50rem;   /* заголовок страницы               */
    --fs-3xl:  1.85rem;   /* крупные числа статистики         */
    --fs-4xl:  2.25rem;   /* герой-цифры витрины              */

    --lh-tight:   1.2;    /* числа, крупные заголовки         */
    --lh-snug:    1.35;   /* заголовки, компактные списки     */
    --lh-normal:  1.5;    /* основной текст                   */
    --lh-relaxed: 1.7;    /* длинные абзацы витрин            */

    --fw-normal:   400;
    --fw-medium:   500;
    --fw-semibold: 600;
    --fw-bold:     700;

    /* =================================================================
       БРЕЙКПОИНТЫ. CSS-переменные в @media не работают, поэтому это
       не токены, а ЗАФИКСИРОВАННАЯ ДОГОВОРЁННОСТЬ — совпадает с сеткой
       Bootstrap 5, на которой стоит вся вёрстка. Новые медиазапросы
       пишем только по этим значениям:

         вверх:  min-width: 576px / 768px / 992px / 1200px / 1400px
         вниз:   max-width: 575.98px / 767.98px / 991.98px / 1199.98px

       Дробный .98 обязателен: без него min- и max-правила перекрываются
       на целочисленной границе и оба применяются в одной точке.
       Легаси-выбросы (480px, 575px, 820px) переводятся покомпонентно.
       ================================================================= */

    /* Фоновый узор из 3D-ромбиков (изометрические кубы).
       Грани задаются полупрозрачными накладками поверх --bg-app, поэтому
       узор сам подстраивается под любую тему. На тёмных темах верхняя грань
       светлее, боковые — темнее (свет сверху). */
    --diamond-light: rgba(255,255,255,0.05);
    --diamond-dark:  rgba(0,0,0,0.30);
    /* «Чернила» плоских узоров (сетка/точки/полосы): светлые на тёмных темах. */
    --pat-ink: rgba(255,255,255,0.06);
}

/* =====================================================================
   ТЕМЫ САЙТА. По умолчанию — тёмная (:root выше). Остальные включаются
   атрибутом data-theme на <html> (ставит переключатель тем, см. base.html).
   Переопределяем только цветовые переменные — вся вёрстка уже на var(--…).
   ===================================================================== */

/* Светлая */
:root[data-theme="light"] {
    --bg-app:#f4f6f9; --bg-surface:#ffffff; --bg-surface-2:#eef1f5; --bg-surface-3:#e6eaf0;
    --bg-card:#ffffff; --bg-modal:#ffffff; --bg-input:#ffffff; --bg-hover:#e9edf3;
    --accent:#2563eb; --accent-hover:#1d4ed8; --accent-pressed:#1e40af; --accent-soft:rgba(37,99,235,0.12);
    --text-primary:#1c2128; --text-secondary:#5b6573; --text-muted:#8b95a3; --text-disabled:#b6bdc7;
    --border:#d9dee6; --border-soft:#e9edf3; --border-strong:#c2cad6;
    --shadow-sm:0 1px 2px rgba(16,24,40,0.06);
    --shadow-md:0 8px 24px rgba(16,24,40,0.10);
    --shadow-lg:0 20px 60px rgba(16,24,40,0.14);
    --diamond-light:rgba(0,0,0,0.018); --diamond-dark:rgba(0,0,0,0.06); --pat-ink:rgba(0,0,0,0.05);
}

/* Сепия (тёплая светлая) */
:root[data-theme="sepia"] {
    --bg-app:#f3ecdf; --bg-surface:#fbf6ec; --bg-surface-2:#f0e7d6; --bg-surface-3:#e9dec9;
    --bg-card:#fbf6ec; --bg-modal:#fbf6ec; --bg-input:#fffaf1; --bg-hover:#ece0cc;
    --accent:#b4690e; --accent-hover:#995a0c; --accent-pressed:#7c490a; --accent-soft:rgba(180,105,14,0.14);
    --text-primary:#3b2f1e; --text-secondary:#6b5a44; --text-muted:#917e63; --text-disabled:#b8a888;
    --border:#ddcdb2; --border-soft:#e9dec9; --border-strong:#c9b594;
    --shadow-sm:0 1px 2px rgba(60,40,10,0.08);
    --shadow-md:0 8px 24px rgba(60,40,10,0.12);
    --shadow-lg:0 20px 60px rgba(60,40,10,0.16);
    --diamond-light:rgba(60,40,10,0.022); --diamond-dark:rgba(60,40,10,0.07); --pat-ink:rgba(60,40,10,0.06);
}

/* Полночь (глубокая сине-чёрная) */
:root[data-theme="midnight"] {
    --bg-app:#0b1020; --bg-surface:#121933; --bg-surface-2:#172142; --bg-surface-3:#1d2950;
    --bg-card:#121933; --bg-modal:#121933; --bg-input:#1d2950; --bg-hover:#243161;
    --accent:#7c83ff; --accent-hover:#646cff; --accent-pressed:#4f57e6; --accent-soft:rgba(124,131,255,0.18);
    --text-primary:#e7e9f5; --text-secondary:#9aa3c7; --text-muted:#6f78a0; --text-disabled:#4a5278;
    --border:#283566; --border-soft:#1d2950; --border-strong:#36457f;
}

/* Лес (тёмная зелёная) */
:root[data-theme="forest"] {
    --bg-app:#0f1511; --bg-surface:#16201a; --bg-surface-2:#1b2820; --bg-surface-3:#203026;
    --bg-card:#16201a; --bg-modal:#16201a; --bg-input:#203026; --bg-hover:#284032;
    --accent:#22c55e; --accent-hover:#16a34a; --accent-pressed:#15803d; --accent-soft:rgba(34,197,94,0.16);
    --text-primary:#e3ece5; --text-secondary:#8aa394; --text-muted:#6b8475; --text-disabled:#4b5d52;
    --border:#26392e; --border-soft:#203026; --border-strong:#33503f;
}

/* Океан (тёмная бирюзовая) */
:root[data-theme="ocean"] {
    --bg-app:#0c1418; --bg-surface:#102027; --bg-surface-2:#142a33; --bg-surface-3:#18333e;
    --bg-card:#102027; --bg-modal:#102027; --bg-input:#18333e; --bg-hover:#1f4350;
    --accent:#06b6d4; --accent-hover:#0891b2; --accent-pressed:#0e7490; --accent-soft:rgba(6,182,212,0.16);
    --text-primary:#e0edf1; --text-secondary:#86a3ad; --text-muted:#688089; --text-disabled:#48595f;
    --border:#1d3640; --border-soft:#18333e; --border-strong:#2a4d59;
}

/* Слива (тёмная фиолетовая) */
:root[data-theme="plum"] {
    --bg-app:#140f1c; --bg-surface:#1d1629; --bg-surface-2:#251c33; --bg-surface-3:#2d233e;
    --bg-card:#1d1629; --bg-modal:#1d1629; --bg-input:#2d233e; --bg-hover:#392d4f;
    --accent:#a855f7; --accent-hover:#9333ea; --accent-pressed:#7e22ce; --accent-soft:rgba(168,85,247,0.16);
    --text-primary:#ece6f5; --text-secondary:#a294b8; --text-muted:#80748f; --text-disabled:#594f66;
    --border:#352a47; --border-soft:#2d233e; --border-strong:#473a5e;
}

/* Кофе (тёмная тёплая коричневая) */
:root[data-theme="coffee"] {
    --bg-app:#17120e; --bg-surface:#211a14; --bg-surface-2:#2a2019; --bg-surface-3:#33271e;
    --bg-card:#211a14; --bg-modal:#211a14; --bg-input:#33271e; --bg-hover:#3f3025;
    --accent:#d97706; --accent-hover:#b45309; --accent-pressed:#92400e; --accent-soft:rgba(217,119,6,0.16);
    --text-primary:#efe7dd; --text-secondary:#b0a08e; --text-muted:#8a7866; --text-disabled:#5f5446;
    --border:#352a1f; --border-soft:#33271e; --border-strong:#4a3a2b;
}

/* ВерЮ (фирменная: тёмный уголь + янтарь неоновой вывески студии).
   Палитра снята с фоновых фото студии (static/img/bg/veru-*): базовый уголь
   #1b191a…#2c2827, тёплое дерево #3d312a, свечение вывески — янтарь.
   Контраст к --bg-surface: text-primary 14.7, text-secondary 8.0,
   text-muted 4.9, accent 7.7 — с запасом выше порога AA (4.5). */
:root[data-theme="veru"] {
    --bg-app:#141110; --bg-surface:#1e1a17; --bg-surface-2:#272220; --bg-surface-3:#302a26;
    --bg-card:#1e1a17; --bg-modal:#1e1a17; --bg-input:#2a2421; --bg-hover:#36302b;
    --accent:#e0a058; --accent-hover:#c9863d; --accent-pressed:#a96c2c; --accent-soft:rgba(224,160,88,0.16);
    --text-primary:#f2ece4; --text-secondary:#bcae9c; --text-muted:#9d9080; --text-disabled:#6b6157;
    --border:#332c27; --border-soft:#2a2421; --border-strong:#4a4038;
    --shadow-sm:0 1px 2px rgba(0,0,0,0.4);
    --shadow-md:0 8px 24px rgba(0,0,0,0.55);
    --shadow-lg:0 20px 60px rgba(0,0,0,0.6);
    --diamond-light:rgba(224,160,88,0.05); --diamond-dark:rgba(0,0,0,0.42); --pat-ink:rgba(224,160,88,0.07);
}

/* Роза (светлая розовая) */
:root[data-theme="rose"] {
    --bg-app:#fdf2f5; --bg-surface:#ffffff; --bg-surface-2:#fbe9ee; --bg-surface-3:#f7dde4;
    --bg-card:#ffffff; --bg-modal:#ffffff; --bg-input:#ffffff; --bg-hover:#fbe4ea;
    --accent:#e11d72; --accent-hover:#be185d; --accent-pressed:#9d174d; --accent-soft:rgba(225,29,114,0.12);
    --text-primary:#3b1f2b; --text-secondary:#7a5663; --text-muted:#a07f8b; --text-disabled:#c9aeb7;
    --border:#f0d4dd; --border-soft:#f7dde4; --border-strong:#e6bcc8;
    --shadow-sm:0 1px 2px rgba(80,20,40,0.06);
    --shadow-md:0 8px 24px rgba(80,20,40,0.10);
    --shadow-lg:0 20px 60px rgba(80,20,40,0.14);
    --diamond-light:rgba(80,20,40,0.02); --diamond-dark:rgba(80,20,40,0.06); --pat-ink:rgba(80,20,40,0.05);
}

/* Мята (светлая зелёная) */
:root[data-theme="mint"] {
    --bg-app:#f0faf4; --bg-surface:#ffffff; --bg-surface-2:#e6f6ec; --bg-surface-3:#dbf1e3;
    --bg-card:#ffffff; --bg-modal:#ffffff; --bg-input:#ffffff; --bg-hover:#e3f5ea;
    --accent:#059669; --accent-hover:#047857; --accent-pressed:#065f46; --accent-soft:rgba(5,150,105,0.12);
    --text-primary:#13291f; --text-secondary:#4f6b5c; --text-muted:#7d9587; --text-disabled:#aec5b7;
    --border:#cfe9d8; --border-soft:#dbf1e3; --border-strong:#b6dcc3;
    --shadow-sm:0 1px 2px rgba(10,50,30,0.06);
    --shadow-md:0 8px 24px rgba(10,50,30,0.10);
    --shadow-lg:0 20px 60px rgba(10,50,30,0.14);
    --diamond-light:rgba(10,50,30,0.02); --diamond-dark:rgba(10,50,30,0.06); --pat-ink:rgba(10,50,30,0.05);
}

/* Контраст (максимальная контрастность) */
:root[data-theme="contrast"] {
    --bg-app:#000000; --bg-surface:#0a0a0a; --bg-surface-2:#141414; --bg-surface-3:#1c1c1c;
    --bg-card:#0a0a0a; --bg-modal:#0a0a0a; --bg-input:#141414; --bg-hover:#262626;
    --accent:#ffd400; --accent-hover:#facc15; --accent-pressed:#eab308; --accent-soft:rgba(255,212,0,0.18);
    --text-primary:#ffffff; --text-secondary:#d4d4d4; --text-muted:#a3a3a3; --text-disabled:#737373;
    --border:#3f3f3f; --border-soft:#262626; --border-strong:#525252;
}

/* Матрица (чёрно-зелёная, «цифровой дождь») — лучше всего вместе с фоном
   «Матрица» (data-bg="matrix"). */
:root[data-theme="matrix"] {
    --bg-app:#000800; --bg-surface:#04140a; --bg-surface-2:#08200f; --bg-surface-3:#0c2a14;
    --bg-card:#04140a; --bg-modal:#04140a; --bg-input:#0c2a14; --bg-hover:#103418;
    --accent:#00ff66; --accent-hover:#00e65c; --accent-pressed:#00cc52; --accent-soft:rgba(0,255,102,0.18);
    --success:#22c55e; --success-soft:rgba(34,197,94,0.18);
    --warning:#aaff00; --warning-soft:rgba(170,255,0,0.18);
    --danger:#ff5555; --danger-soft:rgba(255,85,85,0.18); --info:#39ff14;
    --text-primary:#c6ffce; --text-secondary:#5fb874; --text-muted:#3f8a52; --text-disabled:#2a5c38;
    --border:#0f3a1d; --border-soft:#0c2a14; --border-strong:#176b30;
    --shadow-sm:0 1px 2px rgba(0,0,0,0.5);
    --shadow-md:0 8px 24px rgba(0,40,10,0.55);
    --shadow-lg:0 20px 60px rgba(0,50,15,0.6);
    --diamond-light:rgba(0,255,102,0.05); --diamond-dark:rgba(0,0,0,0.45); --pat-ink:rgba(0,255,102,0.07);
}

/* Музыкальный (сине-голубая) — лучше всего вместе с фоном «Музыкальный»
   (data-bg="music", падающие нотки). */
:root[data-theme="music"] {
    --bg-app:#06121f; --bg-surface:#0c1f33; --bg-surface-2:#11283f; --bg-surface-3:#16314c;
    --bg-card:#0c1f33; --bg-modal:#0c1f33; --bg-input:#16314c; --bg-hover:#1d3c5c;
    --accent:#38bdf8; --accent-hover:#0ea5e9; --accent-pressed:#0284c7; --accent-soft:rgba(56,189,248,0.18);
    --success:#22c55e; --warning:#f59e0b; --danger:#ef4444; --info:#22d3ee;
    --text-primary:#dbeafe; --text-secondary:#8fb3d4; --text-muted:#5f86a8; --text-disabled:#3f5d78;
    --border:#1b3a57; --border-soft:#16314c; --border-strong:#27557d;
    --shadow-sm:0 1px 2px rgba(0,0,0,0.4);
    --shadow-md:0 8px 24px rgba(2,30,60,0.5);
    --shadow-lg:0 20px 60px rgba(3,40,80,0.55);
    --diamond-light:rgba(125,211,252,0.06); --diamond-dark:rgba(0,0,0,0.32); --pat-ink:rgba(125,211,252,0.08);
}

/* Осень (тёплая тёмная) — к фону «Осень» (падающие листья). */
:root[data-theme="autumn"] {
    --bg-app:#1a0f08; --bg-surface:#26160c; --bg-surface-2:#311c10; --bg-surface-3:#3d2415;
    --bg-card:#26160c; --bg-modal:#26160c; --bg-input:#3d2415; --bg-hover:#4a2c19;
    --accent:#e8772e; --accent-hover:#d2691e; --accent-pressed:#b5571a; --accent-soft:rgba(232,119,46,0.18);
    --success:#9caf3a; --warning:#e0a32e; --danger:#d9544d; --info:#cf8a4b;
    --text-primary:#f6e7d6; --text-secondary:#c4a585; --text-muted:#9a7d5f; --text-disabled:#6b5740;
    --border:#3a2415; --border-soft:#311c10; --border-strong:#52341f;
    --diamond-light:rgba(232,119,46,0.06); --diamond-dark:rgba(0,0,0,0.34); --pat-ink:rgba(232,119,46,0.08);
}

/* Зима (ледяная тёмно-синяя ночь) — к фону «Зима» (снежинки). */
:root[data-theme="winter"] {
    --bg-app:#0c1822; --bg-surface:#122430; --bg-surface-2:#173040; --bg-surface-3:#1d3b4f;
    --bg-card:#122430; --bg-modal:#122430; --bg-input:#1d3b4f; --bg-hover:#244a63;
    --accent:#38bdf8; --accent-hover:#0ea5e9; --accent-pressed:#0284c7; --accent-soft:rgba(56,189,248,0.18);
    --success:#34d399; --warning:#fbbf24; --danger:#f87171; --info:#7dd3fc;
    --text-primary:#e6f3fb; --text-secondary:#9fc0d4; --text-muted:#6f93a8; --text-disabled:#4a6577;
    --border:#1f3c50; --border-soft:#1d3b4f; --border-strong:#2c5570;
    --diamond-light:rgba(255,255,255,0.06); --diamond-dark:rgba(0,0,0,0.32); --pat-ink:rgba(255,255,255,0.07);
}

/* Новый год (эпичная: тёмно-синяя ночь + красный/золотой, декор сверху). */
:root[data-theme="newyear"] {
    --bg-app:#0a1020; --bg-surface:#101936; --bg-surface-2:#16224a; --bg-surface-3:#1c2c5c;
    --bg-card:#101936; --bg-modal:#101936; --bg-input:#1c2c5c; --bg-hover:#243670;
    --accent:#e63946; --accent-hover:#d62836; --accent-pressed:#b51f2c; --accent-soft:rgba(230,57,70,0.20);
    --success:#2ec27e; --success-soft:rgba(46,194,126,0.18);
    --warning:#ffd166; --warning-soft:rgba(255,209,102,0.18);
    --danger:#ef4444; --danger-soft:rgba(239,68,68,0.18); --info:#48cae4;
    --text-primary:#f5f2e8; --text-secondary:#aab6d8; --text-muted:#7886ad; --text-disabled:#515f86;
    --border:#27336a; --border-soft:#1c2c5c; --border-strong:#3a4a8f;
    --shadow-md:0 8px 24px rgba(0,0,10,0.55); --shadow-lg:0 20px 60px rgba(0,0,15,0.6);
    --diamond-light:rgba(255,209,102,0.06); --diamond-dark:rgba(0,0,0,0.4); --pat-ink:rgba(255,209,102,0.08);
}

/* =====================================================================
   ЕДИНАЯ ПРОЗРАЧНОСТЬ ПОВЕРХНОСТЕЙ

   Раньше прозрачность была вразнобой: шапка витрины полупрозрачная только
   на широких экранах, карточки сплошные, модалки сплошные. С фото-фоном это
   стало заметно — где-то картинка просвечивает, где-то нет.

   Здесь одна ручка на всё: --surface-alpha (доля непрозрачности). Крутится
   ползунком в переключателе тем и уходит в трансляцию «всем».

   Как это работает без правки полусотни компонентов: на :root считаем
   полупрозрачные копии токенов под ОТДЕЛЬНЫМИ именами (--t-*), а на body
   подменяем ими исходные имена. Разные элементы и разные имена — цикла в
   custom properties не возникает, а всё содержимое страницы наследует уже
   прозрачные значения. Компоненты не трогаем вообще.

   --bg-app намеренно НЕ трогаем: это подложка страницы, под ней ничего нет.

   Границы диапазона не произвольны. При 30% прозрачности худший контраст
   текста к поверхности поверх фото: светлая 8.03, сепия 6.06, роза 7.04,
   мята 7.31, «ВерЮ» 11.50 при пороге AA 4.50. На 40% сепия проваливается до
   3.22 — поэтому ползунок ограничен 35%.
   ===================================================================== */
:root {
    --surface-alpha: 0.70;

    --t-surface:   color-mix(in srgb, var(--bg-surface)   calc(var(--surface-alpha) * 100%), transparent);
    --t-surface-2: color-mix(in srgb, var(--bg-surface-2) calc(var(--surface-alpha) * 100%), transparent);
    --t-surface-3: color-mix(in srgb, var(--bg-surface-3) calc(var(--surface-alpha) * 100%), transparent);
    --t-card:      color-mix(in srgb, var(--bg-card)      calc(var(--surface-alpha) * 100%), transparent);
    --t-modal:     color-mix(in srgb, var(--bg-modal)     calc(var(--surface-alpha) * 100%), transparent);
    --t-input:     color-mix(in srgb, var(--bg-input)     calc(var(--surface-alpha) * 100%), transparent);
    --t-hover:     color-mix(in srgb, var(--bg-hover)     calc(var(--surface-alpha) * 100%), transparent);
}

body {
    --bg-surface:   var(--t-surface);
    --bg-surface-2: var(--t-surface-2);
    --bg-surface-3: var(--t-surface-3);
    --bg-card:      var(--t-card);
    --bg-modal:     var(--t-modal);
    --bg-input:     var(--t-input);
    --bg-hover:     var(--t-hover);
}

/* =====================================================================
   Глобальные сбросы и базовые стили
   ===================================================================== */
html {
    background: var(--bg-app) !important;
}
html, body {
    color: var(--text-primary) !important;
    font-family: var(--font-stack);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    min-height: 100vh;
}
/* Body — прозрачный, иначе его сплошная заливка перекрыла бы узор-слой
   ::before (z-index:-1 рисуется ПОД фоном body). Сплошной фон остаётся на
   html и на самом слое ::before. */
body {
    background: transparent !important;
}

/* =====================================================================
   Фоновый узор из статичных 3D-ромбиков (изометрические кубы).
   Лежит отдельным фиксированным слоем ПОЗАДИ всего контента (z-index:-1),
   не двигается при скролле (position: fixed) и виден в промежутках между
   карточками — те отбрасывают тень, создавая ощущение глубины.
   Узор — только CSS-градиенты: ни картинок, ни JS, ни анимаций.
   ===================================================================== */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-color: var(--bg-app);
    background-image:
        linear-gradient(30deg,  var(--diamond-dark)  12%, transparent 12.5%, transparent 87%, var(--diamond-dark)  87.5%, var(--diamond-dark)),
        linear-gradient(150deg, var(--diamond-dark)  12%, transparent 12.5%, transparent 87%, var(--diamond-dark)  87.5%, var(--diamond-dark)),
        linear-gradient(30deg,  var(--diamond-dark)  12%, transparent 12.5%, transparent 87%, var(--diamond-dark)  87.5%, var(--diamond-dark)),
        linear-gradient(150deg, var(--diamond-dark)  12%, transparent 12.5%, transparent 87%, var(--diamond-dark)  87.5%, var(--diamond-dark)),
        linear-gradient(60deg,  var(--diamond-light) 25%, transparent 25.5%, transparent 75%, var(--diamond-light) 75%, var(--diamond-light)),
        linear-gradient(60deg,  var(--diamond-light) 25%, transparent 25.5%, transparent 75%, var(--diamond-light) 75%, var(--diamond-light));
    background-size: 72px 126px;
    background-position: 0 0, 0 0, 36px 63px, 36px 63px, 0 0, 36px 63px;
}

/* =====================================================================
   Варианты фонового узора. Выбираются в переключателе тем — он ставит
   атрибут data-bg на <html>. Все перекрывают слой body::before и
   адаптивны к теме через var(--pat-ink) / var(--accent-soft).
   Без атрибута data-bg действует фон по умолчанию — «Ромбики 3D» (выше).
   ===================================================================== */
html[data-bg="none"] body::before { background-image: none; }

/* Матрица — узор-слой пустой, поверх рисует <canvas> #matrix-rain
   (создаётся переключателем тем только когда выбран этот фон). */
html[data-bg="matrix"] body::before { background-image: none; }

/* Музыкальный — узор-слой пустой, поверх рисует <canvas> #music-notes
   (падающие нотки со столкновениями; создаётся только при выборе фона). */
html[data-bg="music"] body::before { background-image: none; }

/* Осень / Зима / Новый год — поверх рисует <canvas> #fall-bg (падающие
   листья / снежинки / снежинки+игрушки; создаётся только при выборе). */
html[data-bg="autumn"] body::before,
html[data-bg="winter"] body::before,
html[data-bg="newyear"] body::before { background-image: none; }

/* Плоская ромбовидная сетка (диагональная клетка) */
html[data-bg="rhombus"] body::before {
    background-image:
        repeating-linear-gradient(45deg,  var(--pat-ink) 0 1px, transparent 1px 24px),
        repeating-linear-gradient(-45deg, var(--pat-ink) 0 1px, transparent 1px 24px);
    background-size: auto;
    background-position: 0 0;
}

/* Сетка («миллиметровка») */
html[data-bg="grid"] body::before {
    background-image:
        linear-gradient(to right,  var(--pat-ink) 1px, transparent 1px),
        linear-gradient(to bottom, var(--pat-ink) 1px, transparent 1px);
    background-size: 40px 40px;
    background-position: 0 0;
}

/* Точки */
html[data-bg="dots"] body::before {
    background-image: radial-gradient(var(--pat-ink) 1.6px, transparent 1.8px);
    background-size: 24px 24px;
    background-position: 0 0;
}

/* Диагональные полосы */
html[data-bg="lines"] body::before {
    background-image: repeating-linear-gradient(45deg,
        var(--pat-ink) 0 1px, transparent 1px 12px);
    background-size: auto;
    background-position: 0 0;
}

/* Мягкое свечение акцентом сверху */
html[data-bg="glow"] body::before {
    background-image: radial-gradient(120% 80% at 50% -10%,
        var(--accent-soft) 0%, transparent 60%);
    background-size: 100% 100%;
    background-position: center;
    background-repeat: no-repeat;
}

/* =====================================================================
   ФОТО-ФОНЫ: встроенный «ВерЮ» и загруженный админом «свой».

   Картинка лежит в том же слое body::before (position:fixed), поэтому она
   не едет при скролле БЕЗ `background-attachment: fixed` — на iOS тот
   баговал и подтормаживал.

   Поверх картинки — затемняющий слой (скрим). Он не украшение: замеры по
   исходникам показали, что без него на 3.15% площади десктопной картинки
   (светящаяся вывеска) контраст к --text-primary падает до 1.77, то есть
   текст там нечитаем. При скриме 50% худший контраст по всей площади —
   5.94 (десктоп) и 8.40 (мобильная), проблемных пикселей не остаётся.

   Ориентация, а не ширина: планшет в портрете должен получить вертикальную
   картинку, иначе от неё видна только узкая центральная полоса.
   ===================================================================== */
html[data-bg="veru"] body::before,
html[data-bg="custom"] body::before {
    background-color: var(--bg-app);
    background-position: center center;
    background-repeat: no-repeat;
    background-size: cover;
}

html[data-bg="veru"] body::before {
    background-image:
        linear-gradient(rgba(10,8,7,0.5), rgba(10,8,7,0.5)),
        url("../img/bg/veru-landscape.webp?v=2");
}
@media (orientation: portrait) {
    html[data-bg="veru"] body::before {
        background-image:
            linear-gradient(rgba(10,8,7,0.5), rgba(10,8,7,0.5)),
            url("../img/bg/veru-portrait.webp?v=2");
    }
}

/* Свой фон: ссылки на картинки подставляет сервер в --custom-bg-*
   (см. _theme_boot.html). Пока не загружены — переменной нет, и слой
   молча остаётся однотонным, без «битой картинки». */
html[data-bg="custom"] body::before {
    background-image:
        linear-gradient(rgba(10,8,7,0.5), rgba(10,8,7,0.5)),
        var(--custom-bg-landscape, none);
}
@media (orientation: portrait) {
    html[data-bg="custom"] body::before {
        background-image:
            linear-gradient(rgba(10,8,7,0.5), rgba(10,8,7,0.5)),
            var(--custom-bg-portrait, var(--custom-bg-landscape, none));
    }
}

/* =====================================================================
   Плавный переход между страницами. Без этого при полной перезагрузке
   (переключение вкладок) на тёмной теме мелькал чёрный пустой кадр.
   View Transitions (Chromium): браузер показывает снимок старой страницы
   и кроссфейдит в новую — чёрного кадра нет. Firefox/Safari игнорируют.
   ===================================================================== */
@view-transition { navigation: auto; }
::view-transition-old(root),
::view-transition-new(root) { animation-duration: 0.18s; }
@media (prefers-reduced-motion: reduce) {
    ::view-transition-old(root),
    ::view-transition-new(root) { animation-duration: 0.001ms; }
}

* {
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
}

*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: var(--radius-pill);
}
*::-webkit-scrollbar-thumb:hover { background: #4a5b73; }

a { color: var(--accent); text-decoration: none; transition: var(--transition); }
a:hover { color: var(--accent-hover); }

hr, .dropdown-divider {
    border-color: var(--border) !important;
    opacity: 1;
}

::selection { background: var(--accent-soft); color: var(--text-primary); }

.text-muted { color: var(--text-muted) !important; }
.text-secondary { color: var(--text-secondary) !important; }
.bg-light { background: var(--bg-surface-2) !important; color: var(--text-primary) !important; }
.bg-white { background: var(--bg-surface) !important; }
.opacity-75 { opacity: 0.75; }

/* =====================================================================
   Навигация
   ===================================================================== */
.navbar {
    background: var(--bg-surface) !important;
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
    padding: 0.5rem 1rem;
    /* Шапка прилипает к верху и не двигается при прокрутке. */
    position: sticky;
    top: 0;
    z-index: 1030;
}

.navbar-brand {
    color: var(--text-primary) !important;
    font-weight: 600;
    font-size: 1.1rem;
    display: flex;
    align-items: center;
    gap: 8px;
}
.navbar-brand i { color: var(--accent); }

.navbar .nav-link {
    color: var(--text-secondary) !important;
    font-weight: 500;
    padding: 0.5rem 0.85rem !important;
    border-radius: var(--radius-md);
    transition: var(--transition);
    display: flex;
    align-items: center;
    gap: 6px;
}
.navbar .nav-link:hover {
    color: var(--text-primary) !important;
    background: var(--bg-hover);
}
/* Активный раздел. Подсветку считает utils/navigation.py по request.path —
   до этого все пункты выглядели одинаково, и по меню нельзя было понять,
   где ты сейчас. Раздел остаётся подсвеченным, пока ты внутри любой из его
   вкладок: «Управление» горит и на /admin/users, и на /admin/logs. */
.navbar .nav-link.active {
    color: var(--text-primary) !important;
    background: var(--accent-soft);
    font-weight: 600;
}
.navbar .nav-link.active i { color: var(--accent); }

/* Раскрытое меню на телефоне — со своей прокруткой.
   Шапка прилипшая (position: sticky выше), и раскрытый список рос внутри неё
   без ограничения высоты: у кого много пунктов, нижняя часть (в том числе
   «Выйти» в меню пользователя) оказывалась за нижним краем экрана. Дотянуться
   было нельзя — палец листал страницу ПОД меню, а само меню стояло на месте.

   overscroll-behavior: contain — ключевая строка: она не даёт прокрутке
   «перетечь» на страницу, когда список долистан до конца.
   dvh учитывает адресную строку мобильных браузеров; строкой выше vh как
   запасной вариант для тех, кто dvh не понимает. */
@media (max-width: 991.98px) {
    .navbar-collapse {
        max-height: calc(100vh - 60px);
        max-height: calc(100dvh - 60px);
        overflow-y: auto;
        overscroll-behavior: contain;
    }
    /* Выпадающие разделы внутри раскрытого меню идут в потоке (Bootstrap так
       делает ниже lg), поэтому отдельная прокрутка им не нужна — но убираем
       рамку и тень, чтобы вложенный список не выглядел «окном в окне». */
    .navbar-collapse .dropdown-menu {
        border: 0;
        box-shadow: none;
        background: transparent;
        padding-left: 0.75rem;
    }
}

.navbar-toggler {
    border-color: var(--border) !important;
    color: var(--text-primary);
}
.navbar-toggler:focus { box-shadow: none; }
.navbar-toggler-icon {
    filter: invert(1) brightness(0.85);
}

/* =====================================================================
   ПОДШИВКА ВКЛАДОК (.nav-tabs-bar) — второй уровень навигации под шапкой.

   Верхняя строка держит только разделы, вкладки раздела уехали сюда. До
   этого второй уровень существовал лишь у модуля репетиций (rh-subnav), а
   у остальных разделов его не было вовсе: все пункты лежали в одну строку
   и в выпадающих списках.

   Намеренно НЕ sticky: шапка уже прилипшая, а привязка второй полосы к её
   высоте требовала бы магического числа, которое разъезжается при переносе
   шапки на две строки.
   ===================================================================== */
.nav-tabs-bar {
    background: var(--bg-surface-2);
    border-bottom: 1px solid var(--border);
}
.nav-tabs-bar__inner {
    display: flex;
    gap: var(--space-1);
    align-items: stretch;
    /* Вкладок может быть семь: на узком экране полоса листается вбок сама,
       не утаскивая за собой страницу. */
    overflow-x: auto;
    scrollbar-width: none;
}
.nav-tabs-bar__inner::-webkit-scrollbar { display: none; }

.nav-tab {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    color: var(--text-secondary);
    text-decoration: none;
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    white-space: nowrap;
    border-bottom: 2px solid transparent;
    transition: var(--transition);
}
.nav-tab:hover { color: var(--text-primary); background: var(--bg-hover); }
.nav-tab i { opacity: 0.85; }
.nav-tab.active {
    color: var(--text-primary);
    font-weight: var(--fw-semibold);
    border-bottom-color: var(--accent);
    background: var(--accent-soft);
}
.nav-tab.active i { color: var(--accent); opacity: 1; }

/* Начало смысловой группы внутри подшивки (например витрина после
   администрирования): вкладок бывает десяток, и без черты они читаются
   сплошной строкой. */
.nav-tab--group {
    border-left: 1px solid var(--border);
    margin-left: var(--space-2);
    padding-left: var(--space-4);
}

@media (max-width: 767.98px) {
    .nav-tab { padding: var(--space-2) var(--space-3); font-size: var(--fs-xs); }
    .nav-tab--group { margin-left: var(--space-1); padding-left: var(--space-3); }
}

/* =====================================================================
   СВОРАЧИВАЕМЫЕ СПИСКИ (static/js/collapsible.js)

   Списки в кабинетах (абонементы) разрастались портянкой: на виду держим
   первые несколько, остальное — по клику на плашку-заголовок или на кнопку
   под списком.
   ===================================================================== */
.collapsible-head {
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    -webkit-user-select: none;
    user-select: none;
}
.collapsible-head__arrow {
    margin-left: auto;
    opacity: 0.85;
    transition: var(--transition);
}
.collapsible-head:hover .collapsible-head__arrow { opacity: 1; }
.collapsible-head:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.collapsible-more {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    width: 100%;
    margin-top: var(--space-2);
    padding: var(--space-2) var(--space-3);
    background: var(--bg-surface-2);
    color: var(--text-secondary);
    border: 1px dashed var(--border);
    border-radius: var(--radius-md);
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    cursor: pointer;
    transition: var(--transition);
}
.collapsible-more:hover {
    color: var(--text-primary);
    background: var(--bg-hover);
    border-style: solid;
}

/* =====================================================================
   Карточки
   ===================================================================== */
/* Карточка — через переменные Bootstrap (см. пояснение у кнопок ниже):
   --bs-card-cap-* задаёт разом и шапку, и подвал, поэтому отдельные правила
   для .card-header/.card-footer больше не воюют с бутстрапом через !important. */
.card {
    --bs-card-bg: var(--bg-surface);
    --bs-card-color: var(--text-primary);
    --bs-card-border-color: var(--border);
    --bs-card-border-radius: var(--radius-lg);
    --bs-card-inner-border-radius: var(--radius-lg);
    --bs-card-cap-bg: var(--bg-surface-2);
    --bs-card-cap-color: var(--text-primary);
    box-shadow: var(--shadow-sm);
    transition: var(--transition);
}
.card:hover { box-shadow: var(--shadow-md); }

.card-header {
    padding: 0.85rem 1.1rem;
    font-weight: 600;
}
/* Здесь !important ОБОСНОВАН и убирать его нельзя: .bg-* — это утилиты
   Bootstrap, а они объявлены с !important в самом фреймворке. Перебить их
   можно только тем же оружием. Смысл правила: цветные шапки карточек
   (синяя/красная/зелёная) в тёмной теме выглядели кислотно — гасим их до
   нейтральной поверхности. */
.card-header.bg-primary,
.card-header.bg-info,
.card-header.bg-success,
.card-header.bg-warning,
.card-header.bg-danger {
    background: var(--bg-surface-3) !important;
    color: var(--text-primary) !important;
}

.card-body { padding: 1.1rem; }

/* =====================================================================
   Кнопки
   ===================================================================== */
.btn {
    border-radius: var(--radius-md);
    font-weight: 500;
    padding: 0.5rem 1rem;
    transition: var(--transition);
    border: 1px solid transparent;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    line-height: 1.4;
}
.btn:focus, .btn:focus-visible {
    box-shadow: 0 0 0 3px var(--accent-soft) !important;
    outline: none;
}

/* Кнопки задаются через СОБСТВЕННЫЕ переменные Bootstrap 5.3 (--bs-btn-*),
   а не перебиванием background/color с !important.
   Почему так правильнее: Bootstrap рисует .btn через var(--bs-btn-bg) и т.д.,
   поэтому переопределение переменной подхватывается всеми его состояниями
   разом — hover, :active, .active, :disabled, .btn-check и фокусное кольцо.
   Прежний вариант перебивал только background/border/color, из-за чего
   disabled-кнопка оставалась «яркой», а фокусное кольцо — синим бутстраповским
   в любой теме. И всё это требовало !important на каждой строке.

   Двойная строка hover-bg — фолбэк: браузеры без color-mix (Chrome < 111)
   отбросят вторую и получат ровный цвет вместо затемнённого. */
.btn-primary {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--accent);
    --bs-btn-border-color: var(--accent);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--accent-hover);
    --bs-btn-hover-border-color: var(--accent-hover);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--accent-pressed);
    --bs-btn-active-border-color: var(--accent-pressed);
    --bs-btn-disabled-color: #fff;
    --bs-btn-disabled-bg: var(--accent);
    --bs-btn-disabled-border-color: var(--accent);
}

.btn-outline-primary {
    --bs-btn-color: var(--accent);
    --bs-btn-border-color: var(--accent);
    --bs-btn-bg: transparent;
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--accent);
    --bs-btn-hover-border-color: var(--accent);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--accent-pressed);
    --bs-btn-active-border-color: var(--accent-pressed);
    --bs-btn-disabled-color: var(--text-disabled);
    --bs-btn-disabled-border-color: var(--border);
}

/* ── Единая палитра кнопок ─────────────────────────────────────────────────
   Раньше на странице стоял ряд кнопок разных цветов: жёлтая, оранжевая,
   бирюзовая, зелёная — причём у большинства цвет ничего не значил («Справка»
   светлая, «Приложения» бирюзовая, «Кто на сайте» зелёная просто чтобы
   отличались). Получалась пестрота, выпадающая из стиля сайта.

   Теперь ровно три роли:
     1. СПЛОШНАЯ АКЦЕНТНАЯ — .btn-primary. Главное действие, одно на экран.
     2. НЕЙТРАЛЬНАЯ — всё, что цветом ничего не сообщает.
     3. МЯГКАЯ СЕМАНТИЧЕСКАЯ — .btn-success/-warning/-danger/-info: заливка
        тем же цветом, но 16%-й прозрачности, текст цветной. Смысл читается,
        крика нет; насыщается до полного цвета при наведении.
        Приём в проекте уже был — так сделан «Удалить» в подвале модалок.
   ────────────────────────────────────────────────────────────────────────── */

/* Роль 2: нейтральные. Сюда же — цветные outline-варианты, у которых цвет
   был декоративным (info/warning/success/light/dark). */
.btn-secondary,
.btn-light {
    --bs-btn-color: var(--text-primary);
    --bs-btn-bg: var(--bg-surface-3);
    --bs-btn-border-color: var(--border-strong);
    --bs-btn-hover-color: var(--text-primary);
    --bs-btn-hover-bg: var(--bg-hover);
    --bs-btn-hover-border-color: var(--border-strong);
    --bs-btn-active-color: var(--text-primary);
    --bs-btn-active-bg: var(--bg-hover);
    --bs-btn-active-border-color: var(--border-strong);
    --bs-btn-disabled-color: var(--text-disabled);
    --bs-btn-disabled-bg: var(--bg-surface-2);
    --bs-btn-disabled-border-color: var(--border);
}

.btn-outline-secondary,
.btn-outline-light,
.btn-outline-dark,
.btn-outline-info,
.btn-outline-warning,
.btn-outline-success {
    --bs-btn-color: var(--text-secondary);
    --bs-btn-bg: transparent;
    --bs-btn-border-color: var(--border-strong);
    --bs-btn-hover-color: var(--text-primary);
    --bs-btn-hover-bg: var(--bg-hover);
    --bs-btn-hover-border-color: var(--border-strong);
    --bs-btn-active-color: var(--text-primary);
    --bs-btn-active-bg: var(--bg-hover);
    --bs-btn-active-border-color: var(--border-strong);
    --bs-btn-disabled-color: var(--text-disabled);
    --bs-btn-disabled-border-color: var(--border);
}

/* Роль 3: мягкие семантические. */
.btn-success {
    --bs-btn-color: var(--success);
    --bs-btn-bg: var(--success-soft);
    --bs-btn-border-color: transparent;
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--success);
    --bs-btn-hover-border-color: var(--success);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--success);
    --bs-btn-active-border-color: var(--success);
    --bs-btn-disabled-color: var(--text-disabled);
    --bs-btn-disabled-bg: var(--bg-surface-2);
    --bs-btn-disabled-border-color: transparent;
}

.btn-danger {
    --bs-btn-color: var(--danger);
    --bs-btn-bg: var(--danger-soft);
    --bs-btn-border-color: transparent;
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--danger);
    --bs-btn-hover-border-color: var(--danger);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--danger);
    --bs-btn-active-border-color: var(--danger);
    --bs-btn-disabled-color: var(--text-disabled);
    --bs-btn-disabled-bg: var(--bg-surface-2);
    --bs-btn-disabled-border-color: transparent;
}

.btn-warning {
    --bs-btn-color: var(--warning);
    --bs-btn-bg: var(--warning-soft);
    --bs-btn-border-color: transparent;
    --bs-btn-hover-color: #1c1c1c;
    --bs-btn-hover-bg: var(--warning);
    --bs-btn-hover-border-color: var(--warning);
    --bs-btn-active-color: #1c1c1c;
    --bs-btn-active-bg: var(--warning);
    --bs-btn-active-border-color: var(--warning);
    --bs-btn-disabled-color: var(--text-disabled);
    --bs-btn-disabled-bg: var(--bg-surface-2);
    --bs-btn-disabled-border-color: transparent;
}

.btn-info {
    --bs-btn-color: var(--info);
    --bs-btn-bg: var(--accent-soft);
    --bs-btn-border-color: transparent;
    --bs-btn-hover-color: #1c1c1c;
    --bs-btn-hover-bg: var(--info);
    --bs-btn-hover-border-color: var(--info);
    --bs-btn-active-color: #1c1c1c;
    --bs-btn-active-bg: var(--info);
    --bs-btn-active-border-color: var(--info);
    --bs-btn-disabled-color: var(--text-disabled);
    --bs-btn-disabled-bg: var(--bg-surface-2);
    --bs-btn-disabled-border-color: transparent;
}

/* Красный контурный оставляем красным: это единственный outline, где цвет
   реально предупреждает («Удалить»), а не украшает. */
.btn-outline-danger {
    --bs-btn-color: var(--danger);
    --bs-btn-bg: transparent;
    --bs-btn-border-color: var(--danger);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--danger);
    --bs-btn-hover-border-color: var(--danger);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--danger);
    --bs-btn-disabled-color: var(--text-disabled);
    --bs-btn-disabled-border-color: var(--border);
}

/* Фокусное кольцо — акцентом темы, а не бутстраповским синим. Только
   :focus-visible: у мыши кольцо не появляется, у клавиатуры остаётся. */
.btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    box-shadow: none;
}

.btn-sm { padding: 0.3rem 0.65rem; font-size: 0.85rem; }
.btn-lg { padding: 0.7rem 1.4rem; font-size: 1rem; }

.btn-close {
    filter: invert(1) brightness(0.9);
    opacity: 0.85;
}
.btn-close:hover { opacity: 1; }
.btn-close-white { filter: none; }

/* =====================================================================
   Формы
   ===================================================================== */
.form-control,
.form-select,
textarea.form-control,
input[type="text"],
input[type="password"],
input[type="email"],
input[type="number"],
input[type="search"],
input[type="tel"],
input[type="date"],
input[type="time"],
input[type="datetime-local"] {
    background-color: var(--bg-input) !important;
    color: var(--text-primary) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--radius-md) !important;
    transition: var(--transition);
    padding: 0.55rem 0.85rem;
}
.form-control:focus,
.form-select:focus {
    background-color: var(--bg-input) !important;
    color: var(--text-primary) !important;
    border-color: var(--accent) !important;
    box-shadow: 0 0 0 3px var(--accent-soft) !important;
    outline: none;
}
.form-control::placeholder { color: var(--text-muted); opacity: 1; }
.form-control[readonly], .form-control:disabled {
    background: var(--bg-surface-2) !important;
    color: var(--text-muted) !important;
}

.form-select {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23aab8c5' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e") !important;
    background-repeat: no-repeat !important;
    background-position: right 0.75rem center !important;
    background-size: 14px 12px !important;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    padding-right: 2.25rem !important;
}
.form-select option { background: var(--bg-modal); color: var(--text-primary); }

.form-label {
    color: var(--text-secondary);
    font-weight: 500;
    margin-bottom: 0.4rem;
}
.form-text, small.text-muted { color: var(--text-muted) !important; }

.form-check-input {
    background-color: var(--bg-input);
    border-color: var(--border-strong);
}
.form-check-input:checked {
    background-color: var(--accent);
    border-color: var(--accent);
}
.form-check-input:focus {
    box-shadow: 0 0 0 3px var(--accent-soft);
    border-color: var(--accent);
}
.form-check-label { color: var(--text-secondary); }

.input-group-text {
    background: var(--bg-surface-2) !important;
    border-color: var(--border) !important;
    color: var(--text-secondary) !important;
}

/* =====================================================================
   Модальные окна
   ===================================================================== */
/* Модалка — тоже через переменные Bootstrap. Они объявляются на .modal, но
   кастомные свойства наследуются вниз, поэтому задание на .modal-content
   доходит и до .modal-header/.modal-footer (они читают те же --bs-modal-*). */
.modal-content {
    --bs-modal-bg: var(--bg-modal);
    --bs-modal-color: var(--text-primary);
    --bs-modal-border-color: var(--border);
    --bs-modal-border-radius: var(--radius-lg);
    --bs-modal-inner-border-radius: var(--radius-lg);
    --bs-modal-header-border-color: var(--border);
    --bs-modal-footer-border-color: var(--border);
    box-shadow: var(--shadow-lg);
}
/* Шапка и подвал модалки отличаются от тела фоном — своей переменной под это
   у Bootstrap нет (в отличие от карточек), поэтому задаём напрямую. */
.modal-header,
.modal-footer { background: var(--bg-surface-2); }
.modal-header { padding: 0.9rem 1.2rem; }
/* .bg-danger — утилита Bootstrap с встроенным !important (см. карточки выше). */
.modal-header.bg-danger {
    background: var(--danger) !important;
    color: #fff !important;
}
.modal-title { font-weight: 600; }
.modal-body { padding: 1.2rem; }
.modal-backdrop.show { opacity: 0.7; }

/* ── Переработка модалок: спокойные кнопки, лёгкие таблицы, пропорции ──────
   Раньше в таблицах модалок пары «Редактировать»(синяя)/«Удалить»(красная)
   светились сплошной заливкой → пёстро и непропорционально. Делаем действия
   нейтральными, цвет проявляем на наведении; таблицы — без тяжёлой сетки. */
.modal-footer { gap: 0.5rem; padding: 0.85rem 1.15rem; }
.modal-footer .btn { min-width: 110px; justify-content: center; }
.modal-footer .dropdown .btn { min-width: 0; }   /* «Повторить» не растягиваем */

/* Отдельное правило для «Удалить» в подвале модалки больше не нужно: мягкий
   тон с насыщением на наведении стал поведением .btn-danger по умолчанию
   (см. «Единая палитра кнопок» ниже). Минус ещё 5 !important. */

/* Таблицы в модалках: только разделители строк, заголовок-метка, воздух */
.modal-content .table { font-size: 0.9rem; margin-bottom: 0; }
.modal-content .table > :not(caption) > * > * {
    border-width: 0 0 1px 0 !important;
    border-color: var(--border) !important;
    padding: 0.55rem 0.6rem;
    vertical-align: middle;
}
.modal-content .table thead th {
    color: var(--text-muted);
    font-weight: 600;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.modal-content .table tbody tr:last-child > * { border-bottom: 0 !important; }

/* Кнопки действий в строках — компактные и спокойные (цвет на hover).
   Задаётся переменными Bootstrap, а не перебиванием свойств: 12 !important
   отсюда ушли. Смысл тот же, что и раньше, — в плотной таблице пары
   «Редактировать»/«Удалить» не должны пестрить заливкой. */
.modal-content .table .btn-sm { padding: 0.3rem 0.6rem; font-size: 0.82rem; }
.modal-content .table .btn-primary,
.modal-content .table .btn-outline-primary,
.modal-content .table .btn-success,
.modal-content .table .btn-info {
    --bs-btn-color: var(--text-secondary);
    --bs-btn-bg: var(--bg-surface-3);
    --bs-btn-border-color: var(--border);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--accent);
    --bs-btn-hover-border-color: var(--accent);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--accent);
}
.modal-content .table .btn-danger,
.modal-content .table .btn-outline-danger {
    --bs-btn-color: var(--text-secondary);
    --bs-btn-bg: transparent;
    --bs-btn-border-color: var(--border);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--danger);
    --bs-btn-hover-border-color: var(--danger);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--danger);
}

/* Полноширинные «Добавить/Сохранить» — ровная высота и вес */
.modal-body .btn.w-100 { padding: 0.6rem 1rem; font-weight: 600; margin-top: 0.25rem; }
/* Группы кнопок действий в строках не липнут друг к другу */
.modal-content .table td .btn + .btn { margin-left: 0.35rem; }

/* ── Единый вид форм в модалках: ровный ритм и одинаковая высота полей ──── */
.modal-body .form-label { margin-bottom: 0.3rem; font-size: 0.85rem; font-weight: 500; }
.modal-body .form-control,
.modal-body .form-select { min-height: 2.5rem; }
.modal-body textarea.form-control { min-height: 4rem; }
.modal-body .form-text { margin-top: 0.25rem; }
/* Иконочные кнопки действий — ровный квадрат, иконка по центру */
.modal-content .table .btn-sm > i { font-size: 0.95rem; line-height: 1; }
.modal-content .table td:last-child { white-space: nowrap; }

/* Палитра цвета — ровная сетка одинаковых ячеек (для занятия и преподавателя) */
.color-picker { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0; }
.color-picker .color-option {
    width: 28px;
    height: 28px;
    padding: 0;
    border-radius: 6px;
    border: 2px solid var(--border);
    cursor: pointer;
    transition: transform .12s ease, border-color .12s ease, box-shadow .12s ease;
}
.color-picker .color-option:hover { transform: scale(1.12); }
.color-picker .color-option.active,
.color-picker .color-option.selected {
    border-color: var(--text-primary);
    box-shadow: 0 0 0 2px var(--bg-modal), 0 0 0 4px var(--text-primary);
    outline: none;
}

/* Мобильные модалки: кнопки футера равной ширины (не вылезают), компактные
   таблицы. Таблицы окон управления обёрнуты в .table-responsive — широкий
   список скроллится внутри своего блока, а форма остаётся ровно на ширину окна. */
@media (max-width: 768px) {
    .modal-footer { flex-wrap: wrap; gap: 0.4rem; }
    .modal-footer .btn { min-width: 0; flex: 1 1 auto; }
    .modal-footer .dropdown { flex: 1 1 auto; }
    .modal-footer .dropdown .btn { width: 100%; }
    .modal-content .table { font-size: 0.82rem; }
    .modal-content .table > :not(caption) > * > * { padding: 0.4rem 0.45rem; }
    .modal-content .table .btn-sm { padding: 0.26rem 0.45rem; }
}

/* Окна управления (преподаватели/ученики/дисциплины) — шире обычного modal-xl,
   чтобы список влезал без горизонтальной прокрутки. На десктопе ~95vw. */
@media (min-width: 992px) {
    .modal-dialog.modal-mgmt-wide { max-width: min(1600px, 95vw); }
}

/* На узких телефонах прячем второстепенные колонки в списках управления,
   чтобы таблица влезала по ширине окна и не нужно было свайпать вбок.
   (преподаватели: Telegram ID + Цвет; ученики: Преподаватели) */
/* 575.98, а не 575: рядом есть min-width:576px, и на дробной ширине между
   575 и 576 (зум, дробный DPR) не срабатывало НИ ОДНО из правил. */
@media (max-width: 575.98px) {
    #teachersMgmtTable th:nth-child(4), #teachersMgmtTable td:nth-child(4),
    #teachersMgmtTable th:nth-child(5), #teachersMgmtTable td:nth-child(5),
    #studentsMgmtTable th:nth-child(3), #studentsMgmtTable td:nth-child(3) {
        display: none;
    }
}

/* =====================================================================
   Дропдауны
   ===================================================================== */
.dropdown-menu {
    --bs-dropdown-bg: var(--bg-modal);
    --bs-dropdown-border-color: var(--border);
    --bs-dropdown-border-radius: var(--radius-md);
    --bs-dropdown-link-color: var(--text-secondary);
    --bs-dropdown-link-hover-color: var(--text-primary);
    --bs-dropdown-link-hover-bg: var(--bg-hover);
    --bs-dropdown-link-active-color: #fff;
    --bs-dropdown-link-active-bg: var(--accent);
    --bs-dropdown-header-color: var(--text-primary);
    --bs-dropdown-divider-bg: var(--border);
    box-shadow: var(--shadow-md);
    padding: 0.4rem;
    z-index: 99999;
}
.dropdown-item {
    border-radius: var(--radius-sm);
    padding: 0.5rem 0.75rem;
    transition: var(--transition);
    display: flex;
    align-items: center;
    gap: 8px;
}
.dropdown-header { font-weight: 600; padding: 0.5rem 0.75rem; }
.dropdown-divider { margin: 0.3rem 0; }

.nav-item.dropdown.show .dropdown-menu { z-index: 100000 !important; }

/* =====================================================================
   Таблицы
   ===================================================================== */
.table {
    --bs-table-color: var(--text-primary);
    --bs-table-bg: var(--bg-surface);
    --bs-table-border-color: var(--border);
    --bs-table-striped-color: var(--text-primary);
    --bs-table-striped-bg: var(--bg-surface-2);
    --bs-table-hover-color: var(--text-primary);
    --bs-table-hover-bg: var(--bg-hover);
    --bs-table-active-color: var(--text-primary);
    --bs-table-active-bg: var(--bg-hover);
}
.table thead th {
    background: var(--bg-surface-2);
    color: var(--text-secondary);
    font-weight: 600;
    border-bottom: 1px solid var(--border);
}

/* =====================================================================
   Алерты
   ===================================================================== */
.alert {
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    padding: 0.75rem 1rem;
}
/* Текст алертов — var(--text-primary), а НЕ жёсткий светлый цвет.
   Раньше здесь стояли #d4f5e3 / #ffe5b8 / #fcd6d1 / #cfe5fb — почти белые
   оттенки, рассчитанные только на тёмную тему. В светлой и сепии фон алерта
   тоже светлый (заливка 16%-й прозрачности), и текст на нём практически
   пропадал. Семантику несут фон и рамка, их и оставляем цветными. */
.alert-success { background: var(--success-soft); border-color: var(--success); color: var(--text-primary); }
.alert-warning { background: var(--warning-soft); border-color: var(--warning); color: var(--text-primary); }
.alert-danger  { background: var(--danger-soft);  border-color: var(--danger);  color: var(--text-primary); }
.alert-info    { background: var(--accent-soft);  border-color: var(--accent);  color: var(--text-primary); }

/* =====================================================================
   Бейджи
   ===================================================================== */
.badge {
    font-weight: 500;
    padding: 0.3em 0.6em;
    border-radius: var(--radius-pill);
}
.badge.bg-primary { background: var(--accent) !important; }
.badge.bg-success { background: var(--success) !important; }
.badge.bg-danger  { background: var(--danger)  !important; }
.badge.bg-warning { background: var(--warning) !important; color: #1c1c1c !important; }
.badge.bg-info    { background: var(--info)    !important; color: #1c1c1c !important; }
.badge.bg-secondary { background: var(--bg-surface-3) !important; color: var(--text-primary) !important; }

/* =====================================================================
   Списки
   ===================================================================== */
.list-group-item {
    background: var(--bg-surface) !important;
    color: var(--text-primary) !important;
    border-color: var(--border) !important;
}
.list-group-item-action:hover { background: var(--bg-hover) !important; }
.list-group-item.active {
    background: var(--accent) !important;
    border-color: var(--accent) !important;
    color: #fff !important;
}

/* =====================================================================
   Поиск (глобальный в навбаре)
   ===================================================================== */
.search-container { position: relative; width: 220px; max-width: 320px; flex: 0 0 auto; }
.search-container #globalSearch { width: 100%; }
/* 991.98 — та же причина, что и у 575.98 выше: парный min-width:992px. */
@media (max-width: 991.98px) {
    .search-container { width: 100%; max-width: none; margin: 8px 0; }
}
.search-results {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    background: var(--bg-modal);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    max-height: 320px;
    overflow-y: auto;
    z-index: 1050;
    display: none;
}
.search-result-item {
    padding: 0.6rem 0.85rem;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
    transition: var(--transition);
    color: var(--text-secondary);
}
.search-result-item:last-child { border-bottom: none; }
.search-result-item:hover { background: var(--bg-hover); color: var(--text-primary); }

/* =====================================================================
   Уведомления (badge + toasts)
   ===================================================================== */
.notification-badge {
    position: absolute;
    top: 4px;
    right: 4px;
    background: var(--danger);
    color: #fff;
    border-radius: var(--radius-pill);
    min-width: 18px;
    height: 18px;
    font-size: 0.7rem;
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 5px;
    box-shadow: 0 0 0 2px var(--bg-surface);
}

.toast-container {
    position: fixed;
    top: 70px;
    right: 20px;
    z-index: 10500;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.toast {
    background: var(--bg-modal);
    color: var(--text-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    min-width: 280px;
    overflow: hidden;
}
.toast.bg-success { border-color: var(--success); background: var(--bg-modal); }
.toast.bg-danger  { border-color: var(--danger);  background: var(--bg-modal); }
.toast.bg-info    { border-color: var(--info);    background: var(--bg-modal); }
.toast .toast-body { color: var(--text-primary); padding: 0.7rem 1rem; }

/* =====================================================================
   Loading spinner
   ===================================================================== */
.loading-spinner {
    position: fixed;
    inset: 0;
    background: rgba(20, 23, 28, 0.78);
    /* -webkit- обязателен: без него размытие не работает в Safari и во всех
       браузерах на iOS, а приложение ставится на iPhone как PWA. */
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 10600;
}
.spinner-border { color: var(--accent) !important; }

/* =====================================================================
   Аватары
   ===================================================================== */
.user-avatar {
    border-radius: 50%;
    object-fit: cover;
    border: 2px solid var(--border);
    background: var(--bg-surface-2);
}

/* =====================================================================
   Ширина рабочей области. Bootstrap-класс .container на больших экранах
   ограничивает контент ~1140–1320px — расширяем примерно на четверть, чтобы
   страницы были просторнее. Касается всех страниц (навбар + контент в .container).
   ===================================================================== */
@media (min-width: 1200px) {
    .container { max-width: 1440px; }
}

/* =====================================================================
   ШАПКА СТРАНИЦЫ (.page-header) — единый заголовок для всех страниц
   кабинета. Разметку даёт макрос page_header из templates/_ui.html.

   До неё каждая страница верстала заголовок сама: display-3, h2.mb-1,
   h1.text-center, h2.mb-0 — кегль гулял от 1.5rem до 4.5rem, и контент
   начинался на разной высоте. Для дашбордов с аватаром и рангом есть более
   крупный родственник — .page-hero ниже.
   ===================================================================== */
.page-header {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    justify-content: space-between;
    align-items: center;
    margin: 0 0 var(--space-5);
}
/* min-width:0 обязателен: без него длинный заголовок распирает флекс-строку
   и выдавливает кнопки действий за пределы контейнера. */
.page-header__main { min-width: 0; }
.page-header__title {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    font-size: var(--fs-2xl);
    line-height: var(--lh-tight);
    font-weight: var(--fw-semibold);
    color: var(--text-primary);
}
.page-header__title i { color: var(--accent); font-size: 0.9em; }
.page-header__subtitle {
    margin: var(--space-2) 0 0;
    color: var(--text-secondary);
    font-size: var(--fs-md);
    line-height: var(--lh-normal);
}
.page-header__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
}
@media (max-width: 767.98px) {
    .page-header { gap: var(--space-3); margin-bottom: var(--space-4); }
    .page-header__title { font-size: var(--fs-xl); }
    /* Действия уходят на отдельную строку: в 320–480px они иначе
       ужимаются до нечитаемых огрызков рядом с заголовком. */
    .page-header__actions { width: 100%; }
}

/* =====================================================================
   ШАПКА ДАШБОРДА (.page-hero) — «приветственный» блок с аватаром/иконкой,
   рангом и кнопками. Отличается от .page-header тем, что несёт лицо
   человека и крупные показатели, поэтому оформлен поверхностью.

   Свёл сюда два прежних блока: .welcome-section (админ-дашборд, плоская
   поверхность) и .dashboard-header-card (кабинеты педагога/ученика и
   статистика). Второй был залит ЗАХАРДКОЖЕННЫМ градиентом #1e3a5f→#2b5278
   с !important — из-за него кабинеты педагога и ученика выглядели одинаково
   тёмно-синими во всех 11 темах сайта, тема на них просто не действовала.
   Здесь градиент собирается из --accent и --bg-surface, то есть следует теме.
   ===================================================================== */
.page-hero {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4);
    margin: 0 0 var(--space-5);
    padding: var(--space-5);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    /* Первая строка — фолбэк для браузеров без color-mix (Chrome < 111):
       там останется сплошная поверхность, а не прозрачный фон. */
    background: var(--bg-surface);
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--accent) 20%, var(--bg-surface)) 0%,
        var(--bg-surface) 70%);
}
.page-hero__media {
    flex: 0 0 auto;
    width: 72px;
    height: 72px;
    border-radius: 50%;
    object-fit: cover;
    display: grid;
    place-items: center;
    font-size: 2rem;
    color: var(--accent);
    background: color-mix(in srgb, var(--accent) 14%, transparent);
}
/* min-width:0 — иначе длинное имя распирает строку и выдавливает ранг. */
.page-hero__main { flex: 1 1 260px; min-width: 0; }
.page-hero__title {
    margin: 0;
    font-size: var(--fs-2xl);
    line-height: var(--lh-tight);
    font-weight: var(--fw-semibold);
    color: var(--text-primary);
}
.page-hero__subtitle {
    margin: var(--space-2) 0 0;
    color: var(--text-secondary);
    font-size: var(--fs-md);
    line-height: var(--lh-normal);
}
.page-hero__aside {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--space-2);
    text-align: right;
}
.page-hero__rank {
    font-size: var(--fs-xl);
    font-weight: var(--fw-bold);
    color: var(--text-primary);
    line-height: var(--lh-tight);
}
.page-hero__level {
    font-size: var(--fs-xs);
    color: var(--text-secondary);
}
/* Нижняя полка на всю ширину — кнопки календарей на админ-дашборде. */
.page-hero__footer {
    flex: 0 0 100%;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
    padding-top: var(--space-4);
    border-top: 1px solid var(--border);
}
.page-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
}

@media (max-width: 767.98px) {
    .page-hero { padding: var(--space-4); gap: var(--space-3); }
    .page-hero__title { font-size: var(--fs-xl); }
    .page-hero__media { width: 56px; height: 56px; font-size: 1.5rem; }
    /* Ранг с правого края уезжает под имя: рядом они делят ~150px и рвутся. */
    .page-hero__aside { align-items: flex-start; text-align: left; flex-basis: 100%; }
}

/* =====================================================================
   Дашборд — общие классы
   ===================================================================== */
/* Верхний отступ контента задаётся ЗДЕСЬ и только здесь. Раньше каждая
   страница добавляла свой (mt-4 / mt-3 / py-4 / ничего) поверх этого поля, и
   контент начинался на высоте от 1.5rem до 3rem в зависимости от страницы. */
.main-content {
    padding: var(--space-6) 0 var(--space-7);
    min-height: calc(100vh - 64px);
}

.dashboard-container {
    max-width: 1600px;
    margin: 0 auto;
    /* Вертикальных полей нет: их даёт .main-content (см. выше). */
    padding: 0 1rem;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
/* Заголовки-метки разделов («Активность», «Люди и предметы»): прижимаем к
   их сетке карточек снизу. Сбрасываем bootstrap-отступы (mt-*/mb-*), которые
   раньше складывались с gap контейнера и раздували вертикаль. */
.dashboard-container > h6 {
    margin: 0.3rem 0 0 !important;
}

/* .welcome-section / .welcome-header / .welcome-text убраны — админ-дашборд
   переведён на общий .page-hero (см. секцию «ШАПКА ДАШБОРДА» выше). */

.calendar-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}
.calendar-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0.55rem 1rem;
    background: var(--bg-surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--text-primary);
    font-weight: 500;
    transition: var(--transition);
}
.calendar-btn:hover {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}
.create-calendar-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0.55rem 1rem;
    background: transparent;
    border: 1px solid var(--accent);
    border-radius: var(--radius-md);
    color: var(--accent);
    font-weight: 500;
    transition: var(--transition);
    cursor: pointer;
}
.create-calendar-btn:hover {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}
/* Кнопка удаления календаря — приглушённая иконка как в модуле репетиций:
   нейтральная по умолчанию, красная только при наведении. */
.delete-calendar-btn {
    width: 32px;
    height: 32px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    background: var(--bg-surface-2);
    color: var(--text-secondary);
    cursor: pointer;
    transition: all .15s ease;
}
.delete-calendar-btn:hover {
    background: var(--danger);
    border-color: var(--danger);
    color: #fff;
}

/* .dashboard-header-card удалён: захардкоженный градиент #1e3a5f→#2b5278 с
   !important не подчинялся ни одной из 11 тем. Кабинеты и статистика теперь
   на .page-hero, форма регистрации — на обычной .card-header. */

.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 1rem;
}
.stat-card {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 1.2rem;
    text-align: center;
    transition: var(--transition);
}
.stat-card:hover { border-color: var(--accent); }
.stat-icon { font-size: 1.7rem; margin-bottom: 0.5rem; color: var(--accent); line-height: 1; }
.stat-value {
    font-size: 1.85rem;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1;
}
.stat-label {
    margin-top: 0.4rem;
    color: var(--text-secondary);
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.studio-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1rem;
}
.studio-card {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 1.2rem;
}
.studio-header { margin-bottom: 0.85rem; }
.studio-title {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--text-primary);
}
.studio-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.5rem;
}
.studio-stat {
    text-align: center;
    padding: 0.6rem 0.4rem;
    background: var(--bg-surface-2);
    border-radius: var(--radius-md);
}
.studio-stat-value {
    font-size: 1.2rem;
    font-weight: 700;
    color: var(--accent);
}
.studio-stat-label {
    font-size: 0.7rem;
    color: var(--text-muted);
    text-transform: uppercase;
}

/* ── Админ-виджеты: «Требует внимания», деньги/тренд, лента «Сегодня» ─────── */
.attention-card {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-left: 3px solid var(--warning);
    border-radius: var(--radius-lg);
    padding: 1.1rem 1.2rem;
}
.attention-head { font-weight: 600; color: var(--text-primary); margin-bottom: 0.8rem; }
.attention-head i { color: var(--warning); }
.attention-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.attention-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0.4rem 0.75rem;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--bg-surface-2);
    color: var(--text-primary);
    font-size: 0.85rem;
    font-weight: 500;
    cursor: pointer;
    transition: var(--transition);
}
.attention-chip:hover { border-color: var(--accent); }
.attention-chip-num { font-weight: 700; }
.attention-chip.warning .attention-chip-num { color: var(--warning); }
.attention-chip.danger .attention-chip-num { color: var(--danger); }
.attention-chip.info .attention-chip-num { color: var(--accent); }
.attention-list { margin-top: 0.8rem; display: flex; flex-direction: column; gap: 0.35rem; }
.attention-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    padding: 0.45rem 0.6rem;
    background: var(--bg-surface-2);
    border-radius: var(--radius-md);
}
.attention-row-main { display: flex; flex-direction: column; min-width: 0; }
.attention-row-name { font-weight: 600; color: var(--text-primary); }
.attention-row-sub { font-size: 0.8rem; color: var(--text-secondary); }
.attention-badge {
    flex-shrink: 0;
    font-size: 0.75rem;
    font-weight: 600;
    padding: 0.2rem 0.55rem;
    border-radius: 999px;
    background: var(--bg-surface-3);
    color: var(--text-secondary);
    white-space: nowrap;
}
.attention-badge.unpaid { color: var(--warning); }

.insights-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1rem;
}
.insight-card {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 1.2rem;
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
}
.insight-head { font-size: 0.85rem; color: var(--text-secondary); font-weight: 500; }
.insight-value { font-size: 1.85rem; font-weight: 700; color: var(--text-primary); line-height: 1; }
.insight-sub { font-size: 0.85rem; color: var(--text-secondary); }
.insight-sub .delta { font-weight: 700; }
.insight-sub .delta.up { color: var(--success); }
.insight-sub .delta.down { color: var(--danger); }
.insight-link {
    margin-top: auto;
    align-self: flex-start;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--accent);
}
.insight-link:hover { text-decoration: underline; }
.sparkline { width: 100%; height: 44px; display: block; }

.today-card {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 1.2rem;
}
.today-head { font-weight: 600; color: var(--text-primary); margin-bottom: 0.75rem; }
.today-head i { color: var(--accent); }
.today-list { display: flex; flex-direction: column; }
.today-row {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--border);
}
.today-row:last-child { border-bottom: none; }
.today-time {
    flex-shrink: 0;
    width: 48px;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--accent);
}
.today-main { display: flex; flex-direction: column; min-width: 0; flex-grow: 1; }
.today-title { font-weight: 500; color: var(--text-primary); }
.today-meta { font-size: 0.8rem; color: var(--text-secondary); }
.today-badge {
    flex-shrink: 0;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    background: var(--bg-surface-3);
    color: var(--text-secondary);
}

.actions-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 1rem;
}
.action-card, .notifications-card {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 1.2rem;
}
.action-title, .notifications-title {
    margin: 0 0 1rem;
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-primary);
}
.action-buttons {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.action-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 0.7rem 1rem;
    background: var(--bg-surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--text-primary);
    font-weight: 500;
    text-align: left;
    cursor: pointer;
    transition: var(--transition);
}
.action-btn:hover {
    background: var(--bg-hover);
    border-color: var(--accent);
    color: var(--text-primary);
}
.action-btn.primary { border-left: 3px solid var(--accent); }
.action-btn.warning { border-left: 3px solid var(--warning); }
.action-btn.success { border-left: 3px solid var(--success); }

.notifications-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.85rem;
}
.refresh-btn {
    background: var(--bg-surface-2);
    border: 1px solid var(--border);
    color: var(--text-secondary);
    border-radius: var(--radius-md);
    width: 36px;
    height: 36px;
    cursor: pointer;
    transition: var(--transition);
}
.refresh-btn:hover { background: var(--bg-hover); color: var(--text-primary); }

.notification-item {
    padding: 0.7rem;
    background: var(--bg-surface-2);
    border-radius: var(--radius-md);
    margin-bottom: 0.5rem;
    border-left: 3px solid var(--accent);
}
.notification-item:last-child { margin-bottom: 0; }
.notification-text { color: var(--text-primary); font-size: 0.9rem; }
.notification-date { color: var(--text-muted); font-size: 0.78rem; margin-top: 0.2rem; }

.no-calendars { text-align: center; padding: 2rem 1rem; color: var(--text-secondary); }
.no-calendars h3 { color: var(--text-primary); margin-bottom: 0.5rem; }

/* =====================================================================
   Чаты
   ===================================================================== */
#chatList .list-group-item-action {
    background: var(--bg-surface-2) !important;
    border-color: var(--border) !important;
    margin-bottom: 6px;
    border-radius: var(--radius-md) !important;
}
#chatList .list-group-item-action:hover { background: var(--bg-hover) !important; }
#chatList .list-group-item-action.active {
    background: var(--accent-soft) !important;
    border-color: var(--accent) !important;
    color: var(--text-primary) !important;
}
#messages .bg-light { background: var(--bg-surface-2) !important; color: var(--text-primary) !important; }
#messages .bg-primary { background: var(--accent) !important; color: #fff !important; }
#messages .text-white-50 { color: rgba(255,255,255,0.65) !important; }

/* =====================================================================
   FullCalendar — тёмная тема
   ===================================================================== */
.fc {
    background: var(--bg-surface);
    color: var(--text-primary);
    border-radius: var(--radius-lg);
    padding: 0.5rem;
}
.fc .fc-toolbar-title {
    color: var(--text-primary);
    font-weight: 700;
    font-size: 1.6rem;
    letter-spacing: 0.01em;
}
.fc .fc-toolbar.fc-header-toolbar { margin-bottom: 1rem; gap: 0.5rem; }
.fc .fc-button {
    background: var(--bg-surface-2) !important;
    border: 1px solid var(--border) !important;
    color: var(--text-primary) !important;
    box-shadow: none !important;
    text-transform: none;
    font-weight: 500;
    font-size: 0.95rem;
    padding: 0.4rem 0.8rem;
    border-radius: var(--radius-md) !important;
}
.fc .fc-button:hover {
    background: var(--bg-hover) !important;
    border-color: var(--border-strong) !important;
}
.fc .fc-button-primary:not(:disabled).fc-button-active,
.fc .fc-button-primary:not(:disabled):active {
    background: var(--accent) !important;
    border-color: var(--accent) !important;
    color: #fff !important;
}
.fc .fc-col-header-cell {
    background: var(--bg-surface-2);
    color: var(--text-primary);
    border-color: var(--border) !important;
    font-weight: 600;
    font-size: 1rem;
    padding: 0.7rem 0;
}
.fc .fc-col-header-cell-cushion { padding: 0.4rem 0.5rem; font-size: 1rem; }
.fc .fc-daygrid-day-number,
.fc .fc-list-day-text,
.fc .fc-list-day-side-text {
    font-size: 0.95rem;
}
.fc .fc-daygrid-day,
.fc .fc-timegrid-slot,
.fc .fc-scrollgrid,
.fc .fc-scrollgrid-section > * {
    border-color: var(--border) !important;
}
.fc .fc-daygrid-day:hover { background: var(--bg-hover); }
.fc .fc-day-today { background: var(--accent-soft) !important; }
.fc .fc-daygrid-day-number,
.fc .fc-timegrid-axis-cushion,
.fc .fc-list-day-cushion {
    color: var(--text-secondary);
}
.fc .fc-event {
    border-radius: var(--radius-sm);
    border: none;
    padding: 2px 4px;
    font-size: 0.82rem;
}
.fc .fc-list-empty { background: var(--bg-surface); color: var(--text-muted); }
.fc-theme-standard td, .fc-theme-standard th { border-color: var(--border) !important; }
.fc-list-event:hover td { background: var(--bg-hover) !important; }

/* =====================================================================
   Адаптив
   ===================================================================== */
@media (max-width: 768px) {
    /* Масштаб (html font-size) задаётся инлайн в base.html — чтобы SW не
       отдавал старую версию из кэша /static. */
    .dashboard-container { padding: 0 0.4rem; gap: var(--space-2); }
    .stats-grid { grid-template-columns: repeat(2, 1fr); }
    .studio-grid, .actions-grid, .insights-grid { grid-template-columns: 1fr; }
    .navbar .nav-link { padding: 0.4rem 0.65rem !important; }
    .fc .fc-toolbar-title { font-size: 1.25rem; }
    .fc .fc-col-header-cell { font-size: 0.85rem; padding: 0.5rem 0; }
    .fc .fc-col-header-cell-cushion { font-size: 0.85rem; padding: 0.3rem 0.25rem; }
    .fc .fc-button { font-size: 0.85rem; padding: 0.3rem 0.55rem; }
}

@media (max-width: 480px) {
    .stats-grid { grid-template-columns: 1fr; }
    .stat-value { font-size: 1.5rem; }
}

/* На телефонах ужимаем боковые отступы контейнера, чтобы блоки заняли
   больше ширины экрана (на десктопе расширение задаётся max-width выше). */
@media (max-width: 575.98px) {
    .container { padding-left: 0.5rem; padding-right: 0.5rem; }
}

/* =====================================================================
   Новогодний декор. Активен только при теме «Новый год». Фигурки по углам
   и гирлянду создаёт переключатель (#ny-decor), здесь — анимации и Дед
   Мороз 🎅 на углу шапки дашборда (.page-hero).
   ===================================================================== */
@keyframes nyTwinkle { 0%,100% { opacity:.35; } 50% { opacity:1; } }
@keyframes nyBob { 0%,100% { transform: translateY(0) rotate(var(--r,0deg)); } 50% { transform: translateY(-8px) rotate(var(--r,0deg)); } }

:root[data-theme="newyear"] .page-hero { position: relative; overflow: visible; }
:root[data-theme="newyear"] .page-hero::after {
    content: "🎅";
    position: absolute;
    top: -20px;
    right: -6px;
    font-size: 38px;
    transform: rotate(14deg);
    pointer-events: none;
    filter: drop-shadow(0 2px 3px rgba(0,0,0,0.45));
    z-index: 2;
}

/* =====================================================================
   Полупрозрачные блоки. Сквозь поверхности слегка просвечивает фоновый
   узор (~10% прозрачности) — заметно, но читаемость сохраняется.
   color-mix адаптивен к теме; в браузерах без его поддержки декларация
   игнорируется и остаётся сплошной фон (заданный выше). Навбар, модалки,
   дропдауны и тосты намеренно НЕ трогаем — там важна чёткость.
   ===================================================================== */
.card,
.stat-card,
.studio-card,
.action-card,
.notifications-card,
.list-group-item {
    background: color-mix(in srgb, var(--bg-surface) 90%, transparent) !important;
}

/* =====================================================================
   Дашборд — полировка карточек: мягкая тень, «подъём» при наведении,
   иконки статистики в круглой плашке с оттенком акцента. Тема-безопасно
   (только переменные темы + rgba-тени), работает во всех пресетах.
   ===================================================================== */
.stat-card, .studio-card, .insight-card, .attention-card, .today-card {
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
    transition: transform .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.stat-card:hover, .studio-card:hover, .insight-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.14);
    border-color: var(--accent);
}
.stat-icon {
    width: 46px; height: 46px; margin-left: auto; margin-right: auto; margin-bottom: 0.55rem;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%; font-size: 1.4rem;
    background: color-mix(in srgb, var(--accent) 14%, transparent);
}
.studio-stat { transition: background .15s ease, transform .15s ease; }
.studio-card:hover .studio-stat { transform: translateY(-1px); }
