/* Переход между страницами — плавный, а не белой вспышкой.

   Система работает полными перезагрузками: щёлкнул раздел — браузер стёр
   страницу и нарисовал заново. Сервер отдаёт за 200 мс, тянуть нечего,
   но глазу видно именно стирание. `navigation: auto` просит браузер
   перелистнуть страницы кросс-фейдом вместо вспышки.

   Браузеры, которые этого не умеют, строку просто пропускают.
   При включённом «уменьшить движение» — тоже, ниже. */
@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) { animation-duration: .12s; }

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

/* Inter — тот же шрифт, что раньше тянулся с Google Fonts. Лежит у нас:
   система живёт во внутренней сети, и ждать чужой сервер, чтобы нарисовать
   страницу, ей не с руки — из-за него страница открывалась через секунду.
   Оставлены наборы кириллицы и латиницы; греческий и вьетнамский не нужны.
   Файл переменный: одна начертанием покрывает веса от 100 до 900. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/fonts/inter-cyrillic-ext.woff2') format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/fonts/inter-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==========================================================================
   Мавсим и К — дизайн-система (v2)
   Без сборки: один CSS-файл, токены на :root, БЭМ-подобные классы.
   ========================================================================== */

:root {
  /* Брендовые цвета */
  --brand-50:  #ecfdf5;
  --brand-100: #d1fae5;
  --brand-200: #a7f3d0;
  --brand-500: #10b981;
  --brand-600: #059669;
  --brand-700: #047857;

  /* Нейтральные */
  --bg:         #f6f7f9;
  --surface:    #ffffff;
  --border:     #e6e8ec;
  --border-str: #d5d9e0;
  --text:       #10151c;
  --text-mut:   #66707d;
  --text-soft:  #97a0ac;

  /* Статусы */
  --ok:      #059669;
  --ok-bg:   #ecfdf5;
  --info:    #2563eb;
  --info-bg: #eff6ff;
  --warn:    #b45309;
  --warn-bg: #fffbeb;
  --danger:  #dc2626;
  --danger-bg:#fef2f2;
  --violet:  #7c3aed;
  --violet-bg:#f5f3ff;

  /* Формы */
  --r-sm: 6px;
  --r:    10px;
  --r-lg: 14px;
  --shadow-sm: 0 1px 2px rgba(16, 21, 28, .05);
  --shadow:    0 1px 3px rgba(16, 21, 28, .06), 0 8px 24px -12px rgba(16, 21, 28, .12);


  /* Поверхности и заливки, которые раньше были вписаны в правила.
     Тёмная тема переопределяет только их — сами правила не трогаются. */
  --surface-2:  #fafbfc;      /* шапки таблиц, подложки подкарточек */
  --hover:      #f2f4f7;      /* наведение на пункт, кнопку, строку меню */
  --track:      #eef0f3;      /* дорожки полос, счётчики, скелетоны */
  --on-brand:   #ffffff;      /* текст поверх цветной заливки */
  --teal:       #0e7490;
  --teal-bg:    #ecfeff;
  --danger-brd: #fecaca;
  --ok-brd:     #a7f3d0;
  --warn-solid: #f59e0b;

  /* Штамп электронной подписи — синий, как оттиск на бумаге */
  --stamp: #3f5a8a;
  --toast-bg:   #111827;
  --toast-fg:   #ffffff;
  --chart-line: #94a3b8;      /* пунктир «завершено» на графике */

  --sidebar-w: 264px;
  --topbar-h:  60px;

  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;

  color-scheme: light;
}

/* ============================================================ Тёмная тема ==
   Переопределяются только токены — правила ниже по файлу общие для обеих тем.
   Поэтому новый компонент, собранный на токенах, темнеет сам.

   Три состояния: выбор человека (data-theme на <html>) главнее системной
   настройки, а без выбора действует системная. Ровно поэтому один и тот же
   набор описан дважды: в @media — для «как в системе», в [data-theme] — для
   явного переключателя, иначе он не смог бы включить тёмную тему на светлой
   системе и наоборот. */

:root[data-theme="dark"] {
  color-scheme: dark;

  /* Бренд: заливки чуть глуше, текстовый оттенок — светлее, иначе
     зелёный на тёмном читается как грязно-серый */
  --brand-50:  rgba(16, 185, 129, .14);
  --brand-100: rgba(16, 185, 129, .22);
  --brand-200: rgba(16, 185, 129, .36);
  --brand-500: #34d399;
  --brand-600: #0b9d6e;
  --brand-700: #6ee7b7;

  --bg:         #0e1116;
  --surface:    #151a21;
  --surface-2:  #1a212a;
  --hover:      #212a35;
  --border:     #242c37;
  --border-str: #313b48;
  --track:      #232c37;
  --text:       #e6eaf0;
  --text-mut:   #9aa5b4;
  --text-soft:  #6f7b8b;

  --ok:      #2fbf87;
  --ok-bg:   rgba(47, 191, 135, .14);
  --info:    #4f8ef7;
  --info-bg: rgba(79, 142, 247, .14);
  --warn:    #e3a008;
  --warn-bg: rgba(227, 160, 8, .14);
  --danger:  #e5484d;
  --danger-bg: rgba(229, 72, 77, .14);
  --danger-brd: rgba(229, 72, 77, .4);
  --ok-brd:     rgba(47, 191, 135, .4);
  --violet:  #9277f5;
  --violet-bg: rgba(146, 119, 245, .14);
  --teal:    #35b8cc;
  --teal-bg: rgba(53, 184, 204, .14);

  --warn-solid: #d97706;
  --stamp:      #8fa8d4;
  --toast-bg:   #e6eaf0;
  --toast-fg:   #10151c;
  --chart-line: #7c8899;

  /* На тёмном фоне мягкая тень не видна — нужна плотная */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .5);
  --shadow:    0 1px 3px rgba(0, 0, 0, .5), 0 8px 24px -12px rgba(0, 0, 0, .7);
}

/* Тёмная система — если человек не выбрал тему руками */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --brand-50:  rgba(16, 185, 129, .14);
    --brand-100: rgba(16, 185, 129, .22);
    --brand-200: rgba(16, 185, 129, .36);
    --brand-500: #34d399;
    --brand-600: #0b9d6e;
    --brand-700: #6ee7b7;

    --bg:         #0e1116;
    --surface:    #151a21;
    --surface-2:  #1a212a;
    --hover:      #212a35;
    --border:     #242c37;
    --border-str: #313b48;
    --track:      #232c37;
    --text:       #e6eaf0;
    --text-mut:   #9aa5b4;
    --text-soft:  #6f7b8b;

    --ok:      #2fbf87;
    --ok-bg:   rgba(47, 191, 135, .14);
    --info:    #4f8ef7;
    --info-bg: rgba(79, 142, 247, .14);
    --warn:    #e3a008;
    --warn-bg: rgba(227, 160, 8, .14);
    --danger:  #e5484d;
    --danger-bg: rgba(229, 72, 77, .14);
    --danger-brd: rgba(229, 72, 77, .4);
    --ok-brd:     rgba(47, 191, 135, .4);
    --violet:  #9277f5;
    --violet-bg: rgba(146, 119, 245, .14);
    --teal:    #35b8cc;
    --teal-bg: rgba(53, 184, 204, .14);

    --warn-solid: #d97706;
    --stamp:      #8fa8d4;
    --toast-bg:   #e6eaf0;
    --toast-fg:   #10151c;
    --chart-line: #7c8899;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .5);
    --shadow:    0 1px 3px rgba(0, 0, 0, .5), 0 8px 24px -12px rgba(0, 0, 0, .7);
  }
}

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

/* Атрибут hidden должен побеждать любой display у класса */
[hidden] { display: none !important; }

html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; }
svg { display: block; }

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

.layout { display: flex; min-height: 100vh; }

.main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  margin-left: var(--sidebar-w);
  transition: margin-left .28s cubic-bezier(.4, 0, .2, 1);
}

body.is-collapsed .main { margin-left: 0; }

/* Реестры занимают всю ширину окна: колонок много, поля по бокам съедают место.
   Дашборд остаётся в колонке 1560px — длинные строки текста иначе не читаются. */
.main--wide .content,
.main--wide .topbar__inner,
.main--wide .footer__inner { max-width: none; }

.content {
  flex: 1;
  padding: 24px 28px 40px;
  max-width: 1560px;
  width: 100%;
  margin-inline: auto;   /* центрируем, иначе при свёрнутом сайдбаре контент липнет влево */
}

/* -------------------------------------------------------------- Сайдбар -- */

.sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  width: var(--sidebar-w);
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  z-index: 40;
  transition: transform .28s cubic-bezier(.4, 0, .2, 1);
}

body.is-collapsed .sidebar { transform: translateX(-100%); }

.sidebar__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  height: var(--topbar-h);
  padding: 0 18px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

/* Знак логотипа, без надписи: рядом уже стоит название конторы, и повторять
   его картинкой значит написать «Мавсим» дважды. Подложки под знаком нет —
   оранжевый читается и на светлой, и на тёмной теме. */
.sidebar__logo {
  width: 32px; height: 32px;
  display: grid; place-items: center;
  flex-shrink: 0;
}

.sidebar__logo img { width: 100%; height: auto; }

.sidebar__title { font-weight: 650; font-size: 15px; letter-spacing: -.01em; }
/* display: block обязателен — рядом с названием лежит второй <span>,
   и без него подпись вставала в ту же строку: «Мавсим и К Логистика». */
.sidebar__sub   { display: block; font-size: 11px; color: var(--text-soft); margin-top: -2px; }

.sidebar__scroll { flex: 1; overflow-y: auto; padding: 14px 12px 20px; }

.sidebar__search { padding: 0 12px 12px; }

.nav-group { margin-bottom: 18px; }

.nav-group__label {
  font-size: 10.5px;
  font-weight: 650;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-soft);
  padding: 0 10px 6px;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  text-align: left;
  font-size: 14px;
  border: none;
  background: none;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  color: var(--text-mut);
  font-weight: 500;
  transition: background .12s, color .12s;
  position: relative;
}

.nav-item:hover { background: var(--hover); color: var(--text); }

.nav-item.is-active {
  background: var(--brand-50);
  color: var(--brand-700);
  font-weight: 600;
}

.nav-item.is-active::before {
  content: "";
  position: absolute;
  left: -12px; top: 50%;
  transform: translateY(-50%);
  width: 3px; height: 18px;
  border-radius: 0 3px 3px 0;
  background: var(--brand-600);
}

.nav-item__icon { width: 18px; height: 18px; flex-shrink: 0; opacity: .9; }
.nav-item__text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Подменю сворачивается через grid-template-rows: 1fr → 0fr.
   Это даёт плавную анимацию по реальной высоте без замеров в JS. */
.nav-sub {
  display: grid;
  grid-template-rows: 1fr;
  margin: 2px 0 6px 28px;
  opacity: 1;
  transition: grid-template-rows .26s cubic-bezier(.4, 0, .2, 1),
              opacity .18s ease .06s,
              margin .26s cubic-bezier(.4, 0, .2, 1),
              visibility 0s;
}

.nav-sub__list {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-height: 0;
  overflow: hidden;
}

.nav-sub.is-collapsed {
  grid-template-rows: 0fr;
  opacity: 0;
  margin-top: 0;
  margin-bottom: 0;
  visibility: hidden;
  transition: grid-template-rows .24s cubic-bezier(.4, 0, .2, 1),
              opacity .16s ease,
              margin .24s cubic-bezier(.4, 0, .2, 1),
              visibility 0s linear .24s;   /* прячем от фокуса только после схлопывания */
}

.nav-sub .nav-item { padding: 6px 10px; font-size: 13.5px; font-weight: 500; }

/* Активный пункт внутри группы: раньше маркер прятался, и подсветка терялась
   среди соседей. Оставляем и заливку, и полоску — только короче, по высоте
   строки подменю. */
.nav-sub .nav-item.is-active::before { left: -8px; height: 14px; }

/* Группа, внутри которой открыт текущий раздел. Сама группа не активна —
   активен пункт внутри неё, — но по свёрнутому меню должно быть видно,
   где человек находится. */
.nav-item.is-branch { color: var(--brand-700); font-weight: 600; }
.nav-item.is-branch .nav-item__icon { color: var(--brand-600); }

/* Пока меню раскладывают по сохранённому состоянию, анимации выключены:
   иначе при каждом переходе группы разъезжаются на глазах. */
.sidebar--quiet .nav-sub,
.sidebar--quiet .nav-item,
.sidebar--quiet .nav-item__chevron { transition: none !important; }

/* Маркер пункта подменю: у «Нового запроса» иконка со смыслом, у списков —
   просто кружок. Без него подписи стояли бы с разным отступом. */
.nav-item__icon--dot { width: 10px; height: 10px; margin: 0 4px; opacity: .45; }

.nav-item__chevron {
  width: 14px; height: 14px; opacity: .5;
  transition: transform .26s cubic-bezier(.4, 0, .2, 1);
}
.nav-item[aria-expanded="true"] .nav-item__chevron { transform: rotate(180deg); }

.sidebar__footer {
  border-top: 1px solid var(--border);
  padding: 12px;
  flex-shrink: 0;
}

/* Профиль и выход — рядом, но это разные кнопки */
.sidebar__user { display: flex; align-items: center; gap: 4px; }
.sidebar__user .user-chip { flex: 1; min-width: 0; }

.user-chip {
  display: flex; align-items: center; gap: 10px;
  padding: 8px; border-radius: var(--r-sm);
}
.user-chip:hover { background: var(--hover); }

.avatar {
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--brand-100); color: var(--brand-700);
  display: grid; place-items: center;
  font-weight: 650; font-size: 13px;
  flex-shrink: 0;
}

.user-chip__name { font-weight: 600; font-size: 13.5px; }
.user-chip__role { font-size: 11.5px; color: var(--text-soft); }

/* --------------------------------------------------------------- Топбар -- */

.topbar {
  height: var(--topbar-h);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 30;
}

/* Внутренние обёртки топбара и футера повторяют ширину .content,
   иначе при свёрнутом сайдбаре шапка и подвал не совпадают с контентом. */
.topbar__inner,
.footer__inner {
  max-width: 1560px;
  margin-inline: auto;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 14px;
}

.topbar__inner {
  height: 100%;
  padding: 0 28px;
}

.icon-btn {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-mut);
  position: relative;
}
.icon-btn:hover { background: var(--hover); color: var(--text); }

.icon-btn__dot {
  position: absolute; top: 6px; right: 7px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--danger);
  border: 2px solid var(--surface);
}

.breadcrumb { display: flex; align-items: center; gap: 7px; color: var(--text-soft); font-size: 13px; }
.breadcrumb__current { color: var(--text); font-weight: 550; }

.topbar__spacer { flex: 1; }

/* ----------------------------------------------------------- Инпуты/кн -- */

/* Высота 40, а не 34: поля заполняют весь день, и текст в них — не подпись
   к чему-то, а сама работа. На 34 с 14-м кеглем строка прижата к рамке
   сверху и снизу, и глазу не за что зацепиться. Размер шрифта задан явно:
   у input он не наследуется от body, браузер ставит свой мелкий. */
.input {
  width: 100%;
  height: 40px;
  /* Отступ одинаковый с обеих сторон. Раньше слева стояло 34px — место под
     иконку внутри поля, — но иконка есть у меньшинства полей, а отступ
     доставался всем: текст в обычном поле начинался с пустого пятна шириной
     в три символа. Место под иконку теперь выдаётся там, где она есть. */
  padding: 0 12px;
  font: inherit;
  font-size: 14px;
  border: 1px solid var(--border-str);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text);
  outline: none;
  transition: border-color .12s, box-shadow .12s;
}
.input::placeholder { color: var(--text-soft); }
.input:focus { border-color: var(--brand-500); box-shadow: 0 0 0 3px var(--brand-50); }

.input:disabled,
.select:disabled {
  background-color: var(--hover);
  color: var(--text-soft);
  cursor: not-allowed;
}

/* Гасим и подпись поля, чтобы выключенное состояние читалось целиком */
.field.is-disabled .field__label,
.field.is-disabled .range__dash { opacity: .5; }

.input-wrap { position: relative; }
.input-wrap__icon {
  position: absolute; left: 9px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--text-soft); pointer-events: none;
}

/* Место под иконку — только полю, у которого она есть: иконка лежит поверх
   поля, и без отступа текст пошёл бы прямо по ней. */
.input-wrap .input { padding-left: 34px; }

/* Строка-ссылка: курсор говорит, что по ней можно нажать, ещё до нажатия */
tr[data-row-href] { cursor: pointer; }

/* Найденное в реестре. Не жёлтый маркер поверх тёмной темы, а подложка
   бренда: подсветка должна читаться в обеих темах и не спорить со статусами
   в соседних колонках. */
mark, .mark {
  background: var(--brand-100);
  color: inherit;
  border-radius: 3px;
  padding: 0 1px;
  font-weight: 650;
}

/* --------------------------------------------------- Доступ к разделам --- */

/* Список разделов в карточке пользователя. Отделён рамкой от полей выше:
   там — кто человек, здесь — что ему открыто, и это разные вопросы. */
.access {
  margin-top: 20px;
  border-top: 1px solid var(--border);
  padding-top: 18px;
}

.access__head { margin-bottom: 12px; }
.access__title { font-weight: 650; font-size: 14px; }
.access__note {
  display: block; margin-top: 3px;
  font-size: 12.5px; line-height: 1.45; color: var(--text-soft);
}

.access__all {
  display: flex; align-items: flex-start;
  padding: 11px 12px; margin-bottom: 14px;
  border: 1px solid var(--border-str);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--text);
}

.access__groups {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px 20px;
}

/* Когда стоит «Администратор», выбирать нечего: список гаснет целиком,
   а не спорит с флажком выше. */
.access__groups.is-off { opacity: .45; pointer-events: none; }

.access__group-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin-bottom: 6px;
}
.access__group-name {
  font-size: 12px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-soft);
}
.access__group-head .link-btn { font-size: 12px; }

/* Каждый раздел с новой строки. Правило именное, потому что рядом стоит
   `.check` с inline-flex: без него разделы шли бы по два-три в строку,
   и колонка группы читалась бы как сплошной текст. */
.access .access__item { display: flex; align-items: center; padding: 3px 0; }

/* Кнопка, выглядящая ссылкой: действие внутри пояснительной строки под полем.
   Именно кнопка, а не <a href="#">: она ничего не открывает, а делает. */
.link-btn {
  border: 0; background: none; padding: 0;
  font: inherit; color: var(--brand-600);
  text-decoration: underline; text-underline-offset: 2px;
  cursor: pointer;
}
.link-btn:hover { color: var(--brand-700); }

/* Глазок в поле пароля. Кнопка лежит поверх поля справа, поэтому справа же
   поле и поджимается — иначе длинный пароль уезжает под неё. */
.input-wrap--pass .input { padding-right: 38px; }

.input-wrap__btn {
  position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border: 0; background: none; padding: 0;
  border-radius: var(--r-sm);
  color: var(--text-soft);
  cursor: pointer;
}
.input-wrap__btn:hover { color: var(--text); background: var(--hover); }
.input-wrap__btn svg { width: 16px; height: 16px; }

.btn {
  display: inline-flex; align-items: center; gap: 7px;
  height: 40px; padding: 0 16px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-str);
  background: var(--surface);
  color: var(--text);
  font-weight: 550;
  transition: background .12s, border-color .12s;
}
.btn:hover { background: var(--bg); }

.btn--primary {
  background: var(--brand-600);
  border-color: var(--brand-600);
  color: var(--on-brand);
}
.btn--primary:hover { background: var(--brand-700); border-color: var(--brand-700); }

.btn--ghost { border-color: transparent; background: transparent; color: var(--text-mut); }
.btn--ghost:hover { background: var(--hover); color: var(--text); }

.btn--sm { height: 32px; padding: 0 12px; font-size: 13px; }

/* ------------------------------------------------------------ Заголовок -- */

.page-head {
  display: flex;
  align-items: flex-end;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}

.page-head__title {
  margin: 0;
  font-size: 24px;
  font-weight: 680;
  letter-spacing: -.02em;
}

.page-head__sub { margin: 4px 0 0; color: var(--text-mut); font-size: 13.5px; }
.page-head__actions { margin-left: auto; display: flex; gap: 8px; }

/* ---------------------------------------------------------------- Формы --- */

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px 20px;
}

.form-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.field--full { grid-column: 1 / -1; }

.field__label .req { color: var(--danger); margin-left: 2px; }
.field__hint { font-size: 12.5px; line-height: 1.45; color: var(--text-soft); }

/* Подпись о расхождении. Не ошибка — вписанное человеком остаётся, — но и не
   рядовая подсказка: цветом отделяем «имей в виду» от «так и задумано». */
.field__hint--warn { color: var(--warn); }

.field__error {
  display: flex; align-items: center; gap: 5px;
  font-size: 12px; color: var(--danger);
}
.field__error svg { width: 13px; height: 13px; flex-shrink: 0; }

.input.is-invalid,
.select.is-invalid { border-color: var(--danger); }
.input.is-invalid:focus { box-shadow: 0 0 0 3px var(--danger-bg); }

.input[readonly] { background: var(--bg); color: var(--text-mut); }

textarea.input { height: auto; min-height: 88px; padding: 10px 12px; resize: vertical; line-height: 1.55; }

/* Поле с иконкой-префиксом слева */
.input-group { display: flex; }
.input-group__icon {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border: 1px solid var(--border-str);
  border-right: none;
  border-radius: var(--r-sm) 0 0 var(--r-sm);
  background: var(--bg);
  color: var(--text-soft);
  flex-shrink: 0;
}
.input-group__icon svg { width: 16px; height: 16px; }
.input-group .input,
.input-group .select { border-radius: 0 var(--r-sm) var(--r-sm) 0; }

/* Поле с подсказками (автодополнение) */
.combo { position: relative; }

.combo__list {
  position: absolute;
  z-index: 50;
  top: calc(100% + 4px);
  left: 0; right: 0;
  max-height: 280px;
  overflow-y: auto;
  padding: 5px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  box-shadow: 0 8px 28px -8px rgba(16, 21, 28, .22);
}

.combo__list[hidden] { display: none; }

.combo__item {
  display: block;
  width: 100%;
  padding: 7px 10px;
  border: none;
  background: none;
  border-radius: var(--r-sm);
  text-align: left;
  cursor: pointer;
}

.combo__item:hover,
.combo__item.is-active { background: var(--brand-50); }

.combo__name { font-size: 13.5px; font-weight: 550; }
.combo__meta { font-size: 12px; color: var(--text-soft); }
.combo__meta b { color: var(--brand-700); font-weight: 600; }   /* совпавшая часть */

.combo__empty { padding: 12px 10px; font-size: 13px; color: var(--text-soft); text-align: center; }

/* Переключатель из радиокнопок */
.segmented { display: inline-flex; gap: 4px; padding: 4px; background: var(--hover); border-radius: var(--r); }

.segmented__item { position: relative; }
.segmented__item input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }

.segmented__label {
  display: block;
  padding: 7px 18px;
  border-radius: var(--r-sm);
  font-size: 13.5px; font-weight: 550;
  color: var(--text-mut);
  cursor: pointer;
  transition: background .14s, color .14s, box-shadow .14s;
}

.segmented__item input:hover + .segmented__label { color: var(--text); }

.segmented__item input:checked + .segmented__label {
  background: var(--surface);
  color: var(--brand-700);
  box-shadow: var(--shadow-sm);
}

.segmented__item input:focus-visible + .segmented__label { box-shadow: 0 0 0 3px var(--brand-50); }

/* Теги выбранных значений в поле множественного выбора */
.chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 24px; padding: 0 6px 0 9px;
  border-radius: 99px;
  background: var(--brand-50);
  color: var(--brand-700);
  font-size: 12.5px; font-weight: 550;
}
.chip button { border: none; background: none; color: inherit; display: grid; place-items: center; padding: 0; opacity: .6; }
.chip button:hover { opacity: 1; }
.chip svg { width: 13px; height: 13px; }

/* Вложенная таблица внутри формы (адреса, товары) */
.subcard { border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }

.subcard__head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.subcard__title { font-weight: 620; font-size: 13.5px; }
.subcard__head .btn { margin-left: auto; }

.subcard .table th { padding: 8px 14px; }
.subcard .table td { padding: 9px 14px; }

.table__total td {
  background: var(--surface-2);
  font-weight: 620;
  border-top: 1px solid var(--border);
}

/* Липкая панель сохранения внизу формы */
.form-actions {
  position: sticky;
  bottom: 0;
  display: flex; align-items: center; gap: 10px;
  padding: 14px 18px;
  margin-top: 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: 0 -2px 16px -8px rgba(16, 21, 28, .18);
}
.form-actions__note { color: var(--text-soft); font-size: 12.5px; margin-right: auto; }

/* Универсальный сворачиваемый блок — та же техника, что у подменю сайдбара */
.collapse {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows .26s cubic-bezier(.4, 0, .2, 1), opacity .18s ease .06s;
}

.collapse > * { min-height: 0; overflow: hidden; }
.collapse.is-collapsed { grid-template-rows: 0fr; opacity: 0; }

/* ------------------------------------------------------- Модальное окно --- */

.modal {
  position: fixed; inset: 0;
  z-index: 80;
  display: grid; place-items: center;
  padding: 20px;
  background: rgba(16, 21, 28, .45);
  animation: mvs-fade .16s ease both;
}

.modal[hidden] { display: none; }

.modal__box {
  width: 100%; max-width: 640px;
  max-height: 90vh;
  display: flex; flex-direction: column;
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: 0 24px 60px -20px rgba(16, 21, 28, .4);
  animation: mvs-rise .2s cubic-bezier(.22, .8, .3, 1) both;
}

.modal__box--sm { max-width: 440px; }

/* Широкое окно — для тех, где список: доступ к разделам в 640 пикселях встаёт
   в две колонки и уезжает под прокрутку почти целиком. В 980 он виден сразу
   тремя-четырьмя колонками, и отмечать в нём можно, не листая. */
.modal__box--lg { max-width: 980px; }

/* Форма внутри окна — тоже колонка во всю его высоту.
   Иначе прокрутка не включается ни у кого: высоту ограничивает окно, а между
   ним и телом стоит форма, которая растёт под содержимое. Тело при этом ничем
   не сжато, `overflow` ему не на чем сработать, и длинный список вылезает
   из рамки вниз, унося кнопки за край экрана. */
.modal__box > form {
  display: flex; flex-direction: column;
  min-height: 0; flex: 1 1 auto;
}

.modal__head {
  display: flex; align-items: center; gap: 12px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;               /* шапку и подвал окна не сжимаем: жмётся тело */
}
.modal__title { font-weight: 640; font-size: 15.5px; }
.modal__close { margin-left: auto; }

/* Тело окна прокручивается внутри рамки.
   `min-height: 0` здесь обязателен: по умолчанию элемент во флексе не сжимается
   меньше своего содержимого, и длинный список (доступ к разделам — семь групп)
   вылезал из окна вниз, наезжая на подвал страницы. Кнопки при этом уезжали
   за край экрана. */
.modal__body { padding: 18px; overflow-y: auto; min-height: 0; flex: 1 1 auto; }
.modal__text { color: var(--text-mut); font-size: 14px; }

.modal__foot {
  display: flex; justify-content: flex-end; gap: 8px;
  padding: 14px 18px;
  border-top: 1px solid var(--border);
  flex-shrink: 0;               /* «Сохранить» всегда на виду, как бы ни было длинно тело */
}

/* --------------------------------------------------------------- Сетка --- */

.grid { display: grid; gap: 16px; }
.grid--kpi   { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid--split { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.grid--half  { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.mt-16 { margin-top: 16px; }
.mt-8  { margin-top: 8px; }

/* -------------------------------------------------------------- Карточка -- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.card__head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
}

.card__title { font-weight: 620; font-size: 14.5px; letter-spacing: -.01em; }
.card__sub   { font-size: 12.5px; color: var(--text-soft); margin-top: 1px; }
.card__tools { margin-left: auto; display: flex; align-items: center; gap: 6px; }
.card__body  { padding: 18px; }
.card__body--flush { padding: 0; }
/* Загрузка файла: поле и кнопка стоят в одну строку, подпись — под ними.
   Кнопка не тянется на всю колонку: .field выкладывает детей столбиком и
   растягивает их по ширине, а кнопка шириной со своё название читается
   как кнопка, а не как полоса. */
.upload { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.upload .input { flex: 1 1 320px; }
.upload .btn { flex: 0 0 auto; }

/* Системное поле файла показывает свою кнопку и надпись «файл не выбран».
   Прячем рамку у самого поля и приводим его кнопку к виду наших. */
.input[type="file"] { padding: 4px 8px; line-height: 24px; color: var(--text-mut); }

.input[type="file"]::file-selector-button {
  margin-right: 10px;
  height: 24px;
  padding: 0 10px;
  border: 1px solid var(--border-str);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}

.input[type="file"]::file-selector-button:hover { background: var(--hover); }

/* Перетаскивание файла. Вся область — это <label>, поэтому щелчок по ней
   открывает выбор файла без единой строчки скрипта: перетаскивание останется
   удобством, а не единственным способом. */
.dropzone {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 18px;
  margin-bottom: 12px;
  border: 1px dashed var(--border-str);
  border-radius: var(--r);
  background: var(--surface-2);
  cursor: pointer;
  transition: border-color .15s, background .15s;
}

.dropzone:hover { border-color: var(--brand-600); }

/* Файл над областью: подсвечиваем, иначе непонятно, отпускать здесь или нет */
.dropzone.is-over {
  border-color: var(--brand-600);
  border-style: solid;
  background: var(--brand-50);
}

.dropzone__icon { width: 22px; height: 22px; color: var(--text-soft); flex-shrink: 0; }
.dropzone__text { display: flex; flex-direction: column; gap: 2px; font-size: 13.5px; }
.dropzone__sub { color: var(--text-mut); font-size: 12.5px; }

.dropzone__name {
  margin-left: auto;
  padding: 4px 10px;
  border-radius: var(--r-sm);
  background: var(--brand-50);
  color: var(--brand-700);
  font-weight: 600;
  font-size: 13px;
}

/* Само поле не показываем — щелчок по области его и открывает */
.dropzone__input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

/* Кнопка, похожая на ссылку: «считать по размерам» внутри подсказки поля.
   Именно кнопка, а не ссылка: она ничего не открывает, а меняет поведение. */
.link {
  border: none; background: none; padding: 0;
  color: var(--brand-700); font: inherit; text-decoration: underline;
}
.link:hover { color: var(--brand-600); }

/* Величина с единицей: поле ввода и выбор единицы стоят вплотную, одним
   элементом — иначе взгляд читает их как два разных поля.

   Селекторы двойные — .measure .measure__unit, а не просто .measure__unit:
   базовые .input и .select описаны ниже по файлу, и при равной силе побеждали
   бы они. Скругление возвращалось на стык, и шов расходился. Тот же приём
   уже применён в .input-group выше. */
.measure { display: flex; }

.measure .measure__value {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  min-width: 0;
}

.measure .measure__unit {
  width: auto;
  min-width: 78px;
  margin-left: -1px;
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  background-color: var(--surface-2);
}

.measure .measure__value:focus + .measure__unit { border-left-color: var(--brand-600); }

/* Размеры идут тройкой: у средних полей скруглений нет вовсе */
.measure .measure__value + .measure__value { border-radius: 0; margin-left: -1px; }

/* Подсказка в шапке карточки: «отмечено 3 из 12» рядом с заголовком */
.card__hint { margin-left: auto; font-size: 13px; color: var(--text-mut); }

/* Карточка с ошибками формы: рамка цветом опасности, а не только текст —
   иначе сообщение теряется среди полей. */
.card--danger { border-color: var(--danger-brd); background: var(--danger-bg); }

/* Согласие — той же зеленью, что и кнопка согласия: цвет карточки говорит
   о решении раньше, чем прочитаны слова, и красным о согласии он врёт. */
.card--ok     { border-color: var(--ok-brd);     background: var(--ok-bg); }

/* Длинная строка без пробелов — пробы сканера в логине именно такие */
.u-break { word-break: break-all; }

.card__foot {
  padding: 12px 18px;
  border-top: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between;
  font-size: 13px; color: var(--text-mut);
}

/* Панель действий внизу карточки: слева печать и ход заявки, справа
   сохранение. Разделены не только положением, но и смыслом — слева то, что
   делают с готовой заявкой, справа то, чем правку заканчивают.
   На узком экране ряд переносится, а не выдавливает кнопки за край. */
.card__foot--actions { flex-wrap: wrap; gap: 10px; padding: 14px 18px; }

/* Расхождения между списком товаров и шапкой запроса: строк бывает несколько,
   и они должны читаться сверху вниз, а не выстраиваться в ряд. */
.card__foot--notes {
  display: block; color: var(--warn); background: var(--warn-bg);
}
.card__foot--notes .goods-note { display: block; }
.card__foot--notes .goods-note + .goods-note { margin-top: 4px; }
.card__foot-group { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }

/* Черта между печатью и действиями над заявкой: печать ничего не меняет,
   остальное меняет статус, и ставить их вплотную значит уравнять. */
.card__foot-sep { width: 1px; height: 24px; background: var(--border); margin: 0 4px; }

/* Карточка с цветной чертой сверху. Черта отмечает пару «погрузка —
   разгрузка»: в форме идут два одинаковых блока, и без метки взгляд теряет,
   где кончается один и начинается другой. */
.card--accent { border-top: 2px solid var(--ok); }

/* -------------------------------------------------------------- Вкладки --
   Карточка запроса и карточка заявки — не четыре страницы, а четыре части
   одной. Переключаются они адресом (?tab=…), поэтому это ссылки, а не кнопки:
   на вкладку можно дать ссылку, вернуться назад и открыть в новой вкладке
   браузера. Скрипту тут делать нечего. */

.tabs {
  display: flex;
  gap: 2px;
  padding: 0 8px;
  background: var(--surface-2);
  /* Рамка со всех сторон, а не только снизу: полоса вкладок и карточка под
     ней — одна фигура, и без боковых линий она разваливалась на две. */
  border: 1px solid var(--border);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  overflow-x: auto;
}

.tabs__item {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 13px 16px 11px;
  border-bottom: 2px solid transparent;
  color: var(--brand-700);
  font-size: 13.5px; font-weight: 550;
  white-space: nowrap;
}

.tabs__item:hover { color: var(--brand-600); background: var(--hover); }

.tabs__item.is-active {
  background: var(--surface);
  border-bottom-color: var(--brand-600);
  color: var(--text);
}

/* Число рядом с названием вкладки: сколько там документов или писем.
   Пустая вкладка тоже показывает ноль — «нет ничего» это ответ, ради
   которого не надо открывать. */
.tabs__count {
  min-width: 20px; padding: 0 6px;
  border-radius: 99px;
  background: var(--track);
  color: var(--text-mut);
  font-size: 11.5px; font-weight: 600; line-height: 18px;
  text-align: center;
}

.tabs__item.is-active .tabs__count { background: var(--brand-50); color: var(--brand-700); }

/* Вкладки прирастают к карточке снизу: между ними не должно быть шва */
/* Нижняя граница вкладок и верхняя граница карточки стояли бы вплотную
   и читались как одна жирная линия. Верхнюю у карточки снимаем —
   её роль играет нижняя у вкладок. */
.tabs + .card {
  border-top: 0;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

/* ------------------------------------------------------------------ KPI -- */

.kpi {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
  transition: box-shadow .15s, transform .15s;
}
.kpi:hover { box-shadow: var(--shadow); transform: translateY(-1px); }

.kpi__top { display: flex; align-items: center; gap: 10px; }

.kpi__icon {
  width: 34px; height: 34px;
  border-radius: 9px;
  display: grid; place-items: center;
  flex-shrink: 0;
}
.kpi__icon svg { width: 18px; height: 18px; }
.kpi__icon--brand  { background: var(--brand-50);  color: var(--brand-600); }
.kpi__icon--info   { background: var(--info-bg);   color: var(--info); }
.kpi__icon--warn   { background: var(--warn-bg);   color: var(--warn); }
.kpi__icon--violet { background: var(--violet-bg); color: var(--violet); }

.kpi__label { font-size: 12.5px; color: var(--text-mut); font-weight: 550; }

.kpi__value {
  font-size: 27px;
  font-weight: 680;
  letter-spacing: -.025em;
  line-height: 1.1;
}
.kpi__unit { font-size: 15px; font-weight: 550; color: var(--text-soft); margin-left: 2px; }

.kpi__foot { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-soft); }

.trend { display: inline-flex; align-items: center; gap: 3px; font-weight: 600; }
.trend svg { width: 13px; height: 13px; }
.trend--up   { color: var(--ok); }
.trend--down { color: var(--danger); }
.trend--flat { color: var(--text-soft); }

/* Тонкий прогресс-бар под KPI */
/* display: block обязателен — .meter используется и как <span> внутри ячеек таблицы,
   у строчного элемента height и width в процентах не работают. */
.meter {
  display: block;
  height: 5px;
  border-radius: 99px;
  background: var(--track);
  overflow: hidden;
}

.meter__fill {
  display: block;
  height: 100%;
  border-radius: 99px;
  background: var(--brand-500);
}

/* -------------------------------------------------------------- Графики -- */

.chart { width: 100%; height: auto; overflow: visible; }

.legend { display: flex; flex-wrap: wrap; gap: 14px; }
.legend__item { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--text-mut); }
.legend__dot { width: 9px; height: 9px; border-radius: 3px; flex-shrink: 0; }
.legend__val { margin-left: auto; font-weight: 620; color: var(--text); font-variant-numeric: tabular-nums; }

.donut-wrap { display: flex; align-items: center; gap: 20px; }
.donut { position: relative; flex-shrink: 0; }
.donut__center {
  position: absolute; inset: 0;
  display: grid; place-content: center; text-align: center;
}
.donut__value { font-size: 22px; font-weight: 680; letter-spacing: -.02em; }
.donut__label { font-size: 11.5px; color: var(--text-soft); }

.donut-legend { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 9px; }

/* -------------------------------------------------------------- Таблица -- */

.table-scroll { overflow-x: auto; }

/* Реестры: прокрутка внутри таблицы, а не страницы.
   Иначе sticky-шапка привязывается к скролл-контейнеру, который сам не прокручивается,
   и залипание либо не работает, либо шапка уходит под строки. */
.table-scroll--fixed {
  max-height: min(70vh, calc(100vh - 320px));
  overflow: auto;
  overscroll-behavior: contain;
}

/* border-collapse: separate обязателен: при collapse браузеры игнорируют z-index
   у sticky-ячеек, и строки прорисовываются поверх залипшей шапки. */
.table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13.5px;
}

.table th {
  text-align: left;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-soft);
  padding: 10px 18px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

.table td {
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr:hover { background: var(--surface-2); }

/* Строка с незаполненной карточкой: реквизитов нет, работать с ней нельзя.
   Цвет берётся токеном — в тёмной теме подсветка приглушается сама. */
.table tbody tr.is-flagged { background: var(--danger-bg); }
.table tbody tr.is-flagged:hover { background: var(--danger-bg); }

.table__num { font-variant-numeric: tabular-nums; }

/* Числа в колонке равняются по правому краю — и заголовок, и значения.
   Разъехавшиеся половины («КОЛ-ВО МЕСТ» справа, 12 слева) читаются как две
   разные колонки. Отдельным классом, а не в `.table__num`: тот же класс стоит
   в таблицах, где колонка левая, и молча их сдвинуть нельзя. */
.u-right { text-align: right; }
.table__id  { font-weight: 620; color: var(--brand-700); white-space: nowrap; }
.table__muted { color: var(--text-mut); }

.cell-stack { display: flex; flex-direction: column; }
.cell-stack__sub { font-size: 12px; color: var(--text-soft); }

/* ------------------------------------------------------ Панель фильтров -- */

.toolbar {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  flex-wrap: wrap;
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
}

.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field--grow { flex: 1 1 260px; }
.field--md   { flex: 0 1 240px; }

.field__label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-mut);
}

.select {
  height: 40px;
  padding: 0 32px 0 12px;
  font: inherit;
  font-size: 14px;
  border: 1px solid var(--border-str);
  border-radius: var(--r-sm);
  background: var(--surface) url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2366707d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 8px center;
  color: var(--text);
  appearance: none;
  outline: none;
  width: 100%;
  transition: border-color .12s, box-shadow .12s;
}
.select:focus { border-color: var(--brand-500); box-shadow: 0 0 0 3px var(--brand-50); }

.toolbar__actions { display: flex; gap: 8px; margin-left: auto; }

/* Две разные величины в одной строке — не диапазон, а пара.
   В отличие от .range здесь у каждого поля своя подпись: это не «с / по»,
   где косая черта соединяет два конца одной величины, а «мест» и «штук»,
   которые считают разное. Поэтому вместо разделителя — зазор пошире и
   отдельные label, иначе человек не знает, где что вводит. */
.field-pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 5px 14px;
}
.field-pair__item { display: flex; flex-direction: column; gap: 5px; min-width: 0; }

/* Диапазон дат «от — до»: два поля делят ширину, а не тянут по 100% каждое */
.range { display: flex; align-items: center; gap: 6px; }
.range .input { flex: 1 1 0; width: auto; min-width: 0; }
.range__dash { color: var(--text-soft); flex-shrink: 0; }

.field--lg { flex: 1 1 300px; }

/* Чекбокс */
.check {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 13.5px; color: var(--text-mut); cursor: pointer;
  padding-bottom: 7px;   /* выравнивание по нижнему краю полей в .toolbar */
}
.check input {
  width: 16px; height: 16px; margin: 0;
  accent-color: var(--brand-600);
  cursor: pointer;
}

/* Сортируемый заголовок */
.th-sort {
  display: inline-flex; align-items: center; gap: 5px;
  color: inherit; font: inherit; letter-spacing: inherit; text-transform: inherit;
  background: none; border: none; padding: 0; cursor: pointer;
}
.th-sort:hover { color: var(--text-mut); }
.th-sort__icon { width: 12px; height: 12px; opacity: .45; flex-shrink: 0; }
.th-sort.is-sorted { color: var(--brand-700); }
.th-sort.is-sorted .th-sort__icon { opacity: 1; }

/* Меню действий в строке таблицы */
.dropdown { position: relative; display: inline-flex; }

.dropdown__menu {
  position: fixed;              /* fixed, иначе меню обрежет прокручиваемый контейнер таблицы */
  z-index: 60;
  min-width: 200px;
  padding: 5px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  box-shadow: 0 8px 28px -8px rgba(16, 21, 28, .22), 0 2px 6px rgba(16, 21, 28, .06);
}

.dropdown__item {
  display: flex; align-items: center; gap: 9px;
  width: 100%; padding: 8px 10px;
  border: none; background: none;
  border-radius: var(--r-sm);
  color: var(--text); font: inherit; font-size: 13.5px; text-align: left;
  cursor: pointer;
}
.dropdown__item:hover { background: var(--hover); }
.dropdown__item svg { width: 15px; height: 15px; color: var(--text-soft); flex-shrink: 0; }
.dropdown__item--danger { color: var(--danger); }
.dropdown__item--danger:hover { background: var(--danger-bg); }
.dropdown__item--danger svg { color: var(--danger); }
.dropdown__sep { height: 1px; margin: 5px 0; background: var(--border); }

/* Оплата: сколько осталось и сколько уже внесено.
   Суммы идут столбиком — так колонка вдвое уже, а расшифровка живёт в title. */
.pay { display: flex; flex-direction: column; gap: 3px; align-items: flex-start; }
.pay__item {
  padding: 1px 6px;
  border: 1px solid;
  border-radius: var(--r-sm);
  font-size: 11.5px; font-weight: 600; line-height: 1.5;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pay__item small { font-weight: 500; opacity: .75; }
.pay__item--due  { color: var(--danger); border-color: var(--danger-brd); background: var(--danger-bg); }
.pay__item--paid { color: var(--ok);     border-color: var(--brand-200); background: var(--ok-bg); }

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

.steps { display: flex; flex-direction: column; gap: 5px; min-width: 116px; }

.steps__track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 3px;
}

.steps__seg {
  height: 5px;
  border-radius: 99px;
  background: var(--track);
}

.steps__seg.is-done { background: var(--brand-500); }

/* Остановленный запрос: докуда дошёл — видно, но это не достижение */
.steps__seg.is-stopped { background: var(--border-str); }

.steps__label {
  font-size: 11.5px;
  color: var(--text-soft);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.steps__label--stopped { color: var(--danger); }

.meter__fill--warn   { background: var(--warn-solid); }
.meter__fill--danger { background: var(--danger); }

/* ------------------------------------------------- Путь запроса (шаги) -----
   Порядок работы конторы, показанный полосой: цены → перевозчик → КП →
   подпись → согласие заказчика → заявка. Раньше его знали наизусть, а новый
   человек узнавал, промахнувшись мимо вкладки.

   Каждый шаг — ссылка на свою вкладку, поэтому полоса заодно и меню.
   Цвета ровно три: зелёный — пройдено, тёмный — здесь сейчас, серый — впереди.
   Красный только у остановки, и он означает «дальше не пойдёт», а не «плохо».

   Прирастает к вкладкам снизу — между полосой и вкладками шва быть не должно. */

.flow {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-bottom: 0;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}

/* Шаги переносятся на вторую строку, а не уезжают за край.

   Раньше полоса прокручивалась вбок, и на обычном мониторе последние шаги
   оказывались за границей: человек видел «Заявка зав…» и полосу прокрутки
   под ней. Путь запроса — то, что читают целиком, одним взглядом; ради него
   не листают. Две строки на узком экране честнее одной обрезанной. */
.flow__list {
  display: flex; align-items: center; flex-wrap: wrap; gap: 2px 2px;
  flex: 1; min-width: 0;
  margin: 0; padding: 0; list-style: none;
}

/* Разделитель между шагами рисуется псевдоэлементом, а не отдельным узлом:
   в разметке он ничего не значит и с клавиатуры на него не попасть. */
.flow__step + .flow__step::before {
  content: ""; display: block;
  width: 14px; height: 1px; flex-shrink: 0;
  background: var(--border-str);
}

/* На узком экране черта между шагами не нужна: она соединяла бы конец одной
   строки с началом другой, будто путь идёт справа налево. */
@media (max-width: 1500px) {
  .flow__step + .flow__step::before { width: 8px; }
}

@media (max-width: 1100px) {
  .flow { align-items: flex-start; }
  .flow__step + .flow__step::before { display: none; }
  .flow__link { padding: 4px 7px; }
}

.flow__step { display: flex; align-items: center; min-width: 0; }

.flow__link {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 9px;
  border-radius: var(--r-sm);
  color: var(--text-soft);
  white-space: nowrap;
}

.flow__link:hover { background: var(--hover); }

.flow__mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; flex-shrink: 0;
  border-radius: 99px;
  background: var(--track);
  color: var(--text-mut);
  font-size: 11px; font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.flow__mark svg { width: 12px; height: 12px; }

.flow__text { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.flow__label { font-size: 12.5px; font-weight: 550; }

/* Что именно случилось на пройденном шаге: имя перевозчика, число
   предложений, номер заявки. Без этого полоса говорит «сделано»,
   но не говорит «что». */
.flow__note {
  font-size: 11px; color: var(--text-soft);
  overflow: hidden; text-overflow: ellipsis; max-width: 150px;
}

.flow__step--done .flow__mark  { background: var(--brand-50); color: var(--brand-700); }
.flow__step--done .flow__label { color: var(--brand-700); }

.flow__step--current .flow__mark  { background: var(--brand-600); color: #fff; }
.flow__step--current .flow__label { color: var(--text); font-weight: 650; }

/* Перешагнули: дальше по пути сделано, а здесь пусто. Не достижение
   и не «предстоит» — своим цветом, чтобы не путать ни с тем, ни с другим. */
.flow__step--skipped .flow__mark  { background: var(--track); color: var(--text-soft); }
.flow__step--skipped .flow__label { color: var(--text-soft); text-decoration: line-through; }

.flow__step--stopped .flow__mark  { background: var(--danger-bg); color: var(--danger); }
.flow__step--stopped .flow__label { color: var(--danger); }
.flow__step--stopped .flow__note  { color: var(--danger); }

.flow__count {
  flex-shrink: 0;
  font-size: 11.5px; color: var(--text-soft);
  font-variant-numeric: tabular-nums;
}

.flow__count--stopped { color: var(--danger); font-weight: 600; }

.flow + .tabs { border-top-left-radius: 0; border-top-right-radius: 0; }

/* Узкий экран: подписи прячем, остаются кружки — по ним видно, сколько
   пройдено и где стоим, а название текущего шага и так в заголовке. */
@media (max-width: 720px) {
  .flow__text  { display: none; }
  .flow__count { display: none; }
  .flow__step + .flow__step::before { width: 8px; }
}
/* -------------------------------------------------- Появление после выбора --
   Блок с данными выбранной записи справочника. Скрыт, пока не выбрали:
   пустые поля с прочерками обещают ввод, которого не ждут.

   Движение короткое и небольшое — оно отвечает на вопрос «откуда это
   взялось», а не развлекает. Кому оно мешает, тот его не увидит. */

.reveal {
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity .18s ease, transform .18s ease;
}

.reveal.is-shown { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { transition: none; }
}
/* Несохранённые изменения ---------------------------------------------------
   Кнопка сохранения загорается оранжевым, как только в форме что-то тронули.
   Зелёная кнопка выглядит одинаково и до правки, и после: человек уходит
   со страницы, будучи уверен, что всё записано, — а записано не было.

   Оранжевый, а не красный: это не ошибка, а незаконченное дело. Возвращается
   в зелёный при отправке. */

.btn--primary.is-dirty {
  background: var(--warn-solid);
  border-color: var(--warn-solid);
}

.btn--primary.is-dirty:hover {
  background: var(--warn);
  border-color: var(--warn);
}

/* Подпись рядом с кнопкой: цвет говорит «что-то не так», а слово — что именно.
   Одного цвета мало тому, кто его не различает. */
.dirty-note {
  display: none;
  align-items: center;
  gap: 6px;
  margin-right: 10px;
  color: var(--warn);
  font-size: 12.5px;
  font-weight: 550;
}

.dirty-note.is-shown { display: inline-flex; }
/* --------------------------------------------- Согласованные условия -------
   Полоса над заявкой перевозчику: что он назвал и на что мы согласились.
   Не таблица — строк три-шесть, и заголовки в них длиннее значений; парами
   «подпись — значение» читается быстрее, чем шапка и строка под ней. */

.agreed {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}

.agreed__head { display: flex; align-items: center; gap: 10px; }

.agreed__title { font-size: 13.5px; font-weight: 650; color: var(--text); }

.agreed__who { font-size: 13px; color: var(--text-mut); }

.agreed__terms {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 22px;
  margin: 2px 0 0;
}

.agreed__terms > div { display: flex; align-items: baseline; gap: 6px; min-width: 0; }

.agreed__terms dt { font-size: 12px; color: var(--text-soft); }

.agreed__terms dd {
  margin: 0;
  font-size: 13px; font-weight: 600; color: var(--text);
  font-variant-numeric: tabular-nums;
}

.agreed__foot { font-size: 11.5px; color: var(--text-soft); }
/* ------------------------------------------- Штамп электронной подписи -----
   Повторяет оттиск с бумажной заявки: рамка, заглавная строка, дата и тот,
   кто подписал. Похожесть тут не украшение — человек сверяет распечатку
   с экраном, и одинаковый вид избавляет его от вопроса, одно ли это и то же.

   Синий, а не зелёный: зелёным в системе помечено пройденное, а подпись —
   не этап, а документ. Тот же синий стоит и на настоящем оттиске. */

/* Штамп электронной подписи. Имя своё, не `.stamp`: так называется ячейка
   «дата + автор» в реестрах, и рамка штампа обводила её на каждой строке. */
.esign {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 12px;
  border: 1px solid var(--stamp);
  border-radius: 3px;
  color: var(--stamp);
  background: transparent;
  max-width: 100%;
}

.esign__title {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  line-height: 1.3;
}

.esign__line {
  font-size: 11.5px;
  line-height: 1.35;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* В шапке карточки штамп стоит справа — тем же приёмом, что .card__tools
   и .card__hint: слева заголовок, справа то, что к нему относится. */
.card__head > .esign { margin-left: auto; }

/* На узком экране штамп не жмётся в столбик из обрезков — переносим строки */
@media (max-width: 720px) {
  .esign { width: 100%; }
  .esign__line { white-space: normal; }
}
/* Пустое состояние вместо голой строки «ничего не найдено» */
.empty { padding: 56px 24px; text-align: center; }
.empty__icon {
  width: 52px; height: 52px; margin: 0 auto 14px;
  border-radius: 14px;
  background: var(--hover); color: var(--text-soft);
  display: grid; place-items: center;
}
.empty__icon svg { width: 24px; height: 24px; }
.empty__title { font-weight: 620; font-size: 15px; margin-bottom: 4px; }
.empty__text { color: var(--text-mut); font-size: 13.5px; max-width: 380px; margin: 0 auto 16px; }

/* ------------------------------------------------- Таблица: доп. режимы -- */

/* Шапка липнет под топбаром при длинных реестрах */
.table--sticky thead th {
  position: sticky;
  top: 0;                                         /* относительно .table-scroll--fixed */
  z-index: 10;
  background: var(--surface-2);                            /* непрозрачный фон обязателен */
  box-shadow: inset 0 -1px 0 var(--border);       /* линия под шапкой не «уезжает» при скролле */
}

/* Плотный режим для широких реестров: узкие отступы, чтобы влезали все колонки */
.table--dense th { padding: 9px 11px; }
.table--dense td { padding: 8px 11px; font-size: 13px; }
.table--dense .badge { height: 20px; padding: 0 7px; font-size: 11.5px; }
.table--dense .btn--sm { height: 28px; padding: 0 10px; font-size: 12.5px; }

/* На ноутбучном экране таблицы поджимаются: отступы в ячейках съедают
   по два-три сантиметра на строку, и из-за них вбок уезжает то, что иначе
   поместилось бы. Сама прокрутка остаётся — реестр в полтора десятка колонок
   не влезет никуда, — но пользоваться ею приходится реже. */
@media (max-width: 1500px) {
  .table th { padding-left: 9px; padding-right: 9px; }
  .table td { padding-left: 9px; padding-right: 9px; }
  .table--dense th { padding: 8px 8px; }
  .table--dense td { padding: 7px 8px; }
}

@media (max-width: 1200px) {
  .table--dense th { padding: 7px 6px; font-size: 10.5px; }
  .table--dense td { padding: 6px 6px; font-size: 12.5px; }
}

/* Широкие реестры: колонка действий закреплена справа и не уезжает при прокрутке.
   Работает только при border-collapse: separate — см. правило .table выше. */
.table--pin-actions th:last-child,
.table--pin-actions td:last-child {
  position: sticky;
  right: 0;
  z-index: 5;
  background: var(--surface);
  border-left: 1px solid var(--border);
}

.table--pin-actions thead th:last-child {
  z-index: 12;                       /* выше залипшей шапки, иначе перекроется */
  background: var(--surface-2);
}

/* Фон закреплённой ячейки должен повторять подсветку строки */
.table--pin-actions tbody tr:hover td:last-child { background: var(--surface-2); }

/* Тень появляется, только если таблица реально прокручена вбок */
.table-scroll--fixed.is-scrolled .table--pin-actions th:last-child,
.table-scroll--fixed.is-scrolled .table--pin-actions td:last-child {
  box-shadow: -10px 0 10px -10px rgba(16, 21, 28, .28);
}

/* Кнопки в строке не переносятся по словам: «На согласование» в две строки
   растит строку вдвое и сбивает выравнивание всей таблицы. Тесно — таблица
   прокрутится вбок, это честнее. */
.table__actions { display: flex; gap: 3px; justify-content: flex-end; }
.table__actions .btn { white-space: nowrap; }

.act {
  width: 28px; height: 28px;
  display: grid; place-items: center;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-soft);
  transition: background .12s, color .12s;
}
.act svg { width: 15px; height: 15px; }
.act:hover { background: var(--hover); color: var(--text); }
.act--danger:hover { background: var(--danger-bg); color: var(--danger); }
.act--ok:hover     { background: var(--ok-bg);     color: var(--ok); }

/* Число с единицей измерения: единица не должна спорить с цифрой */
.qty { white-space: nowrap; font-variant-numeric: tabular-nums; }
.qty__unit { color: var(--text-soft); font-weight: 500; font-size: 12.5px; }

/* Ячейка «дата + автор» */
.stamp { display: flex; flex-direction: column; }
.stamp__date { font-variant-numeric: tabular-nums; }
.stamp__by { font-size: 12px; color: var(--text-soft); display: flex; align-items: center; gap: 4px; }
.stamp__by svg { width: 12px; height: 12px; }

/* Да / Нет */
.flag { display: inline-flex; align-items: center; gap: 5px; font-weight: 550; }
.flag svg { width: 15px; height: 15px; }
.flag--yes { color: var(--ok); }
.flag--no  { color: var(--text-soft); }

/* ---------------------------------------------------------- Пагинация ---- */

.pager {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 18px;
  border-top: 1px solid var(--border);
  font-size: 13px; color: var(--text-mut);
}

.pager__pages { display: flex; gap: 4px; margin-left: auto; }

.pager__size { display: flex; align-items: center; gap: 7px; color: var(--text-mut); }
.select--sm { height: 28px; width: auto; padding: 0 26px 0 8px; font-size: 13px; }

.pager__btn {
  min-width: 30px; height: 30px; padding: 0 8px;
  display: grid; place-items: center;
  border: 1px solid var(--border-str);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text-mut);
  font-size: 13px; font-weight: 550;
  font-variant-numeric: tabular-nums;
}
.pager__btn:hover { background: var(--bg); color: var(--text); }
.pager__btn.is-current {
  background: var(--brand-600); border-color: var(--brand-600); color: var(--on-brand);
}
.pager__btn:disabled { opacity: .45; cursor: default; background: var(--surface); }
.pager__btn svg { width: 15px; height: 15px; }
.pager__gap { display: grid; place-items: center; min-width: 20px; color: var(--text-soft); }

/* --------------------------------------------------------------- Бейджи -- */

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  height: 22px; padding: 0 8px;
  border-radius: 99px;
  font-size: 12px; font-weight: 600;
  white-space: nowrap;
}
.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

.badge--new    { background: var(--info-bg);   color: var(--info); }
.badge--work   { background: var(--warn-bg);   color: var(--warn); }
.badge--done   { background: var(--ok-bg);     color: var(--ok); }
.badge--cancel { background: var(--danger-bg); color: var(--danger); }
.badge--draft  { background: var(--hover);          color: var(--text-mut); }
.badge--violet { background: var(--violet-bg);  color: var(--violet); }
.badge--teal   { background: var(--teal-bg);           color: var(--teal); }

.count {
  display: inline-grid; place-items: center;
  min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: 99px;
  background: var(--track); color: var(--text-mut);
  font-size: 11.5px; font-weight: 650;
}
.count--danger { background: var(--danger-bg); color: var(--danger); }
.count--brand  { background: var(--brand-50);  color: var(--brand-700); }

/* --------------------------------------------------------------- Списки -- */

.feed { display: flex; flex-direction: column; }

.feed__item {
  display: flex; gap: 12px;
  padding: 13px 18px;
  border-bottom: 1px solid var(--border);
}
.feed__item:last-child { border-bottom: none; }

.feed__dot {
  width: 30px; height: 30px; border-radius: 8px;
  display: grid; place-items: center; flex-shrink: 0;
}
.feed__dot svg { width: 15px; height: 15px; }

.feed__text { font-size: 13.5px; min-width: 0; }
.feed__time { font-size: 12px; color: var(--text-soft); margin-top: 2px; }

.rank { display: flex; flex-direction: column; }
.rank__item { display: flex; align-items: center; gap: 12px; padding: 11px 18px; border-bottom: 1px solid var(--border); }
.rank__item:last-child { border-bottom: none; }
.rank__pos {
  width: 22px; height: 22px; border-radius: 6px;
  background: var(--hover); color: var(--text-mut);
  display: grid; place-items: center;
  font-size: 11.5px; font-weight: 650; flex-shrink: 0;
}
.rank__pos--top { background: var(--brand-50); color: var(--brand-700); }
.rank__name { flex: 1; min-width: 0; font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rank__bar { width: 90px; height: 5px; border-radius: 99px; background: var(--track); overflow: hidden; flex-shrink: 0; }
.rank__bar span { display: block; height: 100%; background: var(--brand-500); border-radius: 99px; }
.rank__val { width: 42px; text-align: right; font-variant-numeric: tabular-nums; font-weight: 620; font-size: 13px; }

/* -------------------------------------------------------- Быстрые ссылки -- */

.quick { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }

.quick__item {
  display: flex; align-items: center; gap: 10px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--r);
  transition: border-color .12s, background .12s;
}
.quick__item:hover { border-color: var(--brand-200); background: var(--brand-50); }
.quick__icon {
  width: 30px; height: 30px; border-radius: 8px;
  background: var(--hover); color: var(--text-mut);
  display: grid; place-items: center; flex-shrink: 0;
}
.quick__item:hover .quick__icon { background: var(--brand-100); color: var(--brand-700); }
.quick__icon svg { width: 16px; height: 16px; }
.quick__label { font-weight: 550; font-size: 13px; }
.quick__sub { font-size: 11.5px; color: var(--text-soft); }

/* --------------------------------------------------------------- Футер --- */

.footer {
  border-top: 1px solid var(--border);
  background: var(--surface);
  padding: 14px 0;
  font-size: 12.5px; color: var(--text-soft);
}

.footer__inner { padding: 0 28px; justify-content: space-between; }

/* -------------------------------------------------------------- Утилиты -- */

.u-empty { padding: 40px 18px; text-align: center; color: var(--text-soft); font-size: 13.5px; }
.u-nowrap { white-space: nowrap; }

.scrim {
  position: fixed; inset: 0;
  background: rgba(16, 21, 28, .4);
  z-index: 35;
  display: none;
}

/* ------------------------------------------------------------ Адаптив ---- */

@media (max-width: 1280px) {
  .grid--kpi { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 1080px) {
  .grid--split, .grid--half { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 860px) {
  .sidebar { transform: translateX(-100%); }
  .main { margin-left: 0; }
  body.is-open .sidebar { transform: translateX(0); }
  body.is-open .scrim { display: block; }
  .content { padding: 18px 16px 32px; }
  .topbar__inner, .footer__inner { padding: 0 14px; }
  .grid--kpi { grid-template-columns: minmax(0, 1fr); }
  .quick { grid-template-columns: minmax(0, 1fr); }
  .toolbar { padding: 14px; }
  .field, .field--grow, .field--md { flex: 1 1 100%; }
  .toolbar__actions { margin-left: 0; width: 100%; }
  .toolbar__actions .btn { flex: 1; justify-content: center; }
  .pager__pages { margin-left: 0; }
  .donut-wrap { flex-direction: column; align-items: stretch; }
  .donut { align-self: center; }
  .footer__inner { flex-direction: column; gap: 6px; text-align: center; }
}

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

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

   Пустые ячейки исчезают: «Прицеп —» ничего не сообщает, а место занимает. */

@media (max-width: 700px) {
  .table-scroll--cards { overflow: visible; }

  .table--cards thead { display: none; }

  .table--cards,
  .table--cards tbody,
  .table--cards tr,
  .table--cards td { display: block; width: 100%; }

  .table--cards tr {
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface);
    margin: 0 0 10px;
    padding: 4px 0;
  }

  .table--cards td {
    border: 0;
    display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
    padding: 8px 14px;
    text-align: right;
  }

  .table--cards td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    color: var(--text-soft);
    font-size: 12.5px;
    text-align: left;
  }

  /* Ячейка без подписи — заголовок карточки: номер рейса, наименование груза */
  .table--cards td:not([data-label]) {
    justify-content: flex-start;
    text-align: left;
    font-size: 15px;
    padding-bottom: 4px;
  }

  .table--cards td:empty { display: none; }

  /* Кнопки в карточке — во всю ширину и под палец, а не под курсор */
  .table--cards .table__actions { width: 100%; justify-content: stretch; gap: 8px; }
  .table--cards .table__actions .btn,
  .table--cards .table__actions form { flex: 1; }
  .table--cards .table__actions .btn { height: 42px; justify-content: center; width: 100%; }

  .table--cards .u-empty { text-align: center; }

  /* Итоговая строка остаётся строкой: это сумма, а не ещё одна карточка */
  .table--cards tfoot tr { background: var(--bg); }
}

/* Окно на телефоне — во весь экран. В 20 пикселях полей от края окно с тремя
   полями выглядит случайно приоткрытым ящиком, а клавиатура съедает половину
   того, что осталось. */

@media (max-width: 700px) {
  .modal { padding: 0; }

  .modal__box {
    max-width: none;
    width: 100%; height: 100%; max-height: 100%;
    border-radius: 0;
  }

  .modal__foot { padding-bottom: max(14px, env(safe-area-inset-bottom)); }
  .modal__foot .btn { flex: 1; justify-content: center; height: 44px; }
}


/* ------------------------------------------------------- Индикатор загрузки --
   Тонкая полоса поверх интерфейса: показывает, что переход или запрос идёт.
   Живёт на текущей странице, поэтому закрывает именно ожидание ответа. */

.load-bar {
  position: fixed;
  top: 0; left: 0;
  height: 3px;
  width: 0;
  z-index: 100;
  background: linear-gradient(90deg, var(--brand-600), var(--brand-500));
  box-shadow: 0 0 10px rgba(5, 150, 105, .6);
  opacity: 0;
  transition: width .25s ease, opacity .25s ease;
  pointer-events: none;
}

.load-bar.is-active { opacity: 1; }

/* ------------------------------------------------------------- Скелетоны ----
   Заглушки на месте данных, пока идёт запрос. Форма повторяет реальную строку,
   поэтому при подстановке данных таблица не прыгает. */

@keyframes mvs-shimmer {
  from { background-position: 100% 0; }
  to   { background-position: -100% 0; }
}

.skeleton {
  display: block;
  height: 11px;
  border-radius: 4px;
  background: linear-gradient(90deg, var(--track) 25%, var(--surface-2) 45%, var(--track) 65%);
  background-size: 200% 100%;
  animation: mvs-shimmer 1.3s linear infinite;
}

.skeleton + .skeleton { margin-top: 6px; }
.skeleton--sub { height: 9px; opacity: .7; }
.skeleton--badge { height: 20px; width: 84px; border-radius: 99px; }
.skeleton--btn { height: 26px; width: 86px; border-radius: var(--r-sm); }

/* Пока грузится — содержимое таблицы не кликается */
.is-loading { pointer-events: none; }

/* ------------------------------------------------------ Появление контента --
   Классы навешивает JS: без него страница просто видна сразу,
   поэтому при отключённом скрипте ничего не пропадает. */

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

@keyframes mvs-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes mvs-grow {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.mvs-rise {
  animation: mvs-rise .5s cubic-bezier(.22, .8, .3, 1) both;
  animation-delay: var(--d, 0s);
}

.mvs-fade {
  animation: mvs-fade .4s ease both;
  animation-delay: var(--d, 0s);
}

/* Полосы прогресса и рейтингов вырастают из нуля */
.mvs-grow {
  transform-origin: left center;
  animation: mvs-grow .7s cubic-bezier(.22, .8, .3, 1) both;
  animation-delay: var(--d, 0s);
}

/* Линии графика прочерчиваются: длину подставляет JS в --len */
.mvs-draw {
  stroke-dasharray: var(--len);
  stroke-dashoffset: var(--len);
  animation: mvs-draw .9s cubic-bezier(.4, 0, .2, 1) forwards;
  animation-delay: var(--d, 0s);
}

@keyframes mvs-draw {
  to { stroke-dashoffset: 0; }
}

/* ------------------------------------------- Автообновление реестра ------
   Полоска появляется только когда обновление не дошло: данные на экране
   в этот момент устаревшие, и человек должен об этом знать. */

.live-error {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 -1px;
  padding: 10px 16px;
  border-top: 1px solid var(--danger-brd);
  border-bottom: 1px solid var(--danger-brd);
  background: var(--danger-bg);
  color: var(--danger);
  font-size: 13px;
}

.live-error[hidden] { display: none; }
.live-error svg { flex: none; fill: none; stroke: currentColor; stroke-width: 2; }
.live-error span { flex: 1; }
.live-error .btn { border-color: var(--danger-brd); color: var(--danger); background: var(--surface); }

/* ------------------------------------------------- График и «бублик» ------
   Цвета линий и сетки берутся из токенов, а не из атрибутов SVG: иначе
   в тёмной теме сетка светится, а точки на линии остаются белыми. */

.chart__grid { stroke: var(--track); }
.chart__axis { fill: var(--text-soft); }
.chart__grad { stop-color: var(--brand-600); }
.chart__line--created { stroke: var(--brand-600); }
.chart__line--done    { stroke: var(--chart-line); }
.chart__dot { fill: var(--surface); stroke: var(--brand-600); }
.donut__track { stroke: var(--track); }

/* Отметка времени последнего обновления в шапке реестра */
.page-head__sub [data-live-stamp] { font-variant-numeric: tabular-nums; }

/* Блок или бейдж, который только что обновился сам: без этого цифры
   меняются незаметно, и человек не понимает, что данные другие. */
.is-fresh { animation: mvs-fresh 1.1s ease-out; }

@keyframes mvs-fresh {
  0%   { background-color: var(--ok-bg); }
  100% { background-color: transparent; }
}

/* Кнопки смены статуса в строке таблицы */
.row-actions { display: inline-flex; gap: 6px; justify-content: flex-end; }
.row-actions:empty::after { content: '—'; color: var(--text-mut); }

.btn--danger {
  background: var(--danger);
  border-color: var(--danger);
  color: var(--on-brand);
}

/* Фон повторяется намеренно: у .btn:hover специфичность выше, чем у
   .btn--danger, и без него красная кнопка под курсором белеет вместе
   с белым текстом. */
.btn--danger:hover {
  background: var(--danger);
  border-color: var(--danger);
  filter: brightness(.94);
}

/* Шаг назад: вернуть заявку на доработку. Не красная — ничего не теряется,
   но и не обычная: это движение против хода, и стоять вровень с «Отправить»
   она не должна. Фон в :hover повторён по той же причине, что и у красной. */
.btn--warn {
  background: var(--warn-solid);
  border-color: var(--warn-solid);
  color: #3d2b00;
}

.btn--warn:hover {
  background: var(--warn-solid);
  border-color: var(--warn-solid);
  filter: brightness(.94);
}

/* Группа действий в выпадающем меню строки */
.dropdown__group { display: flex; flex-direction: column; }

/* Короткое сообщение о результате действия */
.toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  z-index: 90;
  max-width: min(420px, calc(100vw - 32px));
  padding: 11px 18px;
  border-radius: 10px;
  background: var(--toast-bg);
  color: var(--toast-fg);
  font-size: 13.5px;
  box-shadow: 0 10px 30px rgba(16, 24, 40, .22);
  opacity: 0;
  transform: translate(-50%, 12px);
  transition: opacity .18s, transform .18s;
  pointer-events: none;
}

.toast.is-visible { opacity: 1; transform: translate(-50%, 0); }
.toast--error { background: var(--danger); color: var(--on-brand); }

/* ------------------------------------------------------------------ Вход --- */

/* Единственный экран без меню и шапки: пока не вошли, идти по ним некуда.
   Карточка узкая и по центру — на ней ровно два поля, растягивать нечего. */
.auth {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--bg);
}

.auth__box {
  width: 100%;
  max-width: 380px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
  padding: 28px;
}

.auth__brand { display: flex; align-items: center; gap: 11px; margin-bottom: 22px; }
.auth__title { display: block; font-weight: 650; font-size: 16px; letter-spacing: -.01em; }
.auth__sub   { display: block; font-size: 12px; color: var(--text-soft); }

.auth__form { display: flex; flex-direction: column; gap: 14px; }
.auth__submit { justify-content: center; height: 38px; }

.auth__error {
  display: flex; align-items: center; gap: 7px;
  font-size: 13px; color: var(--danger);
  background: var(--danger-bg);
  border: 1px solid var(--danger-brd);
  border-radius: var(--r-sm);
  padding: 9px 11px;
}

.auth__note {
  margin-top: 18px;
  font-size: 12px; line-height: 1.5; color: var(--text-soft);
  border-top: 1px solid var(--border);
  padding-top: 14px;
}

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

@media print {
  .sidebar, .topbar, .page-head__actions, .card__tools { display: none !important; }
  .main { margin-left: 0; }
  .card, .kpi { box-shadow: none; break-inside: avoid; }
}
