/* Minta Finance — прежние слои V2.2 под островком `.ds22`. ГЕНЕРИРУЕТСЯ: node scripts/ds/build-v23.mjs (scripts/ds/legacy-scope.mjs). Руками не править.
   Источники (правятся как прежде, затем пересборка): public/tokens.css, public/tokens-adesk.css, public/app.css, public/shell.css, public/ds/legacy-bridge.css, public/ds/base.css, public/ds/components.css.
   Каждое правило действует только внутри <div class="ds22"> — экраны без двойника V2.3 (KEEP). Слой V2.3 в островок не входит: `@scope (.ds23) to (.ds22)`. */
/* ═══ public/tokens.css ═══ */
/* Прежние имена переменных (--bg, --tx, --acc…) — ПЕРЕВЕДЕНЫ НА ПАЛИТРУ Minta DS V1
   (docs/design/v2.2/tokens.css, 25.09.2026). Имена остались, потому что ими
   пользуются сотни мест в экранах: переименование разом означало бы правку
   каждого экрана вслепую. Значения — дословно из канонических токенов:
   --bg=background, --surface2=surface-sunken, --surface3=surface-muted,
   --line=border, --line2=border-strong, --tx=text-primary, --tx2=text-secondary,
   --tx3=text-muted, --acc=accent-mint-strong (ссылка и акцент; главная кнопка
   нового интерфейса — --action-primary), --pos/--neg/--warn — positive/negative/
   warning, --c1..--c6 — chart-cat-1..6, --c7=chart-neutral, --c8=chart-expense.
   Тёмная тема — ПРЕЖНЯЯ возможность продукта; у V2.2 её нет, и новые цвета для
   неё не придуманы: там, где у DS есть обратная (inverse) палитра, взята она,
   остальное — прежние значения тёмной темы. Решение о её судьбе — за владельцем
   (docs/design/v2.2/IMPLEMENTATION-LEDGER.md, раздел «Решения»). */
.ds22{color-scheme:light;--bg:#F4F4F1;--surface:#FFFFFF;--surface2:#F9F9F7;--surface3:#EFEEEA;--line:#E3E2DD;--line2:#CFCEC7;--tx:#15171A;--tx2:#474B52;--tx3:#646973;--acc:#0B7366;--on-acc:#FFFFFF;--accs:#E3F3EF;--pos:#16733A;--neg:#B42318;--warn:#8F5600;--warnbg:#FBF1E1;--lock:#EFEEEA;--empty:#868A92;--sh:0 1px 2px rgba(21,23,26,.08),0 0 0 1px rgba(21,23,26,.06);--nav:#1B1D21;--nav2:#2A2D32;--navtx:#C9CCD1;--navtx3:#A7A9AE;--navon:#FFFFFF;--c1:#2F4F9A;--c2:#A88A57;--c3:#8E2F63;--c4:#4B9BC7;--c5:#8A62B9;--c6:#5E6A80;--c7:#B9BCC1;--c8:#15171A;--row-h:83px;--row-p:13px;--cols:57px 68px 138px minmax(180px,337fr) minmax(90px,131fr) minmax(110px,150fr) minmax(130px,187fr)}
.ds22[data-theme="dark"],[data-theme="dark"] .ds22,.ds22 [data-theme="dark"]{color-scheme:dark;--bg:#1B1D21;--surface:#2A2D32;--surface2:#2E3137;--surface3:#3A3D42;--line:#3A3D42;--line2:#4A4D52;--tx:#E7E6E1;--tx2:#C9CCD1;--tx3:#A7A9AE;--acc:#7FD1C1;--on-acc:#1B1D21;--accs:#2E3137;--pos:#7FD1A0;--neg:#f0736a;--warn:#dfb15f;--warnbg:#2d2615;--lock:#2E3137;--empty:#A7A9AE;--sh:0 1px 2px rgba(0,0,0,.5),0 8px 22px rgba(0,0,0,.45);--nav:#131518;--nav2:#22262b;--c1:#7cb0f5;--c2:#5fb894;--c3:#d08e5c;--c4:#c0ad4e;--c5:#a68bc0;--c6:#5fa8bf;--c7:#d1707f;--c8:#8f8a82}
.ds22[data-dense="1"],[data-dense="1"] .ds22,.ds22 [data-dense="1"]{--row-h:36px;--row-p:0px}
.ds22,.ds22 *{box-sizing:border-box}
.ds22{margin:0;background:var(--bg);color:var(--tx);font:400 14px/20px var(--font-family-ui);-webkit-font-smoothing:antialiased}
.ds22 input,.ds22 select,.ds22 button,.ds22 textarea{font:inherit;color:inherit}
.ds22 a{color:var(--acc);text-decoration:none}.ds22 a:hover{color:var(--tx)}
.ds22::selection,.ds22 ::selection{background:var(--accs)}
.ds22 button:focus-visible,.ds22 input:focus-visible,.ds22 select:focus-visible,.ds22 textarea:focus-visible,.ds22 [tabindex]:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}
.ds22[data-dense="1"] [data-sub],[data-dense="1"] .ds22 [data-sub],.ds22 [data-dense="1"] [data-sub]{display:none !important}
.ds22::-webkit-scrollbar,.ds22 ::-webkit-scrollbar{width:11px;height:11px}
.ds22::-webkit-scrollbar-thumb,.ds22 ::-webkit-scrollbar-thumb{background:var(--line2);border-radius:6px;border:3px solid transparent;background-clip:content-box}
.ds22::-webkit-scrollbar-track,.ds22 ::-webkit-scrollbar-track{background:transparent}
@keyframes pop{from{opacity:0;transform:translateY(8px) scale(.985)}to{opacity:1;transform:none}}
@keyframes slidein{from{transform:translateX(24px);opacity:0}to{transform:none;opacity:1}}
@keyframes fade{from{opacity:0}to{opacity:1}}

/* ═══ public/tokens-adesk.css ═══ */
/* ТОКЕНЫ ОФОРМЛЕНИЯ, СНЯТЫЕ С ЖИВОГО ADESK 24 АВГУСТА 2026.
 *
 * ЧЕМ ЭТО ОТЛИЧАЕТСЯ ОТ `tokens.css`. Тот перенесён из макета «Рабочее
 * место.dc.html» — красивого, но придуманного. Значения ниже ИЗМЕРЕНЫ:
 * `getComputedStyle` на страницах кабинета владельца, плюс снимки экрана.
 * Источник каждого — раздел ОБОЛОЧКА и ВИЗУАЛЬНЫЙ_СЛОЙ в
 * `fixtures/adesk-screens/ui-baseline-2026-08-24.json`.
 *
 * ПОЧЕМУ ТОКЕНАМИ, А НЕ ЧИСЛАМИ ПО МЕСТУ. Расхождений по подаче найдено
 * несколько десятков на 51 экране. Если чинить их числами в каждом файле,
 * следующая правка разъедется опять — и разъедется молча. Токен правится
 * один раз и применяется везде.
 *
 * ПОСЛЕ 15 СЕНТЯБРЯ ПЕРЕСНЯТЬ БУДЕТ НЕГДЕ. Значения здесь — единственный
 * источник; менять их можно только вместе с фикстурой эталона.
 */
.ds22{
  /* ── полотно ─────────────────────────────────────────────────────── */
  --a-bg: #f4f4f4;              /* фон страницы */
  --a-surface: #ffffff;         /* карточка, таблица, полоса шапки */
  --a-tx: #333333;              /* основной текст */
  --a-tx-muted: rgba(0, 0, 0, .45);  /* шапка таблицы, приписки */
  --a-line: #eeeeee;            /* разделитель внутри карточки */
  --a-line-soft: rgba(230, 230, 230, .7);  /* граница шапки таблицы */
  --a-line-bar: rgba(224, 224, 224, .7);   /* граница верхней полосы */
  --a-card-radius: 3px;
  --a-card-shadow: 0 1px 2px rgba(33, 33, 33, .14), 0 0 1px rgba(0, 0, 0, .14);

  /* ── тёмная навигация ────────────────────────────────────────────── */
  --a-rail-bg: #21252d;
  --a-rail-w: 70px;
  --a-rail-pad: 10px 5px;
  --a-rail-item-w: 60px;
  --a-rail-item-h: 36px;
  --a-rail-step: 37px;          /* шаг между пунктами по вертикали */
  --a-rail-gap: 25px;           /* отступ между группами пунктов */
  --a-rail-radius: 4px;
  --a-rail-icon: #bbc3d6;
  --a-rail-icon-size: 20px;
  --a-rail-active-bg: #2f3440;
  --a-rail-active-tx: #ffffff;

  --a-side-bg: #272d38;         /* второе меню — только у настроек */
  --a-side-w: 250px;
  --a-side-pad: 20px 15px;
  --a-side-item-w: 220px;
  --a-side-item-h: 30px;
  --a-side-item-pad: 5px 10px;
  --a-side-active-bg: #333947;
  --a-side-title-size: 12px;
  --a-side-title-h: 27px;

  --a-pop-bg: #21252d;          /* всплывающий список группы */
  --a-pop-radius: 4px;
  --a-pop-pad: 10px;

  /* ── верхняя полоса ──────────────────────────────────────────────── */
  --a-bar-h: 60px;
  --a-title-size: 16px;
  --a-title-weight: 700;

  /* ── кнопки ──────────────────────────────────────────────────────── */
  --a-btn-h: 35px;
  --a-btn-pad: 6px 17px;
  --a-btn-radius: 3px;
  --a-btn-primary-bg: #0072ec;      /* «завести новое» */
  --a-btn-primary-bd: rgba(0, 79, 191, .5);
  --a-btn-save-bg: #7252d3;         /* «сохранить правку» — ФИОЛЕТОВАЯ */
  --a-btn-default-bg: #ffffff;
  --a-btn-default-bd: rgba(33, 33, 33, .17);
  --a-danger: #d83c31;

  /* ── типографика ─────────────────────────────────────────────────── */
  --a-font: "PT Sans", "Segoe UI", Arial, sans-serif;
  --a-size: 14px;
  --a-lh: 20px;
  --a-ls: .14px;
  --a-th-size: 11px;            /* шапка таблицы */
  --a-th-lh: 15px;
  --a-th-weight: 700;
  --a-th-pad: 14px 3px 14px 20px;
  --a-td-pad: 20px;

  /* ── таблицы ─────────────────────────────────────────────────────── */
  --a-row-h: 66px;              /* обычная строка справочника */
  --a-row-h-tall: 80px;         /* строка счёта: две строчки в ячейке */
  --a-row-h-ops: 78px;          /* строка операции в карточке сущности */
  --a-select-col: 57px;         /* служебная колонка отметки выбора */
}

/* ЭКРАН НЕ ПЕРЕКРАШИВАЕТСЯ ЦЕЛИКОМ. Токены выше подключаются постепенно,
   экран за экраном, по мере сверки с эталоном. Разом перекрасить всё —
   значит одним движением сломать всё, что уже сходится. */

/* ВСПЛЫВАЮЩИЙ СПИСОК ГРУППЫ ПОКАЗЫВАЕТСЯ ПО НАВЕДЕНИЮ — без JS.
   У Adesk измерено наведением настоящей мыши: список появляется справа от
   рейки, на том же тёмном фоне. Держать состояние наведения в состоянии
   приложения незачем — перерисовка на каждое движение мыши это лишняя
   работа, а результат тот же. */
/* Спрятан по умолчанию — ЗДЕСЬ, а не инлайном в разметке: инлайновый стиль
   сильнее правила по классу, и правило наведения строкой ниже не смогло бы
   его перебить. Ровно так список и не появлялся никогда. */
.ds22 .a-rail .a-rail-pop{ display: none; }
.ds22 .a-rail .a-rail-item:hover .a-rail-pop{ display: block; }
.ds22 .a-rail .a-rail-pop button:hover{ background: var(--a-side-active-bg); }
.ds22 .a-rail > aside,.ds22 .a-rail{ overflow: visible; }
.ds22 .a-side a:hover{ background: var(--a-side-active-bg); }

/* ═══ public/app.css ═══ */
/* `@import` обязан идти первым правилом файла (после него можно всё,
   до него — только комментарии и `@charset`). Токены совместимой подачи
   Adesk, найденные при починке расхождений подачи (задача B) — см. шапку
   самого файла. Подключается здесь, а не в `index.html`/`_harness.html`:
   те вне области правки этого агента, а `app.css` грузится после
   `tokens-adesk.css` в обоих. */
@import url("/theme/adesk-compat.css");

/* Остатки прежнего оформления, которых НЕТ в tokens.css.
   Палитра, шрифт, полосы прокрутки и плотность строк переехали в
   tokens.css — он перенесён дословно из макета «Рабочее место».
   Здесь только то, что макет не покрывает: шаг фильтров и перенос
   длинного текста в ячейках. Дублировать переменные нельзя — этот файл
   грузится после tokens.css и молча перебил бы их. */

.ds22{ --sp: 10px; }
.ds22[data-dense="1"],[data-dense="1"] .ds22,.ds22 [data-dense="1"]{ --sp: 5px; }
/* ПЛОТНЫЙ РЕЖИМ ПРЯЧЕТ ПОДПИСЬ ГЛАЗАМИ, НО НЕ УБИРАЕТ ЕЁ СОВСЕМ.
   Было `display: none`, и десять полей фильтров на пяти экранах (Год,
   Источник, Действие, Пользователь, С даты, По дату, Файл выписки)
   оставались вообще без подписи: ни видимой, ни программной — `aria-label`
   рядом с ними нет. Поле без имени нечитаемо для чтения с экрана и
   непонятно при возврате к экрану через неделю.
   Приём ниже убирает подпись с глаз, оставляя её в дереве доступности:
   размер в один пиксель, обрезка и вынос за границы. `display: none`
   так не умеет — он выбрасывает узел целиком. */
.ds22[data-dense="1"] [data-flabel],[data-dense="1"] .ds22 [data-flabel],.ds22 [data-dense="1"] [data-flabel]{
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

.ds22[data-wrap="on"] [data-clip],[data-wrap="on"] .ds22 [data-clip],.ds22 [data-wrap="on"] [data-clip]{ white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.25; }
.ds22[data-wrap="on"] [data-artcell],[data-wrap="on"] .ds22 [data-artcell],.ds22 [data-wrap="on"] [data-artcell]{ flex-direction: column; align-items: flex-start; gap: 0; justify-content: center; }
.ds22[data-wrap="on"] [data-artcell] > *,[data-wrap="on"] .ds22 [data-artcell] > *,.ds22 [data-wrap="on"] [data-artcell] > *{ max-width: 100%; }

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

/* Доля строки от выручки — под самой суммой, мелко и приглушённо.
   Процент РЯДОМ с числом ничего не прячет; процент ВМЕСТО числа прячет всё,
   поэтому сумма остаётся на месте, а доля лишь дополняет её. */
.ds22 .pct{
  font-size: 10.5px;
  line-height: 1.2;
  color: var(--tx3);
  font-variant-numeric: tabular-nums;
}

/*
 * КНОПКА `.btn` — ПРАВИЛА У НЕЁ НЕ БЫЛО ВОВСЕ.
 *
 * ЧТО НАШЛОСЬ 27 августа прогоном геометрии (`npm run geometry:remote`):
 * семь экранов ставят `class="btn"`, а в стилях этого класса НЕ СУЩЕСТВУЕТ.
 * Кнопки падали на умолчание браузера — 26 пикселей высоты против 35 у
 * Adesk, и вместе с высотой уезжала ширина: «Выставить новый счет» 158 px
 * против 193, «Экспорт» 75 против 107.
 *
 * Класс писался как оформление, а оформлял его никто. Заметить это глазами
 * нельзя: кнопка выглядит кнопкой, просто мельче.
 *
 * ЗНАЧЕНИЯ НЕ ПОДОБРАНЫ, А ВЗЯТЫ ИЗ ИЗМЕРЕННОГО: `--a-btn-h`, `--a-btn-pad`,
 * `--a-btn-radius`, `--a-btn-default-bg` и `--a-btn-default-bd` лежат в
 * `public/tokens-adesk.css` с 24 августа — снятые с живого кабинета
 * вычисленные стили. Токены были, ими не пользовались.
 *
 * ИНЛАЙНОВЫЕ СТИЛИ ЭКРАНОВ СИЛЬНЕЕ ЭТОГО ПРАВИЛА и остаются как есть: там,
 * где экран задал высоту сам, менять её надо в экране, а не отсюда.
 */
.ds22 .btn{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: var(--a-btn-h, 35px);
  padding: var(--a-btn-pad, 6px 17px);
  border-radius: var(--a-btn-radius, 3px);
  border: 1px solid var(--a-btn-default-bd, var(--line2));
  background: var(--a-btn-default-bg, var(--surface));
  color: var(--tx);
  font: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.ds22 .btn:disabled{ cursor: not-allowed; opacity: .55; }

/* «Завести новое» — синяя, как `btn-complete` у Adesk. */
.ds22 .btn.btn-primary{
  border-color: var(--a-btn-primary-bd, transparent);
  background: var(--a-btn-primary-bg, var(--acc));
  color: var(--on-acc, #fff);
}

/* Разрушающее действие: цвет текста, а не заливка — так же у Adesk
   («Отключить» в строке: прозрачная, текст #D83C31). */
.ds22 .btn.btn-danger{ color: var(--neg); }

/* Выбранная половина сегмента. Разметка ставит `on` рядом с `btn`. */
.ds22 .btn.on{
  border-color: var(--acc);
  background: var(--accs);
  color: var(--acc);
}

/* Метки операции: строка чипов в карточке и раскрывающееся окно выбора
 * (секция «Метки», public/screens/card.js). Контейнеры — только позиция
 * и перенос, вид чипов даёт .chip. */
.ds22 .tagchips{margin:2px 0 0;line-height:1.9}
.ds22 .tagsel{background:var(--surface);border:1px solid var(--line2);border-radius:8px}

/* ПЕЧАТЬ СЧЁТА: НА БУМАГУ УХОДИТ ТОЛЬКО БУМАГА.
 *
 * У Adesk печатная форма счёта — ОТДЕЛЬНАЯ страница по ссылке («Отправьте
 * своему клиенту эту ссылку, чтобы он смог посмотреть и распечатать счет»),
 * и печатать там нечего, кроме неё. У нас форма открывается окном поверх
 * приложения, поэтому браузеру надо сказать, что печатается только она:
 * иначе на лист уедут меню, полоса фильтров и таблица под окном.
 *
 * ПРИЁМ: спрятать ВСЁ тело, вернуть видимость поддереву формы и вынуть её
 * из положения `fixed` — иначе она печатается на одну страницу и обрезается.
 * Кнопки самого окна помечены `data-inv-noprint` и на бумагу не идут. */
/* ═══════════════════════════════════════════════════════════════════
 * V2.2, РАУНД 2 — ИНСПЕКТОР КАК ПАНЕЛЬ, ОТЗЫВЧИВЫЕ СТОЛБЦЫ СПИСКА
 * ОПЕРАЦИЙ. Источник — `docs/design/v2.2/Minta-handoff.md` §9 и эталоны
 * `F-Ops-Inspector.png`, `F-R-1920/1366/1280/1024.png`, `F-Stress-14col.png`.
 * ═══════════════════════════════════════════════════════════════════ */

/*
 * СПИСОК УЖИМАЕТСЯ САМ, КОГДА ПАНЕЛЬ ПРИСТЫКОВАНА (≥1366 px).
 *
 * `data-inspector` ставит `public/screens/card.js` на `<html>` (не мой файл
 * `shell.js` — общий атрибут вместо правки чужого дерева). `#ds-main` —
 * ID из `shell.js`, читается селектором, а не редактируется: CSS не
 * «трогает» файл, которым владеет другая полоса, он просто ссылается на
 * его разметку по контракту (стабильный id).
 *
 * `--ops-inspector-width` ЖИВЁТ ЗДЕСЬ ТОЛЬКО ДО ПЕРВОГО РАСЧЁТА. Настоящее
 * значение (ширина панели по ширине окна) ставит `card.js`
 * (`document.documentElement.style.setProperty('--ops-inspector-width', …)`,
 * см. его же комментарий про `html[data-inspector]` + эту переменную) —
 * объявление здесь не переопределяет JS (`style.setProperty` всегда
 * побеждает правило из таблицы стилей), оно только даёт переменной
 * СУЩЕСТВОВАТЬ до того, как card.js успеет её посчитать (первая отрисовка,
 * SSR-подобный холодный старт), и снимает пробел, который находит
 * `db/tests/theme.test.ts` («нет ссылок на несуществующие переменные»):
 * `var(--…, 400px)` — запасное значение НА СЛУЧАЙ отсутствия объявления
 * ВООБЩЕ, а тест ищет буквальное `--ops-inspector-width:` где-нибудь в
 * файлах клиента, и раньше её не было нигде.
 */
.ds22{  }
html[data-inspector="docked"] .ds22 #ds-main,.ds22[data-inspector="docked"] #ds-main{
  margin-right: var(--ops-inspector-width, 400px);
  transition: margin-right var(--duration-base, .18s) var(--ease-standard, ease);
}
@media (prefers-reduced-motion: reduce) {
  html[data-inspector="docked"] .ds22 #ds-main,.ds22[data-inspector="docked"] #ds-main{ transition: none; }
}

/*
 * ПРИОРИТЕТ СТОЛБЦОВ СПИСКА ОПЕРАЦИЙ — «остаток → счёт → проект → назначение
 * второй строкой» (Minta-handoff §9). У нас нет отдельного столбца
 * «остаток» (он опциональной второй строкой внутри столбца «Счёт», флажок
 * шестерёнки `flow`) — первый шаг приоритета уже выполнен этим самим
 * фактом: он не показывается, пока не попросили. «Назначение платежа»
 * УЖЕ вторая строка под статьёй ВСЕГДА (`data-sub` под `data-col="cat"`),
 * не только при сужении — то же решение, только принятое раньше и не
 * зависящее от ширины.
 *
 * СЕТКА `--cols` НЕ МЕНЯЕТ ЧИСЛО ТРЕКОВ (7, как в `tokens.css`, — проверено
 * `db/tests/ops-screen.test.ts` подсчётом ЯЧЕЕК, а не их ширины): скрытый
 * столбец получает трек `0px`, а не исчезает из разметки. Число ячеек в
 * шапке и строке остаётся прежним на любой ширине экрана — тест этого не
 * видит и не обязан: он проверяет БАЗОВОЕ значение `--cols` в `:root`,
 * которое этими правилами не переопределяется (переопределения — внутри
 * `@media`, второе вхождение подстроки `--cols:` тем регэкспом не ищется).
 *
 * 1024–1279 (`--bp-laptop`): рейка навигации сужена до 56 px (полоса
 * L-SHELL), инспектор НЕ докуется (порог 1366) — но самого места мало
 * абсолютно. Прячем СЧЁТ и ПРОЕКТ.
 */
@media (max-width: 1279px) {
  .ds22{
    --cols: 57px 68px 130px minmax(160px, 1fr) 0px minmax(120px, 160fr) 0px;
  }
  /*
   * ТРЕК `0px` НЕ ЗНАЧИТ «ЯЧЕЙКА ИСЧЕЗЛА» — ячейка держит `padding:0 9px`
   * (`ops.js:строка`), и в обычной блочной модели (`content-box`) паддинг
   * прибавляется к ширине СВЕРХ трека: измерено на стенде, `0px`-трек всё
   * равно давал 18–21 px видимой полосы. Паддинг снимается ТОЛЬКО у
   * скрытых по ширине столбцов и ТОЛЬКО в этих же условиях — у видимых
   * ячеек (гибкие `fr`-треки) паддинг трогать нельзя, иначе текст сядет
   * вплотную к соседней колонке везде, а не только там, где надо.
   */
  .ds22 .ops-body [data-col="pr"],.ds22 .ops-body [data-col="acc"]{ padding: 0 !important; overflow: hidden; }
}

/*
 * 1366–1599 (`--bp-desktop`) — порог, на котором докуется инспектор
 * (400 px). Прячем СЧЁТ ТОЛЬКО КОГДА ПАНЕЛЬ ДЕЙСТВИТЕЛЬНО ЗАНЯЛА МЕСТО
 * (`html[data-inspector="docked"]`): без открытой карточки список стоит во
 * всю ширину, и прятать столбец не за что. Порядок приоритета — счёт
 * раньше проекта (следующее правило ниже добавляет проект, когда открыт
 * ещё и на более узкой части этого же диапазона).
 */
@media (min-width: 1366px) and (max-width: 1599px) {
  html[data-inspector="docked"] .ds22,.ds22[data-inspector="docked"]{
    --cols: 57px 68px 138px minmax(190px, 1fr) minmax(90px, 131fr) minmax(120px, 150fr) 0px;
  }
  /* Паддинг у 0px-трека — см. разбор в блоке ≤1279px выше. */
  html[data-inspector="docked"] .ds22 .ops-body [data-col="acc"],.ds22[data-inspector="docked"] .ops-body [data-col="acc"]{ padding: 0 !important; overflow: hidden; }
}
/* Совсем тесно даже для докед-панели на нижней границе диапазона — прячем и проект. */
@media (min-width: 1366px) and (max-width: 1439px) {
  html[data-inspector="docked"] .ds22,.ds22[data-inspector="docked"]{
    --cols: 57px 68px 130px minmax(170px, 1fr) 0px minmax(120px, 160fr) 0px;
  }
  html[data-inspector="docked"] .ds22 .ops-body [data-col="pr"],.ds22[data-inspector="docked"] .ops-body [data-col="pr"]{ padding: 0 !important; overflow: hidden; }
}

/*
 * ≥1600 (`--bp-wide`/`--bp-ultra`) — «использовать ширину, а не оставлять
 * пустоту» (F-R-1920.png). Новых столбцов эта полоса не добавляет (нет
 * готовых данных под них — не выдумывать), поэтому свободное место уходит
 * СУЩЕСТВУЮЩИМ гибким столбцам: `--cols` в `tokens.css` уже держит их
 * `minmax(…,Nfr)`, и они и так растут на широком экране без единой строки
 * здесь. Проверено на стенде (см. отчёт полосы) — цифры (доля fr) не
 * трогались.
 */

/*
 * СТОЛБЦЫ-ЯКОРЯ ПРИ ГОРИЗОНТАЛЬНОЙ ПРОКРУТКЕ («14 столбцов» — F-Stress-14col
 * .png). Флажок (первый) липнет слева, счёт (последний ВИДИМЫЙ на сегодня
 * столбец — 3 переключаемых в меню столбцов максимум расширяют список
 * назад до семи; каталог столбцов сверх этих семи эта полоса не заводит,
 * см. отчёт) липнет справа. Список — тот же контейнер, что скроллит
 * строки по вертикали (`.ops-body`/`.body`): горизонтальная прокрутка
 * добавляется ему же, а не оборачивается новым узлом, иначе виртуализация
 * (спорки по `offsetTop`) считала бы не тот контейнер.
 */
.ds22 .ops-body{ overflow-x: auto; }
.ds22 .ops-body > div{ min-width: fit-content; }
.ds22 .ops-body [data-col="sel"]{
  position: sticky; left: 0; z-index: 2;
  background: inherit;
}
.ds22 .ops-body [data-col="acc"]{
  position: sticky; right: 0; z-index: 2;
  background: inherit;
  box-shadow: var(--shadow-sticky-edge, -6px 0 8px -6px rgba(21, 23, 26, .18));
}

@media print{
  body *{visibility:hidden!important}
  #inv-print,#inv-print *{visibility:visible!important}
  #inv-print{position:absolute!important;inset:0 auto auto 0!important;
    width:100%!important;max-height:none!important;overflow:visible!important;
    padding:0!important;border-radius:0!important;box-shadow:none!important}
  [data-inv-noprint]{display:none!important}
  [data-inv-printback]{position:static!important;background:none!important;display:block!important}
}

/* ИТОГИ ВЫБОРКИ НА УЗКОМ ОКНЕ (V2.2). Полоса итогов — одна строка из пяти
   сумм; на 390 px она вылезала за край на 176 px (e2e/90, M-Transaction,
   26.09). Уже 820 — переносим на новые строки; суммы при этом не усекаются. */
@media (max-width: 819px) {
  .ds22 .totals-bar{ flex-wrap: wrap; row-gap: var(--space-3) !important; column-gap: var(--space-7) !important; }
}

/* ═══ public/shell.css ═══ */
/* Каркас приложения: то, чего в прототипе не было отдельным файлом —
   раскладка окна, шапка, боковая колонка, таблица. Переменные и цвета —
   из app.css, здесь ни одного своего цвета. */

/* Раскладку окна задаёт теперь каркас из screens/shell.js: боковая
   колонка плюс колонка содержимого, обе на flex. Прежняя сетка в четыре
   ряда (шапка-фильтры-тело-итоги) держала СТАРУЮ шапку со вкладками и
   ломала бы новую. */
.ds22.ds22--page{ height: 100vh; overflow: hidden; }

/* ══════════════════ ОБОЛОЧКА V2.2 (public/screens/shell.js) ═══════════════
 * Дополняет `public/ds/components.css` (`.ds-shell`/`.ds-nav`/`.ds-topbar`/
 * `.ds-tabbar` и их точки перелома уже определены там — фундамент F0, не
 * трогается отсюда). Здесь — только то, чего в фундаменте не было: строка
 * между пунктом и его раскрывающимся списком, вторая колонка настроек внутри
 * рабочей области, кнопка-триггер палитры команд, сама палитра, «пропустить
 * к содержимому». Ни одного цветового/отступного/радиусного литерала —
 * только `var(--…)` токенов Minta DS V1 (правило 10, LANE-RULES.md). */

/* Строка внутри рабочей области: вторая колонка настроек (если она есть) +
   содержимое. Раньше второе меню настроек стояло отдельной колонкой во всю
   высоту, рядом с рейкой; теперь оно — часть рабочей области (V2.2: «settings
   screens show their sub-menu inside the content area»). */
.ds22 .ds-body-row{ display: flex; min-height: 0; flex: 1; overflow: hidden; }

/* Кнопка-триггер палитры команд в колонке навигации — выглядит как поле
   поиска, а является кнопкой (палитра не ищет по ДАННЫМ, только по уже
   известным пунктам меню — см. shell-v22.js). */
.ds22 .ds-nav__cmdk{
  display: flex; align-items: center; gap: var(--space-3); width: 100%;
  min-height: var(--v22-control-md); padding: 0 var(--space-4);
  border: var(--border-width) solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text-muted); font: var(--type-body);
  cursor: pointer; text-align: left;
}
.ds22 .ds-nav__cmdk:hover{ background: var(--action-secondary-hover); color: var(--text-primary); }
.ds22 .ds-nav__cmdk .ds-kbd{ margin-left: auto; }
/* Подпись — одной строкой: при 240 px она не влезала рядом с «Ctrl K» и
   переносилась на две строки поверх подсказки (стенд, 1440 px, 25.09). */
.ds22 .ds-nav__cmdk > span{ flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: left; }
.ds22 .ds-provider .ds-nav__cmdk{ background: var(--inverse-surface); border-color: var(--inverse-border); color: var(--inverse-text-muted); }
.ds22 .ds-provider .ds-nav__cmdk:hover{ background: var(--inverse-surface-raised); color: var(--inverse-text-primary); }
.ds22 .ds-topbar > .ds-nav__cmdk{ width: auto; }

/* Групповой пункт — обёртка нужна как точка отсчёта для всплывающего списка
   на полосе значков (ниже) и как единый узел, чей `[hidden]` переключает
   shell-v22.js без полной перерисовки оболочки. */
.ds22 .ds-navgroup{ position: relative; }
/* `hidden` у `.ds-nav__sub` иначе не действует: `.ds-nav__sub{display:flex}`
   в components.css — авторское правило той же специфичности, что и
   `[hidden]` из UA-таблицы стилей, и авторское побеждает по происхождению
   независимо от специфичности. Без строки ниже раскрытие/схлопывание
   раздела было бы всегда видимым. */
.ds22 .ds-nav__sub[hidden]{ display: none; }

/* Полоса значков 56 px (1024–1279): групповой список — всплывающий, как был
   у Adesk по наведению, но теперь по клику/клавиатуре (aria-expanded),
   единственный доступный с клавиатуры способ добраться до сгруппированных
   экранов в этом режиме. */
@media (min-width: 1024px) and (max-width: 1279px) {
  .ds22 .ds-shell:not([data-nav="full"]) .ds-navgroup .ds-nav__item[aria-expanded="true"] + .ds-nav__sub{
    display: flex; flex-direction: column; position: absolute; left: calc(100% + var(--space-3)); top: 0;
    width: calc(var(--space-12) * 4); padding: var(--space-3); padding-left: var(--space-3);
    background: var(--surface-raised); border-radius: var(--radius-md); box-shadow: var(--shadow-overlay);
    z-index: var(--z-dropdown);
  }
  .ds22 .ds-provider.ds-shell:not([data-nav="full"]) .ds-navgroup .ds-nav__item[aria-expanded="true"] + .ds-nav__sub{
    background: var(--inverse-surface-raised);
  }
}

/* Вторая колонка настроек: список внутри рабочей области, не во всю высоту
   оболочки — сама рейка остаётся видимой и на экранах настроек (V2.2). */
.ds22 .ds-settings-nav{
  flex: none; width: calc(var(--space-12) * 3.4); overflow-y: auto;
  padding: var(--space-6) var(--space-4); background: var(--surface-sunken);
  border-right: var(--border-width) solid var(--border);
}
.ds22 .ds-settings-nav .ds-menu__item{ width: 100%; }
.ds22 .ds-settings-nav [aria-current="page"]{ background: var(--accent-mint-subtle); color: var(--text-primary); font-weight: 600; }

/* Палитра команд (Ctrl+K) — рисуется shell-v22.js напрямую в document.body,
   в обход renderShell(), чтобы текст запроса не терялся при чужой
   перерисовке; здесь только её вид. */
.ds22 .ds-cmdk{
  position: fixed; z-index: var(--z-modal); left: 50%; top: 15vh; transform: translateX(-50%);
  width: min(calc(var(--space-12) * 9), calc(100vw - var(--space-9)));
  max-height: min(60vh, calc(var(--space-12) * 9));
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--surface-raised); border-radius: var(--radius-xl); box-shadow: var(--shadow-overlay);
}
.ds22 .ds-cmdk__field{ display: flex; align-items: center; gap: var(--space-4); padding: var(--space-6); border-bottom: var(--border-width) solid var(--border); color: var(--text-muted); }
.ds22 .ds-cmdk__field .ds-input{ border: 0; padding: 0; min-height: auto; }
/* Кольцо фокуса переезжает с поля (без рамки, слитого с полосой поиска) на
   всю строку целиком — фокус ОБЯЗАН быть виден (правило 12, LANE-RULES.md),
   просто не как рамка внутри рамки. */
.ds22 .ds-cmdk__field .ds-input:focus-visible{ outline: none; }
.ds22 .ds-cmdk__field:focus-within{ outline: var(--focus-ring-width) solid var(--focus-ring); outline-offset: calc(-1 * var(--focus-ring-width)); }
.ds22 .ds-cmdk #ds-cmdk-list{ position: static; box-shadow: none; overflow: auto; padding: var(--space-3); max-height: none; }

/* Пропустить к содержимому — первый фокусируемый элемент страницы, скрыт
   визуально до фокуса (WCAG 2.4.1). */
.ds22 .ds-skip-link{
  position: absolute; left: var(--space-4); top: calc(-1 * var(--space-11)); z-index: var(--z-toast);
  padding: var(--space-3) var(--space-5); background: var(--inverse-background); color: var(--inverse-text-primary);
  border-radius: var(--radius-sm); transition: top var(--duration-fast) var(--ease-standard);
}
.ds22 .ds-skip-link:focus{ top: var(--space-4); }

/* ═══ Верхняя полоса на телефоне — только то, что помещается ═══════════
 * НАЙДЕНО живой приёмкой (docs/design/v2.2/VISUAL-ACCEPTANCE.md §7.2, все
 * пять телефонных экранов, 390 px): полоса несла ВСЕ элементы рабочего
 * стола разом и вылезала за правый край (кнопка-значок на 442 px при
 * ширине окна 390). `.ds-topbar__quick` (public/screens/shell.js:топбар,
 * топбарПоставщика) — контейнер «десктопных» действий; скрывается
 * ЦЕЛИКОМ ниже 600 px, а не сжимается: каждое действие внутри уже
 * достижимо иначе (остатки/импорт — со своих экранов, лента и
 * оргпереключатель — из ящика меню). `.ds-topbar__phoneaction` — обратное:
 * скрыта на десктопе (там тот же поиск уже есть в колонке навигации),
 * видна только ниже 600 px как единственное оставленное действие. */
.ds22 .ds-topbar__quick{ display: flex; align-items: center; gap: var(--space-6); min-width: 0; }
/*
 * СПЕЦИФИЧНОСТЬ ДВУМЯ КЛАССАМИ — НЕ УКРАШЕНИЕ.
 *
 * `public/index.html` подключает `shell.css` ДО `ds/components.css`
 * («tokens.css первым» — своя причина, `shell.css` в неё просто попадает
 * раньше). При равной специфичности (один класс) побеждает файл,
 * подключённый ПОЗЖЕ — то есть `.ds-btn{display:inline-flex}` из
 * components.css бил бы `.ds-topbar__phoneaction{display:none}` отсюда,
 * и кнопка-действие телефона была бы видна ВСЕГДА, а не только ниже
 * 600 px. Измерено: `getComputedStyle` при одном классе отдавал
 * `inline-flex` независимо от медиазапроса. `.ds-btn.ds-topbar__phoneaction`
 * (два класса) специфичнее — и побеждает независимо от порядка файлов.
 */
.ds22 .ds-btn.ds-topbar__phoneaction{ display: none; }
@media (max-width: 599px) {
  .ds22 .ds-topbar__quick{ display: none; }
  .ds22 .ds-btn.ds-topbar__phoneaction{ display: inline-flex; }
  /* Крошки — только текущая страница: группа и разделитель перед ней на
     390 px не помещаются рядом с кнопкой меню и полем поиска. */
  .ds22 .ds-breadcrumb{ flex: 1; min-width: 0; }
  .ds22 .ds-breadcrumb > *:not([aria-current="page"]){ display: none; }
  .ds22 .ds-breadcrumb [aria-current="page"]{ display: block; min-width: 0; }
  .ds22 .ds-fresh{ display: none; }
  /* Кнопка поиска в тёмной оболочке поставщика — тоже без подписи и без
     подсказки клавиши, иначе она одна уже шире экрана. */
  .ds22 .ds-nav__cmdk > span,.ds22 .ds-nav__cmdk .ds-kbd{ display: none; }
  .ds22 .ds-topbar > .ds-nav__cmdk{ padding: 0; width: var(--control-height); justify-content: center; }
}

/* Полосы над таблицей не сжимаются, таблица занимает остаток и прокручивается
   ВНУТРИ себя. Без `min-height:0` flex-элемент не даёт себя сжать ниже
   содержимого: при 28 тысячах строк таблица растянула бы колонку и уехала
   за край экрана вместе с боковым меню. */
.ds22 .opsbar,.ds22 .filters,.ds22 .foot{ flex: none; }
.ds22 .body{ flex: 1; min-height: 0; }

/* Итоги и полоса выделения рисуют свой контейнер сами (перенос макета),
   поэтому обёртка `.foot` не должна добавлять ни фона, ни рамок. */
.ds22 .foot{ display: block; padding: 0; background: transparent; border: 0; }

/* ── шапка ── */
.ds22 .top{
  display: flex; align-items: center; gap: 14px;
  padding: 0 12px; height: 44px;
  background: var(--surface); border-bottom: 1px solid var(--line);
}
.ds22 .brand{ font-weight: 650; letter-spacing: .2px; }
.ds22 .nav{ display: flex; gap: 2px; margin-left: 6px; }
.ds22 .nav button{
  border: 0; background: transparent; color: var(--tx2);
  padding: 6px 11px; border-radius: 6px; cursor: pointer;
}
.ds22 .nav button:hover{ background: var(--surface3); color: var(--tx); }
.ds22 .nav button[aria-current="page"]{ background: var(--accs); color: var(--acc); font-weight: 600; }
.ds22 .top .spacer{ flex: 1; }
.ds22 .who{ color: var(--tx3); }

.ds22 .seg{ display: inline-flex; border: 1px solid var(--line2); border-radius: 7px; overflow: hidden; }
/*
 * ВЫСОТА ПОЛОВИНЫ СЕГМЕНТА — 35 px, ИЗМЕРЕНО У ADESK.
 *
 * Было `padding: 5px 9px` без высоты: половинки выходили в 28–30 пикселей
 * против 35 у Adesk, и полоса переключателей над отчётом стояла заметно
 * ниже чужой. Найдено прогоном `npm run geometry:remote` — одиннадцать
 * расхождений на двух отчётах разом.
 *
 * 35 — не подобранное число: `--a-btn-h` в `public/tokens-adesk.css`, снято
 * с вычисленных стилей живого кабинета 24 августа, и подтверждено описью:
 * «Статьи|76x35», «Метод начисления|152x35», «Активные|96x35».
 */
.ds22 .seg button{
  border: 0; background: var(--surface); color: var(--tx2);
  height: var(--a-btn-h, 35px); padding: 0 12px; cursor: pointer;
  font: inherit;
}
.ds22 .seg button[aria-pressed="true"]{ background: var(--accs); color: var(--acc); font-weight: 600; }

/*
 * КНОПКА ADESK, ПОД КОТОРОЙ У НАС НИЧЕГО НЕТ.
 *
 * Стоит на своём месте — иначе экран разошёлся бы с Adesk по составу, —
 * выключена и приглушена, а причина висит подсказкой. Разбор в шапке
 * `кнопкаБезОпоры` (`public/screens/reports.js`).
 */
.ds22 .btn-noop{
  /* Та же высота, что у работающих кнопок: выключенная кнопка обязана
     стоять в один ряд с остальными, иначе полоса выглядит сломанной, а не
     частично недоступной. */
  height: var(--a-btn-h, 35px); padding: 0 17px; border: 1px solid var(--line2); border-radius: 6px;
  background: var(--surface2); color: var(--tx2); font: inherit;
  cursor: not-allowed; opacity: .55;
}

/* ── полоса фильтров ── */
.ds22 .filters{
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp);
  padding: var(--sp) 12px; background: var(--surface2); border-bottom: 1px solid var(--line);
}
.ds22 .fld{ display: flex; flex-direction: column; gap: 3px; }
.ds22 .fld > label{ font-size: 10px; text-transform: uppercase; letter-spacing: .5px; color: var(--tx3); }
.ds22 .fld > select,.ds22 .fld > input{
  height: 28px; padding: 0 7px; min-width: 130px;
  background: var(--surface); border: 1px solid var(--line2); border-radius: 6px;
}
.ds22 .fld > input[type="search"]{ min-width: 220px; }
.ds22 .toggle{
  height: 28px; padding: 0 10px; cursor: pointer;
  background: var(--surface); color: var(--tx2);
  border: 1px solid var(--line2); border-radius: 6px;
}
.ds22 .toggle[aria-pressed="true"]{ background: var(--accs); color: var(--acc); border-color: var(--acc); font-weight: 600; }
.ds22 .toggle b{ font-variant-numeric: tabular-nums; }
.ds22 .linkish{ border: 0; background: transparent; color: var(--acc); cursor: pointer; height: 28px; }

/* поиск контрагента с выпадающим списком */
.ds22 .cp{ position: relative; }
.ds22 .cp-list{
  position: absolute; z-index: 20; top: 100%; left: 0; right: 0; max-height: 260px; overflow: auto;
  background: var(--surface); border: 1px solid var(--line2); border-radius: 7px; box-shadow: var(--sh);
}
.ds22 .cp-list button{
  display: block; width: 100%; text-align: left; border: 0; background: transparent;
  padding: 6px 9px; cursor: pointer; color: var(--tx);
}
.ds22 .cp-list button:hover{ background: var(--surface3); }
.ds22 .cp-hint{ padding: 5px 9px; color: var(--tx3); border-top: 1px solid var(--line); }

/* ── итоги ── */
.ds22 .totals{ display: flex; gap: 22px; padding: 7px 12px; background: var(--surface); border-bottom: 1px solid var(--line); }
.ds22 .tot{ display: flex; flex-direction: column; }
.ds22 .tot .lbl{ font-size: 9.5px; text-transform: uppercase; letter-spacing: .5px; color: var(--tx3); }
.ds22 .tot .num{ font-size: 15px; font-weight: 650; font-variant-numeric: tabular-nums; }
.ds22 .num.pos{ color: var(--pos); } .ds22 .num.neg{ color: var(--neg); }

/* ── таблица ──
   Сетка, высота строки и отступы ячеек задаются ТЕПЕРЬ В РАЗМЕТКЕ
   (`screens/ops.js`), как в макете. Прежние правила здесь описывали
   таблицу на девять колонок и плоскую строку в 30 пикселей; когда
   приехали токены макета (`--cols` на семь колонок, `--row-h` в 81),
   разметка и стили разошлись, колонки наехали друг на друга, а текст
   схлопнулся в «О…». Держать раскладку в двух местах — та же ошибка,
   поэтому здесь остаётся только то, что от разметки не зависит. */
.ds22 .body{ overflow: auto; background: var(--surface); }

/*
 * ПОЛЯ ПО 31 px — ТОЛЬКО У ТАБЛИЦЫ СПИСКА ОПЕРАЦИЙ.
 *
 * Первая попытка положила их на `.body` целиком — и накрыла все экраны
 * разом: у справочников и настроек поля тут же удвоились (свои 31 плюс
 * общие 31), таблица ужалась с 831 до 769, и прогон геометрии показал
 * −62 там, где только что было ровно. Общее правило, наложенное поверх
 * частных, ломает ровно то, что частные уже починили.
 *
 * Класс ставит `public/app.js` ТОЛЬКО списку операций: у него разметка
 * своя, четыре узла подряд, и отличить его от прочих по структуре нельзя
 * — можно только назвать.
 *
 * Проверка числом: 1213 − 70 (рейка) − 62 (поля) − 15 (полоса прокрутки)
 * = 1066 против 1068 у Adesk.
 */
.ds22 .ops-body{ padding: 0 31px; }

/* `.head` — шапка таблиц ОСТАЛЬНЫХ экранов (отчёты, лента, импорт,
   категоризация): у них своя разметка и свои сетки. Список операций ею
   больше не пользуется, он задаёт шапку в разметке. Правило вернулось
   после того, как я снёс его вместе со старой таблицей и уронил четыре
   набора тестов отрисовки — они и поймали. */
.ds22 .head{
  /* DISPLAY: GRID — БЕЗ НЕГО ВСЯ ТАБЛИЦА ВАЛИТСЯ В СТОЛБИК.
     Девять мест в экранах задают `.head` инлайновый
     `grid-template-columns`, и двадцать три — `.row`. Без `display: grid`
     это свойство не действует ВООБЩЕ: браузер молча его игнорирует, ячейки
     становятся блоками во всю ширину и выстраиваются вертикально.
     Ни ошибки, ни предупреждения — просто отчёт нечитаем.

     Найдено 17 августа 2026 живым взглядом на боевой П&У: месяцы шли
     вертикальной колонкой, каждый шириной 2286 px. Измерено, а не
     показалось: у всех тринадцати ячеек совпадал `x`, различался `y`.

     Комментарий выше рассказывает, что правило однажды сносили вместе со
     старой таблицей и вернули по упавшим тестам. Вернули НЕ ЦЕЛИКОМ —
     `display` потерялся, а тесты отрисовки проверяют СТРОКУ разметки и о
     применённых стилях не знают ничего. */
  display: grid;
  position: sticky; top: 0; z-index: 10;
  background: var(--surface2); border-bottom: 1px solid var(--line2);
  color: var(--tx3); font-size: 10px; text-transform: uppercase; letter-spacing: .5px;
}
.ds22 .head > *{ padding: 0 7px; overflow: hidden; }
.ds22 .head button{ border: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; text-align: left; padding: 0; text-transform: inherit; letter-spacing: inherit; }

/* `.row` — строка тех же таблиц. Колонки ей задают инлайном двадцать три
   места; `display: grid` обязан быть здесь по той же причине, что и у
   `.head`. Держать их порознь нельзя: шапка и строки разъедутся. */
.ds22 .row{ display: grid; align-items: center; }
.ds22 .row:hover{ background: var(--surface2); }
.ds22 .row.locked{ background: var(--lock); }
.ds22 .clip{ white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }
.ds22 .sum{ text-align: right; font-variant-numeric: tabular-nums; }
.ds22 .muted{ color: var(--tx3); }
.ds22 .chip{
  display: inline-block; padding: 0 6px; border-radius: 4px;
  background: var(--surface3); color: var(--tx2); font-size: 11px;
}
.ds22 .chip.warn{ background: var(--warnbg); color: var(--warn); }

/*
 * ═══ V2.2 (L-REP) — DS-ПОДАЧА ТАБЛИЦ ОТЧЁТОВ (П&У/ДДС) ═══
 *
 * docs/design/v2.2/reference/F-PnL.png, F-CashFlow.png: подпись «Статья»
 * приглушённая и НЕ капителью, строки на тонкой линии-разделителе, отрицательные
 * — цветом токена DS, сумма плана/процента — мельче и серым под фактом.
 *
 * ПОЧЕМУ ПРЕФИКС `.reports`, А НЕ ПРАВКА `.head`/`.row` НАПРЯМУЮ. Комментарий
 * у `.head` выше говорит прямо: те же классы держат ленту, импорт,
 * категоризацию — экраны, которых это задание не касается и о которых у
 * полосы L-REP нет ни эталона, ни разрешения трогать вёрстку. Каждое правило
 * здесь начинается с `.reports` (public/screens/reports.js,
 * `<div class="reports" id="reports-screen">`) — соседние экраны этих правил
 * не видят вовсе, а старые тесты отрисовки (`.row`/`.filters`/`.chip` как
 * селекторы) не задевает ничего: классы те же, добавлены только CSS-правила
 * поверх, разметка не тронута ни в одном месте.
 */
.ds22 .reports .head{
  background: var(--surface-sunken); border-bottom: var(--border-width) solid var(--border-strong);
  color: var(--text-muted); font: var(--type-caption); font-weight: 500;
  text-transform: none; letter-spacing: normal;
}
.ds22 .reports .row{ font: var(--type-table); color: var(--text-primary); border-bottom: var(--border-width) solid var(--border); }
.ds22 .reports .row:hover{ background: var(--surface-sunken); }
.ds22 .reports .sum.pos{ color: var(--text-primary); }
.ds22 .reports .sum.neg{ color: var(--negative); }
/* Подпись плана/процента/тренда под фактом (DG-30 «план под фактом»,
   F-PnL.png) — мельче и приглушённо, той же строкой ячейки, без своего
   грид-места. */
.ds22 .reports .pct{ font: var(--type-caption); color: var(--text-muted); margin-top: 2px; }
.ds22 .reports .muted{ color: var(--text-muted); }
/* Итоговые строки (`total()` в renderPnl, «Остаток на начало/конец» в
   renderCashflow) — вес держит сама разметка (`<b>`, F-PnL.png: полужирный
   текст без заливки строки, в отличие от проверочной строки Баланса, см.
   #balance-screen ниже). */
.ds22 .reports .row b{ font-weight: 600; color: var(--text-primary); }
.ds22 .reports .chip{ background: var(--surface-sunken); color: var(--text-secondary); border-radius: var(--radius-xs); }

/* ── вход ── */
.ds22 .login{ display: grid; place-items: center; height: 100vh; }
.ds22 .login form{
  display: flex; flex-direction: column; gap: 10px; width: 320px;
  padding: 22px; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--sh);
}
.ds22 .login h1{ margin: 0 0 4px; font-size: 17px; }
.ds22 .login input{
  height: 32px; padding: 0 9px; background: var(--surface2);
  border: 1px solid var(--line2); border-radius: 6px;
}
.ds22 .login button{
  height: 32px; border: 0; border-radius: 6px; cursor: pointer;
  background: var(--acc); color: var(--on-acc); font-weight: 600;
}
.ds22 .err{ color: var(--neg); min-height: 17px; }

.ds22 .toast{
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
  padding: 8px 14px; border-radius: 7px; box-shadow: var(--sh);
  background: var(--surface); border: 1px solid var(--line2);
}

/* ══ Карточка операции (Ш1) ══════════════════════════════════════════
   ВСПЛЫВАЮЩЕЕ ОКНО ПО ЦЕНТРУ — как в Adesk. Первая редакция делала панель
   справа; владелец поправил, и он прав: он работает в Adesk три года, а
   моё обоснование панели было тем самым «показалось чище», которое в
   правиле этапа не считается причиной. Подробнее — в шапке card.js.

   Центрирование — сеткой на затемнении, без расчётов в пикселях. Высота
   ограничена окном просмотра: длинная история изменений обязана прокручиваться
   ВНУТРИ окна, а не растягивать его за край экрана. */

.ds22 .card-back{
  position: fixed; inset: 0; z-index: 40;
  background: rgba(0, 0, 0, .38);
  display: grid; place-items: center;
  padding: 20px;
}
.ds22 .card{
  position: relative;
  width: min(760px, 100%);
  max-height: min(90vh, 100%);
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line2); border-radius: 12px;
  box-shadow: var(--sh);
  animation: pop .13s ease-out;
}
@keyframes pop {
  from { opacity: 0; transform: translateY(8px) scale(.985); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .ds22 .card{ animation: none; } }

.ds22 .card-head{
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 16px; border-bottom: 1px solid var(--line);
  background: var(--surface2);
}
.ds22 .card-kind{ font-size: 10px; text-transform: uppercase; letter-spacing: .5px; }
.ds22 .card-sum{ font-size: 23px; font-weight: 650; font-variant-numeric: tabular-nums; line-height: 1.15; }
.ds22 .card-meta{ color: var(--tx3); }
.ds22 .card-chips{ display: flex; flex-wrap: wrap; gap: 4px; margin-left: auto; max-width: 260px; justify-content: flex-end; }
.ds22 .card-x{
  border: 0; background: transparent; color: var(--tx3);
  font-size: 22px; line-height: 1; cursor: pointer; padding: 0 2px;
}
.ds22 .card-x:hover{ color: var(--tx); }

.ds22 .card-body{ flex: 1; overflow: auto; padding: 4px 16px 16px; }
.ds22 .card-sec{ padding: 13px 0; border-bottom: 1px solid var(--line); }
.ds22 .card-sec:last-child{ border-bottom: 0; }
.ds22 .card-sec h3{
  margin: 0 0 9px; font-size: 10px; font-weight: 650;
  text-transform: uppercase; letter-spacing: .5px; color: var(--tx3);
}
.ds22 .card .fld{ margin-bottom: 9px; }
.ds22 .card .fld > span{ font-size: 10px; text-transform: uppercase; letter-spacing: .5px; color: var(--tx3); }
.ds22 .card .fld > input,.ds22 .card .fld > select,.ds22 .card .fld > textarea{
  width: 100%; min-height: 30px; padding: 5px 8px;
  background: var(--surface2); border: 1px solid var(--line2); border-radius: 6px;
}
.ds22 .card .fld > textarea{ resize: vertical; }
.ds22 .card .fld > :disabled{ opacity: .55; cursor: not-allowed; }
.ds22 .grid2{ display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

/* флажок с раскрывающейся подсказкой */
.ds22 .check{ display: flex; align-items: center; flex-wrap: wrap; gap: 7px; margin: 4px 0 9px; }
.ds22 .check label{ display: flex; align-items: center; gap: 6px; cursor: pointer; }
.ds22 .hint{
  width: 17px; height: 17px; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--line2); background: var(--surface2); color: var(--tx3);
  font-size: 11px; line-height: 1; padding: 0;
}
.ds22 .hint[aria-expanded="true"]{ background: var(--accs); color: var(--acc); border-color: var(--acc); }
.ds22 .tip{
  flex-basis: 100%; margin: 0; padding: 8px 10px;
  background: var(--surface2); border-left: 2px solid var(--acc); border-radius: 0 6px 6px 0;
  color: var(--tx2);
}

/* НДС — закрытый список ставок, ТЗ §3.13 */
.ds22 .vat-row{ display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 9px; }
.ds22 button.vat{
  padding: 4px 10px; cursor: pointer;
  background: var(--surface2); color: var(--tx2);
  border: 1px solid var(--line2); border-radius: 6px;
}
.ds22 button.vat.on{ background: var(--accs); color: var(--acc); border-color: var(--acc); font-weight: 600; }

.ds22 .note{ margin: 5px 0 0; color: var(--tx3); }
.ds22 .warn-line{ margin: 5px 0 0; color: var(--warn); font-weight: 600; }
.ds22 .locked{
  margin: 0; padding: 9px 16px;
  background: var(--warnbg); color: var(--warn); border-bottom: 1px solid var(--line);
}

/* части разбиения */
.ds22 table.parts{ width: 100%; border-collapse: collapse; }
.ds22 table.parts th{
  text-align: left; font-size: 10px; text-transform: uppercase; letter-spacing: .5px;
  color: var(--tx3); font-weight: 600; padding: 3px 6px; border-bottom: 1px solid var(--line2);
}
.ds22 table.parts td{ padding: 4px 6px; border-bottom: 1px solid var(--line); }
.ds22 table.parts td.sum{ text-align: right; font-variant-numeric: tabular-nums; }

/* поля только для чтения — с причиной, а не молча */
.ds22 dl.ro{ margin: 0; display: grid; grid-template-columns: 92px 1fr; gap: 4px 10px; }
.ds22 dl.ro dt{ color: var(--tx3); }
.ds22 dl.ro dd{ margin: 0; }

/* лента изменений внутри карточки */
.ds22 ul.events{ list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.ds22 li.ev{ padding: 8px 10px; background: var(--surface2); border-radius: 7px; }
.ds22 .ev-top{ display: flex; flex-wrap: wrap; align-items: center; gap: 7px; margin-bottom: 3px; }
.ds22 .ev-when{ font-variant-numeric: tabular-nums; color: var(--tx3); }
.ds22 .ev-who{ font-weight: 600; }
.ds22 ul.ev-diff{ margin: 5px 0 0; padding-left: 17px; color: var(--tx2); }
.ds22 ul.ev-diff s{ color: var(--tx3); }

.ds22 .card-foot{
  display: flex; align-items: center; flex-wrap: wrap; gap: 9px;
  padding: 11px 16px; border-top: 1px solid var(--line); background: var(--surface2);
}
.ds22 .card-foot .spacer{ flex: 1; }
.ds22 .card-foot button{
  height: 30px; padding: 0 13px; cursor: pointer;
  background: var(--surface); color: var(--tx);
  border: 1px solid var(--line2); border-radius: 6px;
}
.ds22 .card-foot button.primary{ background: var(--acc); color: var(--on-acc); border-color: var(--acc); font-weight: 600; }
.ds22 .card-foot button.danger{ color: var(--neg); }
.ds22 .card-foot button:disabled{ opacity: .5; cursor: not-allowed; }
.ds22 .card-foot .err{ flex-basis: 100%; }
.ds22 .confirm{ display: flex; align-items: center; gap: 7px; color: var(--neg); }

/* Выбранный контрагент — значением, а не подсказкой поля: серый
   placeholder читался как «пусто» на заполненном поле. */
.ds22 .cp-now{ padding: 3px 0; }
.ds22 .cp-now .linkish{ height: auto; padding: 0 0 0 8px; }

/* Кнопки формы разбиения. Живут в теле карточки, а не в её подвале, поэтому
   правила .card-foot button до них не достают — своё правило, но тех же
   размеров и цветов: две одинаковые с виду кнопки разной высоты читаются
   как недоделка. */
.ds22 .split-actions{ display: flex; gap: 9px; margin-top: 10px; }
.ds22 .split-actions button{
  height: 30px; padding: 0 13px; cursor: pointer;
  background: var(--surface); color: var(--tx);
  border: 1px solid var(--line2); border-radius: 6px;
}
.ds22 .split-actions button.primary{ background: var(--acc); color: var(--on-acc); border-color: var(--acc); font-weight: 600; }
.ds22 .split-actions button:disabled{ opacity: .5; cursor: not-allowed; }

/* ══ Импорт выписки: дата начисления (Ш про переходящие платежи) ══════
   Колонка редактируется ПОЧЕРОЧНО, prямо в таблице предпросмотра — правки
   уходят на сервер как соответствия «номер документа → дата», см.
   `screens/import.js`. Подсказка по периоду НИКОГДА не применяется сама:
   кнопка рядом — единственный способ её принять. */
.ds22 .acc-cell{ display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.ds22 .acc-date{
  height: 24px; padding: 0 5px; font: inherit;
  background: var(--surface); border: 1px solid var(--line2); border-radius: 5px;
  color: var(--tx);
}
.ds22 .acc-date:disabled{ opacity: .55; cursor: not-allowed; }
.ds22 .acc-hint{
  font-size: 11px; padding: 0 6px; height: 20px; border-radius: 4px;
  background: var(--warnbg); color: var(--warn);
}
.ds22 .acc-hint:disabled{ opacity: .55; cursor: not-allowed; }

/* блок подсказок по периоду под сводкой — тот же приём, что `.tip` у
   карточки операции: акцентная полоса слева, чтобы не спутать со сверкой. */
.ds22 .hints{ margin: 0 12px 9px; padding: 9px 12px; background: var(--surface2); border-left: 2px solid var(--acc); border-radius: 0 6px 6px 0; }
.ds22 .hint-row{ display: flex; align-items: center; gap: 10px; padding: 4px 0; flex-wrap: wrap; }
.ds22 .hint-row .clip{ flex: 1; min-width: 220px; }
.ds22 .hint-row .to{ color: var(--tx3); white-space: nowrap; }

/*
 * Рабочий стол: сетка в ЧЕТЫРЕ КОЛОНКИ с осознанными пролётами.
 *
 * Прежде здесь стояло `repeat(auto-fit, minmax(320px,1fr))` — то есть блоки
 * вставали «как поместятся», и рядом оказывались виджеты, отвечающие на
 * совершенно разные вопросы. Владелец сказал прямо: «блоки вообще никак не
 * согласованы, рядом могут стоять разные метрики». Так и было.
 *
 * Раскладка снята с живого Adesk замером геометрии его блоков при ширине
 * окна 1280: контейнер 1136, четыре колонки по 276 с зазором 10.
 *
 *   ряд 1  четыре карточки по одной колонке
 *   ряд 2  «Деньги на счетах» на три колонки + правая колонка из двух
 *          блоков в столбик (рентабельность и задолженность)
 *   ряд 3  «Динамика расходов» на три + «Структура расходов» на одну
 *   ряд 4  два блока по половине ширины
 *
 * Логика пролётов не декоративная: широкий блок — это ряд во времени
 * (месяцы), узкий — разрез на один момент. Ставить их одинаковыми значит
 * заставлять читателя каждый раз выяснять, что перед ним.
 */
.ds22 .desk-grid{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  align-items: start;
}
.ds22 .desk-grid > .w-wide{ grid-column: span 3; }
.ds22 .desk-grid > .w-half{ grid-column: span 2; }
.ds22 .desk-grid > .w-stack{ display: flex; flex-direction: column; gap: 12px; }

/* Узкий экран: сетка распрямляется в одну колонку, пролёты снимаются —
   иначе блок на три колонки уедет за край. */
@media (max-width: 1100px) {
  .ds22 .desk-grid{ grid-template-columns: 1fr; }
  .ds22 .desk-grid > .w-wide,.ds22 .desk-grid > .w-half{ grid-column: span 1; }
}

/* ─────────────── анализ расходов ───────────────
 *
 * Мультиселект статей — единственный на всю систему, поэтому классы свои, а
 * не переиспользованные. Статей у бизнеса 46: список в столбик занял бы
 * экран целиком, поэтому они лежат плитками в несколько рядов и переносятся
 * по ширине окна. Сумма за год стоит РЯДОМ С НАЗВАНИЕМ, а не только в
 * таблице: выбирать статью, не зная её веса, значит выбирать вслепую.
 */
.ds22 .exp-picker{ padding: 10px 12px; border-bottom: 1px solid var(--line); }
.ds22 .exp-picker-head{ display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.ds22 .exp-chips{ display: flex; flex-wrap: wrap; gap: 6px; }
.ds22 .exp-chip{
  display: inline-flex; align-items: center; gap: 7px;
  padding: 4px 9px; border: 1px solid var(--line2); border-radius: 7px;
  font-size: 12.5px; cursor: pointer; background: var(--surface);
}
.ds22 .exp-chip.on{ border-color: var(--acc); background: var(--accs); }
.ds22 .exp-chip input{ margin: 0; cursor: pointer; }
/* 34ch, а не 26. При 26 обрезались шесть настоящих статей владельца —
   «Лицензии Битрикс24 На продажу», «Налог на добавленную стоимость»,
   «Проценты по кредитам и займам» и другие. Измерено 23 августа на снятых
   боевых экранах: 163 пикселя против нужных 180. Полное имя всё равно
   остаётся в `title`: на случай статьи длиннее и этой меры. */
.ds22 .exp-chip-name{ max-width: 34ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds22 .exp-chip-sum{ color: var(--tx3); font-variant-numeric: tabular-nums; }

/* Доля статьи в выручке — второй строкой под суммой, как у Adesk.
   Ячейка становится двухэтажной, поэтому высота строки здесь своя. */
.ds22 .expenses .exp-share{ font-size: 10.5px; color: var(--tx3); font-variant-numeric: tabular-nums; }
.ds22 .expenses .row{ align-items: center; }

/* ─── полоса «вышла новая версия» ───
   Сверху, во всю ширину, содержимое сдвигается вниз на её высоту. Не
   перекрывает работу и не закрывается: закрыв её однажды, человек остался бы
   на старой сборке без единого напоминания. */
.newbuild{
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  height: 40px;
  padding: 0 16px;
  font-size: 13px;
  color: #fff;
  background: #2c3e50;
}
.newbuild__btn{
  padding: 4px 12px;
  font: inherit;
  color: #2c3e50;
  cursor: pointer;
  background: #fff;
  border: 0;
  border-radius: 3px;
}
body.has-newbuild{ padding-top: 40px; }

/* ═══ public/ds/legacy-bridge.css ═══ */
/* Minta DS V1 — МОСТ ДЛЯ ПРЕЖНИХ ТОКЕНОВ ОФОРМЛЕНИЯ.
 *
 * ЗАЧЕМ. Экраны продукта (пятьдесят модулей public/screens/*.js) рисуют
 * себя атрибутом style= поверх переменных двух прежних слоёв: --bg/--tx/…
 * (public/tokens.css) и --a-* (public/tokens-adesk.css — измеренный Adesk).
 * Переписывать каждый экран ради цвета — значит править пятьдесят файлов
 * вслепую и потерять что-нибудь молча. Здесь прежние имена получают значения
 * дизайн-системы, и ВСЕ экраны разом переходят на её палитру, шрифт и
 * радиусы — без единой правки в модуле экрана.
 *
 * tokens-adesk.css НЕ ТРОНУТ: это запись измерения живого Adesk
 * (24.08.2026), и она остаётся записью. Мост грузится ПОСЛЕ него и
 * перекрывает значения каскадом.
 *
 * Литералов здесь нет — только var(--…) из public/ds/tokens.css.
 */
.ds22{
  --a-bg:var(--background);
  --a-surface:var(--surface);
  --a-tx:var(--text-primary);
  --a-tx-muted:var(--text-muted);
  --a-line:var(--border);
  --a-line-soft:var(--border);
  --a-line-bar:var(--border);
  --a-card-radius:var(--v22-radius-lg);
  --a-card-shadow:var(--shadow-panel);

  --a-rail-bg:var(--background-sidebar);
  --a-rail-icon:var(--text-secondary);
  --a-rail-active-bg:var(--surface);
  --a-rail-active-tx:var(--text-primary);
  --a-side-bg:var(--background-sidebar);
  --a-side-active-bg:var(--surface);
  --a-pop-bg:var(--surface-raised);
  --a-pop-radius:var(--radius-md);

  --a-btn-h:var(--v22-control-md);
  --a-btn-radius:var(--radius-sm);
  --a-btn-primary-bg:var(--action-primary);
  --a-btn-primary-bd:var(--action-primary);
  --a-btn-save-bg:var(--action-primary);
  --a-btn-default-bg:var(--surface);
  --a-btn-default-bd:var(--border-strong);
  --a-danger:var(--action-destructive);

  --a-font:var(--font-family-ui);
  --a-size:14px;
  --a-lh:20px;
  --a-ls:0;
  --a-th-size:12px;
  --a-th-lh:16px;
  --a-th-weight:500;
}

/* ── тёмная тема для токенов DS ──────────────────────────────────────
 * Прежняя возможность продукта (см. шапку public/tokens.css). Значения —
 * обратная палитра самой DS (--inverse-*): новых цветов не придумано. */
.ds22[data-theme="dark"],[data-theme="dark"] .ds22,.ds22 [data-theme="dark"]{
  --background:var(--inverse-background);
  --background-sidebar:var(--inverse-background);
  --surface:var(--inverse-surface);
  --surface-sunken:var(--inverse-surface-raised);
  --surface-muted:var(--inverse-border);
  --surface-raised:var(--inverse-surface-raised);
  --border:var(--inverse-border);
  --border-strong:var(--inverse-border-strong);
  --text-primary:var(--inverse-text-primary);
  --text-secondary:var(--inverse-text-secondary);
  --text-muted:var(--inverse-text-muted);
  --action-primary:var(--inverse-text-primary);
  --action-primary-hover:var(--inverse-text-secondary);
  --action-primary-pressed:var(--inverse-text-muted);
  --text-inverse:var(--inverse-background);
  --action-secondary-hover:var(--inverse-surface-raised);
  --accent-mint-strong:var(--inverse-accent);
  --accent-mint-subtle:var(--inverse-surface-raised);
  --row-current:var(--inverse-surface-raised);
  --row-changed:var(--inverse-surface-raised);
  --positive:var(--inverse-positive);
  --focus-ring:var(--inverse-accent);
}

/* ═══ public/ds/base.css ═══ */
/* Minta Finance DS V1 — база: шрифт, фон, фокус, плотность, движение.
 *
 * Грузится ПОСЛЕ public/ds/tokens.css (канонические токены, копия
 * docs/design/v2.2/tokens.css — равенство держит src/web/ds-foundation.test.ts)
 * и ПОСЛЕ прежних tokens*.css: на спорных местах побеждает дизайн-система.
 *
 * ЧИСЕЛ ЗДЕСЬ НЕТ. Ни цвета, ни отступа, ни радиуса литералом — только
 * var(--…) из токенов. Это проверяется тестом, а не вкусом: литерал, вписанный
 * в один экран, через месяц расходится с соседним экраном молча.
 */

.ds22{-webkit-text-size-adjust:100%;text-size-adjust:100%}
.ds22{background:var(--background);color:var(--text-primary)}
.ds22{
  font:var(--type-body);
  font-family:var(--font-family-ui);
  letter-spacing:var(--type-body-tracking);
  font-feature-settings:"kern" 1;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}
.ds22 input,.ds22 select,.ds22 button,.ds22 textarea{font-family:inherit}
.ds22 code,.ds22 kbd,.ds22 samp,.ds22 pre,.ds22 .ds-mono{font-family:var(--font-family-mono)}

/* Деньги и любые числа в столбик — табличные цифры. Правило держится на
   атрибуте, а не на классе экрана: ячейку суммы узнают по смыслу. */
.ds22 .ds-num,.ds22 [data-money],.ds22 .ds-money{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}

/* ── фокус: кольцо 2 px focus-ring + зазор 2 px ─────────────────────── */
.ds22 :where(a,button,input,select,textarea,summary,[tabindex]):focus-visible{
  outline:var(--focus-ring-width) solid var(--focus-ring);
  outline-offset:var(--focus-ring-offset);
}
.ds22 :where(a,button,input,select,textarea,summary,[tabindex]):focus:not(:focus-visible){outline:none}

.ds22::selection,.ds22 ::selection{background:var(--accent-mint-subtle);color:var(--text-primary)}

/* ── плотность: одни компоненты, три набора размеров ──────────────────
   Канонические значения — в tokens.css ([data-density=…]). Здесь только
   то, что токены не называют: высота шапки таблицы, полосы инструментов,
   отступ панели и шаг — из тех же строк таблицы плотности. */
.ds22,.ds22[data-density=standard],[data-density=standard] .ds22,.ds22 [data-density=standard]{
  --ds-header-height:var(--density-standard-header);
  --ds-toolbar-height:var(--density-standard-toolbar);
  --ds-panel-pad:var(--density-standard-panel);
  --ds-gap:var(--density-standard-gap);
  --ds-icon:var(--density-standard-icon);
}
.ds22[data-density=comfortable],[data-density=comfortable] .ds22,.ds22 [data-density=comfortable]{
  --ds-header-height:var(--density-comfortable-header);
  --ds-toolbar-height:var(--density-comfortable-toolbar);
  --ds-panel-pad:var(--density-comfortable-panel);
  --ds-gap:var(--density-comfortable-gap);
  --ds-icon:var(--density-comfortable-icon);
}
.ds22[data-density=compact],[data-density=compact] .ds22,.ds22 [data-density=compact]{
  --ds-header-height:var(--density-compact-header);
  --ds-toolbar-height:var(--density-compact-toolbar);
  --ds-panel-pad:var(--density-compact-panel);
  --ds-gap:var(--density-compact-gap);
  --ds-icon:var(--density-compact-icon);
}
/* Корень без атрибута ведёт себя как «Стандарт». */
:root:not([data-density]) .ds22,.ds22:not([data-density]){--row-height:var(--density-standard-row);--control-height:var(--density-standard-input);--cell-padding-x:var(--density-standard-cell-px);--table-font-size:var(--density-standard-font);--hit-area:var(--density-standard-hit)}

/* ── движение ─────────────────────────────────────────────────────────
   Уменьшенное движение: переходы гаснут до --motion-reduced; правило
   для всего дерева стоит в tokens.css. Здесь — то же самое для
   прокрутки, которой токены не касаются. */
@media (prefers-reduced-motion: reduce){.ds22{scroll-behavior:auto}}

/* ── только для чтения с экрана ─────────────────────────────────────── */
.ds22 .ds-sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}

/* ── прокрутка ──────────────────────────────────────────────────────── */
.ds22,.ds22 *{scrollbar-color:var(--border-strong) transparent}
.ds22::-webkit-scrollbar-thumb,.ds22 ::-webkit-scrollbar-thumb{background:var(--border-strong)}

/* ═══ public/ds/components.css ═══ */
/* Minta DS V1 — компоненты. Один набор на три плотности.
 *
 * Источник подачи — доски DS-Actions-Forms, DS-Nav-Overlays, DS-Data-Table,
 * DS-Domain, DS-Numbers-Charts, DS-System-States (docs/design/v2.2/).
 * Литералов цвета, отступа, радиуса и высоты здесь нет: только var(--…) из
 * public/ds/tokens.css. Проверяет src/web/ds-foundation.test.ts.
 *
 * Разметку этих классов строят функции public/ds/ui.js — экраны пишут
 * ds.btn(…), а не класс руками, чтобы состояние (aria-*, disabled, busy)
 * не разошлось с видом.
 */

/* ═══ Кнопки ══════════════════════════════════════════════════════════ */
.ds22 .ds-btn{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--space-3);
  min-height:var(--control-height);min-width:var(--target-min);
  padding:0 var(--space-6);border:var(--border-width) solid transparent;border-radius:var(--radius-sm);
  font:var(--v22-type-label);white-space:nowrap;cursor:pointer;text-decoration:none;
  transition:background-color var(--duration-fast) var(--ease-standard),border-color var(--duration-fast) var(--ease-standard);
}
.ds22 .ds-btn--primary{background:var(--action-primary);color:var(--text-inverse)}
.ds22 .ds-btn--primary:hover{background:var(--action-primary-hover)}
.ds22 .ds-btn--primary:active{background:var(--action-primary-pressed)}
.ds22 .ds-btn--secondary{background:var(--surface);color:var(--text-primary);border-color:var(--border-strong)}
.ds22 .ds-btn--secondary:hover,.ds22 .ds-btn--ghost:hover{background:var(--action-secondary-hover)}
.ds22 .ds-btn--secondary:active,.ds22 .ds-btn--ghost:active{background:var(--surface-muted)}
.ds22 .ds-btn--ghost{background:transparent;color:var(--text-primary)}
.ds22 .ds-btn--destructive{background:var(--action-destructive);color:var(--text-inverse)}
.ds22 .ds-btn--destructive:hover{background:var(--action-destructive-hover)}
.ds22 .ds-btn--destructive:active{background:var(--action-destructive-pressed)}
.ds22 .ds-btn[aria-pressed="true"],.ds22 .ds-btn--selected{background:var(--accent-mint-subtle);border-color:var(--accent-mint-strong);color:var(--text-primary)}
.ds22 .ds-btn:disabled,.ds22 .ds-btn[aria-disabled="true"]{cursor:not-allowed;background:var(--surface-muted);color:var(--text-disabled);border-color:transparent}
.ds22 .ds-btn--ghost:disabled{background:transparent}
.ds22 .ds-btn[aria-busy="true"]{cursor:progress}
.ds22 .ds-btn--sm{min-height:var(--control-sm);padding:0 var(--space-5)}
.ds22 .ds-btn--xs{min-height:var(--v22-control-xs);padding:0 var(--space-4);font:var(--v22-type-caption)}
.ds22 .ds-btn--lg{min-height:var(--v22-control-lg);padding:0 var(--space-8)}
.ds22 .ds-btn--icon{padding:0;width:var(--control-height);min-width:var(--control-height)}
.ds22 .ds-btn--icon.ds-btn--sm{width:var(--control-sm);min-width:var(--control-sm)}
.ds22 .ds-btn--block{width:100%}
.ds22 .ds-btn .ds-icon{flex:none}
.ds22 .ds-spinner{display:inline-block;width:var(--icon-sm);height:var(--icon-sm);border-radius:var(--radius-pill);
  border:var(--border-width-strong) solid currentColor;border-right-color:transparent;animation:ds-spin var(--duration-slow) linear infinite}
@keyframes ds-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion: reduce){.ds22 .ds-spinner{animation:none;border-right-color:currentColor;opacity:.6}}

.ds22 .ds-link{color:var(--accent-mint-strong);text-decoration:underline;text-underline-offset:2px;background:none;border:0;padding:0;font:inherit;cursor:pointer}
.ds22 .ds-link:hover{color:var(--text-primary)}

.ds22 .ds-kbd{display:inline-flex;align-items:center;flex:none;white-space:nowrap;min-height:var(--v22-icon-lg);padding:0 var(--space-2);
  border:var(--border-width) solid var(--border-strong);border-radius:var(--radius-xs);
  font:var(--type-technical);color:var(--text-muted);background:var(--surface)}

/* ═══ Поля ════════════════════════════════════════════════════════════ */
.ds22 .ds-field{display:flex;flex-direction:column;gap:var(--space-2);min-width:0}
.ds22 .ds-field__label{font:var(--v22-type-label);color:var(--text-secondary)}
.ds22 .ds-field__hint{font:var(--v22-type-caption);color:var(--text-muted)}
.ds22 .ds-field__error{display:flex;gap:var(--space-2);align-items:flex-start;font:var(--v22-type-caption);color:var(--negative)}
.ds22 .ds-input,.ds22 .ds-select,.ds22 .ds-textarea{
  width:100%;min-height:var(--control-height);padding:0 var(--space-5);
  border:var(--border-width) solid var(--border-control);border-radius:var(--radius-sm);
  background:var(--surface);color:var(--text-primary);font:var(--type-body);
}
.ds22 .ds-textarea{padding:var(--space-4) var(--space-5);min-height:calc(var(--control-height) * 2);resize:vertical}
.ds22 .ds-input::placeholder,.ds22 .ds-textarea::placeholder{color:var(--text-muted)}
.ds22 .ds-input:hover,.ds22 .ds-select:hover,.ds22 .ds-textarea:hover{border-color:var(--text-secondary)}
.ds22 .ds-input:focus-visible,.ds22 .ds-select:focus-visible,.ds22 .ds-textarea:focus-visible{outline:var(--focus-ring-width) solid var(--focus-ring);outline-offset:var(--focus-ring-offset)}
.ds22 .ds-input:disabled,.ds22 .ds-select:disabled,.ds22 .ds-textarea:disabled{background:var(--surface-sunken);color:var(--text-disabled);border-color:var(--border)}
.ds22 .ds-input[readonly],.ds22 .ds-textarea[readonly]{background:var(--surface-sunken);border-style:dashed;border-color:var(--border-strong)}
.ds22 .ds-input[aria-invalid="true"],.ds22 .ds-select[aria-invalid="true"],.ds22 .ds-textarea[aria-invalid="true"]{border-color:var(--negative)}
.ds22 .ds-select{appearance:none;padding-right:var(--space-9);
  background-image:linear-gradient(45deg,transparent 50%,var(--text-muted) 50%),linear-gradient(135deg,var(--text-muted) 50%,transparent 50%);
  background-position:calc(100% - var(--space-6)) 50%,calc(100% - var(--space-5)) 50%;
  background-size:var(--space-2) var(--space-2),var(--space-2) var(--space-2);background-repeat:no-repeat}
.ds22 .ds-search{position:relative;display:flex;align-items:center;min-width:0}
.ds22 .ds-search>.ds-icon{position:absolute;left:var(--space-5);color:var(--text-muted);pointer-events:none}
.ds22 .ds-search>.ds-input{padding-left:var(--space-10)}
.ds22 .ds-search>.ds-kbd{position:absolute;right:var(--space-4)}
.ds22 .ds-check{display:inline-flex;align-items:center;gap:var(--space-4);min-height:var(--target-min);cursor:pointer;font:var(--type-body)}
.ds22 .ds-check input{width:var(--icon-md);height:var(--icon-md);margin:0;accent-color:var(--accent-mint-strong)}
.ds22 .ds-switch{display:inline-flex;align-items:center;gap:var(--space-4);cursor:pointer;min-height:var(--target-min)}
.ds22 .ds-switch input{appearance:none;margin:0;width:calc(var(--v22-icon-xl) + var(--space-4));height:var(--v22-icon-lg);border-radius:var(--radius-pill);
  background:var(--surface-muted);border:var(--border-width) solid var(--border-control);position:relative;cursor:pointer;
  transition:background-color var(--duration-fast) var(--ease-standard)}
.ds22 .ds-switch input::after{content:"";position:absolute;top:var(--space-1);left:var(--space-1);width:var(--icon-sm);height:var(--icon-sm);
  border-radius:var(--radius-pill);background:var(--surface);box-shadow:var(--shadow-raised);transition:transform var(--duration-fast) var(--ease-standard)}
.ds22 .ds-switch input:checked{background:var(--action-primary);border-color:var(--action-primary)}
.ds22 .ds-switch input:checked::after{transform:translateX(var(--space-6))}
.ds22 .ds-switch input:disabled{opacity:.5;cursor:not-allowed}

/* ═══ Навигация: вкладки, сегменты ═══════════════════════════════════ */
.ds22 .ds-tabs{display:flex;align-items:stretch;gap:var(--space-8);border-bottom:var(--border-width) solid var(--border);min-width:0;overflow-x:auto;scrollbar-width:none}
.ds22 .ds-tab{display:inline-flex;align-items:center;gap:var(--space-3);min-height:var(--v22-control-lg);padding:0;border:0;
  border-bottom:var(--border-width-strong) solid transparent;margin-bottom:calc(-1 * var(--border-width));
  background:none;color:var(--text-secondary);font:var(--v22-type-label);white-space:nowrap;cursor:pointer}
.ds22 .ds-tab:hover{color:var(--text-primary)}
.ds22 .ds-tab[aria-selected="true"]{color:var(--text-primary);border-bottom-color:var(--text-primary);font-weight:600}
.ds22 .ds-tab__count{color:var(--text-muted);font-weight:400}
.ds22 .ds-segmented{display:inline-flex;padding:var(--space-1);gap:var(--space-1);background:var(--surface-muted);border-radius:var(--radius-sm);border:var(--border-width) solid var(--border)}
.ds22 .ds-segmented button{min-height:calc(var(--control-height) - var(--space-3));padding:0 var(--space-5);border:0;border-radius:var(--radius-xs);
  background:transparent;color:var(--text-secondary);font:var(--v22-type-label);cursor:pointer;white-space:nowrap}
.ds22 .ds-segmented button:hover{color:var(--text-primary)}
.ds22 .ds-segmented button[aria-pressed="true"],.ds22 .ds-segmented button[aria-checked="true"]{background:var(--action-primary);color:var(--text-inverse)}

.ds22 .ds-breadcrumb{display:flex;align-items:center;gap:var(--space-4);min-width:0;font:var(--v22-type-label);color:var(--text-muted)}
.ds22 .ds-breadcrumb a,.ds22 .ds-breadcrumb button{color:var(--text-muted);background:none;border:0;padding:0;font:inherit;cursor:pointer}
.ds22 .ds-breadcrumb a:hover,.ds22 .ds-breadcrumb button:hover{color:var(--text-primary)}
.ds22 .ds-breadcrumb [aria-current="page"]{margin:0;font:inherit;color:var(--text-primary);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ds22 .ds-breadcrumb__sep{color:var(--border-strong)}

/* ═══ Метки ═══════════════════════════════════════════════════════════ */
.ds22 .ds-badge{display:inline-flex;align-items:center;gap:var(--space-2);min-height:var(--v22-icon-lg);padding:0 var(--space-3);
  border-radius:var(--radius-xs);font:var(--v22-type-micro);letter-spacing:var(--type-micro-tracking);white-space:nowrap;
  background:var(--surface-muted);color:var(--text-secondary)}
.ds22 .ds-badge--positive{background:var(--positive-subtle);color:var(--positive)}
.ds22 .ds-badge--negative{background:var(--negative-subtle);color:var(--negative-strong)}
.ds22 .ds-badge--warning{background:var(--warning-subtle);color:var(--warning-strong)}
.ds22 .ds-badge--info{background:var(--information-subtle);color:var(--information-strong)}
.ds22 .ds-badge--mint{background:var(--accent-mint-subtle);color:var(--accent-mint-strong)}
.ds22 .ds-badge--env{background:var(--environment-marker);color:var(--text-primary)}
.ds22 .ds-counter{display:inline-flex;align-items:center;justify-content:center;gap:var(--space-1);min-width:var(--v22-icon-lg);height:var(--v22-icon-lg);
  padding:0 var(--space-2);border-radius:var(--radius-pill);font:var(--v22-type-micro);color:var(--negative)}
.ds22 .ds-status{display:inline-flex;align-items:center;gap:var(--space-3);font:var(--type-body);color:var(--text-primary);white-space:nowrap}
.ds22 .ds-status .ds-icon{flex:none}
.ds22 .ds-status--positive .ds-icon{color:var(--positive)}
.ds22 .ds-status--neutral .ds-icon{color:var(--text-muted)}
.ds22 .ds-status--negative{color:var(--negative)}
.ds22 .ds-status--warning{color:var(--warning)}
.ds22 .ds-status--info .ds-icon{color:var(--information)}
.ds22 .ds-avatar{display:inline-grid;place-items:center;flex:none;width:var(--control-sm);height:var(--control-sm);border-radius:var(--radius-pill);
  background:var(--action-primary);color:var(--text-inverse);font:var(--v22-type-micro)}
.ds22 .ds-avatar--sm{width:var(--v22-icon-lg);height:var(--v22-icon-lg)}
.ds22 .ds-avatar--lg{width:var(--v22-control-md);height:var(--v22-control-md);font:var(--v22-type-label)}

/* ═══ Происхождение значения: MANUAL · RULE · MINTA · BANK ═══════════
 * Различаются ФОРМОЙ знака и словом; цвет — дополнительный признак. */
.ds22 .ds-prov{display:inline-flex;align-items:center;gap:var(--space-2);font:var(--v22-type-caption);color:var(--text-muted);white-space:nowrap}
.ds22 .ds-prov__mark{display:inline-grid;place-items:center;flex:none;width:var(--icon-md);height:var(--icon-md);font:var(--v22-type-micro);color:var(--text-secondary)}
.ds22 .ds-prov--manual .ds-prov__mark{font-size:var(--icon-xs);letter-spacing:0;color:var(--text-primary)}
.ds22 .ds-prov--rule .ds-prov__mark{border:var(--border-width) solid var(--information);border-radius:var(--radius-xs);color:var(--information);font-size:var(--icon-xs)}
.ds22 .ds-prov--minta .ds-prov__mark{color:var(--accent-mint-strong)}
.ds22 .ds-prov--bank .ds-prov__mark{color:var(--text-secondary)}
.ds22 .ds-prov a{color:inherit;text-decoration:underline;text-underline-offset:2px}

/* ═══ Контейнеры ══════════════════════════════════════════════════════ */
.ds22 .ds-card{background:var(--surface);border:var(--border-width) solid var(--border);border-radius:var(--v22-radius-lg);box-shadow:var(--shadow-panel);min-width:0}
.ds22 .ds-card__head{display:flex;align-items:center;justify-content:space-between;gap:var(--space-5);padding:var(--space-6) var(--space-7);border-bottom:var(--border-width) solid var(--border)}
.ds22 .ds-card__head--plain{border-bottom:0;padding-bottom:0}
.ds22 .ds-card__title{margin:0;font:var(--v22-type-section-title);color:var(--text-primary)}
.ds22 .ds-card__title small{font:var(--type-body);color:var(--text-muted);margin-left:var(--space-2)}
.ds22 .ds-card__body{padding:var(--space-6) var(--space-7)}
.ds22 .ds-card__foot{padding:var(--space-5) var(--space-7);border-top:var(--border-width) solid var(--border);color:var(--text-muted);font:var(--v22-type-caption)}
.ds22 .ds-kpi__label{font:var(--v22-type-label);color:var(--text-secondary)}
.ds22 .ds-kpi__value{font:var(--v22-type-money-large);letter-spacing:var(--type-money-large-tracking);font-variant-numeric:tabular-nums;white-space:nowrap}
.ds22 .ds-kpi__value--hero{font:var(--v22-type-money-hero);letter-spacing:var(--type-money-hero-tracking)}
.ds22 .ds-kpi__value .ds-money__minor{font-size:.6em;color:var(--text-muted);font-weight:500}
.ds22 .ds-chip{display:inline-flex;align-items:center;gap:var(--space-3);min-height:var(--control-sm);padding:0 var(--space-5);
  border:var(--border-width) dashed var(--border-strong);border-radius:var(--radius-sm);background:var(--surface);
  color:var(--text-secondary);font:var(--v22-type-label);white-space:nowrap;cursor:pointer}
.ds22 .ds-chip:hover{background:var(--action-secondary-hover);color:var(--text-primary)}
.ds22 .ds-chip--on{border-style:solid;border-color:var(--accent-mint-strong);background:var(--accent-mint-subtle);color:var(--text-primary)}
.ds22 .ds-chip__main{appearance:none;display:inline-flex;align-items:center;gap:inherit;min-height:var(--target-min);min-width:var(--target-min);margin:0;padding:0;border:0;background:none;font:inherit;color:inherit;cursor:pointer}
.ds22 .ds-chip__x{display:inline-grid;place-items:center;min-width:var(--target-min);min-height:var(--target-min);border:0;background:none;color:inherit;cursor:pointer;padding:0;border-radius:var(--radius-xs)}

/* ═══ Числа ══════════════════════════════════════════════════════════ */
.ds22 .ds-money{font:var(--v22-type-money);font-variant-numeric:tabular-nums;white-space:nowrap}
.ds22 .ds-money--pos{color:var(--positive)}
.ds22 .ds-money--neg{color:var(--text-primary)}
.ds22 .ds-money--danger{color:var(--negative)}
.ds22 .ds-delta{display:inline-flex;align-items:center;gap:var(--space-1);font:var(--v22-type-label);white-space:nowrap;font-variant-numeric:tabular-nums}
.ds22 .ds-delta--up{color:var(--positive)}
.ds22 .ds-delta--down{color:var(--negative)}
.ds22 .ds-budget{display:flex;flex-direction:column;gap:var(--space-3)}
.ds22 .ds-budget__track{position:relative;height:var(--space-4);border-radius:var(--radius-pill);background:var(--surface-muted);overflow:hidden}
.ds22 .ds-budget__used{position:absolute;inset:0 auto 0 0;background:var(--text-primary)}
.ds22 .ds-budget__committed{position:absolute;top:0;bottom:0;background:var(--chart-neutral)}
.ds22 .ds-budget__this{position:absolute;top:0;bottom:0;background:var(--accent-mint)}
.ds22 .ds-budget__this--over{background:var(--negative)}

/* ═══ Обратная связь ═════════════════════════════════════════════════ */
.ds22 .ds-alert{display:flex;gap:var(--space-4);align-items:flex-start;padding:var(--space-5) var(--space-6);border-radius:var(--radius-md);
  border:var(--border-width) solid var(--border);background:var(--surface-sunken);color:var(--text-primary);font:var(--type-body)}
.ds22 .ds-alert--warning{background:var(--warning-subtle);border-color:var(--warning-subtle);color:var(--warning-strong)}
.ds22 .ds-alert--negative{background:var(--negative-subtle);border-color:var(--negative-subtle);color:var(--negative-strong)}
.ds22 .ds-alert--info{background:var(--information-subtle);border-color:var(--information-subtle);color:var(--information-strong)}
.ds22 .ds-alert--positive{background:var(--positive-subtle);border-color:var(--positive-subtle);color:var(--positive)}
.ds22 .ds-alert .ds-icon{flex:none;margin-top:var(--space-1)}
.ds22 .ds-banner{display:flex;align-items:center;gap:var(--space-4);padding:var(--space-4) var(--space-7);font:var(--v22-type-label);
  background:var(--warning-subtle);color:var(--warning-strong);border-bottom:var(--border-width) solid var(--border)}
.ds22 .ds-toast-region{position:fixed;z-index:var(--z-toast);left:50%;bottom:var(--space-8);transform:translateX(-50%);display:flex;flex-direction:column;gap:var(--space-4);pointer-events:none}
.ds22 .ds-toast{pointer-events:auto;display:flex;align-items:center;gap:var(--space-6);padding:var(--space-5) var(--space-6);border-radius:var(--radius-md);
  background:var(--inverse-background);color:var(--inverse-text-primary);box-shadow:var(--shadow-overlay);font:var(--type-body);max-width:min(640px,calc(100vw - var(--space-9)))}
.ds22 .ds-toast .ds-link{color:var(--inverse-accent)}

/* ═══ Наложения ══════════════════════════════════════════════════════ */
.ds22 .ds-popover,.ds22 .ds-menu{position:absolute;z-index:var(--z-dropdown);min-width:calc(var(--space-12) * 3);padding:var(--space-2);
  background:var(--surface-raised);border-radius:var(--radius-md);box-shadow:var(--shadow-overlay)}
.ds22 .ds-popover{padding:var(--space-6)}
.ds22 .ds-menu [role="menuitem"],.ds22 .ds-menu [role="option"],.ds22 .ds-menu__item{display:flex;align-items:center;gap:var(--space-4);width:100%;min-height:var(--control-sm);
  padding:0 var(--space-5);border:0;border-radius:var(--radius-xs);background:none;color:var(--text-primary);font:var(--type-body);text-align:left;cursor:pointer}
.ds22 .ds-menu [role="menuitem"]:hover,.ds22 .ds-menu [role="option"]:hover,.ds22 .ds-menu [aria-selected="true"],.ds22 .ds-menu__item:hover{background:var(--action-secondary-hover)}
.ds22 .ds-menu__sep{height:var(--border-width);margin:var(--space-2) 0;background:var(--border)}
.ds22 .ds-menu__label{padding:var(--space-3) var(--space-5);font:var(--v22-type-caption);color:var(--text-muted)}
.ds22 .ds-tooltip{position:absolute;z-index:var(--z-tooltip);padding:var(--space-3) var(--space-4);border-radius:var(--radius-xs);
  background:var(--inverse-background);color:var(--inverse-text-primary);font:var(--v22-type-caption);max-width:calc(var(--space-12) * 5);pointer-events:none}
.ds22 .ds-scrim{position:fixed;inset:0;z-index:var(--z-drawer);background:color-mix(in srgb,var(--text-primary) 32%,transparent)}
.ds22 .ds-modal{position:fixed;z-index:var(--z-modal);left:50%;top:50%;transform:translate(-50%,-50%);width:min(520px,calc(100vw - var(--space-9)));
  max-height:calc(100vh - var(--space-11));overflow:auto;background:var(--surface-raised);border-radius:var(--radius-xl);box-shadow:var(--shadow-overlay)}
.ds22 .ds-modal__head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--space-6);padding:var(--space-8) var(--space-8) var(--space-4)}
.ds22 .ds-modal__title{margin:0;font:var(--v22-type-subsection)}
.ds22 .ds-modal__body{padding:0 var(--space-8) var(--space-6);color:var(--text-secondary)}
.ds22 .ds-modal__foot{display:flex;justify-content:flex-end;gap:var(--space-4);padding:var(--space-6) var(--space-8) var(--space-8)}
.ds22 .ds-drawer{position:fixed;z-index:calc(var(--z-drawer) + 1);top:0;right:0;bottom:0;width:min(440px,100vw);display:flex;flex-direction:column;
  background:var(--surface);box-shadow:var(--shadow-overlay)}
.ds22 .ds-drawer--left{left:0;right:auto}
.ds22 .ds-sheet{position:fixed;z-index:calc(var(--z-drawer) + 1);left:0;right:0;bottom:0;max-height:90vh;overflow:auto;display:flex;flex-direction:column;
  background:var(--surface);border-radius:var(--radius-xl) var(--radius-xl) 0 0;box-shadow:var(--shadow-overlay)}

/* ═══ Таблица ════════════════════════════════════════════════════════ */
.ds22 .ds-table-wrap{position:relative;overflow:auto;background:var(--surface);border:var(--border-width) solid var(--border);border-radius:var(--v22-radius-lg)}
.ds22 .ds-table{width:100%;border-collapse:separate;border-spacing:0;font:var(--v22-type-table);font-size:var(--table-font-size)}
.ds22 .ds-table th{position:sticky;top:0;z-index:var(--z-sticky);height:var(--ds-header-height);padding:0 var(--cell-padding-x);text-align:left;
  background:var(--surface-sunken);color:var(--text-muted);font:var(--v22-type-caption);font-weight:500;white-space:nowrap;
  border-bottom:var(--border-width) solid var(--border-strong)}
.ds22 .ds-table td{height:var(--row-height);padding:0 var(--cell-padding-x);border-bottom:var(--border-width) solid var(--border);vertical-align:middle}
.ds22 .ds-table tbody tr:hover td{background:var(--surface-sunken)}
.ds22 .ds-table tr[aria-selected="true"] td{background:var(--accent-mint-subtle)}
.ds22 .ds-table tr[aria-current="true"] td{background:var(--row-current)}
.ds22 .ds-table tr[data-changed] td{background:var(--row-changed)}
.ds22 .ds-table .ds-num,.ds22 .ds-table td[data-money],.ds22 .ds-table th[data-money]{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.ds22 .ds-table tfoot td,.ds22 .ds-table tr.ds-total td{font-weight:600;background:var(--surface-sunken);border-top:var(--border-width) solid var(--border-strong)}
.ds22 .ds-table tr.ds-group td{font-weight:600;background:var(--surface)}
.ds22 .ds-table th button{display:inline-flex;align-items:center;gap:var(--space-2);border:0;background:none;padding:0;font:inherit;color:inherit;cursor:pointer}
.ds22 .ds-table th[aria-sort] button{color:var(--text-primary)}
.ds22 .ds-table .ds-clip{max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ds22 .ds-cell-sub{display:block;font:var(--v22-type-caption);color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ds22 .ds-rowcheck{display:grid;place-items:center;width:100%;height:100%;min-height:var(--target-min);cursor:pointer}
.ds22 .ds-batchbar{display:flex;align-items:center;gap:var(--space-5);min-height:var(--ds-toolbar-height);padding:0 var(--space-6);
  background:var(--inverse-background);color:var(--inverse-text-primary);border-radius:var(--radius-md);box-shadow:var(--shadow-overlay)}
.ds22 .ds-batchbar .ds-btn--ghost{color:var(--inverse-text-primary)}
.ds22 .ds-batchbar .ds-btn--ghost:hover{background:var(--inverse-surface-raised)}

/* ═══ Состояния системы ══════════════════════════════════════════════ */
.ds22 .ds-skeleton{display:block;min-height:var(--space-6);border-radius:var(--radius-xs);background:var(--surface-muted);animation:ds-pulse var(--duration-slow) var(--ease-standard) infinite alternate}
@keyframes ds-pulse{from{opacity:.55}to{opacity:1}}
@media (prefers-reduced-motion: reduce){.ds22 .ds-skeleton{animation:none}}
.ds22 .ds-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-4);padding:var(--space-11) var(--space-8);text-align:center;color:var(--text-secondary)}
.ds22 .ds-empty__title{margin:0;font:var(--v22-type-section-title);color:var(--text-primary)}
.ds22 .ds-empty .ds-icon{color:var(--text-muted)}
.ds22 .ds-state--error .ds-empty__title{color:var(--negative)}

/* ═══ Предметные: пункт внимания, предложение Minta ═════════════════ */
.ds22 .ds-attn{display:grid;grid-template-columns:var(--v22-icon-lg) minmax(0,1fr) auto;gap:var(--space-4) var(--space-5);align-items:start;
  padding:var(--space-6) var(--space-7);border-bottom:var(--border-width) solid var(--border)}
.ds22 .ds-attn:last-child{border-bottom:0}
.ds22 .ds-attn[aria-current="true"]{outline:var(--border-width-strong) solid var(--accent-mint);outline-offset:calc(-1 * var(--border-width-strong));border-radius:var(--radius-md)}
.ds22 .ds-attn__title{margin:0;font:var(--type-body);font-weight:600;color:var(--text-primary)}
.ds22 .ds-attn__why{margin:var(--space-1) 0 0;color:var(--text-secondary)}
.ds22 .ds-attn__meta{display:flex;flex-wrap:wrap;gap:var(--space-2) var(--space-5);margin-top:var(--space-3);font:var(--v22-type-caption);color:var(--text-muted)}
.ds22 .ds-attn__side{display:flex;flex-direction:column;align-items:flex-end;gap:var(--space-2);text-align:right}
.ds22 .ds-attn__amount{font:var(--v22-type-money);font-weight:600;white-space:nowrap}
.ds22 .ds-attn__when{font:var(--v22-type-caption);color:var(--text-muted)}
.ds22 .ds-sev{display:inline-grid;place-items:center;width:var(--v22-icon-lg);height:var(--v22-icon-lg)}
.ds22 .ds-sev--critical{color:var(--negative)}
.ds22 .ds-sev--warning{color:var(--warning)}
.ds22 .ds-sev--info{color:var(--information)}
.ds22 .ds-minta{padding:var(--space-5) var(--space-6);border-radius:var(--radius-md);background:var(--accent-mint-subtle);color:var(--text-primary)}
.ds22 .ds-minta--explain{background:var(--surface);border:var(--border-width) solid var(--border)}

/* ═══ Каркас: навигация 240 / 56, верхняя полоса ═════════════════════ */
.ds22 .ds-shell{display:flex;height:100vh;height:100dvh;overflow:hidden;background:var(--background);color:var(--text-primary)}
.ds22 .ds-nav{flex:none;width:calc(var(--space-12) * 3.75);display:flex;flex-direction:column;gap:var(--space-2);padding:var(--space-6) var(--space-4) var(--space-4);
  background:var(--background-sidebar);border-right:var(--border-width) solid var(--border);overflow-y:auto;z-index:var(--z-sidebar)}
.ds22 .ds-nav__company{display:flex;align-items:center;gap:var(--space-5);width:100%;padding:var(--space-2) var(--space-3);margin-bottom:var(--space-5);
  border:0;border-radius:var(--radius-md);background:none;text-align:left;cursor:pointer;color:var(--text-primary)}
.ds22 .ds-nav__company:hover{background:var(--action-secondary-hover)}
.ds22 .ds-nav__logo{display:grid;place-items:center;flex:none;width:var(--v22-control-md);height:var(--v22-control-md);border-radius:var(--radius-md);
  background:var(--action-primary);color:var(--text-inverse);font:var(--v22-type-label);font-weight:600}
.ds22 .ds-nav__company-name{display:block;font:var(--v22-type-label);font-weight:600;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.ds22 .ds-nav__company-sub{display:block;font:var(--v22-type-caption);color:var(--text-muted)}
.ds22 .ds-nav__search{margin-bottom:var(--space-5)}
.ds22 .ds-nav__search .ds-input{min-height:var(--v22-control-md);background:var(--surface);border-color:var(--border-strong)}
.ds22 .ds-nav__item{position:relative;display:flex;align-items:center;gap:var(--space-5);width:100%;min-height:var(--v22-control-md);padding:0 var(--space-5);
  border:var(--border-width) solid transparent;border-radius:var(--radius-md);background:none;color:var(--text-secondary);
  font:var(--v22-type-label);text-align:left;text-decoration:none;cursor:pointer;white-space:nowrap}
.ds22 .ds-nav__item:hover{background:var(--action-secondary-hover);color:var(--text-primary)}
.ds22 .ds-nav__item[aria-current="page"]{background:var(--surface);border-color:var(--border);color:var(--text-primary);font-weight:600;box-shadow:var(--shadow-panel)}
.ds22 .ds-nav__item[aria-current="page"]::before{content:"";position:absolute;left:calc(-1 * var(--space-4));top:var(--space-3);bottom:var(--space-3);width:var(--border-width-strong);border-radius:var(--radius-pill);background:var(--accent-mint)}
.ds22 .ds-nav__item .ds-icon{flex:none;color:var(--text-muted)}
.ds22 .ds-nav__item[aria-current="page"] .ds-icon{color:var(--text-primary)}
.ds22 .ds-nav__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}
.ds22 .ds-nav__chev{flex:none;color:var(--text-muted);transition:transform var(--duration-fast) var(--ease-standard)}
.ds22 .ds-nav__item[aria-expanded="true"] .ds-nav__chev{transform:rotate(90deg)}
.ds22 .ds-nav__sep{height:var(--border-width);margin:var(--space-5) var(--space-3);background:var(--border)}
.ds22 .ds-nav__group-title{font:var(--v22-type-label);color:var(--text-muted)}
.ds22 .ds-nav__sub{display:flex;flex-direction:column;gap:var(--space-1);padding-left:var(--space-9)}
.ds22 .ds-nav__sub .ds-nav__item{min-height:var(--control-sm);font-weight:400}
.ds22 .ds-nav__spacer{flex:1}
.ds22 .ds-nav__user{display:flex;align-items:center;gap:var(--space-5);padding:var(--space-5) var(--space-3) 0;border-top:var(--border-width) solid var(--border);margin-top:var(--space-4)}
.ds22 .ds-nav__user-name{display:block;font:var(--v22-type-label);font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ds22 .ds-nav__user-role{display:block;font:var(--v22-type-caption);color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ds22 .ds-main{flex:1;min-width:0;display:flex;flex-direction:column;overflow:hidden}
.ds22 .ds-topbar{flex:none;display:flex;align-items:center;gap:var(--space-6);min-height:calc(var(--v22-control-lg) + var(--space-5));padding:0 var(--space-8);
  background:var(--surface);border-bottom:var(--border-width) solid var(--border)}
.ds22 .ds-topbar__spacer{flex:1;min-width:var(--space-4)}
.ds22 .ds-fresh{display:inline-flex;align-items:center;gap:var(--space-3);font:var(--v22-type-caption);color:var(--text-muted);white-space:nowrap}
.ds22 .ds-fresh--stale{color:var(--warning)}
.ds22 .ds-page{flex:1;min-width:0;overflow:auto;padding:var(--space-8)}
.ds22 .ds-page__head{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:var(--space-5);margin-bottom:var(--space-7)}
.ds22 .ds-page__kicker{font:var(--v22-type-caption);color:var(--text-muted);margin-bottom:var(--space-2)}
.ds22 .ds-page__title{margin:0;font:var(--v22-type-page-title);letter-spacing:var(--type-page-title-tracking)}
.ds22 .ds-page__actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-4)}
.ds22 .ds-grid{display:grid;gap:var(--space-7)}

/* Полоса значков 56 px: 1024–1279 и по выбору человека. */
.ds22 .ds-shell[data-nav="rail"] .ds-nav{width:calc(var(--v22-control-lg) + var(--space-5));padding-left:var(--space-3);padding-right:var(--space-3);align-items:center}
.ds22 .ds-shell[data-nav="rail"] .ds-nav__label,.ds22 .ds-shell[data-nav="rail"] .ds-nav__chev,.ds22 .ds-shell[data-nav="rail"] .ds-nav__company-text,.ds22 .ds-shell[data-nav="rail"] .ds-nav__search,.ds22 .ds-shell[data-nav="rail"] .ds-nav__group-title,.ds22 .ds-shell[data-nav="rail"] .ds-nav__sub,.ds22 .ds-shell[data-nav="rail"] .ds-nav__user-text{display:none}
.ds22 .ds-shell[data-nav="rail"] .ds-nav__item{justify-content:center;padding:0;width:var(--v22-control-md)}
@media (min-width:1024px) and (max-width:1279px){
  .ds22 .ds-shell:not([data-nav="full"]) .ds-nav{width:calc(var(--v22-control-lg) + var(--space-5));padding-left:var(--space-3);padding-right:var(--space-3);align-items:center}
  .ds22 .ds-shell:not([data-nav="full"]) .ds-nav__label,.ds22 .ds-shell:not([data-nav="full"]) .ds-nav__chev,.ds22 .ds-shell:not([data-nav="full"]) .ds-nav__company-text,.ds22 .ds-shell:not([data-nav="full"]) .ds-nav__search,.ds22 .ds-shell:not([data-nav="full"]) .ds-nav__group-title,.ds22 .ds-shell:not([data-nav="full"]) .ds-nav__sub,.ds22 .ds-shell:not([data-nav="full"]) .ds-nav__user-text{display:none}
  .ds22 .ds-shell:not([data-nav="full"]) .ds-nav__item{justify-content:center;padding:0;width:var(--v22-control-md)}
}
/* Узкие окна (< 1024): навигация — ящик по кнопке «Меню»; на телефоне — нижняя полоса. */
.ds22 .ds-topbar__menu{display:none}
@media (max-width:1023px){
  .ds22 .ds-shell .ds-nav{position:fixed;inset:0 auto 0 0;transform:translateX(-100%);transition:transform var(--duration-base) var(--ease-standard);box-shadow:var(--shadow-overlay);z-index:var(--z-drawer)}
  .ds22 .ds-shell[data-nav-open="1"] .ds-nav{transform:none}
  .ds22 .ds-topbar__menu{display:inline-flex}
  .ds22 .ds-topbar{padding:0 var(--space-6)}
  .ds22 .ds-page{padding:var(--space-6)}
}
@media (max-width:599px){
  .ds22 .ds-page{padding:var(--space-5) var(--space-6) calc(var(--v22-control-touch) + var(--space-8))}
  .ds22 .ds-page__title{font:var(--v22-type-page-title)}
}
.ds22 .ds-tabbar{display:none}
@media (max-width:599px){
  .ds22 .ds-tabbar{position:fixed;left:0;right:0;bottom:0;z-index:var(--z-sidebar);display:grid;grid-template-columns:repeat(5,1fr);
    min-height:calc(var(--v22-control-touch) + var(--space-5));padding-bottom:env(safe-area-inset-bottom);
    background:var(--surface);border-top:var(--border-width) solid var(--border)}
  .ds22 .ds-tabbar button{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-1);
    min-height:var(--v22-control-touch);border:0;background:none;color:var(--text-muted);font:var(--v22-type-micro);cursor:pointer}
  .ds22 .ds-tabbar button[aria-current="page"]{color:var(--text-primary)}
  .ds22 .ds-tabbar .ds-counter{position:absolute;top:var(--space-2);left:calc(50% + var(--space-3))}
}

/* ═══ Кабинет поставщика: тёмная оболочка на тех же компонентах ═════ */
.ds22 .ds-provider{--background-sidebar:var(--inverse-background)}
.ds22 .ds-provider .ds-nav{background:var(--inverse-background);border-right-color:var(--inverse-border);color:var(--inverse-text-primary)}
.ds22 .ds-provider .ds-nav__item{color:var(--inverse-text-secondary)}
.ds22 .ds-provider .ds-nav__item .ds-icon{color:var(--inverse-text-muted)}
.ds22 .ds-provider .ds-nav__item:hover{background:var(--inverse-surface);color:var(--inverse-text-primary)}
.ds22 .ds-provider .ds-nav__item[aria-current="page"]{background:var(--inverse-surface-raised);border-color:var(--inverse-border-strong);color:var(--inverse-text-primary);box-shadow:none}
.ds22 .ds-provider .ds-nav__item[aria-current="page"] .ds-icon{color:var(--inverse-accent)}
.ds22 .ds-provider .ds-nav__item[aria-current="page"]::before{background:var(--inverse-accent)}
.ds22 .ds-provider .ds-nav__company-sub,.ds22 .ds-provider .ds-nav__user-role,.ds22 .ds-provider .ds-nav__group-title{color:var(--inverse-text-muted)}
.ds22 .ds-provider .ds-nav__logo{background:var(--inverse-accent);color:var(--inverse-background)}
.ds22 .ds-provider .ds-nav__sep,.ds22 .ds-provider .ds-nav__user{border-color:var(--inverse-border);background:var(--inverse-border)}
.ds22 .ds-provider .ds-nav__user{background:none}

