/* Брейкпоинты этого файла — четыре именованные точки из `tokens.css`
   (`--bp-phone` 520, `--bp-mobile` 768, `--bp-shell` 920, `--bp-dense` 1280)
   плюс три помеченных исключения (tablet 1024, laptop 1180, ultrawide 2200),
   каждое из которых объяснено по месту. Условие @media не умеет читать var(),
   поэтому значения повторены литералами; других значений в файле быть не
   должно: «ниже точки» — `max-width: <N - 0.02>px`, «от точки и выше» —
   `min-width: <N>px`. Каждый @media подписан именем порога.

   Веса задаются только токенами `--weight-*`: числовых font-weight в файле нет.
   Роли — тело / усиленный текст / акцент / заголовок, см. `tokens.css`. */

* {
  box-sizing: border-box;
}

/* Место под полосу прокрутки держится всегда. На компьютере полоса занимает
   ширину (15–17 px): без резерва страница короче окна («Платёж», «Касса»,
   «Архив», «Доставки», «Редактор» на 1366) была шире длинной, и при каждом
   переходе между ними правый край шапки, «Добавить…» и таблицы сдвигались
   на ширину полосы — и ещё раз посреди загрузки, когда полоса появлялась
   (NAV_JUMP_AUDIT_2026-09-26). На телефоне полоса поверх содержимого, там
   правило ничего не меняет.

   Общей плавной прокрутки (`scroll-behavior: smooth`) нет: браузер применял
   её и к возврату места на «Назад» — список открывался сверху и за ~12 кадров
   доезжал до прежнего места. Плавно — только прокрутка к месту на этой же
   странице, правило ниже. */
html {
  min-height: 100%;
  -webkit-text-size-adjust: 100%;
  scrollbar-gutter: stable;
}

/* Плавная прокрутка — одна, к месту на этой же странице: ссылка-якорь
   («К сохранению реквизитов», «Добавить счёт», поле из сводки «Проверьте
   данные») и сообщение об ошибке формы. Класс ставит app.js на время этой
   прокрутки. При «уменьшить движение» её нет, как и остальных переходов. */
@media (prefers-reduced-motion: no-preference) {
  html.is-smooth-scroll {
    scroll-behavior: smooth;
  }
}

body {
  min-height: 100%;
  margin: 0;
  overflow-x: hidden;
  color: var(--color-text);
  background:
    radial-gradient(circle at 12% 0%, rgb(96 165 250 / 0.12), transparent 28rem),
    var(--color-bg);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button,
input,
select,
textarea {
  font: inherit;
}

button {
  cursor: pointer;
}

input,
select,
textarea {
  min-width: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

h1,
h2,
h3,
p {
  margin: 0;
}

h1,
h2,
h3 {
  line-height: var(--leading-tight);
  font-weight: var(--weight-heading);
}

/* `<strong>` по умолчанию наследует относительный `bolder`: внутри тела 400 он
   даёт 700, а внутри значения 750 давал 900. Абсолютный токен убирает эту
   зависимость от контекста — выделение всегда одна и та же ступень. */
strong,
b {
  font-weight: var(--weight-accent);
}

[hidden] {
  display: none !important;
}

.app {
  width: min(100%, var(--container-max));
  margin: 0 auto;
  padding: var(--space-4);
}

.shell {
  display: grid;
  gap: var(--space-4);
  grid-template-rows: auto 1fr;
  align-content: start;
  min-height: 0;
}

.topbar,
.panel,
.auth-panel {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: rgb(255 255 255 / 0.86);
  box-shadow: var(--shadow-soft);
}

.topbar {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
}

.topline,
.navrow,
.userline,
.head-actions,
.mobile-top-actions {
  display: flex;
  align-items: center;
  min-width: 0;
}

.topline {
  justify-content: space-between;
  gap: var(--space-4);
  align-items: flex-start;
  flex-wrap: wrap;
}

/* Строка контекста: слева выбор юрлица с подписью, справа — доступ и выход.
   Переключатель больше не тянется на всю ширину как ряд вкладок; подпись и
   черта под строкой (см. .navrow) отделяют его от навигации разделов
   (DARYA-2026-09-03-001). */
.org-line {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex: 1 1 auto;
  min-width: 0;
}

.topline .org-tabs {
  flex: 0 1 auto;
  flex-wrap: wrap;
  overflow-x: visible;
}

/* Навигация разделов отделена от строки контекста той же чертой и тем же
   отступом, что и «Общие» ниже: одна и та же граница шапки, без новых
   токенов. */
.navrow {
  justify-content: flex-start;
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-3);
}

/* Высота строки держится ЗАРАНЕЕ, под кнопку «Выйти» (`.btn`, 40 px).

   Кнопка — модальный триггер, и до готовности `app.js` она скрыта правилом
   `html:not([data-app-ready]) .js-only-modal-trigger`. Скрипт с `defer`
   доезжает на Fast 4G к 552-й миллисекунде, строка вырастала с 21 px до 40, и
   вниз на 4 px уезжала вся страница: именно это давало CLS 0,118 на карточке
   маршрута и 0,077 на списке заявок — не подмена шрифта, как предполагал
   сплошной проход (волна 1, находка 7), а появление кнопки. Замерено по
   источникам сдвига: `DIV.userline` 220×21 → 309×40, следом `DIV.navrow`,
   `DIV.common-nav` и `MAIN.main` на +4 px.

   Резерв ничего не меняет в готовом виде: с JavaScript в строке стоит та же
   кнопка 40 px, без него — та же кнопка из `<noscript>`-формы. Ниже 920 px
   резерв снимается: там кнопки в этой строке нет вовсе (см. «ниже shell»). */
.userline {
  flex: 0 1 auto;
  justify-content: flex-end;
  min-height: 40px;
  gap: var(--space-2);
  color: var(--color-text-muted);
  font-weight: var(--weight-strong);
  white-space: nowrap;
}

.topline--no-org .userline {
  margin-left: auto;
}

.topline--no-org .userline__context {
  padding-left: var(--space-3);
  border-left: 1px solid var(--color-border-strong);
}

.topline--no-org .userline .btn {
  margin-left: var(--space-1);
}

/* Длинное название юрлица (до 255 символов) переносится внутри строки доступа
   и не выталкивает кнопку выхода за пределы экрана. Правило намеренно
   ограничено span: у кнопки «Выйти» остаётся nowrap от .btn и .userline. */
span.desktop-access {
  white-space: normal;
  overflow-wrap: anywhere;
}

.mobile-access,
.mobile-top-actions {
  display: none;
}

.org-tabs,
.section-tabs,
.shared-tabs,
.drawer-nav {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

.org-tabs,
.section-tabs {
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}

.org-tabs::-webkit-scrollbar,
.section-tabs::-webkit-scrollbar {
  display: none;
}

.org-switch-form,
.inline-form {
  margin: 0;
}

.chip,
.tab,
.btn {
  border: 1px solid var(--color-border);
  color: var(--color-ink);
  background: rgb(255 255 255 / 0.72);
  transition:
    background var(--motion-duration) ease,
    border-color var(--motion-duration) ease,
    color var(--motion-duration) ease,
    transform var(--motion-duration) ease;
}

/* Микропереходы состояний hover / focus-visible / active у ссылок, полей
   ввода и иконочных кнопок (пак 2026-09-03, T10). Переходят только цвет, фон,
   рамка и фокус-кольцо — ничего, что двигает раскладку. Длительность одна,
   `--motion-duration`; при prefers-reduced-motion все переходы отключаются
   (правило в конце файла). Раскрытие <details> не анимируется: без перехода
   по высоте оно остаётся скачком раскладки, а переход по высоте запрещён. */
a,
.input,
.select,
.textarea,
.copy-icon-button,
.phone-add-button {
  transition:
    color var(--motion-duration) ease,
    background-color var(--motion-duration) ease,
    border-color var(--motion-duration) ease,
    box-shadow var(--motion-duration) ease;
}

.chip,
.tab {
  min-height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  border-radius: var(--radius-pill);
  padding: var(--space-2) var(--space-4);
  font-weight: var(--weight-accent);
  white-space: nowrap;
}

.org-chip {
  max-width: min(100%, 260px);
  white-space: normal;
  overflow-wrap: anywhere;
  text-align: center;
  line-height: 1.25;
}

.chip[aria-selected="true"],
.chip[aria-current="true"],
.tab[aria-current="page"] {
  background: var(--color-ink);
  border-color: var(--color-ink);
  color: #ffffff;
}

.tab--muted {
  color: var(--color-text-muted);
}

.chip:hover,
.tab:hover,
.btn:hover {
  border-color: var(--color-border-strong);
}

.btn {
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-4);
  font-weight: var(--weight-accent);
  white-space: nowrap;
}

.btn-primary {
  border-color: var(--color-accent);
  color: var(--color-accent-on);
  background: var(--color-accent);
}

.btn-primary:hover {
  background: var(--color-accent-hover);
}

.btn:disabled {
  cursor: not-allowed;
  opacity: 0.62;
}

.btn-primary:disabled {
  border-color: #94a3b8;
  color: #f8fafc;
  background: #64748b;
}

.btn-secondary {
  background: var(--color-surface);
}

.btn-plain {
  border-color: transparent;
  color: var(--color-text-muted);
  background: transparent;
}

.btn-danger {
  border-color: var(--color-danger);
  color: #ffffff;
  background: var(--color-danger);
}

.btn-danger:hover {
  background: #be123c;
}

.main {
  min-width: 0;
}

.workspace {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
  min-width: 0;
}

.common-nav {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-3);
}

.common-nav__label,
.org-line__label {
  flex: 0 0 auto;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.common-nav__tabs {
  flex-wrap: wrap;
}

.nav-label {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.screens-wrap {
  display: grid;
  gap: var(--space-4);
  min-width: 0;
}

.panel {
  min-width: 0;
  overflow: hidden;
  scroll-margin-top: var(--space-4);
}

.screen {
  display: grid;
  gap: 0;
}

/* `min-width: 0` — защита шапки от единственного длинного слова: имя юрлица
   допускает 255 символов без пробелов, и без этой строки шапка растягивалась
   бы по min-content содержимого за пределы панели, унося кнопки действий за
   край (панель их обрезает). С ней вместо разрыва раскладки сжимается сам
   бейдж. */
.view-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  min-width: 0;
  padding: var(--space-5) var(--space-5) var(--space-4);
  border-bottom: 1px solid var(--color-border);
}

.title-block {
  display: grid;
  gap: var(--space-2);
  min-width: 0;
}

/* Заголовок страницы скрыт (его текст несут хлебные крошки), поэтому бейджи
   рядом с ним оставались одни на отдельной строке под крошками. Здесь крошки
   и бейджи собираются в одну строку, а подзаголовок переносится под неё. */
.title-block--inline {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
}

.title-block--inline > .view-subtitle {
  flex: 1 0 100%;
  margin: 0;
}

/* Шапка «Добавить заявки»: номер маршрута, водитель, направление и дата
   выезда отдельной строкой под крошками, пары «подпись — значение» карточки
   маршрута в ряд (заказчик 2026-09-15, скриншот 9). */
.title-block--inline > .route-add-head-facts {
  display: flex;
  flex: 1 0 100%;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
}

/* Крошки — единственная надпись, называющая экран: заголовок `h1` на этих
   экранах `sr-only`. Поэтому кегль на ступень выше тела (16 px при теле 14 px):
   заказчик просила «чуть увеличить шрифт по стрелке» (`DARYA-2026-08-31-004`),
   и до 2026-09-12 крошка отличалась от тела только весом. Ступень взята из
   шкалы (`--text-base`), нового размера не заводится.

   Обрезка вместо прокрутки: `overflow-x: auto` прятал хвост длинного названия
   БЕЗ единого признака, что текст оборван, — на карточке клиента-юрлица строка
   в 1301 px уезжала в контейнер 1162 px и обрывалась на полуслове прямо под
   кнопкой «Создать заявку». Теперь последняя крошка (она же значение — имя
   клиента, номер заявки, название юрлица) сжимается и честно заканчивается
   многоточием, а полный текст остаётся в `title`. Разделители и ссылки выше по
   пути не сжимаются: путь должен читаться целиком. */
.crumb {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  color: var(--color-meta);
  font-size: var(--text-base);
  font-weight: var(--weight-heading);
  text-transform: uppercase;
  white-space: nowrap;
}

.crumb > * {
  flex: 0 0 auto;
}

.crumb > :last-child {
  flex: 0 1 auto;
  min-width: 3ch;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Последнее звено правки заявки: многоточием режется слово «Редактирование»,
   номер виден целиком. На 360–375 у КРИПВЗ многоточие съедало сам номер —
   «Редактирование 002…» (ревью 319c463, находка 3). Промежуток — ширина
   пробела, как в тексте звена. */
.crumb .crumb-edit {
  display: flex;
  gap: var(--space-1);
}

.crumb-edit__label {
  min-width: 3ch;
  overflow: hidden;
  text-overflow: ellipsis;
}

.view-title {
  color: var(--color-ink);
  font-size: 28px;
}

.view-subtitle,
.auth-note,
.summary-card p,
.empty-card p {
  color: var(--color-text-muted);
}

.head-actions {
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* Блок действий шапки экрана сжимается не уже своей самой широкой кнопки.

   Общее `min-width: 0` выше позволяло ему сжаться уже кнопки, и кнопка
   вылезала из блока влево — на карточке клиента-юрлица и сотрудника с длинным
   именем прямо поверх крошек (до 63 px на 920–1440). Запрет сжатия целиком
   (`flex: 0 0 auto`, батч 2026-09-12) это закрывал, но ломал соседей: на
   920–1100 px кнопки карточки заявки и маршрута переставали переноситься во
   вторую строку, и номер заявки в крошке — единственная надпись экрана —
   обрезался многоточием до «001-…» (независимое ревью 2026-09-13). Нижняя
   граница по содержимому держит оба: блок уступает место крошкам, пока кнопки
   могут переноситься, и не уже одной кнопки. */
.view-head > .head-actions {
  min-width: min-content;
}

.foundation-summary,
.empty-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-3);
  padding: var(--space-5);
}

.panel > .organization-list,
.panel > .empty-state {
  padding: var(--space-5);
}

.summary-card,
.empty-card {
  min-width: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-soft);
}

.summary-card {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-4);
}

.summary-card span,
.empty-card__org {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
  text-transform: uppercase;
}

.summary-card strong {
  color: var(--color-ink);
  font-size: var(--text-base);
}

.empty-state {
  min-width: 0;
  min-height: 150px;
}

.empty-card {
  display: grid;
  align-content: space-between;
  gap: var(--space-4);
  min-height: 100%;
  padding: var(--space-4);
}

.empty-card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.empty-card__dot {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-pill);
  background: var(--color-border-strong);
}

.empty-state--blue .empty-card__dot {
  background: var(--color-accent);
}

.empty-state--warn .empty-card__dot {
  background: var(--color-warn);
}

.empty-state--shared .empty-card {
  background: #f3f7fb;
}

.empty-state--shared .empty-card__dot {
  background: var(--color-success);
}

.badge {
  display: inline-flex;
  align-items: center;
  min-height: 26px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  padding: var(--space-1) var(--space-3);
  color: var(--color-text-muted);
  background: var(--color-surface-soft);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
  white-space: nowrap;
}

.badge.blue {
  border-color: rgb(96 165 250 / 0.45);
  color: #1d4ed8;
  background: rgb(96 165 250 / 0.16);
}

.badge.warn {
  border-color: rgb(245 158 11 / 0.45);
  color: #92400e;
  background: rgb(245 158 11 / 0.15);
}

.badge.success {
  border-color: rgb(34 197 94 / 0.45);
  color: #166534;
  background: rgb(34 197 94 / 0.16);
}

.badge.danger {
  border-color: rgb(225 29 72 / 0.45);
  color: #9f1239;
  background: rgb(225 29 72 / 0.14);
}

.auth-main {
  min-height: 100vh;
  display: grid;
  align-items: center;
  justify-items: center;
  padding: var(--space-4);
}

.auth-panel,
.organization-list {
  width: min(520px, 100%);
}

.auth-panel {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-6);
}

.error-panel {
  width: min(640px, 100%);
  display: grid;
  gap: var(--space-5);
  padding: var(--space-6);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: rgb(255 255 255 / 0.9);
  box-shadow: var(--shadow-panel);
}

.error-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.error-copy {
  display: grid;
  gap: var(--space-3);
}

.error-copy h1 {
  color: var(--color-ink);
  font-size: 34px;
  overflow-wrap: anywhere;
}

.error-copy p:not(.eyebrow) {
  max-width: 44rem;
  color: var(--color-text-muted);
  font-size: var(--text-base);
}

.error-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.auth-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--color-ink);
  font-weight: var(--weight-heading);
}

.brand-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: var(--radius-md);
  color: #ffffff;
  background: var(--color-ink);
  font-size: var(--text-xs);
}

.eyebrow {
  color: var(--color-meta);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
  text-transform: uppercase;
}

.auth-panel h1 {
  color: var(--color-ink);
  font-size: clamp(30px, 5vw, 44px);
}

.form-stack,
.organization-list {
  display: grid;
  gap: var(--space-4);
}

/* Short single-purpose forms (cash operation, emergency-shutdown confirm) are
   paired with .form-stack. The grid would otherwise stretch the inputs across
   the full panel width on wide desktops; cap it to the same readable column the
   auth/error surfaces use. Mobile keeps its natural full width. */
.form-narrow {
  max-width: 640px;
}

.field {
  display: grid;
  gap: var(--space-2);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-accent);
}

.field-hint,
.form-section__hint,
.panel-hint {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-body);
  line-height: 1.35;
  overflow-wrap: anywhere;
}

/* Предупреждение о том, что без JavaScript подтверждения не будет. Стоит
   СВОЕЙ строкой над рядом действий и занимает ширину секции целиком.

   Внутрь `.form-actions` его класть нельзя: у формы названия юрлица ряд
   действий — вторая колонка сетки секции с шириной ПО СОДЕРЖИМОМУ
   (`grid-template-columns: minmax(0, 1fr) auto`), и длинная строка внутри
   него забирала ширину у самих полей — «Название» садилось с 407 px до 130. */
.field-hint--noscript {
  margin: 0;
  text-align: left;
}

/* Элемент сетки здесь — сам `<noscript>`, а не абзац внутри него: без
   JavaScript браузер разбирает содержимое `<noscript>` как обычный DOM, и
   строкой сетки становится именно он. `display: block` нужен потому, что по
   умолчанию `<noscript>` строчный. */
.noscript-row {
  display: block;
}

.field-hint--warning {
  color: #9f1239;
}

.input,
.select,
.textarea {
  width: 100%;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 12px 13px;
  color: var(--color-text);
  background: var(--color-surface);
  font-weight: var(--weight-body);
}

.input:focus,
.select:focus,
.textarea:focus,
.btn:focus-visible,
.chip:focus-visible,
.tab:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.form-error {
  border: 1px solid rgb(225 29 72 / 0.28);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  color: #9f1239;
  background: rgb(225 29 72 / 0.08);
}

.form-error--summary {
  display: grid;
  gap: var(--space-2);
  margin: 0 var(--space-5);
}

.form-error--summary p,
.form-error--summary ul {
  margin: 0;
}

.form-error--summary a,
.field-error {
  color: #9f1239;
}

.field-error {
  font-size: var(--text-sm);
  font-weight: var(--weight-strong);
}

[aria-invalid="true"] {
  border-color: rgb(225 29 72 / 0.62);
}

.notice-banner {
  margin: 0 var(--space-5) var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid rgb(37 99 235 / 0.22);
  border-radius: var(--radius-sm);
  color: var(--color-ink);
  background: rgb(37 99 235 / 0.08);
  font-weight: var(--weight-strong);
}

.organization-list {
  max-width: 520px;
  width: 100%;
  justify-self: center;
  margin-inline: auto;
}

.panel--chooser {
  width: min(680px, 100%);
  justify-self: center;
}

.panel--chooser > .view-head {
  padding-block: var(--space-4) var(--space-3);
}

/* The no-org chooser is a deliberate, compact selection surface, not a
   full-width empty island: bound the empty state to the same centered column
   as the form above. */
.panel--chooser > .empty-state {
  justify-self: center;
  width: 100%;
  max-width: 520px;
}

.organization-option {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-soft);
}

.organization-option input {
  margin-top: 5px;
}

.organization-option span {
  display: grid;
  gap: var(--space-1);
}

.organization-option small {
  color: var(--color-text-muted);
}

.organization-option {
  cursor: pointer;
}

.organization-option:hover {
  border-color: var(--color-border-strong);
}

/* Obvious selected row. Pure CSS (:has) — no JS — so it degrades gracefully
   to the native radio if :has is unsupported; the radio still submits its
   value and the POST/CSRF/return_to contract is unchanged. */
.organization-option:has(input:checked) {
  border-color: var(--color-accent);
  background: rgb(96 165 250 / 0.10);
}

.organization-option:has(input:checked) strong {
  color: #1d4ed8;
}

.drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: none;
  align-items: flex-end;
  padding: var(--space-3);
  background: rgb(9 11 18 / 0.34);
}

.drawer-backdrop.is-open {
  display: flex;
}

/* Без JavaScript ящик «Разделы» открывается адресом: кнопка — ссылка на
   #sectionsDrawer, и :target показывает ящик тем же display, что и is-open;
   «Закрыть» ведёт на несуществующий якорь и снимает :target без прокрутки.
   Правило действует только пока app.js не подал сигнал готовности: с
   JavaScript ящик ведёт класс, и случайный #sectionsDrawer в адресе
   (перезагрузка) не держит ящик открытым без возможности его закрыть. */
html:not([data-app-ready]) .drawer-backdrop:target {
  display: flex;
}

.drawer {
  width: min(100%, 520px);
  max-height: min(82vh, 720px);
  display: grid;
  gap: var(--space-4);
  overflow: auto;
  margin: 0 auto;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  box-shadow: var(--shadow-panel);
}

.drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.drawer-group,
.drawer-footer {
  display: grid;
  gap: var(--space-2);
}

.drawer-nav {
  display: grid;
  align-items: stretch;
}

.drawer-nav .tab {
  width: 100%;
  justify-content: flex-start;
  border-radius: var(--radius-md);
}

.mono {
  font-family: var(--font-mono);
}

/* Группа цифр телефона в таблице не рвётся — номер переносится только между
   группами (`partials/phone.html`): иначе «+7 921 555- / 18-19» в «Архиве»
   (В-05) и «+7 812 445- / 90-11» у курьера (В-06). Неразрывна только группа,
   а не весь телефон: два номера или приписка раздвигали таблицу «Архива», а
   номер без пробелов («+375-29-245-67-89») вылезал из ячейки курьера на
   «Клиент» (ревью 319c463, находки 1 и 2). */
.phone-group {
  white-space: nowrap;
}

/* Visually hidden, still announced. Used by labels that duplicate a visible
   section heading and by the page <h1> whose text the breadcrumb already
   carries: the heading stays in the DOM as the accessible name target for
   `aria-labelledby`, but no longer repeats itself on screen. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
}

/* Inline qualifier text («вручную/расчёт», «(недоступно)», перевозчик) that
   must read as secondary meta next to a primary value. Uses the shared muted
   token so it matches the established meta-text color. */
.muted {
  color: var(--color-text-muted);
}

/* Классификация рядом с заголовком страницы (тип клиента): по правилу бейджей
   это не сигнал внимания, поэтому обычный текст, а не «кружочек». */
.title-meta {
  color: var(--color-text-muted);
  font-weight: var(--weight-accent);
}

.filter-bar,
.form-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--space-3);
  align-items: end;
}

.filter-bar {
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
}

.filter-bar--orders {
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
  padding-block: var(--space-3);
  align-items: end;
}

/* Блок вторичных фильтров (заявки, доставки, сотрудники). `<details>` приходит
   свёрнутым прямо в SSR-разметке; с активными фильтрами сервер отдаёт его
   раскрытым, чтобы человек видел, что список отфильтрован. Скрипт состояние
   не трогает — раньше он схлопывал блок после загрузки, и страница дёргалась.
   Подпись видна на всех ширинах, поэтому свёрнутый блок никогда не заперт и
   без JavaScript. */
.filter-collapsible {
  margin: 0;
  min-width: 0;
}

.filter-collapsible__summary {
  display: flex;
  align-items: center;
  min-height: 42px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  font-weight: var(--weight-accent);
  cursor: pointer;
}

/* Chevron keeps the collapsed state discoverable; the light rotation is the
   only motion on the disclosure (no measured-height animation). */
.filter-collapsible__summary::after {
  content: "";
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--motion-duration) ease;
  margin-left: auto;
}

.filter-collapsible[open] > .filter-collapsible__summary::after {
  transform: rotate(225deg);
}

.filter-collapsible__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
  align-items: end;
  margin-top: var(--space-2);
  min-width: 0;
}

.filter-collapsible__body > .field,
.filter-collapsible__body > .filter-size,
.filter-collapsible__body .input,
.filter-collapsible__body .select {
  min-width: 0;
  max-width: 100%;
}

.filter-collapsible__body > .field,
.filter-collapsible__body > .filter-size {
  grid-column: auto;
}

/* The explicit GET submit is the SSR/no-JS fallback. Hide it only after this
   specific form has completed its live-search initialization. */
[data-live-search-form][data-live-search-ready="true"] [data-live-search-fallback] {
  display: none;
}

@media (min-width: 920px) { /* shell и выше: десктопная оболочка */
  .filter-bar--orders {
    grid-template-columns: minmax(260px, 1fr) minmax(140px, 170px) auto;
    align-items: end;
  }

  /* Cap the search field so it does not stretch across the full width on
     wide desktop. The column above still grows (1fr), but the input itself
     stops at a comfortable reading width, keeping the row compact and the
     sort/actions beside it rather than pushed to the far edge. */
  .filter-bar--orders > .filter-field--orders-search .input {
    max-width: 420px;
  }

  /* Primary controls fill the first row; the disclosure spans the full width
     below it. The summary stays visible so the collapsed state reclaims the
     workspace while every filter remains one click away. */
  .filter-bar--orders > .filter-collapsible {
    grid-column: 1 / -1;
  }

  .filter-collapsible > .filter-collapsible__summary {
    width: fit-content;
    min-height: 36px;
    padding: var(--space-1) var(--space-3);
  }

  .filter-collapsible__body {
    margin-top: 0;
  }

  .filter-bar--orders .filter-collapsible__body {
    grid-template-columns: repeat(8, minmax(0, 1fr));
  }

  .filter-collapsible__body > .filter-field,
  .filter-collapsible__body > .filter-size,
  .filter-collapsible__body > .filter-field:first-child {
    grid-column: auto;
    min-width: 0;
  }
}

/* Deliveries keeps the permanently visible search row (search + Reset) and
   moves every secondary filter into the shared collapsible disclosure below
   it, mirroring the Orders filter-bar contract. */
.filter-bar--deliveries {
  grid-template-columns: minmax(260px, 1fr) auto;
  gap: var(--space-2);
  padding-block: var(--space-3);
  align-items: end;
}

.filter-bar--deliveries > .filter-collapsible {
  grid-column: 1 / -1;
}

@media (min-width: 920px) { /* shell и выше */
  .filter-bar--deliveries {
    grid-template-columns: minmax(260px, 420px) auto minmax(0, 1fr);
  }

  .filter-bar--deliveries .filter-collapsible__body {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-3);
  }
}

.filter-bar--routes {
  grid-template-columns:
    minmax(260px, 1fr)
    minmax(140px, 170px)
    minmax(180px, 220px)
    minmax(120px, 150px)
    minmax(92px, 110px)
    auto;
  gap: var(--space-2);
  padding-block: var(--space-3);
  align-items: end;
}

.filter-bar--deliveries > .filter-field,
.filter-bar--deliveries > .filter-size,
.filter-bar--deliveries > .filter-actions {
  grid-column: auto;
}

.filter-bar--orders > .filter-field,
.filter-bar--orders > .filter-size,
.filter-bar--orders > .filter-actions {
  grid-column: auto;
}

.filter-bar--routes > .filter-field,
.filter-bar--routes > .filter-size,
.filter-bar--routes > .filter-actions {
  grid-column: auto;
}

.filter-bar--orders > .filter-field:first-child {
  grid-column: auto;
}

.filter-bar--deliveries > .filter-field:first-child {
  grid-column: auto;
}

.filter-bar--routes > .filter-field:first-child {
  grid-column: auto;
}

.filter-field--deliveries-search {
  min-width: 0;
}

.filter-field--orders-search,
.filter-field--orders-sort,
.filter-field--orders-direction,
.filter-field--orders-status,
.filter-field--orders-payment,
.filter-size--orders {
  min-width: 0;
}

.filter-bar--orders > .filter-field--orders-search:first-child,
.filter-bar--orders > .filter-field--orders-sort,
.filter-bar--orders > .filter-field--orders-direction,
.filter-bar--orders > .filter-field--orders-status,
.filter-bar--orders > .filter-field--orders-payment,
.filter-bar--orders > .filter-size--orders {
  grid-column: auto;
}

.filter-field--routes-search,
.filter-field--routes-org,
.filter-field--routes-direction,
.filter-field--routes-delivery,
.filter-size--routes {
  min-width: 0;
}

.filter-field--deliveries-org,
.filter-field--deliveries-status,
.filter-field--deliveries-zone,
.filter-field--deliveries-courier,
.filter-size--deliveries {
  min-width: 0;
}

.filter-bar--deliveries .field > span {
  line-height: 1.2;
}

.filter-bar--orders .field > span {
  line-height: 1.2;
}

.filter-bar--routes .field > span {
  line-height: 1.2;
}

.filter-bar--orders .input,
.filter-bar--orders .select,
.filter-bar--orders .btn {
  min-height: 42px;
}

.filter-bar--deliveries .input,
.filter-bar--deliveries .select,
.filter-bar--deliveries .btn {
  min-height: 42px;
}

.filter-bar--routes .input,
.filter-bar--routes .select,
.filter-bar--routes .btn {
  min-height: 42px;
}

/* Employees follows the incumbent Orders/Deliveries filter-bar contract:
   search + sorting + actions stay always visible in one compact row; every
   secondary filter lives in the shared collapsible disclosure below, which a
   small JS enhancement collapses when idle and active filters pin open. This
   keeps the phone toolbar dense without dropping or shrinking any filter. */
.filter-bar--employees {
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
  padding-block: var(--space-3);
  align-items: end;
  width: 100%;
  max-width: 1680px;
}

.filter-bar--employees > .filter-field,
.filter-bar--employees > .filter-actions {
  grid-column: auto;
  min-width: 0;
}

/* The generic ``.filter-field:first-child { span 3 }`` base rule would win the
   cascade for the search field (equal specificity, later source order); the
   explicit :first-child qualifier mirrors the incumbent Orders override so the
   search label occupies exactly one track of the toolbar row. */
.filter-bar--employees > .filter-field--employees-search:first-child,
.filter-bar--employees > .filter-field--employees-sort {
  grid-column: auto;
}

.filter-field--employees-search,
.filter-field--employees-org,
.filter-field--employees-type,
.filter-field--employees-position,
.filter-field--employees-workplace,
.filter-field--employees-status,
.filter-field--employees-sort,
.filter-size--employees {
  min-width: 0;
}

.filter-bar--employees .field > span {
  line-height: 1.2;
}

.filter-bar--employees .input,
.filter-bar--employees .select,
.filter-bar--employees .btn {
  min-height: 42px;
}

.filter-actions--employees {
  justify-content: flex-start;
  min-width: 0;
}

.filter-actions--employees .btn {
  padding-inline: var(--space-3);
  white-space: nowrap;
}

.filter-bar--employees > .filter-collapsible {
  grid-column: 1 / -1;
}

@media (min-width: 920px) { /* shell и выше */
  .filter-bar--employees {
    grid-template-columns: minmax(260px, 1fr) minmax(140px, 170px) auto;
    align-items: end;
  }

  /* Bound the search field like Orders so the always-visible row stays
     compact on wide desktops. */
  .filter-bar--employees > .filter-field--employees-search .input {
    max-width: 420px;
  }

  .filter-bar--employees > .filter-field--employees-sort {
    grid-column: auto;
  }

  .filter-bar--employees .filter-collapsible__body {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: var(--space-3);
  }
}

/* Клиенты. Заказчик 03.09 просила поставить «Сбросить» вплотную к строке
   поиска, «к крестику». В общей двенадцатиколоночной сетке кнопка живёт в
   собственной ячейке: на десктопе она отделена от поля пустым треком, а ниже
   920px общее правило раскидывает поле и кнопку на две строки — то есть ровно
   «не около поиска». Здесь ряд собирается флексом из двух элементов, поэтому
   кнопка держится у поля на всех вьюпортах. Ширина поиска ограничена тем же
   потолком 420px, что в Заявках и Сотрудниках. Крестик рисует сам браузер
   внутри input — он не трогается. */
.filter-bar--clients {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--space-3);
}

/* Базис 200px — измеренный порог: строка фильтров отдаёт полю 333px при
   375px экрана и 318px при 360px. С 05.09 в группе действий две кнопки —
   «Сбросить» и «Новый клиент» (заказчик попросила перенести её из шапки к
   строке поиска, кадр 31 пака 2026-09-03), и на телефонах (замерено 390 и
   430 px) flex-wrap опускает пару кнопок одной строкой под поле, а галочку —
   строкой ниже. От 768 px поле, обе кнопки и галочка стоят в один ряд.
   Горизонтальной прокрутки нет ни на одной ширине. */
.filter-bar--clients > .filter-field--clients-search {
  flex: 1 1 200px;
  min-width: 0;
  max-width: 420px;
}

.filter-actions--clients {
  flex: 0 0 auto;
  justify-content: flex-start;
  min-width: 0;
}

.filter-actions--clients .btn {
  padding-inline: var(--space-3);
  white-space: nowrap;
}

/* «Показать скрытых» — третий трек той же строки фильтров: поле, «Сбросить»,
   галочка. Она не растягивается и не переносит подпись. Замерено: от 1366 до
   768 px все три стоят в один ряд; между 640 и 560 px flex-wrap роняет галочку
   на свою строку, и дальше вниз до 320 px она там и остаётся. Горизонтальной
   прокрутки нет ни на одной из этих ширин. */
.filter-field--clients-hidden,
.filter-field--show-hidden {
  flex: 0 0 auto;
  /* Ряд фильтров выровнен по низу (`align-items: end`), и поле с кнопкой
     заканчиваются на одной линии. Галочка ниже их по высоте, поэтому она
     садится на ту же линию и отступает вверх ровно настолько, чтобы её
     середина совпала с серединой соседних контролов: (40 − 24) / 2 = 8px. */
  align-self: end;
  margin-block-end: 8px;
  white-space: nowrap;
}

/* В сеточной строке фильтров (Архив) галочка «Показать скрытые» и её кнопка —
   такие же элементы двенадцатиколоночной сетки, как поля и блок действий, и
   долю в ней нужно назвать явно. Без этого галочке доставались два трека при
   нужных 172 px, а кнопке — вообще один (18 px на 390 px): подпись «Показать»
   не помещалась и рисовалась поверх подписи галочки. Три трека покрывают
   «Показать скрытые» с 920 px и выше, два — «Показать»; ниже оболочки оба
   уходят на целую строку вместе с остальными детьми строки фильтров.
   Свойство `flex` выше действует только во флексовой строке фильтров
   клиентов, в сетке оно ничего не значит. */
.filter-bar > .filter-field--show-hidden {
  grid-column: span 3;
}

.filter-bar > .filter-submit--nojs {
  grid-column: span 2;
}

.filter-field--show-hidden input {
  flex: 0 0 auto;
}

.filter-submit--nojs {
  flex: 0 0 auto;
  padding-inline: var(--space-3);
  white-space: nowrap;
}

/* Кнопка «Показать» нужна только без JavaScript: с ним список обновляется от
   самой галочки, как от списка или даты (см. app.js, live search). */
html[data-app-ready] .filter-submit--nojs {
  display: none;
}

/* «Скрыть клиента» — «кнопка маленькая в сторонке» её словами: тот же ряд, но
   отодвинута вправо от «Сохранить изменения» и «Назад к списку», чтобы не
   читаться как ещё одно обычное действие карточки. */
.form-actions.client-card-actions .client-hide-button {
  margin-inline-start: auto;
  /* На телефоне общий ряд действий раздаёт кнопкам `flex: 1 1 auto`, и третья
     кнопка, попадая на свою строку, растягивалась во всю ширину — читалась как
     главное действие карточки. Заказчик просила «кнопка маленькая в сторонке»,
     поэтому эта не растягивается ни на одном экране: она остаётся по
     содержимому и уходит вправо. Селектор берёт оба класса ряда намеренно:
     мобильное правило `.form-actions .btn` идёт в файле ниже и при равной
     специфичности выигрывало бы. */
  flex: 0 0 auto;
}

/* Карточка и форма сотрудника делятся на три зоны (заказчик, пак 2026-09-01,
   скриншот 05): человек — работа — доступ к CRM. Прежний потолок 1120px
   оставлял пустые поля по бокам и уводил содержимое вниз. */
.order-form.employee-form {
  max-width: none;
}

.employee-form-zones {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4);
  align-items: start;
  min-width: 0;
}

/* Три равные трети формы не соответствуют её содержимому: в правой зоне один
   селект, а в левой при 391px обрезались дата рождения, гражданство и оба
   адреса (адрес проживания требует 435px при доступных 357px). Это ровно
   замечание заказчика про пустые поля по бокам, только вывернутое. Доли
   выровнены по измеренной потребности зон: при 1280px левая получает ~481px
   (адрес проживания — 435px), средняя ~403px (марка и модель авто — 355px),
   правая ~290px (селект логина курьера — 244px, он виден при категории
   «Курьер» и без JavaScript). У каждой зоны остаётся ~12px запаса. */
.employee-form-zones {
  grid-template-columns:
    minmax(0, 1.23fr)
    minmax(0, 1.03fr)
    minmax(0, 0.74fr);
}

.employee-zone {
  display: grid;
  align-content: start;
  gap: var(--space-4);
  min-width: 0;
}

/* Вход курьера — вложенный блок зоны доступа: JS скрывает именно его при смене
   категории, поэтому он остаётся отдельным узлом, а не отдельной секцией. */
.employee-courier-access {
  display: grid;
  gap: var(--space-2);
  min-width: 0;
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}

.employee-courier-access h3 {
  color: var(--color-ink);
  font-size: var(--text-base);
}

.employee-phone-list {
  display: grid;
  gap: var(--space-3);
  max-width: 760px;
}

.employee-phone-list__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.employee-phone-list__head h3 {
  color: var(--color-ink);
  font-size: var(--text-base);
}

.employee-phone-rows {
  display: grid;
  gap: var(--space-2);
}

.employee-phone-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: var(--space-3);
  min-width: 0;
}

.employee-phone-row__number {
  min-width: 0;
}

.employee-phone-row__active,
.employee-trailer-check {
  min-height: 42px;
  padding-block: var(--space-2);
}

.employee-detail-values dd,
.employee-detail-values dt {
  min-width: 0;
  overflow-wrap: anywhere;
}

.filter-field {
  grid-column: span 2;
}

.filter-field:first-child {
  grid-column: span 3;
}

.filter-field--wide {
  grid-column: span 5;
}

.filter-size {
  grid-column: span 3;
}

.filter-actions {
  grid-column: span 2;
  display: flex;
  gap: var(--space-2);
  align-items: flex-end;
  justify-content: flex-start;
}

.filter-bar--orders > .filter-actions--orders {
  grid-column: auto;
  justify-content: flex-start;
  min-width: 0;
}

.filter-actions--deliveries {
  justify-content: flex-start;
  min-width: 0;
}

.filter-actions--routes {
  justify-content: flex-start;
  min-width: 0;
}

.filter-actions--deliveries .btn {
  padding-inline: var(--space-3);
  white-space: nowrap;
}

.filter-actions--orders .btn {
  padding-inline: var(--space-3);
  white-space: nowrap;
}

.filter-actions--routes .btn {
  padding-inline: var(--space-3);
  white-space: nowrap;
}

/* Две строки счётчиков переносятся, а не наезжают друг на друга: на 390 px
   «Показано 1–14 из 14» и «Всего: 14 · …» без зазора и переноса читались
   как «Показано 1–14Всего: 14 ·» (снимки 2026-09-06). Зазор — минимум
   между ними и на десктопе, где `space-between` разводит их и так; перенос
   срабатывает только когда обе не помещаются. */
.list-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-3);
  color: var(--color-text-muted);
  font-weight: var(--weight-strong);
  padding: var(--space-2) var(--space-5);
}

.list-meta--deliveries {
  gap: var(--space-3);
  flex-wrap: wrap;
}

.list-meta--routes {
  gap: var(--space-3);
  flex-wrap: wrap;
}

.list-meta--deliveries .money-visibility-note {
  margin-left: auto;
  text-align: right;
}

.list-meta--routes .money-visibility-note {
  margin-left: auto;
  text-align: right;
}

.bulk-action-form {
  display: grid;
  gap: 0;
}

.bulk-action-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-5);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-strong);
}

.bulk-action-bar[hidden] {
  display: none;
}

.bulk-check {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-strong);
}

.bulk-check input {
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: var(--color-accent);
}

.bulk-check--card {
  min-height: 34px;
  padding-inline: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

.inline-action-form {
  display: contents;
}

/* Finance surfaces (/cash, /payment, /payment/orders/{id}).
   These mirror the shared list/table language (see .orders-table-wrap,
   .orders-table) so finance reads as the same product, without a parallel
   finance-only design system. Local horizontal scrolling lives inside
   .table-wrap so the page itself never scrolls horizontally. */
.balance-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-4);
}

.balance-tile {
  display: grid;
  gap: var(--space-2);
  min-width: 0;
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.balance-tile__currency {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.balance-tile__amount {
  color: var(--color-ink);
  font-size: var(--text-xl);
  font-weight: var(--weight-heading);
  line-height: var(--leading-tight);
  overflow-wrap: anywhere;
}

.balance-tile__hint {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

.balance-tile--negative {
  border-color: rgb(225 29 72 / 0.45);
  background: rgb(225 29 72 / 0.06);
}

.balance-tile--negative .balance-tile__amount {
  color: var(--color-danger);
}

.balance-tiles--cash {
  grid-template-columns: repeat(2, minmax(150px, 220px));
  gap: 0;
  padding: var(--space-2) var(--space-5);
  border-bottom: 1px solid var(--color-border);
}

.balance-tiles--cash .balance-tile {
  gap: var(--space-1);
  padding: var(--space-1) var(--space-4);
  border: 0;
  border-left: 1px solid var(--color-border);
  border-radius: 0;
  background: transparent;
}

.balance-tiles--cash .balance-tile:first-child {
  padding-left: 0;
  border-left: 0;
}

.balance-tiles--cash .balance-tile__amount {
  font-size: var(--text-lg);
}

.filter-bar--finance {
  gap: var(--space-2);
  padding-block: var(--space-3);
  align-items: end;
}

.filter-bar--finance .input,
.filter-bar--finance .select,
.filter-bar--finance .btn {
  min-height: 42px;
}

.filter-actions--finance {
  min-width: 0;
}

.filter-actions--finance .btn {
  padding-inline: var(--space-3);
  white-space: nowrap;
}

/* Обёртка живого поиска «Кассы» и «Платежа» — ячейка сетки `.screen`.
   Без `min-width: 0` она растягивается по ширине таблицы, а с ней и строка
   фильтров: на телефоне «Способ», «С даты» и «Отменить» уходили за край
   панели (F-04, аудит 26.09). С ней таблица листается вбок внутри
   `.table-wrap`. */
.finance-results {
  min-width: 0;
}

@media (min-width: 920px) { /* shell и выше */
  .filter-bar--payments {
    grid-template-columns:
      minmax(210px, 300px)
      repeat(3, minmax(105px, 150px))
      repeat(2, minmax(135px, 170px))
      auto;
    justify-content: start;
  }

  .filter-bar--cash {
    grid-template-columns:
      repeat(3, minmax(130px, 180px))
      repeat(2, minmax(150px, 190px))
      auto;
    justify-content: start;
  }

  .filter-bar--finance > .filter-field,
  .filter-bar--finance > .filter-field:first-child,
  .filter-bar--finance > .filter-actions {
    grid-column: auto;
    min-width: 0;
  }
}

.table-wrap {
  width: 100%;
  overflow-x: auto;
  border-block: 1px solid var(--color-border);
  background: var(--color-surface);
}

.data-table {
  width: 100%;
  min-width: 720px;
  border-collapse: collapse;
}

.data-table th,
.data-table td {
  padding: 9px var(--space-3);
  border-bottom: 1px solid var(--color-border);
  text-align: left;
  vertical-align: top;
}

.data-table th {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
  text-transform: uppercase;
  white-space: nowrap;
}

.data-table tr:last-child td {
  border-bottom: 0;
}

.payment-order-body {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5) var(--space-5);
}

.payment-order-overview {
  display: grid;
  grid-template-columns: minmax(240px, 320px) minmax(0, 1fr);
  gap: var(--space-3);
  align-items: stretch;
}

.payment-order-overview > .detail-panel {
  align-self: stretch;
}

.payment-order-overview > .detail-panel:only-child {
  grid-column: 1 / -1;
  width: min(100%, 520px);
}

.payment-order-costs {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
}

.payment-order-costs__item {
  padding-block: var(--space-1);
}

.payment-order-costs__item dd {
  font-size: var(--text-base);
}

/* Per-order payment conduct block. The submitted native select and hidden
   currency stay unchanged; only their visual grouping and desktop measure are
   constrained so the finance action reads as one compact operation. */
.payment-conduct-row {
  display: grid;
  grid-template-columns: minmax(150px, 180px) minmax(200px, 240px) auto;
  align-items: flex-end;
  justify-content: start;
  gap: var(--space-3);
}

.payment-conduct-amount {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.payment-conduct-amount > span {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-accent);
}

.payment-conduct-amount > strong {
  min-height: 42px;
  display: inline-flex;
  align-items: center;
  padding-inline: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface-soft);
  color: var(--color-ink);
  font-size: var(--text-base);
  white-space: nowrap;
}

.payment-method-field {
  width: 100%;
}

.payment-conduct-form + .payment-conduct-form {
  margin-top: var(--space-3);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}

.orders-table-wrap {
  width: 100%;
  overflow-x: auto;
  border-block: 1px solid var(--color-border);
  background: var(--color-surface);
}

.orders-table {
  width: 100%;
  min-width: 1060px;
  border-collapse: collapse;
}

.orders-list-table {
  min-width: 0;
  table-layout: fixed;
}

/* B6 Route assignment tables render full-width under the Route detail panel.
   They must not inherit the shared 1060px orders-table floor, which forces
   inner horizontal scroll inside the panel. */
.routes-assigned-table,
.routes-candidates-table {
  min-width: 0;
}

/* Список заявок маршрута (пак 2026-09-03, п. 29): числовые колонки не
   переносятся, длинные адреса и ФИО — переносятся.

   РАСКЛАДКА ФИКСИРОВАННАЯ с 2026-09-12. Автоматическая раздавала ширину по
   длине содержимого, и на карточке рейса получалось ровно наоборот тому, что
   читает логист: «Клиент» 226 px, «Груз» 127 px, «Адрес» 142 px на 1366 и
   «Клиент» 416 px против «Груз» 301 / «Адрес» 319 на 1920; слова рвались
   посреди слова («Запчас/ти на/поддон/е», «пр-т Дзержинск/ого»). Причина —
   `overflow-wrap: anywhere` ниже: он опускает минимум колонки до одного знака,
   и автораскладка спокойно сжимала груз и адрес в пользу длинных ФИО
   (сплошной проход 2026-09-12, волна 1, находка 2).

   Доли привязаны к КЛАССАМ колонок, а не к `nth-child`: три колонки
   условные — «Снять» (право на состав), «Дата забора» (настройка юрлица
   МАРШРУТА) и «Порядок» (заданный ключ сортировки), — и позиционные
   селекторы съезжали бы. Сумма всех двенадцати ровно 100 %; когда условной
   колонки нет, объявленная сумма меньше 100 % и браузер поднимает оставшиеся
   пропорционально — лишнего остатка, который в автораскладке уходил
   «Выбору», здесь не возникает.

   Доли выверены по содержимому на 1280 px — самой узкой ширине, где таблица
   рисуется (ниже — карточки); таблица там 1172 px. Мерилом служит выход за
   границу ячейки: содержимое плюс левый отступ 12 px не шире колонки.
   «Снять» — ряд «× + галочка» без JavaScript (60 px), «Заявка» —
   восьмизначный номер моноширинным (67 px), «Дата забора» — неразрывное
   «13.09.2026» (71 px), «Вес, кг» — вес в семь знаков из широких цифр
   («99999,9», 58 px), «Доставить до» — слово заголовка «ДОСТАВИТЬ» (81 px).
   Минимумы закреплены тестом `tests/test_route_assignments.py`. Вес в восемь
   знаков с тремя знаками после запятой («8888,888», 67 px) на 1280 заходит в
   левый отступ соседней ячейки на 3 px — брать место не у кого.

   Заголовки ПЕРЕНОСЯТСЯ по словам, как в списке заявок: при фиксированной
   раскладке неразрывный заголовок не расширяет колонку, а ложится поверх
   соседнего — «ДОСТАВИТЬ ДО» сливался с «АДРЕС» на 1280 и 1366 (независимое
   ревью 2026-09-13; «Вес, кг», «Мест», «Объём, м³» и «Дата забора» — туда же).
   Одиночное слово заголовка держит своя доля. */
.routes-assigned-table {
  table-layout: fixed;
}

.routes-assigned-table thead th,
.routes-assigned-table thead th.num {
  line-height: 1.25;
  white-space: normal;
  overflow-wrap: normal;
  word-break: keep-all;
}

.routes-assigned-table .assigned-col-remove {
  width: 6.5%;
}

.routes-assigned-table .assigned-col-index {
  width: 3.5%;
}

.routes-assigned-table .assigned-col-pickup {
  width: 7.5%;
}

.routes-assigned-table .assigned-col-order {
  width: 7.5%;
}

.routes-assigned-table .assigned-col-cargo {
  width: 14%;
}

.routes-assigned-table .assigned-col-weight {
  width: 6.5%;
}

.routes-assigned-table .assigned-col-places {
  width: 4.5%;
}

.routes-assigned-table .assigned-col-volume {
  width: 6.5%;
}

.routes-assigned-table .assigned-col-client {
  width: 13.5%;
}

.routes-assigned-table .assigned-col-zone {
  width: 8.5%;
}

.routes-assigned-table .assigned-col-address {
  width: 14%;
}

.routes-assigned-table .num {
  white-space: nowrap;
}

/* Колонка «Дата забора» в обоих списках заявок маршрута. Не `.num`: дата — не
   число, и правое выравнивание числовых колонок ей не нужно. Нужна ей только
   неразрывность — иначе «07.09.2026» рвётся по точкам и колонка прыгает по
   ширине от строки к строке. Ширина по содержимому: раскладка этих таблиц
   автоматическая. */
.date-col {
  white-space: nowrap;
}

/* `anywhere`, а не `break-word`, — та же причина, что у списка заявок ниже:
   `break-word` НЕ уменьшает min-content, а стопка `.cell-stack` внутри ячейки
   состоит из grid-элементов, которые ниже своего min-content не сжимаются.
   Замерено на этой же таблице: с `break-word` ФИО «ООО „Северо-Западная
   Транспортно-Экспедиционная Компания…"» вылезало из колонки «Клиент» на 27 px
   поверх соседней. Переносы посреди слова, ради которых `break-word`
   пробовался, лечатся не этим, а долями колонок выше: при «Грузе» 176 px
   вместо 127 и «Адресе» 176 вместо 142 рвать уже нечего. */
.routes-assigned-table td {
  overflow-wrap: anywhere;
}

/* Номер заявки и телефон не рвутся по дефисам ради ширины соседей: их длина
   задаёт минимум своей колонки, лишнее уходит адресу и грузу. */
.routes-assigned-table td .mono {
  white-space: nowrap;
}

.route-row-controls {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

/* «Порядок» — ручной ключ сортировки строк маршрута (колонка «№» карточки
   рейса старой CRM, у них 60 px). Поле на четыре цифры; значение числовое,
   поэтому по правому краю, как вес и места рядом. Колонка по содержимому и не
   переносится. */
.route-position-col {
  width: 1%;
  white-space: nowrap;
  text-align: right;
}

/* В списке заявок маршрута раскладка фиксированная, и «по содержимому» (1 %)
   там означало бы колонку в один процент: поле на четыре цифры — 56 px,
   слово заголовка «ПОРЯДОК» — 65 px. 7,5 % дают 88 px на 1172 px таблицы при 1280.
   В таблице кандидатов раскладка осталась автоматической, и правило выше
   продолжает работать как прежде. */
.routes-assigned-table .route-position-col {
  width: 7.5%;
}

.route-position-input {
  width: 4em;
  padding: 6px 8px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Одна кнопка «Сохранить порядок» на всю таблицу, под ней; у карточек — после
   последней карточки. Подсказка говорит, что значение делает. */
.route-positions-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-3) var(--space-5);
  border-top: 1px solid var(--color-border);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

.route-positions-bar__hint {
  min-width: 0;
  flex: 1 1 16rem;
}

/* В раскладке карточек (до 1280 px) панель липнет к низу экрана: на рейсе в
   полторы сотни строк кнопка под последней карточкой стояла за девяносто
   тысяч пикселей прокрутки. `position: sticky; bottom: 0` — без JavaScript и
   без изменения формы: панель остаётся последним потомком списка карточек и
   встаёт на своё место, когда список прокручен до конца. Непрозрачный фон —
   чтобы карточки не просвечивали под кнопкой. Подсказка в карточках стоит
   перед списком (`.route-positions-hint`), в липкой панели — только кнопка. */
.route-positions-hint {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

.orders-cards > .route-positions-bar {
  position: sticky;
  bottom: 0;
  z-index: 2;
  margin-inline: calc(-1 * var(--space-5));
  padding: var(--space-3) var(--space-5);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface);
}

/* В раскладке таблицы панель липнет так же. Она стоит следующей за
   `.orders-table-wrap`, а не внутри неё: обёртка прокручивается по
   горизонтали и потому сама является контейнером прокрутки — липкий элемент
   внутри неё липнет к ней, а не к экрану. Своя верхняя черта нужна: пока
   панель висит над списком, нижней границы обёртки рядом нет. В покое, когда
   панель встала на своё место под таблицей, эти две черты совпали бы в одну
   двойную — поэтому панель поднята на свой же пиксель (`margin-top: -1px`) и
   черта остаётся одна в обоих положениях. Ниже 1280 px таблица скрыта, и
   панель скрыта вместе с ней. */
.route-positions-bar--table {
  position: sticky;
  bottom: 0;
  z-index: 2;
  margin-top: -1px;
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface);
}

/* `.panel` обрезает содержимое через `overflow: hidden`, а это делает панель
   контейнером прокрутки: липкий элемент внутри липнет к панели, которая не
   прокручивается, и не липнет ни к чему. `overflow: clip` обрезает так же
   (в том числе по скруглению), но контейнера прокрутки не создаёт — липкая
   панель порядка держится за экран. Только карточка маршрута: остальные
   панели не трогаются. Где `clip` не поддержан, остаётся `hidden`. */
.route-card-panel {
  overflow: hidden;
  overflow: clip;
}

/* Режим «Выбрать несколько». По умолчанию у строки только крестик; в режиме
   выбора — только галочка, а внизу кнопка снятия выбранных. Режим включает
   кнопка на панели заявок (атрибут на панели переживает подмену списка живым
   поиском). Без JavaScript кнопки нет, поэтому галочки, крестики и кнопка
   снятия видны всегда — путь без JS остаётся полным. */
html[data-app-ready] [data-route-selection-scope]:not([data-route-selecting]) .route-select-check,
html[data-app-ready] [data-route-selection-scope]:not([data-route-selecting]) .route-selection-form .bulk-action-bar {
  display: none;
}

html[data-app-ready] [data-route-selection-scope][data-route-selecting] .route-remove-one {
  display: none;
}

html:not([data-app-ready]) [data-route-select-toggle] {
  display: none;
}

[data-route-select-toggle][aria-pressed="true"] {
  border-color: var(--color-ink);
  background: var(--color-surface-muted);
}

/* Бюджет ширин списка заявок, пересчитан 2026-09-08 под КОРОТКИЙ номер
   заявки. Десять колонок данных, одиннадцать с колонкой выбора.

   Что изменилось. До 08.09 номер заявки был техническим — 26 знаков
   (`KRIPVZ-260904130307-21D5FD`, 219 px одной строкой), и «Номер» держал под
   него самую большую долю бюджета: 231,9 px на 1366 и 234,3 px на 1280.
   Короткий номер (`001-0042`, ревизия `20260908_0026`) — всегда ровно восемь
   знаков и всегда 67,4 px; формат `999-9999` закрыт сверху самой нумерацией
   (`app/services/order_numbers.py`), длиннее номер не станет. Доля под него
   больше не нужна: колонка стала ФИКСИРОВАННОЙ, как «Выбор», и освободила
   ~136 px на 1366 и ~240 px на 1920 в пользу колонок, которые рвались.

   Отсюда же устройство файла: доли считаются от ширины, оставшейся после
   ДВУХ фиксированных колонок, и потому одни и те же в обоих вариантах
   таблицы — с колонкой выбора и без неё. Прежние два параллельных набора
   `nth-child` (и третий, переопределявший три доли от 1366 px) сведены в один
   набор КЛАССОВ: `nth-child` съезжал на единицу от наличия «Выбора», и каждое
   изменение состава колонок приходилось вносить дважды. Классы стоят на
   `<th>` — при `table-layout: fixed` ширину колонки задаёт первая строка.

   Минимумы, ниже которых слово рвётся посреди себя (замер в браузере
   2026-09-08 на стенде, отступ ячейки 2 × var(--space-1) = 8 px):
   «Номер» 75,4 px (восемь знаков моноширинным `--text-sm`),
   «Выбор» 89 px (галочка 18 px + зазор + слово «Выбрать»),
   «Наименование груза» 114 px и «Направление» 100 px (их заголовки —
   формулировки заказчика от 05.07, сокращать нельзя), «Действия» 125 px
   («Редактировать» 109 px при левом отступе колонки 12 px),
   «Стоимость» 92 px (заголовок), «Статус» 78 px («курьера» внутри бейджа) и
   «Оплата» 87 px («Оплачено» там же), «Комментарий» 108 px (заголовок;
   до 08.09 он был сокращён до «Коммент.» ровно потому, что полного слова
   бюджет не выдерживал), «Клиент» 60 px (заголовок).

   Доли выбраны так, чтобы на 1280 px — самой узкой ширине, где таблица вообще
   рисуется (ниже неё `.orders-table-wrap` скрыт и работают карточки), — ни
   одна колонка не опускалась ниже своего минимума, а прибавка доставалась
   пяти текстовым колонкам: «Клиент», «Наименование груза», «Направление»,
   «Доставка» и «Комментарий». Отдала место одна «Действия» (152,9 → 137,3 на
   1366), и у неё остаётся 12 px запаса. «Оплата» и «Статус» подняты ровно
   настолько, чтобы «Не оплачено» и «У курьера» встали в одну строку на 1366 и
   выше; на 1280 «Не оплачено» по-прежнему в две — одной строкой ему там нужно
   105 px при доступных 99,4, и брать их больше не у кого. Ширина каждой колонки до и после, на 1366, 1440
   и 1920, — в `references/customer-feedback/CRM3_FEEDBACK_VERIFICATION_2026-09-08.md`,
   раздел «Волна 4». */
/* Колонка выбора держит фиксированный контрол (18 px галочка + зазор +
   «Выбрать»). Доля не удерживала его на 1280–1440: подпись выходила в «Номер»,
   поэтому ширина в пикселях. С отступом ячейки var(--space-1) контролу нужно
   89 px (81 px самого контрола с веб-шрифтом плюс отступ); 92 px — это плюс
   запас, ровно как прежние 104 px при отступе var(--space-2). */
.orders-list-table .orders-col-select {
  width: 92px;
}

/* Номер заявки: фиксированная ширина, а не доля. Содержимое ячейки — только
   ссылка с номером, и его ширина известна и постоянна (67,4 px). 96 px — это
   она плюс отступ ячейки 8 px плюс запас на смену шрифта; на всех ширинах от
   1280 до 1920 колонка одна и та же, потому что расти ей не на что. */
.orders-list-table .orders-col-no {
  width: 96px;
}

.orders-list-table .orders-col-client {
  width: 12%;
}

.orders-list-table .orders-col-cargo {
  width: 12.7%;
}

.orders-list-table .orders-col-direction {
  width: 10.4%;
}

.orders-list-table .orders-col-status {
  width: 8.2%;
}

.orders-list-table .orders-col-delivery {
  width: 13.1%;
}

.orders-list-table .orders-col-comment {
  width: 13.2%;
}

.orders-list-table .orders-col-payment {
  width: 9.4%;
}

.orders-list-table .orders-col-cost {
  width: 9%;
}

.orders-list-table .orders-col-actions {
  width: 12%;
}

/* Та же мера как класс: таблицы назначения на маршрут помечают свой заголовок
   выбора `.select-col`, и у них раскладка `auto` — здесь это нижняя граница
   колонки, а не точная ширина. Список заявок перебивает её своим классом
   выше: у него раскладка `fixed` и своя, меньшая мера. */
.select-col {
  width: 116px;
}

/* Кандидаты на «Добавить заявки» — своя таблица: восемь колонок (с 04.09
   добавилась «Дата забора» второй) и раскладка `auto`, поэтому доли работают
   как нижняя граница. Доли привязаны к КЛАССАМ колонок, а не к `nth-child`:
   с 05.09 «Дата забора» может не рисоваться вовсе (юрлицо со скрытым блоком
   «Забор груза» и ни одной заявки с сохранённым забором), и позиционные
   селекторы съезжали бы на одну колонку — ровно тот дефект, который в этой
   таблице уже был 04.09, когда «Статус» остался без доли и забирал ~415 px
   на 1280, а номер заявки ломался на три строки. */
.routes-candidates-table .candidates-col-pickup {
  width: 9%;
}

.routes-candidates-table .candidates-col-order {
  width: 17%;
}

.routes-candidates-table .candidates-col-org {
  width: 8%;
}

.routes-candidates-table .candidates-col-cargo {
  width: 14%;
}

.routes-candidates-table .candidates-col-client {
  width: 14%;
}

.routes-candidates-table .candidates-col-delivery {
  width: 16%;
}

.routes-candidates-table .candidates-col-status {
  width: 10%;
}

/* Без колонки «Дата забора» её доля должна достаться СОДЕРЖАТЕЛЬНЫМ колонкам.
   Раскладка таблицы автоматическая, и незаявленный остаток уходит
   единственной колонке без доли — «Выбору»: при снятой колонке забора он
   раздувался со 114 до 230 px на 1280 и до 396 px на 1920, то есть галочка
   получала треть экрана. Девять процентов возвращаются грузу, клиенту и
   доставке — тем, что читают. */
.routes-candidates-table--no-pickup .candidates-col-cargo,
.routes-candidates-table--no-pickup .candidates-col-client {
  width: 17%;
}

.routes-candidates-table--no-pickup .candidates-col-delivery {
  width: 19%;
}

/* Номер заявки в списке кандидатов не переносится — та же неразрывность, что
   у `.routes-assigned-table .num` и `.date-col` рядом. Долей 17% на 1280 не
   хватало: содержимое ячейки 188 px при 194 px, нужных самому короткому
   боевому номеру (`KRI-…-3D412A`), и 230 px — номеру КРИПВЗ из 26 знаков,
   который заказчик приводит в примере (`KRIPVZ-260904130246-5412D3`); номер
   рвался надвое. Неразрывность поднимает min-content колонки, автораскладка
   отдаёт ширину за счёт переносимых соседей (груз, клиент, адрес), и на всех
   вьюпортах номер стоит одной строкой без горизонтальной прокрутки. */
.routes-candidates-table td.candidates-col-order > .mono {
  white-space: nowrap;
}

/* Имя клиента одним длинным словом переносится внутри своей колонки, как в
   списке заявок: без этого оно раздвигало таблицу, и на 1280 появлялась
   прокрутка вбок на 331 px (В-16). В карточке на телефоне — так же: имя
   вылезало за край карточки на 384 px. */
.routes-candidates-table td.candidates-col-client,
.candidates-card-client {
  overflow-wrap: anywhere;
}

.access-table {
  min-width: 0;
  table-layout: fixed;
}

.access-table th:nth-child(1) {
  width: 16%;
}

.access-table th:nth-child(2) {
  width: 13%;
}

.access-table th:nth-child(3) {
  width: 9%;
}

/* «Юрлица» и «Курьер» отдали по 2 и 1 % датам: при 8 % дате «27.09.2026»
   (84 px) доставалось 74 px на 1280 и 81 на 1366, и она рвалась посреди года
   (В-01, правило неразрывности ниже). */
.access-table th:nth-child(4) {
  width: 14%;
}

.access-table th:nth-child(5) {
  width: 14%;
}

.access-table th:nth-child(6),
.access-table th:nth-child(7) {
  width: 9.5%;
}

.access-table th:nth-child(8) {
  width: 15%;
}

.access-table td,
.access-table .badge,
.access-table .mono {
  overflow-wrap: break-word;
  white-space: normal;
}

.access-table .btn {
  min-height: 34px;
  padding-inline: var(--space-3);
}

.access-table td:nth-child(3) .badge {
  overflow-wrap: normal;
  white-space: nowrap;
}

/* Дата «Создан» / «Обновлён» переносится только по пробелу между датой и
   временем. Общий `break-word` таблицы рвал её посреди года на 1280–1440:
   «26.09.202 / 6 21:21» (визуальная проверка 26.09, В-01); ширина колонок
   под дату — выше. */
.access-table td.mono {
  overflow-wrap: normal;
}

/* Название юрлица — идентификация, а не сигнал внимания: по правилу бейджей
   оно выводится обычным текстом, перечислением через запятую. Строка остаётся
   такой же высоты, как прежний ряд «кружочков», поэтому плотность таблицы
   доступов не меняется. */
.access-org-names {
  display: inline;
  min-width: 0;
}

.access-org-name {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* `anywhere`, а не `break-word`: по спецификации `break-word` НЕ уменьшает
   min-content ячейки, поэтому стопка `.cell-stack` внутри узкой колонки
   раздувалась до самого длинного слова («Строительные» — 111 px в колонке
   «Наименование груза» шириной 105 px) и выезжала на соседнюю. Видимый
   перенос у обоих значений одинаковый; разница только в расчёте минимальной
   ширины, а он в `table-layout: fixed` и решает. Номер заявки не затронут:
   у него `white-space: nowrap`, и он сильнее. */
.orders-list-table td,
.orders-list-table .badge,
.orders-list-table .mono {
  overflow-wrap: anywhere;
  white-space: normal;
}

/* Номер заявки стоит одной строкой. Самый длинный боевой номер — 26 знаков
   (`KRIPVZ-260904130307-21D5FD`), это 219 px моноширинным `--text-sm`, и доля
   колонки «Номер» посчитана под них. До 05.09 здесь стоял перенос по любому
   месту: колонка держала 80 px при 235 px, нужных содержимому, и номер рвался
   на ЧЕТЫРЕ строки в каждой строке списка — заказчик ищет заявку глазами
   именно по номеру. Тот же приём уже стоял у списка заявок маршрута и у
   кандидатов на добавление; здесь он не изобретается заново, а достаётся
   до конца. */
.orders-list-table .table-link.mono {
  white-space: nowrap;
}

/* ОБЩЕЕ ПРАВИЛО СПИСКОВ (2026-09-12): неразрывное значение остаётся в своей
   колонке. Раскладка этих таблиц фиксированная, у ячейки `overflow` по
   умолчанию `visible`, и неразрывная строка длиннее колонки просто ЛОЖИЛАСЬ
   ПОВЕРХ соседней — не обрезалась, а накладывалась, и нечитаемыми становились
   оба значения. На коротком номере `123-4567` этого не происходит (88 px в
   колонке 96 px), но страховки от длинного значения не было ни у одной
   колонки: телефон, номер заявки, номер доставки, наименование юрлица в
   доступах — всё это данные, длину которых задаёт не CRM.

   Обрезка ставится на САМ ЭЛЕМЕНТ, а не на ячейку: `overflow: hidden` у `td`
   обрезал бы и всплывающее меню действий строки. Полное значение остаётся в
   `title` там, где значение может не поместиться. */
.orders-list-table .orders-col-no .table-link,
.routes-assigned-table td .mono,
.clients-table td .mono,
.employees-table td .mono,
.deliveries-order-no,
.courier-table .table-link.mono,
.access-table td .mono {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Бейджи статуса и оплаты в списке заявок — с горизонтальным отступом
   `var(--space-2)` вместо общих `var(--space-3)`: тот же приём, что у ячеек
   этой таблицы. Причина измерена (ревью 06.09, 1280 px с колонкой выбора и
   полосой прокрутки, таблица 1231 px): колонке «Статус» достаётся 85,6 px, из
   них тексту бейджа при общем отступе — 51,6 px, а слову «курьера» нужно
   52 px, и оно рвалось внутри («У курьер / а», бейдж ростом в три строки);
   «Оплачено» (61 px) в колонке «Оплата» на 94,6 px рвалось надвое так же.
   Меньший отступ возвращает каждому слову ~8 px запаса, ни одна колонка не
   меняет доли, бейджи вне этой таблицы не тронуты. */
.orders-list-table .badge {
  padding-inline: var(--space-2);
}

/* Номер маршрута под направлением (пак 2026-09-03, п. 39): ссылка ростом с
   номер заявки — `--text-sm` вместо приглушённых 12px соседних строк, ничего
   нового в шкале. Колонка узкая (~110 px на 1280), длинный номер переносится
   внутри ячейки, а не распирает её. */
.orders-list-table .cell-stack .route-ref-projection {
  font-size: var(--text-sm);
  overflow-wrap: anywhere;
}

.orders-list-table td {
  line-height: 1.35;
}

.orders-list-table .row-actions,
.access-table td:last-child .row-actions {
  align-items: stretch;
  gap: var(--space-1);
}

.orders-list-table .row-actions .btn,
.access-table td:last-child .row-actions .btn {
  min-width: 0;
  white-space: normal;
}

.orders-list-table .row-actions .btn {
  flex: 0 0 auto;
  padding-inline: var(--space-1);
  font-size: var(--text-xs);
  white-space: nowrap;
}

.access-table td:last-child .row-actions .btn {
  flex: 1 1 150px;
}

.organizations-table {
  min-width: 0;
  table-layout: fixed;
}

.organizations-table th:nth-child(1) {
  width: 22%;
}

.organizations-table th:nth-child(2) {
  width: 10%;
}

.organizations-table th:nth-child(3) {
  width: 10%;
}

.organizations-table th:nth-child(4) {
  width: 16%;
}

.organizations-table th:nth-child(5) {
  width: 12%;
}

.organizations-table th:nth-child(6) {
  width: 12%;
}

.organizations-table th:nth-child(7) {
  width: 18%;
}

.organizations-table td,
.organizations-table .badge,
.organizations-table .mono {
  overflow-wrap: break-word;
  white-space: normal;
}

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

.organization-actions form {
  display: inline-flex;
  margin: 0;
}

.organization-actions .btn {
  min-height: 34px;
  padding-inline: var(--space-3);
}

.organization-title-row {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.organization-detail-head .head-actions form {
  display: inline-flex;
  margin: 0;
}

.order-detail-head .head-actions form {
  display: inline-flex;
  margin: 0;
}

/* Карточка юрлица: реквизиты целиком, разложенные по категориям в несколько
   колонок. Категория = панель, а не строка списка с разделителем — тот же
   приём, что заказчик назвал эталоном на карточке сотрудника. */
.organization-detail-zones {
  min-width: 0;
  padding: var(--space-5);
  columns: 320px;
  column-gap: var(--space-4);
}

.organization-detail-zones > .detail-panel {
  break-inside: avoid;
  margin-bottom: var(--space-4);
}

.organization-detail-list {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
  min-width: 0;
}

.organization-detail-list > li {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
  overflow-wrap: anywhere;
  font-weight: var(--weight-strong);
}

.organization-detail-list__meta {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.organization-identity-form {
  padding-bottom: 0;
}

.input-readonly {
  font-weight: var(--weight-body);
  min-height: 44px;
  display: flex;
  align-items: center;
  padding: 12px 13px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  background: var(--color-surface);
  overflow-wrap: anywhere;
}

.organization-confirm-body {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-5);
}

.organization-confirm-body .notice-banner {
  margin: 0;
}

.organization-confirm-actions {
  justify-content: flex-start;
}

/* Клиент | Тип | Телефон | Примечание.

   До 2026-09-03 ширины не задавались вовсе: на 1280 px таблица шириной 1246 px
   отдавала имени 249 px, типу 120 px и телефону все оставшиеся 877 px. ФИО не
   помещалось в 249 px и переносилось на две строки, кнопка копирования уезжала
   на третью, примечание под именем добавляло ещё две — строки списка имели
   четыре разные высоты, а справа простаивала треть экрана.

   Ширины считаны от реальной потребности колонки: ФИО и наименование юрлица
   вместе с кнопкой копирования в одну строку, номер в одну строку и не шире
   номера, тип по своей подписи. Остаток отдан примечанию — оно и занимает то
   место, которое иначе читается как незаполненный интерфейс. Счётчики заявок
   (синяя рамка скриншота 03) не согласованы; когда они появятся, они встают
   между телефоном и примечанием, и доля примечания уменьшается. */
.clients-table {
  min-width: 820px;
  table-layout: fixed;
}

/* Шесть колонок с 2026-09-06: за телефоном встали счётчики «Всего заявок» и
   «Не оплачено» (заказчик 2026-09-02, кадр 03, синяя область). Их доля взята
   у примечания — оно эластичное и обрезается многоточием. */
.clients-table th:nth-child(1) {
  width: 32%;
}

.clients-table th:nth-child(2) {
  width: 8%;
}

.clients-table th:nth-child(3) {
  width: 15%;
}

.clients-table th:nth-child(4),
.clients-table th:nth-child(5) {
  width: 9%;
}

/* Доля примечания уменьшена 2026-09-12 с 35 % до 27 % в пользу имени
   (24 % → 32 %). На 1366 «Примечание» занимало 466 px против 316 px у
   «Клиента» — самая широкая колонка списка при том, что примечание заполнено у
   единиц клиентов, а длинные ФИО из-за этого переносились на две строки
   (сплошной проход, волна 1, находка 14). Примечание остаётся одной строкой с
   многоточием и `title`, как и было. */
.clients-table th:nth-child(6) {
  width: 27%;
}

.clients-table td {
  overflow-wrap: break-word;
}

/* Номер читается одной строкой — то же правило, что у списка сотрудников. */
.clients-table td .mono {
  white-space: nowrap;
}

/* Имя и кнопка копирования — один инлайновый поток: у обычного ФИО кнопка
   стоит сразу после последнего слова. Так остаётся в КАРТОЧКЕ на узком экране,
   где колонок нет и имя переносится целиком. */
.client-name-cell {
  display: block;
  min-width: 0;
  /* Имя одним словом (вставка без пробелов) переносится внутри карточки, а не
     режет её: 64 знака вылезали на 320 px за край на 390 (В-16). В строке
     таблицы имя по-прежнему одной строкой с многоточием — правило ниже. */
  overflow-wrap: anywhere;
}

.client-name-cell .copy-icon-button {
  margin-inline-start: var(--space-2);
  vertical-align: middle;
}

/* В СТРОКЕ ТАБЛИЦЫ — иначе: имя занимает колонку и заканчивается многоточием,
   кнопка прижата к правому краю ячейки.

   До 2026-09-12 здесь был тот же инлайновый поток, и X кнопки менялся от
   строки к строке: на первых восьми строках разброс 140 px (150, 253, 258,
   251, 270, 275, 248, 237) — столбец кнопок выглядел рваным, а длинное ФИО
   переносилось на две строки (сплошной проход, волна 1, находка 11). Замысел
   «кнопка у последнего слова» отменён только для таблицы: ровный столбец
   кнопок читается лучше рваного, а имя от этого не страдает — колонка
   «Клиент» получила те же 8 %, что отданы примечанием. Полное ФИО остаётся
   в `title` у ссылки. */
.clients-table .client-name-cell {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.clients-table .client-name-cell > .table-link {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.clients-table .client-name-cell .copy-icon-button {
  flex: 0 0 auto;
  margin-inline-start: auto;
}

.clients-table .client-name-cell > .badge {
  flex: 0 0 auto;
}

/* Приглушённая подпись типа рядом с именем в карточке списка на узком экране:
   отдельным полем `dt`/`dd` тип весил столько же, сколько телефон. */
.client-card-type {
  display: inline-block;
  margin-inline-start: var(--space-2);
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

/* A note can be up to 2000 characters; two lines is as much as a card can
   carry without breaking its rhythm. The full text stays in the card itself. */
.client-note {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

/* В таблице заметка занимает ровно одну строку: длина примечания не должна
   менять высоту строки списка. Полный текст остаётся в `title`. */
.clients-table .client-note {
  display: block;
  overflow: hidden;
  font-size: var(--text-sm);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.clients-table .client-note--empty {
  color: var(--color-text-muted);
}

/* «Выбрать несколько» / «Отменить выбор» списка клиентов (решение qXstay 13.09:
   галочки копирования в другое юрлицо — за переключателем, как в карточке
   рейса). Ссылка стоит справа в строке «Показано …» и эту строку не выше
   делает: у неё высота строки текста, 21 px, а у строки — 37 px с полями.
   Кнопка там же подняла бы строку до 55 px на десктопе и 89 px на телефоне и
   сдвинула бы список. Поля ссылки по 8 px сверху и снизу со сдвигом на те же
   8 px делают попадание пальцем высотой в строку, не меняя раскладки. */
.client-select-toggle {
  margin-inline-start: auto;
  padding-block: var(--space-2);
  margin-block: calc(-1 * var(--space-2));
  white-space: nowrap;
}

/* Колонка галочек в режиме выбора. Раскрой 2026-09-12 не трогается: у
   «Клиента», «Типа», «Телефона» и счётчиков те же доли от ширины таблицы, что и
   без выбора, а 48 px галочки целиком отдаёт «Примечание» — у него ширины нет,
   и в фиксированной раскладке оно берёт остаток. 48 = галочка 18 px и поля
   ячейки по 12 px. */
.clients-table.clients-table--selectable th:nth-child(1) {
  width: 48px;
}

.clients-table.clients-table--selectable th:nth-child(2) {
  width: 32%;
}

.clients-table.clients-table--selectable th:nth-child(3) {
  width: 8%;
}

.clients-table.clients-table--selectable th:nth-child(4) {
  width: 15%;
}

.clients-table.clients-table--selectable th:nth-child(5),
.clients-table.clients-table--selectable th:nth-child(6) {
  width: 9%;
}

.clients-table.clients-table--selectable th:nth-child(7) {
  width: auto;
}

/* Панель выбора над списком: число, три кнопки, строка сообщения. Вид — общая
   панель массовых действий (`.bulk-action-bar`), только кнопки стоят в ряд
   и переносятся, а сообщение уходит на свою строку. */
.client-selection-bar {
  flex-wrap: wrap;
  border-top: 0;
  border-bottom: 1px solid var(--color-border);
}

.client-selection-bar__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.client-selection-bar__message {
  flex: 1 0 100%;
  color: var(--color-ink);
  font-weight: var(--weight-strong);
}

/* Форма выбора оборачивает результаты списка, но собственного бокса не
   строит: раскладка панели та же, что без неё. */
.client-selection-form {
  display: contents;
}

/* Галочка стоит в шапке карточки справа от имени, а не отдельной строкой под
   карточкой: строка «Выбрать» добавляла каждой карточке 56 px. На узком экране
   шапка — одна колонка, поэтому для неё здесь две: имя и галочка. */
.clients-cards--selectable .order-card__head > .bulk-check {
  flex: 0 0 auto;
}

@media (max-width: 767.98px) { /* ниже mobile */
  .clients-cards--selectable .order-card__head {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
  }
}

/* Галочка таблицы — голый чекбокс без подписи (имя клиента — в aria-label):
   сотня обёрток на странице весила килобайты несжатого HTML. Размер и цвет —
   как у `.bulk-check input`; отступ сверху ставит её на середину первой строки
   ячейки, рядом с кнопкой копирования имени, и не меняет высоту строки. */
.clients-table .clients-col-select input {
  display: block;
  width: 18px;
  height: 18px;
  margin: 4px 0 0;
  accent-color: var(--color-accent);
}

/* Шаг копирования и его итог. */
.client-transfer-body {
  max-width: 880px;
}

.client-transfer-target {
  max-width: 360px;
}

.client-transfer-rules {
  display: grid;
  gap: var(--space-2);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

.client-transfer-rules p {
  margin: 0;
}

.client-transfer-names summary {
  cursor: pointer;
  font-weight: var(--weight-strong);
}

/* До 500 имён: список прокручивается внутри, кнопки не уезжают за экран. */
.client-transfer-list {
  display: grid;
  gap: var(--space-1);
  max-height: 320px;
  overflow: auto;
  margin: var(--space-2) 0 0;
  padding: var(--space-3) var(--space-3) var(--space-3) calc(var(--space-3) + 2ch);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  overflow-wrap: anywhere;
}

.client-transfer-list__type {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

/* Три числа итога: в ряд на широком экране, по два в ряд на телефоне. */
.client-transfer-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-3);
  max-width: 640px;
  margin: 0;
}

.client-transfer-summary > div {
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

.client-transfer-summary dt {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-strong);
}

.client-transfer-summary dd {
  margin: var(--space-1) 0 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-strong);
}

.client-transfer-group h2 {
  margin: 0;
  font-size: var(--text-sm);
}

.client-form-screen .order-form {
  max-width: 1320px;
}


/* ── Карточка клиента ─────────────────────────────────────────────────────
   Карточка сразу редактируемая: одна форма, зоны рядом, кнопки внизу перед
   списком заявок. Вертикальные разделители между зонами и одна горизонтальная
   линия перед заявками — ровно то, что заказчик разрешил (пак 2026-09-02,
   п. 12). */
.client-card {
  display: grid;
  gap: var(--space-4);
  /* Same inset as every other block of a panel screen (.view-head,
     .order-detail-body): the panel itself carries no padding. */
  padding: var(--space-5);
}

/* Карточка-форма: fieldset несёт только состояние «можно править», а не рамку.
   Один и тот же сброс у клиента и у сотрудника — приём один и тот же. */
.client-card-body,
.employee-card-body {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

/* Факты записи под полями доступа: тот же приглушённый регистр, что у остальных
   служебных отметок карточки. */
.employee-card-facts {
  margin-top: var(--space-3);
}

.client-card-stamps {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

/* Колонки тянутся на высоту самой длинной, содержимое остаётся вверху. Иначе
   бледный вертикальный разделитель, который заказчик разрешила (п. 12),
   обрывается на высоте короткой зоны, и три зоны читаются как «колонка и
   приписка». Выравнивание содержимого задаёт `align-content: start` внутри
   самой зоны и колонки, поэтому поля не растягиваются. */
.client-card-zones {
  display: grid;
  gap: var(--space-5);
  align-items: stretch;
}

.client-card-zone {
  display: grid;
  gap: var(--space-3);
  align-content: start;
  min-width: 0;
}

/* Одна колонка карточки может нести больше одной зоны: у физлица под адресом
   идёт примечание, и правая колонка перестаёт обрываться на 283 px, пока
   левая тянется до 743 px. */
.client-card-column {
  display: grid;
  gap: var(--space-5);
  align-content: start;
  min-width: 0;
}


.client-card-zone__title {
  margin: 0;
  color: var(--color-ink);
  font-size: var(--text-lg);
}

/* Кнопки под данными клиента, как на рукописном макете заказчика: слева, под
   первой зоной, а не у правого края экрана. Специфичность (0,2,0) перекрывает
   общий .form-actions с его flex-end. */
.form-actions.client-card-actions {
  justify-content: flex-start;
}

.client-card-divider {
  margin: 0 var(--space-5);
  border: 0;
  border-top: 1px solid var(--color-border);
}

.client-accounts-panel {
  margin: 0 var(--space-5) var(--space-4);
}

.client-orders-panel {
  margin: var(--space-4) var(--space-5) var(--space-5);
}

/* ── Телефоны клиента: одна коллекция, одна точка сохранения ───────────────
   Блок счетов на форме создания юрлица (пак 2026-09-03, п. 10) — тот же
   приём и тот же вид: рамка, заголовок с «+», строки-индексы. */
.client-phone-list,
.client-account-list {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

.client-phone-list__head,
.client-account-list__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.client-phone-list__head h3,
.client-account-list__head h3 {
  margin: 0;
  color: var(--color-ink);
  font-size: var(--text-sm);
}

.client-phone-rows,
.client-account-rows {
  display: grid;
  gap: var(--space-3);
}

.client-phone-row {
  display: grid;
  gap: var(--space-2);
}

.client-phone-row__flags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.client-phone-row__flags .check-field {
  font-size: var(--text-sm);
  font-weight: var(--weight-body);
}

/* Кружок с плюсом рядом с номером: «добавить ещё один номер телефона». */
.phone-add-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  min-width: 28px;
  height: 28px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  color: var(--color-link);
  background: var(--color-surface-soft);
  font-size: var(--text-lg);
  font-weight: var(--weight-accent);
  line-height: 1;
  cursor: pointer;
}

.phone-add-button:hover {
  border-color: var(--color-accent);
  background: var(--color-surface-muted);
}

.phone-add-button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Реквизит, который раньше обрезался в однострочном поле: текст при той же
   плотности, что и `.input`.

   Ручка растягивания ВЕРТИКАЛЬНАЯ с 2026-09-12. Запрет был поставлен ради
   того, чтобы поле не уезжало под соседнюю зону, — но `resize: vertical`
   меняет только высоту, ширина остаётся в своей зоне, и исходная причина
   запрета сохраняется. Без ручки белорусский юридический адрес было не
   раскрыть вовсе: при высоте поля 56 px содержимое занимало 92 px, и третья
   строка была видна наполовину, по глифам (сплошной проход, волна 1,
   находка 5). */
.textarea--compact {
  min-height: 0;
  padding: 8px 13px;
  line-height: 1.35;
  resize: vertical;
}

.residency-fields[hidden] {
  display: none;
}

@media (min-width: 920px) { /* shell и выше: зоны карточки клиента встают рядом */
  .client-card-zones--two,
  .client-card-zones--three {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* Бледная вертикальная полоска между зонами — ровно то, что заказчик
     разрешил; при двух колонках её получает только вторая колонка в ряду. */
  .client-card-zones--two > :nth-child(even),
  .client-card-zones--three > :nth-child(even) {
    border-left: 1px solid var(--color-border);
    padding-left: var(--space-5);
  }

  .client-phone-row {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
  }

  /* Строка с выбором типа (юрлицо) стоит в колонке шириной около трети экрана.
     Тип во всю ширину оставлял номеру 150 px рядом с флажками (независимый
     ревью 2026-09-02); тип и номер делят первую строку, флажки уходят на
     вторую, и номер получает всю оставшуюся ширину колонки. */
  .client-phone-row--typed {
    grid-template-columns: minmax(0, 150px) minmax(0, 1fr);
  }

  .client-phone-row--typed .client-phone-row__flags {
    grid-column: 1 / -1;
  }
}

@media (min-width: 1280px) { /* dense и выше: третья зона встаёт в общий ряд */
  .client-card-zones--three {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .client-card-zones--three > :nth-child(even) {
    border-left: 0;
    padding-left: 0;
  }

  .client-card-zones--three > :not(:first-child) {
    border-left: 1px solid var(--color-border);
    padding-left: var(--space-5);
  }
}

/* Трёхзонная карточка физлица (паспортная зона видна владельцу и
   администратору с ревизии 0024): при ширине экрана 1280–1365 левая зона —
   384 px, и номер рядом с флажками получал 142 px, а «+375 33 700-10-20»
   обрезался на два знака (независимое ревью 2026-09-06). Флажки уходят под
   номер — тот же приём, что у строки с типом номера (`--typed`); с 1366 номеру
   хватает места и ряд остаётся прежним. Юрлицо не затронуто: его строка уже
   двухрядная. */
@media (min-width: 1280px) and (max-width: 1365.98px) {
  .client-card-zones--three .client-phone-row:not(.client-phone-row--typed) {
    grid-template-columns: minmax(0, 1fr);
  }
}

.client-type-choice {
  align-items: stretch;
}

/* Одна строка вместо карточки в две строки: выбор типа остаётся видимым, но
   не занимает высоту, которой не хватает форме, чтобы уместиться на экране. */
.choice-card {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  cursor: pointer;
}

.choice-card:focus-within {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px rgb(37 99 235 / 0.14);
}

.choice-card > span {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
  min-width: 0;
}

.choice-card small {
  color: var(--color-text-muted);
}

.client-type-section h3 {
  color: var(--color-ink);
  font-size: var(--text-base);
}

.client-child-list {
  margin-bottom: 0;
}

.client-child-actions,
.client-child-edit {
  display: flex;
  align-items: end;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.client-child-edit {
  width: 100%;
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}

.client-child-edit .field {
  flex: 1 1 160px;
  min-width: 0;
}

/* Строка счёта: «Назначение» — самая длинная величина ряда («Расчётный счёт по
   договору ВС-2026/07» не помещалось в 160 px и обрезалось), а валюта и
   порядок укладываются в свои значения. Раньше все четыре поля делили ширину
   поровну. */
.client-child-edit .field--account-number {
  flex: 2 1 230px;
}

.client-child-edit .field--account-purpose {
  flex: 3 1 260px;
}

.client-child-edit .field--account-small {
  flex: 0 1 116px;
}

/* Примечание клиента в списке заявок — рамка без тона (пак 2026-09-03, п. 11,
   по правилу бейджей заказчика). Не янтарный: янтарный в системе означает
   предупреждение, а в примечаниях заказчика стоят «VIP» и «очень важный
   клиент» — это важность, и десять таких строк читались бы как десять
   тревог (независимое ревью 2026-09-04). В карточке заявки примечание
   переносится целиком и не растягивается на всю ширину. */
.client-note-projection {
  max-width: 34ch;
  justify-self: start;
  /* Метка-надпись, а не статус: у пилюли радиус в половину высоты, и
     примечание в несколько строк превращалось в овал. */
  border-radius: var(--radius-sm);
  white-space: normal;
  text-align: left;
  overflow-wrap: anywhere;
}

/* Примечание клиента в строке таблицы занимает ровно одну строку — как
   заметка в колонке списка клиентов (`.clients-table .client-note`) — и
   усекается честным многоточием: показано столько, сколько влезает в
   колонку, полный текст — в `title` и в мобильной карточке. Колонка «Клиент»
   узкая (96 px на 1280 с колонкой выбора), и перенос превращал примечание в
   узкий столбик, тянувший высоту строки (независимое ревью 2026-09-04).
   Слово-указатель вместо текста (05.09, «Примеч.») отклонено ревью 06.09:
   заказчик сама заводит примечания и просила видеть их в списке, а `title`
   на телефоне не работает. */
.orders-list-table .client-note-projection {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Заполненный номер груза выделен цветом и весом в стопке ячейки (пак
   2026-09-03, п. 12); «Без номера» остаётся приглушённой строкой.

   С 2026-09-16 номер крупнее наименования (заказчик 14.09: «Шрифт в графе
   Номер груза делаем больше, чем в графе Наименование… Это прям надо для
   работы» — по номеру на складе сверяют коробки): `--text-lg` при
   наименовании `--text-sm` и акцентный вес. Две ступени, а не одна:
   моноширинный стек у заказчика на Windows — Consolas, и при 16 px его
   заглавные той же высоты, что заглавные Inter при 14 px (проверено на
   настоящем Consolas), номер выходил только жирнее, но не крупнее. Новой
   ступени не заводится. Длинный номер переносится внутри своей колонки по
   любому знаку, а не раздвигает её и не ложится на соседнюю. Тот же вид — в
   мобильной карточке списка и в карточке маршрута (строка таблицы и
   карточка). */
.cargo-number-projection,
.cell-stack .cargo-number-projection {
  color: var(--color-text);
  font-size: var(--text-lg);
  font-weight: var(--weight-accent);
  overflow-wrap: anywhere;
}

/* В мобильной карточке номер идёт в строке сразу за наименованием и рвался
   там, где кончилась строка: «SM- / 1042» (визуальная проверка 26.09, В-04).
   Строчный блок переносится на следующую строку целиком; номер длиннее строки
   по-прежнему переносится внутри себя и не вылезает. */
.cargo-number-projection {
  display: inline-block;
  max-width: 100%;
}

/* В таблице маршрута моноширинные значения стоят одной строкой (номер заявки,
   телефон — правило выше по файлу); номер груза — нет: колонка «Груз» узкая,
   и неразрывный номер раздвигал бы её или вылезал на «Вес». */
.routes-assigned-table td .cargo-number-projection {
  white-space: normal;
}

/* Пункт доставки в списке заявок — «в кружочке» по правилу бейджей заказчика
   (пак 2026-09-03, п. 7/8: подчёркнуты «Автолайт», «Минск», «СКЛАД МИНСК-2»).
   Тон нейтральный, текст основным цветом: это место, куда едет груз, а не
   тревога. Скругление как у примечания клиента — метка-надпись, а не статус,
   иначе в стопке под «Не назначена» две одинаковые пилюли читаются как два
   статуса. Длинное название переносится внутри метки. */
.delivery-point-projection {
  justify-self: start;
  border-radius: var(--radius-sm);
  color: var(--color-text);
  white-space: normal;
  text-align: left;
  overflow-wrap: anywhere;
}

/* В строке таблицы метка не добавляет высоты вовсе: строка с пунктом доставки
   ровно такая же, как если бы на его месте стоял обычный `span`. У пилюли своя
   высота 26 px против 16.2 px у строки текста; `min-height: 0` убирает её, но
   рамка и вертикальный отступ всё ещё давали +4 px на каждой такой заявке
   (замер 2026-09-04 подстановкой голого `span`, четыре ширины). Эти 4 px
   вынесены из потока отрицательным полем: пилюля нарисована ровно так же, с
   рамкой и отступом — выделение пункта доставки сохраняется (-007), — но в
   стопке занимает высоту одной строки и забирает по 2 px из зазора сверху и
   снизу. В карточке заявки на mobile метка остаётся обычной высоты. */
.orders-list-table .delivery-point-projection {
  min-height: 0;
  margin-block: -2px;
  padding-block: 1px;
}

/* Комментарий заявки в своей колонке (пак 2026-09-03, п. 20): до двух строк
   с многоточием на второй, полный текст — в `title`, в карточке заявки и в
   мобильной карточке. Две строки, а не одна: до 08.09 колонка комментария была
   самой узкой в списке (78 px на 1280), и одна строка вмещала девять знаков.
   Перекрой бюджета 08.09 поднял её до 139,7 px на 1280 и 151 px на 1366 —
   слово посреди себя больше не рвётся (самое длинное в боевых примечаниях,
   «штабелирование», 120 px), — но две строки остаются: при этом
   соседние ячейки строки («Клиент» — имя и телефон, «Действия» — кнопки
   34 px) и так не ниже двух строк, поэтому высота строки списка от
   комментария не растёт (замер 06.09 на 14 заявках КРИПВЗ: средняя строка
   126,1 px до и после). `line-clamp` уже используется в списке клиентов.
   Пустой комментарий не рисуется вовсе (прочерка тоже нет). */
.orders-list-table .order-comment-projection {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  max-width: 100%;
  overflow: hidden;
  font-size: var(--text-sm);
  white-space: normal;
  overflow-wrap: anywhere;
}

@media (max-width: 767.98px) { /* ниже mobile */
  .client-child-actions,
  .client-child-edit {
    align-items: stretch;
  }

  .client-child-actions .btn,
  .client-child-edit .btn,
  .client-child-edit .field {
    flex: 1 1 100%;
  }

  /* На узком экране строка чтения счёта и форма его редактирования стояли одна
     под другой и показывали одно и то же дважды: номер, валюту и назначение.
     Читаемая строка убирается только там, где под ней есть форма — у
     наблюдателя без прав редактирования она остаётся единственным
     представлением счёта. */
  .requisite-item--editable > .requisite-item__main {
    display: none;
  }

  /* Короткие поля клиента остаются в ряд: «Дом», «Подъезд» и «Квартира» тремя
     отдельными строками растягивали карточку юрлица до шести экранов. Правило
     ограничено зонами клиента, общие `.span-*` не трогает. */
  .client-card-zone .form-grid > .span-4 {
    grid-column: span 4;
  }

  .client-card-zone .form-grid > .span-6 {
    grid-column: span 6;
  }
}

.routes-table {
  min-width: 1080px;
}

.client-orders-table {
  min-width: 980px;
}

/* Номер заявки в списке доставок стоит одной строкой — та же мера, что в
   списке заявок, архиве, списках заявок маршрута и кабинете курьера
   (заказчик 2026-09-05: «Номер обязан держаться в одну строку на всех
   рабочих ширинах»). Здесь он выводится не ссылкой, а `<strong class="mono">`,
   поэтому общее правило `.table-link.mono` его не покрывало и он ломался
   надвое уже на пятнадцати знаках. Раскладка таблицы автоматическая: длина
   номера поднимает минимум своей колонки, лишнее уходит переносимым соседям —
   грузу и адресу. В мобильной карточке номер стоит в шапке, ширины хватает. */
.deliveries-order-no {
  white-space: nowrap;
}

.orders-table th,
.orders-table td {
  padding: 9px var(--space-3);
  border-bottom: 1px solid var(--color-border);
  text-align: left;
  vertical-align: top;
}

.orders-table th {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
  text-transform: uppercase;
  white-space: nowrap;
}

.orders-list-table th {
  line-height: 1.25;
  white-space: normal;
  overflow-wrap: normal;
  word-break: keep-all;
}

/* Горизонтальный отступ ячейки ужат ради одиннадцатой колонки и (с 05.09)
   ради неразрывного номера заявки: `var(--space-1)` вместо `var(--space-2)`
   отдаёт бюджету колонок 88 px на одиннадцать колонок — ровно то, чего не
   хватало «Номеру». Между колонками остаётся 8 px просвета. Стоит после
   `.orders-table th, .orders-table td`, иначе базовый `padding` перекрывает
   `padding-inline` обратно. Вертикальный отступ, размер шрифта и высота
   строки не тронуты. */
.orders-list-table th,
.orders-list-table td {
  padding-inline: var(--space-1);
}

/* Просвет между «Стоимостью» и «Действиями»: правая выключка чисел и их
   заголовка упирается в левую выключку кнопок, и на 1280 «СТОИМОСТЬ» и
   «ДЕЙСТВИЯ» читались одной надписью. Левый отступ последней колонки —
   `var(--space-3)` и у заголовка, и у ячеек, чтобы кнопки остались под
   своим заголовком. Колонке это стоит 8 px из запаса, который появился после
   переноса кнопки копирования под «Редактировать». */
.orders-list-table th:last-child,
.orders-list-table td:last-child {
  padding-inline-start: var(--space-3);
}

.access-table th,
.organizations-table th {
  white-space: normal;
  overflow-wrap: normal;
  word-break: keep-all;
}

/* Список сотрудников. До 2026-09-02 таблица раскладывалась автоматически: под
   телефон доставалось 150px и номер рвался на две строки, «Открыть» и
   «Редактировать» не влезали в 244px и вставали друг под другом, а под ФИО
   дублировалась должность из соседней колонки. Строка занимала 105px — экран
   стал длиннее, чем был до переделки.

   Ширины заданы явно, по той же схеме, что у `.organizations-table`. Восемь
   колонок этого раздела при 1280px (ширина обёртки 1246px) требуют 1303px со
   стандартными отступами ячейки `9px var(--space-3)`. Недостающие 57px взяты
   не из колонок, а из горизонтального отступа: `var(--space-2)` вместо
   `var(--space-3)` освобождает по 8px на колонку, 64px всего. Размер шрифта не
   тронут — читаемость выше плотности (docs/DESIGN.md). Доли посчитаны от
   измеренной потребности каждой колонки (ФИО 246, юрлицо 71, должность 217,
   место работы 108, телефон 160, категория 92, статус 107, пара кнопок 238) и
   потому дробные: целые проценты этот баланс не выражают. */
.employees-table {
  min-width: 0;
  table-layout: fixed;
}

/* Отступ ячейки ужат и заголовки переносятся: «Место работы» шире своего
   содержимого и иначе задавал бы колонке лишнюю ширину. Блок стоит после
   `.orders-table th, .orders-table td`, иначе базовый `padding` перекрывает
   `padding-inline` обратно. */
.employees-table th,
.employees-table td {
  padding-inline: var(--space-2);
}

.employees-table th {
  white-space: normal;
  overflow-wrap: normal;
  word-break: keep-all;
}

.employees-table th:nth-child(1) {
  width: 19.8%;
}

.employees-table th:nth-child(2) {
  width: 5.8%;
}

.employees-table th:nth-child(3) {
  width: 17.5%;
}

.employees-table th:nth-child(4) {
  width: 8.7%;
}

.employees-table th:nth-child(5) {
  width: 12.9%;
}

.employees-table th:nth-child(6) {
  width: 7.4%;
}

.employees-table th:nth-child(7) {
  width: 8.7%;
}

.employees-table th:nth-child(8) {
  width: 19.2%;
}

.employees-table td {
  overflow-wrap: break-word;
}

/* Телефон читается одной строкой — это и было замечание заказчика. */
.employees-table td .mono {
  white-space: nowrap;
}

/* «Открыть» и «Редактировать» стоят в одну строку: у `.btn-compact`
   горизонтальный отступ ужат с `var(--space-3)` до `var(--space-2)`, шрифт
   кнопки не уменьшен. */
.employees-table .row-actions {
  flex-wrap: nowrap;
  gap: var(--space-1);
}

.employees-table .row-actions .btn {
  flex: 0 0 auto;
  min-width: 0;
  padding-inline: var(--space-2);
}

.orders-table tr:last-child td {
  border-bottom: 0;
}

.copy-icon-button {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  min-width: 34px;
  height: 34px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  color: var(--color-text-muted);
  background: var(--color-surface-soft);
  font-size: 0;
  line-height: 0;
  cursor: pointer;
}

.copy-icon-button::before,
.copy-icon-button::after {
  content: "";
  position: absolute;
  width: 12px;
  height: 14px;
  border: 1.7px solid currentColor;
  border-radius: 3px;
  pointer-events: none;
}

.copy-icon-button::before {
  transform: translate(-3px, -3px);
  opacity: 0.62;
}

.copy-icon-button::after {
  transform: translate(2px, 2px);
  background: var(--color-surface-soft);
}

.copy-icon-button:hover {
  color: var(--color-link);
  border-color: rgb(96 165 250 / 0.45);
}

/* Крупная кнопка копирования получила фокус того же вида, что и остальные
   кнопки: до этого у неё оставалось только умолчание браузера. */
.copy-icon-button:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.copy-icon-button--detail {
  width: 40px;
  min-width: 40px;
  height: 40px;
}

/* Кнопка копирования в списке заявок. Заказчик просила её выделить (пак
   2026-09-03, п. 43: «переносим куда нить вниз, и делаем больше и выделим
   другим цветом»). До 05.09 это была плита во всю ширину «Действий» ростом
   40 px, и строка списка вырастала с 34 до 78 px; 05.09 кнопку ужали до
   значка 34×34 в одну строку с «Редактировать» — и заодно сняли подпись,
   о чём заказчик не просила. Теперь подпись «Копировать» стоит рядом со
   значком, коробка — те же 34 px высоты и та же ширина, что у
   «Редактировать» (108 px против 109), заливка — `--color-accent`, тот же
   токен, что у `.btn-primary`.

   Почему кнопка стоит ПОД «Редактировать», а не рядом. Подпись стоит 76 px
   текста; в одну строку с «Редактировать» группе нужно 221 px, а колонке
   «Действия» на 1280 достаётся ~150 px. Недостающее можно взять только у
   «Клиента» и «Доставки» (остальные колонки стоят на минимумах своих
   заголовков и бейджей, «Выбор» и «Номер» — в пикселях), а именно они задают
   высоту строки в 13 строках из 14 у заказчика: измерено 06.09 на копии её
   базы, при любой делёжке росли 5–8 строк на 16–100 px. Под «Редактировать»
   кнопка не стоит ни пикселя ширины и ни пикселя высоты на её данных: две
   строки контролов — 72 px, а строки списка 93–186 px. Это и есть её «вниз».
   Задняя карточка значка красится `inherit`, поэтому при наведении следует
   за фоном кнопки. Значок центрируется по левой зоне 26 px; отступ подписи
   справа — `var(--space-1)`, как у «Редактировать». */
.copy-icon-button--row {
  width: auto;
  min-width: 0;
  padding: 0 var(--space-1) 0 26px;
  border-color: var(--color-accent);
  color: var(--color-accent-on);
  background: var(--color-accent);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
  line-height: 1;
  white-space: nowrap;
}

.copy-icon-button--row::before,
.copy-icon-button--row::after {
  top: 50%;
  left: 13px;
}

.copy-icon-button--row::before {
  transform: translate(calc(-50% - 3px), calc(-50% - 3px));
}

.copy-icon-button--row::after {
  transform: translate(calc(-50% + 2px), calc(-50% + 2px));
  background: inherit;
}

.copy-icon-button--row:hover {
  color: var(--color-accent-on);
  border-color: var(--color-accent-hover);
  background: var(--color-accent-hover);
}

/* Крестик «снять заявку с маршрута» (пак 2026-09-03, п. 29): та же коробка,
   что у кнопки копирования, знак — текстом. Спокойный по умолчанию, при
   наведении и фокусе — цвет опасного действия, как у кнопки снятия выбранных.
   Снятие не удаляет данные: заявка остаётся в системе. */
.remove-icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  min-width: 34px;
  height: 34px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  color: var(--color-text-muted);
  background: var(--color-surface-soft);
  font-size: var(--text-lg);
  font-weight: var(--weight-strong);
  line-height: 1;
  cursor: pointer;
  transition:
    color var(--motion-duration) ease,
    background-color var(--motion-duration) ease,
    border-color var(--motion-duration) ease;
}

.remove-icon-button:hover,
.remove-icon-button:focus-visible {
  color: var(--color-danger);
  border-color: var(--color-danger);
}

/* Sits inside a table cell next to the client name, so it must not set the
   row height: smaller than the standalone control, same affordance. */
.copy-icon-button--inline {
  width: 26px;
  min-width: 26px;
  height: 26px;
  border-radius: var(--radius-sm);
}

.copy-icon-button--inline::before,
.copy-icon-button--inline::after {
  width: 9px;
  height: 11px;
}

.order-title-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
  flex-wrap: wrap;
}

.table-link {
  color: var(--color-link);
  font-weight: var(--weight-accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* Ссылки на заявку и на маршрут (пак 2026-09-03, пп. 39 и 41) дожили до
   состояний остального приложения: наведение красит тем же токеном, что и
   активная кнопка, фокус с клавиатуры — общим кольцом `--focus-ring`, а не
   умолчанием браузера. Раскладка не двигается: цвет и кольцо, ничего больше. */
.table-link:hover {
  color: var(--color-accent-hover);
}

.table-link:focus-visible {
  outline: none;
  border-radius: var(--radius-sm);
  box-shadow: var(--focus-ring);
}

.table-link.mono {
  white-space: nowrap;
}

/* A long identifier (order_no/route_no up to 64 chars) inside a page title
   must wrap within the heading instead of clipping behind the panel's
   overflow:hidden on narrow viewports. Short identifiers are visually
   unchanged: normal wrapping has no effect on content that already fits.
   List-cell .table-link.mono keeps nowrap above. */
.view-title .mono {
  overflow-wrap: anywhere;
}

.cell-stack,
.order-card__head > div {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

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

/* Перенос разрешён: в колонке «Действия» списка «Копировать» встаёт под
   «Редактировать» (почему — у `.copy-icon-button--row`), в мобильной карточке
   ряд действий и так переносится. */
.order-actions-primary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-width: 0;
  flex-wrap: wrap;
}

.cell-stack span,
.order-card__head span,
.order-card dt {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

/* A long order_no (up to 64 chars) in a mobile list-card head must wrap inside
   the card instead of clipping behind the panel's overflow:hidden. Scoped to
   the card head so the list-table .table-link.mono nowrap and the route-card
   <strong class="mono"> (different element) are both unaffected. Short
   identifiers are visually unchanged: normal wrapping has no effect on content
   that already fits. */
.order-card__head .table-link.mono {
  white-space: normal;
  overflow-wrap: anywhere;
}

.num {
  text-align: right !important;
  white-space: nowrap;
}

.orders-cards {
  display: none;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
}

.order-card {
  display: grid;
  gap: var(--space-4);
  min-width: 0;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.order-card__head {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  justify-content: space-between;
}

/* Скрытая из архива заявка несёт две метки: «Скрыта» и статус закрытия. В
   таблице они стоят в двух колонках, в шапке мобильной карточки — друг за
   другом справа, с переносом на узких экранах, чтобы ни одна не выдавливала
   другую и не расширяла карточку. */
.order-card__badges {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-1);
  min-width: 0;
}

.order-card__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
  margin: 0;
}
/* Карточка сотрудника на телефоне. Ниже порога `phone` шапка карточки
   становится одноколоночной сеткой, и бейдж статуса растягивался на всю
   ширину — плашка читалась как пустое поле ввода. Бейдж остаётся своей
   ширины; дублирующая строка «Статус» из тела карточки убрана в шаблоне.
   Правило намеренно ограничено сотрудниками: заявки, доставки и курьер в
   эту задачу не входят. */
.employees-cards .order-card__head .badge,
/* Та же мера для карточки заявки: с переработкой карточки (2026-09-05) шапка
   стала опорной точкой карточки, и растянутый на всю ширину бейдж статуса
   читался как пустое поле ввода. Бейдж остаётся своей ширины. */
.orders-cards .order-card__head .badge {
  justify-self: start;
}


.order-card__grid div {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.order-card__grid .is-wide {
  grid-column: 1 / -1;
}

/* Мобильная карточка заявки (2026-09-05): сводка сверху, всё остальное — под
   нативным `<details>`. Раскрытие пользуется общей раскладкой дисклоужера
   (`.filter-collapsible`), как уже делает сводка маршрута, поэтому шеврон,
   рамка и фокус здесь не заводятся заново. Отступ сверху отделяет раскрытие
   от единственной видимой кнопки. */
.order-card__more {
  margin-top: 0;
}

.order-card__more > .order-card__more-summary {
  justify-content: flex-start;
  gap: var(--space-2);
  font-size: var(--text-sm);
}

.order-card__more-body {
  display: grid;
  gap: var(--space-4);
  margin-top: var(--space-3);
}

.order-card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  justify-content: flex-start;
  min-width: 0;
}

.btn-compact {
  min-height: 34px;
  padding-inline: var(--space-3);
}

.order-card dd {
  margin: 0;
  overflow-wrap: anywhere;
  font-weight: var(--weight-strong);
}

.courier-screen {
  display: grid;
  gap: var(--space-4);
}

/* Courier detail: bound readable width on wide viewports (no sparse full-width
   key/value stretching), with the working panel + terminal action as the main
   column and cargo/order meta as the aside. Mobile stays sequential cards in
   the same information order. */
.courier-detail-layout {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  max-width: 1160px;
}

.courier-detail-main,
.courier-detail-aside {
  display: grid;
  gap: var(--space-3);
  min-width: 0;
  align-items: start;
}

/* Исключение «tablet» (1024). Правая колонка карточки — не класс устройства, а
   ширина контента: рабочая панель + aside `minmax(320px, 0.56fr)` перестают
   быть тесными примерно с 1024px. Свести порог к `shell` (920) — рабочая
   колонка проседает; свести к `dense` (1280) — карточка теряет вторую колонку
   на всём диапазоне 1024–1279, то есть становится длиннее ровно там, где
   заказчик просит меньше прокрутки. Порог оставлен и помечен. */
@media (min-width: 1024px) { /* исключение «tablet» */
  .courier-detail-layout {
    grid-template-columns: minmax(0, 1fr) minmax(320px, 0.56fr);
    gap: var(--space-4);
    align-items: start;
  }
}

/* Desktop shows the courier table; cards are the mobile projection. */
.courier-table-wrap {
  width: 100%;
  overflow-x: auto;
  border-block: 1px solid var(--color-border);
  background: var(--color-surface);
}

.courier-table {
  width: 100%;
  /* Десять колонок списка заказчика (04.09.2026): №, заявка, груз, время,
     адрес, телефон, клиент, примечание, оплата, статус. Нижняя граница поднята
     с 1080 до 1231 px (2026-09-05): номер заявки в колонке «Заявка» стал
     неразрывным, и самому длинному боевому номеру нужно 219 px + 2 ×
     var(--space-3) = 243 px. 1231 px — это ширина области списка на 1280 px
     при наличии вертикальной полосы прокрутки, то есть худший случай; ниже
     1280 таблица не рисуется вовсе (показываются карточки), поэтому
     внутренней горизонтальной прокрутки не возникает ни на одной рабочей
     ширине. Доли ниже посчитаны от этих 1231 px и на каждой колонке оставляют
     запас над её минимумом, замеренным в браузере. */
  min-width: 1231px;
  border-collapse: collapse;
  /* Фиксированная раскладка: ширины колонок берутся из `th`, а не из длины
     самого широкого бейджа. */
  table-layout: fixed;
}

/* Бейджи и кнопка в стопке ячейки не растягиваются на всю колонку. */
.courier-table .cell-stack > .badge,
.courier-table .courier-table__status > .btn {
  justify-self: start;
}

.courier-table th,
.courier-table td {
  padding: var(--space-3);
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--color-border);
  font-size: var(--text-sm);
}

.courier-table th {
  font-weight: var(--weight-accent);
  color: var(--color-text-muted);
  background: var(--color-surface-soft);
}

.courier-table .cell-muted,
.courier-table .cell-stack span {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

.courier-table .cell-stack strong,
.courier-table .cell-stack .courier-note {
  color: var(--color-text);
  font-size: var(--text-sm);
}

.courier-table td .badge {
  margin-bottom: var(--space-1);
}

/* Бюджет ширин на 1366 (контент ~1317 px): адрес и клиент получают запас,
   номер/время/оплата/статус — ровно своё. Явные ширины, чтобы браузер не
   раздавал место по длине бейджей и не сжимал адрес до одного слова. */
/* Минимумы колонок на 1231 px (замер в браузере, отступ ячейки 2 ×
   var(--space-3)): № 39, «Заявка» 243 (номер одной строкой), «Груз» 110,
   «Время» 134 (метка не переносится), «Адрес» 70, «Телефон» 89, «Клиент» 88,
   «Примечание» 117, «Оплата» 129, «Статус» 125. Сумма минимумов — 1144 px,
   поэтому свободные 87 px отданы адресу и грузу: это то, что курьер читает
   на ходу.
   С 27.09 группы цифр телефона неразрывны (В-06, правило у `.phone-group`):
   номер рвётся только по пробелу — «+375 33 / 245-67-89». Самая длинная
   группа — 76 px; на 1280 «Телефону» остаётся 71 px, и группа заходит на 5 px
   в собственный отступ ячейки (12 px), до соседнего текста остаётся 19 px.
   Одной строкой телефону нужно ещё 60 px, кнопке «Отметить выдачу» — 55:
   свободных в таблице 87 px, и адрес сжался бы до разрыва слов
   («Притыцког / о» при 105 px). */
.courier-table th:nth-child(1) { width: 3.17%; }
.courier-table th:nth-child(2) { width: 20.10%; }
.courier-table th:nth-child(3) { width: 9.10%; }
.courier-table th:nth-child(4) { width: 10.97%; }
.courier-table th:nth-child(5) { width: 10.04%; }
.courier-table th:nth-child(6) { width: 7.72%; }
.courier-table th:nth-child(7) { width: 7.96%; }
.courier-table th:nth-child(8) { width: 9.75%; }
.courier-table th:nth-child(9) { width: 10.72%; }
.courier-table th:nth-child(10) { width: 10.47%; }

/* Номер заявки стоит одной строкой — тот же приём, что в списке заявок и в
   списках заявок маршрута. До 05.09 он рвался по любому месту: колонке
   доставалось 119 px при 243 px, нужных 26-значному номеру, и курьер читал
   свой единственный опознавательный признак заявки по кускам. Ширину дала
   поднятая нижняя граница таблицы, а не соседние колонки. */
.courier-table .table-link.mono {
  white-space: nowrap;
}

.courier-table__index {
  color: var(--color-text-muted);
}

.courier-table__time {
  white-space: nowrap;
}

/* Сумма в таблице переносится между валютами, а не растягивает колонку;
   кнопка выдачи при нехватке места переносится на две строки. */
.courier-table .courier-payment__sum {
  white-space: normal;
}

.courier-table__status .btn {
  white-space: normal;
  text-align: center;
}

/* Телефон в таблице переносится между группами (`.phone-group`), номер без
   пробелов — после дефиса. Посреди цифр он рвётся, только если кусок до
   дефиса шире ячейки: «+375(29)245-» (12 знаков) не помещается в «Телефон»
   на 1280–1440 и заходил на «Клиент» на 6–18 px — и до партии 319c463, и после
   (ревью 319c463, находка 1). Группы номера неразрывны и так. */
.courier-table .courier-phone {
  overflow-wrap: break-word;
}

/* В таблице примечание клиента и пункт назначения — одна строка с многоточием,
   как в списке заявок; полный текст остаётся в карточке. */
.courier-table .client-note-projection {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.courier-table__status .btn {
  justify-self: start;
}

.courier-phone {
  color: var(--color-link);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  overflow-wrap: anywhere;
}

/* Выданная строка читается как закрытая: чуть приглушена, бейдж и номер
   остаются полноконтрастными. */
.courier-table tr.is-issued td:not(:first-child) .cell-wrap,
.courier-table tr.is-issued .courier-note,
.courier-card.is-issued .courier-card__rows dd {
  color: var(--color-text-muted);
}

.courier-cards {
  display: none;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
}

.cell-wrap {
  overflow-wrap: anywhere;
  min-width: 0;
}

.courier-card {
  display: grid;
  gap: var(--space-3);
  min-width: 0;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.courier-card__head {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  justify-content: space-between;
  min-width: 0;
}

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

.courier-card__id .table-link.mono {
  white-space: normal;
  overflow-wrap: anywhere;
  font-size: var(--text-base);
}

/* Порядковый номер строки — первый пункт списка заказчика. */
.courier-card__index {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-accent);
}

.courier-card__index::before {
  content: "№ ";
}

.courier-card__date {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

.courier-card__cargo {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  min-width: 0;
  overflow-wrap: anywhere;
}

.courier-card__cargo strong {
  color: var(--color-ink);
  font-size: var(--text-base);
}

.courier-card__cargo .mono {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

/* Строки карточки: подпись слева, значение справа — одна строка на пункт
   списка заказчика, в её порядке. */
.courier-card__rows {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  gap: var(--space-2) var(--space-3);
  margin: 0;
}

.courier-card__rows > div {
  display: contents;
}

.courier-card__rows dt {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  line-height: 1.6;
}

.courier-card__rows dd {
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--color-text);
  font-weight: var(--weight-strong);
}

.courier-card__address {
  color: var(--color-ink);
}

.courier-card__phone {
  justify-self: start;
  color: var(--color-link);
  font-weight: var(--weight-accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  overflow-wrap: anywhere;
}

.courier-card__client {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-2);
  min-width: 0;
}

.courier-card__client .client-note-projection {
  font-weight: var(--weight-accent);
}

.courier-note {
  overflow-wrap: anywhere;
  white-space: normal;
}

.courier-note--courier {
  color: var(--color-text-muted);
}

/* Оплата: статус и сумма в одну стопку. Неоплаченная сумма подписана
   нейтрально — «Стоимость», а не «к получению»: флаг оплаты один на заявку, и
   при двух валютах одна из показанных сумм может быть уже закрыта
   (независимое ревью 2026-09-04, F1). Оплаченная — итог для сверки. Кнопки
   «Оплата» здесь нет и место под неё не резервируется (заказчик распишет
   оплаты отдельно). */
.courier-payment {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
  min-width: 0;
}

.courier-payment__sum {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-2);
  color: var(--color-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-strong);
}

.courier-payment__part {
  white-space: nowrap;
}

.courier-payment__label {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-body);
}

.courier-payment__sum--empty {
  color: var(--color-text-muted);
  font-weight: var(--weight-body);
  white-space: normal;
}

.courier-table .courier-payment__sum,
.courier-table .courier-payment__sum .mono {
  color: var(--color-text);
  font-size: var(--text-sm);
}

.courier-table .courier-payment__label {
  font-size: var(--text-xs);
}

.list-meta--courier {
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* Сумма в карточке/подтверждении: валюты в ряд, при нехватке места — по одной
   на строку, без разрыва внутри «888.88 RUB». Заглушка «не указана» — обычным
   приглушённым текстом, не ценой. */
.courier-price dd {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
}

.courier-price dd .cell-muted {
  color: var(--color-text-muted);
  font-family: inherit;
  font-size: var(--text-sm);
}

.courier-scope {
  color: var(--color-text);
}

.courier-card__actions,
.courier-detail-action {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  justify-content: flex-start;
}

.filter-bar--courier {
  display: grid;
  /* Дата · статус · «Сегодня · Все даты» · кнопка (видна без JS). */
  grid-template-columns:
    minmax(160px, 220px)
    minmax(140px, 200px)
    auto
    minmax(0, 1fr);
  gap: var(--space-2) var(--space-3);
  padding-block: var(--space-3);
  align-items: end;
}

.filter-bar--courier > .filter-field,
.filter-bar--courier > .filter-actions {
  grid-column: auto;
  min-width: 0;
}

.filter-actions--courier {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: end;
}

/* «Сегодня · Все даты» — быстрые переходы рядом с датой; на широком экране в
   одном ряду с фильтром, выровнены по нижней кромке контролов. */
.courier-date-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  min-height: 40px;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

.courier-date-links a {
  color: var(--color-link);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* Confirmation stays a compact focused step: bound width so the summary of
   who/where/when and the primary «Подтвердить выдачу» remain one visual group
   on wide desktops. */
.courier-confirm {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  max-width: 760px;
}

.courier-confirm__summary,
.courier-confirm__body {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.courier-confirm__text {
  margin: 0;
  overflow-wrap: anywhere;
}

.courier-confirm__form {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.detail-note {
  margin: 0;
  color: var(--color-text-muted);
}

.notice-banner--error {
  border-color: rgb(220 38 38 / 0.24);
  color: var(--color-ink);
  background: rgb(220 38 38 / 0.08);
}

.detail-status {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
}

.detail-status--inline {
  padding: 0;
  border-bottom: 0;
}

.detail-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
  align-items: start;
  padding: var(--space-5);
}

.detail-section {
  display: grid;
  gap: var(--space-3);
  align-self: start;
  min-width: 0;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.detail-section h2 {
  color: var(--color-ink);
  font-size: var(--text-lg);
}

.detail-section--wide {
  grid-column: 1 / -1;
}

/* Стороны ЦМР в обзоре юрлиц: пара одна на систему, поэтому это не карточка
   юрлица, а один блок над списком. Композиция — существующая: рамка и фон
   `.detail-section`, поля `.field`, кнопка `.btn`; своего визуального языка
   блок не заводит. На узком экране поля встают в столбец. */
.cmr-sides {
  display: grid;
  gap: var(--space-3);
  margin-block: var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.cmr-sides__title {
  color: var(--color-ink);
  font-size: var(--text-lg);
}

.cmr-sides__hint {
  max-width: 980px;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

.cmr-sides__form {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--space-3) var(--space-4);
}

.cmr-sides__form .field {
  flex: 1 1 16rem;
  min-width: 0;
}

.cmr-sides__readout {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

.cmr-sides__readout dt {
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.cmr-sides__readout dd {
  color: var(--color-ink);
}

/* История правок пары — тот же свёрнутый блок, что в Редакторе
   (`editor/_history.html`), но внутри карточки сторон: верхнюю черту и поля
   даёт сама `.cmr-sides`, своих у блока нет. `min-width: 0` держит таблицу
   истории внутри ячейки сетки на узком экране. */
.cmr-history {
  min-width: 0;
}

.audit-timeline {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.audit-event {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr);
  gap: var(--space-3);
}

.audit-event__marker {
  width: 10px;
  height: 10px;
  margin-top: 5px;
  border-radius: var(--radius-pill);
  background: var(--color-accent);
  box-shadow: 0 0 0 4px rgb(96 165 250 / 0.16);
}

.audit-event__body {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.audit-event__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.audit-event__head time,
.audit-event__body p,
.audit-empty {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

/* Route status-history list (routes/detail). Mirrors the clean-list language of
   .audit-timeline / .detail-list: no browser bullets, no default <ul> indent,
   just a calm stacked log where each entry reads as a muted timestamp over the
   description. Does not change audit content, ordering or visibility. */
.audit-list {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.audit-list__item {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.audit-list__time {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.audit-list__text {
  color: var(--color-text);
  overflow-wrap: anywhere;
}

/* Per-field change rows inside an order audit event (orders/detail). A <dl> with
   wrapped dt/dd pairs: aligns with the .detail-kv meta-text pattern (muted label
   over the value) and drops the browser default 40px <dd> indent. Presentation
   only; the old → new text is unchanged. */
.audit-change-list {
  display: grid;
  gap: var(--space-2);
  margin: 0;
}

.audit-change-list__row {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.audit-change-list__row dt {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.audit-change-list__row dd {
  margin: 0;
  overflow-wrap: anywhere;
  color: var(--color-ink);
}

.detail-list {
  display: grid;
  gap: var(--space-3);
  margin: 0;
}

.detail-list div {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.detail-list dt {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
  text-transform: uppercase;
}

.detail-list dd {
  min-width: 0;
  margin: 0;
  overflow-wrap: anywhere;
  font-weight: var(--weight-strong);
}

.order-detail-body {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-5);
}

/* Route detail keeps the summary and the next lifecycle action in one first
   working row. The route-specific grid leaves shared detail surfaces unchanged. */
.route-detail-body {
  gap: var(--space-4);
}

.route-detail-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 0.46fr);
  gap: var(--space-4);
  align-items: start;
}

.route-summary-panel,
.route-status-panel,
.route-orders-panel,
.route-history-panel {
  min-width: 0;
}

/* Свёрнутая история статусов: та же нативная раскрывашка, что у «Подробностей
   автомобиля» выше и у списка заявок в карточке клиента, поэтому и вид у неё
   тот же. Заголовок остаётся заголовком уровня панели — он просто стоит
   внутри `summary`. */
.route-history-disclosure > .filter-collapsible__summary {
  justify-content: flex-start;
  gap: var(--space-2);
}

.route-history-disclosure > .filter-collapsible__summary h2 {
  color: var(--color-ink);
  font-size: var(--text-lg);
}

.route-history-disclosure__count {
  color: var(--color-text-muted);
  font-weight: var(--weight-strong);
}

.route-history-disclosure > .audit-list,
.route-history-disclosure > .form-section__hint {
  margin-top: var(--space-3);
}

/* Сетка сводки размеряется содержимым панели, а не шириной экрана: панель
   делит первую строку карточки с панелью статуса, поэтому фиксированное число
   колонок здесь давало бы то слишком узкие, то слишком широкие ячейки. */
.route-summary-grid {
  grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
  gap: var(--space-3) var(--space-4);
}

/* Без панели статуса сводка занимает всю ширину карточки. */
.route-detail-top > .route-summary-panel:only-child {
  grid-column: 1 / -1;
}

/* Шапка карточки: номер, направление и крупный статус одной строкой слева
   (пак 2026-09-03, п. 27: «сам статус переносим туда, где стрелочка» — к
   номеру и направлению; рукописный макет 2026-09-01 ставил его справа, более
   свежая просьба главнее). */
.route-summary-head {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-5);
  min-width: 0;
}

.route-summary-head__main {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-6);
  min-width: 0;
}

.route-summary-head__main .detail-kv__item {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.route-summary-head__main dt {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.route-summary-head__main dd {
  margin: 0;
  min-width: 0;
  color: var(--color-ink);
  font-size: var(--text-lg);
  font-weight: var(--weight-heading);
  overflow-wrap: anywhere;
}

.route-summary-status {
  display: grid;
  justify-items: start;
  gap: var(--space-1);
  min-width: 0;
}

.route-summary-status > span:first-child {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

/* Тот же «кружочек», что и везде, только крупнее: по правилу заказчика статус —
   именно то, на что надо обращать внимание («прям крупно в кружочке»). Тона
   берутся у общего `.badge`, здесь задаётся только размер. */
.route-status-chip .badge {
  min-height: 40px;
  padding: var(--space-2) var(--space-5);
  font-size: var(--text-base);
}

/* Служебные подробности: на экране, но не в первом экране. */
.route-summary-more > .filter-collapsible__summary {
  justify-content: flex-start;
  gap: var(--space-2);
  font-size: var(--text-sm);
}

.route-summary-more__body {
  margin-top: var(--space-3);
}

.route-orders-heading > span {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.route-status-panel {
  gap: var(--space-3);
}

.route-status-next {
  display: grid;
  gap: var(--space-1);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-soft);
}

.route-status-next__label {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.route-status-next strong,
.route-status-confirm strong {
  color: var(--color-ink);
  overflow-wrap: anywhere;
}

.route-status-form {
  display: grid;
  gap: var(--space-3);
}

.route-status-confirm {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--space-2);
  min-width: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  background: var(--color-surface);
  cursor: pointer;
}

.route-status-confirm input {
  margin-top: 3px;
}

.route-status-confirm__copy {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.route-status-confirm__copy small {
  color: var(--color-text-muted);
  line-height: 1.4;
}

.route-status-form .btn {
  justify-self: start;
}

/* Смена статуса по просьбе заказчика (пак 2026-09-01, п. 21): кнопка «Статус»
   со стрелкой, список статусов, «Применить», подтверждение отдельным окном.
   Выбирается только разрешённый следующий переход — остальные строки остаются
   на экране и объясняют, почему они заперты. */
.route-status-menu {
  min-width: 0;
}

.route-status-menu__trigger {
  width: fit-content;
  list-style: none;
}

.route-status-menu__trigger::-webkit-details-marker {
  display: none;
}

.route-status-menu__trigger::after {
  content: "";
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-right: 2px solid currentcolor;
  border-bottom: 2px solid currentcolor;
  transform: rotate(45deg);
  transition: transform var(--motion-duration) ease;
}

.route-status-menu[open] > .route-status-menu__trigger::after {
  transform: rotate(225deg);
}

/* Меню «Складской список» в шапке карточки маршрута — появляется, только
   когда у юрлица маршрута включено поле «Вид доставки» и листов несколько:
   весь маршрут и по одному на вид. Стрелка — та же, что у «Статуса»; список
   всплывает над страницей, чтобы не раздвигать шапку. */
.route-print-menu {
  position: relative;
}

.route-print-menu__list {
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  z-index: 20;
  display: grid;
  gap: var(--space-1);
  min-width: 100%;
  width: max-content;
  max-width: min(320px, calc(100vw - 2 * var(--space-4)));
  margin: 0;
  padding: var(--space-2);
  list-style: none;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  box-shadow: var(--shadow-soft);
}

.route-print-menu__item {
  display: block;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--color-ink);
  text-decoration: none;
  overflow-wrap: anywhere;
}

.route-print-menu__item:hover,
.route-print-menu__item:focus-visible {
  background: var(--color-surface-soft);
}

/* Список ведёт себя как меню: он не растягивается на всю панель, иначе на
   широком экране подпись шага уезжала бы от названия статуса через полпанели. */
.route-status-menu__list {
  display: grid;
  gap: var(--space-1);
  width: fit-content;
  min-width: 0;
  max-width: 100%;
  margin: var(--space-2) 0 0;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

.route-status-option {
  display: grid;
  grid-template-columns: auto max-content minmax(0, 1fr);
  align-items: center;
  gap: var(--space-2) var(--space-4);
  min-width: 0;
  min-height: 40px;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.route-status-option:hover {
  background: var(--color-surface-soft);
}

.route-status-option__label {
  color: var(--color-ink);
  font-weight: var(--weight-accent);
  overflow-wrap: anywhere;
}

.route-status-option__hint {
  min-width: 0;
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  overflow-wrap: anywhere;
}

/* Недоступный шаг не прячется: он и есть «где мы находимся» на всём пути. */
.route-status-option--locked,
.route-status-option--locked:hover {
  cursor: not-allowed;
  background: transparent;
}

.route-status-option--locked .route-status-option__label {
  color: var(--color-text-muted);
  font-weight: var(--weight-body);
}

/* Цвет и вес берёт общий `.field-error`: это та же ошибка ввода, что и в
   формах, второй красной шкалы в системе быть не должно. */
.route-status-hint {
  margin: 0;
}

/* Финальный статус: объяснение вместо мёртвой кнопки. */
.route-status-final {
  margin: 0;
  color: var(--color-text-muted);
}

/* Что именно произойдёт с заявками: числа считает сервер, поэтому это
   перечень фактов, а не абзац с оценкой. */
.status-facts {
  display: grid;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--color-text);
}

.status-facts strong {
  color: var(--color-ink);
}

.route-orders-heading {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.route-driver-cell {
  min-width: 0;
}

.route-driver-cell > span,
.route-driver-cell > strong,
.route-driver-picker .field-hint,
.route-summary-grid dd {
  overflow-wrap: anywhere;
}

/* Форма создания маршрута: компактная, с равнением влево, поля шириной по
   содержимому (заказчик, пак 2026-09-01, скриншоты 16 и 17: «все компактно на
   страничке, чтобы не надо было мышкой по всему экрану бегать», «равнение по
   самому длинному слову»). Узкие колонки вместо растянутой 12-колоночной
   сетки на всю оболочку.

   С 08.09 колонок ТРИ, а не две, и правая половина листа больше не пустует:
   форма занимала 1065 px при вьюпорте 768 (замер 08.09 на 1366×768) — то есть
   ровно то, на что заказчик и жаловалась, — при том что справа от полей
   оставалось около 660 px пустой ширины. Высоту держал один блок подбора
   водителя: поиск, список, карточка авто и три пояснения шли в нём стопкой
   на всю ширину сетки. Карточка авто вынесена из подбора в соседнюю ячейку
   (см. шаблон), поля разложены по трём колонкам явной раскладкой, и форма
   умещается в экран. Порядок чтения слева направо — её же: водитель,
   направление, даты. */
.route-form {
  max-width: none;
}

.route-form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(200px, 300px));
  justify-content: start;
  align-items: start;
  gap: var(--space-4);
  min-width: 0;
}

/* Обёртки колонок. Ниже 1180 px они снимаются целиком, и ячейки снова
   раскладывает сама сетка — двумя колонками, как до 08.09. */
.route-form-col {
  display: contents;
}

/* Пара дат рейса. Ниже 520 px — стопкой: два поля даты в 390 px обрезают
   собственный календарный значок. */
.route-form-dates {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
  gap: var(--space-4);
  min-width: 0;
}

@media (max-width: 519.98px) {
  .route-form-dates {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Три колонки-стопки там, где для них есть ширина. Каждая колонка — свой
   вертикальный поток, поэтому высокий блок подбора водителя стоит РЯДОМ с
   остальными полями, а не растит общую строку сетки под себя:
     колонка 1 — подбор водителя,
     колонка 2 — автомобиль водителя, номер маршрута,
     колонка 3 — направление, дата выезда, плановое прибытие. */
@media (min-width: 1180px) {
  /* Первая колонка шире двух остальных: в ней две длинные подписи — про
     подбор по юрлицу и про «Добавить нового водителя», — и именно они держат
     высоту всей формы. На 360 px каждая занимала четыре строки, на 440 px —
     три; это те самые 34 px, которых форме не хватало до одного экрана на
     1366×768. Поля дат и списки остаются узкими: разгонять их до 440 px
     значило бы вернуть стрелку списка далеко от значения (заказчик, пак
     2026-09-01, п. 17). */
  .route-form-grid {
    grid-template-columns: minmax(280px, 440px) repeat(2, minmax(200px, 380px));
  }

  .route-form-col {
    display: grid;
    align-content: start;
    gap: var(--space-4);
    min-width: 0;
  }
}

/* Номер маршрута с 08.09 присваивает система (заказчик 01.09 в 19:12), поэтому
   в форме он не поле ввода, а показанное значение. Вертикальные отступы
   повторяют внутренние отступы `.input`, чтобы значение стояло на той же
   высоте, что и соседние поля сетки, и строка формы не съезжала. */
.route-no-assigned {
  margin: 0;
  padding: 12px 0;
  color: var(--color-text);
  font-size: var(--text-base);
  font-weight: var(--weight-accent);
  line-height: 1.4;
  overflow-wrap: anywhere;
}

/* До сохранения номера ещё нет: подпись объясняет это словами и звучит тише
   настоящего значения. */
.route-no-assigned--pending {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-body);
}

/* Кнопки сохранения встают по левому краю секции формы, а не по правому краю
   оболочки. Форма занимает всю ширину shell, а сетка полей упирается влево,
   поэтому общий для всех форм `justify-content: flex-end` уводил «Создать
   маршрут» через пустую ширину к правому краю экрана (заказчик, пак
   2026-09-01, скриншоты 16 и 17: «все компактно на страничке, чтобы не надо
   было мышкой по всему экрану бегать»). То же решение уже принято на формах
   реквизитов юрлица. */
.route-form > .form-actions {
  justify-content: flex-start;
}

/* Поиск и выбор водителя — одно поле: строка ввода с кнопкой и список ниже.
   Ниже 1180 px колонок две, и подбор занимает обе: в нём три элемента подряд.
   От 1180 px он встаёт первой колонкой из трёх — см. раскладку выше. */
.route-driver-picker {
  grid-column: 1 / -1;
  min-width: 0;
  max-width: 620px;
}

.route-driver-picker__title {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-accent);
}

.route-driver-picker__search {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

.route-driver-picker__search .input {
  flex: 1 1 200px;
  min-width: 0;
}

.route-driver-picker__search .btn {
  flex: 0 0 auto;
}

/* «Эти все стрелочки не надо так далеко… равнение по самому длинному слову»
   (заказчик, пак 2026-09-01, п. 17). Список ФИО занимал все 616 px блока при
   самом длинном ФИО «Астапенко Виктор Николаевич», и стрелка стояла далеко от
   значения. `width: auto` даёт селекту ширину по самому длинному варианту
   (замер после правки: 263 px на 1366/1440/1920, 298 px на 390/430),
   `max-width: 100%` не пускает его за границу блока на длинном ФИО, а
   `min-width` держит его достаточно широким, чтобы «Не выбран» не читался
   как обрубок. Нижняя граница берётся через `min(…, 100%)`: на узком экране
   `min-width` сильнее `max-width`, и голые 260 px вылезли бы за блок.
   Поле поиска над списком не трогается: в него печатают, и ширина ему нужна. */
.route-driver-picker select.select {
  width: auto;
  min-width: min(260px, 100%);
  max-width: 100%;
  /* `.route-driver-picker` — грид (`.field`), и его дети по умолчанию тянутся
     на всю колонку: без `justify-self` ширина `auto` у списка всё равно
     давала те же 616 px. */
  justify-self: start;
}

/* Автомобиль выбранного водителя — соседняя ячейка сетки формы (до 08.09 он
   стоял внутри блока подбора и растил его на 100 px). Своих констант нет: та же
   мягкая поверхность, тот же радиус и та же шкала отступов, что у остальных
   вспомогательных блоков формы. Пары «подпись — значение» повторяют .detail-kv,
   но в две колонки: блок стоит внутри узкой колонки формы маршрута. */
.route-driver-vehicle {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface-soft);
  min-width: 0;
}

.route-driver-vehicle__title {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.route-driver-vehicle__empty {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  /* Блок стоит внутри `.field`, который держит акцентный вес для подписи поля;
     пояснение обязано читаться как пояснение. */
  font-weight: var(--weight-body);
  line-height: 1.4;
}

.route-driver-vehicle__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2) var(--space-3);
  margin: 0;
  min-width: 0;
}

.route-driver-vehicle__item {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.route-driver-vehicle__item dt {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.route-driver-vehicle__item dd {
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--color-ink);
  font-size: var(--text-sm);
  font-weight: var(--weight-strong);
}

/* Одна колонка на телефоне: две пары в 390 px обрезают «Грузоподъёмность, т». */
@media (max-width: 520px) {
  .route-driver-vehicle__list {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* «Добавить нового водителя» — последний элемент подбора, отделён от подписей
   тем же шагом, что и остальные блоки поля. */
.route-driver-picker__add {
  display: grid;
  justify-items: start;
  gap: var(--space-1);
  min-width: 0;
}

/* Исключение «tablet» (1024), обратная половина той же пары: карточка маршрута
   складывается в одну колонку ровно там, где правая панель статуса перестаёт
   помещаться рядом с рабочей. Причина и цена сведения к шкале — см. комментарий
   у `.courier-detail-layout`. */
@media (max-width: 1023.98px) { /* исключение «tablet» */
  .route-detail-top {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 767.98px) { /* ниже mobile */
  .route-form-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .route-orders-panel .detail-panel__head--row {
    align-items: stretch;
    flex-direction: column;
  }

  .route-orders-panel .head-actions {
    justify-content: flex-start;
  }

  /* Блок «Заявки» стоит внутри панели со своим отступом; отступы фильтра,
     строки «Показано», карточек и листалки страницы сдвигали всё это на 12 px
     правее заголовка и кнопок «История» и «Выбрать несколько» (В-17). */
  .route-orders-panel .filter-bar,
  .route-orders-panel .list-meta,
  .route-orders-panel .orders-cards,
  .route-orders-panel .pagination {
    padding-inline: 0;
  }

  .route-orders-panel .head-actions .btn,
  .route-status-form .btn {
    flex: 1 1 auto;
  }

  /* Шапка на телефоне прижата влево — меню печати раскрывается от левого края
     кнопки, а не уходит за край экрана. */
  .route-print-menu__list {
    right: auto;
    left: 0;
  }

  .route-positions-bar .btn {
    flex: 1 1 auto;
  }

  .route-status-form .btn {
    width: 100%;
  }
}

.order-note {
  display: grid;
  gap: var(--space-1);
  max-width: 980px;
  border: 1px solid rgb(245 158 11 / 0.24);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  color: #492f08;
  background: rgb(245 158 11 / 0.09);
}

.order-note span {
  color: #8a5b0a;
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.order-note p {
  overflow-wrap: anywhere;
  font-weight: var(--weight-strong);
}

.detail-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
  gap: var(--space-4);
  align-items: start;
}

.detail-main {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
  min-width: 0;
}

.detail-side {
  display: grid;
  gap: var(--space-4);
  min-width: 0;
}

.detail-panel {
  display: grid;
  gap: var(--space-3);
  align-self: start;
  min-width: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  background: var(--color-surface);
}

.detail-panel--compact {
  grid-column: 1 / -1;
}

/* Order-detail Comments panel. Unlike the generic --compact full-span, it must
   occupy the second cell of row 2 (beside Pickup) when .detail-main is a
   2-column grid, so the desktop main grid reads as a true 2×2:
   Клиент | Направление  /  Забор | Комментарии. It only reclaims the full row
   once the main grid itself collapses to a single column (mobile). */
.detail-panel--comments {
  grid-column: auto;
}

.detail-panel__head {
  display: grid;
  gap: var(--space-1);
}

.detail-panel__head--row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.detail-panel__head h2 {
  color: var(--color-ink);
  font-size: var(--text-lg);
}

.detail-panel__head span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  height: 28px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  color: var(--color-text-muted);
  background: var(--color-surface-soft);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.route-orders-heading > span {
  min-width: 0;
  height: auto;
  border: 0;
  border-radius: 0;
  padding: 0;
  color: var(--color-text-muted);
  background: transparent;
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
  /* Общее правило счётчика шапки центрирует текст; здесь подпись во всю
     ширину, и на телефоне «1 в маршруте» вставала по центру под прижатым
     влево «Заявки» (визуальная проверка 26.09, В-17). */
  justify-content: flex-start;
}

.detail-kv {
  display: grid;
  gap: var(--space-3);
  margin: 0;
}

.detail-kv--split {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* В панели «Комментарии» с 06.09 одна пара — «Курьеру»: комментарий заявки
   показан баннером над панелями и здесь не повторяется. Одна колонка, чтобы
   единственное значение не жалось в половину панели. */
.detail-kv--comments {
  grid-template-columns: minmax(0, 1fr);
}

.detail-kv__item {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.detail-kv__item--wide {
  grid-column: 1 / -1;
}

.detail-kv dt {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.detail-kv dd {
  min-width: 0;
  margin: 0;
  overflow-wrap: anywhere;
  color: var(--color-ink);
  font-weight: var(--weight-strong);
}

/* Пояснение под значением и под панелью: тот же приглушённый вес и цвет, что у
   остальной вспомогательной подписи, чтобы не спорить со значением. */
.detail-kv__note,
.detail-panel__note {
  display: block;
  max-width: 70ch;
  margin: 0;
  color: var(--color-text-muted);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-body);
  line-height: 1.4;
}

.detail-panel__note {
  font-size: var(--text-sm);
}

.detail-kv__item--price {
  margin-block: var(--space-1);
  border: 1px solid rgb(96 165 250 / 0.28);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  background: rgb(96 165 250 / 0.10);
}

.detail-kv__item--price dd {
  color: #1d4ed8;
  font-size: var(--text-xl);
  line-height: var(--leading-tight);
}

.audit-timeline--compact {
  gap: var(--space-2);
}

.audit-timeline--compact .audit-event {
  grid-template-columns: 8px minmax(0, 1fr);
  gap: var(--space-2);
}

.audit-timeline--compact .audit-event__marker {
  width: 8px;
  height: 8px;
  margin-top: 6px;
  box-shadow: 0 0 0 3px rgb(96 165 250 / 0.13);
}

.audit-timeline--compact .audit-event__body {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
  background: var(--color-surface-soft);
}

.copy-status {
  position: fixed;
  right: var(--space-5);
  bottom: var(--space-5);
  z-index: 50;
  pointer-events: none;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 140ms ease, transform 140ms ease;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3);
  color: var(--color-ink);
  background: var(--color-surface);
  box-shadow: var(--shadow-soft);
  font-size: var(--text-sm);
  font-weight: var(--weight-strong);
}

.copy-status.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.copy-fallback {
  position: fixed;
  left: -9999px;
  top: 0;
}

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background: rgb(9 11 18 / 0.38);
}

.modal-backdrop.is-open {
  display: flex;
}

.modal {
  width: min(100%, 440px);
  display: grid;
  gap: var(--space-4);
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  box-shadow: var(--shadow-panel);
}

.modal-head,
.modal-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.modal-head {
  justify-content: space-between;
}

.modal-head h2 {
  color: var(--color-ink);
  font-size: var(--text-lg);
}

.modal-note {
  color: var(--color-text-muted);
}

.modal-actions {
  justify-content: flex-end;
  flex-wrap: wrap;
}

.pagination,
.form-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.requisite-list {
  display: grid;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
  padding: 0;
  list-style: none;
}

.requisite-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

.requisite-item__main {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  min-width: 0;
}

.requisite-add {
  margin-top: var(--space-3);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}

/* Форма реквизитов раскладывается по категориям в несколько колонок и берёт
   всю ширину оболочки: прежний потолок 1200px при shell до 2320px оставлял
   пустые поля по бокам и растягивал форму в бесконечное полотно вниз. Каждая
   секция остаётся отдельной категорией внутри ТОГО ЖЕ сабмита — точки
   сохранения не объединяются. */
.organization-requisites-page .organization-profile-form {
  display: block;
  max-width: none;
  columns: 390px;
  column-gap: var(--space-8);
}

/* Категория целиком остаётся в одной колонке; колонки балансируются сами,
   поэтому короткие категории не оставляют пустых прямоугольников. */
.organization-requisites-page .organization-profile-form > .form-section {
  break-inside: avoid;
  margin-bottom: var(--space-5);
}

/* Заказчик: «все эти горизонтали никакой нагрузки не несут, но мельтешат в
   глазах». Секции внутри форм реквизитов больше не рисуют ни рамку, ни
   разделительную линию — категории держатся заголовком и ритмом. Общие
   `.view-head` и `.form-section` не затронуты: они держат вид 45 и 17 других
   шаблонов. */
.organization-requisites-page .organization-identity-form > .form-section,
.organization-requisites-page .organization-profile-form > .form-section {
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
}

/* Внутри колонки 12-колоночная сетка даёт поля уже их содержимого, поэтому
   ширина полей определяется содержимым: треки не меньше 150px, «широкие»
   поля (адреса, банк, email) по-прежнему занимают строку целиком через
   уже существующий `span-12`. */
.organization-requisites-page .organization-profile-form .form-grid {
  grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr));
}

.organization-requisites-page .organization-profile-form .form-grid > .field,
.organization-requisites-page .organization-profile-form .form-grid > .residency-fields > .field {
  grid-column: auto;
}

.organization-requisites-page .organization-profile-form .form-grid > .span-12,
.organization-requisites-page .organization-profile-form .form-grid > .residency-fields > .span-12 {
  grid-column: 1 / -1;
}

/* Поля одного резидента обёрнуты для `app.js`, но остаются ячейками сетки:
   обёртка не даёт своей коробки, и без JavaScript поля стоят там же, где
   стояли до разделения. Скрытая обёртка по-прежнему не показывается —
   `[hidden]` сильнее (`!important`). */
.organization-requisites-page .organization-profile-form .form-grid > .residency-fields {
  display: contents;
}

.organization-requisites-page .organization-profile-form > .form-actions {
  column-span: all;
  margin: 0;
  padding: 0;
  border: 0;
}

/* Название юрлица — короткая самостоятельная точка сохранения, её незачем
   растягивать на всю оболочку. Кнопки обеих форм реквизитов стоят слева, по
   той же направляющей, что и поля. */
.organization-requisites-page .organization-identity-form {
  max-width: 860px;
  margin-inline: 0;
}

/* «Основное» — полоса, а не блок в треть листа. Название и технический код
   стоят в одной строке с кнопкой «Сохранить название», а не над ней: под
   формой из двух полей уходило 248 px листа, а справа от неё пустовала вся
   правая половина. Это та самая область, которую заказчик обвела 31.08
   («Выделила пустующую область, давайте мы ее заполним данными»). Точка
   сохранения остаётся своей: это по-прежнему отдельная форма и отдельный POST.
   Ниже 1180 px — как было, стопкой: в одну строку они там не встают. */
@media (min-width: 1180px) {
  .organization-requisites-page .organization-identity-form .form-section {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
  }

  .organization-requisites-page .organization-identity-form .form-section__head {
    grid-column: 1 / -1;
  }

  .organization-requisites-page .organization-identity-form .form-grid {
    grid-column: 1;
  }

  .organization-requisites-page .organization-identity-form .form-actions {
    grid-column: 2;
  }

  /* Предупреждение «без JavaScript подтверждения не будет» — своей строкой во
     всю ширину секции, под полями и рядом действий. */
  .organization-requisites-page .organization-identity-form .noscript-row {
    grid-column: 1 / -1;
  }
}

.organization-requisites-page .form-actions {
  justify-content: flex-start;
}

/* Счета и телефоны — две коллекции переменной длины. Рядом друг с другом они
   занимают один экран вместо двух. */
.organization-collections {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
  gap: var(--space-4);
  align-items: start;
  padding: var(--space-5);
}

.organization-requisites-page .organization-collection-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
}

.organization-requisites-page .organization-collection-head > div {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.organization-requisites-page .organization-collection-head .btn {
  flex: 0 0 auto;
}

.organization-requisites-page .requisite-list {
  margin-bottom: 0;
}

.organization-requisites-page .requisite-item {
  padding: var(--space-2) var(--space-3);
}

/* Строка счёта с отметкой «В документах» (2026-09-13) шире остальных, и при
   ширине блока по содержимому кнопка «Отключить» уходила на вторую строку
   только у этого счёта. База в 18rem держит кнопку справа, пока рядом есть
   место, а отметка переносится внутри блока; на телефоне строка по-прежнему
   складывается: блок сверху, кнопка под ним. */
.organization-requisites-page .requisite-item__main {
  flex: 1 1 18rem;
}

.organization-requisites-page .requisite-item__main > .mono {
  min-width: 0;
  max-width: 100%;
  overflow-wrap: anywhere;
}

.organization-requisites-page .requisite-add {
  max-width: none;
  margin-top: var(--space-2);
  padding: var(--space-3) 0 0;
}

/* Формы добавления счёта и телефона живут внутри узкой колонки коллекции,
   поэтому их поля тоже размеряются содержимым, а не 12-колоночной сеткой. */
.organization-requisites-page .requisite-add .form-grid {
  grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr));
}

.organization-requisites-page .requisite-add .form-grid > .field {
  grid-column: auto;
}

.organization-requisites-page .organization-account-number {
  grid-column: 1 / -1;
}

.organization-collection-prerequisite {
  display: grid;
  justify-items: start;
  gap: var(--space-2);
  max-width: 62ch;
  padding: var(--space-3);
  border: 1px solid rgb(37 99 235 / 0.22);
  border-radius: var(--radius-sm);
  background: rgb(37 99 235 / 0.06);
}

.organization-collection-prerequisite p {
  margin: 0;
  color: var(--color-text-muted);
}

.noscript-actions {
  display: grid;
  gap: var(--space-4);
}

/* Modal-trigger controls are dead without JavaScript (the modal never opens).
   Hide them until app.js signals readiness; the <noscript> fallback forms cover
   the same actions. Warehouse handoff uses a plain POST form and stays usable.
   The route status picker carries the class on the whole form: without the
   modal its «Применить» has nothing to open, and its <noscript> twin applies
   the same transition with a checkbox instead. */
html:not([data-app-ready]) .js-only-modal-trigger {
  display: none;
}

/* No-JS logout fallback: sits inline in .userline next to the access line so the
   button is reachable on desktop and mobile without JavaScript. */
.logout-nojs {
  display: inline-flex;
}

.noscript-action-form {
  display: grid;
  gap: var(--space-2);
  align-items: start;
}

/* B17 — emergency shutdown confirmation, done and public 503 surfaces. */
.shutdown-confirm {
  display: grid;
  gap: var(--space-5);
}

/* Поля и кнопки — с тем же отступом от края панели, что баннер над ними
   (`.notice-banner`): без него форма стояла вплотную к левой кромке, а кнопки
   — на нижней (визуальная проверка 26.09, В-02). */
.shutdown-confirm > form {
  padding: 0 var(--space-5) var(--space-5);
}

.shutdown-page {
  width: min(560px, 100%);
  display: grid;
  gap: var(--space-3);
  padding: var(--space-6);
  text-align: center;
}

.shutdown-page__title {
  font-size: var(--text-xl);
  font-weight: var(--weight-heading);
  color: var(--color-ink);
}

.shutdown-page__text {
  color: var(--color-text);
  line-height: 1.5;
}

.shutdown-page__text--muted {
  color: var(--color-text-muted);
}

@media (min-width: 768px) { /* mobile и выше */
  .noscript-actions {
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  }
}

.pagination {
  padding: var(--space-4) var(--space-5);
}

.pagination__current {
  color: var(--color-text-muted);
  font-weight: var(--weight-strong);
}

.is-disabled {
  opacity: 0.5;
  pointer-events: none;
}

.order-form,
.form-section {
  display: grid;
  gap: var(--space-4);
}

.order-form {
  padding: var(--space-5);
  width: 100%;
  max-width: 1600px;
  margin-inline: auto;
}

.form-section {
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-soft);
}

.form-section__head h2 {
  color: var(--color-ink);
  font-size: var(--text-lg);
}

.form-section__head {
  display: grid;
  gap: var(--space-1);
}

.order-form .form-grid {
  align-items: start;
}

/* Паспортная зона клиента: «Идентификационный номер» — единственная подпись,
   которая переносится на две строки в половине зоны (170 px при ширине экрана
   1280). Карточка выравнивает ряд по низу и держит оба поля на одной линии, а
   форма создания выравнивает по верху (правило выше) — и там поле с переносной
   подписью опускалось на 21 px ниже соседней «Даты выдачи». Ряд паспорта
   выравнивается по низу на обеих поверхностях. Только выравнивание: ни цвета,
   ни тени, ни брейкпоинта здесь не заводится. */
.form-grid.client-passport-grid {
  align-items: end;
}

/* ── Форма заявки: три равные зоны ──────────────────────────────────────────
   Пак 2026-09-02, п. 21: лево — клиент и груз, центр — направление, вид
   доставки, забор и адресная доставка, право — стоимость. Пак 2026-09-03,
   п. 03: зоны ОДИНАКОВОЙ ширины — доли «от содержимого» сняты; п. 04 (вторая
   половина): та же раскладка у формы редактирования, поэтому правила
   привязаны к самим зонам, а не к модификатору формы создания. Одна колонка
   на узком экране, две на среднем, три на широком. */
.order-form-zones {
  display: grid;
  gap: var(--space-4);
  align-items: start;
}

.order-form-zone {
  display: grid;
  gap: var(--space-4);
  align-content: start;
  min-width: 0;
}

@media (min-width: 1024px) { /* tablet: исключение шкалы, см. tokens.css */
  .order-form-zones {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* В зоне шириной с треть экрана 12-колоночная сетка резала бы поля до
     70 px. Внутри зон спаны пересчитываются под узкую колонку: половины и
     трети становятся строкой целиком. Затрагивает только зоны. */
  .order-form-zone .form-grid > .span-2 {
    grid-column: span 4;
  }

  .order-form-zone .form-grid > .span-3,
  .order-form-zone .form-grid > .span-4,
  .order-form-zone .form-grid > .span-5 {
    grid-column: span 6;
  }

  .order-form-zone .form-grid > .span-6,
  .order-form-zone .form-grid > .span-8,
  .order-form-zone .client-picker__grid > .span-6 {
    grid-column: span 12;
  }

  /* У номера накладной двухстрочная подсказка: в половине колонки она рвёт
     ритм следующей строки, поэтому поле занимает строку целиком. */
  .order-form-zone .form-grid > .field--cargo-number {
    grid-column: span 12;
  }

  /* Числовые поля груза — схема заказчика (пак 2026-09-03, п. 05): «Вес» и
     «Мест» парой, «Объём вручную» и «Итоговый объём» парой, три размера по
     трети. Те же спаны, что у формы без зон; здесь они защищены от общего
     пересчёта выше. В трети ширины зоны подписи «Длина, см», «Ширина, см» и
     «Высота, см» стоят в одинаковых клетках — ряд из пяти полей, в котором
     «Высота, см» переносилась на две строки, ушёл вместе со старой схемой. */
  .order-form-zone .form-grid > .field--cargo-count,
  .order-form-zone .form-grid > .field--cargo-volume {
    grid-column: span 6;
  }

  .order-form-zone .form-grid > .field--cargo-dim {
    grid-column: span 4;
  }
}

@media (min-width: 1280px) { /* dense: третья зона встаёт в общий ряд */
  /* Три одинаковые доли — просьба заказчика (пак 2026-09-03, п. 03). Зоны
     тянутся на высоту ряда, а содержимое остаётся вверху: так три зоны
     читаются как три колонки, а не как «колонка и приписка». Пустоту под
     правой зоной ничем не заполняем — стоимость заказчик отложила сама, а
     растянутый комментарий был бы подменой. */
  .order-form-zones {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: stretch;
  }
}

.field--cargo-number .field-hint {
  max-width: 30rem;
  color: var(--color-text-muted);
}

.cargo-workflow-fields,
.cargo-payer,
.pickup-fields,
.recipient-override,
.recipient-override__fields,
.delivery-schedule {
  min-width: 0;
}

.cargo-payer,
.recipient-override {
  display: grid;
  gap: var(--space-3);
}

/* Поля наших курьеров при выбранном перевозчике (пак 2026-09-03, п. 02):
   спрятаны, но не отключены — значения остаются в форме и уходят на сервер,
   поэтому здесь класс, а не атрибут hidden, который в форме заявки означает
   «поле отключено и не отправляется». */
.order-form .is-carrier-hidden {
  display: none !important;
}

.time-choice {
  min-width: 0;
  margin: 0;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

.time-choice legend {
  padding-inline: var(--space-1);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-accent);
}

.time-choice__modes,
.time-choice__fields {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.time-choice__fields {
  margin-top: var(--space-3);
}

.time-choice__fields .field {
  flex: 1 1 180px;
}

/* Server-authoritative derived volume. It keeps the form field rhythm while
   reading as a result, not as a disabled editable control. */
.calculated-volume {
  align-self: stretch;
}

.calculated-volume__value {
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-1);
  border: 1px solid rgb(96 165 250 / 0.36);
  border-radius: var(--radius-sm);
  padding: 12px 13px;
  color: var(--color-ink);
  font-weight: var(--weight-strong);
  background: rgb(96 165 250 / 0.08);
  overflow-wrap: anywhere;
}

.calculated-volume__amount {
  min-width: 0;
}

.calculated-volume__source {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding-inline: var(--space-2);
  border: 1px solid rgb(96 165 250 / 0.34);
  border-radius: var(--radius-pill);
  color: #1d4ed8;
  background: var(--color-surface);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
  white-space: nowrap;
}

.cash-operation-form {
  width: min(100%, 920px);
  margin-inline: auto;
  padding: var(--space-5);
}

.cash-operation-section {
  min-width: 0;
  margin: 0;
}

.cash-operation-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
}

/* Ошибка под «Суммой» (F-01) удлиняет ряд — соседнее «Тип» не тянется за
   ней. Без ошибки ряд прежний: поля одной высоты. */
.cash-operation-grid:has(.field-error) {
  align-items: start;
}

.cash-operation-comment {
  grid-column: 1 / -1;
}

.cargo-history-values {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-2);
  margin: 0;
}

.cargo-history-values div {
  min-width: 0;
}

.cargo-history-values dt {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
}

.cargo-history-values dd {
  margin: 2px 0 0;
  overflow-wrap: anywhere;
}

.span-2 {
  grid-column: span 2;
}

.span-3 {
  grid-column: span 3;
}

.span-4 {
  grid-column: span 4;
}

.span-5 {
  grid-column: span 5;
}

.span-6 {
  grid-column: span 6;
}

.span-8 {
  grid-column: span 8;
}

.span-12 {
  grid-column: span 12;
}

.client-picker {
  display: grid;
  gap: var(--space-3);
  min-width: 0;
}

.client-picker__grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--space-3);
}

.client-picker__warning {
  border: 1px solid rgb(245 158 11 / 0.28);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
  color: #9a6700;
  background: rgb(245 158 11 / 0.09);
  font-size: var(--text-sm);
  font-weight: var(--weight-strong);
}

/* "Такого клиента в базе нет" states a fact, it is not a problem: the amber
   attention tone is reserved for a real match or a phone conflict. */
.client-picker__warning.is-info {
  border-color: var(--color-border);
  color: var(--color-text-muted);
  background: var(--color-surface-soft);
}

.client-picker__dropdown {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
}

.client-picker__list {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.client-picker__option {
  display: grid;
  gap: 2px;
  width: 100%;
  padding: 11px 13px;
  border: 0;
  border-bottom: 1px solid var(--color-border);
  color: var(--color-text);
  background: transparent;
  text-align: left;
  cursor: pointer;
}

.client-picker__list li:last-child .client-picker__option {
  border-bottom: 0;
}

.client-picker__option:hover,
.client-picker__option.is-active {
  background: var(--color-surface-soft);
}

.client-picker__option-name {
  font-weight: var(--weight-accent);
}

.client-picker__option-meta {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

.check-field {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-text);
  font-weight: var(--weight-accent);
}

.check-field input {
  width: 18px;
  height: 18px;
}

/* Галочка «Показать скрытых» и радио «Без времени» — тоже точки, куда приходит
   клавиатура. Кольцо общее, как у полей и кнопок. */
.check-field input:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* Радио круглое — кольцо повторяет его форму, а не рисует вокруг квадрат. */
.check-field input[type="radio"]:focus-visible {
  border-radius: 50%;
}

/* Inline checkbox + label living inside a labeled .field (Editor cargo toggle).
   Lighter than .check-field — keeps the field's inherited color/weight — but
   aligns the box to the shared 18px checkbox norm with a clean gap instead of
   the bare inline default. */
.check-line {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.check-line input {
  width: 18px;
  height: 18px;
  margin: 0;
  flex: 0 0 auto;
  accent-color: var(--color-accent);
}

.access-checkbox-list,
.access-org-list {
  display: grid;
  gap: var(--space-2);
}

.access-checkbox,
.access-org-row {
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

.access-checkbox {
  justify-content: flex-start;
  cursor: pointer;
}

.access-checkbox input {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
}

.access-checkbox span {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.access-checkbox small,
.access-org-row span {
  color: var(--color-text-muted);
}

.access-checkbox strong,
.access-org-row > span {
  overflow-wrap: anywhere;
}

.access-password-form {
  padding-top: 0;
}

.access-password-action {
  align-self: end;
}

.empty-page-body {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-5);
}

.empty-page-body .empty-state {
  min-height: 240px;
}

.money-visibility-note {
  color: var(--color-text-muted);
  text-align: center;
  font-weight: var(--weight-body);
}

.finance-review {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-5);
}

.finance-review-hero,
.finance-review-card,
.finance-review-table {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
}

.finance-review-hero {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-5);
}

.finance-review-hero h2,
.finance-review-card h3,
.finance-review-table h3 {
  margin: var(--space-3) 0 var(--space-2);
  font-size: var(--text-lg);
  line-height: 1.25;
}

.finance-review-hero p,
.finance-review-table__head span {
  margin: 0;
  color: var(--color-text-muted);
  font-weight: var(--weight-body);
}

.review-status {
  flex: 0 0 auto;
  border-radius: var(--radius-pill);
  border: 1px solid var(--color-border);
  background: var(--color-surface-muted);
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
  padding: 8px 12px;
  text-transform: uppercase;
}

.finance-review-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4);
}

.finance-review-card,
.finance-review-table {
  padding: var(--space-4);
}

.finance-review-card ul {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding-left: 1.1rem;
  color: var(--color-text-muted);
  font-weight: var(--weight-body);
}

.finance-review-table__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.finance-review-table__head h3 {
  margin: 0;
}

.finance-column-list {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-2);
}

.finance-column-list span {
  min-width: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface-muted);
  color: var(--color-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-strong);
  line-height: 1.25;
  padding: 10px 12px;
}

.delivery-status-stack {
  display: grid;
  gap: var(--space-2);
}

.delivery-money-note {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-body);
}

.route-badge-list,
.route-summary-list,
.route-preview-list {
  display: grid;
  gap: var(--space-2);
}

.route-badge-list {
  justify-items: start;
}

.route-summary-row td {
  background: var(--color-surface);
}

.route-summary-row.is-expanded td {
  border-bottom-color: transparent;
}

.route-summary-cell strong {
  font-size: var(--text-base);
}

.route-summary-subtitle {
  color: var(--color-text-muted);
}

.route-summary-list {
  padding: 0;
  margin: 0;
  list-style: none;
  color: var(--color-text-muted);
}

.route-actions {
  justify-content: flex-end;
}

.route-actions-cell {
  white-space: nowrap;
}

.route-detail-row td {
  padding: 0;
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface-soft);
}

.route-detail-panel {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
}

.route-detail-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
}

.route-detail-head h3 {
  margin: 0;
  font-size: var(--text-lg);
}

.route-detail-head p {
  margin: var(--space-1) 0 0;
  color: var(--color-text-muted);
}

.route-order-list {
  display: grid;
  gap: var(--space-2);
}

.route-order-row {
  display: grid;
  grid-template-columns: minmax(0, 1.8fr) minmax(220px, 1fr) auto;
  gap: var(--space-3);
  align-items: center;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.route-order-main {
  display: grid;
  gap: 3px;
}

.route-order-main > span {
  overflow-wrap: anywhere;
}

.route-order-org {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

.route-order-statuses {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

.route-order-action {
  justify-self: end;
}

.route-preview-item {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
}

.route-preview-item:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.route-preview-copy {
  display: grid;
  gap: 2px;
}

.route-preview-copy > span {
  overflow-wrap: anywhere;
}

.route-preview-copy > span:last-child,
.route-preview-delivery,
.route-preview-more {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

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

.route-card {
  gap: var(--space-3);
}

.route-card__grid dt,
.route-card__grid dd {
  align-self: start;
}

.route-card .order-card__actions {
  padding-top: 0;
}

/* Исключение «ultrawide» (2200). Единственное правило, работающее у самой
   границы `--container-max` (2320px): на 4K сводные плитки получают четвёртую
   колонку, чтобы ряд не превращался в три растянутые полосы. К классам
   устройств отношения не имеет и в шкалу не сводится. */
@media (min-width: 2200px) { /* исключение «ultrawide» */
  .empty-grid,
  .foundation-summary {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* Исключение «laptop» (1180), нижняя половина: между `shell` и `laptop` панель
   фильтров заявок раскладывается на шесть колонок вместо однострочной десктопной
   композиции. Верхняя граница — ширина, на которой однострочный вариант
   перестаёт быть тесным; расширение до `dense` сделало бы 1180–1279 менее
   плотным, чем сейчас. */
@media (min-width: 920px) and (max-width: 1179.98px) { /* shell…ниже laptop */
  .filter-bar--orders {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: var(--space-3);
  }

  .filter-bar--orders > .filter-field.filter-field--orders-search,
  .filter-bar--orders > .filter-field.filter-field--orders-sort {
    grid-column: span 3;
  }

  .filter-bar--orders > .filter-field.filter-field--orders-status,
  .filter-bar--orders > .filter-field.filter-field--orders-payment,
  .filter-bar--orders > .filter-field.filter-field--orders-direction {
    grid-column: span 2;
  }

  .filter-bar--orders > .filter-size.filter-size--orders,
  .filter-bar--orders > .filter-actions.filter-actions--orders {
    grid-column: span 3;
  }

  .filter-bar--orders .filter-actions--orders .btn {
    width: 100%;
  }

  /* Долей списка заявок здесь больше нет. Этот диапазон (920–1179,98 px) лежит
     целиком ниже 1280 px, а ниже 1280 `.orders-table-wrap` скрыт и работают
     карточки заявок — переопределения не доходили до экрана ни разу. Заодно
     они не сходились: в варианте без «Выбора» их сумма давала 111,6 % и
     браузер сжимал все одиннадцать колонок пропорционально. Снято 08.09
     вместе с перекроем бюджета. */
}

@media (min-width: 768px) and (max-width: 1023.98px) { /* mobile…ниже tablet */
  .filter-bar--routes {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: var(--space-3);
  }

  .filter-bar--routes > .filter-field.filter-field--routes-search {
    grid-column: 1 / -1;
  }

  .filter-bar--routes > .filter-field.filter-field--routes-org,
  .filter-bar--routes > .filter-field.filter-field--routes-direction,
  .filter-bar--routes > .filter-field.filter-field--routes-delivery,
  .filter-bar--routes > .filter-size.filter-size--routes,
  .filter-bar--routes > .filter-actions.filter-actions--routes {
    grid-column: span 2;
  }

  .filter-bar--routes .filter-actions--routes .btn {
    width: 100%;
  }

  .employee-phone-row {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .route-order-row {
    grid-template-columns: 1fr;
    align-items: start;
  }

  .route-order-action {
    justify-self: start;
  }
}

/*
  Ниже точки `dense` живёт вся «недостаточно широкая для плотного десктопа»
  композиция.

  1. Списки. Плотные таблицы (заявки/архив/доставки/маршруты/клиенты/журнал/
     сотрудники/доступы/юрлица) переходят на карточки, как только вьюпорт
     перестаёт держать читаемую таблицу. Точка намеренно отделена от `shell`:
     десктопная обвязка (общий ряд, section-tabs) остаётся на месте, а
     расслабляется только сетка данных. Ниже `shell` включается мобильная
     оболочка, и те же карточки остаются видимыми.
  2. Карточки-детали. Измерение показало, что main + правая колонка 360px
     остаются тесными заметно выше 1024px: на 1024px main ~574px (панели
     ~279px), здоровая геометрия 2×2 начинается только ближе к 1280px
     (панели ~397px). Поэтому весь этот диапазон карточка заявки стоит одной
     колонкой: main получает полную ширину, а двухколоночная раскладка
     возвращается там, где контент её действительно выдерживает. Порог был
     частным значением 1260 и переехал на точку шкалы: разница затрагивает
     только полосу 1261–1279, на 1280px и выше поведение не изменилось.
     Карточки маршрута и курьера складываются раньше — на пороге `tablet`,
     см. исключение у `.courier-detail-layout`.
*/
@media (max-width: 1279.98px) { /* ниже dense */
  .detail-layout {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Три зоны сотрудника перестают помещаться рядом: работа и доступ встают
     во вторую колонку, содержимое зон не меняется. */
  .employee-form-zones {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .orders-table-wrap {
    display: none;
  }

  .route-positions-bar--table {
    display: none;
  }

  .orders-cards {
    display: grid;
  }

  .courier-table-wrap {
    display: none;
  }

  .courier-cards {
    display: grid;
  }

  /* Compact filter composition: date + status as one two-column row, the
     button and the quick date links share the next row. */
  .filter-bar--courier {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3);
  }

  .filter-bar--courier > .filter-actions.filter-actions--courier {
    grid-column: auto;
    min-width: 0;
  }

  .filter-bar--courier .filter-actions--courier .btn {
    flex: 1 1 auto;
  }

  .filter-bar--courier .courier-date-links {
    justify-content: flex-end;
    min-height: 44px;
  }
}

@media (max-width: 919.98px) { /* ниже shell */
  .workspace {
    grid-template-columns: 1fr;
  }

  .common-nav {
    display: none;
  }

  .desktop-access {
    display: none;
  }

  /* Курьеру «Выйти» остаётся в шапке и на телефоне: у него нет ни мобильной
     панели, ни ящика «Разделы», где эта кнопка живёт у остальных ролей
     (DARYA-2026-09-03-048). Идёт после .desktop-access и побеждает при равной
     специфичности; без JavaScript кнопку по-прежнему прячет
     .js-only-modal-trigger, а выход даёт <noscript>-форма рядом. */
  .userline__logout--phone {
    display: inline-flex;
  }

  /* Резерв высоты строки доступа (см. `.userline` выше) ниже 920 px снимается:
     `.desktop-access` здесь скрыт, и кнопки «Выйти» в строке нет вовсе — резерв
     давал бы 40 px пустоты в шапке на каждом экране телефона (замерено: +43 px
     на каждом снимке 390 и 430). Исключение — курьер: у него кнопка в этой
     строке остаётся и на телефоне, значит остаётся и причина резерва. */
  .userline {
    min-height: 0;
  }

  .userline:has(.userline__logout--phone) {
    min-height: 40px;
  }

  .mobile-access,
  .mobile-top-actions {
    display: flex;
  }

  .mobile-top-actions {
    gap: var(--space-2);
  }

  /* Блок действий экрана, который на узком экране повторяет кнопку из верхней
     панели оболочки. Панель появляется ровно здесь, поэтому и дубликат
     скрывается ровно здесь: на десктопе панели нет, и кнопка экрана остаётся
     единственной. */
  .head-actions.is-mobile-duplicate {
    display: none;
  }

  .mobile-access {
    min-width: 0;
    max-width: 100%;
    white-space: normal;
    overflow-wrap: anywhere;
  }

  .topline {
    align-items: flex-start;
    flex-direction: column;
  }

  /* Ряд разделов на этой ширине скрыт (.section-tabs ниже), поэтому черта и
     отступ строки навигации сняты — иначе в шапке осталась бы висящая линия
     над пустым блоком. */
  .navrow {
    border-top: 0;
    padding-top: 0;
  }

  /* Подпись и полоса чипов остаются одной строкой: подпись держит свою
     ширину, чипы занимают остаток и прокручиваются внутри себя. */
  .org-line {
    width: 100%;
    gap: var(--space-2);
  }

  /* One compact, horizontally scrollable org-chip row. Overrides the desktop
     .topline .org-tabs (wrap + auto flex-basis) at equal specificity so a long
     org name can no longer stack chips into multiple rows or wrap inside a chip
     and inflate the header. Only the strip scrolls; the page itself does not. */
  .topline .org-tabs {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
    flex-wrap: nowrap;
    overflow-x: auto;
  }

  .org-switch-form {
    min-width: 0;
    flex: 0 0 auto;
  }

  .org-chip {
    flex: 0 0 auto;
    max-width: none;
    white-space: nowrap;
    overflow-wrap: normal;
  }

  .section-tabs {
    display: none;
  }

  .empty-grid,
  .finance-review-grid,
  .foundation-summary,
  .detail-grid {
    grid-template-columns: 1fr;
  }

  .finance-column-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .detail-layout,
  .detail-main,
  .detail-kv--split,
  .detail-kv--comments,
  .employee-form-zones {
    grid-template-columns: 1fr;
  }

  .payment-order-overview {
    grid-template-columns: 1fr;
  }

  .payment-order-overview > .detail-panel:only-child {
    width: 100%;
  }

  .view-head {
    display: grid;
  }

  .head-actions {
    justify-content: flex-start;
  }

  .filter-field,
  .filter-field:first-child,
  .filter-field--wide,
  .filter-size,
  .filter-actions,
  .filter-bar > .filter-field--show-hidden,
  .filter-bar > .filter-submit--nojs,
  .span-2,
  .span-3,
  .span-4,
  .span-5,
  .span-6,
  .span-8 {
    grid-column: span 12;
  }

  .filter-actions,
  .form-actions,
  .pagination {
    justify-content: stretch;
  }

  .client-picker__grid {
    grid-template-columns: 1fr;
  }

  /* Пять числовых полей груза одной строкой на каждое — это пять экранных
     строк под «12» и «1,5». В зонах формы заявки они остаются в ряд: вес и
     мест парой, три размера тройкой; объём и итог — строкой каждый, там
     стоит подсказка. Ограничено зонами формы заявки (создание и
     редактирование). */
  .order-form-zone .form-grid > .field--cargo-count {
    grid-column: span 6;
  }

  .order-form-zone .form-grid > .field--cargo-dim {
    grid-column: span 4;
  }

  .filter-actions .btn,
  .form-actions .btn,
  .pagination .btn {
    flex: 1 1 auto;
  }

  /* Кабинет курьера на телефоне: дата во всю ширину как главный контрол,
     статус и быстрые ссылки одной строкой, кнопка (без JS) — отдельной. Общее
     правило `.filter-field { span 12 }` выше рассчитано на 12-колоночную
     сетку, а здесь колонок две, поэтому оно переопределено явно. */
  .filter-bar--courier > .filter-field.filter-field--courier-date,
  .filter-bar--courier > .filter-actions.filter-actions--courier {
    grid-column: 1 / -1;
  }

  .filter-bar--courier > .filter-field.filter-field--courier-status {
    grid-column: 1;
  }

  .filter-bar--courier > .courier-date-links {
    grid-column: 2;
  }

}

@media (min-width: 768px) and (max-width: 1179.98px) { /* mobile…ниже laptop */
  .filter-bar--finance {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .filter-bar--finance > .filter-field,
  .filter-bar--finance > .filter-field:first-child,
  .filter-bar--finance > .filter-actions {
    grid-column: auto;
  }

  .filter-bar--payments > .filter-field--payment-search {
    grid-column: 1 / -1;
  }
}

@media (max-width: 519.98px) { /* ниже phone */
  .app,
  .auth-main {
    padding: var(--space-2);
  }

  .shell {
    gap: var(--space-2);
  }

  .topbar,
  .panel,
  .auth-panel {
    border-radius: var(--radius-md);
  }

  .topbar,
  .auth-panel {
    padding: var(--space-3);
  }

  .panel--chooser > .view-head {
    padding: var(--space-3);
  }

  .form-error--summary {
    margin-inline: var(--space-3);
  }

  .error-panel {
    padding: var(--space-4);
    border-radius: var(--radius-md);
  }

  .error-copy h1 {
    font-size: 30px;
  }

  .error-actions .btn {
    width: 100%;
  }

  .topbar,
  .topline {
    gap: var(--space-2);
  }

  .topline {
    display: grid;
  }

  .userline {
    justify-content: flex-start;
    font-size: var(--text-xs);
  }

  .view-head,
  .filter-bar,
  .order-form,
  .client-card,
  .detail-grid,
  .order-detail-body,
  .orders-cards,
  .courier-cards,
  .courier-detail-layout,
  .empty-page-body,
  .finance-review,
  .foundation-summary,
  .empty-grid,
  .panel > .organization-list,
  .panel > .empty-state {
    padding: var(--space-3);
  }

  /* Те же 12 px по краям, что и у остальных блоков карточки: на 390 px
     реквизит счёта не должен терять 16 px ширины на отступы панели. */
  .client-card-divider,
  .client-accounts-panel {
    margin-inline: var(--space-3);
  }

  .client-orders-panel {
    margin: var(--space-3);
  }

  .list-meta,
  .detail-status:not(.detail-status--inline),
  .pagination {
    padding-inline: var(--space-3);
  }

  .org-tabs {
    gap: var(--space-1);
  }

  .chip,
  .tab {
    min-height: 44px;
    padding-inline: var(--space-3);
    font-size: var(--text-xs);
  }

  .btn {
    min-height: 44px;
    padding-inline: var(--space-3);
  }

  /* Scoped 34px action reductions (.organization-actions .btn, .access-table
     .btn) outweigh the shared .btn rule above, so the phone floor would not
     reach them without a matching scoped override. The organizations card
     projection is the visible mobile surface and carries primary touch actions;
     the access table is hidden on phones but the rule is matched here for
     consistency so a short-label button can never fall below the floor. Desktop
     34px density is untouched (this only applies inside the phone breakpoint). */
  .organization-actions .btn,
  .access-table .btn {
    min-height: 44px;
  }

  .order-detail-head .head-actions {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr);
    width: 100%;
  }

  .order-detail-head .head-actions .btn {
    min-width: 0;
    padding-inline: var(--space-2);
  }

  /* Та же причина, что у печати в карточке маршрута строкой ниже: треть
     ширины телефона не держит длинную подпись. «Акт приёма-передачи» —
     134 px текста в ячейке 113 px, и подпись обрезалась посреди слова.
     Печать идёт своей строкой во всю ширину, последней в ряду действий:
     это документ, а не правка заявки. */
  .order-detail-head .head-actions > .order-print-action {
    grid-column: 1 / -1;
    order: 1;
  }

  /* Карточка маршрута: сетка на три действия заявки не держит длинную
     подпись «Складской список» в трети ширины. Навигация — первой строкой
     пополам, печать — второй строкой во всю ширину. */
  .route-detail-head {
    grid-template-columns: minmax(0, 1fr);
  }

  .route-detail-head .head-actions {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .route-detail-head .head-actions > .route-print-action {
    grid-column: 1 / -1;
    order: 1;
  }

  .route-detail-head .route-print-action > .route-status-menu__trigger {
    width: 100%;
    justify-content: center;
  }

  /* C3 — editable controls inherit the 14px body text, which is the known
     <16px phone focus-zoom risk condition. Raise editable control text to the
     existing --text-base (16px) on phones only; desktop/tablet stay at 14px.
     The 16px text lifts .input/.textarea well above 44px; native <select>
     renders ~1px shorter than <input> at equal font/padding, so a 44px
     min-height is added to guarantee the touch floor without inflating .input
     (already 46px) or .textarea (multiline). Desktop density is untouched. */
  .input,
  .select,
  .textarea {
    padding: 10px 11px;
    font-size: var(--text-base);
    min-height: 44px;
  }

  /* R2 — the copy-icon button is a fixed 34x34 icon-only target on phones.
     min-* alone cannot override the fixed width/height, so set the actual box
     to 44x44 inside the phone breakpoint. The existing flex centering and
     ::before/::after icon pseudo-elements stay aligned; the --detail variant
     (already 40x40 on desktop) becomes 44x44 on phones, which is consistent. */
  .copy-icon-button {
    width: 44px;
    min-width: 44px;
    height: 44px;
  }

  /* Кнопка списка заявок с 06.09 несёт подпись «Копировать»: ширина по
     подписи, а не 44 px, иначе подпись обрезается в мобильной карточке;
     высота 44 px как у остальных касаемых контролов телефона. */
  .copy-icon-button--row {
    width: auto;
  }

  /* R2 — the inline (in-row) variant is lifted to the same 44px phone target
     by the rule above, so its smaller glyph is restored to the shared size. */
  .copy-icon-button--inline::before,
  .copy-icon-button--inline::after {
    width: 12px;
    height: 14px;
  }

  /* R2 — «добавить ещё один номер» is an operational touch control: the same
     44px phone floor as every other icon-only button. */
  .phone-add-button {
    width: 44px;
    min-width: 44px;
    height: 44px;
  }

  /* R2 — filter-bar controls carry a higher-specificity (0,2,0) 42px
     min-height from their desktop rules (.filter-bar--orders .btn/.select etc.),
     which the shared .btn phone floor (0,1,0) cannot override. Apply/Reset
     buttons and filter <select>s are primary phone touch controls, so raise
     them to the 44px floor here at matching specificity. The .input is left
     alone: 16px text already lifts it to >=46px, so no min-height is added
     (double-expansion avoided). Desktop filter density (42px) is untouched. */
  .filter-bar .btn,
  .filter-bar .select {
    min-height: 44px;
  }

  .field {
    gap: var(--space-1);
  }

  .order-form {
    gap: var(--space-3);
  }

  .form-section {
    gap: var(--space-3);
  }

  .cash-operation-form {
    padding: var(--space-3);
  }

  .cash-operation-grid {
    grid-template-columns: 1fr;
    gap: var(--space-3);
  }

  .cash-operation-comment {
    grid-column: auto;
  }

  .time-choice__modes,
  .time-choice__fields,
  .cargo-history-values {
    display: grid;
    grid-template-columns: 1fr;
  }

  .form-grid {
    gap: var(--space-2);
  }

  .form-section__head h2,
  .detail-panel__head h2 {
    font-size: var(--text-base);
  }

  .view-title {
    font-size: 24px;
  }

  .crumb > *:not(:first-child):not(:last-child) {
    display: none;
  }

  .crumb > :last-child::before {
    content: "/";
    margin-right: var(--space-2);
  }

  /* В гибком звене правки заявки к отступу добавляется его промежуток. */
  .crumb > .crumb-edit::before {
    margin-right: var(--space-1);
  }

  .mobile-top-actions .btn {
    min-width: 0;
  }

  .mobile-top-actions {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .order-card__head,
  .order-card__grid {
    grid-template-columns: 1fr;
  }

  /* Сводка карточки заявки остаётся В ДВЕ КОЛОНКИ и на телефоне: четыре
     значения, по которым заявку узнают, должны попадать в один взгляд, а не
     в четыре экрана прокрутки. Наименование груза занимает всю ширину. */
  .orders-cards .order-card__grid--summary {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-2) var(--space-3);
  }

  .order-card__head {
    display: grid;
  }

  /* Шапка карточки курьера остаётся в одну строку: номер слева, статус
     справа — как в списке заказчика. */
  .courier-card__head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
  }

  /* Карточка заявки маршрута: крестик снятия остаётся справа от номера, а не
     падает под него отдельной строкой. */
  .route-orders-panel .order-card__head {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .order-card,
  .courier-card,
  .form-section,
  .detail-section,
  .detail-panel {
    gap: var(--space-3);
    padding: var(--space-3);
  }

  .order-note {
    padding: var(--space-3);
  }

  .detail-kv {
    gap: var(--space-2);
  }

  .detail-kv__item--price dd {
    font-size: var(--text-lg);
  }

  .order-card__actions .btn,
  .courier-card__actions .btn,
  .courier-card__actions .inline-form,
  .courier-confirm__form .btn {
    flex: 1 1 auto;
  }

  /* The terminal courier action stays the obvious primary: it takes the
     larger share of the actions row while «Открыть» remains a full control. */
  .courier-card__actions .btn-primary {
    flex: 2 1 auto;
  }

  .order-card__actions > .order-actions-primary .btn {
    flex: 1 1 0;
    padding-inline: var(--space-2);
  }

  .empty-page-body .empty-state {
    min-height: 180px;
  }

  .finance-review-hero,
  .finance-review-table__head {
    display: grid;
  }

  .finance-review-hero,
  .finance-review-card,
  .finance-review-table {
    padding: var(--space-3);
  }

  .review-status {
    justify-self: flex-start;
  }

  .finance-column-list {
    grid-template-columns: 1fr;
  }

  .audit-event__head {
    display: grid;
    gap: var(--space-1);
  }

  .modal {
    border-radius: var(--radius-md);
    padding: var(--space-4);
  }

  .modal-actions .btn {
    flex: 1 1 auto;
  }

  .list-meta--deliveries {
    display: grid;
    justify-content: flex-start;
  }

  .list-meta--routes {
    display: grid;
    justify-content: flex-start;
  }

  .list-meta--deliveries .money-visibility-note {
    margin-left: 0;
    text-align: left;
  }

  .list-meta--routes .money-visibility-note {
    margin-left: 0;
    text-align: left;
  }

  .route-detail-panel {
    padding: var(--space-3);
  }
}

@media (max-width: 767.98px) { /* ниже mobile */
  .filter-bar--finance {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .filter-bar--finance > .filter-field,
  .filter-bar--finance > .filter-field:first-child {
    grid-column: auto;
    min-width: 0;
  }

  .filter-bar--payments > .filter-field--payment-search:first-child,
  .filter-bar--finance > .filter-actions {
    grid-column: 1 / -1;
  }

  .balance-tiles--cash {
    grid-template-columns: 1fr;
    padding-inline: var(--space-3);
  }

  .balance-tiles--cash .balance-tile,
  .balance-tiles--cash .balance-tile:first-child {
    padding-inline: 0;
    border-left: 0;
  }

  .balance-tiles--cash .balance-tile + .balance-tile {
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border);
  }

  .payment-conduct-row {
    grid-template-columns: 1fr;
    align-items: stretch;
  }

  .payment-conduct-row .btn {
    width: 100%;
  }

  .filter-bar--orders {
    grid-template-columns: 1fr;
    gap: var(--space-2);
  }

  .filter-bar--deliveries {
    grid-template-columns: 1fr;
    gap: var(--space-2);
  }

  .filter-bar--routes {
    grid-template-columns: 1fr;
    gap: var(--space-2);
  }

  .filter-bar--orders > .filter-field,
  .filter-bar--orders > .filter-size,
  .filter-bar--orders > .filter-actions {
    grid-column: 1 / -1;
  }

  .filter-bar--deliveries > .filter-field,
  .filter-bar--deliveries > .filter-size,
  .filter-bar--deliveries > .filter-actions {
    grid-column: 1 / -1;
  }

  .filter-bar--routes > .filter-field,
  .filter-bar--routes > .filter-size,
  .filter-bar--routes > .filter-actions {
    grid-column: 1 / -1;
  }

  /* Employees phone: search, sorting and the actions stack full-width like
     Orders, and the collapsed disclosure summary keeps every remaining filter
     one tap away — the toolbar no longer eats the initial viewport. */
  .filter-bar--employees > .filter-field,
  .filter-bar--employees > .filter-actions {
    grid-column: 1 / -1;
  }

  .filter-bar--orders .filter-actions {
    justify-content: stretch;
  }

  .filter-bar--deliveries .filter-actions {
    justify-content: stretch;
  }

  .filter-bar--routes .filter-actions {
    justify-content: stretch;
  }

  .filter-bar--employees .filter-actions {
    justify-content: stretch;
  }

  .filter-bar--orders .filter-actions .btn {
    flex: 1 1 auto;
    width: 100%;
  }

  .filter-bar--deliveries .filter-actions .btn {
    flex: 1 1 auto;
    width: 100%;
  }

  .filter-bar--routes .filter-actions .btn {
    flex: 1 1 auto;
    width: 100%;
  }

  .filter-bar--employees .filter-actions .btn {
    flex: 1 1 auto;
  }

  /* Compact the filter disclosures on phones: a shorter summary row and
     tighter body rhythm reduce the vertical weight of the filter stack
     without changing the disclosure behavior or field order. */
  .filter-bar--orders .filter-collapsible__summary,
  .filter-bar--deliveries .filter-collapsible__summary,
  .filter-bar--employees .filter-collapsible__summary {
    min-height: 42px;
    padding: var(--space-1) var(--space-3);
  }

  .filter-bar--orders .filter-collapsible__body,
  .filter-bar--deliveries .filter-collapsible__body,
  .filter-bar--employees .filter-collapsible__body {
    gap: var(--space-2);
  }

  .filter-bar--orders .filter-collapsible__body > .field,
  .filter-bar--orders .filter-collapsible__body > .filter-size,
  .filter-bar--deliveries .filter-collapsible__body > .field,
  .filter-bar--deliveries .filter-collapsible__body > .filter-size,
  .filter-bar--employees .filter-collapsible__body > .field,
  .filter-bar--employees .filter-collapsible__body > .filter-size {
    grid-column: 1 / -1;
  }

  .notice-banner {
    margin-inline: var(--space-3);
  }

  .shutdown-confirm > form {
    padding-inline: var(--space-3);
  }

  .organization-detail-zones,
  .organization-collections,
  .organization-confirm-body {
    padding: var(--space-3);
  }

  .organization-requisites-page .organization-collection-head {
    display: grid;
    align-items: stretch;
  }

  .organization-requisites-page .organization-collection-head .btn {
    width: 100%;
  }

  .organization-requisites-page .organization-account-number {
    grid-column: 1 / -1;
  }

  .bulk-action-bar {
    align-items: stretch;
    padding-inline: var(--space-3);
    flex-direction: column;
  }

  .bulk-action-bar .btn {
    width: 100%;
  }

  .list-meta--deliveries .money-visibility-note {
    font-size: var(--text-xs);
    line-height: 1.4;
  }

  .list-meta--routes .money-visibility-note,
  .route-summary-list,
  .route-preview-delivery,
  .route-preview-more {
    font-size: var(--text-xs);
    line-height: 1.4;
  }
}

/* --- B4: Редактор (общие справочники) --- */

/* Список модулей слева, пояснение к выбранному справа. Описания больше не
   живут на кнопках. */
/* Домашний экран Редактора обязан помещаться в один экран 1366×768: заказчик
   просила это дословно («чтобы все влазило на экран», `DARYA-2026-09-01-011`).
   На 1440 и 1920 это выполнялось, на 1366 странице не хватало 33 px — ровно
   восемь модулей списка слева задают её высоту. Ниже сняты те 33 px и ещё
   немного запаса: отступ блока по вертикали 16 → 12 px и высота пункта списка
   40 → 36 px. Пункт остаётся заметно выше пальца (36 px против 24 px самого
   текста), ширина и горизонтальные отступы не тронуты. */
.editor-modules {
  display: grid;
  grid-template-columns: minmax(220px, 300px) minmax(0, 1fr);
  gap: var(--space-4) var(--space-6);
  align-items: start;
  padding: var(--space-3) var(--space-5);
}

.editor-module-list {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.editor-module-link {
  display: flex;
  align-items: center;
  min-height: 36px;
  min-width: 0;
  padding: 6px var(--space-3);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font-weight: var(--weight-accent);
  text-decoration: none;
  overflow-wrap: break-word;
  transition:
    border-color var(--motion-duration) ease,
    background-color var(--motion-duration) ease;
}

.editor-module-link:hover {
  border-color: var(--color-border);
  background: var(--color-surface-soft);
}

.editor-module-link:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.editor-module-link.is-selected {
  border-color: var(--color-border-strong);
  color: var(--color-ink);
  background: var(--color-surface);
}

.editor-module-detail {
  display: grid;
  justify-items: start;
  gap: var(--space-3);
  align-content: start;
  min-width: 0;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-soft);
}

.editor-module-detail h2 {
  margin: 0;
  font-size: var(--text-lg);
  line-height: var(--leading-tight);
}

.editor-module-detail__description {
  max-width: 70ch;
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-body);
}

.editor-module-detail__counts {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
  font-size: var(--text-xs);
  font-weight: var(--weight-strong);
  color: var(--color-text-muted);
}

.editor-modules-note {
  margin: 0;
  padding: 0 var(--space-5) var(--space-4);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-body);
}

.editor-org-note {
  margin: var(--space-4) var(--space-5) 0;
}

.editor-confirm-note {
  margin: var(--space-4) var(--space-5) 0;
}

.editor-confirm-actions {
  padding: var(--space-4) var(--space-5) var(--space-5);
}

/* Success/error outcome of the last Editor action; fixed server-side text. */
.editor-notice {
  margin: var(--space-4) var(--space-5) 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid rgb(37 99 235 / 0.22);
  border-radius: var(--radius-sm);
  color: var(--color-ink);
  background: rgb(37 99 235 / 0.08);
  font-weight: var(--weight-strong);
}

.editor-notice--error {
  border-color: rgb(225 29 72 / 0.28);
  color: #9f1239;
  background: rgb(225 29 72 / 0.08);
}

/* Row actions: per-organization group first, then the clearly separated
   system-wide group. The divider text names the scope of the global actions. */
.editor-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.editor-actions__org,
.editor-actions__global {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  min-width: 0;
}

.editor-actions__divider {
  padding-left: var(--space-2);
  border-left: 1px solid var(--color-border-strong);
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-accent);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.editor-actions__hint {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-body);
  max-width: 18rem;
}

/* Long organization names (up to 255) and dictionary labels (up to 128) must
   wrap instead of clipping or forcing horizontal scroll. */
.editor-orgname,
.editor-label {
  overflow-wrap: anywhere;
}

.editor-actions .btn {
  white-space: normal;
  overflow-wrap: anywhere;
  text-align: center;
}

.editor-table td {
  vertical-align: top;
}

/* The availability header carries the organization name (up to 255 chars);
   the shared table header is nowrap, so allow this one column to wrap instead
   of forcing the whole table past the viewport. */
.editor-table th.editor-orgname {
  white-space: normal;
  overflow-wrap: anywhere;
  min-width: 180px;
}

/* Same rule for the head badge: the shared .badge is nowrap, and a 255-char
   organization name must wrap inside the Editor head instead of widening the
   whole panel past the viewport.

   `break-word`, не `anywhere`: `anywhere` делает min-content бейджа равным
   одному символу, и флекс-элемент шапки схлопывался до этой ширины — короткое
   название («КРИ») рвалось на «КР / И» на всех десктопных ширинах. `break-word`
   разрывает по пробелу и не рвёт короткое слово. Предельный случай — 255
   символов без единого пробела — при этом не переносится, а обрезается внутри
   бейджа: горизонтальной прокрутки и разъезжающейся шапки не возникает
   (см. `min-width: 0` у `.view-head`). */
.editor-orgbadge {
  display: inline-flex;
  min-width: 0;
  max-width: 100%;
}

.editor-orgbadge .badge {
  white-space: normal;
  overflow-wrap: break-word;
  min-width: 0;
  max-width: 100%;
}

.editor-history {
  border-top: 1px solid var(--color-border);
  padding: var(--space-4) var(--space-5);
}

/* Свёрнутый по умолчанию список изменений: та же нативная раскрывашка, что и
   у второстепенных фильтров заявок, поэтому и вид у неё тот же. */
.editor-history__disclosure > .filter-collapsible__summary,
.client-orders-disclosure > .filter-collapsible__summary {
  justify-content: flex-start;
  gap: var(--space-2);
}

/* Число заявок в заголовке раскрывашки карточки клиента — тот же счётчик, что
   стоял справа в шапке панели «Заявки клиента» до сворачивания. */
.client-orders-count {
  color: var(--color-text-muted);
  font-weight: var(--weight-strong);
}

/* Поиск по заявкам клиента: поле и кнопка одной строкой, на телефоне кнопка
   уходит под поле. Без JavaScript — обычная GET-форма. */
.client-orders-search {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.client-orders-search .field {
  flex: 1 1 200px;
  min-width: 0;
  max-width: 420px;
}

/* Подпись раскрывашки истории несёт вид заголовка секции, но не является
   `<h2>` (см. комментарий в `editor/_history.html`), поэтому ступень веса и
   межстрочный интервал заданы здесь явно, а не унаследованы от h1–h3. */
.editor-history__title {
  margin: 0;
  font-size: var(--text-base);
  font-weight: var(--weight-heading);
  line-height: var(--leading-tight);
}

.editor-history__body {
  margin-top: var(--space-3);
}

.editor-history__empty {
  margin: 0;
  color: var(--color-text-muted);
  font-weight: var(--weight-body);
}

.filter-bar--editor {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding-block: var(--space-3);
  align-items: end;
}

.filter-bar--editor > .filter-field,
.filter-bar--editor > .filter-size,
.filter-bar--editor > .filter-actions {
  min-width: 0;
}

.filter-field--editor-search {
  flex: 1 1 280px;
  max-width: 420px;
}

.filter-field--editor-kind,
.filter-field--editor-status {
  flex: 0 1 170px;
}

.filter-size--editor {
  flex: 0 1 110px;
}

.filter-bar--editor .input,
.filter-bar--editor .select,
.filter-bar--editor .btn {
  min-height: 42px;
}

.filter-actions--editor {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: var(--space-2);
  justify-content: flex-start;
  min-width: 0;
}

.filter-actions--editor .btn {
  padding-inline: var(--space-3);
  white-space: nowrap;
}

.editor-cargo-settings {
  width: min(calc(100% - var(--space-5) - var(--space-5)), 960px);
  margin: var(--space-4) var(--space-5) 0;
  padding: var(--space-3) var(--space-4);
  gap: var(--space-3);
}

.editor-cargo-settings .form-section__head p {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-body);
}

.editor-cargo-settings__form {
  display: grid;
  grid-template-columns: minmax(180px, 220px) minmax(280px, 420px) auto;
  gap: var(--space-3);
  align-items: end;
  min-width: 0;
}

.editor-cargo-settings__toggle,
.editor-cargo-settings__prefix,
.editor-cargo-settings__actions {
  min-width: 0;
}

.editor-cargo-settings__actions {
  display: flex;
  align-items: end;
}

.editor-cargo-settings__actions .btn {
  min-height: 42px;
  white-space: nowrap;
}

/* Блок из одного флажка (поле «Вид доставки» в модуле «Виды доставки»):
   та же секция, что у грузового контура, без колонки префикса — флажок с
   подсказкой занимает всю ширину до кнопки. */
.editor-cargo-settings__form--single {
  grid-template-columns: minmax(280px, 640px) auto;
}

/* Блок из двух флажков (страница «Состав форм»): две равные колонки с
   подсказками, выровненные по верху, и кнопка отдельной строкой; те же
   токены, что у грузового контура. Блок стоит на странице последним, поэтому
   несёт нижний отступ панели сам. */
.editor-cargo-settings__form--pair {
  grid-template-columns: minmax(240px, 1fr) minmax(240px, 1fr);
  align-items: start;
}

.editor-cargo-settings__form--pair .editor-cargo-settings__actions {
  grid-column: 1 / -1;
}

/* Третий переключатель страницы «Состав форм» — «Пункт выдачи». Он не про вид
   формы, а про правило счётчика долга, и подсказка у него длиннее двух верхних:
   в колонке 240px она встала бы в шесть строк. Поэтому он занимает ряд целиком
   и отделён от пары тем же бледным разделителем, что и зоны карточки, — новых
   цветов, теней и брейкпоинтов здесь не заводится. */
.editor-cargo-settings__toggle--wide {
  grid-column: 1 / -1;
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}

/* Строка «Последний выданный номер» в блоке нумерации заявок: справочное
   значение, а не поле. Занимает ряд целиком и отделяется тем же бледным
   разделителем, что и «Пункт выдачи», — новых токенов не заводится. */
.editor-cargo-settings__note {
  grid-column: 1 / -1;
  margin: 0;
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}

.editor-cargo-settings--standalone {
  margin-bottom: var(--space-5);
}

@media (min-width: 768px) and (max-width: 1023.98px) { /* mobile…ниже tablet */
  .editor-cargo-settings__form {
    grid-template-columns: minmax(180px, 220px) minmax(260px, 420px);
  }

  .editor-cargo-settings__actions {
    grid-column: 2;
  }

  .editor-cargo-settings__form--single {
    grid-template-columns: minmax(260px, 1fr) auto;
  }

  .editor-cargo-settings__form--single .editor-cargo-settings__actions {
    grid-column: auto;
  }
}

@media (max-width: 767.98px) { /* ниже mobile */
  .filter-bar--editor {
    grid-template-columns: 1fr;
    gap: var(--space-2);
  }

  .filter-bar--editor > .filter-field,
  .filter-bar--editor > .filter-size,
  .filter-bar--editor > .filter-actions {
    grid-column: 1 / -1;
  }

  .filter-bar--editor .filter-actions {
    justify-content: stretch;
  }

  .filter-bar--editor .filter-actions .btn {
    flex: 1 1 auto;
    width: 100%;
  }

  .editor-cargo-settings {
    width: auto;
    margin-inline: var(--space-3);
    padding: var(--space-3);
  }

  .editor-cargo-settings__form {
    grid-template-columns: 1fr;
    gap: var(--space-3);
  }

  .editor-cargo-settings__actions {
    grid-column: auto;
  }

  .editor-cargo-settings__actions .btn {
    min-height: 44px;
    width: 100%;
  }

  .editor-modules {
    grid-template-columns: 1fr;
    padding: var(--space-4) var(--space-3);
  }

  .editor-modules-note {
    padding-inline: var(--space-3);
  }

  .editor-history {
    padding: var(--space-4) var(--space-3);
  }

  .editor-org-note,
  .editor-confirm-note,
  .editor-notice {
    margin-inline: var(--space-3);
  }

  .editor-confirm-actions {
    padding: var(--space-4) var(--space-3) var(--space-5);
  }

  .editor-actions__divider {
    flex-basis: 100%;
    padding-left: 0;
    border-left: 0;
  }
}

/* B4: «Редактор» is a sixth shared link; on 390x844 the opened drawer becomes
   scrollable and «Выйти» fell below the fold. Pin the footer to the drawer
   bottom so logout stays visible while the section links scroll. */
.drawer-footer {
  position: sticky;
  /* The sticky inset tracks the margin edge, and the negative bottom margin
     (which cancels the drawer padding) sits 16px above the border edge — a
     plain bottom: 0 therefore pins the footer 16px too high and swallows the
     grid gap before it. Offset the inset by the same amount so the pinned
     footer lands exactly on its natural slot, flush with the drawer bottom. */
  bottom: calc(-1 * var(--space-4));
  z-index: 1;
  margin: 0 calc(-1 * var(--space-4)) calc(-1 * var(--space-4));
  padding: var(--space-3) var(--space-4) var(--space-4);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface);
}

/* «Сменить пароль» и «Выйти» — одной строкой, две равные колонки. Столбиком
   (2026-09-13) липкий подвал вырос с 73 до 125 px и закрыл одну ссылку списка.
   Без JavaScript вторая колонка — сам `<noscript>` с формой выхода, а
   модальный триггер скрыт и колонки не занимает; форма растягивает кнопку на
   ширину колонки, как ссылку рядом. */
.drawer-footer {
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
}

.drawer-footer .logout-nojs {
  display: grid;
}

/* The old min(82vh, 720px) cap left a 690px scrollport at 390x844, so the
   pinned footer covered the last link «Редактор» at open and the drawer ran
   out of scroll range with 0px clearance. Let the drawer use the height the
   fixed backdrop already reserves (viewport minus its padding): with six
   shared links the full list now fits above the footer, nothing is covered,
   and shorter drawers keep their content-sized height unchanged. */
.drawer {
  max-height: min(calc(100vh - 2 * var(--space-3)), 800px);
}

/* R2 phone touch floor — final cascade guard. Earlier phone overrides for
   .filter-bar .btn/.select and the orders filter summary are defeated by
   editor-specific rules (.filter-bar--editor .btn/.select, set later in the
   stylesheet) and by the «ниже mobile» summary rule. This block runs last, so at
   equal specificity it wins on phones (ниже phone) only; desktop/tablet keep their
   existing dense geometry. C3 16px editable-control text is inherited from the
   earlier phone .input/.select/.textarea rule and is not re-declared here. */
@media (max-width: 519.98px) { /* ниже phone */
  .filter-bar .btn,
  .filter-bar .select {
    min-height: 44px;
  }

  /* Tap-to-call phone link on courier cards is a real operational touch
     control: raise it to the phone touch floor. Negative inline margins keep
     the link visually aligned with the contact block around it. */
  .courier-card__phone {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding-inline: var(--space-2);
    margin-inline: calc(-1 * var(--space-2));
  }

  /* Подпись «Телефон» центрируется по высокой (44px) ссылке звонка, чтобы не
     висеть над ней. */
  .courier-card__rows .courier-card__phone-label {
    align-self: center;
  }

  .filter-bar--orders .filter-collapsible__summary,
  .filter-bar--deliveries .filter-collapsible__summary,
  .filter-bar--employees .filter-collapsible__summary {
    min-height: 44px;
  }

  /* Route-card bulk-select checkbox label is a real phone touch control with a
     34px base min-height; raise only the height floor here. Its inline checkbox
     stays 18px; the clickable label box grows. Desktop/tablet unchanged. */
  .bulk-check--card {
    min-height: 44px;
  }
}

/* Панель выбора клиентов на узком экране. Общая мобильная панель массовых
   действий ставит кнопки столбиком во всю ширину — три кнопки занимали 206 px
   над списком. Здесь число и «Выбрать всех» стоят одной строкой, а
   «Скопировать» — своей строкой во всю ширину. */
@media (max-width: 767.98px) { /* ниже mobile */
  .client-selection-bar {
    flex-direction: row;
    align-items: center;
  }

  .client-selection-bar__actions {
    display: contents;
  }

  .client-selection-bar [data-selection-select-all] {
    margin-inline-start: auto;
  }

  .client-selection-bar .btn {
    width: auto;
  }

  .client-selection-bar [data-selection-transfer] {
    flex: 1 1 100%;
  }
}

/* Уважение к настройке «уменьшить движение»: все переходы отключаются
   (пак 2026-09-03, T10). Ключевых кадров в проекте нет, отключать нечего. */
@media (prefers-reduced-motion: reduce) {
  *,
  ::before,
  ::after {
    transition: none !important;
  }
}
