/* Место под вертикальную полосу прокрутки резервируется всегда. Иначе её
   появление и исчезновение меняет ширину страницы: таблицы со своей прокруткой
   сначала рисуются во всю высоту, страница получает полосу, а когда скрипт
   ограничит высоту таблицы — полоса пропадает, и вся вёрстка скачком
   расширяется на её ширину */
html { scrollbar-gutter: stable; }

:root {
    --menu-width: 260px;
    --navbar-height: 3.5rem;
    /* Светлее болотного bs-success (#198754): тот на тёмном фоне почти не читается */
    --breadcrumb-accent: #4ade80;
}

[data-bs-theme="light"] { --breadcrumb-accent: #198754; }

/* Иконка в переключателе темы: показываем ту, на которую переключимся */
.theme-icon-light { display: none; }

[data-bs-theme="light"] .theme-icon-dark  { display: none; }
[data-bs-theme="light"] .theme-icon-light { display: inline-block; }

/* Навбар выше выдвижной панели: иначе она накрывает левый угол вместе
   с кнопкой-гамбургером, и закрыть меню становится нечем */
.navbar {
    position: sticky;
    top: 0;
    z-index: 1060;
    min-height: var(--navbar-height);
    background: var(--bs-body-bg);
}

/* Путь до текущей страницы в шапке — зелёный, вместе с разделителями: это
   единственная меняющаяся часть навбара, и цвет отделяет её от названия
   приложения. Активному элементу нужен свой селектор — у Bootstrap для него
   отдельная переменная цвета */
.navbar .breadcrumb-item,
.navbar .breadcrumb-item.active,
.navbar .breadcrumb-item + .breadcrumb-item::before {
    color: var(--breadcrumb-accent);
}

/* ── Выдвижная панель меню ─────────────────────────────────────────────────── */

.side-menu {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--menu-width);
    z-index: 1045;
    overflow-y: auto;
    padding-top: var(--navbar-height);
    background: var(--bs-body-bg);
    transform: translateX(-100%);
    transition: transform .2s ease;
}

body.menu-open .side-menu { transform: translateX(0); }

/* Во время перетаскивания сплиттера анимация мешает — ширина должна
   следовать за курсором мгновенно */
body.menu-resizing .side-menu,
body.menu-resizing .page-content { transition: none; }

body.menu-resizing { cursor: col-resize; user-select: none; }

/* На широких экранах панель раздвигает контент, на узких — накрывает его */
@media (min-width: 992px) {
    body.menu-open .page-content { margin-left: var(--menu-width); }
    .page-content { transition: margin-left .2s ease; }
}

.menu-overlay {
    position: fixed;
    inset: 0;
    z-index: 1040;
    background: rgba(0, 0, 0, .45);
    opacity: 0;
    visibility: hidden;
    transition: opacity .2s ease, visibility .2s ease;
}

body.menu-open .menu-overlay { opacity: 1; visibility: visible; }

@media (min-width: 992px) {
    .menu-overlay { display: none; }
}

/* ── Сплиттер ширины панели ────────────────────────────────────────────────── */

.menu-resizer {
    position: fixed;
    top: 0;
    bottom: 0;
    left: var(--menu-width);
    width: 6px;
    margin-left: -3px;
    z-index: 1046;
    cursor: col-resize;
    display: none;
}

body.menu-open .menu-resizer { display: block; }

.menu-resizer::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 2px;
    width: 2px;
    background: transparent;
    transition: background .15s ease;
}

.menu-resizer:hover::after,
body.menu-resizing .menu-resizer::after { background: var(--bs-primary); }

/* На узких экранах панель накрывает контент целиком — тянуть нечего */
@media (max-width: 991.98px) {
    .menu-resizer { display: none !important; }
}

/* ── Дерево меню ───────────────────────────────────────────────────────────── */

.menu-tree a.menu-leaf {
    display: block;
    padding: .4rem 1rem .4rem 1.25rem;
    color: var(--bs-body-color);
    text-decoration: none;
    font-size: .9rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.menu-tree a.menu-leaf:hover { background: var(--bs-secondary-bg); }

.menu-tree a.menu-leaf.is-active {
    background: var(--bs-primary);
    color: #fff;
}

/* Пункт, по которому только что кликнули: жёлтым, пока страница грузится.
   Синим (is-active) он станет уже на новой странице, а до неё бывает несколько
   секунд — без отклика кажется, что клик не сработал. Часики в конце строки
   рисует CSS, отдельного элемента для них не нужно */
.menu-tree a.menu-leaf.is-loading {
    background: #eab308;
    color: #212529;
}

.menu-tree a.menu-leaf.is-loading::after {
    content: ' ⏳';
    animation: chart-pulse 1s ease-in-out infinite;
}

.menu-branch > summary {
    padding: .45rem 1rem;
    cursor: pointer;
    font-size: .82rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--bs-secondary-color);
    list-style: none;
}

.menu-branch > summary::-webkit-details-marker { display: none; }

.menu-branch > summary::before {
    content: '▸';
    display: inline-block;
    width: 1em;
    transition: transform .15s ease;
}

.menu-branch[open] > summary::before { transform: rotate(90deg); }

.menu-branch a.menu-leaf { padding-left: 2.25rem; }

/* Закрытый select держим узким, длинное название обрезаем многоточием.
   Раскрытый список браузер всё равно расширяет по длине пунктов */
.market-select {
    max-width: 320px;
    text-overflow: ellipsis;
}

/* Там, где рядом в строке стоят флажок и два списка, рынок наоборот забирает
   всю свободную ширину: соседи держат свой размер, а он ужимается ровно
   настолько, чтобы «Свои и активные» помещались в окно */
.market-select-grow {
    flex: 1 1 auto;
    min-width: 0;
    max-width: none;
}

/* Выбор рынка выделен цветом: в строке подряд стоят три-четыре списка, и
   главный из них — этот. Тем же зелёным, что путь в шапке, — цвет в приложении
   уже означает «где вы находитесь» */
.market-pick {
    border-color: var(--breadcrumb-accent);
    font-weight: 500;
}

.market-pick:focus {
    border-color: var(--breadcrumb-accent);
    box-shadow: 0 0 0 .2rem rgba(74, 222, 128, .25);
}

/* ── График ────────────────────────────────────────────────────────────────── */

/* График тянется по доступной ширине, но ужимается не бесконечно: ниже
   минимума появляется горизонтальная прокрутка вместо нечитаемой каши */
.chart-scroll { overflow-x: auto; }

/* Полоса загрузки поверх всей страницы. Нужна там, где часиков нет вовсе
   («Главная», списки сделок) и когда панель меню задвинута: без неё переход
   выглядит так, будто клик не сработал. Ширина ползёт к 90% и там замирает —
   сколько именно осталось ждать, браузер не знает, а дорисовать до конца
   нечестно: страница сменится сама, когда придёт ответ */
@keyframes page-busy-grow {
    0%   { width: 0; }
    40%  { width: 55%; }
    100% { width: 90%; }
}

.page-busy {
    position: fixed;
    top: 0;
    left: 0;
    height: 3px;
    width: 0;
    z-index: 2000;
    background: var(--breadcrumb-accent);
    box-shadow: 0 0 8px var(--breadcrumb-accent);
    opacity: 0;
    transition: opacity .1s ease;
}

.page-busy.show {
    opacity: 1;
    animation: page-busy-grow 8s cubic-bezier(.2, .8, .3, 1) forwards;
}

/* «Часики» поверх графика на время чтения данных — как .kc-loading в BTC-5m:
   полупрозрачная накладка во всю область, ⏳ по центру, пульсация */
@keyframes chart-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: .4; }
}

.chart-loading {
    display: none;
    position: absolute;
    inset: 0;
    align-items: center;
    justify-content: center;
    font-size: 28px;
    border-radius: 6px;
    z-index: 10;
    background: rgba(14, 17, 23, .75);
    animation: chart-pulse 1s ease-in-out infinite;
}

[data-bs-theme="light"] .chart-loading { background: rgba(255, 255, 255, .75); }

.chart-loading.show { display: flex; }

/* Инлайновые часики: у счётчика рынков — на время живого поиска, у списка
   сделок и журнала баланса — пока страница перезагружается */
#marketBusy,
#tradesBusy,
#chartBusy {
    display: none;
    animation: chart-pulse 1s ease-in-out infinite;
}

#marketBusy.show,
#tradesBusy.show,
#chartBusy.show { display: inline; }

/* ── Раскладка «таблица слева, график справа» ──────────────────────────────── */

/* Используется страницами баланса и объёмов. Колонки не переносятся ни при
   какой ширине окна: график остаётся справа от таблицы, а когда места мало —
   прокручивается внутри своего поля. Перенос (flex-wrap) давал обратное:
   график уезжал под таблицу, а та растягивалась во всю ширину */
.split-body {
    --split-w: 460px;
    display: flex;
    flex-wrap: nowrap;
    gap: 0;
    align-items: flex-start;
}

/* Ширину таблицы задаёт сплиттер. Ужиматься ниже basis колонка может только
   когда окну совсем тесно, и не мельче 260 px — дальше таблица нечитаема
   и начинает прокручиваться сама */
.split-left {
    flex: 0 1 var(--split-w);
    min-width: 260px;
}

/* Высоту колонки задаёт скрипт в base.html — она зависит от того, на сколько
   строк легла шапка. Прокручивается внутри только поле графика (ниже) */
.split-right {
    flex: 1 1 0;
    min-width: 260px;
    overflow: hidden;
}

/* Карточка занимает колонку целиком, тело раскладывается в столбец: строка
   с кнопкой сброса зума прижата сверху, сводка — снизу, а всё, что не помещается
   по высоте, прокручивается в поле графика между ними. Прокручивать карточку
   целиком означало бы уводить из виду и кнопку, и сводку */
.split-right > .card,
.split-right > .card > .card-body,
.chart-fit,
.chart-fit > .card-body {
    height: 100%;
}

/* .chart-fit — та же карточка, но на странице без раскладки со сплиттером
   (страница цен): высоту ей тоже задаёт скрипт, и внутри так же прокручивается
   только поле графика */
.split-right > .card > .card-body,
.chart-fit > .card-body {
    display: flex;
    flex-direction: column;
}

.split-right .chart-scroll,
.chart-fit .chart-scroll {
    flex: 1 1 auto;
    overflow: auto;
    /* Без min-height flex-элемент не ужимается ниже своего содержимого, и
       вместо прокрутки графика колонка просто вылезает за экран */
    min-height: 0;
}

/* Графику отведён минимум ширины: когда таблицу растянули и поля не хватает,
   появляется горизонтальная прокрутка вместо нечитаемой каши. Минимум меньше,
   чем на странице цен, — здесь всего одна линия и столбики */
.split-right .chart-min-width { min-width: 420px; }

/* Сплиттер между таблицей и графиком */
.split-resizer {
    flex: 0 0 11px;
    align-self: stretch;
    min-height: 120px;
    cursor: col-resize;
    position: relative;
}

.split-resizer::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 5px;
    width: 2px;
    background: var(--bs-border-color);
    transition: background .15s ease;
}

.split-resizer:hover::after,
body.split-resizing .split-resizer::after { background: var(--bs-primary); }

body.split-resizing { cursor: col-resize; user-select: none; }

/* Сплиттер остаётся и на узком экране: колонки там тоже стоят рядом, и ширину
   таблицы как раз и нужно уменьшить, чтобы графику осталось поле */

/* Изменения в журнале — теми же цветами, что столбики на графике и колонка Δ
   в BTC-5m (.wallet-balance-pos/-neg в его main.css): связь строки и столбика
   видна сразу, а бутстраповский text-success (#198754) для этого слишком блёкл.
   Цвет обязательно дублируется для .table td: правило Bootstrap
   `.table > :not(caption) > * > *` задаёт ячейкам свой цвет и перебивает
   одиночный класс — из-за этого вся колонка Δ оказалась белой */
.delta-pos,
.table td.delta-pos { color: #3ecf6f; }

.delta-neg,
.table td.delta-neg { color: #e0544c; }

[data-bs-theme="light"] .delta-pos,
[data-bs-theme="light"] .table td.delta-pos { color: #16a34a; }

[data-bs-theme="light"] .delta-neg,
[data-bs-theme="light"] .table td.delta-neg { color: #d6372e; }

/* Сводка под графиком — три карточки в ряд, с переносом вниз, когда поле
   графика узкое */
/* Карточки со сводкой под графиком: сперва появились на «Балансе», теперь
   и на «Объёмах» — отсюда общее имя */
.chart-stats {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .5rem;
    margin-top: .5rem;
    /* В колонке с графиком сводка стоит последней и не ужимается: место
       отдаётся полю графика, а она остаётся прижатой к низу карточки */
    flex: 0 0 auto;
}

/* Ширина карточки — по её содержимому: числа в группах разной длины, и общая
   ширина растягивала бы узкие группы пустотой */
.stat-group {
    flex: 0 0 auto;
    border: 1px solid var(--bs-border-color);
    border-radius: .375rem;
    padding: .35rem .6rem .45rem;
    background: var(--bs-tertiary-bg);
}

.stat-title {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--bs-secondary-color);
    margin-bottom: .15rem;
}

.stat-row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    font-size: .78rem;
    line-height: 1.5;
}

.stat-row > span { color: var(--bs-secondary-color); }

/* Два значения в строке. Колонки авто-ширины: обе подстраиваются под самое
   длинное содержимое, поэтому подписи и числа стоят друг под другом, а карточка
   не шире, чем нужно. Столбцом она вырастала бы вдвое и отъедала высоту
   у графика, под которым стоит */
.stat-grid {
    display: grid;
    grid-template-columns: auto auto;
    column-gap: 1.25rem;
}

/* Итог под журналом баланса: продолжение таблицы, но вне её прокрутки, —
   колонки те же, поэтому ширины должны совпасть с основной таблицей */
.balance-total {
    table-layout: auto;
    border-top: 2px solid var(--bs-border-color);
    font-weight: 600;
}

/* Кнопка сброса зума: без зума обычная кнопка темы, при зуме мигает красным.
   Эмодзи, цвет и характер мигания взяты из BTC-5m (blink-red-bg в
   static/css/main.css): жёсткое переключение step-end, 0.7 сек, #e0544c.
   Отличие одно — «спокойная» фаза берёт цвета темы, а не фиксированные светлые */
@keyframes zoom-blink {
    0%, 100% {
        background: #e0544c;
        border-color: #e0544c;
        color: #fff;
        box-shadow: 0 0 8px rgba(224, 84, 76, .8);
    }
    50% {
        background: var(--bs-body-bg);
        border-color: var(--bs-border-color);
        color: var(--bs-body-color);
        box-shadow: none;
    }
}

#zoomReset.is-zoomed { animation: zoom-blink .7s step-end infinite; }

.chart-min-width { min-width: 640px; }

/* Переключатель порядка живёт в строке над списком рынков — рядом со счётчиком
   и кнопками листания, поэтому ужимаем его до высоты этой строки */
.market-sort {
    width: auto;
    height: 1.6rem;
    padding-top: 0;
    padding-bottom: 0;
    font-size: .75rem;
}

/* Форма добавления конкурента раскрывается через <details>: маркер-треугольник
   убираем, иначе <summary> не выглядит обычной кнопкой */
.add-user > summary {
    display: inline-block;
    list-style: none;
}

.add-user > summary::-webkit-details-marker { display: none; }

/* Таблица прокручивается сама, а не вместе со страницей: фильтры, итоги и
   пояснение над ней остаются на виду. Высота выставляется скриптом по остатку
   экрана — шапка страницы переносится по строкам и её высота заранее неизвестна */
.table-scroll {
    overflow: auto;
    border: 1px solid var(--bs-border-color);
    border-radius: .375rem;
    /* Запас высоты до того, как скрипт посчитает точный: без него таблица на
       первой отрисовке занимает всю свою длину и тянет страницу вниз. Значение
       заведомо меньше итогового — лишняя высота потом добавится, а вот убыль
       выглядела бы схлопыванием */
    max-height: calc(100vh - 320px);
}

/* Шапка столбцов закреплена внутри прокручиваемой области */
.table-scroll thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--bs-body-bg);
    box-shadow: inset 0 -1px 0 var(--bs-border-color);
}

/* Строка, выбранная кликом по графику. Цвет задаётся переменной Bootstrap:
   свой background таблица перебивает — у неё состояние строки рисуется
   внутренней тенью (.table > :not(caption) > * > *), и обычное правило
   проигрывает по весу */
.table tbody tr.is-picked > * {
    --bs-table-bg-state: rgba(234, 179, 8, .22);
}

/* Итог прилипает к низу области прокрутки — как шапка к верху. Отдельной
   таблицей под прокруткой (как на «Балансе») колонки рискуют разъехаться:
   здесь их семь, и ширины должны совпадать до пикселя */
.table-scroll tfoot td {
    position: sticky;
    bottom: 0;
    z-index: 1;
    background: var(--bs-body-bg);
    box-shadow: inset 0 2px 0 var(--bs-border-color);
    font-weight: 600;
}

/* Заголовки-ссылки сортировки: выглядят как обычный текст шапки, активный
   выделен цветом — стрелка направления подставляется шаблоном */
.sort-link {
    color: inherit;
    text-decoration: none;
    white-space: nowrap;
}

.sort-link:hover { text-decoration: underline; }

.sort-link.is-active {
    color: var(--bs-body-color);
    font-weight: 600;
}

/* Поле с номером страницы в листателе. Ширина под четыре цифры: строка
   листания и так тесная, а стрелки-крутилку браузер рисует внутри поля */
.page-jump {
    width: 4.2rem;
    text-align: center;
    padding-left: .25rem;
    padding-right: .25rem;
}

/* ── polydata_web ────────────────────────────────────────────────────────────
   Левая колонка сплиттера той же высоты, что правая: высоту обеим ставит
   скрипт в base.html, а таблица растягивается на всё место под строкой
   листания. Без этого у таблицы оставался запасной max-height из
   .table-scroll, и она выходила ниже карточки справа */
.split-left {
    display: flex;
    flex-direction: column;
}
.split-left > .table-scroll {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
}

/* Полосы прокрутки тоньше стандартных: в таблице событий и карточке превью
   их две рядом, и обычная ширина Windows (17 px) заметно отъедала место.
   scrollbar-width — стандартное свойство (Chrome 121+, Firefox); цвет
   полупрозрачный серый, чтобы одинаково смотреться в тёмной и светлой теме.
   ::-webkit-scrollbar — для браузеров, где стандартного свойства ещё нет */
* {
    scrollbar-width: thin;
    scrollbar-color: rgba(128, 128, 128, .55) transparent;
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: rgba(128, 128, 128, .55); border-radius: 5px; }
::-webkit-scrollbar-track { background: transparent; }

/* «Часики» на всю страницу при долгом чтении — в дополнение к полоске сверху,
   которая на тёмном фоне почти не заметна. Тот же вид, что у часиков над
   графиками (.chart-loading): полупрозрачная накладка и пульсирующие ⏳.
   Показываются с задержкой (base.html), чтобы не мигать на быстрых переходах */
.page-clock {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1999;
    align-items: center;
    justify-content: center;
    background: rgba(14, 17, 23, .55);
}
[data-bs-theme="light"] .page-clock { background: rgba(255, 255, 255, .55); }
.page-clock.show { display: flex; }
.page-clock > div {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .25rem;
    padding: 1rem 1.5rem;
    border-radius: .5rem;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    box-shadow: 0 4px 16px rgba(0, 0, 0, .25);
    animation: chart-pulse 1s ease-in-out infinite;
}
.page-clock .page-clock-icon { font-size: 2.2rem; line-height: 1; }

