@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 300; font-display: swap; src: url('/static/fonts/JetBrainsMono-Light.woff2') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('/static/fonts/JetBrainsMono-Regular.woff2') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 500; font-display: swap; src: url('/static/fonts/JetBrainsMono-Medium.woff2') format('woff2'); }

:root {
    --bg-0: #0a0a0b;
    --bg-1: #101012;
    --bg-2: #16161a;
    --fg: #e6e6e8;
    --fg-2: #8a8a90;
    --fg-3: #4d4d54;
    --fg-4: #2a2a2f;
    --signal: #c8c8cc;
    --signal-warn: #b87a5a;
    --screen: #5faa7a;
    --font: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
    --tracking: 0.02em;
    --tracking-wide: 0.18em;
    --t-fast: 120ms cubic-bezier(.2, .6, .2, 1);
    --t-med: 320ms cubic-bezier(.2, .6, .2, 1);
    --t-slow: 800ms cubic-bezier(.2, .6, .2, 1);

    /* === UI scaling ===
       Корневой font-size = 14px * --auto-scale * --ui-scale. Всё, что должно
       расти с экраном (аватары, кнопки, шапка, отступы) — в rem.

       --auto-scale: автоматический коэффициент по физической ширине монитора
                     (screen.width). Выставляется inline-скриптом в <head>
                     index.html ДО загрузки CSS — без FOUC. На FHD ≈1.21,
                     на 2K ≈1.86, на 4K ≈3.14. На малых экранах = 1.
                     Сверху ×1.2 при devicePixelRatio ≥ 2 (retina и Windows
                     @200%): там screen.width отдаёт «маленькую» логическую
                     ширину, а пиксель физически мелкий — без поправки
                     MacBook 14" получал ту же базу, что ноутбук с 1366.
                     ВАЖНО: НЕ используем vw, потому что vw реагирует на
                     браузерный zoom — и fluid-формула перекомпенсировала
                     zoom (Ctrl+Minus делал интерфейс крупнее, а не мельче).
                     screen.width к zoom иммунен, поэтому zoom работает
                     ортогонально нашему scaling.

       --ui-scale: пользовательский множитель из настроек («масштаб
                   интерфейса», слайдер). По дефолту 1.0. */
    --auto-scale: 1;
    --ui-scale: 1;

    /* Высота custom titlebar'а. 0px в web (no titlebar), переопределяется
       в html.desktop scope в css/titlebar.css. Используется fixed-элементами
       (chat-panel, chat-toggle, settings-panel, intro) чтобы не залезать
       под titlebar в desktop-сборке без правки каждого их CSS отдельно. */
    --titlebar-h: 0px;

    /* Размер кнопок полноэкранных оверлеев (крестик, fullscreen, громкость).
       Один источник правды: демка тянет отсюда же свой --sc-btn. */
    --overlay-btn: 2.2rem;
}

/* ===== Кнопка «закрыть» полноэкранного оверлея =====
   Одна кнопка на все оверлеи (демонстрация экрана, картинка из чата). Раньше у
   каждого была своя: 2.2rem с подложкой против 3.14rem прозрачной — рядом они
   читались как элементы из разных интерфейсов. Эталон — вид из демки.

   Позиционирование сюда НЕ входит: у оверлеев разные системы координат (демка
   начинается под титлбаром, лайтбокс — от края окна), поэтому top/right задаёт
   каждый у себя. Анимация появления тоже своя: демка гасит контролы по
   бездействию, лайтбокс выезжает вместе с картинкой. */
.overlay-close {
    position: absolute;
    z-index: 2;
    width: var(--overlay-btn);
    height: var(--overlay-btn);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: rgba(16, 16, 18, 0.6);
    border: 1px solid var(--fg-4);
    /* Дизайн-гайд: border-radius 2px на прямоугольных элементах, не больше. */
    border-radius: 2px;
    color: var(--fg-2);
    cursor: pointer;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

.overlay-close:hover {
    color: var(--fg);
    border-color: var(--fg-2);
    background: rgba(16, 16, 18, 0.88);
}

.overlay-close svg {
    width: 1rem;
    height: 1rem;
    stroke: currentColor;
    stroke-width: 1.5;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html,
body {
    height: 100%;
    background: var(--bg-0);
    color: var(--fg);
    font-family: var(--font);
    font-size: calc(14px * var(--auto-scale) * var(--ui-scale));
    letter-spacing: var(--tracking);
    line-height: 1.5;
    overflow: hidden;
    /* macOS по умолчанию рисует текст субпиксельно и «подкармливает» его
       контрастом — светлый JetBrains Mono Light на почти чёрном фоне из-за
       этого выходит заметно ЖИРНЕЕ и мутнее, чем тот же кадр в Windows, под
       который типографика и подбиралась. Серая антиалиасинг-модель убирает
       разницу. Лендинг (landing.css) и окно апдейтера это уже делают — здесь
       правило просто отсутствовало, из-за чего app и лендинг на маке
       выглядели разными шрифтами. На Windows/Linux свойство — no-op. */
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

button,
input {
    font-family: inherit;
    font-size: inherit;
    color: inherit;
    letter-spacing: inherit;
}

body {
    opacity: 0;
    transition: opacity 0.3s ease;
}

/* Выделение текста — инверсия в стиле primary-кнопки (grayscale), вместо
   дефолтного браузерного синего. Один тон на весь сервис. */
::selection {
    background: var(--fg);
    color: var(--bg-0);
}

#background-gl,
#background,
#background-stars,
#background-grain {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    /* Smooth crossfade при смене темы фона: background.js на время свопа
       ставит на <html> класс `bg-switching`, мы гасим opacity → меняем
       тему → отпускаем класс → новая тема плавно появляется. */
    transition: opacity 280ms cubic-bezier(.4, 0, .2, 1);
}

html.bg-switching #background-gl,
html.bg-switching #background,
html.bg-switching #background-stars,
html.bg-switching #background-grain {
    opacity: 0;
}

/* Плёнка шума — ДИЗЕРИНГ, а не декор. Блоб набирает всего ~5-6 градаций
   яркости (альфа 0.022 на почти чёрном фоне) и растягивает их на полэкрана,
   виньетка — ещё ~5. В 8 битах такой градиент физически не может быть гладким:
   он обязан рисоваться террасами с чёткими границами. Размытие тут не лечит —
   после блюра результат снова округляется до 8 бит и полосы возвращаются,
   просто в других местах. Лечит только шум: он делает границу между полосами
   рваной, и глаз перестаёт видеть контур.

   1) z-index 2 — ВЫШЕ виньетки (body::after, z-index 1). Иначе её собственные
      террасы по углам не дизерятся вовсе. UI выше: у него z-index 2+ и он идёт
      позже в DOM.
   2) Готовый PNG 64×64 с равномерным шумом, а не feTurbulence. У турбулентности
      разброс значений неизвестен заранее, и подобранная «на глаз» opacity давала
      амплитуду меньше одной градации — после округления такой шум схлопывается
      в равномерную подсветку и не дизерит вообще. Здесь математика точная:
      слой непрозрачный, значения равномерны 0..255, поэтому размах на выходе =
      255 × opacity = ровно 4 градации при 0.016, среднее смещение +1.8.
   3) image-rendering: pixelated — на retina браузер иначе растянул бы тайл вдвое
      с интерполяцией и срезал бы половину амплитуды.
   4) data URI в base64. Прежний вариант был записан как `;utf8,<svg …>` —
      нестандартное сокращение (по спеке `;charset=utf-8`) с неэкранированными
      угловыми скобками: Chromium его берёт, Safari НЕТ. На маке плёнки не
      существовало вовсе. base64 понимают все. */
#background-grain {
    z-index: 2;
    opacity: 0.016;
    background-image: url("data:image/png;base64,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");
    background-repeat: repeat;
    image-rendering: pixelated;
}

/* На шейдерных темах плёнка остаётся только фактурой: дизеринг уже сделан
   в шейдере до округления, дублировать его шумом сверху незачем. */
html[data-bg-gl] #background-grain {
    opacity: 0.008;
}

/* На grid grain съедает чёткость точек — делаем плёнку тоньше. */
html[data-bg-theme="grid"] #background-grain {
    opacity: 0.01;
}

/* На grid периферийная виньетка усиливает «свет из центра» — затемняем
   углы чуть сильнее, чем в default-варианте body::after. */
html[data-bg-theme="grid"] body::after {
    background: radial-gradient(120% 80% at 50% 50%,
        transparent 25%,
        rgba(0, 0, 0, 0.04) 44%,
        rgba(0, 0, 0, 0.13) 60%,
        rgba(0, 0, 0, 0.28) 74%,
        rgba(0, 0, 0, 0.47) 88%,
        rgba(0, 0, 0, 0.72) 100%);
}

/* На блобовых темах виньетку рисует шейдер — вместе с фоном, в вещественных
   числах и с общим дизером. Слоем CSS сверху она принесла бы свои собственные
   пять градаций на полэкрана, то есть свои террасы поверх уже гладкого кадра. */
html[data-bg-gl] body::after {
    display: none;
}

body::after {
    content: "";
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 1;
    /* Многостоповый спад вместо двух стопов: на одном стопе браузер
       переключается с «ничего» на линейное затемнение, и этот излом наклона
       виден кольцом по периметру (та же болезнь, что была у блобов). Стопы
       идут по квадратичной кривой — переход без границы. */
    background: radial-gradient(120% 80% at 50% 50%,
        transparent 40%,
        rgba(0, 0, 0, 0.03) 55%,
        rgba(0, 0, 0, 0.10) 68%,
        rgba(0, 0, 0, 0.21) 79%,
        rgba(0, 0, 0, 0.36) 90%,
        rgba(0, 0, 0, 0.55) 100%);
}

/* ========= GLOBAL SCROLLBAR =========
   Стандартный OS-серый бьёт по тёмной теме. Делаем тонкую полупрозрачную
   полоску — единообразно везде (textarea, settings-панель, чат, dropdown'ы).
   Локальные правила в chat.css / chat-attach.css / settings.css перекрывают
   эту базу, если им нужен иной look. */

*::-webkit-scrollbar {
    width: 6px;
    height: 6px;
    background: transparent;
}

*::-webkit-scrollbar-track,
*::-webkit-scrollbar-corner {
    background: transparent;
}

*::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.08);
    border-radius: 3px;
    transition: background var(--t-fast);
}

*::-webkit-scrollbar-thumb:hover {
    background: rgba(255, 255, 255, 0.18);
}

/* Кнопок прокрутки (стрелочки на тач-bar Windows) скрываем — мешают. */
*::-webkit-scrollbar-button {
    display: none;
    width: 0;
    height: 0;
}

/* Firefox: нет ::-webkit-* псевдо-элементов, есть собственное API.

   @supports-гейт ОБЯЗАТЕЛЕН (тот же приём уже стоит в chat.css и
   chat-attach.css — здесь его просто забыли). Chrome 121+ и Safari 18.4+
   реализовали стандартные scrollbar-width/color и договорились, что при
   одновременном объявлении СТАНДАРТ выигрывает, а весь блок ::-webkit-
   scrollbar-* игнорируется. Селектор `*` раздавал их всему документу — то
   есть вся кастомная полоса выше (и её локальные переопределения в чате и
   настройках) в современных Chrome/Safari просто не применялась.
   Дополнительно на macOS `scrollbar-color` переключает системные overlay-
   полосы в классические, всегда видимые. */
@supports (-moz-appearance: none) {
    * {
        scrollbar-width: thin;
        scrollbar-color: rgba(255, 255, 255, 0.12) transparent;
    }
}

/* Скрытое через атрибут [hidden] должно быть скрыто, даже когда у элемента
   объявлен display: flex/grid (наш bug-view, например). */
[hidden] {
    display: none !important;
}
