/* Оформление скринера.

   Палитра построена вокруг тёмно-серого #141414 и намеренно
   малоконтрастная: на карту смотрят часами, и всё, что не данные, должно
   уходить в фон. Цветом выделены только две вещи — стороны стакана и то,
   на что можно нажать.

   Поверхности идут ступенями: утопленные поля, страница, панели,
   островки, приподнятое. Ступени мелкие, но каждая различима — иначе
   поле ввода сливается с секцией, в которой лежит.

   Хэдер собран из трёх «островков»: плавающих панелей со своим фоном и
   скруглением. Между ними виден фон страницы — так шапка не превращается
   в сплошную полосу и не давит на рабочую область. */

:root {
  /* Оттенки набраны вокруг #141414 и намеренно нейтральны: любая примесь
     синевы на этом фоне читается как грязь. Ступени мелкие — поверхности
     различаются, но ни одна не выпрыгивает. */
  --sunken: #121212;   /* поля ввода — утоплены глубже всего */
  --bg: #141414;       /* страница */
  --bg-glow: #171717;  /* свечение по центру */
  --panel: #191919;    /* окна и секции внутри диалога */
  --island: #1e1e1e;   /* островки шапки, диалоги, меню */
  --raised: #262626;   /* колонки, наведение, приподнятые строки */
  --panel-edge: #2b2b2b;
  --island-edge: #333333;
  --edge-hover: #3d3d3d;

  /* Текст с едва заметной прохладой: чистый серый на сером выглядит
     плоско, а заметный оттенок спорит с нейтральным фоном.

     Приглушённый подтянут вслед за фоном: на прежнем почти чёрном он
     читался, а на #141414 просел до трёх к одному — это уже на грани. */
  --text: #e3e4e6;
  --text-dim: #9a9ca1;
  --text-faint: #7c7e83;

  /* Фон стал светлее — подложки и акцент подняты, иначе теряются. */
  --accent: #6b8afc;
  --accent-soft: rgba(107, 138, 252, 0.16);
  --accent-edge: rgba(107, 138, 252, 0.5);

  --bid: #35c98f;
  --bid-bg: rgba(53, 201, 143, 0.15);
  --ask: #e8606e;
  --ask-bg: rgba(232, 96, 110, 0.15);
  --warn: #e0aa4a;

  --header-h: 52px;
  --radius: 12px;
  --radius-sm: 8px;

  /* Кнопка выбора и её выпадающий список одной ширины: иначе список
     выезжает шире кнопки и выглядит съехавшим вбок. */
  --picker-w: 216px;
}

/* Псевдоэлементы перечислены отдельно: звёздочка их не покрывает, и без
   этого граница добавляется к заданному размеру. Значки, нарисованные
   границей, оказываются крупнее и смещаются от центра ровно на её
   толщину. */
*,
*::before,
*::after { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;
}

body {
  background: var(--bg);
  color: var(--text);
  font: 13px/1.45 "Inter", "Segoe UI", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* Мягкое свечение по центру — единственное украшение фона. Оно же
   подсказывает, где середина рабочей области, когда она пуста. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  background: radial-gradient(75% 70% at 50% 45%, var(--bg-glow), transparent 80%);
  pointer-events: none;
  z-index: 0;
}

button, input, select { font: inherit; color: inherit; }
button { cursor: pointer; border: none; background: none; }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: #303030; border-radius: 4px; }
::-webkit-scrollbar-track { background: transparent; }

/* ------------------------------------------------------------ хэдер */
.topbar {
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--header-h);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 12px;
  z-index: 100;
  pointer-events: none;
}

.island {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding: 0 6px;
  background: var(--island);
  border: 1px solid var(--island-edge);
  border-radius: var(--radius);
  pointer-events: auto;
}

.island.brand {
  padding: 0 12px;
  font-weight: 600;
  letter-spacing: 0.2px;
}
.brand .mark { color: var(--text-faint); font-weight: 500; }
.brand .name { color: var(--text); }

.topbar .spacer { flex: 1; pointer-events: none; }

/* --- островок состояния потока --- */
.stat {
  display: flex;
  align-items: baseline;
  gap: 5px;
  padding: 0 8px;
  color: var(--text-faint);
  white-space: nowrap;
}
.stat b { color: var(--text-dim); font-weight: 600; }

.dot {
  width: 7px;
  height: 7px;
  margin: 0 2px 0 6px;
  border-radius: 50%;
  background: var(--text-faint);
  flex: none;
  transition: background 0.3s, box-shadow 0.3s;
}
.dot.live {
  background: var(--bid);
  box-shadow: 0 0 8px rgba(53, 201, 143, 0.5);
}

.island .divider {
  width: 1px;
  height: 16px;
  background: var(--island-edge);
  flex: none;
}

/* --- кнопки внутри островков --- */
.icon-button {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-sm);
  color: var(--text-dim);
  flex: none;
}
.icon-button:hover { background: var(--raised); color: var(--text); }
.icon-button.on { color: var(--warn); }

.picker { position: relative; display: flex; align-items: center; gap: 2px; }
/* Список ровно под своей кнопкой, а не шире её. */
.picker .menu { width: var(--picker-w); }

.picker-button {
  display: flex;
  align-items: center;
  gap: 8px;
  width: var(--picker-w);
  height: 26px;
  padding: 0 10px;
  border-radius: var(--radius-sm);
  color: var(--text-dim);
  white-space: nowrap;
  transition: color 0.15s;
}
.picker-button:hover { background: var(--raised); color: var(--text); }
/* Стрелка светлеет вместе с надписью: у неё свой приглушённый цвет, и
   без этого она осталась бы тусклой рядом с прояснившимся текстом. */
.picker-button:hover .caret { color: var(--text); }
.picker-button.open { background: var(--accent-soft); color: var(--accent); }
.picker-button > span:first-child {
  flex: 1;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Стрелки нарисованы уголком из двух границ, а не символом: символ
   зависит от шрифта, прыгает по базовой линии и не поворачивается вокруг
   своего центра. Уголок ведёт себя одинаково везде. */
.caret,
.chevron {
  position: relative;
  width: 10px;
  height: 10px;
  flex: none;
  color: var(--text-faint);
  transition: transform 0.2s ease;
}
.caret::before,
.chevron::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 7.5px;
  height: 7.5px;
  border-right: 1.6px solid currentColor;
  border-bottom: 1.6px solid currentColor;
}
/* Вниз — для выпадающих списков. */
.caret::before { transform: translate(-50%, -70%) rotate(45deg); }
/* Вправо — для раскрывающихся секций. */
.chevron::before { transform: translate(-70%, -50%) rotate(-45deg); }

.open > .caret,
.select-button.open .caret { transform: rotate(180deg); }
.section.open > .section-head .chevron,
.section.open > .exchange-row .chevron { transform: rotate(90deg); }

.menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: var(--picker-w);
  max-height: 60vh;
  overflow-y: auto;
  padding: 6px;
  background: var(--island);
  border: 1px solid var(--island-edge);
  border-radius: var(--radius);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.5);
  display: none;
  z-index: 200;
}
.menu.open {
  display: block;
  animation: drop 0.16s ease-out;
}

@keyframes drop {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: none; }
}
.menu-empty { padding: 14px; color: var(--text-faint); text-align: center; }

.menu-item {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  text-align: left;
  color: var(--text);
  /* Строки списка — не кнопки, а div-ы, и указатель им нужен явно:
     нажимается вся строка целиком, включая галочку слева. */
  cursor: pointer;
}
.menu-item:hover { background: var(--raised); }
.menu-item.active { background: var(--accent-soft); }
.menu-item .title { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.menu-item .title > span:first-child { overflow: hidden; text-overflow: ellipsis; }
.menu-item .subtitle { color: var(--text-faint); font-size: 11px; }
.menu-item .row-action {
  color: var(--text-faint);
  padding: 2px 6px;
  border-radius: 6px;
  flex: none;
}
.menu-item .row-action:hover { background: var(--island-edge); color: var(--text); }
/* Удаление подсвечивается красным, как крестик в шапке окна: действие
   одно и то же, и выглядеть оно должно одинаково. Правка рядом — нет:
   она ничего не теряет. */
.menu-item .row-action.danger:hover { background: var(--ask-bg); color: var(--ask); }
.menu-item[disabled] { opacity: 0.4; cursor: default; }

/* Галочка выбора вкладки — квадрат с плотной заливкой, как в образце. */
.tick {
  width: 15px;
  height: 15px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 4px;
  border: 1px solid var(--panel-edge);
  background: var(--sunken);
  color: transparent;
  font-size: 10px;
  transition: background 0.18s, border-color 0.18s, color 0.18s;
}
.tick.on { background: var(--accent); border-color: var(--accent); color: #fff; }

/* ------------------------------------------------- рабочая область */
.workspace {
  position: fixed;
  inset: var(--header-h) 0 0 0;
  overflow: hidden;
  z-index: 1;
}

.placeholder {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  gap: 6px;
  text-align: center;
  color: var(--text-faint);
  pointer-events: none;
}
.placeholder .big {
  font-size: 34px;
  font-weight: 700;
  letter-spacing: 10px;
  color: #232323;
  margin-bottom: 6px;
}
kbd {
  display: inline-block;
  padding: 1px 6px;
  border: 1px solid var(--panel-edge);
  border-radius: 5px;
  background: var(--panel);
  color: var(--text-dim);
  font-size: 11px;
}

/* ------------------------------------------------------------ окна */
.window {
  position: absolute;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--panel-edge);
  border-radius: var(--radius);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45);
  overflow: hidden;
}
/* Перетаскивание отмечено только тенью: прозрачное окно мешает
   попадать в место, куда его несёшь. */
.window.dragging { box-shadow: 0 26px 60px rgba(0, 0, 0, 0.6); }

/* Вкладка, открытая в своём окне браузера. Двигать и растягивать её
   больше нечем — этим занимается оконный менеджер, — поэтому окно
   распахнуто на всю страницу и лишено собственных полей и тени. */
body.detached .topbar,
body.detached .placeholder,
.window.alone .resizer { display: none; }
body.detached .workspace { inset: 0; }
.window.alone {
  position: absolute;
  inset: 0;
  width: auto;
  height: auto;
  border: none;
  border-radius: 0;
  box-shadow: none;
}
.window.alone .window-head { cursor: default; }

.window-head {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  padding: 0 8px 0 12px;
  border-bottom: 1px solid var(--panel-edge);
  cursor: grab;
  flex: none;
  user-select: none;
}

/* Пока тащат окно или меняют размер, курсор ходит по всей странице —
   без этого браузер принимает движение за выделение текста. */
body.busy, body.busy * { user-select: none !important; }
.window.dragging .window-head { cursor: grabbing; }
.window-head .glyph { color: var(--text-faint); }
.window-head .name { font-weight: 600; }
.window-head .meta { color: var(--text-faint); font-size: 11px; }
.window-head .spacer { flex: 1; }

/* Текст в шапке уступает кнопкам, а не наоборот.

   Без min-width: 0 текст не сжимается ниже самого длинного своего слова,
   а кнопки не сжимаются вовсе (flex: none) — значит, выдавливает их, и
   первым уходит крайний правый. На минимальной ширине вкладки (MIN_W,
   280px) шапке нужно было 333px, и крестик уезжал за край на 54px; окно
   обрезает вылезшее, то есть удалить вкладку становилось нечем.

   Счётчик монет сдаётся первым: название вкладки человек задал сам, а
   счётчик виден и на карте. */
.window-head .name,
.window-head .meta {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.window-head .meta { flex-shrink: 999; }

.window-action {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-sm);
  color: var(--text-faint);
  flex: none;
}
.window-action:hover { background: var(--raised); color: var(--text); }
.window-action.danger:hover { background: var(--ask-bg); color: var(--ask); }
.window-action[disabled] { opacity: 0.45; cursor: not-allowed; }
.window-action[disabled]:hover { background: none; color: var(--text-faint); }

/* То же и в окне: колонки появляются и исчезают постоянно, а вместе с
   ними — полоса прокрутки. */
.window-body {
  flex: 1;
  overflow: auto;
  padding: 10px;
  scrollbar-gutter: stable;
}
.window-empty {
  height: 100%;
  display: grid;
  place-content: center;
  color: var(--text-faint);
}

.resizer {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 16px;
  height: 16px;
  cursor: nwse-resize;
  user-select: none;
}
.resizer::after {
  content: "";
  position: absolute;
  right: 4px;
  bottom: 4px;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--panel-edge);
  border-bottom: 2px solid var(--panel-edge);
}

/* --------------------------------------------------- карта плотностей */
/* Карточки расставляет JS (packColumns), а не поток: каждая уходит в тот
   столбец, который сейчас ниже всех. Переносом строк это не сделать —
   там высота ряда равна самой высокой карточке в нём, и под низкими
   остаётся пустота. Высоту полотна тоже проставляет JS: у контейнера с
   вынутыми из потока детьми своей высоты нет. */
.columns {
  position: relative;
  /* Наименьшая ширина карточки: от неё packColumns считает, сколько
     столбцов влезет, а дальше растягивает их на всё полотно без
     остатка. Ниже этого числа четыре колонки строки уровня начинают
     жать друг друга. Саму ширину проставляет JS — держать её ещё и
     здесь значит однажды разойтись с ним молча. */
  --column-min: 204px;
}

.column {
  position: absolute;
  top: 0;
  left: 0;
  background: var(--raised);
  border: 1px solid var(--panel-edge);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.column:hover { border-color: var(--edge-hover); }

.column-head {
  position: relative;   /* под плашку «Скопировано» */
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 9px;
  border-bottom: 1px solid var(--panel-edge);
}
/* По названию монеты щёлкают, чтобы его скопировать. Курсор — вся
   подсказка: подпись рядом с каждой монетой съела бы шапку столбика, а
   всплывающая есть в title. Ответ на нажатие — цвет, который наливается,
   а не щёлкает: зелёный при удаче и красный при отказе буфера. */
/* Имя не растянуто на всю шапку, а занимает только себя: иначе галочка,
   стоящая следом, уезжала бы к самым значкам вместо того, чтобы стоять
   рядом с текстом. Место до значков держит распорка после неё. */
.column-head .symbol {
  font-weight: 600;
  letter-spacing: 0.4px;
  color: var(--text);
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}
.column-head .spacer { flex: 1; }
/* Цвет имени идёт по тем же долям времени, что и плашка (см. @keyframes
   copied ниже): разгорается к 12%, держится до 72%, гаснет к концу. Так
   он возвращается к прежнему ровно тогда, когда плашка исчезает, а не
   спустя собственный переход после неё. */
.column-head .symbol.copied { animation: copied-name 1.1s ease forwards; }
.column-head .symbol.copy-failed { animation: failed-name 1.1s ease forwards; }
@keyframes copied-name {
  0% { color: var(--text); }
  12%, 72% { color: var(--bid); }
  100% { color: var(--text); }
}
@keyframes failed-name {
  0% { color: var(--text); }
  12%, 72% { color: var(--ask); }
  100% { color: var(--text); }
}

/* Галочка — сразу за названием монеты, и только при удаче.

   Нарисована границами, а не набрана символом — как ⊘ и воронка рядом.
   Символ ✓ в разных шрифтах сидит по-разному и почти всегда чуть выше
   середины; на десяти пикселях это видно.

   Рисуется прямо на этом узле, без вложенного. Вложенный назывался .tick,
   а такой класс в проекте уже занят — это квадрат с тёмной заливкой в
   списке вкладок. Заливка и рамка достались галочке молча, и вместо
   уголка выходил тёмный кругляшок. */
.copied-tick {
  position: relative;
  display: inline-block;
  width: 10px;
  height: 10px;
  flex: none;
  color: var(--bid);
  animation: copied 1.1s ease forwards;
}
.copied-tick::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 0;
  width: 4px;
  height: 9px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
}

/* Плашка о копировании — в правом нижнем углу окна браузера.

   Место одно на всю страницу, а не своё у каждого столбика: в шапке она
   накрывала собой название и значки, ради которых по столбику и щёлкают.
   Заводится по нажатию и уходит по концу своей анимации — держать её
   скрытой ради секунды в час незачем.

   Выше диалогов (z-index 300): скопировать можно и при открытой форме, и
   ответ должен быть виден. */
.copied-note {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 400;
  padding: 9px 14px;
  border-radius: var(--radius);
  background: var(--island);
  border: 1px solid var(--bid);
  color: var(--bid);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  pointer-events: none;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
  animation: copied-toast 1.1s ease forwards;
}
.copied-note.failed { border-color: var(--ask); color: var(--ask); }

/* Доли времени у всех троих одни: имя, галочка и плашка загораются к 12%
   и гаснут к концу, поэтому исчезают вместе. */
@keyframes copied {
  0% { opacity: 0; }
  12%, 72% { opacity: 1; }
  100% { opacity: 0; }
}
/* Плашка выезжает из-за правого края и туда же уходит: движение вдоль
   ближней к ней стороны окна читается как «выехала», а не «возникла». */
@keyframes copied-toast {
  0% { opacity: 0; transform: translateX(28px); }
  12%, 72% { opacity: 1; transform: translateX(0); }
  100% { opacity: 0; transform: translateX(28px); }
}

/* Значок биржи — в шапке столбика и в строке биржи в настройках.

   Размера здесь нет намеренно: он стоит атрибутами на самой картинке
   (см. exchangeIcon в app.js). Файлы приходят от бирж величиной до двух
   с половиной тысяч пикселей, и значок, чей размер живёт только тут,
   разносит вёрстку всякий раз, когда стиль до браузера не доехал.

   Остальное — то, чего атрибутами не выразить: картинка вписывается в
   площадку целиком, иначе широкий логотип вышел бы сплющенным. */
.exchange-icon {
  flex: none;
  object-fit: contain;
  border-radius: 4px;
}
/* Значок занимает место всегда, а по наведению только проявляется. Убери
   его из потока — и заголовок станет на пиксель ниже, а вся карточка
   дёрнется вверх, стоит увести курсор. */
.column-head .tool {
  position: relative;
  width: 20px;
  height: 20px;
  flex: none;
  border-radius: 5px;
  color: var(--text-faint);
  font-size: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s;
}
.column:hover .tool { opacity: 1; pointer-events: auto; }
.column-head .tool:hover { background: var(--panel); color: var(--text); }
/* У монеты со своим порогом воронка видна всегда: иначе непонятно,
   почему она отбирается не так, как соседние. */
.column-head .tool.on {
  opacity: 1;
  pointer-events: auto;
  color: var(--accent);
}

/* Оба значка нарисованы, а не набраны символами: ⊘ и воронка в разных
   шрифтах сидят по-разному и почти всегда чуть выше середины — в кнопке
   двадцать на двадцать это заметно.

   Части центрует translate, а не отрицательные поля: поля пришлось бы
   считать вручную как половину от дробного размера, и полоска в
   1,4 пикселя с отступом −0,7 садилась между физическими пикселями —
   браузер размазывал её на две строки неровно, и она уезжала с центра.
   Проценты в translate он считает сам и от настоящего размера. */
.tool::before,
.tool.block::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
}
.tool.block::before {
  width: 11px;
  height: 11px;
  border: 1.4px solid currentColor;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

/* Воронка вырезана из прямоугольника, а не собрана из границ: у неё
   косые рёбра, и границами их пришлось бы имитировать наклонённым
   треугольником — тот сидит по центру хуже и мылится по краям. */
.tool.filter::before {
  width: 12px;
  height: 11px;
  background: currentColor;
  transform: translate(-50%, -50%);
  clip-path: polygon(
    0 0, 100% 0, 100% 16%, 61% 52%,
    61% 100%, 39% 86%, 39% 52%, 0 16%
  );
}
/* Полоска короче кружка: одиннадцать — это внешний край, и на такой
   длине углы наклонённой полоски вылезали бы за границу. Десять
   упирается в кольцо изнутри и не торчит наружу. */
.tool.block::after {
  width: 10px;
  height: 1.4px;
  background: currentColor;
  transform: translate(-50%, -50%) rotate(-45deg);
}

/* Порог одной монеты. Панель плавает над картой на месте, куда её
   поставил скрипт, поэтому у неё фиксированное положение и свой слой:
   колонка под ней перерисовывается каждую секунду. */
.coin-filter {
  position: fixed;
  width: 248px;
  padding: 12px 14px 14px;
  background: var(--island);
  border: 1px solid var(--island-edge);
  border-radius: var(--radius);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.5);
  z-index: 300;
  animation: drop 0.16s ease-out;
}
.coin-filter-head {
  display: flex;
  align-items: center;
  margin-bottom: 8px;
}
.coin-filter-head .symbol {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 700;
  letter-spacing: 0.4px;
  color: var(--accent);
}
.coin-filter-where {
  margin: 10px 0 2px;
  color: var(--text-faint);
  font-size: 10px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
}
.coin-filter-where:first-of-type { margin-top: 0; }
.coin-filter .thresholds td:first-child { color: var(--text-dim); font-size: 12px; }
.coin-filter .unit { color: var(--text-faint); font-size: 11px; }
.coin-filter-foot { display: flex; gap: 8px; margin-top: 12px; }
.coin-filter-foot .button { flex: 1; height: 32px; padding: 0 10px; }

.market-label {
  padding: 4px 9px 2px;
  font-size: 10px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* Четыре колонки в двухсот пикселях помещаются впритык, поэтому каждая
   умеет сжиматься: без minmax(0, …) колонка цены упирается в свою
   минимальную ширину, грид становится шире карточки и выдавливает
   расстояние за край. Многоточие — страховка на длинные значения. */
/* Отступы по бокам ровно такие же, какие у шапки столбика и у подписи
   рынка (9px до текста): строка отходит от стенок на 5px полем, и ещё
   4px добирает своим отступом. Разойдись эти числа — цифры поехали бы
   относительно названия монеты над ними.

   Отступ только снизу: сверху строку и так отделяет либо подпись рынка,
   либо нижний отступ соседки. Поле сверху добавило бы к нему второе —
   схлопнулись бы они в одно или нет, лишний просвет под подписью рынка
   виден в любом случае. */
.level {
  display: grid;
  grid-template-columns: 40px 32px minmax(0, 1fr) minmax(0, 34px);
  align-items: center;
  gap: 5px;
  margin: 0 5px 5px;
  padding: 3px 4px;
  border-radius: 5px;
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
}
.level > span {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* Крупная плотность видна размером заливки.

   Строка залита от левого края на свою долю от самой крупной плотности
   этой вкладки (--share, ставит updateLevel). Тускло-ровный фон, как
   было, говорит только сторону стакана: стенка в тридцать миллионов и
   стенка в триста тысяч выглядели одинаково, и найти крупную можно было
   только читая цифры подряд.

   Второй слой, а не замена: слабый фон остаётся под заливкой и держит
   сторону читаемой даже у самых мелких строк, где заливки почти нет. */
.level.bid,
.level.ask {
  background-image: linear-gradient(
    to right,
    var(--fill) calc(var(--share, 0) * 100%),
    transparent calc(var(--share, 0) * 100%)
  );
}
/* Заливка приглушена нарочно: она под цифрами, и яркая полоса спорит с
   ними за внимание — читать надо объём, а полоса лишь подсказывает, куда
   смотреть в первую очередь. */
.level.bid { background-color: var(--bid-bg); --fill: rgba(53, 201, 143, 0.17); }
.level.ask { background-color: var(--ask-bg); --fill: rgba(232, 96, 110, 0.17); }
.level.bid .amount { color: var(--bid); }
.level.ask .amount { color: var(--ask); }
.level .amount { font-weight: 600; }
.level .age { color: var(--text-faint); font-size: 10.5px; }
.level .price { text-align: right; }
.level .dist { color: var(--text-dim); text-align: right; font-size: 10.5px; }
.level.fresh { box-shadow: inset 2px 0 0 var(--accent); }

.spread-row {
  padding: 2px 9px;
  color: var(--text-faint);
  font-size: 10px;
  text-align: center;
  border-block: 1px solid var(--panel-edge);
}

/* --------------------------------------------------------- диалоги */
.overlay {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: none;
  place-items: center;
  padding: 24px;
  background: rgba(10, 10, 10, 0.74);
  backdrop-filter: blur(3px);
}
.overlay.open { display: grid; animation: veil 0.18s ease-out; }

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

.dialog {
  width: min(560px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--island);
  border: 1px solid var(--island-edge);
  border-radius: 14px;
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.55);
  overflow: hidden;
  animation: rise 0.2s cubic-bezier(0.2, 0.9, 0.3, 1);
}

@keyframes rise {
  from { opacity: 0; transform: translateY(12px) scale(0.985); }
  to { opacity: 1; transform: none; }
}

/* Настройки скринера — во всю высоту: секций много, и прыгающая от
   раскрытия высота диалога читается хуже, чем прокрутка внутри него. */
#density-dialog .dialog { height: 100%; }

.dialog-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 16px 14px 12px 20px;
  flex: none;
}
.dialog-head h2 { margin: 0; font-size: 17px; font-weight: 600; }
.dialog-head .spacer { flex: 1; }

/* Место под полосу прокрутки держится всегда. Иначе она появляется при
   раскрытии секции и исчезает при сворачивании, каждый раз сдвигая
   содержимое вбок. */
.dialog-body {
  padding: 0 20px 4px;
  overflow-y: auto;
  flex: 1;
  scrollbar-gutter: stable;
}
.dialog-foot {
  display: flex;
  gap: 10px;
  padding: 14px 20px 18px;
  flex: none;
}
.dialog-foot .button { flex: 1; }

.button {
  height: 38px;
  padding: 0 18px;
  border-radius: 10px;
  background: var(--raised);
  border: 1px solid var(--panel-edge);
  color: var(--text);
}
.button:hover { border-color: var(--edge-hover); }
.button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 600;
}
.button.primary:hover { filter: brightness(1.08); }
.button.ghost { background: none; border-color: transparent; color: var(--text-dim); }
.button.ghost:hover { color: var(--ask); border-color: var(--ask-bg); }
/* Кнопка, подтверждающая удаление. Не залита целиком, как основная:
   красная заливка тянет нажать её первой, а первой здесь должна быть
   «Отмена» — диалог для того и открыли, что промах дорог. */
.button.danger {
  background: var(--ask-bg);
  border-color: var(--ask-bg);
  color: var(--ask);
  font-weight: 600;
}
.button.danger:hover { border-color: var(--ask); }

/* --------------------------------------------------- поля и секции */
.field { margin-bottom: 14px; }
.field > label {
  display: block;
  margin-bottom: 6px;
  color: var(--text-dim);
  font-size: 12px;
}

.input {
  width: 100%;
  height: 36px;
  padding: 0 12px;
  border-radius: 10px;
  background: var(--sunken);
  border: 1px solid var(--panel-edge);
  color: var(--text);
  outline: none;
}
.input:focus { border-color: var(--accent-edge); }
.input::placeholder { color: var(--text-faint); }

/* Свой выпадающий список: системный нельзя оформить — его раскрытую
   часть рисует операционная система, и посреди тёмной страницы она
   выглядит чужой. */
.select { position: relative; }
.select-button {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  height: 36px;
  padding: 0 12px;
  border-radius: 10px;
  background: var(--sunken);
  border: 1px solid var(--panel-edge);
  color: var(--text);
  text-align: left;
}
.select-button:hover { border-color: var(--edge-hover); }
.select-button.open { border-color: var(--accent-edge); }
.select-button .value { flex: 1; overflow: hidden; text-overflow: ellipsis; }
.select-button .caret { color: var(--text-faint); font-size: 10px; }
.select .menu { left: 0; right: 0; min-width: 0; }
.select .menu-item .title { display: block; }

/* Подсказки поиска монеты. Список висит поверх страницы, а не внутри
   секции: секция подрезает содержимое ради анимации раскрытия, и список
   в ней обрывался бы по её нижнему краю. Положение и ширину задаёт
   скрипт — он держит их по полю. */
.symbol-menu {
  position: fixed;
  top: auto;
  right: auto;
  min-width: 0;
  max-height: 264px;
  z-index: 300;
  font-variant-numeric: tabular-nums;
}

/* Раскрытие вверх — для списков у нижнего края формы. */
.menu.up {
  top: auto;
  bottom: calc(100% + 8px);
}
.menu.up.open { animation: lift 0.16s ease-out; }

@keyframes lift {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

.hint { margin-top: 6px; color: var(--text-faint); font-size: 11px; }
.error-box {
  display: none;
  margin-bottom: 12px;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--ask-bg);
  border: 1px solid rgba(232, 96, 110, 0.32);
  color: #f3aab1;
}
.error-box.show { display: block; }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.row { display: flex; align-items: center; gap: 10px; }
.row > .grow { flex: 1; }

/* Секция-гармошка: заголовок-кнопка и тело, которое сворачивается. */
.section {
  margin-bottom: 10px;
  background: var(--panel);
  border: 1px solid var(--panel-edge);
  border-radius: 10px;
  overflow: hidden;
}
.section-head {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  text-align: left;
  color: var(--text);
}
.section-head:hover { background: var(--raised); }
.section-head .title { flex: 1; font-weight: 500; }

/* Раскрытие анимируется через дробную долю строки сетки: высоту
   содержимого заранее знать не нужно, а переход выходит плавным.
   Отступы живут на внутреннем слое, иначе свёрнутая секция осталась бы
   толщиной в собственные поля. */
.section-body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.22s ease;
}
.section.open .section-body { grid-template-rows: 1fr; }
.section-inner { min-height: 0; overflow: hidden; }
.section-pad { padding: 14px; }

.badge {
  min-width: 20px;
  padding: 1px 7px;
  border-radius: 20px;
  background: var(--raised);
  color: var(--text-dim);
  font-size: 11px;
  text-align: center;
}

/* Чекбокс-строка: квадратик с галочкой и подпись. Оставлен там, где
   выбирают несколько значений сразу, — рынки биржи. */
.check {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  user-select: none;
}
.check .box {
  width: 16px;
  height: 16px;
  display: grid;
  place-items: center;
  border-radius: 4px;
  border: 1px solid var(--panel-edge);
  background: var(--sunken);
  color: transparent;
  font-size: 10px;
  flex: none;
  /* Заливка наливается, а не появляется: без перехода галочка щёлкает
     в новое состояние, и глаз не успевает понять, какая из двух
     сработала. */
  transition: background 0.18s, border-color 0.18s, color 0.18s;
}
.check.on .box { background: var(--accent); border-color: var(--accent); color: #fff; }
.check-row { display: flex; flex-wrap: wrap; gap: 14px; }

/* Тумблер: включено или нет, без промежуточных состояний. */
.switch {
  width: 34px;
  height: 19px;
  flex: none;
  position: relative;
  border-radius: 20px;
  background: var(--panel-edge);
  cursor: pointer;
  transition: background 0.18s;
}
.switch::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--text-faint);
  transition: transform 0.18s, background 0.18s;
}
.switch.on { background: var(--accent-soft); }
.switch.on::after { transform: translateX(15px); background: var(--accent); }

/* Выключенный блок: видно, что там будет, но трогать нечего. */
.muted {
  opacity: 0.4;
  pointer-events: none;
  user-select: none;
}

/* Строка биржи: она же заголовок секции с её настройками. */
.exchange-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 11px 14px;
  background: none;
  color: var(--text);
  text-align: left;
}
.exchange-row:hover { background: var(--raised); }
.exchange-row .name { flex: 1; font-weight: 600; }
.section.on { border-color: var(--accent-edge); }
.section.on > .exchange-row { background: var(--accent-soft); }

/* Список категорий: строки с отступом друг от друга. */
.stack { display: flex; flex-direction: column; gap: 8px; }
.stack .exchange-row {
  border: 1px solid var(--panel-edge);
  border-radius: 10px;
  background: var(--raised);
}
.stack .exchange-row.on { border-color: var(--accent-edge); background: var(--accent-soft); }

.slider-row { display: flex; align-items: center; gap: 12px; }
.slider-row input[type="range"] {
  flex: 1;
  appearance: none;
  height: 4px;
  border-radius: 2px;
  background: var(--panel-edge);
  outline: none;
}
.slider-row input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
}
.slider-value { min-width: 46px; text-align: right; color: var(--text-dim); }

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px 4px 10px;
  border-radius: 20px;
  background: var(--ask-bg);
  border: 1px solid rgba(232, 96, 110, 0.28);
  color: #f2aeb4;
  font-size: 12px;
}
.chip.allow {
  background: var(--bid-bg);
  border-color: rgba(53, 201, 143, 0.28);
  color: #96e5c6;
}
/* Крестики фишек — с фоном при наведении, как у кнопок окна: иначе
   непонятно, куда именно надо попасть. */
/* Крестик нарисован двумя полосками, а не набран символом: в кружке
   шестнадцать на шестнадцать глазу видно даже полпикселя, а у символа
   ✕ своя посадка относительно базовой линии, и она всегда чуть выше. */
.chip button {
  position: relative;
  width: 16px;
  height: 16px;
  flex: none;
  border-radius: 50%;
  color: inherit;
  opacity: 0.55;
  font-size: 0;
}
.chip button::before,
.chip button::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 9px;
  height: 1.4px;
  background: currentColor;
  border-radius: 1px;
}
/* Центрует translate, как и у значка колонки: см. .tool. */
.chip button::before { transform: translate(-50%, -50%) rotate(45deg); }
.chip button::after { transform: translate(-50%, -50%) rotate(-45deg); }
.chip button:hover { opacity: 1; background: rgba(255, 255, 255, 0.12); }

.thresholds { width: 100%; border-collapse: collapse; }
.thresholds th {
  padding: 4px 6px 4px 0;
  color: var(--text-faint);
  font-size: 11px;
  font-weight: 500;
  text-align: left;
}
.thresholds td { padding: 3px 6px 3px 0; }
.thresholds td:first-child { color: var(--text-dim); white-space: nowrap; }
.thresholds .input { height: 30px; padding: 0 8px; }

.unit { color: var(--text-faint); font-size: 12px; white-space: nowrap; }
