:root {
  --bg: #f5f6f8;
  --panel: #ffffff;
  --line: #d9dde3;
  --ink: #1c2230;
  --muted: #6b7480;
  --accent: #1f5fa9;
  --warn: #a35a00;
  --warn-bg: #fff6e5;
  --bad: #a52020;
  --bad-bg: #fdeeee;
  --ok: #1d6b3a;
  --ok-bg: #eaf6ee;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 14px/1.45 -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--ink);
}

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

header.top {
  background: #1c2230;
  color: #fff;
  padding: 0 16px;
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
}
header.top .brand { font-weight: 600; padding: 12px 0; margin-right: 8px; }
header.top nav { display: flex; gap: 2px; flex-wrap: wrap; flex: 1; }
header.top nav a {
  color: #c7ced8; padding: 12px 10px; border-bottom: 2px solid transparent;
}
header.top nav a:hover { color: #fff; text-decoration: none; }
header.top nav a.active { color: #fff; border-bottom-color: #6ea8e8; }
header.top .who { color: #c7ced8; font-size: 13px; display: flex; gap: 10px;
  align-items: center; }
header.top .who form { display: inline; }

main { padding: 18px; max-width: 1720px; margin: 0 auto; }

h1 { font-size: 20px; margin: 0 0 14px; }
h2 { font-size: 16px; margin: 22px 0 10px; }

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 14px 16px;
  margin-bottom: 16px;
}

/* Реестр, с которым сейчас нельзя работать: пустой список выбора
   в ячейке молчит, и человек думает, что сломан он сам. */
.panel.warn-panel { border-color: #e6bb7a; background: var(--warn-bg); }

.cards { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 18px; }
.card {
  background: var(--panel); border: 1px solid var(--line); border-radius: 6px;
  padding: 12px 16px; min-width: 190px; flex: 1;
}
.card .n { font-size: 26px; font-weight: 600; }
.card .t { color: var(--muted); font-size: 13px; }
.card.alarm { border-color: #e6bb7a; background: var(--warn-bg); }
.card.alarm .n { color: var(--warn); }

/* Таблица целиком помещается в ширину экрана: колонки делят доступное
   место, а не растягивают страницу. Ради этого именно fixed — при auto
   браузер игнорирует ограничения ширины ячейки и раздвигает таблицу
   под самое длинное значение. */
table { border-collapse: collapse; width: 100%; background: var(--panel);
  table-layout: fixed; }

/* Не влезло — обрезается многоточием, а не переносится на вторую строку.
   Полное значение остаётся в подсказке при наведении. */
/* Мельче основного текста и с тесными полями: колонок в выгрузке
   за двадцать, и каждый лишний пиксель отступа съедает целую колонку
   в конце — так «Пометки» и схлопывались до нечитаемой полоски. */
th, td { border: 1px solid var(--line); padding: 4px 6px; text-align: left;
  vertical-align: middle; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; font-size: 12.5px; }

/* Подпись переносится, значение — нет. Иначе ширину колонки диктует
   заголовок: «МАВ пост.» шире любого числа под ним, и ради подписи
   пришлось бы отдать место данным соседней колонки. */
th { background: #eef1f5; font-weight: 600; position: sticky; top: 0;
  z-index: 2; box-shadow: inset 0 -1px 0 var(--line);
  white-space: normal; line-height: 1.15; vertical-align: bottom; }
/* Коробка подписи в заголовке. Появляется вокруг подписи, когда
   у таблицы включается протяжка столбцов, и нужна ради одного: у неё,
   в отличие от самой ячейки, можно закрепить высоту. У таблицы `height`
   на ячейке — это минимум, и подпись, перенесённая на вторую строку,
   всё равно подняла бы шапку, а вместе с ней уехали бы вниз строки:
   таблица прыгала бы под курсором ровно тогда, когда в неё целятся.

   Подпись остаётся прижатой к низу, как и была: заголовки в один
   и в две строки стоят в ряду и обязаны читаться одной линией. */
th .th-label { display: flex; align-items: flex-end; overflow: hidden; }
/* Сама подпись внутри — обычным потоком, как она лежала в ячейке:
   `flex` раскладывает содержимое по-своему, и от одной перемены
   раскладки шапка становится выше. min-width: 0 обязателен — без него
   элемент flex не даёт ячейке сжаться. */
th .th-text { flex: 1 1 auto; min-width: 0; }

/* Край заголовка, за который тянут ширину столбца. Внутри ячейки,
   а не поверх границы: у th стоит overflow: hidden, и всё, что вылезло
   за её край, всё равно обрезалось бы. Заметен он только под курсором:
   постоянная полоска у каждой подписи — это двадцать полосок в шапке
   выгрузки, и читать её они мешают больше, чем помогают. */
th .grip { position: absolute; top: 0; right: 0; width: 7px; height: 100%;
  cursor: col-resize; user-select: none; }
th:hover .grip { background: linear-gradient(to right,
    transparent, rgba(60, 90, 130, .28)); }
/* Пока тянут — курсор один на всю страницу: мышь уходит с ячейки
   далеко, и «стрелка» посреди перетаскивания читается как «отпустил».
   И ни одного случайного выделения: тянут ведь через текст. */
body.resizing { cursor: col-resize; user-select: none; }
/* Подсвечен ровно тот край, который тянут: мышь давно ушла с ячейки,
   и отметка «вот эта колонка» — единственное, что связывает движение
   с тем, что от него меняется. */
th .grip.pulling { background: rgba(60, 90, 130, .45); }

td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
/* Дата и тег сервера: значение короткое и заранее известной ширины,
   его можно набрать мельче и не тратить на него колонку. */
td.tight { font-size: 11.5px; color: var(--muted); }
/* Метки не должны переноситься на вторую строку и растить строку
   таблицы: их место узкое, и лишнее прячется за прокруткой ячейки. */
td.tags { padding: 3px 4px; }
td.tags .tag { font-size: 10.5px; padding: 0 3px; }
tr.muted td { color: var(--muted); }
tr:hover td { background: #fafbfc; }

/* Контейнер прокрутки по вертикали: шапка прилипает к его верху.
   По горизонтали прокручивать нечего — таблица и так по ширине. */
.wrap { overflow-y: auto; overflow-x: hidden; max-height: 78vh;
  border: 1px solid var(--line); border-radius: 6px; }
/* Колонок больше, чем помещается: ужимать их дальше некуда, цифры
   превращаются в полоски. Таблица берёт свою ширину и едет вбок. */
.wrap.sideways { overflow-x: auto; }
table.wide { width: auto; min-width: 100%; }
table.wide th, table.wide td { min-width: 62px; }

/* Правки выгрузки: в последней колонке форма отката — поле пояснения
   и кнопка, — и меньше своей ширины она не станет. Ширина таблицы
   задана суммой колонок, чтобы колонке хватило места; на узком экране
   таблица едет вбок, а не обрезается. */
#corrections { table-layout: fixed; width: 1462px; }
#corrections th, #corrections td { min-width: 0; }

.wrap table { border-collapse: separate; border-spacing: 0; }
.wrap th, .wrap td { border: 0; border-bottom: 1px solid var(--line);
  border-right: 1px solid var(--line); }
.wrap th:last-child, .wrap td:last-child { border-right: 0; }
.wrap tr:last-child td { border-bottom: 0; }

/* Ячейка с несколькими значениями в столбик: сама строка не переносится,
   но значений может быть несколько. */
td.stack { white-space: normal; }

/* Столбец действий прилипает к правому краю. Таблица истории шире
   экрана и едет вбок, и кнопка, до которой перед каждым нажатием надо
   доехать прокруткой, — это тот же лишний переход, ради избавления
   от которого её в строку и поставили. */
.wrap td.acts, .wrap th.acts { position: sticky; right: 0;
  background: var(--panel); border-left: 1px solid var(--line); }
.wrap th.acts { background: #eef1f5; z-index: 3; }
.wrap td.acts { z-index: 1; }
/* Подсветку строки липкая ячейка обязана держать тоже: иначе под
   курсором она выглядит ячейкой другой строки. */
.wrap tr:hover td.acts { background: #fafbfc; }

/* Хэш транзакции — 64 знака, и обрезать его нечестно: по нему сверяют
   платёж. Переносим прямо посреди строки: разрывать там нечего, это
   не слово. */
.hash { word-break: break-all; }
td.stack > div { white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }

.mono { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12.5px; }

.tabs { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 14px;
  border-bottom: 1px solid var(--line); }
.tabs a {
  padding: 7px 12px; border: 1px solid transparent; border-bottom: none;
  border-radius: 5px 5px 0 0; color: var(--muted);
}
.tabs a.active {
  background: var(--panel); border-color: var(--line); color: var(--ink);
  margin-bottom: -1px; font-weight: 600;
}

/* Ряд полей отбора. Не `form.filters`: на остатках рядов два — момент
   и разрез по карточке, — а форма у них одна общая, иначе каждый ряд
   пришлось бы дублировать в соседнем скрытыми полями. */
.filters { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; }
.filters label { display: block; font-size: 12px; color: var(--muted); }
input, select, textarea {
  font: inherit; padding: 5px 7px; border: 1px solid var(--line);
  border-radius: 4px; background: #fff; color: var(--ink);
}
textarea { width: 100%; }
input:focus, select:focus, textarea:focus { outline: 2px solid #b8d3f2; }
/* Погашенное поле. Своё оформление обязательно: правило выше красит фон
   белым и затирает браузерное, из-за чего реестр у человека с правом
   «только смотреть» выглядел точно так же, как у того, кто его правит. */
input:disabled, select:disabled, textarea:disabled {
  background: #f2f3f5; color: #7c8492; cursor: not-allowed;
  border-color: #e2e5ea;
}

/* Свой display у .btn/.tag/.pager перебивает браузерное
   [hidden] { display: none }, и скрытое остаётся на виду. */
[hidden] { display: none !important; }

.btn {
  display: inline-block; padding: 6px 13px; border-radius: 4px;
  border: 1px solid var(--line); background: #eef1f5; color: var(--ink);
  cursor: pointer; font: inherit;
}
.btn:hover { background: #e3e8ef; text-decoration: none; }
.btn.primary { background: var(--accent); border-color: var(--accent);
  color: #fff; }
.btn.primary:hover { background: #174c8a; }
.btn.danger { background: var(--bad-bg); border-color: #e3b3b3;
  color: var(--bad); }
.btn.small { padding: 3px 8px; font-size: 12.5px; }

.tag {
  display: inline-block; padding: 1px 7px; border-radius: 10px;
  font-size: 12px; border: 1px solid var(--line); background: #eef1f5;
  white-space: nowrap;
}
.tag.warn { background: var(--warn-bg); border-color: #e6bb7a;
  color: var(--warn); }
.tag.bad { background: var(--bad-bg); border-color: #e3b3b3;
  color: var(--bad); }
.tag.ok { background: var(--ok-bg); border-color: #a8d5b8; color: var(--ok); }
.tag.muted { color: var(--muted); }

.msg { padding: 9px 13px; border-radius: 5px; margin-bottom: 10px;
  border: 1px solid var(--line); background: var(--panel); }
.msg.success { background: var(--ok-bg); border-color: #a8d5b8; }
.msg.warning { background: var(--warn-bg); border-color: #e6bb7a; }
.msg.error { background: var(--bad-bg); border-color: #e3b3b3; }

.formrow { margin-bottom: 12px; max-width: 620px; }
.formrow label { display: block; font-weight: 600; margin-bottom: 3px; }
.formrow .help { color: var(--muted); font-size: 12.5px; margin-top: 2px; }
/* Красным — везде, а не только в строке поля. Общие ошибки формы
   («уже заведено такое поручение») стоят отдельным абзацем, и чёрными
   читаются как пояснение — то есть как то, мимо чего можно пройти. */
.err { color: var(--bad); }
.formrow .err { font-size: 12.5px; margin-top: 2px; }
.formrow input[type=text], .formrow input[type=password],
.formrow input[type=date], .formrow input[type=number],
.formrow input[type=url], .formrow select, .formrow textarea { width: 100%; }
.formrow input[type=checkbox] { width: auto; }

.pager { display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  color: var(--muted); font-size: 13px; margin: 8px 0; }
.pager .grow { flex: 1; }
.pager .per a { padding: 2px 6px; border-radius: 3px; }
.pager .per a.on { background: var(--accent); color: #fff; }

/* -------------------------------------------------- правка прямо в строке */

td.editable { padding: 2px 3px; overflow: visible; }
/* min-width: 0 обязателен: иначе поле не даёт колонке сжаться,
   и таблица снова вылезает за экран. */
.cell { width: 100%; min-width: 0; padding: 3px 5px; font-size: 13px;
  border-radius: 3px; }
tr.dirty td { background: #fff8e3; }
tr.dirty:hover td { background: #fff3d2; }
/* Отмеченная к удалению строка не должна выглядеть как отредактированная:
   это противоположные намерения, и путать их дорого. */
tr.doomed td { background: #fdeceb; color: #8a3b34; text-decoration: line-through; }
tr.doomed td:first-child { text-decoration: none; }
tr.rowerr td { background: var(--bad-bg); }
td .err { white-space: normal; max-width: 220px; }
/* Похоже на уже заведённое. Не ошибка — предупреждение: пока это
   только догадка браузера, отказывает всё равно сервер. Поэтому
   цвет предупреждения, а не красный: красным человек читает
   «не отправится», и перестаёт разбираться. */
td .dup { white-space: normal; max-width: 220px; margin-top: 2px;
  color: var(--warn); font-size: 12.5px; }
/* Совпала только половина: у страны это не дубль, а соседняя запись —
   «1 Canada» рядом с «1 USA». Сервер такое пропускает, и подсказка
   поэтому тише предыдущей: она к сведению, а не к исправлению. */
td .dup.near { color: var(--muted); }

/* Кнопка «протянуть значение вниз» в шапке редактируемой колонки. */
th .fill {
  border: 1px solid var(--line); background: #fff; border-radius: 3px;
  cursor: pointer; font: inherit; font-size: 11px; line-height: 1;
  padding: 1px 4px; margin-left: 4px; color: var(--muted);
}
th .fill:hover { background: var(--accent); color: #fff;
  border-color: var(--accent); }

/* Панель «создать заявку» стоит НАД таблицей: прилипшая снизу полоса
   закрывала последние строки и мешала читать длинные списки. */
.editbar {
  background: var(--panel); border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 6px; padding: 10px 14px; margin-bottom: 10px;
}
.editbar .row { display: flex; gap: 10px; align-items: flex-end;
  flex-wrap: wrap; }
.editbar label { display: block; font-size: 12px; color: var(--muted); }
.editbar textarea { min-height: 34px; }

/* Панель группового заполнения. Появляется, когда отмечена хоть одна
   строка: постоянный ряд полей над таблицей занимал бы место каждый
   раз, а нужен он не всегда. Отличается от «создать заявку» цветом
   полосы — это разные действия, и путать их дорого: одно правит
   строки на экране, другое отправляет их на согласование. */
.bulkbar {
  background: var(--panel); border: 1px solid var(--line);
  border-left: 3px solid #7a9bc4;
  border-radius: 6px; padding: 10px 14px; margin-bottom: 10px;
}
.bulkbar .row { display: flex; gap: 10px; align-items: flex-end;
  flex-wrap: wrap; }
.bulkbar label { display: block; font-size: 12px; color: var(--muted); }
.bulkbar .row > div { min-width: 120px; }
.bulkbar .picked-count { min-width: 0; font-weight: 600; padding-bottom: 4px; }
.bulkbar .note { margin-top: 7px; }

/* Отметка строки. Своим цветом, не жёлтым: жёлтый уже занят под
   «изменено», и отмеченная строка читалась бы как правленая. */
#grid th.pick, #grid td.pick { text-align: center; padding: 2px; }
#grid th.pick input, #grid td.pick input { margin: 0; cursor: pointer; }
tr.picked td { background: #eef4fd; }
tr.picked:hover td { background: #e3edfb; }
/* Заполнили — строка стала изменённой, и это важнее отметки: отметка
   живёт до конца разметки, а «изменено» решает, что уйдёт в заявку. */
tr.picked.dirty td { background: #fff8e3; }

/* Строки одного направления, различающиеся мелочью: полоса слева.
   Строки-заголовка у группы нет — она заняла бы место в таблице,
   которую и так читают вширь, — а границу видно и так. Соседние
   группы красятся по очереди: две подряд иначе сливаются в одну.

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

   Классы свои, не общие с группами документа (`doc-a`/`doc-b`): здесь
   полоса цепляется за первую ячейку строки, а там — за растянутую
   ячейку отметки, и одно правило на двоих рисовало в допуслугах
   две полосы вместо одной. */
tr.grp-a > td:first-child { box-shadow: inset 3px 0 0 #6f97c7; }
tr.grp-b > td:first-child { box-shadow: inset 3px 0 0 #c79c6f; }

.was { color: var(--muted); text-decoration: line-through; }
.now { font-weight: 600; }

.login { max-width: 320px; margin: 12vh auto; }
.login .panel { padding: 22px; }

dl.kv { display: grid; grid-template-columns: 260px 1fr; gap: 4px 14px;
  margin: 0; }
dl.kv dt { color: var(--muted); }
dl.kv dd { margin: 0; }

/* Список галочек в несколько колонок: разделов столько же, сколько
   вкладок в реестрах, и в одну колонку они вытягивают форму на два
   экрана. Колонки набираются по ширине, а не числом, — подписи
   разной длины, и фиксированная сетка оставила бы половину пустой. */
div.checkgrid {
  display: grid; gap: 2px 18px; margin-top: 4px;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
}
div.checkgrid label { font-weight: normal; display: flex; gap: 6px;
  align-items: center; }

.note { color: var(--muted); font-size: 13px; }
.nowrap { white-space: nowrap; }
.right { text-align: right; }
.inline { display: inline; }

/* Проблема подсвечивается там, где она есть, а не только тегом справа:
   узкая колонка пометок обрезается, а цвет ячейки видно всегда. */
td.warn-cell { background: var(--warn-bg); }
td.bad-cell { background: var(--bad-bg); color: var(--bad); }
/* Не проблема, а «деньги лежат здесь»: у входящей строки выручка
   не в той колонке, где её ищут глазами. */
td.good-cell { background: var(--ok-bg); }
tr:hover td.warn-cell { background: #ffeecd; }
tr:hover td.bad-cell { background: #fbe2e2; }
tr:hover td.good-cell { background: #dff0e6; }

/* ------------------------------------- раскрытие строки и поиск в списках */

/* Строка кликабельна: колонки обрезаны, а посмотреть значение целиком
   надо не отходя от таблицы. */
tbody tr:not(.rowdetails):hover, table tr:not(.rowdetails):hover {
  cursor: default;
}
tr.opened td { background: #eef4fb; }

tr.rowdetails td { background: #f7f9fc; white-space: normal;
  padding: 10px 14px; }
tr.rowdetails dl {
  display: grid; grid-template-columns: 220px 1fr; gap: 3px 14px; margin: 0;
}
tr.rowdetails dt { color: var(--muted); }
tr.rowdetails dd { margin: 0; word-break: break-word; }

.combo { position: relative; }
.combo-hidden { position: absolute; opacity: 0; pointer-events: none;
  width: 1px; height: 1px; }
/* Уголок, как у обычного списка: без него поле читается как строка
   ввода, и человек не понимает, что выбирать вообще есть из чего. */
.combo::after {
  content: ""; position: absolute; right: 7px; top: 50%; width: 0; height: 0;
  margin-top: -1px; pointer-events: none;
  border: 4px solid transparent; border-top-color: var(--muted);
}
.combo-input { width: 100%; padding-right: 18px; }

/* Список лежит в <body>, а не в ячейке, и ставится из JS. В ячейке его
   резало: таблица внутри .wrap с overflow, и всё, что вылезает за её
   границы, обрезается — от списка оставалась полоска в высоту строки. */
.combo-list {
  position: fixed; z-index: 60;
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 4px; box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
}
.combo-item { padding: 5px 10px; cursor: pointer; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; font-size: 13px; }
.combo-item:hover { background: #eef4fb; }
.combo-item.on { font-weight: 600; }
.combo-item.note { cursor: default; color: var(--muted); }

/* Пустая строка под новую запись — отличается от существующих, чтобы
   не путать «правлю» и «завожу». */
tr.newrow td { background: #f6f9f6; }
tr.newrow.dirty td { background: #eaf6ee; }
/* Подпись «новая запись N» — по классу, а не по первой ячейке: слева
   от названия стоят колонки отметок, и сколько их, решает реестр. */
tr.newrow td.rowname { color: var(--muted); font-size: 12.5px; }

/* Строка, исключённая из расчёта: сырьё цело, но в цифры она не идёт. */
tr.hidden-row td { text-decoration: line-through; color: var(--muted); }
tr.hidden-row td input { text-decoration: none; }

/* Неприменимая ячейка: не спрятана, а погашена. Спрятать значило бы
   сломать выравнивание колонок, а человеку надо видеть, что поле
   существует, просто сейчас не про него. */
td.off { background: repeating-linear-gradient(
    135deg, #f4f4f6, #f4f4f6 6px, #eeeef1 6px, #eeeef1 12px); }
td.off input, td.off select, td.off .combo { opacity: .45; cursor: not-allowed; }

/* Примеры строк выгрузки в раскрытой строке реестра: таблица внутри
   ячейки, поэтому мельче и без прилипающей шапки. */
.examples-slot { margin-top: 10px; }
table.examples { table-layout: auto; font-size: 12.5px; width: auto;
  min-width: 100%; }
table.examples th, table.examples td { padding: 3px 7px; }
table.examples th { position: static; }

/* Ввод факта по инвойсу: три поля в одной ячейке. Переносится
   и не обрезается — у остальных ячеек `nowrap` и `overflow: hidden`,
   и форма уезжала за край вместе с кнопкой: поле видно, сохранить
   нечем. */
td.factcell { overflow: visible; white-space: normal; padding: 4px 6px; }
form.fact { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
form.fact input[name=amount] { width: 74px; flex: none; }
form.fact input[name=comment] { flex: 1 1 110px; min-width: 0; }

/* Включатель и цена в одной ячейке: «продаём за столько» — это одно
   решение, и порознь они разъезжаются по таблице. Без flex поле ввода
   с width:100% выдавливает галочку и само сжимается в ноль. */
.pair { display: flex; gap: 5px; align-items: center; }
.pair input[type=checkbox] { width: auto; flex: none; margin: 0; }
.pair .cell { flex: 1; min-width: 0; }

/* Два счёта одного платежа — рядом, а не друг под другом. Разбивка это
   один вопрос про две половины, и сверять их приходится глазами: тот ли
   клиент, та ли валюта, сходятся ли суммы. Колонкой сверху вниз второй
   счёт уезжает под сгиб, и «на какой счёт сколько» превращается
   в прокрутку туда-обратно. */
.sides { display: grid; gap: 14px; }
.sides.split { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Рамка появляется только у разбивки: вокруг единственного счёта она
   обещает второй, которого не будет. Внутри рамки строка формы больше
   не ограничена 620 пикселями — ширину ей задаёт колонка. */
.sides.split .side { border: 1px solid var(--line); border-radius: 6px;
  padding: 12px 14px 2px; background: #fbfcfd; }
.sides.split .side .formrow { max-width: none; }
.sides .side > h3 { display: none; }
.sides.split .side > h3 { display: block; margin: 0 0 10px;
  font-size: 13px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); }
/* Узкий экран: две колонки не помещаются, и сжимать их до нечитаемых
   не за чем — падают одна под другую. */
@media (max-width: 900px) {
  .sides.split { grid-template-columns: 1fr; }
}

/* Поле, которое сейчас не заполняют: выбирать не из чего (вариант один)
   или не по чему (не сделан предыдущий шаг). Гасим и не даём кликнуть —
   иначе человек открывает список и обнаруживает пустоту, а пустой,
   но живой список читается как поломка, а не как «сначала другое». */
select.locked { pointer-events: none; }
.formrow select:disabled, .formrow input:disabled, select.locked {
  background: #f1f3f5; color: var(--muted); border-color: #e3e7ec;
}
.formrow.locked-row label, .formrow.locked-row .help { color: #9aa3ae; }

/* Поле и кнопка к нему в одну строку: «проверить транзакцию» — это
   не «отправить форму», а действие над самим полем, и стоять оно должно
   там, куда человек только что вставил ссылку. */
.beside { display: flex; gap: 6px; align-items: center; }
.beside > :first-child { flex: 1; min-width: 0; }
.beside .btn { flex: none; }
/* Умножить или разделить — выбор из двух знаков, и места ему нужно
   ровно на знак. Растянутый на всю строку, он выглядел бы полем,
   которое надо заполнять. */
.beside select.rate-how { flex: none; width: 62px; text-align: center; }
/* Посчитанное разошлось с тем, что стоит в поле: не ошибка — так
   бывает, когда сумму поправили руками, — но и не «всё сходится».
   Зачислится то, что в поле, и сказать это надо заметно. */
.hint.warn-line { background: var(--warn-bg); border-color: #e6bb7a;
  color: var(--warn); }

/* Что станет доступно после предыдущего шага. Погашено, а не спрятано:
   человек должен видеть, что его ждёт дальше. */
.panel.waiting { opacity: .55; }
fieldset.bare { border: 0; margin: 0; padding: 0; min-width: 0; }

/* Кнопка, которая сейчас не нажимается. Без этого `disabled` у синей
   кнопки не видно вовсе: она выглядит живой, человек жмёт и не понимает,
   почему ничего не происходит. */
.btn:disabled, .btn[disabled] {
  opacity: .45; cursor: not-allowed; box-shadow: none;
}

/* Баланс выбранного аккаунта — вплотную к списку выбора, а не отдельной
   строкой формы: это состояние счёта, а не поле документа. */
/* Подсказка в форме: шаг, который надо сделать до того, как заполнять
   поле. Серым в строку, как `note`, такое читается как примечание
   и пропускается — а без него не работает всё остальное. */
.hint, .balance { padding: 5px 9px; border-radius: 4px;
  background: #f2f6fb; border: 1px solid #dbe6f3; }
.balance { margin: -6px 0 12px; display: inline-block; }
.balance:empty { display: none; }
.hint { margin: 0 0 8px; line-height: 1.45; }

/* Погашенное поле даты в панели правки: рядом с ним подпись о том,
   что получится, поэтому гасим само поле, а не всю ячейку целиком. */
.editbar .row > div.off input { opacity: .55; cursor: not-allowed;
  background: #f2f3f5; }
.editbar #valid-from-note { font-size: 12px; margin-top: 2px; }
#start-choice ul { list-style: none; margin: 0; padding: 0; display: flex;
  gap: 12px; }
#start-choice li label { display: inline-flex; align-items: center; gap: 4px;
  font-size: 13px; color: var(--ink); }

/* Экран «идёт обработка». Не украшение: крупная заявка применяется
   секундами, и без него непонятно, работает платформа или зависла,
   — а неясность лечится повторным нажатием, то есть второй такой же
   заявкой. Поэтому фон не просто затемнён, а перехватывает нажатия. */
.busy-screen {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  background: rgba(28, 34, 48, .35);
  backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
  /* Появляется не сразу: на быстром ответе вспышка мешает больше,
     чем помогает. Задержка в анимации, а не в JS, — так экран
     не переживёт уход со страницы. */
  animation: busy-in .12s ease-out .25s both;
}
@keyframes busy-in { from { opacity: 0 } to { opacity: 1 } }

.busy-box {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 6px; padding: 18px 26px; min-width: 260px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .25);
  display: flex; align-items: center; gap: 14px;
}
.busy-spin {
  width: 22px; height: 22px; flex: none; border-radius: 50%;
  border: 3px solid var(--line); border-top-color: var(--accent);
  animation: busy-turn .8s linear infinite;
}
@keyframes busy-turn { to { transform: rotate(360deg) } }
.busy-text { font-weight: 600; }
.busy-note { font-size: 12.5px; color: var(--muted); font-weight: 400;
  margin-top: 2px; }

@media (prefers-reduced-motion: reduce) {
  .busy-screen { animation-delay: 0s; }
  .busy-spin { animation: none; border-top-color: var(--accent); }
}

/* Фильтры по колонкам: девять списков поверх таблицы — это пол-экрана,
   а нужны они не каждый раз. Свёрнуты, но раскрываются сами, когда
   хоть один выбран: невидимый фильтр читается как пустой список. */
details.colfilters { flex-basis: 100%; margin-top: 2px; }
details.colfilters summary { cursor: pointer; font-size: 12.5px;
  color: var(--accent); width: max-content; }
details.colfilters[open] summary { margin-bottom: 8px; }
.colfilter-grid { display: grid; gap: 8px 12px;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }
.colfilter-grid select { width: 100%; }

/* Сводка: числа вправо, дата и клиент — влево и не жирным. Колонка
   с деньгами читается столбиком только при выравнивании по правому
   краю, иначе разряды не совпадают. */
/* Не только на странице сводки: клиенты дня лежат в окне поверх неё,
   и с них открывается третий уровень — их строки выгрузки. Без этого
   строка второго уровня выглядела бы неактивной. */
tr.clickable { cursor: pointer; }
tr.clickable:hover td { background: #eef4fb; }
/* Подсветка строки не должна съедать пометку на ячейке: наводят
   на строку как раз затем, чтобы прочитать подсказку, — и метка
   пропадала ровно в этот момент. */
tr.clickable:hover td.warn-cell { background: #ffeecd; }
tr.clickable:hover td.bad-cell { background: #fbe2e2; }
td.num { text-align: right; font-variant-numeric: tabular-nums; }
th + th, th:last-child { text-align: right; }
#stats th:first-child, .sheet th:first-child { text-align: left; }
td.head { font-weight: 600; }
tr.totals td { background: #f3f5f8; font-weight: 600;
  border-top: 2px solid var(--line); position: sticky; bottom: 0; }
/* Итог помечается наравне со строками: серый фон итоговой строки
   специфичнее и без этого перекрывал бы предупреждение — а неполный
   итог опаснее неполной строки, его и уносят в отчёт. */
tr.totals td.warn-cell { background: var(--warn-bg); }
tr.totals td.bad-cell { background: var(--bad-bg); }
td.bad-cell { color: var(--bad); }

/* Окно поверх страницы: разбивка дня по клиентам. Не вкладка и не
   отдельная страница — из неё пришлось бы возвращаться к тому же
   месту в сорока строках. */
.sheet-back {
  position: fixed; inset: 0; z-index: 150;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgba(28, 34, 48, .35);
  backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
}
body.sheet-open { overflow: hidden; }

/* Окно «точно?» — вместо браузерного `confirm()`. Выше окна с деталями
   строки: если оба когда-нибудь окажутся на экране, спрашивают всегда
   поверх. Уже его: здесь одна фраза и две кнопки, и на всю ширину
   вопрос читается хуже — глаз идёт по строке до конца и возвращается. */
.ask-back {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgba(28, 34, 48, .35);
  backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
}
.ask {
  background: var(--panel); border-radius: 6px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, .3);
  width: min(440px, 100%); padding: 20px;
}
.ask-text { margin: 0 0 18px; font-size: 15px; line-height: 1.5; }
/* Действие справа, отмена слева от него: справа заканчивается чтение,
   и туда же уходит рука. */
.ask-buttons { display: flex; gap: 8px; justify-content: flex-end; }
.sheet {
  background: var(--panel); border-radius: 6px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, .3);
  width: min(1180px, 100%); max-height: 100%;
  display: flex; flex-direction: column;
}
.sheet-head { display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; border-bottom: 1px solid var(--line); }
.sheet-head h2 { margin: 0; font-size: 16px; flex: 1; }
.sheet-body { padding: 0; overflow: auto; }
.sheet-body .wrap { max-height: none; border: 0; border-radius: 0; }
.sheet-body > :not(.wrap) { padding: 16px; color: var(--muted); }
/* Строка над таблицей окна: сколько показано и куда идти за остальным.
   Молча обрезанный список читается как полный, поэтому место у неё
   постоянное — до таблицы, а не сноской под ней. */
.sheet-note { display: flex; align-items: center; gap: 12px;
  border-bottom: 1px solid var(--line); font-size: 13px; }
.sheet-note .btn { flex: none; }
/* Третий уровень: в первой колонке путь звонка — «наш префикс →
   поставщик с его префиксом · страна · диалпир · шлюз». Он длинный
   по существу, и многоточие прячет ровно то, ради чего окно открывают,
   а следом и пометку о неполноте, которая стоит за ним. */
table.rowpath td.head { white-space: normal; }

/* Таблица загрузок: клетка — один знак, и читается она столбиком.
   Цвет здесь несёт смысл, поэтому знак остаётся и без цвета: «+», «!»
   и «—» различимы в чёрно-белой распечатке и дальтонику. */
td.mark, span.mark { text-align: center; font-weight: 600;
  font-size: 15px; }
/* Шапка над клетками — тоже по центру: числовое правило колонок
   сводки здесь не про числа. */
#loads th + th { text-align: center; }
span.mark { display: inline-block; width: 18px; }
td.good-cell { color: var(--ok); background: var(--ok-bg); }
td.muted-cell { color: var(--muted); }
tr.has-gap td.head { color: var(--warn); }
#loads td.head, #countryless td.head { font-weight: 600; }

/* Инструкция переносится по словам: обрезанная инструкция бесполезна,
   а колонки таблицы обрезают всё подряд. */
#countryless td.what { white-space: normal; overflow: visible;
  line-height: 1.35; }
#countryless td.what .btn { white-space: nowrap; }

/* Префикс, который надо вписать, — моноширинным: его сверяют посимвольно
   и копируют руками. */
code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12.5px; background: #eef1f5; border-radius: 3px;
  padding: 1px 4px; }

/* Сортировка по столбцу: стрелка показывает, по какому и куда. Курсор
   на шапке — единственное, по чему видно, что на неё вообще жмут. */
th.sortable { cursor: pointer; user-select: none; }
th.sortable:hover { background: #e6ecf4; }
th.sorted { color: var(--accent); }
th.sorted::after { content: " ↑"; }
th.sorted[data-dir="down"]::after { content: " ↓"; }

/* Настройка доступа: три десятка разделов, у каждого свой уровень.
   Списком «подпись + поле» это стена одинаковых строк, поэтому сеткой
   и кучками — меню отдельно, реестры отдельно. */
.access h3 { margin: 14px 0 6px; font-size: 14px; color: var(--muted);
  font-weight: 600; }
.access h3:first-child { margin-top: 0; }
.access-grid { display: grid; gap: 6px 14px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.access-row { display: flex; align-items: center; gap: 8px; }
.access-row label { flex: 1; font-size: 13px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.access-row select { flex: none; width: 140px; }

/* Итог по валютам над таблицей остатков: строк в нём столько, сколько
   валют, и на всю ширину растягивать его незачем — колонки уехали бы
   к разным краям экрана и перестали читаться парой «валюта → сумма». */
table.summary { table-layout: auto; width: auto; min-width: 320px; }
table.summary th { position: static; }

/* Подпись выравнивается по содержимому колонки, а не по её номеру.
   Общее правило «все, кроме первой, — вправо» писалось под сводку,
   где числа во всех колонках, кроме даты. В остатках текстовых колонок
   несколько подряд, и шапка над ними уезжала к правому краю, а значения
   оставались у левого. */
#balances th { text-align: left; }
#balances th.num { text-align: right; }

/* Строка, вычеркнутая из итога галочкой. Остаётся на экране, но видно,
   что она не считается: «мы её видели и сознательно не берём» — это
   не то же самое, что «её здесь нет», и исчезающая строка читалась бы
   как второй фильтр. */
#balances tr.dropped td { opacity: .45; text-decoration: line-through; }
#balances tr.dropped td.pick { opacity: 1; text-decoration: none; }
#balances td.pick, #balances th:first-child { text-align: center;
  padding: 2px; }
#balances td.pick input { margin: 0; cursor: pointer; }
/* Валюта, у которой после исключений не осталось строк: гасим, а не
   прячем — пропадающая строка итога читается как сбой. */
#by-currency tr.muted td { color: var(--muted); }

/* Таблица остатков: колонок за десяток, и каждый лишний пиксель отступа
   съедает название клиента в конце. Плотнее общей сетки — как в выгрузке,
   где та же беда решена тем же способом. */
#balances th, #balances td { padding: 3px 5px; font-size: 12px; }
#balances td.pick, #balances th.pick { width: 28px; padding: 2px;
  text-align: center; }
#balances td.pick input { margin: 0; cursor: pointer; }
#balances td.pick { overflow: visible; }
/* Пометка «тестовый»/«поставщик» рядом с обнулённым нулём: мельче
   цифры, чтобы не спорить с ней за внимание. Сам серый цвет ячейки
   даёт `td.muted-cell` — общее правило, оно уже есть. */
#balances td .tag { margin-left: 4px; font-size: 10px; padding: 0 4px; }

/* ------------------------------- таблица документов со свёрнутыми строками */

/* Одна разметка на два раздела: «Номера» и «Допуслуги». Общая целиком,
   кроме ширины: колонок у них разное число. Разойдись эти правила —
   таблицы разъедутся при первой же правке одной из них.

   Колонок два десятка, и без явных ширин браузер отдаёт «Статусу»
   больше места, чем названию клиента, — а обрезанное название читать
   нечем. Ширины стоят в разметке, в `<colgroup>`, и работают они только
   при fixed-раскладке. Включить её мало: с `width: auto` браузер
   откатывается на автоматическую и снова меряет по содержимому, —
   поэтому ширина таблицы задана явно, суммой колонок из её же
   `<colgroup>`. Разойдутся — колонки разъедутся пропорционально.

   На широком экране `min-width: 100%` у `.wide` растянет таблицу
   до контейнера, и это правильно: пустая полоса справа ничего
   не сообщает. На узком включается боковая прокрутка.

   `min-width` общего правила здесь снят: он не давал сделать узкими
   счётчики номеров и дату, из-за которых всё и затевалось. */
table.docs { table-layout: fixed; }
table.docs th, table.docs td { min-width: 0; }
#extras { width: 1146px; }   /* допуслуги */
#charges { width: 1744px; }  /* номера: колонок больше */

/* Ячейки документа — вверх, а не по центру: сверху они читаются как
   шапка группы, чем и являются. Отметка удаления, наоборот, по центру —
   она относится ко всему документу, и посередине группы это видно. */
table.docs td, table.docs th { vertical-align: top; }
table.docs td.pick { vertical-align: middle; }

/* Строки одного документа объединяет полоса слева — как у групп
   маршрутов, и по той же причине: строки-заголовка у группы нет,
   а границу видно и так. Тенью внутрь, а не рамкой: рамка раздвинула
   бы ячейку, и отметки строк встали бы правее соседних.

   Полоса живёт на ячейке отметки, а не на «первой попавшейся»: эта
   ячейка тянется на весь раскрытый документ, и одной полосы хватает
   на всю группу. На первой ячейке каждой строки их выходило две —
   одна от растянутой отметки, вторая от колонки стрелки. Колонка
   отметки поэтому есть всегда, просто без права удалять она тоньше
   и пустая. */
table.docs tr.doc-a > td.pick { box-shadow: inset 3px 0 0 #6f97c7; }
table.docs tr.doc-b > td.pick { box-shadow: inset 3px 0 0 #c79c6f; }
table.docs td.pick, table.docs th.pick { padding: 2px; text-align: center; }
table.docs td.pick input { margin: 0; cursor: pointer; }

/* Правая граница — у всех ячеек. Общее правило снимает её у последней
   в строке, а последняя в разметке и последняя в таблице — разные
   вещи: у части документа колонок меньше, и граница пропадала
   в середине таблицы, между «Затратами» и соседом. */
table.docs td { border-right: 1px solid var(--line); }

/* Граница между документами — сплошная, между строками внутри одного —
   светлее: это один платёж, а не два. Без разницы группа из трёх строк
   читается как три отдельных списания. */
table.docs tbody tr td { border-bottom-color: #edeff2; }
table.docs tr.gend > td { border-bottom: 1px solid var(--line); }

/* Стрелка-раскрывашка. Своей колонкой, а не кликом по строке: по дате
   и клиенту человек попадает, целясь в ссылку рядом, и таблица прыгала
   бы от каждого промаха. */
table.docs td.foldcol, table.docs th.foldcol { padding: 1px 2px;
  text-align: center; }
.fold { border: 0; background: none; cursor: pointer; padding: 2px 4px;
  color: var(--muted); font-size: 12px; line-height: 1;
  transition: transform .12s ease; }
.fold:hover { color: var(--ink); }
.fold.open { transform: rotate(90deg); color: var(--ink); }
/* Свёрнутая строка документа — то, за чем в таблицу и приходят:
   кому, сколько и прошло ли. Её сводка чуть заметнее частей. */
table.docs tr.doc td.summary { color: var(--muted); }
table.docs tr.part td { background: #fcfcfd; }
table.docs tr.part:hover td { background: #f7f9fb; }

/* Строки услуг в форме списания. Горизонтально, а не столбиком:
   услуг в документе несколько, и в столбик они вытянули бы форму
   на несколько экранов там, где человек хочет видеть её целиком. */
table.lines { width: 100%; margin-bottom: 8px; }
table.lines td { padding: 3px 4px; vertical-align: top; }
table.lines select { width: 100%; }
table.lines input[type=text], table.lines input[type=number] { width: 100%; }
table.lines td.sum, table.lines td.cost { white-space: nowrap; }
table.lines label.drop { font-size: 12px; color: var(--muted);
  white-space: nowrap; cursor: pointer; }
/* Замечание ко всей строке — во всю её ширину. Общее правило держит
   ошибку в ячейке узкой (220px, чтобы не растягивать колонку таблицы),
   но здесь ячейка и есть вся строка, и перенос по слогам на четыре
   строки читается хуже одной фразы. */
table.lines tr.lineerr td { white-space: normal; }
table.lines tr.lineerr .err { max-width: none; }
/* Отмеченная к удалению строка гаснет, но остаётся читаемой: её
   ещё могут вернуть, сняв галочку. */
table.lines tr.dropped td { opacity: .45; text-decoration: line-through; }
table.lines tr.dropped td:last-child { opacity: 1;
  text-decoration: none; }
/* Повторённое направление подсвечивается сразу, пока человек ещё
   в строке. Красным помечены три поля, из которых состоит повтор,
   а не строка целиком: числа и цены в ней ни при чём. */
table.lines tr.dupe td:nth-child(-n+3) { background: #fdf3f3; }
table.lines tr.dupe td:nth-child(-n+3) select,
table.lines tr.dupe td:nth-child(-n+3) input { border-color: #c0392b; }
.totals { font-weight: 600; padding: 6px 0; }
/* «Цены закупа нет» — не ошибка ввода, а состояние реестра: жёлтым,
   как остальные предупреждения, а не красным. */
.warn-text { color: #8a6d1f; }

/* Ячейка с галочками по центру: в таблице строк формы их две подряд,
   и слева они читаются как подписи соседней колонки. */
td.mid { text-align: center; }
td.mid label { display: inline-block; margin-right: 8px; font-size: 12px;
  color: var(--muted); white-space: nowrap; }
