/* Fisc.AI — дизайн-система.
 *
 * Плотный «бухгалтерский» интерфейс, а не лендинг: строки 34 px, контролы 36 px,
 * сетка 8 px, границы вместо теней, никаких градиентов. Бухгалтер смотрит в эту
 * таблицу весь день, и каждый лишний пиксель отступа — это строка, которая не
 * поместилась на экран.
 *
 * Палитра взята из sms_monitoring_web: navy #192d4d / #2d4d77, жёлтый #F4CB11,
 * зелёный #2FA36B, красный #EE3735. Она проверена и узнаваема, и те же три
 * цвета сразу дают семантику уверенности распознавания на этапе 9.
 *
 * Тёмная тема — переопределением токенов. Состояний два, и оба явные: тему
 * ставит сервер атрибутом data-theme на <html>, считая её из профиля или куки.
 * Media-блока под prefers-color-scheme здесь нет намеренно — см. комментарий у
 * тёмной палитры ниже.
 *
 * Внешних ресурсов нет вообще: ни шрифтов с CDN, ни иконочных наборов. Через
 * сервис проходит чужая первичка, и страница физически не должна уметь
 * обратиться на сторонний хост.
 */

:root {
  /* Полосы прокрутки, выпадающие списки и прочее, что рисует сам браузер,
     обязаны знать тему. Без этого они остаются светлыми на тёмной странице, а
     поле без наших стилей получает чёрный текст по умолчанию — ровно то, что
     случилось с реквизитами на экране проверки. */
  color-scheme: light;

  --navy: #192d4d;
  --navy-2: #2d4d77;
  --yellow: #f4cb11;
  --green: #2fa36b;
  --red: #ee3735;
  /* Метки учебника («Как работать»): номер на снимке и тот же номер в списке.
     Цвет свой, которого нет ни у статусов, ни у кнопок: метку нельзя спутать
     с красным замечанием или жёлтым предупреждением на самом снимке. */
  --mark: #7c3aed;

  /* Поверхности светлой темы подобраны замером, а не на глаз. Было:
     панель против фона 1.07, её рамка 1.28, разделитель строк ~1.09, подсветка
     строки под курсором 1.02 — то есть её не существовало. Текст при этом
     проходил по контрасту, и потому беда пряталась: она не в тексте, а в том,
     что белые панели стояли на почти белом фоне и держать структуру было
     нечем. В таблице на сто строк и девять колонок глазу не за что зацепиться. */
  --bg: #e9edf3;
  --panel: #ffffff;
  --panel-2: #eff3f8;
  --ink: #192d4d;
  --ink-2: #55647c;
  --ink-3: #8c99ad;
  --line: #c8d2e0;
  --line-2: #dde4ee;
  --accent: #2d4d77;
  --accent-ink: #ffffff;
  --focus: #4b7fc4;

  --ok-bg: #e8f6ef;
  --ok-ink: #1c7a4d;
  --warn-bg: #fdf6dc;
  --warn-ink: #8a6d09;
  --err-bg: #fdeaea;
  --err-ink: #b32020;

  --row-h: 34px;
  --ctl-h: 36px;
  --radius: 7px;
  --radius-lg: 11px;
  --gap: 8px;
  --sidebar: 216px;
  --content-max: 1400px;

  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
}

/* Тёмная палитра — одна, и только по явному `data-theme`.
   Копия под `prefers-color-scheme` удалена: с тех пор как тему ставит сервер
   атрибутом на <html> (включая страницы ошибок), она недостижима, а две
   палитры, которые надо держать в синхроне руками, однажды разъезжаются. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #0f1521;
  --panel: #161f2e;
  --panel-2: #1b2534;
  --ink: #e7ecf4;
  --ink-2: #a8b6cb;
  --ink-3: #74839a;
  --line: #26324a;
  --line-2: #1e2839;
  --accent: #6f9dd8;
  --accent-ink: #0f1521;
  --focus: #7fb0e8;
  --ok-bg: #14301f;
  --ok-ink: #6fd39c;
  --warn-bg: #332a08;
  --warn-ink: #e8c541;
  --err-bg: #3a1414;
  --err-ink: #f08a8a;
  --mark: #8b5cf6;
}

* { box-sizing: border-box; }

/* `hidden` обязан прятать. Браузер задаёт `[hidden] { display: none }` слабым
   правилом, и любой класс с собственным `display` его перебивает — молча.
   Так счётчик предупреждений показывал «0» рядом с числом ошибок: разметка
   ставила `hidden`, а `.chip { display: inline-flex }` оказывался сильнее.
   Ошибка не видна ни в разметке, ни в коде скрипта — только на экране. */
[hidden] { display: none !important; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 14px/1.5 var(--sans);
  -webkit-font-smoothing: antialiased;
}

/* Числа выравниваются по разрядам всегда, где они могут стоять в столбик.
 * Суммы, которые «прыгают» по ширине цифр, невозможно сверять глазами. */
.num, td.num, input[type="number"], .mono { font-variant-numeric: tabular-nums; }
.mono { font-family: var(--mono); }

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

:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }

/* ── Оболочка ─────────────────────────────────────────────────────────────── */

.shell { display: grid; grid-template-rows: auto 1fr; min-height: 100vh; }

.topbar {
  display: flex; align-items: center; gap: 16px;
  height: 52px; padding: 0 16px;
  background: var(--navy); color: #fff;
  border-bottom: 1px solid var(--navy);
}
.topbar .brand { display: flex; align-items: baseline; gap: 8px; font-weight: 650; letter-spacing: -0.01em; }
.topbar .brand .dot { color: var(--yellow); }
.topbar .tagline { color: #b9c6da; font-size: 12px; }
.topbar .spacer { flex: 1; }
.topbar .who { color: #d7e0ec; font-size: 13px; }
.topbar a { color: #d7e0ec; }
.topbar form { display: inline; }

.body { display: grid; grid-template-columns: var(--sidebar) 1fr; min-height: 0; }
/* Дети grid не сжимаются уже своего содержимого: у них `min-width: auto`, и
   это не мелочь оформления, а причина горизонтальной прокрутки всей страницы.
   Пока её нет, `overflow-x: auto` у меню и у обёртки таблицы бесполезны —
   контейнеру просто не дают стать уже, и он растягивает тело вместе с шапкой.

   Замерено на боевом сервисе через рамку нужной ширины: «Позиции» при 390 px
   уезжали на 349, «Настройки» на 273, список документов при 768 на 632 и при
   1024 на 592. С этой строкой — ноль во всех четырёх. */
.body > * { min-width: 0; }

.sidebar {
  border-right: 1px solid var(--line);
  background: var(--panel);
  padding: 12px 8px;
  display: flex; flex-direction: column; gap: 2px;
}
.sidebar a {
  display: block; padding: 7px 10px; border-radius: var(--radius);
  color: var(--ink-2); font-size: 13.5px;
}
.sidebar a:hover { background: var(--line-2); text-decoration: none; }
.sidebar a[aria-current="page"] { background: var(--accent); color: var(--accent-ink); font-weight: 600; }
.sidebar .group { margin-top: 14px; padding: 0 10px 4px; color: var(--ink-3); font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; }

main { padding: 18px 20px 40px; max-width: var(--content-max); }

h1 { margin: 0 0 4px; font-size: 19px; letter-spacing: -0.01em; }
h2 { margin: 22px 0 8px; font-size: 15px; }
.subtitle { margin: 0 0 18px; color: var(--ink-2); font-size: 13px; }

/* ── Панели и сетки ───────────────────────────────────────────────────────── */

.panel {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 16px;
}
/* Свёрнутая панель полей: видны только те, у которых есть замечание. Класс
   ставит скрипт, поэтому без него видно всё. */
[data-fields].folded tr[data-quiet],
[data-fields].folded .fieldrow[data-quiet] { display: none; }

/* Квота одной строкой. Три карточки во всю ширину занимали треть первого
   экрана при каждом входе, а нужны раз в месяц. Полосы остались — приближение к
   пределу видно без чтения цифр, — но высотой в строку. */
.quota-bar {
  display: flex; flex-wrap: wrap; gap: 18px; align-items: baseline;
  padding: 9px 12px; margin-bottom: 12px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
}
.quota-item {
  display: flex; align-items: baseline; gap: 7px;
  color: inherit; text-decoration: none;
}
a.quota-item:hover .value { text-decoration: underline; }
.quota-item .label { color: var(--ink-2); font-size: 12px; }
.quota-item .value { font-size: 14px; font-weight: 650; font-variant-numeric: tabular-nums; }
.quota-item .of { color: var(--ink-3); font-size: 12px; font-weight: 400; }
/* Полоса в строке: узкая и короткая, её задача — показать долю, а не число. */
.quota-item .meter { width: 74px; height: 4px; align-self: center; }

/* Панель отбора. Поле поиска тянется, остальное по содержимому: при сужении
   окна первым отдаёт место именно оно. */
.filters { gap: 8px; margin-bottom: 10px; }
/* `width: 100%` у полей ввода задано глобально — для форм в колонку это верно,
   а в ряду отбора каждое поле занимало всю ширину и уезжало на свою строку.
   Здесь ширину задаёт flex, поэтому `width` снимается. */
.filters select, .filters input[type="search"], .filters input[type="date"] {
  width: auto; height: var(--ctl-h); padding: 0 9px; font-size: 13px;
  background: var(--panel-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius);
}
.filters .grow { flex: 1 1 220px; min-width: 160px; }
.filters select { flex: 0 1 auto; max-width: 230px; }
/* Сумма и даты занимают ровно столько, сколько в них помещается: строка отбора
   и так длинная, а поле под «550,40» шириной в поиск по названию вытеснило бы
   порядок на вторую строку. */
.filters .narrow { flex: 0 0 auto; width: 9em; }
.filters input[type="date"] { width: 10.5em; }
/* «с … по …» держатся вместе: на узком экране ряд переносится, и поле даты
   без своей подписи уезжало на строку одно. */
.filters .daterange { display: inline-flex; align-items: center; gap: 6px; flex: 0 1 auto; }

/* Строка постраничной навигации: подпись слева, кнопки справа. */
.pager { gap: 8px; margin-top: 10px; align-items: center; }
.pager .spacer { flex: 1; }

/* Ссылка, которая не выглядит ссылкой: в плотной таблице подчёркивание на
   каждой строке — это шум, а цвет ссылки спорит с цветом состояния. Ведёт себя
   как ссылка (правый клик, средняя кнопка, Tab), а выглядит как текст. */
.rowlink { color: inherit; text-decoration: none; display: block; }
/* Обрезка длинного имени: строка таблицы должна быть одной высоты у всех. */
/* Обрезка длинного имени: строка таблицы должна быть одной высоты у всех, а
   сама таблица — помещаться в окно. С 22em она вылезала на 114 px, и колонка
   «Проверки» уезжала за край: обрезанная строка ради обрезанного столбца —
   обмен не в ту сторону. Полное имя остаётся в подсказке и в документе. */
.rowlink.clip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 15em; }
.cell-clip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
             max-width: 12.5em; display: block; }
.rowlink:hover { text-decoration: underline; }

.panel + .panel { margin-top: 12px; }
/* ...но не внутри сетки. Там расстояние задаёт `gap`, а верхний отступ у всех
   панелей, кроме первой, опускал их на 12 px — и ряд «Страницы · Хранилище ·
   Тариф» стоял ступенькой. Замерено в браузере: первая панель начиналась на
   266 px, две другие на 278. Правило написано для колонки панелей и в ряду
   означает не то же самое. */
.grid > .panel + .panel { margin-top: 0; }
.panel > h2:first-child { margin-top: 0; }

.grid { display: grid; gap: 12px; }

/* «Настройки»: две колонки, когда места хватает (28.09.2026). 340 px — меньше
   карточка реквизитов уже не вмещает пару «IDNO · код TVA»; при ширине
   содержимого меньше двух таких колонок сетка сама становится одной колонкой. */
.settings-grid {
  display: grid; gap: 12px; align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr));
}
.settings-col { display: grid; gap: 12px; align-content: start; }
.settings-grid .panel + .panel { margin-top: 0; }
/* Пара коротких полей в одну строку; на узком экране — одно под другим. */
.fields-pair {
  display: grid; gap: 0 14px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
}
.grid.cols-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }

.row { display: flex; align-items: center; gap: var(--gap); flex-wrap: wrap; }
.row.end { justify-content: flex-end; }

/* ── Формы ────────────────────────────────────────────────────────────────── */

label { display: block; margin-bottom: 4px; color: var(--ink-2); font-size: 12.5px; }
.field { margin-bottom: 12px; }

/* Флажок с подписью. Подпись — часть цели для мыши: попасть в строку проще,
   чем в квадратик 13×13, и это единственная причина, по которой флажок живёт
   внутри `label`, а не рядом через `for`. Выравнивание по верху: подпись из
   двух строк не должна тянуть флажок к своей середине. */

/* Пустой список: не сообщение об отсутствии, а первый шаг. Человек, впервые
   открывший сервис, спрашивает «что мне делать». */
.empty { padding: 26px 16px; text-align: center; }
.empty-title { font-size: 15px; font-weight: 650; margin: 0 0 10px; color: var(--ink); }
.empty-steps {
  display: inline-block; text-align: left; margin: 0 0 14px;
  padding-left: 20px; color: var(--ink-2); font-size: 13px; line-height: 1.7;
}

/* Область для перетаскивания. Пунктир — общепринятый знак «сюда можно
   бросить»; сплошная рамка читалась бы как поле ввода. */
.dropzone {
  border: 1.5px dashed var(--line); border-radius: var(--radius);
  padding: 22px 16px; background: var(--panel-2); text-align: center;
  transition: border-color .12s ease-out, background .12s ease-out;
}
/* Подписи в рамке — строками одна под другой, без абзацных отступов. */
.dropzone p.hint { margin: 6px 0 0; }
/* Поле выбора спрятано от глаз, но не от клавиатуры и не от формы: нажимается
   своей подписью, а это браузер, а не скрипт. Системная «Choose Files»
   выглядела чужой среди своих кнопок и по-английски в русском интерфейсе. */
.file-input {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); border: 0;
}
.file-input:focus-visible + .btn { outline: 2px solid var(--focus); outline-offset: 2px; }
.dropzone .btn { display: inline-block; cursor: pointer; }
.dropzone.over { border-color: var(--accent); background: var(--ok-bg); }
/* Файл выбран: сплошная зелёная рамка и зелёная строка с именем. Пунктир
   значит «сюда можно бросить», сплошная — «уже лежит, можно отправлять». */
.dropzone.chosen { border-style: solid; border-color: var(--green); background: var(--ok-bg); }
.dropzone.chosen #config-file { color: var(--ok-ink); font-weight: 600; }
/* Без маркеров: поле выравнивает текст по центру, а маркер списка оставался у
   левого края, за полполя от имени файла (найдено 28.09.2026). */
.dropzone-list { margin: 8px 0 0; padding: 0; list-style: none; font-size: 12.5px; color: var(--ink-2); }
.dropzone-list li { font-variant-numeric: tabular-nums; }

.check { display: flex; gap: 8px; align-items: flex-start; margin-bottom: 12px; cursor: pointer; }
.check input { flex: none; margin: 2px 0 0; }
.check span { color: var(--ink-2); font-size: 12.5px; }
.hint { margin-top: 4px; color: var(--ink-3); font-size: 12px; }

/* Выбор одного из вариантов. Рамка вокруг всей строки, а не только вокруг
   кружка: попасть мышью в подпись проще, чем в радиокнопку, а бухгалтер
   работает быстро. */
.choice {
  display: flex; align-items: center; gap: 8px;
  margin-top: 6px; padding: 7px 10px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel-2);
  cursor: pointer;
}
.choice:hover { border-color: var(--ink-3); }
.choice:has(input:checked) { border-color: var(--accent); background: var(--panel); }
.choice input { margin: 0; }
/* Пометка выгоды у варианта («страница скана — 0,75») стоит в строке подписи:
   на телефоне она целиком переносится под подпись, а не сжимает её в три
   строки, как было отдельным элементом рядом. */
.choice .chip { margin-left: 4px; vertical-align: middle; }
.choice + .hint { margin: 4px 0 10px 10px; }

/* Перечислением типов это правило не работало. `input[type="text"]` не
   совпадает с `<input name="value">`: атрибута нет, а селектор требует его
   буквально. Такие поля оставались вовсе без наших стилей и рисовались
   браузером по умолчанию — белым прямоугольником с чёрным текстом.

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

   Поэтому от обратного: все поля ввода, кроме тех, у которых своя разметка. */
input:not([type="checkbox"], [type="radio"], [type="file"], [type="hidden"],
          [type="submit"], [type="button"]),
select, textarea {
  width: 100%; height: var(--ctl-h);
  padding: 0 10px;
  background: var(--panel-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius);
  font: inherit;
}
textarea { height: auto; padding: 7px 10px; line-height: 1.5; }
input:disabled, select:disabled { color: var(--ink-3); background: var(--line-2); }
input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--accent); }

button, .btn {
  height: var(--ctl-h); padding: 0 14px;
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--accent); color: var(--accent-ink);
  border: 1px solid transparent; border-radius: var(--radius);
  font: inherit; font-weight: 600; cursor: pointer;
}
button:hover, .btn:hover { filter: brightness(1.06); text-decoration: none; }
button.secondary, .btn.secondary { background: var(--panel-2); color: var(--ink); border-color: var(--line); }
button.danger, .btn.danger { background: var(--err-bg); color: var(--err-ink); border-color: var(--err-ink); }
/* Необратимое действие отделено рамкой. Не украшение: строки в таблице
   подписчиков стоят вплотную, и промах здесь ничем не откатывается. */
.danger-zone { border: 1px solid var(--err-ink); border-radius: var(--radius); padding: 12px; margin-top: 10px; }
/* Подвал: правовые страницы ищут внизу, а не в меню. */
.footer { display: flex; gap: 14px; align-items: center; padding: 14px 20px; border-top: 1px solid var(--line); font-size: 12px; }
.footer a { color: var(--muted); text-decoration: none; }
.footer a:hover { color: var(--ink); text-decoration: underline; }
.footer .muted { margin-left: auto; }

/* Правовые страницы читают целиком, а не сканируют: строка длиннее и
   промежуток больше, чем в рабочих таблицах. */
.legal { max-width: 62em; }
.legal h2 { font-size: 15px; margin: 18px 0 6px; }
.legal h2:first-child { margin-top: 0; }
.legal p { margin: 0 0 9px; line-height: 1.55; font-size: 14px; }

.danger-zone label { display: block; margin: 8px 0; font-size: 13px; }
button.small, .btn.small { height: 28px; padding: 0 9px; font-size: 12.5px; font-weight: 500; }
button:disabled { opacity: 0.55; cursor: not-allowed; }

/* ── Таблицы ──────────────────────────────────────────────────────────────── */

.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius-lg); }
table { width: 100%; border-collapse: collapse; background: var(--panel); }
thead th {
  position: sticky; top: 0; z-index: 1;
  height: 32px; padding: 0 10px; text-align: left;
  background: var(--panel-2); color: var(--ink-2);
  font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em;
  border-bottom: 1px solid var(--line); white-space: nowrap;
}
tbody td { height: var(--row-h); padding: 0 10px; border-bottom: 1px solid var(--line-2); }
/* Чересполосица. Не украшение: в плотной таблице на сто строк и девять
   колонок взгляд ведёт строку через 1360 пикселей, и без опоры соскальзывает на
   соседнюю. Приём, которым пользуются все финансовые таблицы, и не от бедности
   воображения.

   Подсветка под курсором — другого оттенка, с синевой акцента, а не просто
   серее. Прежде полоса (`--line-2` на 45%) и подсветка (`--panel-2`) совпадали
   почти в цвет: белая строка под курсором серела, а серая не менялась вовсе —
   владелец заметил 28.09.2026. Теперь полоса светлее, а подсветка темнее её и
   с синевой акцента — отзываются обе строки. Отметки замечаний живут на самом
   поле ввода (`cell-red input`), а не на клетке, поэтому ни полоса, ни
   подсветка их не перекрывают. */
tbody tr:nth-child(even) td { background: color-mix(in srgb, var(--line-2) 35%, transparent); }
tbody tr:hover td { background: color-mix(in srgb, var(--accent) 12%, var(--panel)); }
/* Таблица правки — без полос. Клетки там — поля ввода со своим фоном и рамкой,
   строку и так держит глаз, а полоса под серыми полями сливалась с ними. Взамен
   подсвечена строка, в которой сейчас курсор ввода: по ней видно, что правишь,
   даже когда мышь ушла к скану. */
table:has(td :is(input:not([type="checkbox"], [type="hidden"]), textarea))
  tbody tr:nth-child(even) td { background: none; }
table:has(td :is(input:not([type="checkbox"], [type="hidden"]), textarea))
  tbody tr:is(:hover, :focus-within) td {
  background: color-mix(in srgb, var(--accent) 12%, var(--panel));
}
tbody tr:last-child td { border-bottom: 0; }
td.right, th.right { text-align: right; }
.nowrap { white-space: nowrap; }
/* Список документов: длинные двуязычные подписи шапки («Итого с TVA (Total cu
   TVA)») переносятся, а не распирают таблицу. С постоянным столбцом «Файл»
   (03.10.2026) девять столбцов при 1280 уезжали вбок, и «Проверки» с
   «Хранением» оказывались за краем. Отступы ячеек — 6 px вместо 10: при 1280
   этого и не хватало. */
.cards thead th { white-space: normal; line-height: 1.25; padding-top: 6px; padding-bottom: 6px;
                  vertical-align: bottom; }
.cards th, .cards td { padding-left: 6px; padding-right: 6px; }

/* ── Метки и полосы ───────────────────────────────────────────────────────── */

.chip {
  display: inline-flex; align-items: center; gap: 4px;
  height: 21px; padding: 0 8px; border-radius: 11px;
  font-size: 12px; font-weight: 600; white-space: nowrap;
}
.chip.ok { background: var(--ok-bg); color: var(--ok-ink); }
.chip.warn { background: var(--warn-bg); color: var(--warn-ink); }
.chip.err { background: var(--err-bg); color: var(--err-ink); }
.chip.mute { background: var(--line-2); color: var(--ink-2); }

/* Чип-ссылка: цифра состояния и есть отбор по нему. Цвет берётся у чипа, а не
   у ссылки, иначе «Требует проверки 101» стало бы синим и перестало читаться
   как состояние. Подчёркивание при наведении заменено рамкой: у чипа скруглённый
   фон, и подчёркивание под ним выглядит артефактом. */
a.chip { color: inherit; cursor: pointer; }
a.chip:hover { text-decoration: none; box-shadow: inset 0 0 0 1px currentColor; }
a.chip[aria-current] { box-shadow: inset 0 0 0 1px currentColor; }

.meter { height: 6px; border-radius: 3px; background: var(--line-2); overflow: hidden; }
.meter > span { display: block; height: 100%; background: var(--accent); }
.meter.warn > span { background: var(--yellow); }
.meter.err > span { background: var(--red); }

.stat { display: flex; flex-direction: column; gap: 5px; }
.stat .label { color: var(--ink-2); font-size: 12px; }
.stat .value { font-size: 19px; font-weight: 650; font-variant-numeric: tabular-nums; }
.stat .of { color: var(--ink-3); font-size: 13px; font-weight: 400; }

/* ── Сообщения ────────────────────────────────────────────────────────────── */

.alert { padding: 9px 12px; border-radius: var(--radius); border: 1px solid transparent; margin-bottom: 12px; font-size: 13px; }
.alert.ok { background: var(--ok-bg); color: var(--ok-ink); border-color: var(--ok-ink); }
.alert.warn { background: var(--warn-bg); color: var(--warn-ink); border-color: var(--warn-ink); }
.alert.err { background: var(--err-bg); color: var(--err-ink); border-color: var(--err-ink); }

/* Полоса «вы смотрите чужой аккаунт». Жёлтая и во всю ширину: её задача —
   мешать забыть, а не украшать. Прилипает к верху, потому что забывают именно
   при прокрутке вглубь чужих документов. */
.stat .value.err-ink { color: var(--err-ink); }

/* Отметка о сохранении поля. Рядом с полем, а не сообщением наверху: там её не
   свяжут с тем, что человек только что набрал. */
.edit-note { margin-left: 7px; font-size: 12px; color: var(--muted); }
.edit-note.bad { color: var(--err-ink); font-weight: 600; }
/* В клетке таблицы строк отказ рядом с полем не помещается: графа ставки
   шириной в две цифры, и текст «такой ставки нет…» переносился столбиком
   поверх соседней клетки. Найдено при проверке починки двенадцатого аудита.
   Там он всплывает под полем — поверх таблицы и читаемо. */
td .inline-edit { position: relative; }
/* «изменить» у подтверждённой позиции строки: ссылка, а форма — по щелчку. */
.inline-change { display: inline-block; margin-left: 6px; }
.inline-change > summary { cursor: pointer; list-style: none; }
.inline-change > summary::-webkit-details-marker { display: none; }
.inline-change[open] > form { margin-top: 4px; }
/* Открытый выбор — под именем, на всю клетку: рядом с именем список сжимался
   до пяти знаков, и выбирать приходилось вслепую. */
.inline-change[open] { display: block; margin-left: 0; }
.inline-change[open] select { min-width: 12em; max-width: 22em; }
td .inline-edit .edit-note.bad {
  position: absolute; left: 0; top: calc(100% + 2px); z-index: 5; margin: 0;
  width: max-content; max-width: 18em; white-space: normal; text-align: left;
  background: var(--panel); border: 1px solid var(--err-ink); border-radius: 6px;
  padding: 4px 8px; box-shadow: 0 2px 8px rgb(0 0 0 / 12%);
}

/* Указатель: рамка, которую человек рисует мышью. Отдельная от подсветки —
   одна показывает, где мы нашли поле, вторая где человек говорит его искать. */
.scan-page.drawing { cursor: crosshair; }
.scan-page.drawing img { user-select: none; }
.scan-draw {
  position: absolute; border: 2px solid var(--yellow);
  background: color-mix(in srgb, var(--yellow) 18%, transparent);
  pointer-events: none;
}
/* Выбор поля — поверх скана, у самой рамки (координаты ставит скрипт). */
/* Выбор поля для указателя — строкой над листом, как и подсказка режима. Прежде
   он стоял рядом с рамкой внутри листа: масштабировался вместе со сканом,
   обрезался краем окна, а нажатие на список перехватывалось как начало новой
   рамки — список не раскрывался, и видно было одну «Серию» (29.09.2026). */
.anchor-pick {
  flex-basis: 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px;
  margin: 0; padding: 6px 9px; border-radius: var(--radius);
  background: var(--panel); border: 1px solid var(--accent);
}
.anchor-pick select { width: auto; max-width: 100%; flex: 1 1 18em; }
.anchor-pick .anchor-note { flex-basis: 100%; }
.hint.bad { color: var(--err-ink); font-weight: 600; }
/* Доля правок красится по величине: отчёт читают, чтобы решить, что чинить
   следующим, и цвет отвечает на это быстрее числа. */
td.err-ink { color: var(--err-ink); font-weight: 600; }
td.warn-ink { color: var(--warn-ink); }

.impersonation-bar {
  position: sticky; top: 0; z-index: 30;
  background: var(--yellow); color: #1b1b1b;
  padding: 7px 16px; font-size: 13px; font-weight: 600;
  text-align: center; letter-spacing: 0.01em;
}

/* ── Вход ─────────────────────────────────────────────────────────────────── */

.centered { min-height: 100vh; display: grid; place-items: center; padding: 20px; }
.card { width: 100%; max-width: 380px; background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 26px 26px 22px; }
.card h1 { font-size: 18px; }
.card .brandline { display: flex; align-items: baseline; gap: 7px; margin-bottom: 18px; font-weight: 700; font-size: 17px; }
.card .brandline .dot { color: var(--yellow); }
.card button { width: 100%; justify-content: center; margin-top: 6px; }
.card .foot { margin-top: 16px; display: flex; gap: 8px; align-items: center; justify-content: space-between; color: var(--ink-3); font-size: 12px; }
/* Форма языков — своя строка внутри подвала карточки. Без этого её сжимала
   кнопка темы, и RU переносился на вторую строку: на странице входа
   переключатель выглядел сломанным. Найдено глазами в браузере. */
.card .foot form { display: flex; gap: 6px; }
/* Кнопки карточки растянуты во всю ширину — это нужно «Войти», но не подвалу:
   кнопка темы занимала половину карточки. */
.card .foot button { width: auto; }

.muted { color: var(--ink-2); }
.small { font-size: 12.5px; }
.mt { margin-top: 12px; }
.stage-note { margin-top: 20px; color: var(--ink-3); font-size: 12.5px; }

/* Правка прямо в сетке: поле ввода не должно выглядеть тяжелее значения,
   иначе таблица из двадцати строк превращается в анкету. */
.inline-edit { display: flex; gap: 4px; align-items: center; margin: 0 }
/* Выбор позиции у строки — та же раскладка, что у правки поля, но обычной
   отправкой формы: ответ на него — страница, а не короткий JSON. */
.inline-choice { display: flex; gap: 4px; align-items: center; margin: 0 }
.inline-choice button { padding: 2px 8px; height: 26px }
.inline-edit input { width: 100%; padding: 2px 6px; height: 26px; font-size: 13px }
.inline-edit input.num { text-align: right }
/* IBAN — двадцать четыре знака, и в клетке выписки они должны быть видны
   целиком: обрезанный счёт контрагента нечем сверить с бумагой. */
.inline-edit input.mono { font-family: var(--mono); font-size: 12px }

/* Назначение платежа — единственное поле выписки, которое в строку не
   укладывается: у «Decontari tranzactionale …» бывает по четыре строки, и
   бухгалтер по ним и понимает, что это за платёж. Пока клетка была текстом,
   он переносился сам; ставшее полем ввода назначение обрезалось, и это было
   хуже, чем до правки. */
.inline-edit textarea {
  padding: 3px 6px; font-size: 13px; line-height: 1.35;
  resize: vertical; min-height: 26px;
  field-sizing: content; /* где поддержано — высота по содержимому */
}
.inline-edit button { padding: 2px 8px; height: 26px }
td.cell-red :is(input, textarea) {
  border-color: var(--red); background: color-mix(in srgb, var(--red) 8%, transparent) }
td.cell-yellow :is(input, textarea) {
  border-color: var(--yellow); background: color-mix(in srgb, var(--yellow) 12%, transparent) }

/* Слой подсветки поверх скана. Рамка позиционируется в долях изображения:
   страница показывается в разной ширине на разных экранах, а координаты слов
   сняты в долях — это единственный способ не пересчитывать их на каждый резайз. */
/* Окно просмотра скана. Увеличение — на обёртке, а не на изображении: слой
   подсветки задан в долях родителя, и масштабируется вместе с ним. */
.scan-viewport {
  position: relative; overflow: hidden;
  border: 1px solid var(--line); border-radius: 7px;
  background: var(--panel-2); margin-bottom: 8px;
  touch-action: none;
}
.scan-viewport.zoomed { cursor: grab; }
.scan-viewport.dragging { cursor: grabbing; }
.scan-viewport .scan-page { transform-origin: 0 0; margin: 0; }
.scan-viewport img { border: 0; border-radius: 0; }

/* Строка над листом: слева заметка о пачке и сроке хранения, справа кнопки.
   Прежде кнопки лежали поверх скана — «место на экране дороже строки под
   ним», — но с полем числа и «Указать поле» панель выросла до 400 px и
   закрывала правый верх бланка, где стоят номер и дата (29.09.2026). Строка
   заметки над сканом была и так, поэтому высоты это почти не стоит. На узком
   окне кнопки переносятся вниз, а не уезжают за край. */
.scan-bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 6px 10px; margin: 0 0 6px;
}
.scan-bar .scan-note { margin: 0; }
.scan-tools {
  display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 4px; align-items: center;
  margin-left: auto;
}
.scan-tools button { min-width: 28px; height: 26px; padding: 0 7px; }
/* Масштаб числом: «− [100]% +». Поле узкое и с цифрами одной ширины. Без
   отступа снизу, который у подписей по умолчанию: с ним поле стояло на 2 px
   выше кнопок (замечание владельца 29.09.2026). */
.zoom-level {
  display: inline-flex; align-items: center; gap: 2px; margin: 0;
  font-size: 12.5px; color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.zoom-level input {
  width: 4.2em; height: 26px; padding: 0 4px; text-align: right;
  font-size: 12.5px; font-variant-numeric: tabular-nums;
}
/* Режим указателя: подсказка во всю строку над листом, под кнопкой, которая
   его включила. Она же показывает «указатель сохранён». */
.scan-draw-hint {
  flex-basis: 100%; margin: 0;
  padding: 6px 9px; border-radius: var(--radius);
  font-size: 12.5px; line-height: 1.35;
  background: var(--warn-bg); color: var(--warn-ink); border: 1px solid var(--line);
}
.scan-draw-hint.ok { background: var(--ok-bg); color: var(--ok-ink); }

/* Слой прочитанного: лежит поверх изображения и повторяет его размер, потому
   что рамки заданы в долях родителя. Сам слой прозрачен для мыши — кликаются
   только рамки внутри, иначе он перехватывал бы рисование указателя. */
.scan-hits { position: absolute; inset: 0; pointer-events: none; }
.scan-hits > .scan-hit { pointer-events: auto; }
.scan-page.drawing .scan-hits { pointer-events: none; }
.scan-page.drawing .scan-hits > .scan-hit { pointer-events: none; }

.scan-page { position: relative; margin-bottom: 8px }
.scan-page img { width: 100%; display: block; border: 1px solid var(--line); border-radius: 7px }
.scan-box {
  position: absolute; pointer-events: none; border-radius: 3px;
  border: 2px solid var(--yellow);
  background: color-mix(in srgb, var(--yellow) 18%, transparent);
  transition: all .12s ease-out;
}
/* Пришли сюда по красному замечанию — место на скане обведено красным: это то,
   с чем сверять исправление. */
.scan-box[data-tone="err"] {
  border: 3px solid var(--red);
  background: color-mix(in srgb, var(--red) 16%, transparent);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--red) 25%, transparent);
}
/* Зелёная, как у полей шапки: полоска значит «покажу на скане», а жёлтый на
   этом экране — «проверьте». В таблице строк она была жёлтой, и найденные на
   скане наименования выглядели как замечания (аудит 29.09.2026). */
.inline-edit input.has-box { border-left: 3px solid var(--green) }

/* ── Модальное подтверждение ──────────────────────────────────────────────
   Для действий с необратимыми последствиями: надпись на кнопке их не
   вмещает, а confirm() браузера не переводится и выглядит одинаково у
   безобидного и у необратимого действия. Разметку создаёт app.js. */
.modal-back {
  position: fixed;
  inset: 0;
  background: rgb(0 0 0 / 45%);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  z-index: 50;
}

.modal-back[hidden] {
  display: none;
}

/* Широкое окно — для картинки. Страница пачки в 520 px читается не лучше
   миниатюры, ради которой её и открыли: нужны номер и дата на бланке. */
.modal.wide { max-width: min(1100px, 96vw); }
.modal.wide img { max-height: 78vh; object-fit: contain; background: var(--panel-2); }

.modal {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 18px 20px;
  max-width: 520px;
  width: 100%;
  box-shadow: 0 10px 30px rgb(0 0 0 / 25%);
}

.modal h3 {
  margin: 0 0 8px;
  font-size: 16px;
}

.modal .what {
  margin: 0 0 16px;
  color: var(--text);
  font-size: 14px;
  line-height: 1.5;
}

/* Отодвинуть элемент вправо в строке: удаление не должно стоять вплотную к
   утверждению — соседство необратимого с обычным приглашает промахнуться. */
.ml-auto {
  margin-left: auto;
}

/* Числовое поле правки не должно сжиматься до нечитаемости. `table` тянется
   на всю ширину контейнера и отбирает место у узких колонок: цена `5.47`
   обрезалась до `5.4`, а колонки за правым краем были недостижимы. Обёртка
   умеет прокручиваться (`overflow-x: auto`), поэтому правильнее дать полям
   минимум и позволить таблице выйти за ширину панели. */
.inline-edit input.num {
  min-width: 7ch;
}

.inline-edit input:not(.num) {
  min-width: 14ch;
}

/* Итоги документа — снаружи прокручиваемой таблицы. Внутри они были клетками
   с colspan, зависели от числа колонок и уезжали за правый край вместе с
   последней колонкой: подпись «Итого с TVA» была видна, числа не было.
   Это первое, что бухгалтер сверяет с бумагой. */
.totals {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  justify-content: flex-end;
  padding: 10px 12px 2px;
}

.totals > div {
  display: flex;
  gap: 10px;
  align-items: baseline;
}

.totals .label {
  color: var(--ink-2);
  font-size: 13px;
}

.totals .num {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.totals .grand .label,
.totals .grand .num {
  font-size: 16px;
  color: var(--ink);
}

/* ── Узкий экран ──────────────────────────────────────────────────────────────
   Всё, что зависит от ширины, живёт здесь, в самом конце файла, и это не
   вкусовщина: правила одинаковой силы разрешаются порядком, и media-запрос,
   стоящий выше базового правила, молча проигрывает ему. Именно так и вышло с
   первой попыткой: `.sidebar` ниже возвращал себе `flex-direction: column`, и
   меню на телефоне оставалось столбцом шириной в экран.
   ───────────────────────────────────────────────────────────────────────── */

/* На узком экране боковое меню становится горизонтальной полосой, а не
   исчезает. Раньше здесь стояло `display: none`, и с телефона были недоступны
   «Загрузки», «Поставщики», «Настройка 1С» и «Настройки» — всё, кроме списка
   документов. При том что снять документ телефоном — очевидный сценарий.

   Полосой, а не кнопкой-гамбургером: спрятанное за кнопкой меню требует
   догадки, что оно там есть, а места полоса занимает одну строку. Прокрутка
   вбок нужна только когда пунктов больше, чем помещается. */
@media (max-width: 860px) {
  .body { grid-template-columns: 1fr; }
  .sidebar {
    flex-direction: row; gap: 4px;
    border-right: 0; border-bottom: 1px solid var(--line);
    padding: 6px 8px; overflow-x: auto; scrollbar-width: thin;
  }
  .sidebar a { white-space: nowrap; padding: 6px 10px; }
  /* Заголовок раздела в полосе смысла не имеет: он разделял столбец. */
  .sidebar .group { display: none; }
}

/* Шапка на телефоне. Замерено: она не переносилась и была 458 px при экране
   390 — и тянула за собой всю страницу, включая список, который сам по себе
   помещался. То есть горизонтальная прокрутка на телефоне возникала не из-за
   таблицы, а из-за строки заголовка.

   Убирается пояснение под названием и логин: первое — украшение, второй виден
   в «Настройках». Язык, тема и выход остаются: это действия. */
@media (max-width: 720px) {
  .topbar { gap: 10px; padding: 0 10px; }
  .topbar .tagline, .topbar .who { display: none; }
}

/* Список документов на узком экране — карточками, а не таблицей.

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

   Через `order`, а не перестановкой разметки: одна таблица на оба случая, и
   порядок ячеек в HTML остаётся тем, в каком их читает голосовой доступ. */
@media (max-width: 720px) {
  /* Шапки у карточек нет, а фильтры столбцов есть: строка фильтров — блоком
     над карточками, у каждого поля подпись. Без неё на телефоне пропадал
     отбор по сумме — поле переехало в шапку (аудит 04.10.2026). Сортировка
     щелчком по заголовку здесь недоступна. */
  .cards thead { display: block; }
  .cards thead tr:first-child { display: none; }
  .cards thead tr.grid-filters {
    display: flex; flex-wrap: wrap; gap: 6px 10px; padding: 10px 12px;
    border-bottom: 1px solid var(--line);
  }
  .cards thead tr.grid-filters th {
    display: block; flex: 1 1 140px; padding: 0; border: 0; background: none;
  }
  .cards thead tr.grid-filters th:empty,
  .cards thead tr.grid-filters th.grid-note { display: none; }
  .cards .grid-filter-label { display: block; }
  .cards thead tr.grid-filters th.grid-sort-phone > * { display: block; }
  .cards thead tr.grid-filters th.grid-sort-phone select { width: 100%; }
  .cards, .cards tbody, .cards tr, .cards td { display: block; }
  .cards tbody tr {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 3px 10px;
    padding: 10px 12px; border-bottom: 1px solid var(--line);
  }
  /* Длинное имя без пробелов (IBAN, имя файла) иначе распирает карточку. */
  .cards tbody td, .cards tbody a { overflow-wrap: anywhere; }
  /* Ширина карточки — ширина экрана, и не больше. Без этого ячейка с
     `flex-basis: 100%` меряется от содержимого строки, строка растёт под неё, и
     таблица вылезает за окно на два десятка пикселей: замерено 416 при 390. */
  .cards { width: 100%; max-width: 100%; }
  .cards tbody tr { width: 100%; }
  .cards tbody td { border: 0; padding: 0; height: auto; min-width: 0; max-width: 100%; }
  .cards tbody tr:nth-child(even) td { background: none; }
  .cards td:nth-child(1) { order: 1; }
  /* Дата — третьей ячейкой разметки, документ — второй (см. список): на
     карточке порядок прежний — дата и сумма строкой, документ под ними. */
  .cards td:nth-child(3) { order: 2; }
  .cards td:nth-child(6) { order: 3; margin-left: auto; font-weight: 650; }
  .cards td:nth-child(2) { order: 4; flex-basis: 100%; }
  .cards td:nth-child(5) { order: 5; flex-basis: 100%; }
  .cards td:nth-child(7) { order: 6; }
  .cards td:nth-child(8) { order: 7; }
  .cards td:nth-child(4) { order: 8; }
  .cards td:nth-child(9) { order: 9; margin-left: auto; }
  /* Шапки у карточек нет — нет и сортировки с фильтрами столбцов; подсказка
     о них здесь говорила бы о невидимом. Остаются поиск, вид и даты сверху. */
  .grid-hint.for-table { display: none; }
  /* Обрезка по 15em рассчитана на колонку, а не на всю ширину карточки. */
  .cards .rowlink.clip, .cards .cell-clip { max-width: 100%; }
}

/* ── Экран проверки документа ─────────────────────────────────────────────
   Работает как приложение, а не как страница: страница целиком не
   прокручивается, прокручиваются области внутри неё.

   Причина замерена, а не выбрана по вкусу. В прежней раскладке страница была
   высотой 2,3 экрана из девяти панелей подряд: скан, реквизиты и строки
   товаров никогда не помещались вместе, а кнопка утверждения стояла за
   нижним краем — работать можно было только прокруткой. Бухгалтер сверяет
   три вещи одновременно, поэтому все три обязаны быть в одном поле зрения.

   Так же устроен этот экран у всех систем этого класса. */

body.app { overflow: hidden; }
body.app .shell { height: 100dvh; min-height: 0; }
body.app .body { min-height: 0; overflow: hidden; }
body.app main {
  padding: 0; max-width: none; min-height: 0; overflow: hidden;
  display: flex; flex-direction: column;
}
/* Сообщения над экраном не должны его сжимать до неработоспособности. */
body.app main > .alert { margin: 8px 10px 0; flex: none; }

/* Шапка документа: куда вернуться, что это и какой он по счёту в очереди.
   Место в очереди — не украшение: без него человек, проверяющий пачку из ста
   документов, не знает ни сколько осталось, ни куда его перебросит
   «следующий». */
.review-head {
  flex: none; display: flex; align-items: center; gap: 10px;
  height: 46px; padding: 0 12px;
  border-bottom: 1px solid var(--line); background: var(--panel);
}
.review-head .back { color: var(--ink-2); white-space: nowrap; }
/* Заголовок первого уровня, но по виду — строка шапки: размер и отступы
   наследуются от неё, иначе `h1` принёс бы сюда свои 24 px и разорвал ряд. */
.review-head .what {
  font-weight: 600; white-space: nowrap;
  font-size: inherit; margin: 0;
}
.review-head .who {
  color: var(--ink-2); font-size: 12.5px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
/* Поставщик в шапке ведёт ко всем его документам. Пунктир, а не синева:
   цвет ссылки отличался от соседнего текста на оттенок, и при 12,5 пикселя
   этого не видно — замерено на экране, найти её можно было только мышью. */
.review-head .who a { color: inherit; text-decoration: underline dotted; text-underline-offset: 3px; }
.review-head .who a:hover { color: var(--accent); text-decoration-style: solid; }

/* Место в очереди вместе со стрелками: «← 3 из 105 →» — одна группа. Край
   очереди — блёклая стрелка на своём месте, а не пропавшая. Класс свой, не
   `.pager`: тот уже занят листалкой списка, и его отступ сверху опускал
   стрелки на 5 px ниже «Удалить документ». */
.review-head .queue-nav {
  margin-left: auto; display: flex; gap: 6px; align-items: center;
}
.review-head .queue-nav [aria-disabled="true"] { opacity: 0.4; cursor: default; pointer-events: none; }
.review-head .place {
  color: var(--ink-3); font-size: 12.5px;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.review-head .tools { display: flex; gap: 4px; align-items: center; }
/* Подписи действий в шапке не переносятся: «Удалить документ» на 1280 px
   ломался в две строки. Не сжимаются они только в широком режиме — ниже
   раздел «Шапка документа не переносилась». */
.review-head .tools :is(.btn, button) { white-space: nowrap; }
/* «Утвердить» и «Пропустить» — одной строкой под главной кнопкой. */
.approve-more { justify-content: space-between; align-items: center; gap: 8px; margin-top: 6px; }

.review {
  flex: 1; min-height: 0;
  display: grid; grid-template-columns: var(--review-side, 400px) 1fr;
}
/* Та же причина, что у `.body`, уровнем глубже: дети grid не сжимаются уже
   своего содержимого. Таблица строк держала колонку в 1110 px внутри окна в
   388, а `.body` с `overflow-x: hidden` это не показывал — он просто обрезал
   левый край, вместе с кнопкой «к очереди» и началом каждой подписи. Молчаливая
   обрезка хуже прокрутки: прокрутку видно. */
.review > * { min-width: 0; }

/* Левая колонка: своя прокрутка сверху, прибитый низ снизу. Кнопка
   утверждения и список замечаний не уезжают никогда — это единственное, что
   человек ищет на этом экране постоянно. */
.review-side {
  display: grid; grid-template-rows: 1fr auto; min-height: 0;
  border-right: 1px solid var(--line); background: var(--panel);
}
/* Запас снизу — чтобы последнее поле кончалось раньше края, а не упиралось
   в него: докрутив до конца, человек должен видеть поле целиком. */
.review-side-scroll { overflow-y: auto; padding: 10px 12px 26px; }
.review-side-foot {
  border-top: 1px solid var(--line); padding: 8px 12px 10px;
  background: var(--panel);
  position: relative;
}
/* Мягкий край вместо ножа. Прокручиваемая колонка показывает меньше половины
   себя (замерено 20.09.2026: 495 из 1054 px), и её нижняя граница резала поле
   ввода пополам — на вид поломанная вёрстка, а не «ниже есть ещё». Найдено при
   аудите глазами.

   Градиент идёт из цвета панели в прозрачность поверх той же панели: над
   пустым местом он невидим сам собой, и различать «есть прокрутка или нет»
   скриптом не нужно. */
.review-side-foot::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: 100%;
  height: 22px; pointer-events: none;
  background: linear-gradient(to top, var(--panel), transparent);
}

/* Правая область: скан сверху, строки снизу, делитель между ними тянется. */
.review-main { display: grid; grid-template-rows: 1fr auto auto; min-height: 0; }
.review-scan { overflow: auto; min-height: 0; padding: 10px; }
.review-split {
  height: 7px; cursor: row-resize; background: var(--line-2);
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.review-split:hover { background: var(--accent); }
.review-content { overflow: auto; height: var(--lines-height, 250px); min-height: 0; }
.review-content > .panel { border: 0; border-radius: 0; }

/* Поле: подпись, значение и состояние слева. Кнопки «ОК» у поля нет —
   правка сохраняется, когда курсор уходит. Десять кнопок «ОК» на одном
   документе создавали впечатление, что каждое поле надо подтвердить
   отдельно; подтверждается документ. */
.fieldrow {
  display: grid; grid-template-columns: 16px 1fr; gap: 7px;
  align-items: center; padding: 2px 4px; border-radius: 6px;
}
.fieldrow + .fieldrow { margin-top: 1px; }
.fieldrow:hover { background: var(--line-2); }
.fieldrow.is-active { background: color-mix(in srgb, var(--accent) 16%, transparent); }
.fieldrow .mark { font-size: 12px; text-align: center; line-height: 1; }
.fieldrow .mark.ok { color: var(--green); }
.fieldrow .mark.warn { color: var(--warn-ink); }
.fieldrow .mark.err { color: var(--red); }
.fieldrow .mark.edited { color: var(--accent); }
.fieldrow .mark.empty { color: var(--ink-3); }
.fieldrow .flabel {
  display: block; font-size: 11px; color: var(--ink-3);
  letter-spacing: 0.02em; margin-bottom: 1px;
}
.fieldrow input {
  width: 100%; height: 27px; padding: 2px 7px; font-size: 13px;
}
.fieldrow input.mono { font-family: var(--mono); }
/* Поле, которое можно показать на скане: полоска слева, чтобы человек видел
   заранее, что клик по нему что-то покажет, и не тыкал наугад. */
.fieldrow input.has-box { border-left: 3px solid var(--green); }
/* Поле с замечанием — цветом самого поля, а не только значком слева: так
   человек видит, **что** исправлять, не читая список внизу. Тот же приём, что у
   клеток таблицы строк (`td.cell-red`). Значок обновляется после правки
   (`level()` в app.js), и цвет поля уходит вместе с ним. */
.fieldrow:has(> .mark.err) input[data-field],
[data-total].cell-red input[data-field] {
  border-color: var(--red); background: color-mix(in srgb, var(--red) 8%, transparent);
}
.fieldrow:has(> .mark.warn) input[data-field],
[data-total].cell-yellow input[data-field] {
  border-color: var(--yellow); background: color-mix(in srgb, var(--yellow) 12%, transparent);
}
.fieldrow:has(> .mark.err) span[data-field],
[data-total].cell-red span[data-field] { color: var(--red); font-weight: 600; }
span[data-field]:focus { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }

/* Переход по замечанию: строка поля вспыхивает цветом замечания и гаснет за
   пару секунд. Без вспышки фокус в поле сбоку экрана не замечали вовсе. */
.is-flash-err { --flash: var(--red); }
.is-flash-warn { --flash: var(--yellow); }
.is-flash {
  animation: fisc-flash 2.6s ease-out;
  border-radius: 6px;
}
@keyframes fisc-flash {
  0%, 35% {
    background: color-mix(in srgb, var(--flash) 22%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--flash) 70%, transparent);
  }
  100% { background: transparent; box-shadow: 0 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .is-flash { animation: none; box-shadow: 0 0 0 3px var(--flash);
              background: color-mix(in srgb, var(--flash) 18%, transparent); }
}
.fieldgroup {
  margin: 12px 0 5px; font-size: 11px; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--ink-3);
}
.fieldgroup:first-child { margin-top: 2px; }

/* Слой прочитанного на скане. Подсвечено **всё сразу**, а не по одному полю
   при фокусе: так за секунду видно, что прочитано и что пропущено, — ради
   этого слой и нужен. Активное поле выделяется жёлтым поверх зелёного. */
.scan-hit {
  position: absolute; border-radius: 2px; cursor: pointer;
  background: color-mix(in srgb, var(--green) 15%, transparent);
  outline: 1px solid color-mix(in srgb, var(--green) 40%, transparent);
}
.scan-hit:hover { background: color-mix(in srgb, var(--green) 30%, transparent); }
.scan-hit.is-active {
  background: color-mix(in srgb, var(--yellow) 32%, transparent);
  outline: 2px solid var(--yellow);
}

/* Замечания — одним списком у кнопки. Раньше их было три места: «Требует
   внимания», «Проверки» и красная полоса, и первые два показывали одно и то
   же. Три списка об одной ошибке читаются как три ошибки. */
.problem {
  display: grid; grid-template-columns: auto 1fr; gap: 7px;
  align-items: baseline; padding: 5px 0; cursor: pointer;
  border-top: 1px solid var(--line-2); font-size: 12.5px;
}
.problem:first-child { border-top: 0; }
.problem:hover .ptext { text-decoration: underline; }
/* «к полю →» — что на замечание можно нажать, словами (владелец 04.10.2026:
   «нажимаю на проблему — ничего не понятно»). */
.problem .pgo { color: var(--accent); white-space: nowrap; }
.problem:hover .pgo { text-decoration: underline; }
/* Замечание, по которому только что перешли, остаётся отмеченным: глаз
   возвращается к нему после правки. */
.problem.is-current {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  box-shadow: inset 3px 0 0 var(--accent); padding-left: 6px; border-radius: 4px;
}
.problem .pnum {
  display: block; color: var(--ink-3); font-size: 11.5px;
  font-variant-numeric: tabular-nums; margin-top: 1px;
}
.review-side-foot button[type="submit"].wide { width: 100%; margin-top: 8px; }

/* Строка таблицы, из-за которой не сходится итог. Раньше человек видел «Δ
   0.36» в итоге и искал виноватую строку глазами. */
tr.line-suspect > td { background: color-mix(in srgb, var(--warn-bg) 60%, transparent); }

/* Тёмная тема: скан — единственное белое пятно в пол-экрана. Бумага и должна
   быть белой, но на тёмном фоне лист бьёт по глазам, и соседние системы
   (Rossum) в тёмной теме приглушают подложку. Приглушается не изображение —
   его портить нельзя, по нему сверяют, — а рамка вокруг и фон области. Найдено
   при аудите глазами. */
:root[data-theme="dark"] .review-scan { background: #0f141c; }
:root[data-theme="dark"] .scan-viewport { box-shadow: 0 0 0 1px var(--line); }

/* Заголовок таблицы строк переносится по словам. Подписи здесь двуязычные —
   «Итого без TVA (Total fără TVA)» — и `white-space: nowrap`, верный для
   обычных таблиц, раздувал две числовые колонки до 242 и 177 px, отменяя
   заданные им ширины. Таблица становилась шире области на 136 px, и за краем
   оказывалась колонка «Позиция 1С» — ровно та, ради которой всё и делается.
   Замерено 20.09.2026 на экране 1710 px; после переноса таблица 1060 px в
   области 1094 и влезает целиком. Найдено при аудите глазами. */
.review-content thead th {
  white-space: normal;
  /* Плотнее обычной шапки: две строки двуязычной подписи против одной, и без
     этого таблица строк отдавала бы заголовку 91 px из 250 — треть области.
     Замерено 20.09.2026, вышло 46. */
  letter-spacing: 0; font-size: 11px; line-height: 1.15; padding: 4px 8px;
}

/* Ширины колонок держатся заданными, а не подгоняются под содержимое. Без
   этого браузер считал ширину по минимальному содержимому ячеек, а у ячейки с
   полем ввода оно равно нулю: числовые колонки сжимались до 77 px, и «2122.50»
   показывалось как «2122.5». Число в поле важнее подписи над ним. */
.review-content table { table-layout: fixed; }

/* Шапка таблицы строк держится при прокрутке. `position: sticky` у неё стоял с
   самого начала и не работал: `.table-wrap` с `overflow-x: auto` сам становится
   областью прокрутки по обеим осям, и шапка липла к нему, а не к
   `.review-content`, который на самом деле прокручивается. На пятнадцати
   строках человек доезжал до двенадцатой и переставал понимать, где цена, а где
   итог. Найдено при аудите глазами.

   Только в широком режиме: ниже 1100 px `.review-content` прокрутку отдаёт
   странице, и без своей области таблица вышла бы за край экрана. */
@media (min-width: 1101px) {
  .review-content .table-wrap { overflow: visible; }
  /* Стрелки и действия шапки не сжимаются: место уступает имя поставщика,
     которое и так обрезается многоточием. Уже 1100 px шапка сама переносится
     по строкам, и там запрет сжатия вытолкнул бы кнопки за край. */
  .review-head .queue-nav, .review-head .tools { flex: none; }
}

/* Планшет и узкий экран: колонки складываются, прокрутка возвращается.
   Проверять документы с планшета — обычное дело у бухгалтера. */
@media (max-width: 1100px) {
  /* Шапка документа не переносилась: 798 px содержимого в окне 390, и `.body`
     с `overflow-x: hidden` обрезал её молча — вместе с кнопкой «к очереди».
     Здесь ей и правда тесно: возврат, название, поставщик, место в очереди и
     четыре действия. Пусть занимает столько строк, сколько нужно. */
  .review-head {
    height: auto; flex-wrap: wrap; padding: 8px 12px; gap: 6px 10px;
  }
  .review-head .who { flex-basis: 100%; }
  .review-head .queue-nav { margin-left: 0; }
  .review-head .tools { flex-wrap: wrap; }

  body.app { overflow: auto; }
  body.app .shell { height: auto; min-height: 100vh; }
  body.app main { overflow: visible; }
  .review { grid-template-columns: 1fr; }
  .review-side { border-right: 0; border-bottom: 1px solid var(--line); }
  .review-side, .review-main { display: block; }
  .review-scan, .review-content { overflow: visible; height: auto; }
  .review-split { display: none; }
}

/* Итоги правятся, как и остальные поля. Ширина задана: без неё поле
   растягивалось на всю колонку итога и переставало читаться числом. */
.totals .inline-edit { display: block; }
.totals .inline-edit input {
  width: 100%; max-width: 9em; height: 26px; margin-left: auto;
  text-align: right; font-size: 15px; font-variant-numeric: tabular-nums;
}
.totals .grand .inline-edit input { font-size: 17px; font-weight: 600; max-width: 10em; }

/* Полоса действий над отмеченным. Прибита к низу окна и появляется, когда есть
   что делать.

   Раньше те же кнопки стояли внизу документа: список из ста строк — это
   4471 px, то есть отметить строку наверху и дойти до кнопки значило
   прокрутить четыре тысячи пикселей. Замерено на боевом сервере. */
.bulkbar {
  position: sticky; bottom: 0; z-index: 3;
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  margin-top: 10px; padding: 10px 12px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: 0 -2px 10px color-mix(in srgb, var(--ink) 8%, transparent);
}
/* Ширина выбора задана: без неё он растягивался на всю свободную ширину и
   разносил полосу на три ряда — при том что подписи в нём короткие.

   По выбранному пункту (`field-sizing`), а не по самому длинному: румынское
   «Fișier pentru 1C-ul dumneavoastră» в прежних 17em обрезалось до
   «…dumneavoa», а просто широкий выбор переносил русскую полосу во второй ряд.
   Найдено на снимках учебника. Где свойства нет, выбор ограничен 21em. */
.bulkbar select { width: auto; max-width: 21em; flex: 0 1 auto; field-sizing: content; }
.bulkbar .count { font-size: 13px; color: var(--ink-2); white-space: nowrap; }
.bulkbar .count b { font-variant-numeric: tabular-nums; color: var(--ink); }
.bulkbar .hint { margin-left: auto; }
/* Предупреждение о теряемых видах: своя строка во всю ширину полосы. В общем
   ряду оно ломало полосу надвое и прижималось к правому краю. Жёлтым, а не
   серым: это не пояснение, а то, что человек должен прочитать до нажатия. */
.bulkbar .export-warning {
  flex-basis: 100%; margin-left: 0;
  font-size: 12.5px; color: var(--warn-ink);
}

/* Строка сопоставления позиции: выбор и кнопка в один ряд. Без этого выбор
   занимал всю ширину ячейки и выталкивал кнопку на вторую строку — на экране
   из двухсот строк это двести лишних строк высоты. */
.row.nowrap { flex-wrap: nowrap; }
.row.nowrap select.grow { min-width: 0; }

/* Список горячих клавиш: клавиша слева, что делает — справа. */
.keys { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; margin: 0 0 16px; }
.keys dt { white-space: nowrap; }
.keys dd { margin: 0; color: var(--ink-2); font-size: 13px; }
kbd {
  display: inline-block; padding: 1px 6px; min-width: 1.4em; text-align: center;
  background: var(--panel-2); border: 1px solid var(--line);
  border-bottom-width: 2px; border-radius: 4px;
  font: 12px/1.6 var(--mono); color: var(--ink);
}

/* Кнопка, выглядящая ссылкой: действие есть, а веса у него нет. */
.linky {
  background: none; border: 0; padding: 0; height: auto;
  color: var(--ink-3); font: inherit; font-weight: inherit;
  text-decoration: underline dotted; cursor: pointer;
}
.linky:hover { color: var(--ink-2); }

/* Строка, доказанная арифметикой: её числа закреплены и своим отношением, и
   общим итогом, сверять глазами нечего. Зелёным и мелко — это разрешение
   пропустить, а не требование посмотреть. */
.proven { color: var(--green); font-size: 11px; }

/* Вопрос, на который уже ответили: тихой строкой, а не жёлтой панелью. Он
   больше не требует внимания, но и убирать его нельзя — человек должен видеть,
   что именно он подтвердил. */
.answered {
  display: grid; grid-template-columns: 16px 1fr; gap: 7px;
  align-items: start; margin: 0 0 6px; padding: 4px 0;
  color: var(--ink-3); font-size: 12.5px;
}

/* Документ без скана: место отдаётся содержимому, а не пустому прямоугольнику.
   У XML e-Factura картинки нет по устройству, у старого документа она удалена
   по сроку хранения — в обоих случаях верхняя область была белым пятном больше
   половины экрана. */
.review-main.no-scan { grid-template-rows: auto auto 1fr; }
.review-main.no-scan .review-scan { padding: 18px 12px; }
.review-main.no-scan .review-split { display: none; }
.review-main.no-scan .review-content { height: auto; }

/* Дом: работа тремя числами. Первое из них — то, что ждёт человека, и оно
   единственное, ради чего он открыл сервис. */
.work { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; }
.work-card {
  display: flex; flex-direction: column; gap: 2px;
  padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--panel); color: inherit;
}
.work-card:hover { border-color: var(--accent); text-decoration: none; }
.work-card .label { font-size: 12px; color: var(--ink-3); text-transform: uppercase;
  letter-spacing: 0.05em; }
.work-card .value { font-size: 30px; font-weight: 650; font-variant-numeric: tabular-nums;
  line-height: 1.1; }
.work-card .hint { margin: 0; }
/* Карточка с работой, которая ждёт сейчас: её видно первой и без чтения. */
.work-card.is-now { border-color: var(--warn-ink); background: var(--warn-bg); }
.work-card.is-now .value, .work-card.is-now .label { color: var(--warn-ink); }

/* Шаги первой настройки. Исчезают, когда сделаны все. */
/* Шаги первой настройки. Отметка, шаг и подсказка — тремя колонками; строки
   разделены линией, чтобы подсказка справа читалась со своим шагом, а не с
   соседним.

   Класс отметки — `todo`, а не `empty`: `.empty` — это блок пустого состояния
   с отступом в 26 пикселей и выравниванием по центру, и кружок, получивший его,
   уезжал под текст, разгоняя список на пол-экрана. Найдено глазами на свежем
   аккаунте: у всех, у кого настройка уже сделана, блока нет вовсе. */
.steps { list-style: none; margin: 8px 0 0; padding: 0; }
.steps li {
  display: grid; grid-template-columns: 16px 1fr auto; gap: 10px;
  align-items: baseline; padding: 8px 0; border-top: 1px solid var(--line-2);
}
.steps li:first-child { border-top: 0; }
.steps li.done { color: var(--ink-3); }
.steps .mark { font-size: 12px; line-height: 1.5; text-align: center; color: var(--ink-3); }
.steps .mark.ok { color: var(--green); }
.steps .mark.todo { color: var(--ink-3); }
/* Длинное название шага переносится внутри своей колонки, а не выдавливает
   подсказку за край: у ребёнка сетки ширина по умолчанию — по содержимому. */
.steps .step-name { min-width: 0; }

/* История документа: время слева узкой колонкой, событие справа. Сетка, а не
   строка с отступом, — иначе события с разной длиной времени не выстраиваются,
   и список читается как сплошной текст. */
/* Принятое человеком замечание остаётся на виду, но гаснет: оно больше не
   работа, а решение. Совсем убирать нельзя — тогда непонятно, почему документ
   сходится при расхождении на бумаге. */
.problem.is-accepted { opacity: .62; }
/* Следующее открытое замечание после действия по предыдущему: на миг
   подсвечено, чтобы взгляд нашёл его без поиска (тринадцатый аудит). */
.problem.is-next, [data-question].is-next {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  transition: background .8s ease-out;
}

.history { list-style: none; margin: 6px 0 0; padding: 0; }
.history li {
  /* Первая колонка — по содержимому, а не в долях: «19.09 22:28» шире любой
     догадки в em, и при заданной ширине время наезжало на событие. */
  display: grid; grid-template-columns: max-content 1fr; gap: 8px;
  align-items: baseline; padding: 3px 0;
}
.history .when { white-space: nowrap; }
.history .what { min-width: 0; overflow-wrap: anywhere; }

/* На телефоне подсказка уходит под шаг. Замерено рамкой в 390: три колонки
   ужимают название до двух слов в строке, и дата справа виснет над обрывком. */
@media (max-width: 720px) {
  .steps li { grid-template-columns: 16px 1fr; }
  .steps .step-hint { grid-column: 2; white-space: normal; }
}
.steps .step-no { color: var(--ink-3); margin-right: 2px; }
.steps .step-hint { font-size: 12px; color: var(--ink-3); white-space: nowrap; }

/* Сильное число в ряду: итог документа и конечное сальдо. Класс стоял в
   разметке с самого начала и не был описан — два самых важных числа экрана
   выглядели как все остальные. */
.strong { font-weight: 700; color: var(--ink); }

/* Форма из одной кнопки внутри строки. Без этого `form` остаётся блоком и
   разрывает ряд, в который её поставили. */
form.inline { display: inline; }

/* Остаток страниц в подвале меню. Тихо, пока не близко к пределу. */
.nav-quota {
  margin-top: auto; padding: 8px 10px; font-size: 12px;
  color: var(--ink-3); border-top: 1px solid var(--line-2);
}
.nav-quota:hover { color: var(--ink-2); text-decoration: none; }
.nav-quota.warn { color: var(--warn-ink); }
.nav-quota.err { color: var(--err-ink); font-weight: 600; }

/* Разделы списка. Не фишки отбора поверх архива, а ход работы: первый раздел —
   то, что ждёт человека, и он выбран по умолчанию. */
.tabs {
  display: flex; gap: 2px; flex-wrap: wrap;
  margin: 14px 0 0; border-bottom: 1px solid var(--line);
}
.tab {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 13px; border: 1px solid transparent; border-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  color: var(--ink-2); font-size: 13.5px; white-space: nowrap;
}
.tab:hover { background: var(--line-2); text-decoration: none; }
.tab.is-on {
  background: var(--panel); border-color: var(--line); color: var(--ink);
  font-weight: 600; margin-bottom: -1px; padding-bottom: 9px;
}
.tab .count { font-variant-numeric: tabular-nums; font-size: 12px; font-weight: 600;
  padding: 1px 6px; border-radius: 999px; }
.tab .count.warn { background: var(--warn-bg); color: var(--warn-ink); }
.tab .count.ok { background: var(--ok-bg); color: var(--ok-ink); }
.tab .count.err { background: var(--err-bg); color: var(--err-ink); }
.tab .count.mute { background: var(--line-2); color: var(--ink-3); }


/* Полоса месяцев над списком: бухгалтер закрывает период, и «покажи август» —
   один щелчок. Переносится на телефоне, как и всякий ряд фишек. */
.months {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 10px 0 0;
}
.months .chip {
  text-decoration: none;
}
.months .chip.mute:hover {
  background: var(--line);
  color: var(--ink);
}


/* ── Учебник «Как работать» ──────────────────────────────────────────────────
   Шаг — панель: номер, заголовок, как часто это делают, одна фраза, снимок и
   подписи под теми же номерами, что на снимке. Снимок во всю ширину панели, а
   не рядом со списком: сбоку он уменьшался вдвое, и подписи кнопок на нём
   переставали читаться. */
.guide { max-width: 1120px; }
.guide-flow {
  margin: 0 0 12px; padding: 10px 14px; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  font-size: 14px; line-height: 1.55;
}
.guide-toc { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }
.guide-toc a {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 4px 12px 4px 5px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--panel); color: var(--ink-2); font-size: 13px;
}
.guide-toc a:last-child { padding-left: 12px; }
.guide-toc a:hover { text-decoration: none; border-color: var(--accent); color: var(--ink); }
.guide-n {
  display: inline-grid; place-items: center; flex: none;
  min-width: 20px; height: 20px; padding: 0 4px; border-radius: 999px;
  background: var(--accent); color: var(--accent-ink);
  font-size: 11.5px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.guide-n.big { min-width: 28px; height: 28px; font-size: 14px; }
.guide-step { scroll-margin-top: 12px; }
.panel.guide-step + .panel.guide-step { margin-top: 14px; }
.guide-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.guide-head h2 { margin: 0; font-size: 17px; }
.guide-lead { margin: 10px 0 12px; font-size: 14px; line-height: 1.55; max-width: 62em; }
.guide-shot { margin: 0 0 14px; }
.guide-shot a { display: block; }
.guide-zoom { display: none; margin-top: 5px; font-size: 12.5px; }
@media (max-width: 720px) { .guide-zoom { display: block; } }
.guide-shot img {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 1px 4px rgba(25, 45, 77, 0.10);
}
.guide-marks {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: 8px 24px;
}
.guide-marks li { display: flex; gap: 9px; align-items: flex-start; font-size: 14px; line-height: 1.5; }
.guide-mark {
  flex: none; display: inline-grid; place-items: center;
  width: 22px; height: 22px; margin-top: 1px; border-radius: 50%;
  background: var(--mark); color: #fff; font-size: 12px; font-weight: 700;
}
.guide-points { margin: 0; padding-left: 20px; font-size: 14px; line-height: 1.55; }
.guide-points li + li { margin-top: 6px; }
/* Что делать дальше уже в 1С: снять её нечем, поэтому списком под снимком. */
.guide-then { margin: 16px 0 6px; font-size: 14px; font-weight: 650; }
/* «Если что-то не так»: что видите — жирным, что сделать — под ним. */
.guide-trouble { margin: 10px 0 0; font-size: 14px; line-height: 1.55; }
.guide-trouble dt { font-weight: 650; margin-top: 12px; }
.guide-trouble dt:first-child { margin-top: 0; }
.guide-trouble dd { margin: 3px 0 0; color: var(--ink-2); }
.guide-tip {
  margin: 14px 0 0; padding: 9px 12px; border-left: 3px solid var(--mark);
  background: var(--line-2); border-radius: 0 var(--radius) var(--radius) 0;
  font-size: 13px; line-height: 1.55; color: var(--ink-2);
}
.guide-next { margin: 12px 0 0; font-size: 14px; }
.guide-more { margin: 10px 0 0; padding-left: 20px; font-size: 14px; line-height: 1.55; }
.guide-more li + li { margin-top: 6px; }

/* «?» у заголовка экрана — ведёт в нужный шаг учебника. Кружком, а не словом:
   заголовок экрана остаётся заголовком, а подсказка — рядом, а не вместо. */
a.help {
  display: inline-grid; place-items: center; width: 20px; height: 20px;
  margin-left: 8px; border: 1px solid var(--line); border-radius: 50%;
  color: var(--ink-3); font-size: 12px; font-weight: 700; line-height: 1;
  vertical-align: 3px; text-decoration: none;
}
a.help:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }


/* ── Ход распознавания в списке документов ─────────────────────────────────
   Колесо и полоса — пока документы читаются «сразу»; в фоне («можно
   подождать») только строка. Замечание владельца 03.10.2026. */
.progress-panel {
  display: flex; gap: 12px; align-items: flex-start; margin-top: 12px;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel-2);
}
.progress-panel.is-working { border-color: var(--accent); background: var(--ok-bg); }
.progress-bar {
  height: 6px; margin-top: 8px; border-radius: 3px; background: var(--line); overflow: hidden;
}
.progress-bar > span {
  display: block; height: 100%; width: 0; background: var(--accent);
  transition: width .4s ease-out;
}
.spinner {
  flex: none; width: 18px; height: 18px; margin-top: 1px; border-radius: 50%;
  border: 2.5px solid var(--line); border-top-color: var(--accent);
  animation: fisc-spin .9s linear infinite;
}
/* Документ, который сейчас читается, — с маленьким колесом в метке. */
.chip.working::before {
  content: ""; display: inline-block; width: 9px; height: 9px; margin-right: 5px;
  vertical-align: -1px; border-radius: 50%;
  border: 1.5px solid currentColor; border-top-color: transparent;
  animation: fisc-spin .9s linear infinite;
}
@keyframes fisc-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .spinner, .chip.working::before { animation-duration: 3s; }
}
/* Строка списка — целиком ссылка на документ. */
tr[data-href] { cursor: pointer; }

/* ── Таблицы: сортировка и фильтры столбцов (04.10.2026) ─────────────────────
   Заголовок — кнопка или ссылка сортировки со стрелкой: бледная «↕» говорит,
   что по столбцу можно сортировать, «▲ ▼» — что выбрано. Под заголовками —
   строка полей фильтра; заданный фильтр подсвечен, чтобы было видно, какие
   столбцы сужают таблицу. Образец — таблица CDR в sms_monitoring_web. */
/* Строчный, а не гибкий блок: подпись внутри переносится перед скобкой
   («Итого с TVA / (Total cu TVA)»). Гибкий блок держал её в одну строку, и при
   1280 таблица документов снова уезжала за край. */
thead th .sort {
  /* Блоком во всю ширину заголовка: щёлкали по полю заголовка рядом с
     надписью, и ничего не происходило (аудит 04.10.2026). Блок переносит
     подпись так же, как строка, — в отличие от гибкого блока. */
  display: block; width: 100%;
  color: inherit; text-decoration: none; cursor: pointer;
  background: none; border: 0; padding: 0; height: auto; margin: 0;
  font: inherit; text-transform: inherit; letter-spacing: inherit; text-align: inherit;
}
thead th .sort:hover { color: var(--ink); }
.sort-mark { font-size: 10px; opacity: .35; margin-left: 4px; white-space: nowrap; }
thead th .sort:hover .sort-mark { opacity: .8; }
thead th .sort.is-on { color: var(--accent); }
thead th .sort.is-on .sort-mark { opacity: 1; }
/* Строка фильтров не липнет к верху вместе с заголовками: две липкие строки
   с одним `top` легли бы друг на друга. */
thead tr.grid-filters th {
  position: static; height: auto; padding: 4px 6px;
  text-transform: none; letter-spacing: 0; font-weight: 400; white-space: nowrap;
}
tr.grid-filters input, tr.grid-filters select {
  width: 100%; min-width: 0; height: 26px; padding: 2px 6px; font-size: 12px;
}
tr.grid-filters input.right { text-align: right; }
tr.grid-filters input:not(:placeholder-shown), tr.grid-filters input.is-set,
tr.grid-filters select:has(option:checked:not([value=""])) {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, var(--panel));
}
tr.grid-filters .grid-note { font-size: 11px; color: var(--ink-3); }
/* Выбор порядка в строке фильтров — только на телефоне, где заголовков нет. */
tr.grid-filters th.grid-sort-phone > * { display: none; }
/* Подпись поля фильтра — только на телефоне, где шапки нет (см. `.cards`). */
.grid-filter-label { display: none; font-size: 11px; color: var(--ink-3); margin-bottom: 2px; }
.grid-hint { margin: 10px 0 6px; }
.grid-status { margin: 6px 0; }
[data-grid] tr[hidden] { display: none !important; }

/* Значок ⧩ у значения под мышью: «отобрать по этому». Один на страницу —
   переезжает в ячейку, над которой мышь, и в остальных не мешает читать. */
[data-grid] td[data-filter-value] { position: relative; }
.cell-pick {
  position: absolute; right: 2px; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  height: 22px; width: 22px; padding: 0; border-radius: 5px;
  border: 1px solid var(--line); background: var(--panel); color: var(--accent);
  font-size: 12px; line-height: 1; cursor: pointer; box-shadow: 0 1px 3px rgba(0,0,0,.12);
}
.cell-pick:hover { background: color-mix(in srgb, var(--accent) 14%, var(--panel)); }
/* Под мышью строка подсвечена; мягкая тень того же цвета слева от воронки
   прячет конец обрезанного имени под ней, а не режет его посреди буквы. */
tr:hover > td > .cell-pick {
  box-shadow: 0 1px 3px rgba(0,0,0,.12),
              -8px 0 6px -1px color-mix(in srgb, var(--accent) 12%, var(--panel));
}
/* У чисел, прижатых вправо, — слева: справа она закрывала копейки. */
td.right > .cell-pick { right: auto; left: 2px; }
/* На сенсорном экране мыши нет — значок бы не появился вовсе; там остаются
   поля фильтра. */
@media (hover: none) { .cell-pick { display: none; } }

/* Таблица шире рамки: край, за которым есть продолжение, затухает (класс
   ставит app.js). Маска — на рамке, а не на содержимом: она не уезжает при
   прокрутке. Без неё обрезанный столбец читался как конец таблицы. */
.table-wrap.more-right { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
                         mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent); }
.table-wrap.more-left { -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 36px), transparent);
                        mask-image: linear-gradient(to left, #000 calc(100% - 36px), transparent); }
.table-wrap.more-left.more-right {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 36px, #000 calc(100% - 36px), transparent);
  mask-image: linear-gradient(to right, transparent, #000 36px, #000 calc(100% - 36px), transparent);
}

/* Главная на телефоне: название организации стоит, числа прокручиваются. */
@media (max-width: 720px) {
  table.sticky-first th:first-child, table.sticky-first td:first-child {
    position: sticky; left: 0; z-index: 1; min-width: 9em !important;
    background: var(--panel);
    box-shadow: 1px 0 0 var(--line);
  }
  table.sticky-first thead th:first-child { background: var(--panel-2); z-index: 2; }
  table.sticky-first tbody tr:nth-child(even) td:first-child {
    background: color-mix(in srgb, var(--line-2) 35%, var(--panel));
  }
}
/* Слева у такой таблицы стоит закреплённый столбец — его затухание задевало бы
   само название; остаётся только правый край. */
.table-wrap.more-left:has(> table.sticky-first) { -webkit-mask-image: none; mask-image: none; }
.table-wrap.more-left.more-right:has(> table.sticky-first) {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
}
