/* =========================================================================
   Дизайн-система «Стыка». Направление — «акт сверки».
   Обоснование и правила: packages/design-system/DESIGN.md
   Значения: packages/design-system/src/tokens.ts (руками здесь не писать)

   Несущая идея вёрстки — ВЕРТИКАЛЬНАЯ РАЗГРАФКА. Колонки разделены линиями,
   строки не разделены ничем, кроме ритма и чередования плоскости. Сверка —
   это сравнение колонок, и вертикаль здесь несёт смысл.
   ========================================================================= */

/* ---- Шрифты -------------------------------------------------------------
   Начертания лежат рядом, в `fonts/`, и раздаются со своего домена: в
   закрытом контуре банка сторонний шрифтовой хост недоступен ВСЕГДА, и
   кабинет, у которого типографика приезжает из интернета, там открывается
   запасными системными. Политика безопасности страницы сужена до
   `font-src 'self'` — посторонний домен не подгрузится и незаметно.

   ВЗЯТО РОВНО ТО, ЧТО СИСТЕМА УПОТРЕБЛЯЕТ, а не семейства целиком:

     • Geologica только 600. Заголовочное начертание живёт ровно в четырёх
       местах (знак, заголовок экрана, заголовок панели, заголовок состояния),
       и во всех четырёх — полужирным. 400 и 500 у неё не набирает ничто.
     • IBM Plex Sans переменным файлом на диапазон 400–600 вместо трёх
       статических. Все три толщины употребляются на каждой странице разом
       (текст 400, кнопка и текущий пункт 500, шапка таблицы и подпись поля
       600), поэтому переменный файл — не «на будущее», а меньше байт прямо
       сейчас: 104 КБ против 161 КБ у трёх статических на тот же набор
       подмножеств. Замерено, а не предположено.
     • IBM Plex Mono статикой 400 и 500: переменного у неё нет.
     • Курсивов нет ни у одного семейства — система не набирает курсивом
       ничего.

   ПОДМНОЖЕСТВА — три из шести: латиница, расширенная латиница, кириллица.
   Греческого и вьетнамского в кабинете не бывает, расширенной кириллицы
   (U+0460-052F — старославянское и нерусские алфавиты) тоже. Расширенная
   латиница взята из-за ОДНОГО знака: ₽ это U+20BD, и он лежит именно там.
   У Geologica её нет намеренно: ₽ не набирается заголовочным начертанием
   никогда — по правилу «деньги всегда моноширинным» сумма физически не может
   оказаться в заголовке. Полнота набора сверяется тестом `fonts.test.ts`:
   знак, которого нет ни в одном подмножестве, роняет сборку, а не всплывает
   прямоугольником в чужой сумме.

   Лицензии обоих семейств — SIL OFL 1.1, самостоятельный хостинг разрешён.
   Тексты лицензий лежат рядом с файлами (`fonts/OFL-*.txt`) и уезжают вместе
   с ними в `dist/`: это условие лицензии, а не формальность.               */

@font-face {
  font-family: 'Geologica';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('fonts/geologica-600-latin.woff2') format('woff2');
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Geologica';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('fonts/geologica-600-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400 600;
  font-stretch: 100%;
  font-display: swap;
  src: url('fonts/ibm-plex-sans-400-600-latin.woff2') format('woff2');
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400 600;
  font-stretch: 100%;
  font-display: swap;
  src: url('fonts/ibm-plex-sans-400-600-latin-ext.woff2') format('woff2');
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400 600;
  font-stretch: 100%;
  font-display: swap;
  src: url('fonts/ibm-plex-sans-400-600-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/ibm-plex-mono-400-latin.woff2') format('woff2');
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/ibm-plex-mono-400-latin-ext.woff2') format('woff2');
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/ibm-plex-mono-400-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('fonts/ibm-plex-mono-500-latin.woff2') format('woff2');
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('fonts/ibm-plex-mono-500-latin-ext.woff2') format('woff2');
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('fonts/ibm-plex-mono-500-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

/* ---- Основание --------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body.st-body {
  margin: 0;
  background: var(--st-ground);
  color: var(--st-ink);
  font-family: var(--st-font-ui);
  font-size: var(--st-text-body);
  line-height: var(--st-leading-normal);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

.st-body :focus-visible {
  outline: var(--st-border-seam) solid var(--st-seam);
  outline-offset: 2px;
  border-radius: var(--st-radius-sm);
}

/* Ничто не уезжает вбок: широкое содержимое прокручивается внутри своей
   области, а не растягивает страницу. Проверяется замером, а не на глаз. */
.st-scroll-x {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  /* Полоса прокрутки ТОНКАЯ, НО ВИДИМАЯ. Скрытая полоса делает прокрутку
     невидимой, а невидимая прокрутка — это спрятанные данные: человек не
     знает, что справа есть колонка, и не тянет за неё. Признак прокрутки
     обязателен, и в системе без градиентов и теней им остаётся сама полоса. */
  scrollbar-width: thin;
}

/* ---- Ссылки -------------------------------------------------------------
   ОДНО ПРАВИЛО НА ВСЕ ССЫЛКИ КАБИНЕТА, а не по месту. До этого правила
   покрашены были только ссылки таблицы, а те же самые идентификаторы в
   карточках телефона доставались браузеру: он рисовал их своим #0000ee, а
   после первого перехода — посещённым #551a8b. На тёмной поверхности это
   1,77:1 и 1,51:1 при пороге 4,5:1 — то самое «фиолетовое подчёркнутое,
   которое не читается».

   ССЫЛКА ОТЛИЧАЕТСЯ ОТ ТЕКСТА НЕ ЦВЕТОМ. Цвет у неё тот же, что у соседнего
   текста, — тушь. Отличают её ЛИНИЯ подчёркивания (`link-line`, ≥ 3:1 к
   поверхности в обеих темах) и моноширинное начертание идентификатора.
   Цветовая разница в тёмной теме садится первой, поэтому нести признак
   ссылки ей нельзя. Акцент появляется на наведении и фокусе — и появляется
   линией, как ему и положено в этой системе.

   `:visited` перекрыт намеренно: история переходов не имеет отношения к
   реестру заявок, а браузерная умолчальная фиолетовая ссылка — единственный
   цвет на экране, который система не выбирала.

   ПРАВИЛО ЖИВЁТ ВНУТРИ `.st-main`, А НЕ НА ВСЁМ `.st-body`. Рельс разделов,
   знак и ссылка «перейти к содержимому» — это навигация, а не текстовая
   ссылка: у них своя подача (вертикаль слева, заголовочное начертание) и своё
   `text-decoration: none`. Общее правило по одному классу перебивало их по
   силе селектора и подчёркивало всю шапку разом. Граница здесь структурная —
   область содержимого против навигационной обвязки, — а не список исключений,
   который забудут дополнить. */

.st-main a {
  color: var(--st-ink);
  text-decoration-line: underline;
  text-decoration-color: var(--st-link-line);
  text-decoration-thickness: var(--st-border-hairline);
  text-underline-offset: 2px;
  transition:
    color var(--st-duration-instant) var(--st-ease-out),
    text-decoration-color var(--st-duration-instant) var(--st-ease-out);
}

.st-main a:visited {
  color: var(--st-ink);
}

/* Моноширинный внутри ссылки наследует её цвет: иначе `.st-mono` перекрывает
   его собственным, и отклик на наведение не доходит до текста — а текст в
   ссылке реестра целиком и есть этот `.st-mono`. */
.st-main a .st-mono {
  color: inherit;
}

.st-main a:hover {
  color: var(--st-seam-ink);
  text-decoration-color: var(--st-seam);
}

.st-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .st-body *,
  .st-body *::before,
  .st-body *::after {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* ---- Каркас ------------------------------------------------------------ */

.st-shell {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  /* Страница не едет вбок ни при каких данных. Правило доктрины, и держать его
     обязана вёрстка, а не длина слов, которые в неё положат. */
  overflow-x: clip;
}

/* Ярус под шапкой: слева колонка разделов, справа всё остальное.

   ПОЯВИЛСЯ 18.09.2026 ВМЕСТЕ С ВЕРТИКАЛЬНОЙ НАВИГАЦИЕЙ. До него рельс был
   горизонтальной лентой внутри шапки и держал три раздела; разделов стало
   девять, лента начала прокручиваться внутри себя — то есть половина разделов
   перестала быть видимой, и узнать об их существовании можно было, только
   потянув за ленту. Слово владельца в тот день: «навигация горизонтальная мне
   не нравится, сделай её вертикально слева как везде мы делаем».

   `min-width: 0` СТОИТ НА КАЖДОМ УРОВНЕ, а не на одном. У элемента гибкой
   раскладки `min-width` по умолчанию равен `auto`, и он не даёт себе стать уже
   содержимого: широкая таблица в колонке растянула бы весь ярус. Урок куплен
   дважды (аудит 29.08.2026) — снятый на одном уровне, ноль восстанавливается
   соседним. */
.st-shell__frame {
  display: flex;
  flex: 1 1 auto;
  align-items: stretch;
  min-height: 0;
  min-width: 0;
}

.st-shell__column {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
}

.st-header {
  position: sticky;
  top: 0;
  z-index: var(--st-z-sticky);
  background: var(--st-surface);
  border-bottom: var(--st-border-hairline) solid var(--st-line-strong);
}

/* Шапка идёт ВО ВСЮ ШИРИНУ, а не по колонке содержимого: под её левым краем
   стоит рельс, и знак продукта обязан стоять над рельсом, а не над таблицей.
   Высота НАЗНАЧЕНА, а не получается из содержимого: под неё липнут рельс и
   полоса контекста (`top: var(--st-bar-height)`), и разойтись этим числам не в
   чем — оно одно. */
.st-header__top {
  min-height: var(--st-bar-height);
  box-sizing: border-box;
  padding: var(--st-space-2) var(--st-gutter);
  display: flex;
  align-items: center;
  gap: var(--st-space-4);
}

/* Знак. Два столбца разной высоты и шов между ними — это и есть «стык».
   Рисуется разметкой, а не картинкой: знак обязан жить в тёмной теме. */
.st-mark {
  display: inline-flex;
  align-items: flex-end;
  gap: 3px;
  height: 22px;
}

.st-mark__bar {
  width: 4px;
  background: var(--st-ink);
}

.st-mark__bar:nth-child(1) {
  height: 14px;
}

.st-mark__bar:nth-child(2) {
  height: 22px;
}

.st-mark__seam {
  width: var(--st-border-seam);
  height: 22px;
  background: var(--st-seam);
}

.st-mark__bar:nth-child(4) {
  height: 18px;
}

.st-mark__bar:nth-child(5) {
  height: 10px;
}

.st-wordmark {
  font-family: var(--st-font-display);
  font-size: var(--st-text-section);
  font-weight: var(--st-weight-semibold);
  letter-spacing: var(--st-tracking-tight);
  color: var(--st-ink);
  text-decoration: none;
}

.st-header__spacer {
  flex: 1 1 auto;
}

.st-org {
  display: flex;
  flex-direction: column;
  line-height: var(--st-leading-tight);
  text-align: right;
  min-width: 0;
}

.st-org__name {
  font-size: var(--st-text-caption);
  font-weight: var(--st-weight-medium);
  color: var(--st-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.st-org__role {
  font-size: var(--st-text-micro);
  color: var(--st-ink-faint);
}

/* Кто вошёл. Стоит рядом с тем, ЧЕЙ это кабинет, и отвечает на другой вопрос:
   имя партнёра — «чей экран», имя вошедшего — «под кем я сижу». В кабинете,
   где один человек готовит расчёт, а второй его утверждает, второй вопрос
   важнее первого: вход под чужой учётной записью там равен подписи чужим
   именем. Разделяющая линия появляется только когда слева действительно
   стоит имя партнёра — иначе она висела бы у края экрана ни при чём. */
.st-org--partner + .st-org--viewer {
  border-left: var(--st-border-hairline) solid var(--st-line);
  padding-left: var(--st-space-4);
}

/* Выход — форма, а не ссылка: выход по GET срабатывает от чужой картинки на
   постороннем сайте и от предзагрузчика браузера. Форма в шапке не должна
   ничего занимать собой. */
.st-signout {
  display: flex;
  margin: 0;
}

/* Метка контура. Не штриховка по верху окна (так сделано в ЦК) — рамка
   вокруг слова, как оттиск штампа на документе. */
.st-contour {
  font-family: var(--st-font-mono);
  font-size: var(--st-text-micro);
  letter-spacing: var(--st-tracking-label);
  text-transform: uppercase;
  color: var(--st-seam-ink);
  border: var(--st-border-hairline) solid var(--st-seam);
  border-radius: var(--st-radius-sm);
  padding: 2px var(--st-space-2);
  white-space: nowrap;
}

/* ---- Рельс разделов: КОЛОНКА СЛЕВА -------------------------------------

   ЧТО ЗДЕСЬ ИЗМЕНИЛОСЬ 18.09.2026 И ПОЧЕМУ.

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

   ЗАМЕРЕНО 18.09.2026 на ленте заявок, по числу пунктов, видимых ЦЕЛИКОМ:
   1440 и шире — 9 из 9; 1024 — 8 из 9 (лента прокручена на 71 px); 900 — 7 из
   9 (195 px); 768 — 7 из 9 (327 px); 641 — 6 из 9 (454 px). То есть на
   ноутбуке и на планшете часть разделов стояла за правым краем, и человек, не
   знающий об их существовании, узнать о нём не мог: прокрутка отвечает на
   вопрос «можно ли тянуть», а не «что там дальше».

   Проверялось замером, а не на глаз: первая редакция этого комментария
   утверждала, что разделы уезжают уже на 1440, — браузер показал, что нет.

   Слово владельца 18.09.2026: «навигация горизонтальная мне не нравится. Сделай
   её вертикально слева как везде мы делаем». «Как везде» — это админка
   «Цифрового Контура»: колонка разделов слева, разделы сгруппированы, текущий
   помечен штрихом у левого края. Приём взят оттуда целиком; значения — свои,
   и сверка отличий от соседних фронтов холдинга по-прежнему в DESIGN.md.

   В КОЛОНКЕ ВИДНЫ ВСЕ ДЕВЯТЬ РАЗДЕЛОВ СРАЗУ, без прокрутки, на любой высоте от
   700 px. Это и есть причина смены: навигация обязана отвечать на вопрос «что
   вообще есть», а не только «где я». */

.st-rail {
  flex: 0 0 var(--st-rail-width);
  width: var(--st-rail-width);
  box-sizing: border-box;
  background: var(--st-surface);
  border-right: var(--st-border-hairline) solid var(--st-line-strong);
  /* Липнет под шапку, а не к верху окна: шапка сама липкая и накрыла бы первый
     пункт. Смещение — тот же токен, которым задана высота шапки. */
  position: sticky;
  top: var(--st-bar-height);
  align-self: flex-start;
  /* ВЫСОТА, А НЕ ПОТОЛОК. С `max-height` колонка обрывалась там, где кончался
     последний раздел, — на снимке 18.09.2026 это середина экрана: плоскость и
     линия справа заканчивались посреди страницы, и левый край читался как
     недогруженный блок, а не как колонка. Теперь она занимает окно целиком, а
     прокручивается внутри себя, если разделов однажды станет больше. */
  height: calc(100dvh - var(--st-bar-height));
  /* Если разделов однажды станет больше, чем помещается в окно, прокрутится
     САМ РЕЛЬС, а не страница. Полоса видима: прокрутка, о которой человек не
     знает, — это спрятанные данные. */
  overflow-y: auto;
  scrollbar-width: thin;
}

.st-rail__inner {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--st-space-4) var(--st-space-2) var(--st-space-5);
  min-width: 0;
}

/* Подпись группы разделов.

   БЕЗ ПРОПИСНЫХ. Заглавными набирают служебные подписи в «Цифровом Контуре» —
   здесь этого нет по двум причинам сразу: русское слово прописными читается
   медленнее строчного, а тракт из микрокегля, разрядки и капса — расхожий
   приём, по которому узнают интерфейс, собранный из чужого набора. Группу
   отделяет положение и тон, а не рост букв. */
.st-rail__group {
  padding: var(--st-space-4) var(--st-space-3) var(--st-space-1);
  font-size: var(--st-text-micro);
  letter-spacing: var(--st-tracking-label);
  color: var(--st-ink-faint);
}

.st-rail__group:first-child {
  padding-top: 0;
}

/* Текущий раздел отмечен ВЕРТИКАЛЬНОЙ линией слева, а не полосой сверху и не
   заливкой: та же разграфка, что в таблицах. */
.st-rail__link {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--st-space-2);
  min-height: var(--st-rail-height);
  padding: 0 var(--st-space-3);
  border-left: var(--st-border-seam) solid transparent;
  font-size: var(--st-text-lead);
  color: var(--st-ink-muted);
  text-decoration: none;
  min-width: 0;
  transition: color var(--st-duration-instant) var(--st-ease-out);
}

/* Название раздела ужимается ПЕРВЫМ. Длинное имя рядом со счётчиком не толкает
   пункт вбок и не растягивает колонку: обрезается многоточием, а число
   остаётся целым — счётчик и есть то, ради чего в пункт смотрят не глядя. */
.st-rail__name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.st-rail__link:hover {
  color: var(--st-ink);
  background: var(--st-surface-sunken);
}

.st-rail__link[aria-current='page'] {
  border-left-color: var(--st-seam);
  color: var(--st-ink);
  font-weight: var(--st-weight-medium);
  background: var(--st-seam-wash);
}

.st-rail__count {
  flex: 0 0 auto;
  margin-left: auto;
  font-family: var(--st-font-mono);
  font-size: var(--st-text-micro);
  color: var(--st-tone-alarm-ink);
  border: var(--st-border-hairline) solid var(--st-tone-alarm-edge);
  border-radius: var(--st-radius-sm);
  padding: 0 4px;
}

/* Раздел, на который нет права, НАЗВАН, а не спрятан: спрятанная кнопка
   порождает вопрос «а где?», названная — ответ «не ваша роль». Признак не
   цветовой — рядом стоит слово: цветовая разница в тёмной теме садится первой,
   а значков в этой системе нет вовсе. Ссылкой пункт остаётся намеренно, чтобы
   переход по нему привёл на честный экран «этот раздел вам не открыт», а не в
   никуда. Пометка при этом ничего не закрывает: доступ закрывает оркестратор. */
.st-rail__link--locked {
  color: var(--st-ink-faint);
}

.st-rail__locked {
  flex: 0 0 auto;
  margin-left: auto;
  font-size: var(--st-text-micro);
  letter-spacing: var(--st-tracking-label);
  color: var(--st-ink-faint);
  white-space: nowrap;
}

/* ---- Бургер: навигация телефона ----------------------------------------
   Значков-глифов система не употребляет, но навигацию телефона владелец
   потребовал бургером (макет 15.09.2026). Три полосы — не глиф из шрифта, а
   разметка: живёт в тёмной теме и не зависит от того, доехал ли шрифт.
   Кнопка видна ТОЛЬКО на узком экране (правило ниже, в блоке ≤640); на
   десктопе рельс стоит сам, и бургеру там делать нечего. */
.st-burger {
  display: none;
  flex: none;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 40px;
  height: 36px;
  padding: 0 8px;
  background: transparent;
  border: var(--st-border-hairline) solid var(--st-line-strong);
  border-radius: var(--st-radius-sm);
  cursor: pointer;
}

.st-burger span {
  display: block;
  height: 2px;
  background: var(--st-ink);
}

.st-burger[aria-expanded='true'] {
  background: var(--st-seam-wash);
  border-color: var(--st-seam);
}

/* ---- Узкий экран: рельс складывается в лист под шапкой ------------------

   ПОРОГ 1024, А НЕ 640, И ЭТО СЛЕДСТВИЕ ВЕРТИКАЛЬНОЙ НАВИГАЦИИ. Колонка в
   240 px отнимает их у содержимого: на 768 реестру заявок оставалось бы 528, и
   таблица ушла бы в прокрутку внутри себя на экране, где до правки помещалась
   целиком. Между 641 и 1023 рельс теперь тоже за бургером — раньше там висела
   горизонтальная лента.

   ЛИСТ РАСКРЫВАЕТСЯ В ПОТОКЕ, А НЕ НАКРЫВАЕТ СТРАНИЦУ. Всплывающий поверх
   содержимого лист требует ловушки фокуса, закрытия по Esc и запрета
   прокрутки под собой — трёх поведений, каждое из которых ломается молча.
   Лист в потоке раздвигает страницу и не умеет сломаться вовсе.

   ЛИПКОСТЬ ЗДЕСЬ СНЯТА НАМЕРЕННО: шапка на узком экране переносится на две
   строки, её высота перестаёт равняться `--st-bar-height`, и липкий блок,
   смещённый на это число, дал бы наезд. Одно назначенное число держит
   раскладку ровно там, где оно верно, и нигде больше. */
@media (max-width: 1023px) {
  .st-burger {
    display: flex;
  }

  .st-shell__frame {
    flex-direction: column;
  }

  .st-rail {
    display: none;
    position: static;
    flex: none;
    width: auto;
    max-height: none;
    border-right: 0;
    border-bottom: var(--st-border-hairline) solid var(--st-line);
  }

  .st-shell.is-navopen .st-rail {
    display: block;
  }

  .st-rail__inner {
    padding: 0;
  }

  .st-rail__group {
    padding: var(--st-space-3) var(--st-gutter-compact) var(--st-space-1);
  }

  /* Цель нажатия на телефоне не ниже 44 px — правило системы, и здесь оно
     важнее плотности: в лист тычут пальцем, а не целятся курсором. */
  .st-rail__link {
    min-height: var(--st-tap-target);
    padding: 0 var(--st-gutter-compact);
    border-left: 0;
    border-bottom: var(--st-border-hairline) solid var(--st-line-faint);
  }

  /* Текущий пункт помечен слева, как и в колонке: признак раздела не меняет
     сторону между широким и узким экраном. */
  .st-rail__link[aria-current='page'] {
    border-left: var(--st-border-edge) solid var(--st-seam);
  }
}

/* ---- Подвкладки разреза (вторичная навигация) --------------------------
   Восемь равновесных кнопок в ряд читались как действия, а не как навигация,
   и на узком экране рвали строку (аудит 15.09.2026). Подвкладки — вторичная
   навигация: текущий пункт помечен швом-подчёркиванием снизу, ряд
   прокручивается ВНУТРИ своей области, а не растягивает страницу. Та же
   разграфка, что у рельса, но признак текущего снизу — рельс и подвкладки
   не должны читаться одним ярусом. */
.st-subnav {
  background: var(--st-surface);
  border-bottom: var(--st-border-hairline) solid var(--st-line);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
}

.st-subnav__inner {
  display: flex;
  gap: 0;
  min-width: max-content;
}

/* Подвкладки живут внутри `.st-main`, где общее правило подчёркивает ссылки.
   Признак текущей подвкладки — шов снизу, а не подчёркивание, поэтому
   `text-decoration` снимается явно. Селектор той же силы, что общий
   (`.st-main a`), и стоит ниже по файлу — значит побеждает порядком. */
.st-subnav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--st-tap-target);
  padding: 0 var(--st-space-4);
  border-bottom: var(--st-border-edge) solid transparent;
  font-size: var(--st-text-lead);
  color: var(--st-ink-muted);
  text-decoration: none;
  white-space: nowrap;
}

.st-subnav a:hover {
  color: var(--st-ink);
  text-decoration: none;
}

.st-subnav a[aria-current='page'] {
  border-bottom-color: var(--st-seam);
  color: var(--st-ink);
  font-weight: var(--st-weight-medium);
}

/* ---- Полотно ----------------------------------------------------------- */

.st-main {
  flex: 1 1 auto;
  width: 100%;
  max-width: var(--st-content-max);
  margin: 0 auto;
  padding: var(--st-space-5) var(--st-gutter) var(--st-space-8);
}

/* Полотно ворот: заголовок экрана и панель формы стоят в одной колонке.
   Без этого заголовок «Вход» уезжал бы к левому краю полотна в 1440 px, а
   форма стояла бы посреди экрана — два разных выравнивания на странице, где
   всего два элемента. Ширина — колонка формы плюс поля полотна. */
.st-main--gate {
  max-width: calc(420px + 2 * var(--st-gutter));
}

.st-page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--st-space-3);
  margin-bottom: var(--st-space-5);
}

.st-title {
  font-family: var(--st-font-display);
  font-size: var(--st-text-title);
  font-weight: var(--st-weight-semibold);
  letter-spacing: var(--st-tracking-tight);
  line-height: var(--st-leading-tight);
  margin: 0;
}

/* ИМЯ ОБЪЕКТА И ЕСТЬ ЗАГОЛОВОК. Человек пришёл смотреть конкретную заявку, а
   не узнать, что это заявка, — поэтому в заголовке стоит идентификатор, и по
   правилу системы он набран моноширинным: ни одно имя, по которому человек
   принимает решение, не набрано пропорциональным. Разрядка сбрасывается —
   у моноширинного она своя. */
.st-title--mono {
  font-family: var(--st-font-mono);
  font-weight: var(--st-weight-medium);
  letter-spacing: 0;
  /* НОМЕР ЗАЯВКИ ПЕРЕНОСИТСЯ ПО ЛЮБОМУ ЗНАКУ, И БЕЗ ЭТОГО ОН УВОДИТ ВСЮ
     СТРАНИЦУ ВБОК. Замер 28.08.2026 на карточке разбора карантина при ширине
     390: документ 421 против окна 390 — ровно на вылет заголовка. Номер —
     одно «слово» из 28 знаков моноширинным по 1.375rem, переносить его
     обычным правилам не по чему, и страница едет целиком, а не только
     заголовок: горизонтальная прокрутка появляется у ТЕЛА, унося и шапку, и
     таблицы. Более семидесяти процентов сессий приходят с телефона.

     `anywhere`, а не `break-word`: второе переносит длинное слово, но не
     уменьшает вклад слова в минимальную ширину блока, и замер остаётся тем
     же. Разрыв в номере читается — знаки моноширинные и стоят в столбик. */
  overflow-wrap: anywhere;
}

.st-subtitle {
  color: var(--st-ink-muted);
  font-size: var(--st-text-lead);
  margin: 0;
  max-width: 68ch;
}

.st-stack {
  display: flex;
  flex-direction: column;
  gap: var(--st-space-5);
  margin-top: var(--st-space-5);
}

.st-cols {
  display: grid;
  gap: var(--st-space-5);
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  align-items: start;
}

/* КОЛОНКИ ДЛЯ ТЕКСТА, А НЕ ДЛЯ ПАР «ПОДПИСЬ — ЗНАЧЕНИЕ». Обычные `.st-cols`
   рассчитаны на панели со ставками и лимитами: там в строке короткое значение,
   и 320 px хватает. Объяснения «этого раздела ещё не бывает» — сплошной текст
   по несколько строк, и на 1440 их вставало ЧЕТЫРЕ в ряд по 332 px: мера
   строки падала примерно до тридцати знаков, текст рвался посреди слов, а
   низ ряда становился рваным, потому что объяснения разной длины.

   Нижняя граница здесь 30rem вместо 320 px: на широком экране это ровно две
   колонки, на планшете — одна, и мера строки не выходит за то, что читается
   без усилия. `min(100%, …)` обязателен — без него колонка не даёт себя сжать
   на узком экране и распирает страницу вбок. */
.st-cols--prose {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 30rem), 1fr));
}

/* ---- Панель ------------------------------------------------------------ */

.st-panel {
  background: var(--st-surface);
  border: var(--st-border-hairline) solid var(--st-line);
  border-radius: var(--st-radius-md);
}

.st-panel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--st-space-3);
  padding: var(--st-space-3) var(--st-space-4);
  border-bottom: var(--st-border-hairline) solid var(--st-line);
  background: var(--st-surface-sunken);
  border-radius: var(--st-radius-md) var(--st-radius-md) 0 0;
}

.st-panel__title {
  font-family: var(--st-font-display);
  font-size: var(--st-text-section);
  font-weight: var(--st-weight-semibold);
  letter-spacing: var(--st-tracking-tight);
  margin: 0;
}

/* `min-width: 0` обязателен: подпись — гибкий элемент шапки, и внутрь неё
   кладут содержимое, которое прокручивается внутри себя (легенда тонов на
   телефоне). Без сброса минимальной ширины такое содержимое распирает шапку,
   панель и страницу — а выезд вбок в этой системе запрещён. */
.st-panel__note {
  min-width: 0;
  font-size: var(--st-text-caption);
  color: var(--st-ink-faint);
}

/* Действия панели прижаты вправо. Классом, а не атрибутом style: правило
   одно на все панели, и правится оно тоже в одном месте. */
.st-panel__actions {
  margin-left: auto;
}

.st-panel__body {
  padding: var(--st-space-4);
}

.st-panel__body--flush {
  padding: 0;
}

.st-panel__foot {
  padding: var(--st-space-3) var(--st-space-4);
  border-top: var(--st-border-hairline) solid var(--st-line-faint);
  font-size: var(--st-text-caption);
  color: var(--st-ink-faint);
}

/* ---- Деньги ------------------------------------------------------------
   Каждая сумма носит на себе шов: волосяная вертикаль перед дробной частью.
   Копейки НЕ приглушены — в этом продукте копейка несущая: она уникальна и
   служит вторым признаком сопоставления платежа с заявкой.               */

.st-money {
  /* `relative` держит спрятанную запятую при своём числе. Без него она
     позиционируется относительно ближайшего предка с положением и на длинной
     странице уезжает наверх — невидимая, но растягивающая полотно. */
  position: relative;
  font-family: var(--st-font-mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  letter-spacing: -0.01em;
  /* Разряды отбиты неразрывным пробелом, а в моноширинном он шириной в целый
     знак. Без сжатия просвет между разрядами получается шире шва, и «1 946 204»
     читается как три отдельных числа, а шов перестаёт означать дробную часть.
     Проверено замером: до сжатия просвет разряда 9,4 px против 8 px у шва. */
  word-spacing: -0.28em;
}

/* РАЗДЕЛИТЕЛЬ ЕСТЬ, ПРОСТО ЕГО НЕ ВИДНО (29.08.2026).

   До этой правки запятой в разметке не было вовсе: её роль играла рамка
   `border-left` у копеек, а роль пробела перед знаком — отступ `margin-left`.
   Рамка и отступ в буфер не копируются. На экране читалось `25 000│17 ₽`,
   а в письмо уезжало `25 00017₽` — другая сумма, и ошибка тихая.

   Приём тот же, каким прячут текст «только для читающих с экрана»: знак
   вынесен из потока и обрезан до нуля. Он не занимает ширины, не сдвигает
   шов, не мешает выделению — и остаётся в текстовом слое, а копирует браузер
   именно его. `speak: never` не ставится: читающему с экрана запятая как раз
   нужна, иначе он произносит «двадцать пять тысяч семнадцать».

   Проверяется замером в браузере: выделить `.st-money` и сверить
   `getSelection().toString()` с `formatMoneyWithUnit`. */
.st-money__sep {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.st-money__kop {
  margin-left: 4px;
  padding-left: 5px;
  border-left: var(--st-border-hairline) solid var(--st-line-strong);
}

/* Единица несёт СВОЙ неразрывный пробел текстом, поэтому отступа ей больше не
   нужно. `word-spacing` возвращается к обычному: сжатие -0.28em заведено ради
   разрядов внутри числа, а здесь оно съело бы пробел перед знаком до волоска —
   и `₽` снова слипся бы с суммой, теперь уже на вид. */
.st-money__unit {
  word-spacing: normal;
  color: var(--st-ink-faint);
}

.st-money--figure {
  font-size: var(--st-text-figure);
  font-weight: var(--st-weight-medium);
  line-height: var(--st-leading-tight);
}

.st-money--muted {
  color: var(--st-ink-muted);
}

.st-money--strike {
  text-decoration: line-through;
  color: var(--st-ink-faint);
}

.st-money--alarm {
  color: var(--st-tone-alarm-ink);
}

.st-money--alarm .st-money__kop {
  border-left-color: var(--st-tone-alarm-edge);
}

.st-money--done {
  color: var(--st-tone-done-ink);
}

.st-money--done .st-money__kop {
  border-left-color: var(--st-tone-done-edge);
}

/* Машинные строки: идентификаторы, ключи, хэши, время. */
.st-mono {
  font-family: var(--st-font-mono);
  font-size: var(--st-text-caption);
  font-variant-numeric: tabular-nums;
  color: var(--st-ink-muted);
  white-space: nowrap;
}

.st-mono--ink {
  color: var(--st-ink);
}

.st-mono--wrap {
  white-space: normal;
  overflow-wrap: anywhere;
}

/* ---- Копирование нажатием ----------------------------------------------
   ИДЕНТИФИКАТОР САМ И ЕСТЬ КНОПКА. Значка «копировать» нет и не будет: в этой
   системе значков нет вовсе, ни рисованных, ни юникодных. Сорок значков в
   таблице на сорок строк были бы ярмаркой, а ширины у таблицы и без них нет.

   ПРИЗНАК НАЖИМАЕМОГО — ЛИНИЯ, как у ссылки: точками, а не сплошной, чтобы
   отличалось от перехода. Цветом признак не несётся — в тёмной теме цветовая
   разница садится первой, это записано правилом про ссылки выше.

   ПОДТВЕРЖДЕНИЕ ВСТАЁТ ПОВЕРХ, А НЕ ВМЕСТО. Слово «скопировано» длиннее
   короткого номера, и подстановка вместо строки двигала бы колонку на каждое
   нажатие. Поэтому оно `absolute` и не участвует в раскладке.                */

/* ---- Иконки: инлайн-SVG, без иконочного шрифта -------------------------
   Значок нарисован линиями, как и знак «Стыка»: fill нет, stroke — цветом
   строки (`currentColor`), поэтому значок живёт в обеих темах и наследует
   цвет соседнего текста. Иконочных шрифтов система не употребляет: глиф из
   шрифта не приезжает в закрытом контуре так же, как и веб-шрифт. Размер —
   под строку; клик-зона задаётся кнопкой `.st-icon-btn` (≥ 24 px). */
.st-icon {
  display: block;
  width: 18px;
  height: 18px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Кнопка-иконка (смена темы, копирование). Тихая: цвет, а не заливка. Фокус —
   общим правилом `.st-body :focus-visible` (кольцо швом). Клик-зона 28 px —
   выше требуемого порога в 24. */
.st-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  color: var(--st-ink-muted);
  background: transparent;
  border: 0;
  border-radius: var(--st-radius-sm);
  cursor: pointer;
  transition:
    color var(--st-duration-instant) var(--st-ease-out),
    background var(--st-duration-instant) var(--st-ease-out);
}

.st-icon-btn:hover {
  color: var(--st-ink);
  background: var(--st-surface-sunken);
}

/* Переключатель темы показывает значок ТЕКУЩЕЙ темы: солнце на светлой, луна
   на тёмной. Три блока — те же, что у палитры: умолчание и явная светлая,
   системная тёмная, явная тёмная (побеждает в обе стороны). */
.st-theme-toggle .st-icon--sun {
  display: block;
}

.st-theme-toggle .st-icon--moon {
  display: none;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .st-theme-toggle .st-icon--sun {
    display: none;
  }

  :root:not([data-theme='light']) .st-theme-toggle .st-icon--moon {
    display: block;
  }
}

:root[data-theme='dark'] .st-theme-toggle .st-icon--sun {
  display: none;
}

:root[data-theme='dark'] .st-theme-toggle .st-icon--moon {
  display: block;
}

:root[data-theme='light'] .st-theme-toggle .st-icon--sun {
  display: block;
}

:root[data-theme='light'] .st-theme-toggle .st-icon--moon {
  display: none;
}

.st-copy {
  display: inline;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-family: var(--st-font-mono);
  font-size: inherit;
  color: inherit;
  text-align: inherit;
  text-decoration: underline dotted var(--st-link-line);
  text-underline-offset: 0.2em;
  cursor: pointer;
}

.st-copy:hover {
  text-decoration-color: var(--st-seam);
}

/* Отдельная копия рядом со значением — теперь ИКОНКА, а не слово (правка
   владельца 15.09.2026: «текстом несерьёзно»). Клип-борд линиями, клик-зона
   24 px, подтверждение — тем же `::after`, что и у прочих копий. */
.st-copy--action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  color: var(--st-ink-faint);
  vertical-align: middle;
  text-decoration: none;
}

.st-copy--action .st-icon {
  width: 15px;
  height: 15px;
}

.st-copy--action:hover {
  color: var(--st-ink);
  text-decoration: none;
}

/* Подтверждение. Гаснет само — скрипт снимает признак через полторы секунды. */
.st-copy[data-copy-state='done'] {
  position: relative;
  text-decoration-color: var(--st-tone-done-edge);
}

.st-copy[data-copy-state='done']::after {
  content: attr(data-copied);
  position: absolute;
  left: 0;
  top: 100%;
  z-index: 1;
  margin-top: 2px;
  padding: 0 var(--st-space-2);
  border-left: var(--st-border-edge) solid var(--st-tone-done-edge);
  background: var(--st-surface);
  color: var(--st-tone-done-ink);
  font-family: var(--st-font-ui);
  font-size: var(--st-text-caption);
  white-space: nowrap;
  pointer-events: none;
}

/* Сумма и слово «скопировать» рядом. Слово переносится под сумму на узком, а
   не выталкивает её за край: это тот самый выезд вбок, который система себе
   запрещает. */
.st-copyable {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--st-space-2);
  min-width: 0;
}

/* ---- Состояние заявки --------------------------------------------------
   Вертикальный штрих тона и слово. Без точки и без овальной рамки: точка в
   рамке — язык «Цифрового Контура», и повторять его здесь нельзя.        */

/* ПОЧЕМУ `min-width: 0`, А НЕ ТОЛЬКО ЗАПРЕТ ПЕРЕНОСА.

   Замер аудита 29.08.2026: сводка кабинета уезжала вбок на 25 px при 390 px
   ширины, и виновник назван поимённо — `.st-state--act` («оплачено, идёт
   сверка») шириной 149 px с `white-space: nowrap` внутри карточки, у которой
   `min-width` по умолчанию равен `auto`. Плашка распирала карточку, карточка —
   страницу, и вбок уезжал ВЕСЬ документ. Правило системы «ничего не уезжает
   вбок ни на 390, ни на 1440» держится вёрсткой, и вот ровно то место, где
   вёрстка его не удержала.

   Запрет переноса остаётся: в ТАБЛИЦЕ состояние обязано стоять одной строкой,
   там прокрутка есть и она своя. Снимается он на телефоне, где прокрутки нет
   и быть не должно, — правило ниже, в мобильном разделе.                   */
.st-state {
  display: inline-flex;
  align-items: center;
  gap: var(--st-space-2);
  min-width: 0;
  white-space: nowrap;
  color: var(--st-ink);
}

.st-state::before {
  content: '';
  width: var(--st-border-edge);
  height: 1.05em;
  flex: none;
  align-self: flex-start;
  /* Штрих встаёт по верхней строке, а не по середине: при переносе слова на
     две строки центрирование увело бы его в межстрочье, и тон перестал бы
     читаться как отметка строки. */
  margin-top: 0.15em;
  background: var(--st-line-strong);
}

.st-state--wait::before {
  background: var(--st-tone-wait-edge);
}

.st-state--wait {
  color: var(--st-tone-wait-ink);
}

.st-state--closed::before {
  background: var(--st-tone-closed-edge);
}

.st-state--closed {
  color: var(--st-tone-closed-ink);
}

.st-state--move::before {
  background: var(--st-tone-move-edge);
}

.st-state--move {
  color: var(--st-tone-move-ink);
}

.st-state--act::before {
  background: var(--st-tone-act-edge);
}

.st-state--act {
  color: var(--st-tone-act-ink);
}

.st-state--alarm::before {
  background: var(--st-tone-alarm-edge);
}

.st-state--alarm {
  color: var(--st-tone-alarm-ink);
  font-weight: var(--st-weight-medium);
}

.st-state--done::before {
  background: var(--st-tone-done-edge);
}

.st-state--done {
  color: var(--st-tone-done-ink);
}

/* Легенда тонов. Шесть цветов без расшифровки читает каждый по-своему. */
.st-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--st-space-2) var(--st-space-4);
  font-size: var(--st-text-caption);
  color: var(--st-ink-muted);
}

/* ---- Таблица как инструмент --------------------------------------------
   СОРТИРОВКА — ССЫЛКАМИ, А НЕ СКРИПТОМ. Обе поверхности собираются на
   сервере, отбор уже едет строкой запроса, и порядок — такой же её параметр.
   Ссылка работает без единой строки скрипта, открывается в новой вкладке
   средним щелчком, переживает выключенный JavaScript и — главное — её можно
   переслать коллеге вместе с порядком, как уже переслают отбор.

   НАПРАВЛЕНИЕ ПОКАЗАНО ЛИНИЕЙ, А НЕ СТРЕЛКОЙ. Стрелок в этой системе нет:
   значков в ней нет вовсе, ни рисованных, ни юникодных. Отсортированная
   колонка несёт линию под заголовком — снизу при возрастании, сверху при
   убывании. Направление читается положением линии, а не её формой, и это
   работает одинаково в обеих темах.                                        */

.st-sort {
  display: inline-block;
  color: inherit;
  font: inherit;
  text-decoration: underline dotted var(--st-link-line);
  text-underline-offset: 0.25em;
}

.st-sort:hover {
  text-decoration-color: var(--st-seam);
}

.st-th--asc .st-sort,
.st-th--desc .st-sort {
  text-decoration: none;
  color: var(--st-ink);
  font-weight: var(--st-weight-medium);
}

.st-th--asc .st-sort {
  box-shadow: inset 0 -2px 0 0 var(--st-seam);
}

.st-th--desc .st-sort {
  box-shadow: inset 0 2px 0 0 var(--st-seam);
}

/* ИТОГ ПОД ТАБЛИЦЕЙ, А НЕ НАД НЕЙ. Он относится к тому, что показано, и
   читается после — как сумма столбца, а не как заголовок. Разделён от строк
   линией в два волоса: обычная разграфка в этой системе вертикальная, и
   горизонтальная линия здесь означает ровно одно — «дальше не данные». */
.st-table tfoot td {
  padding: var(--st-space-3) var(--st-space-3);
  border-top: var(--st-border-edge) solid var(--st-line-strong);
  font-weight: var(--st-weight-medium);
}

.st-table tfoot .st-total__label {
  color: var(--st-ink-muted);
  font-weight: var(--st-weight-regular);
}

/* СТРАНИЦЫ. Номера ссылками, а не «Страница 1 из 4» без возможности прыгнуть:
   оператор, разбирающий очередь второй раз за день, помнит, что нужное было
   на третьей. Текущая страница — не ссылка: ссылка на саму себя обманывает. */
.st-pages {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--st-space-2);
  font-size: var(--st-text-caption);
}

.st-pages__now {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--st-space-6);
  padding: 0 var(--st-space-2);
  border-bottom: var(--st-border-edge) solid var(--st-seam);
  font-family: var(--st-font-mono);
  color: var(--st-ink);
  font-weight: var(--st-weight-medium);
}

.st-pages__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--st-space-6);
  padding: 0 var(--st-space-2);
  font-family: var(--st-font-mono);
}

.st-pages__gap {
  color: var(--st-ink-faint);
}

.st-pages__count {
  margin-left: auto;
  color: var(--st-ink-faint);
}

@media (max-width: 640px) {
  .st-pages__link,
  .st-pages__now {
    min-height: var(--st-tap-target);
  }

  .st-pages__count {
    margin-left: 0;
    flex-basis: 100%;
  }
}

/* ---- Реестр ------------------------------------------------------------ */

.st-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--st-text-body);
  font-variant-numeric: tabular-nums;
}

/* ТАБЛИЦА В ПРОКРУЧИВАЕМОЙ ОБЛАСТИ НЕ СЖИМАЕТСЯ НИЖЕ СВОЕЙ ЕСТЕСТВЕННОЙ ШИРИНЫ
   (18.09.2026).

   Ячейки реестра набраны `white-space: nowrap` — сжиматься им нечем, и при
   нехватке места содержимое НЕ переносилось, а вылезало из ячейки на соседнюю.
   Замерено на ленте заявок в 1440 после того, как колонка разделов забрала
   240 px: столбец «Заявка» получил 204 px вместо 268 нужных, и пометка
   «ПЕСОЧНИЦА» легла поверх имени партнёра — на 21 px. Страница при этом вбок
   не уезжала, то есть замер выезда этого не ловил и не мог: дефект жил ВНУТРИ
   таблицы.

   Теперь таблица занимает столько, сколько ей нужно, а лишнее прокручивается
   внутри своей области — ровно то, что предписывает раздел 7 DESIGN.md.
   Прокрутка с признаком: полоса у `.st-scroll-x` видима. */
.st-scroll-x .st-table {
  min-width: max-content;
}

.st-table th,
.st-table td {
  text-align: left;
  padding: 0 var(--st-space-3);
  height: var(--st-row-height);
  border-right: var(--st-border-hairline) solid var(--st-line-faint);
  white-space: nowrap;
}

.st-table th:last-child,
.st-table td:last-child {
  border-right: 0;
}

.st-table thead th {
  position: sticky;
  top: 0;
  z-index: var(--st-z-sticky);
  background: var(--st-surface-sunken);
  border-bottom: var(--st-border-hairline) solid var(--st-line-strong);
  border-right-color: var(--st-line);
  font-size: var(--st-text-micro);
  font-weight: var(--st-weight-semibold);
  color: var(--st-ink-muted);
  height: auto;
  padding-top: var(--st-space-2);
  padding-bottom: var(--st-space-2);
}

/* Чередование плоскости вместо горизонтальных линеек: строку ведёт глаз, а
   не линия. Разграфка в этой системе вертикальная. */
.st-table tbody tr:nth-child(even) {
  background: var(--st-surface-sunken);
}

.st-table tbody tr:hover {
  background: var(--st-seam-wash);
}

.st-table td.st-num,
.st-table th.st-num {
  text-align: right;
}

/* Строка, требующая человека: штрих тона у левого края. */
.st-table tbody tr.st-row--alarm td:first-child {
  box-shadow: inset var(--st-border-edge) 0 0 0 var(--st-tone-alarm-edge);
}

.st-table tbody tr.st-row--act td:first-child {
  box-shadow: inset var(--st-border-edge) 0 0 0 var(--st-tone-act-edge);
}

.st-table tbody tr.st-row--muted {
  color: var(--st-ink-faint);
}

.st-table--dense th,
.st-table--dense td {
  height: var(--st-row-height-dense);
  padding-left: var(--st-space-2);
  padding-right: var(--st-space-2);
}

/* Закреплённая справа последняя колонка (действия строки): кнопки видны сразу,
   без горизонтальной прокрутки широкой таблицы. Когда таблица помещается в
   свою обёртку, `right: 0` ничего не сдвигает — правило безвредно. Фон
   непрозрачный и повторяет чередование строк, иначе прокручиваемые ячейки
   просвечивали бы сквозь закреплённую колонку. Ниже 640 px таблицы нет —
   там карточки, — поэтому фонов для узкого вида не требуется. */
.st-table--pin-last th:last-child,
.st-table--pin-last td:last-child {
  position: sticky;
  right: 0;
  background: var(--st-surface);
  box-shadow: inset var(--st-border-hairline) 0 0 0 var(--st-line-faint);
}

.st-table--pin-last tbody tr:nth-child(even) td:last-child {
  background: var(--st-surface-sunken);
}

.st-table--pin-last tbody tr:hover td:last-child {
  background: var(--st-seam-wash);
}

/* Угол «шапка × закреплённая колонка» остаётся выше и вертикальной, и
   горизонтальной прокрутки. */
.st-table--pin-last thead th:last-child {
  z-index: calc(var(--st-z-sticky) + 1);
  background: var(--st-surface-sunken);
}

/* Своего правила у ссылок таблицы нет: оно было вторым описанием той же
   ссылки и отставало от общего — подчёркивание держало `line-strong`
   (1,83:1 на тёмной), пока карточки телефона вообще не были покрашены.
   Ссылка описана один раз, в разделе «Ссылки». */

/* ---- Шов сверки — подпись системы --------------------------------------
   Две колонки сумм и шов между ними. Сошлось — шов сомкнут сплошной линией.
   Не сошлось — шов расходится, и в разрыв встаёт расхождение. Это
   единственное сильное движение системы: оно означает ровно то, что
   показывает. Движений в системе три (шов, пульс скелета, отклик на
   наведение), и каждое сообщает состояние — правило в DESIGN.md, раздел 10. */

.st-seam {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: stretch;
  gap: var(--st-space-4);
  padding: var(--st-space-4);
}

.st-seam__side {
  display: flex;
  flex-direction: column;
  gap: var(--st-space-1);
  min-width: 0;
}

.st-seam__side--right {
  align-items: flex-end;
  text-align: right;
}

.st-seam__label {
  font-size: var(--st-text-micro);
  font-weight: var(--st-weight-semibold);
  color: var(--st-ink-faint);
}

.st-seam__source {
  font-size: var(--st-text-caption);
  color: var(--st-ink-muted);
}

.st-seam__rule {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 96px;
}

.st-seam__stub {
  flex: 1 1 auto;
  width: var(--st-border-seam);
  min-height: var(--st-space-3);
  background: var(--st-seam);
}

.st-seam__gap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  overflow: hidden;
  height: 0;
  transition:
    height var(--st-duration-seam) var(--st-ease-out),
    padding var(--st-duration-seam) var(--st-ease-out);
}

.st-seam--match .st-seam__gap {
  height: 0;
  padding: 0;
}

.st-seam--break .st-seam__gap,
.st-seam--unknown .st-seam__gap {
  height: auto;
  padding: var(--st-space-2) 0;
}

/* Разошедшийся шов красится цветом расхождения, а не гаснет до серого.
   Серые стойки на тёмной теме практически не видны (замерено: #4c4840 на
   #201e1a — контраст 1,6:1), и разрыв читается как пустое место, а не как
   разошедшийся шов. Смысл при этом не теряется: сомкнутый шов — цвета
   акцента, разошедшийся — цвета расхождения. */
.st-seam--break .st-seam__stub {
  background: var(--st-tone-alarm-edge);
}

.st-seam--unknown .st-seam__stub {
  background: var(--st-line-strong);
}

.st-seam__verdict {
  font-size: var(--st-text-micro);
  font-weight: var(--st-weight-semibold);
  letter-spacing: var(--st-tracking-label);
  text-transform: uppercase;
  white-space: nowrap;
  padding: 2px var(--st-space-2);
  border-radius: var(--st-radius-sm);
}

.st-seam--match .st-seam__verdict {
  color: var(--st-tone-done-ink);
  background: var(--st-tone-done-wash);
}

.st-seam--break .st-seam__verdict {
  color: var(--st-tone-alarm-ink);
  background: var(--st-tone-alarm-wash);
}

.st-seam--unknown .st-seam__verdict {
  color: var(--st-ink-faint);
  background: var(--st-surface-sunken);
}

/* Метка «сошлось» сидит верхом на сомкнутом шве. */
.st-seam--match .st-seam__mark {
  position: relative;
  margin: var(--st-space-2) 0;
  background: var(--st-surface);
  z-index: var(--st-z-base);
}

@media (max-width: 640px) {
  .st-seam {
    grid-template-columns: 1fr;
    gap: var(--st-space-2);
  }

  .st-seam__side--right {
    align-items: flex-start;
    text-align: left;
  }

  .st-seam__rule {
    flex-direction: row;
    min-width: 0;
    width: 100%;
  }

  .st-seam__stub {
    width: auto;
    height: var(--st-border-seam);
    min-width: var(--st-space-3);
    min-height: 0;
  }

  .st-seam__gap {
    flex-direction: row;
    height: auto;
    width: 0;
    transition: width var(--st-duration-seam) var(--st-ease-out);
  }

  .st-seam--break .st-seam__gap,
  .st-seam--unknown .st-seam__gap {
    width: auto;
    padding: 0 var(--st-space-2);
  }

  .st-seam--match .st-seam__mark {
    margin: 0 var(--st-space-2);
  }
}

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

.st-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  border: var(--st-border-hairline) solid var(--st-line);
  border-radius: var(--st-radius-md);
  background: var(--st-surface);
  overflow: hidden;
}

.st-figure {
  padding: var(--st-space-4);
  border-right: var(--st-border-hairline) solid var(--st-line-faint);
  display: flex;
  flex-direction: column;
  gap: var(--st-space-1);
  min-width: 0;
}

.st-figure:last-child {
  border-right: 0;
}

.st-figure__label {
  font-size: var(--st-text-micro);
  font-weight: var(--st-weight-semibold);
  color: var(--st-ink-faint);
}

.st-figure__note {
  font-size: var(--st-text-caption);
  color: var(--st-ink-muted);
}

/* Плитки, положенные в панель вплотную к рамке, своей рамки не заводят:
   иначе на экране появляется рамка в рамке, а панель для того и взята, чтобы
   период стоял в её шапке ОДИН раз, а не подписью под каждой плиткой. */
.st-panel__body--flush > .st-figures {
  border: 0;
  border-radius: 0;
}

/* ---- Пары «подпись — значение» ----------------------------------------- */

.st-facts {
  display: grid;
  grid-template-columns: minmax(140px, max-content) 1fr;
}

.st-fact__key {
  padding: var(--st-space-2) var(--st-space-4) var(--st-space-2) 0;
  font-size: var(--st-text-caption);
  color: var(--st-ink-faint);
  border-right: var(--st-border-hairline) solid var(--st-line-faint);
}

.st-fact__value {
  padding: var(--st-space-2) 0 var(--st-space-2) var(--st-space-4);
  min-width: 0;
  overflow-wrap: anywhere;
}

/* ---- Журнал состояний --------------------------------------------------
   Неизменяемый след: время, состояние, источник события. Держится вертикалью
   слева — это то же самое ребро, что у строки реестра.                    */

.st-journal {
  list-style: none;
  margin: 0;
  padding: 0 0 0 var(--st-space-4);
  border-left: var(--st-border-seam) solid var(--st-line);
  display: flex;
  flex-direction: column;
  gap: var(--st-space-3);
}

.st-journal__item {
  position: relative;
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: var(--st-space-1) var(--st-space-3);
  align-items: baseline;
}

.st-journal__item::before {
  content: '';
  position: absolute;
  left: calc(-1 * var(--st-space-4) - var(--st-border-seam));
  top: 0.45em;
  width: var(--st-space-3);
  height: var(--st-border-hairline);
  background: var(--st-line-strong);
}

.st-journal__item--now::before {
  height: var(--st-border-seam);
  background: var(--st-seam);
}

.st-journal__source {
  grid-column: 2;
  font-size: var(--st-text-caption);
  color: var(--st-ink-faint);
}

/* ---- Управление -------------------------------------------------------- */

.st-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--st-space-2);
  align-items: center;
}

.st-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--st-space-2);
  min-height: var(--st-control-height);
  padding: 0 var(--st-space-4);
  border: var(--st-border-hairline) solid var(--st-line-strong);
  border-radius: var(--st-radius-md);
  background: var(--st-surface);
  color: var(--st-ink);
  font: inherit;
  font-size: var(--st-text-lead);
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
  transition:
    background var(--st-duration-instant) var(--st-ease-out),
    border-color var(--st-duration-instant) var(--st-ease-out);
}

.st-btn:hover {
  background: var(--st-surface-sunken);
  border-color: var(--st-ink-faint);
}

/*
 * Действие, которое на самом деле переход, набирается ссылкой в оболочке
 * кнопки: «Обновить», «Показать все», «К реестру». Правило `.st-main a` дало
 * бы ей подчёркивание и цвет ссылки — то есть кнопку с подчёркнутой надписью.
 * Подчёркивание снимается тем же способом, что с рельса разделов и со знака,
 * а цвет берётся кнопочный. Признак «это переход» никуда не девается: рамка,
 * курсор и адрес в строке состояния остаются.
 */
a.st-btn,
a.st-btn:visited,
a.st-btn:hover {
  text-decoration: none;
  color: var(--st-ink);
}

/*
 * Модификаторы перечислены поимённо и с тем же весом селектора, что и базовое
 * правило выше. Иначе `a.st-btn` (класс + элемент) перебил бы по силе
 * `.st-btn--primary` (один класс), и главное действие набралось бы чернилами
 * по чернильной заливке — то есть стало бы нечитаемым. Ловится это только
 * глазами и только на той единственной кнопке, которая оказалась ссылкой.
 */
a.st-btn--primary,
a.st-btn--primary:visited,
a.st-btn--primary:hover {
  color: var(--st-action-ink);
}

a.st-btn--quiet,
a.st-btn--quiet:visited {
  color: var(--st-ink-muted);
}

a.st-btn--quiet:hover {
  color: var(--st-ink);
}

a.st-btn--danger,
a.st-btn--danger:visited,
a.st-btn--danger:hover {
  color: var(--st-danger);
}

/* Главное действие — чернильная заливка, а не цветная. Цвет остаётся швом. */
.st-btn--primary {
  background: var(--st-action);
  border-color: var(--st-action);
  color: var(--st-action-ink);
  font-weight: var(--st-weight-medium);
}

.st-btn--primary:hover {
  background: var(--st-action-hover);
  border-color: var(--st-action-hover);
}

.st-btn--quiet {
  border-color: transparent;
  background: transparent;
  color: var(--st-ink-muted);
}

.st-btn--quiet:hover {
  background: var(--st-surface-sunken);
  color: var(--st-ink);
}

.st-btn--danger {
  border-color: var(--st-danger);
  color: var(--st-danger);
}

.st-btn--danger:hover {
  background: var(--st-danger-wash);
}

.st-btn[disabled],
.st-btn[aria-disabled='true'] {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ЦЕЛЬ НАЖАТИЯ НА ТЕЛЕФОНЕ НЕ НИЖЕ 44 px — ПРАВИЛО СИСТЕМЫ, А НЕ ПОЖЕЛАНИЕ.

   Аудит 29.08.2026 замерил, чем оно исполнялось: пресеты периода 30 px,
   ссылки-номера в таблицах 17 px при собственном токене `tap-target` в 44 px.
   Правило было записано и не держалось ничем — ни стилями, ни проверкой.

   Держится оно теперь тремя правилами подряд: кнопки, фильтры (это и есть
   пресеты периода) и ссылки внутри строк списков. Ссылка получает высоту
   `inline-flex`, а не отступами: отступы у строчного элемента не увеличивают
   его высоту, и цель осталась бы прежней при выросшей на вид кнопке. */
@media (max-width: 640px) {
  .st-btn {
    min-height: var(--st-tap-target);
  }

  /* Номер заявки в таблице и в карточке — 17 px высотой при пороге 44.
     Промахнуться по нему пальцем легче, чем попасть. */
  .st-table a,
  .st-table .st-copy,
  .st-card a,
  .st-card .st-copy,
  .st-facts a,
  .st-facts .st-copy,
  .st-journal a {
    display: inline-flex;
    align-items: center;
    min-height: var(--st-tap-target);
  }

  /* СОСТОЯНИЕ ПЕРЕНОСИТСЯ. На телефоне горизонтальной прокрутки нет и быть не
     должно: это не адаптация, а способ спрятать половину данных за краем.
     Значит «оплачено, идёт сверка» обязано переноситься, а не распирать
     карточку — тот самый выезд на 25 px. */
  .st-state {
    white-space: normal;
  }
}

/* Фильтры. Тот же приём, что в рельсе: вертикаль слева, не заливка. */
/* Фильтры прокручиваются, а не обрезаются: на 390 четыре фильтра не влезают,
   и `overflow: hidden` ради скругления углов прятал последний за краем —
   молча, без полосы прокрутки и без единого признака, что он там есть. */
/* РЯД ПЕРЕНОСИТСЯ, А НЕ ПРЯЧЕТ ХВОСТ ЗА КРАЕМ (29.08.2026).

   Прокрутка сама по себе честна, но у неё не было ПРИЗНАКА: аудит замерил ряд
   из одиннадцати состояний в ленте заявок, у которого «возврат подтверждён»
   уходил за правый край на 1440 px — человек не знает, что справа что-то есть,
   и не тянет. Гаснущий край решил бы это одним правилом, но градиентов в этой
   системе нет ни одного, включая знак, — и заводить первый ради подсказки о
   прокрутке значит менять систему ради частности.

   Перенос решает то же самое и сильнее: спрятанного не остаётся вовсе. Ряд
   встаёт в две строки, вертикали-разделители продолжают читаться как раньше.
   `overflow-x: auto` оставлен подпоркой на случай одного неразрывного фильтра
   шире полосы — такой не перенесётся, и прокрутка окажется единственным, что
   его покажет. */
.st-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  border: var(--st-border-hairline) solid var(--st-line);
  border-radius: var(--st-radius-md);
  background: var(--st-surface);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
}

.st-filter {
  display: inline-flex;
  align-items: center;
  gap: var(--st-space-2);
  min-height: var(--st-control-height);
  padding: 0 var(--st-space-3);
  border: 0;
  border-left: var(--st-border-seam) solid transparent;
  background: transparent;
  color: var(--st-ink-muted);
  font: inherit;
  font-size: var(--st-text-caption);
  cursor: pointer;
  white-space: nowrap;
}

.st-filter:hover {
  background: var(--st-surface-sunken);
  color: var(--st-ink);
}

.st-filter[aria-pressed='true'] {
  border-left-color: var(--st-seam);
  background: var(--st-seam-wash);
  color: var(--st-ink);
  font-weight: var(--st-weight-medium);
}

.st-filter__count {
  font-family: var(--st-font-mono);
  color: var(--st-ink-faint);
}

/* ЦЕЛЬ НАЖАТИЯ У ПРЕСЕТОВ ПЕРИОДА — 44 px, И ПРАВИЛО СТОИТ ЗДЕСЬ, А НЕ В
   БЛОКЕ КНОПОК ВЫШЕ.

   Замерено браузером 29.08.2026 дважды. Первый замер аудита: 30 px при пороге
   44. Первая починка ушла в мобильный блок рядом с `.st-btn` — и НЕ СРАБОТАЛА:
   тот блок стоит в файле РАНЬШЕ базового правила `.st-filter`, вес у них
   одинаковый, и побеждает то, что ниже. Повторный замер показал те же 30 px.

   Урок дороже правила: перекрытие в каскаде проверяется замером в браузере, а
   не чтением стилей. По коду обе правки выглядят одинаково верными. */
@media (max-width: 640px) {
  .st-filter {
    min-height: var(--st-tap-target);
  }
}

/* Панель управления реестром: фильтры и поиск над строками. Отдельным
   классом, а не атрибутом style в разметке: на телефоне у неё свои поля, и
   задать их из разметки нечем — медиазапроса там нет. */
.st-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--st-space-3);
  padding: var(--st-space-3) var(--st-space-4);
}

.st-toolbar__search {
  flex: 1 1 240px;
}

/* ФОРМА ФИЛЬТРОВ ОБЯЗАНА УМЕТЬ СЖИМАТЬСЯ, ИНАЧЕ ПРОКРУТКА ВНУТРИ НЕЁ НЕ
   ВКЛЮЧАЕТСЯ. Поймано замером 25.08.2026: на 390 px реестр уезжал вбок на
   74 px, на 375 — на 89. У `.st-filters` прокрутка по горизонтали стояла и
   раньше, но работать ей было негде: фильтры обёрнуты формой (они стали
   отправляться на сервер), форма — элемент гибкой раскладки, а у такого
   элемента `min-width` по умолчанию равен `auto` и не даёт ему стать уже
   своего содержимого. Форма распирала панель, панель — страницу, и вбок
   уезжал ВЕСЬ документ: рельс разделов и легенда тонов при этом тоже
   вылезали за край, хотя со своей прокруткой у них всё было в порядке —
   они мерили ширину уже разъехавшегося документа.

   Правило поэтому про сжатие, а не про прокрутку: прокрутка уже описана там,
   где ей место. Глазами это не находится — на снимке страница выглядит
   обычной, пока не потянешь её вбок. */
.st-toolbar__filters {
  min-width: 0;
  flex: 0 1 auto;
}

.st-field {
  display: flex;
  flex-direction: column;
  gap: var(--st-space-1);
  min-width: 0;
}

.st-field__label {
  font-size: var(--st-text-micro);
  font-weight: var(--st-weight-semibold);
  color: var(--st-ink-faint);
}

.st-input {
  min-height: var(--st-control-height);
  padding: 0 var(--st-space-3);
  border: var(--st-border-hairline) solid var(--st-line-strong);
  border-radius: var(--st-radius-md);
  background: var(--st-surface);
  color: var(--st-ink);
  font: inherit;
  font-size: var(--st-text-lead);
}

.st-input::placeholder {
  color: var(--st-ink-faint);
}

.st-input--mono {
  font-family: var(--st-font-mono);
  font-size: var(--st-text-body);
}

/* МНОГОСТРОЧНОЕ ПОЛЕ — ТОТ ЖЕ `.st-input` ПЛЮС ТРИ ПРАВИЛА, а не второй набор
   рамок и отступов. Появилось 29.08.2026 вместе с отклонением возврата: причина
   отказа уходит партнёру дословно и в одну строку не помещается.

   `min-height` СНИМАЕТСЯ. `.st-input` держит высоту одного элемента управления;
   унаследовав её, поле в три строки распирало бы себя изнутри и обрезало текст
   на телефоне.

   `resize: vertical`, А НЕ `both`. Растягивание вбок ломает колонку панели, и
   на 390 px документ уезжает за край — ровно тот дефект, который однажды уже
   ловили замером на фильтрах реестра. Вертикально — можно и нужно: причину
   отказа пишут разной длины.

   `max-width: 100%` ОБЯЗАТЕЛЕН: у `textarea` собственная ширина по атрибуту
   `cols`, и без ограничения она не подчиняется ширине колонки. */
.st-textarea {
  min-height: 0;
  padding: var(--st-space-2) var(--st-space-3);
  max-width: 100%;
  resize: vertical;
  line-height: var(--st-leading-normal);
}

/* ---- Форма ------------------------------------------------------------- */

.st-form {
  display: flex;
  flex-direction: column;
  gap: var(--st-space-4);
}

/* Кнопка формы во всю ширину колонки. Не мода: на телефоне это единственная
   цель нажатия на экране, и промахнуться по ней нельзя. */
.st-form__act {
  display: flex;
}

.st-form__act .st-btn {
  width: 100%;
  justify-content: center;
}

/* ФОРМА В МЕРУ СТРОКИ, А НЕ ВО ВСЮ ШИРИНУ ПАНЕЛИ.

   Появилось 29.08.2026 вместе с решением по возврату; замерено на 1440 px.
   Панель на широком экране — это 1400 px, и форма, растянутая на всю её ширину,
   даёт две настоящие беды сразу:

     • подсказку под полем длиной в двести знаков в одну строку. Мера строки, за
       которой глаз теряет начало следующей, давно известна и равна примерно
       70–80 знакам. А подсказка тут — та самая, что объясняет, почему сумму
       набирают руками;
     • поле на девять знаков и кнопку шириной в полтора метра. Правило
       `.st-form__act .st-btn { width: 100% }` заведено ради ТЕЛЕФОНА, где
       кнопка — единственная цель нажатия; на широком экране оно превращает
       самое опасное действие системы в самую большую мишень.

   Ограничение ставится ФОРМЕ, а не кнопке: кнопка по-прежнему во всю ширину
   своей колонки, просто колонка теперь разумной меры. На телефоне 44rem больше
   ширины экрана, значит там не меняется ничего. */
.st-form--measure {
  max-width: 44rem;
}

/* ОЖИДАНИЕ ОТВЕТА ПОСЛЕ ОТПРАВКИ ФОРМЫ (25.09.2026).

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

   Нажатая кнопка гаснет и меняет подпись (это делает скрипт кабинета,
   подпись он берёт из разметки). Под ней — строка «ждём до N секунд» и шов,
   который заполняется за ту же выдержку, что у сервера. Шов, а не крутилка:
   длительность ИЗВЕСТНА, и честнее показать, сколько её осталось, чем
   вращение, которое одинаково выглядит на первой секунде и на девятой. Цвет —
   шов системы, единственный цвет, который ей положен на действии.
   Выдержку разметка ставит на шов свойством `animation-duration` из того же
   числа, что у сервера; десять секунд здесь — запасное значение.

   При `prefers-reduced-motion` шов не ползёт (общее правило вверху файла
   доводит анимацию до конца за миллисекунду): стоит полным, а время
   называет строка. */
.st-btn[aria-busy='true'] {
  cursor: progress;
}

.st-wait {
  display: flex;
  flex-direction: column;
  gap: var(--st-space-2);
  margin: 0;
  font-size: var(--st-text-caption);
  color: var(--st-ink-muted);
}

.st-wait[hidden] {
  display: none;
}

.st-wait__track {
  display: block;
  height: 2px;
  overflow: hidden;
  border-radius: var(--st-radius-sm);
  background: var(--st-line-faint);
}

.st-wait__bar {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--st-seam);
  transform: scaleX(0);
  transform-origin: left center;
}

.st-wait:not([hidden]) .st-wait__bar {
  animation: st-wait-fill 10s linear forwards;
}

@keyframes st-wait-fill {
  to {
    transform: scaleX(1);
  }
}

.st-form__rules {
  display: flex;
  flex-direction: column;
  gap: var(--st-space-1);
}

/* Требования к паролю стоят ДО отправки, а не после отказа: форма, которая
   принимает пароль и отвечает «слишком короткий», заставляет придумывать
   вслепую второй раз. Список без маркеров — вертикальным штрихом у левого
   края: тем же приёмом, каким в этой системе подаётся всё перечислимое.
   Точек и значков в ней нет. */
.st-rules {
  margin: 0;
  padding: 0 0 0 var(--st-space-3);
  list-style: none;
  border-left: var(--st-border-hairline) solid var(--st-line);
  display: flex;
  flex-direction: column;
  gap: var(--st-space-1);
  font-size: var(--st-text-caption);
  color: var(--st-ink-muted);
}

/* ---- Полоса контекста: ЧЬИ это данные ----------------------------------

   ПОЯВИЛАСЬ ВМЕСТЕ С АДМИНКОЙ (25.08.2026) И ПОЯВИЛАСЬ ПО СЛУЧАЮ. Владелец
   открыл стенд, попал в кабинет партнёра — и не понял, чьи суммы перед ним.
   В кабинете этой полосы нет и не нужно: там партнёр всегда один и он же
   смотрящий. В админке партнёр меняется переходом по ссылке, и вопрос «чьи
   это числа» становится тем единственным, на который экран обязан отвечать,
   не дожидаясь, пока его зададут.

   ЖИВЁТ ВНУТРИ ШАПКИ, А НЕ НАД СОДЕРЖИМЫМ, И ЭТО РЕШЕНИЕ, А НЕ УДОБСТВО
   ВЁРСТКИ. Требование — «полоса не прокручивается вместе с таблицей»;
   выполнить его отдельным липким блоком в содержимом можно только задав ему
   смещение, равное высоте шапки, — а шапка липкая, многострочная и на
   телефоне переносится, то есть её высота не выражается ни одним значением.
   Расхождение на несколько пикселей даёт либо щель, сквозь которую при
   прокрутке видны строки реестра, либо полосу, заехавшую под шапку. Внутри
   шапки вопрос снимается: полоса стоит там же, где рельс, и держится тем же
   `position: sticky`, что и он.

   ШОВ ЛИНИЕЙ У ЛЕВОГО КРАЯ И НИКОГДА ЗАЛИВКОЙ — правило системы, тот же
   приём, которым помечены текущий раздел рельса, тон состояния и край
   карточки. Плоскость взята утопленная: полоса обязана оставаться
   непрозрачной — сквозь прозрачную при прокрутке просвечивают строки
   реестра, и подпись становится нечитаемой ровно в тот момент, когда она
   нужна. */
/* ПЕРЕЕХАЛА ИЗ ШАПКИ В КОЛОНКУ СОДЕРЖИМОГО 18.09.2026. Требование к ней не
   менялось — «не прокручивается вместе с таблицей», — а вот причина жить
   внутри шапки отпала. Раньше высота липкой многострочной шапки не выражалась
   ни одним значением, и отдельный липкий блок дал бы щель или наезд; теперь
   шапка одна строка назначенной высоты (`--st-bar-height`), и полоса липнет
   под неё тем же числом. Взамен она встала там, где ей место: над содержимым
   своей колонки, а не над рельсом, к которому не относится. */
.st-context {
  position: sticky;
  top: var(--st-bar-height);
  z-index: var(--st-z-sticky);
  padding: var(--st-space-2) var(--st-gutter);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--st-space-2) var(--st-space-4);
  background: var(--st-surface-sunken);
  border-bottom: var(--st-border-hairline) solid var(--st-line);
  font-size: var(--st-text-caption);
  color: var(--st-ink-muted);
  min-width: 0;
}

/* НА УЗКОМ ЭКРАНЕ ЛИПКОСТЬ СНЯТА: шапка там переносится на две строки, её
   высота перестаёт равняться `--st-bar-height`, и полоса, смещённая на это
   число, дала бы наезд на шапку.

   ПРАВИЛО СТОИТ ЗДЕСЬ, А НЕ В ОБЩЕМ БЛОКЕ УЗКОГО ЭКРАНА ВЫШЕ ПО ФАЙЛУ, и это
   не вкусовщина. Вес селекторов одинаковый, значит побеждает тот, что ниже;
   написанное выше базового правила не сработало бы вовсе — и не сработало,
   проверено прогоном 18.09.2026. Урок DESIGN.md, раздел 7: перекрытие в
   каскаде проверяется замером, а не чтением стилей. */
@media (max-width: 1023px) {
  .st-context {
    position: static;
  }
}

/* Шов — отдельной полосой у левого края полотна, а не рамкой вокруг: полоса
   тянется во всю ширину шапки, и рамка вокруг неё была бы рамкой вокруг
   экрана. */
.st-context::before {
  content: '';
  align-self: stretch;
  width: var(--st-border-seam);
  background: var(--st-seam);
}

.st-context__whose {
  color: var(--st-ink);
  font-weight: var(--st-weight-medium);
}

/* Код партнёра — моноширинным, как всякий идентификатор в системе: по нему
   сверяют адрес в строке браузера с тем, что написано на экране. */
.st-context__code {
  font-family: var(--st-font-mono);
  color: var(--st-seam-ink);
}

/* Выход из партнёра — ЯВНАЯ ССЫЛКА, а не кнопка «назад» браузера. «Назад»
   после трёх переходов внутри одного партнёра возвращает не туда, откуда
   пришли, и человек выясняет это уже глядя в чужие числа. */
.st-context__out {
  margin-left: auto;
}

/* ---- Ворота: вход и установка пароля -----------------------------------
   Узкая колонка, ПРИЖАТАЯ К ВЕРХУ, а не отцентрованная по высоте: у
   отцентрованной формы появление сообщения об отказе сдвигает поля вниз —
   под уже занесённым пальцем. Экран входа человек видит первым, и он же
   единственный, где на странице нет ни одной строки данных. */
.st-gate {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--st-space-4);
}

/* Шов у левого края панели. Тот же приём, которым в системе помечено всё
   значимое: текущий раздел, тон состояния, край карточки на телефоне. Акцент
   линией и никогда заливкой. */
.st-gate > .st-panel {
  border-left: var(--st-border-seam) solid var(--st-seam);
}

/* ---- Сообщение --------------------------------------------------------- */

.st-notice {
  display: flex;
  flex-direction: column;
  gap: var(--st-space-1);
  padding: var(--st-space-3) var(--st-space-4);
  border: var(--st-border-hairline) solid var(--st-line);
  border-left: var(--st-border-seam) solid var(--st-line-strong);
  border-radius: var(--st-radius-md);
  background: var(--st-surface);
}

.st-notice__title {
  font-weight: var(--st-weight-semibold);
  margin: 0;
  font-size: var(--st-text-lead);
}

.st-notice__text {
  margin: 0;
  color: var(--st-ink-muted);
  max-width: 76ch;
}

.st-notice--alarm {
  border-left-color: var(--st-tone-alarm-edge);
  background: var(--st-tone-alarm-wash);
}

.st-notice--act {
  border-left-color: var(--st-tone-act-edge);
  background: var(--st-tone-act-wash);
}

.st-notice--seam {
  border-left-color: var(--st-seam);
  background: var(--st-seam-wash);
}

/* «Сделано» — четвёртый тон извещения (31.08.2026). Заведён вместе с просьбой
   о расчёте: «просьба записана» — не тревога и не приглашение к действию, а
   исход. Красить его тоном «требует внимания» значило бы звать человека
   обратно туда, где он уже всё сделал. Тон берёт те же переменные палитры, что
   и завершённые состояния, — своих цветов здесь не заводится. */
.st-notice--done {
  border-left-color: var(--st-tone-done-edge);
  background: var(--st-tone-done-wash);
}

/* ---- Четыре состояния экрана ------------------------------------------
   Загрузка, пусто, отказ, ограничение. Экран без объяснения — дефект.    */

/* ТОН СОСТОЯНИЯ — ВЕРТИКАЛЬНЫЙ ШТРИХ, А НЕ ЗНАЧОК. Над заголовком стояла
   марка из трёх полосок, перекрашенная по тону. Она не добавляла ничего к
   тому, что уже сказано заголовком и текстом, то есть работала значком —
   а значков в системе нет ни рисованных, ни юникодных. Штрих у левого края
   говорит то же самое тем же приёмом, каким тон подаётся везде: в состоянии
   заявки, в строке реестра, в карточке на телефоне. */

.st-screen-state {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--st-space-3);
  padding: var(--st-space-7) var(--st-space-4);
  border-left: var(--st-border-edge) solid var(--st-line-strong);
  max-width: 62ch;
}

.st-screen-state__title {
  font-family: var(--st-font-display);
  font-size: var(--st-text-section);
  font-weight: var(--st-weight-semibold);
  margin: 0;
}

.st-screen-state__text {
  margin: 0;
  color: var(--st-ink-muted);
}

/* СНОСКА СОСТОЯНИЯ: код, время попытки, куда идти. Подписью, а не основным
   текстом. До 29.08.2026 машинный код стоял в теле сообщения — `503`,
   `payment.failed`, `refunds:approve` читал партнёр наравне со словами. Код
   нужен поддержке, и место ему то же, что у сноски: ниже, мельче, серым. */
.st-screen-state__foot {
  display: flex;
  flex-wrap: wrap;
  gap: var(--st-space-2) var(--st-space-4);
  margin: 0;
  font-size: var(--st-text-caption);
  color: var(--st-ink-faint);
}

.st-screen-state--error {
  border-left-color: var(--st-tone-alarm-edge);
}

.st-screen-state--limited {
  border-left-color: var(--st-tone-act-edge);
}

/* СОСТОЯНИЕ УРОВНЯ СТРАНИЦЫ ЗАНИМАЕТ ПОЛОТНО, А НЕ УГОЛ ЭКРАНА.

   Замер аудита 29.08.2026: сообщение об отказе шириной 460 px в левом верхнем
   углу экрана 1440×900, под ним 700 px пустоты. Формально состояние есть —
   визуально страница выглядит недогруженной, то есть говорит человеку ровно
   то же, что белый экран, ради отмены которого состояние и заводили.

   Полотно берётся высотой, а не шириной: растягивать строку текста на 1440 px
   нельзя — читать её станет труднее, и `max-width: 62ch` остаётся. Блок
   встаёт по центру свободной высоты, и пустота распределяется вокруг него, а
   не собирается снизу одним провалом. */
.st-screen-state--page {
  justify-content: center;
  min-height: 45vh;
}

/* Скелет загрузки: полосы той же ширины, что реальные колонки. Пульсация
   одна на всю систему и гасится при prefers-reduced-motion.

   ШИРИНЫ ЖИВУТ ЗДЕСЬ, А НЕ В РАЗМЕТКЕ. До 29.08.2026 они стояли атрибутом
   `style` пятью числами прямо в кирпиче. Встроенные стили политике не
   противоречат, но ширина полосы ожидания — решение системы о том, как
   выглядит ожидание, и жить ему рядом с остальной пластикой.

   ФОРМ ТРИ. Скелет обязан быть той же формы, что приедет: полосы произвольной
   длины на месте таблицы врут о количестве данных, и страница дёргается при
   подстановке. Дёрганье при подстановке хуже пустого окна — человек уже начал
   читать. */
.st-skeleton-block {
  display: flex;
  flex-direction: column;
  gap: var(--st-space-3);
  width: 100%;
}

.st-skeleton-block--table {
  gap: var(--st-space-2);
}

.st-skeleton-block--figures {
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--st-space-4);
}

.st-skeleton {
  display: block;
  height: 0.85em;
  border-radius: var(--st-radius-sm);
  background: var(--st-line-faint);
  animation: st-pulse 1.4s ease-in-out infinite;
}

/* Полосы неравной длины и НЕ убывающие лесенкой: убывающая лесенка читается
   как список, который кончается, а не как строки, которые ещё едут. */
.st-skeleton--1 {
  width: 68%;
}

.st-skeleton--2 {
  width: 92%;
}

.st-skeleton--3 {
  width: 54%;
}

.st-skeleton--4 {
  width: 80%;
}

.st-skeleton--5 {
  width: 44%;
}

/* Таблица: строки одной длины, потому что колонки одной ширины. */
.st-skeleton-block--table .st-skeleton {
  width: 100%;
  height: 1.6em;
}

/* Плитки сводных величин: столько же, сколько плиток, и той же меры. Пятая
   полоса гасится: плиток на сводке четыре, и пятая полоса под ними обещала бы
   строку, которой не приедет. */
.st-skeleton-block--figures .st-skeleton {
  flex: 1 1 96px;
  min-width: 96px;
  height: 2.4em;
}

.st-skeleton-block--figures .st-skeleton--5 {
  display: none;
}

@keyframes st-pulse {
  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.45;
  }
}

/* ---- Полоса лимита -----------------------------------------------------
   ДВА ПРАВИЛА СИСТЕМЫ, КОТОРЫМ ОНА ОБЯЗАНА ПОДЧИНЯТЬСЯ, И РАНЬШЕ НАРУШАЛА.
   Радиусы здесь 2 и 4: 999 px — язык потребительских приложений, и одна
   пилюля посреди ведомости выдаёт систему целиком. Акцент появляется линиями
   и никогда заливкой: штемпельный фиолетовый залитой полосой перестаёт быть
   оттиском и становится индикатором заряда.

   Отсюда устройство. Заполнение набрано НЕЙТРАЛЬНОЙ линией, а фиолетовый
   оставлен ровно одному штриху — отметке порога, за которым полоса меняет
   тон. Тона `act` и `alarm` заливают полосу законно: `tone-*-edge` в этой
   системе и заведены для штрихов и полос, текстом ими не набирают.        */

.st-meter {
  /* Порог локальной переменной, а не числом в двух местах: полоса меняет тон
     на тех же 80 %, что и отметка (см. `meter()` в кабинете). */
  --st-meter-threshold: 80%;
  position: relative;
  display: block;
  height: var(--st-space-2);
  background: var(--st-surface-sunken);
  border: var(--st-border-hairline) solid var(--st-line);
  border-radius: var(--st-radius-sm);
  overflow: hidden;
}

/* Заполнение — приглушённая тушь, а не линия разграфки: `line-strong` на
   утопленной дорожке даёт 2,1:1 в светлой теме и 1,9:1 в тёмной, то есть
   полоса читается только на просвет. Замерено. `ink-faint` держит 4,5:1
   как текст на своей поверхности и здесь тем более. */
.st-meter__fill {
  display: block;
  height: 100%;
  background: var(--st-ink-faint);
}

.st-meter--act .st-meter__fill {
  background: var(--st-tone-act-edge);
}

.st-meter--alarm .st-meter__fill {
  background: var(--st-tone-alarm-edge);
}

/* Порог. Единственный акцент на полосе — и он линия. Стоит на 80 %: там
   полоса меняет тон, и там же партнёру пора планировать расширение лимита,
   а не узнавать о нём из кода 429. */
.st-meter::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--st-meter-threshold);
  width: var(--st-border-seam);
  background: var(--st-seam);
}

/* ---- Мелочи ------------------------------------------------------------ */

.st-hint {
  font-size: var(--st-text-caption);
  color: var(--st-ink-faint);
  margin: 0;
}

.st-sep {
  border: 0;
  border-top: var(--st-border-hairline) solid var(--st-line-faint);
  margin: var(--st-space-4) 0;
}

.st-secret {
  display: flex;
  align-items: center;
  gap: var(--st-space-2);
  padding: var(--st-space-2) var(--st-space-3);
  border: var(--st-border-hairline) dashed var(--st-line-strong);
  border-radius: var(--st-radius-md);
  background: var(--st-surface-sunken);
  font-family: var(--st-font-mono);
  font-size: var(--st-text-body);
  overflow-wrap: anywhere;
}

/* ---- Период ------------------------------------------------------------
   Пресеты и две даты. Пресеты — те же `.st-filters`, что у реестра: приём
   один, и заводить рядом второй вид переключателя незачем. Отдельного здесь
   ровно две вещи — поля дат и кнопка, и им нужна своя раскладка.

   ПОРЯДОК В РАЗМЕТКЕ: СНАЧАЛА ПРЕСЕТЫ, ПОТОМ ДАТЫ. На телефоне это порядок
   сверху вниз, и он же порядок надобности: «7 дней» нажимают в девяти
   случаях из десяти, руками даты набирают в десятом.                     */

.st-period {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--st-space-3);
  padding: var(--st-space-3) var(--st-space-4);
}

/* Та же беда, что у `.st-toolbar__filters`, и то же лечение: форма — элемент
   гибкой раскладки, её `min-width` по умолчанию `auto`, и без явного нуля она
   распирает панель, а панель — документ. Проверяется замером ширины на 390,
   а не глазами: на снимке разъехавшаяся страница выглядит обычной. */
.st-period__presets {
  min-width: 0;
  flex: 0 1 auto;
}

.st-period__range {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--st-space-2);
  min-width: 0;
}

/* Поле даты своей ширины не имеет: в Chrome оно раздувается под формат, в
   Firefox сжимается в ничто. Задаём явно — иначе два поля рядом на 390 либо
   уезжают вбок, либо становятся нечитаемыми. */
.st-input--date {
  min-width: 9.5rem;
  font-family: var(--st-font-mono);
  font-size: var(--st-text-body);
}

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

   СТОЛБИК ПУСТЫХ СУТОК ОСТАЁТСЯ ВИДЕН волосяной чертой у основания. Совсем
   нулевой высоты он был бы неотличим от промежутка между столбиками, и месяц
   с тремя рабочими днями выглядел бы как три дня подряд.                  */

.st-series {
  display: flex;
  flex-direction: column;
  gap: var(--st-space-2);
  padding: var(--st-space-4);
}

.st-series__bars {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 96px;
  border-bottom: var(--st-border-hairline) solid var(--st-line);
}

.st-series__bar {
  flex: 1 1 0;
  /* Ниже волоска столбик не опускается: пустые сутки обязаны быть видны. */
  min-height: var(--st-border-hairline);
  min-width: 2px;
  background: var(--st-ink-faint);
  border-radius: var(--st-radius-sm) var(--st-radius-sm) 0 0;
}

/* Наибольшие сутки периода набраны цветом чернил, а не акцентом: акцент в
   системе — линии, и заливать им столбик значило бы завести исключение. */
.st-series__bar--peak {
  background: var(--st-ink-muted);
}

.st-series__scale {
  display: flex;
  justify-content: space-between;
  font-family: var(--st-font-mono);
  font-size: var(--st-text-micro);
  color: var(--st-ink-faint);
}

/* Таблица ряда под графиком: свёрнута, потому что тридцать строк чисел над
   реестром заявок отжали бы его за край экрана. Развёрнутая — это и есть
   доступный вид того же ряда, поэтому она настоящая таблица, а не картинка. */
.st-series-table > summary {
  cursor: pointer;
  padding: var(--st-space-2) var(--st-space-4);
  font-size: var(--st-text-caption);
  color: var(--st-ink-muted);
}

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

@media (max-width: 640px) {
  /* ПЕРВАЯ СТРОКА ДАННЫХ ОБЯЗАНА ПОПАДАТЬ В ПЕРВЫЙ ЭКРАН.
     Замерено до правки на 375: первая заявка начиналась на 589-м пикселе —
     бухгалтер открывал раздел заявок и видел что угодно, кроме заявок. Уходило
     это на служебное: подзаголовок в четыре строки, легенда тонов в три,
     переключатель плотности, который на телефоне вообще ничего не
     переключает, и поля рабочего стола.

     Ничего нужного за кнопку «показать фильтры» не спрятано: фильтры — то,
     чем реестр разбирают каждый раз, и они остались на месте. Ужато ровно
     служебное: заголовок ближе к данным, подзаголовок набран строкой факта,
     легенда идёт одним прокручиваемым рядом вместо трёх, а мёртвый на
     телефоне переключатель убран совсем.                                   */
  .st-main {
    padding: var(--st-space-3) var(--st-gutter-compact) var(--st-space-7);
  }

  .st-page-head {
    margin-bottom: var(--st-space-3);
  }

  /* Подзаголовок на телефоне — служебная строка факта, а не абзац. */
  .st-subtitle {
    font-size: var(--st-text-caption);
  }

  .st-stack {
    gap: var(--st-space-4);
    margin-top: var(--st-space-4);
  }

  .st-panel__head {
    gap: var(--st-space-2);
    padding: var(--st-space-2) var(--st-space-3);
  }

  .st-toolbar {
    gap: var(--st-space-2);
    padding: var(--st-space-2) var(--st-space-3);
  }

  .st-period,
  .st-series {
    gap: var(--st-space-2);
    padding: var(--st-space-2) var(--st-space-3);
  }

  /* СВОДНЫЕ ВЕЛИЧИНЫ — В ОДНУ КОЛОНКУ, И ЭТО НЕ ПРО ПРОСТОР.

     Поймано замером на 375 после появления периодов: плитка отдавала числу
     150 px, а «126 810|00 ₽» занимает 172 — рубль уезжал за край плитки
     МОЛЧА. Документ при этом вбок не выезжал ни на пиксель, и на снимке всё
     выглядело обычным: обрезанное внутри своего ящика глазами не находится.
     А за сутки числа были короче, поэтому раньше беды и не было — период её
     не создал, он её показал.

     Уменьшить начертание нельзя: сумма за месяц бывает любой длины, и всякий
     подобранный размер обрежется на следующем разряде. Одна колонка снимает
     вопрос целиком: на 375 числу остаётся 317 px, и это не «пока хватает», а
     «хватает на порядок больше, чем бывает». Цена — вертикаль, и на телефоне
     она правильная: четыре величины читают одну под другой, а не парами.

     Обрезанная сумма в кабинете, где смотрят чужие деньги, — это неверная
     сумма, а не мелкое оформление. */
  .st-figures {
    grid-template-columns: 1fr;
  }

  .st-figure {
    border-right: 0;
    border-bottom: var(--st-border-hairline) solid var(--st-line-faint);
    padding: var(--st-space-3) var(--st-space-4);
  }

  .st-figure:last-child {
    border-bottom: 0;
  }

  /* ДВЕ ДАТЫ В ДВЕ РАВНЫЕ КОЛОНКИ, КНОПКА ПОД НИМИ ВО ВСЮ ШИРИНУ.

     Гибкой раскладкой это не выходит, и найдено это снимком на 390: три
     элемента в ряд делили ширину так, что у полей оставалось по 120 px, и
     родное поле даты обрезало год — `08/25/202`. Обрезанный год в поле, по
     которому задают отчётный период, — это не косметика: человек не видит, за
     что смотрит, и правит вслепую.

     Сетка делит ровно пополам и не зависит от того, сколько места запросила
     кнопка; кнопка переезжает на свою строку, где ей и место — она единственная
     цель нажатия в этой полосе. */
  .st-period__range {
    width: 100%;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--st-space-2);
  }

  .st-period__range .st-btn {
    grid-column: 1 / -1;
  }

  .st-input--date {
    min-width: 0;
    font-size: var(--st-text-caption);
  }

  /* График ниже: на телефоне за ним сразу идут числа, и сотня пикселей
     картинки отжимала бы их под сгиб. */
  .st-series__bars {
    height: 64px;
  }

  /* Цель нажатия у поля ввода — 44 px, как у кнопок. Правило доктрины
     (раздел 7) держалось только для `.st-btn`, а поле оставалось 30 px:
     это единственный способ найти заявку на узком экране, и палец по нему
     промахивается. Правило стоит ЗДЕСЬ, а не рядом с кнопочным: `.st-input`
     объявлен ниже по файлу, и медиазапрос с равной силой обязан идти после
     него, иначе побеждает базовые 30 px. */
  .st-input {
    min-height: var(--st-tap-target);
  }

  /* Легенда в один ряд с прокруткой внутри своей области — тот же приём, что
     у фильтров. Три строки цветных слов над реестром отжимали первую заявку
     на 68 px и читались как содержание, хотя это справочник. */
  .st-legend {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    /* Полоса прокрутки видимая, как у фильтров: спрятанная молча уносит за
       край последние тона, и человек не знает, что они там есть. */
    scrollbar-width: thin;
    width: 100%;
    gap: var(--st-space-3);
  }

  /* Переключатель плотности на телефоне не переключает НИЧЕГО: он меняет
     высоту строки таблицы, а таблица здесь скрыта — реестр развёрнут в
     карточки. Кнопка, которая ничего не делает, хуже отсутствующей. */
  [data-density-toggle] {
    display: none;
  }

  .st-header__top {
    padding-left: var(--st-gutter-compact);
    padding-right: var(--st-gutter-compact);
  }

  /* Шапка на телефоне уходит НА ДВЕ СТРОКИ, а не сжимается. Знак, метка
     контура, имя вошедшего, смена темы и выход не помещаются в одну строку
     даже на 390, а горизонтальная прокрутка страницы в этой системе
     запрещена. Распорка растянута на всю ширину — перенос получается
     предсказуемый, а не «где придётся». */
  .st-header__top {
    flex-wrap: wrap;
    row-gap: var(--st-space-2);
    gap: var(--st-space-2);
  }

  /* Перенос нужен только шапке кабинета: там на второй строке стоят имя
     вошедшего, смена темы и выход. На воротах второй строке достаться нечему
     — пустая строка под знаком выглядела бы недогруженной страницей. */
  .st-header__top:not(.st-header__top--gate) .st-header__spacer {
    flex-basis: 100%;
    height: 0;
  }

  /* Имя партнёра уходит целиком: человек, который открыл СВОЙ кабинет, знает,
     чей он и по какому договору. Имя ВОШЕДШЕГО остаётся вместе с ролью — оно
     отвечает на другой вопрос, и ответ на него нужен перед каждым действием,
     а не один раз при входе. */
  .st-org--partner {
    display: none;
  }

  .st-org {
    max-width: 40vw;
  }

  /* Разделяющая линия снимается вместе с именем партнёра: сам элемент
     остаётся в разметке, поэтому соседский селектор продолжает попадать, и
     на телефоне у левого края висела вертикальная черта ни при чём. */
  .st-org--viewer {
    margin-right: auto;
  }

  /* Разделяющая линия снимается вместе с именем партнёра. Селектор повторён
     соседским НЕ ради красоты: базовое правило стоит на `.st-org--partner +
     .st-org--viewer` (сила 0,2,0), и `.st-org--viewer` (0,1,0) его не
     перебивает — первая редакция этой правки не сработала ровно поэтому, и
     на телефоне у левого края осталась вертикальная черта ни при чём.
     Сам партнёр из разметки не исчезает, только скрыт, поэтому соседский
     селектор продолжает попадать. */
  .st-org--partner + .st-org--viewer {
    border-left: 0;
    padding-left: 0;
  }

  .st-facts {
    grid-template-columns: 1fr;
  }

  .st-fact__key {
    border-right: 0;
    padding-bottom: 0;
  }

  .st-fact__value {
    padding-left: 0;
    padding-top: 0;
    border-bottom: var(--st-border-hairline) solid var(--st-line-faint);
    padding-bottom: var(--st-space-2);
  }

  .st-figure {
    border-right: 0;
    border-bottom: var(--st-border-hairline) solid var(--st-line-faint);
  }

  .st-cards {
    display: flex;
    flex-direction: column;
  }

  .st-card {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: var(--st-space-1) var(--st-space-3);
    padding: var(--st-space-3) var(--st-space-3) var(--st-space-3) var(--st-space-4);
    border-bottom: var(--st-border-hairline) solid var(--st-line-faint);
    border-left: var(--st-border-edge) solid transparent;
  }

  .st-card--alarm {
    border-left-color: var(--st-tone-alarm-edge);
  }

  .st-card--act {
    border-left-color: var(--st-tone-act-edge);
  }

  .st-card__key {
    font-size: var(--st-text-caption);
    color: var(--st-ink-faint);
  }

  /* ШАПКА КАРТОЧКИ ТОЖЕ ОБЯЗАНА УМЕТЬ СЖИМАТЬСЯ.

     Замер аудита 29.08.2026: экран интеграции уезжал вбок на 67 px при 390 px
     ширины, и виновник назван — строка прав `orders:read, settlements:read,
     reports:read` (310 px) машинным начертанием внутри `.st-card__head`.
     Приём против этого в системе УЖЕ БЫЛ (`.st-mono--wrap`, и правило
     `.st-card .st-mono` его включает), но не работал: `.st-card__head` — это
     гибкая раскладка, а у её ребёнка `min-width` по умолчанию равен `auto`,
     и он не даёт себе стать уже содержимого. Перенос при этом разрешён, но
     переносить нечего: ширину диктует не текст, а невозможность сжаться.

     Поэтому ноль ставится ДВАЖДЫ — самой шапке (она сама ребёнок сетки
     карточки) и каждому её ребёнку. Одного из двух не хватает: снятый на
     одном уровне запрет восстанавливается на соседнем.                     */
  .st-card__head {
    grid-column: 1 / -1;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--st-space-3);
    min-width: 0;
    margin-bottom: var(--st-space-1);
  }

  .st-card__head > * {
    min-width: 0;
  }

  /* КАРТОЧКА РЕЕСТРА НЕ ИМЕЕТ ПРАВА РАСПИРАТЬ СОБОЙ ДОКУМЕНТ.

     Найдено замером 29.08.2026 на очереди возвратов: на 390 px документ уезжал
     вбок на 10 px — вместе с рельсом разделов и подвалом, хотя у них со своей
     прокруткой всё в порядке: они мерили ширину уже разъехавшейся страницы.
     Глазами это не находится, на снимке страница выглядит обычной.

     ПРИЧИНА НЕ В КОНКРЕТНОМ ЭКРАНЕ, А В СЕТКЕ КАРТОЧКИ. `.st-card` — это грид
     `max-content 1fr`, а у элемента грида `min-width` по умолчанию равен `auto`
     и не даёт колонке стать уже своего содержимого. Одного неразрывного
     машинного номера (`styk_01K3P8QZ4M7T2XVB9NDR6AAAA` — 28 знаков) хватает,
     чтобы колонка значений перестала сжиматься. Карантин от этого спасала
     только длина его собственных строк, то есть случай.

     `overflow-wrap: anywhere`, А НЕ `break-word`: только `anywhere` влияет на
     ВЫЧИСЛЕНИЕ минимальной ширины колонки. `break-word` переносит уже
     нарисованное и распирающую ширину не убирает — то есть выглядит починкой,
     не будучи ей.

     Перенос машинного номера посреди знака — цена, и она меньше альтернативы:
     половина строки за краем экрана на телефоне, где приходит больше семидесяти
     процентов сессий. */
  .st-card > * {
    min-width: 0;
    overflow-wrap: anywhere;
  }

  /* МАШИННАЯ СТРОКА В КАРТОЧКЕ ПЕРЕНОСИТСЯ, И ЭТО НЕ ОТМЕНА `.st-mono`.

     `white-space: nowrap` у `.st-mono` стоит ради ТАБЛИЦЫ: там номер обязан
     читаться одной строкой, и там для него есть своя прокрутка
     (`.st-table-wrap.st-scroll-x`). В карточке телефона прокрутки нет и быть не
     должно — карточки для того и рисуются вместо таблицы, чтобы горизонтальной
     прокрутки на телефоне не было вовсе. Значит здесь номер переносится.

     Приём в системе УЖЕ ЕСТЬ — `.st-mono--wrap`; правило ниже просто включает
     его там, где вариант «одной строкой» физически невозможен. Второго способа
     переносить машинную строку не заводится.

     Замер после правки: очередь возвратов на 390 px — 0 px выезда (было 10). */
  .st-card .st-mono {
    white-space: normal;
    overflow-wrap: anywhere;
  }
}

@media (min-width: 641px) {
  .st-cards {
    display: none;
  }
}

@media (max-width: 640px) {
  .st-table-wrap {
    display: none;
  }
}

/* -------------------------------------------------------------------------
   ЛЕНТА ЗАЯВОК: ОТБОР, СТРАНИЦЫ, ШАПКА КАРТОЧКИ СТРОКИ
   (заведено 29.08.2026 вместе с экраном ленты)

   `min-width: 0` НА ФОРМЕ ОТБОРА — ЭТО НЕ УКРАШЕНИЕ, А ЗАЩИТА ОТ ВЫЕЗДА ВСЕГО
   ДОКУМЕНТА ВБОК. Урок уже куплен выше, на `.st-toolbar__filters`, и стоит
   ровно тех же денег здесь: внутри формы лежит `.st-filters` с одиннадцатью
   состояниями и своей горизонтальной прокруткой, но у элемента гибкой
   раскладки `min-width` по умолчанию равен `auto` — он не даёт себе стать уже
   содержимого. Форма распирает панель, панель — страницу, и вбок уезжает ВЕСЬ
   документ вместе с рельсом. На снимке страница при этом выглядит обычной,
   пока не потянешь её вбок: находится только замером.

   ПОЛЯ ОТБОРА — СЕТКА С АВТОПОДБОРОМ, А НЕ РЯД. На 390 это одна колонка на всю
   ширину, на 1440 — четыре-пять в ряд, и промежуточных правил не нужно ни
   одного: `auto-fit` с `minmax` делает это сам. Ряд с переносом дал бы на
   средних ширинах последнее поле в четверть строки.                       */

.st-feed-filters {
  display: flex;
  flex-direction: column;
  gap: var(--st-space-3);
  min-width: 0;
}

.st-feed-filters__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--st-space-3);
  align-items: end;
  min-width: 0;
}

/* Поле сетки тоже обязано уметь сжиматься: `min-width: auto` у элемента сетки
   держит его шире собственной колонки ровно так же, как у элемента флекса. */
.st-feed-filters__row > .st-field {
  min-width: 0;
}

/* -------------------------------------------------------------------------
   ПЕРЕХОД ПО СТРАНИЦАМ

   КРАЙ НЕ ПРЯЧЕТСЯ, А ГАСНЕТ, и раскладка это учитывает: «Назад» и «Вперёд»
   стоят по краям, положение показано между ними, и на первой странице ничего
   не сдвигается. Исчезающая кнопка подводит соседнюю под палец — на телефоне
   это нажатие не туда, а лента листается именно с телефона.               */

.st-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--st-space-3);
  padding: var(--st-space-3) var(--st-space-4);
  border-top: var(--st-border-hairline) solid var(--st-line);
  min-width: 0;
}

.st-pager__where {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  text-align: center;
  font-size: var(--st-text-caption);
  color: var(--st-ink-muted);
  min-width: 0;
}

.st-pager [aria-disabled='true'] {
  opacity: 0.45;
  pointer-events: none;
}

/* -------------------------------------------------------------------------
   ШАПКА КАРТОЧКИ СТРОКИ НА ТЕЛЕФОНЕ

   Слева — номер, пометка контура и партнёр; справа — состояние. Два элемента,
   а не четыре: `.st-card__head` разводит детей `space-between`, и четыре
   ребёнка растянулись бы по всей ширине с провалами между ними.

   ПАРТНЁР СТОИТ ЗДЕСЬ, А НЕ В ТЕЛЕ КАРТОЧКИ, потому что вопрос «чей это
   платёж» задают первым, а в теле он оказался бы пятой строкой списка.    */

/* ОДИН РЕБЁНОК У ШАПКИ, ДВЕ СТРОКИ ВНУТРИ НЕГО.

   `.st-card__head` разводит своих детей `space-between` — приём верный там,
   где детей два и оба короткие. Номер заявки «styk_» плюс 26 знаков Crockford
   base32 занимает на 390 всю строку целиком, и подпись состояния, поставленная
   вторым ребёнком, налезала на него буквами. Нашёл это браузер: по коду оба
   элемента законны и каждый по отдельности помещается.

   Поэтому шапка ленты — ОДИН элемент со своей раскладкой в две строки. Первая
   отвечает на вопрос «какая заявка», вторая — «чья и что с ней». */

.st-feed-head {
  display: flex;
  flex-direction: column;
  gap: var(--st-space-1);
  min-width: 0;
  width: 100%;
}

.st-feed-head__ref {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--st-space-2);
  min-width: 0;
  /* Номер — сплошная строка без пробелов: без этого он не переносится вовсе и
     распирает карточку, а вместе с ней и страницу. */
  overflow-wrap: anywhere;
}

.st-feed-head__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--st-space-2);
  min-width: 0;
}

.st-feed-head__partner {
  font-size: var(--st-text-caption);
  color: var(--st-ink-faint);
  overflow-wrap: anywhere;
}
