/* Стили пользовательской части Vectra.

   Оформление — по дизайну Vectra из Figma Make (пакет handoff —
   docs/design/): светлый интерфейс, тёмно-синий текст, холодный
   серо-голубой фон, синий — основные действия и выбор, бирюзовый — ИИ.
   Классы в шаблонах смысловые (.btn-primary, .card, .pill), а вид задан
   здесь, через переменные в :root: смена оформления — правка этого файла,
   а не шаблонов. Утилитарных классов нет — сборки у контура нет.

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

/* ---------- шрифт Manrope ----------

   Шрифт дизайна. Файлы лежат в проекте (public/fonts/manrope/), а не
   подключены с fonts.googleapis.com, как в прототипе: страница не должна
   зависеть от того, ответит ли сторонний CDN. Переменный шрифт — один
   файл на подборку символов со всем диапазоном начертаний (200–800);
   подборки — латиница и кириллица, как их разбивает сама выдача Google
   Fonts, и браузер грузит только тот файл, символы которого встретились
   на странице. Файлы — из пакета @fontsource-variable/manrope, лицензия
   SIL OFL 1.1 (OFL.txt рядом). */
@font-face {
    font-family: 'Manrope';
    font-style: normal;
    font-weight: 200 800;
    font-display: swap;
    src: url('/fonts/manrope/manrope-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Manrope';
    font-style: normal;
    font-weight: 200 800;
    font-display: swap;
    src: url('/fonts/manrope/manrope-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: 'Manrope';
    font-style: normal;
    font-weight: 200 800;
    font-display: swap;
    src: url('/fonts/manrope/manrope-cyrillic.woff2') format('woff2');
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
    font-family: 'Manrope';
    font-style: normal;
    font-weight: 200 800;
    font-display: swap;
    src: url('/fonts/manrope/manrope-cyrillic-ext.woff2') format('woff2');
    unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

/* ---------- палитра и величины ----------

   Токены дизайна (02-design-system.md пакета) под прежними именами
   переменных: шаблоны и правила ниже ссылаются на имена, а не на цвета,
   поэтому новая палитра легла без правки каждого правила.

   Цвета — только через эти переменные: HEX в правилах ниже и в
   шаблонах не повторяется. У текста свои переменные (*-text): цветной
   текст есть у ссылок, меток и сообщений, а основной — --text. */
:root{
  /* Фон приложения (canvas) и поверхности. */
  --bg:#f5f7fb;
  --surface:#ffffff;
  --surface-2:#f0f3f9;
  /* Строка таблицы под курсором — темнее --surface-2, которой залита
     каждая вторая строка (.table-striped). */
  --row-hover:#e6ecf6;
  /* Подложка вкладок-сегментов. */
  --tab-track:#e9edf5;
  /* Затенение ячейки, которую нельзя править (.cell-locked), — поверх
     заливки строки. */
  --cell-locked-shade:rgba(11,23,57,.06);
  --border:#dce3ee;
  --border-strong:#c8d2e2;
  /* Рамка карточки под курсором. */
  --border-hover:#bdcbe2;
  /* Текст: основной (ink), вторичный (ink-soft) и подписи (muted). */
  --text:#0b1739;
  --text-muted:#5e6b84;
  --text-faint:#8792a8;
  /* Основной цвет действий и выбора. */
  --accent:#2455d6;
  --accent-strong:#1d45b5;
  --accent-wash:#eef2ff;
  --accent-line:#c9d6f7;
  --accent-text:#2455d6;
  --accent-strong-text:#1d45b5;
  /* Состояния: фон, рамка и текст метки. */
  --warn:#975414;
  --warn-wash:#fff5e6;
  --warn-line:#ecd2a8;
  --warn-text:#975414;
  --danger:#b53749;
  --danger-wash:#fff0f2;
  /* Рамка кнопки удаления — светлее самого цвета: кнопка не кричит. */
  --danger-line:#e7c2c8;
  --danger-text:#b53749;
  --success:#197052;
  --success-wash:#eaf7f1;
  --success-line:#bde4d4;
  /* Спокойный срок подачи — бирюзово-зелёный, мягче «успеха». */
  --calm-wash:#edf6f4;
  /* Шаги маршрута «Тендеры» в боковой панели (А–Г): цвет буквы и
     заливка кружка и текущего пункта — по прототипу. Синий шаг — акцент. */
  --route-blue-wash:#eef3ff;
  --route-cyan:#0b9da9;
  --route-cyan-wash:#eafafb;
  --route-violet:#7457d9;
  --route-violet-wash:#f1edff;
  --route-green:#16835b;
  --route-green-wash:#eaf8f1;
  --route-line:#dce4f1;
  --nav-count-bg:#edf1f7;
  --calm-text:#287166;
  --success-text:#197052;
  /* ИИ — бирюзовый, отдельный от основного синего. */
  --ai:#12b8c4;
  --ai-wash:#eaf9fa;
  --ai-text:#0d7f88;
  /* Затемнение под окном и панелью. */
  --scrim:rgba(5,12,30,.32);
  /* Обводка фокуса — 20% основного цвета. */
  --focus-ring:rgba(36,85,214,.2);
  /* Мягкая синеватая тень — без тяжёлого чёрного контура. */
  --shadow:0 6px 20px rgba(11,23,57,.05);
  --shadow-lg:-22px 0 60px rgba(11,23,57,.18);
  /* Общие величины:
     --radius-sm — всё, что нажимают и во что вводят, и сообщения;
     --radius — всё, что держит содержимое (панели, карточки, окна);
     --control-h — высота поля и кнопки: в строке отбора они рядом;
     --sidebar-w — ширина боковой панели. */
  --radius-sm:9px;
  --radius:14px;
  --control-h:40px;
  --cell-lines: 8;
  --sidebar-w:246px;
  /* Типографика — по коду прототипа (docs/design/handoff/source/
     styles.reference.css): каждый элемент берёт размер своего аналога в
     прототипе один к одному, но не меньше 11 px (в прототипе служебное
     7–10 px, на настоящем экране не читается; так решено). Насыщенность, разрядка,
     межстрочный и регистр — как у аналога, без пересчёта.
     Размер шрифта в правилах — только этими ступенями, числом не пишется.
     В скобках — размер в прототипе:
     --fs-page — заголовок страницы, h1 (28–39);
     --fs-title — заголовок окна и панели тендера (21);
     --fs-stat — крупное число сводки, цена тарифа (18);
     --fs-section — раздел страницы, h2 (15–16);
     --fs-card-title — название в карточке, НМЦК в подвале (14);
     --fs-subsection — блок панели, h3, пункт меню, шапка столбца (12);
     --fs-lead — пояснение под заголовком, имя в панели, итог (11);
     --fs-body — основной текст, кнопки, поля формы (10);
     --fs-control — вкладки, подписи полей, значения сведений, ячейки
       таблиц, поля отбора, кнопки-ссылки (9);
     --fs-meta — служебное: номера, метки, мелкие строки карточки,
       заголовки таблиц, подписи сведений, подсказки (7–8);
     --fs-eyebrow — надзаголовок заглавными (9). */
  --fs-page:clamp(28px, 3vw, 39px);
  --fs-title:21px;
  --fs-stat:18px;
  --fs-section:16px;
  --fs-card-title:14px;
  --fs-subsection:12px;
  --fs-lead:11px;
  --fs-body:11px;
  --fs-control:11px;
  --fs-meta:11px;
  --fs-eyebrow:11px;
  color-scheme:light;
}

/* ---------- основа ---------- */

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    color: var(--text);
    font-family: 'Manrope', 'Helvetica Neue', Arial, sans-serif;
    font-size: var(--fs-body);
    line-height: 1.45;
    overflow-x: hidden;
    /* Лёгкий бирюзовый отсвет в правом верхнем углу — по дизайну. */
    background:
        radial-gradient(circle at 96% 3%, rgba(18, 184, 196, .08), transparent 24rem),
        var(--bg);
    background-attachment: fixed;
}

h1, h2, h3 {
    text-wrap: balance;
    margin: 0 0 12px;
}

/* Заголовки — плотные, с отрицательной разрядкой и обычной насыщенности,
   как в дизайне: сборка прототипа сбрасывает насыщенность заголовков
   (h1–h6 наследуют 400), и крупный заголовок читается одним лёгким
   пятном. Жирными остаются кнопки, метки и цена. */
h1 {
    font-size: var(--fs-page);
    font-weight: 400;
    line-height: 1.14;
    letter-spacing: -.045em;
}

h2 {
    font-size: var(--fs-section);
    font-weight: 400;
    letter-spacing: -.025em;
}

h3 {
    font-size: var(--fs-subsection);
    font-weight: 400;
    letter-spacing: -.01em;
}

/* Надзаголовок — раздел над названием страницы или блока, по дизайну:
   заглавными, в разрядку, цветом акцента. */
.eyebrow {
    margin: 0 0 6px;
    color: var(--accent-text);
    font-size: var(--fs-eyebrow);
    font-weight: 800;
    letter-spacing: .12em;
    text-transform: uppercase;
}

p { margin: 0 0 10px; }

/* Шапка страницы (<x-page-heading>) — надзаголовок, заголовок, строка
   описания и главное действие справа, как в дизайне. На узком экране
   действие уходит под текст. */
.page-heading {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 12px 24px;
    flex-wrap: wrap;
    margin-bottom: 18px;
}

.page-heading-text {
    min-width: 0;
    flex: 1 1 320px;
}

.page-heading h1 {
    margin: 0 0 7px;
}

.page-lead {
    max-width: 700px;
    margin: 0;
    color: var(--text-muted);
    font-size: var(--fs-lead);
}

.page-heading-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}


/* Подпись к значению — одной насыщенностью везде: в формах (.field),
   в списках «подпись — значение» (.kv), в отборе (.filter), в
   предложениях помощника и приставкой в строке карточки (<strong>).
   Заголовки и названия карточек жирнее — они не подписи. */
strong, b {
    font-weight: 600;
}

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

a:hover,
a:focus-visible {
    color: var(--accent-strong-text);
    text-decoration: underline;
}

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

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

/* Значок Heroicons (<x-heroicon-o-… class="icon" />): размер по высоте текста,
   цвет — от окружающего текста (currentColor). Применяется везде, где значок
   стоит рядом со словом; свой размер в шаблонах не задаётся.

   У ссылок значок несёт его только там, где сообщает что-то новое:

   - стрелка из рамки (arrow-top-right-on-square) — ссылка уводит за
     пределы сайта: площадка, файл с площадки, tel:, mailto:;
   - стрелка направления в .page-nav (arrow-left, arrow-right) — переход
     между страницами, где она и была раньше символом «←»/«→».

   Ссылки внутри приложения значка не несут: стрелка у каждой из них ничего
   не сообщала (внутри приложения ведут почти все ссылки) и только сорила в
   тексте — у ссылки посреди абзаца, у пункта меню, у каждой кнопки-ссылки.
   Отличать ссылку от текста и так есть чем — цветом и подчёркиванием при
   наведении.

   В текстовой ссылке между словом и значком стоит &nbsp;: обычный пробел
   позволил бы значку уехать на следующую строку и остаться там одиноким
   знаком. В кнопке (.btn) его не ставят — промежуток держит gap самой
   кнопки, а лишний пробел стал бы в её флексе отдельным элементом с
   собственным зазором.

   vertical-align, а не flex на ссылке: ссылка остаётся строчной и
   переносится вместе с текстом абзаца, в который вписана. */
.icon {
    width: 1.25em;
    height: 1.25em;
    flex: none;
    vertical-align: -0.25em;
}

.muted-note {
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

/* ---------- поля ввода ---------- */

input, select, textarea {
    font-family: inherit;
    font-size: var(--fs-body);
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 7px 11px;
    transition: border-color .15s ease, box-shadow .15s ease;

    /* Поле не вылезает за то, что его держит. Ширину задаёт место в
       форме, а не содержимое: длинное значение в однострочном поле
       прокручивается внутри, а не растягивает поле вместе с панелью. */
    max-width: 100%;
}

/* Тянуть поле можно только вниз.

   У textarea браузер даёт уголок для растягивания в обе стороны, и вбок
   его утаскивали за край панели: поле вылезало на пустое поле страницы,
   а на узком экране — за край окна, где у body стоит overflow-x: hidden
   и правая часть поля просто обрезалась. Высота — другое дело: ключ
   поиска бывает и на двадцать слов, и разворачивать поле под них
   нормально. */
textarea {
    resize: vertical;
}

/* Многострочное поле — не меньше пяти строк, и сжать его уголком ниже
   нельзя: характеристики, примечания и комментарии пишут абзацами, а в
   поле на две-три строки их приходится читать прокруткой. rows="5" в
   разметке задаёт ту же высоту сразу, правило держит её при
   растягивании. 5lh — пять строк текста поля, 16px — внутренние
   отступы (7px × 2) и рамка (1px × 2).

   Исключение — поле ввода в чате помощника (.chat-input): оно прижато к
   низу панели, и пять строк отняли бы место у переписки. */
textarea:not(.chat-input) {
    min-height: calc(5lh + 16px);
}

/* Поле с редактором Markdown (<x-markdown-editor>, EasyMDE) — примечание
   позиции номенклатуры. Выглядит как обычное многострочное поле: та же
   рамка, скругление, шрифт и подсветка рамки при наведении и фокусе, а
   сверху — строка кнопок на серой заливке. Стили EasyMDE
   (public/vendor/easymde) подгружаются позже этого файла, поэтому каждое
   правило начинается с .markdown-editor — иначе их перебили бы. Цвета —
   переменными: в тёмной теме редактор тёмный, как остальные поля. */
.markdown-editor .EasyMDEContainer {
    min-width: 0;
}

.markdown-editor .editor-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px;
    padding: 4px 6px;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    border-bottom: 0;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    opacity: 1;
}

.markdown-editor .editor-toolbar button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 28px;
    margin: 0;
    color: var(--text);
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
}

.markdown-editor .editor-toolbar button:hover,
.markdown-editor .editor-toolbar button.active {
    background: var(--surface);
    border-color: var(--border-strong);
}

.markdown-editor .editor-toolbar i.separator {
    height: 18px;
    margin: 0 4px;
    border-left: 1px solid var(--border-strong);
    border-right: 0;
}

.markdown-editor .CodeMirror,
.markdown-editor .editor-preview {
    font-family: inherit;
    font-size: var(--fs-body);
    line-height: 1.5;
    color: var(--text);
    background: var(--surface);
}

.markdown-editor .CodeMirror {
    border: 1px solid var(--border-strong);
    border-radius: 0 0 var(--radius-sm) var(--radius-sm);
    padding: 4px 6px;
    transition: border-color .15s ease;
}

.markdown-editor .CodeMirror-focused,
.markdown-editor .EasyMDEContainer:hover .CodeMirror {
    border-color: var(--accent);
}

.markdown-editor .CodeMirror-cursor {
    border-left-color: var(--text);
}

.markdown-editor .CodeMirror-selected,
.markdown-editor .CodeMirror-focused .CodeMirror-selected {
    background: var(--accent-wash);
}

/* Оформленный текст Markdown — примечание в «Подробнее» и в карточке
   позиции (App\Support\Markdown::html()). Поля у абзацев и списков
   ужаты: это короткое примечание, а не статья. */
.markdown-view > :first-child {
    margin-top: 0;
}

.markdown-view > :last-child {
    margin-bottom: 0;
}

.markdown-view :is(p, ul, ol) {
    margin: 0 0 6px;
}

.markdown-view :is(ul, ol) {
    padding-left: 1.4em;
}

/* В «Подробнее» — на месте поля: та же рамка, но без заливки поля
   ввода, текст не правится. */
.markdown-view-field {
    min-height: calc(5lh + 16px);
    padding: 7px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: var(--fs-body);
}

/* Однострочное поле и выпадающий список — той же высоты, что кнопка:
   в отборе над списком они стоят в одной строке. Высота точная, а не
   минимальная: поле даты у браузера своей высоты выше кнопки. */
input:not([type="checkbox"]):not([type="radio"]),
select {
    height: var(--control-h);
}

input:hover, select:hover, textarea:hover {
    border-color: var(--border-strong);
}

/* Фокус — рамкой цвета акцента и мягким кольцом вокруг, как в дизайне. */
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--focus-ring);
}

input:disabled, select:disabled, textarea:disabled {
    background: var(--surface-2);
    color: var(--text-muted);
    cursor: not-allowed;
}

/* Поле с подписью сверху — основная форма записи в формах. */
.field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: var(--fs-meta);
    color: var(--text-muted);
    margin-bottom: 12px;
}

/* Поле файла, на которое можно перетащить файл, — окно импорта
   (partials/import-dialog). Пунктирная рамка говорит, что сюда бросают;
   файл над полем — заливка акцента. Цвет букв не меняется. */
.field.drop-zone {
    padding: 14px;
    border: 2px dashed var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface);
}

.field.drop-zone.is-over {
    border-color: var(--accent);
    background: var(--accent-wash);
}

.field > span {
    font-weight: 800;
    color: var(--text);
    font-size: var(--fs-control);
}

/* Подсказка и ошибка под полем — тоже прямые потомки .field, но подписью
   не являются (ошибка внутри <label class="field"> — у формы товара). */
.field > .muted-note,
.field > .field-error {
    font-weight: 400;
}

/* Второстепенное поле формы — синонимы позиции номенклатуры сразу под
   наименованием (partials/catalog-product-form): подпись мельче, обычной
   насыщенностью и серым, поле ниже обычного и текст в нём серым — оно
   дополняет наименование, а не спорит с ним. */
.field.field-minor > span:first-child {
    font-weight: 600;
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

.field.field-minor input {
    height: calc(var(--control-h) - 10px);
    padding: 4px 10px;
    color: var(--text-muted);
}

.field input,
.field select,
.field textarea {
    width: 100%;
}

/* Свое поле номенклатуры «цена с валютой» (partials/catalog-product-field):
   сумма и код валюты в одну строку, валюта по ширине кода. */
.field-money {
    display: flex;
    gap: 8px;
}

.field-money input {
    flex: 1 1 auto;
    min-width: 0;
}

.field .field-money select {
    flex: 0 0 auto;
    width: auto;
}


.field-error {
    color: var(--danger-text);
    font-size: var(--fs-meta);
}

/* Флажок с подписью — своей строкой: несколько флажков подряд
   (настройки ключа, роли участника, «запомнить меня») встают столбиком с
   одинаковым шагом, без <br> и отступов в разметке. Ширина по
   содержимому — щелчок по пустому месту справа флажок не переключает. */
.checkbox {
    display: flex;
    width: fit-content;
    align-items: center;
    gap: 6px;
    font-size: var(--fs-body);
    color: var(--text-muted);
    cursor: pointer;
}

.checkbox + .checkbox {
    margin-top: 8px;
}

.checkbox input {
    width: auto;
    cursor: pointer;
}

/* ---------- кнопки ---------- */

button {
    font-family: inherit;
    cursor: pointer;
}

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    min-height: var(--control-h);
    padding: 6px 16px;
    font-size: var(--fs-body);
    font-weight: 800;
    white-space: nowrap;
    text-decoration: none;
    transition: background-color .15s ease, color .15s ease, border-color .15s ease, box-shadow .15s ease;
}

/* Главное действие — заливкой акцента с мягкой синей тенью. */
.btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    box-shadow: 0 7px 18px rgba(36, 85, 214, .16);
}

.btn-primary:not(:disabled):hover,
.btn-primary:not(:disabled):focus-visible {
    background: var(--accent-strong);
    border-color: var(--accent-strong);
    color: #fff;
    text-decoration: none;
}

.btn-ghost {
    background: var(--surface);
    color: var(--text);
    border-color: var(--border);
}

.btn-ghost:not(:disabled):hover,
.btn-ghost:not(:disabled):focus-visible {
    background: var(--surface-2);
    color: var(--text);
    text-decoration: none;
}

.btn-danger {
    background: var(--surface);
    color: var(--danger-text);
    border-color: var(--danger-line);
}

.btn-danger:not(:disabled):hover,
.btn-danger:not(:disabled):focus-visible {
    background: var(--danger-wash);
    color: var(--danger-text);
    text-decoration: none;
}

/* Приостановить, не удаляя, — «Отключить» у правила подбора
   (catalog/match-rules). Цвет — рамкой и заливкой при наведении, текст —
   --warn-text, как у .btn-danger. */
.btn-warn {
    background: var(--surface);
    color: var(--warn-text);
    border-color: var(--warn-line);
}

.btn-warn:not(:disabled):hover,
.btn-warn:not(:disabled):focus-visible {
    background: var(--warn-wash);
    color: var(--warn-text);
    text-decoration: none;
}

.btn-block {
    display: flex;
    width: 100%;
}

/* Малая кнопка — в строке таблицы, где кнопка в рост поля раздувала бы
   строку («Подробнее / Редактировать / Удалить» у товара тендера).
   Вид (primary, ghost, danger) — тот же, меняется только размер. */
.btn-sm {
    min-height: 28px;
    padding: 3px 10px;
    font-size: var(--fs-meta);
}

.btn:disabled,
.btn[disabled] {
    opacity: .45;
    cursor: not-allowed;
    box-shadow: none;
}

.btn:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* ---------- панели ---------- */

.panel {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 18px 20px;
    margin-bottom: 16px;
}

/* Последнее поле или абзац не добавляет свой отступ к полю панели — иначе
   снизу у панели с формой поле вдвое больше, чем сверху. */
.panel > :last-child {
    margin-bottom: 0;
}

.panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}

.panel-head h2,
.panel-head h3 {
    margin: 0;
}

/* Пары «подпись — значение»: карточки организации, профиля, тендера. */
.kv {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 6px 14px;
    font-size: var(--fs-body);
    margin: 0;
}

.kv dt {
    color: var(--text-muted);
    font-weight: 400;
    font-size: var(--fs-meta);
}

.kv dd {
    margin: 0;
    font-size: var(--fs-control);
    font-weight: 700;
    line-height: 1.5;
}

/* ---------- таблицы ---------- */

/* Широкую таблицу на узком экране прокручивают вбок, а не сжимают: при
   сжатии длинная колонка превращается в столбик по букве, а body с
   overflow-x: hidden просто обрезал бы правый край — данные стали бы
   недоступны вовсе.

   Списки записей сюда больше не попадают: они выводятся карточками. Это
   на случай таблицы, которая списком записей не является, — например
   сводки с фиксированными столбцами. */
.table-scroll {
    overflow: auto;
    /* Плавная прокрутка пальцем в старых WebKit. */
    -webkit-overflow-scrolling: touch;
    /* Своя прокрутка и по высоте — ради закреплённого заголовка (ниже):
       vh — для браузера без dvh. */
    max-height: 75vh;
    max-height: 75dvh;
}

/* Строка заголовков закреплена при прокрутке таблицы — у всех таблиц
   контура. Закрепить её при прокрутке страницы или окна нельзя: блок с
   прокруткой вбок (.table-scroll) прокручивает и по высоте, и sticky
   держится его, а не страницы. Поэтому длинная таблица прокручивается
   внутри себя, не выше 75% экрана, а заголовок стоит над строками.
   Короткая таблица в предел не упирается и выглядит как прежде.
   Заливка у заголовка своя (thead th), строки под ним не просвечивают;
   угловые ячейки — закреплённые и сверху, и слева — лежат выше всех. */
.table-scroll thead th {
    position: sticky;
    top: 0;
    z-index: 3;
}

.table-scroll .table-pin thead th:is(:first-child, :nth-child(2)),
.table-scroll .table-pin-actions thead th:nth-child(3) {
    z-index: 4;
}

/* Таблица продолжается за краем — край размыт. Полосы прокрутки мало: на
   телефоне и в macOS её не видно, пока не начнёшь прокручивать, и
   столбцы за краем ничем не обозначены.

   Без скрипта: прокрутка самой .table-scroll ведёт анимацию
   (animation-timeline), а та двигает два числа — есть ли что-то слева
   (--scroll-left) и справа (--scroll-right). Таблица, которая
   помещается, прокрутки не имеет, анимация не действует, и оба числа
   остаются нулями — края чёткие. Числа объявлены через @property, иначе
   их нельзя анимировать и наследовать: закреплённый столбец
   (.table-pin) читает --scroll-left, чтобы отбросить тень.

   Маска, а не тень поверх: тень под таблицей закрывали бы залитые строки
   (.table-striped), а маска действует на всё содержимое разом. Слева у
   таблицы с закреплёнными столбцами края не размываются — там размылось
   бы само наименование, и вместо этого тень отбрасывает столбец.

   Браузер без animation-timeline (Firefox на 2026 год) получает таблицу
   как прежде — без размытия и без тени, с полосой прокрутки. */
@property --scroll-left {
    syntax: '<number>';
    inherits: true;
    initial-value: 0;
}

@property --scroll-right {
    syntax: '<number>';
    inherits: true;
    initial-value: 0;
}

@keyframes table-scroll-edges {
    0% { --scroll-left: 0; --scroll-right: 1; }
    3% { --scroll-left: 1; }
    97% { --scroll-right: 1; }
    100% { --scroll-left: 1; --scroll-right: 0; }
}

@supports (animation-timeline: scroll()) {
    .table-scroll {
        --scroll-fade: 40px;
        --scroll-fade-left: var(--scroll-fade);
        animation: table-scroll-edges linear both;
        animation-timeline: scroll(self inline);
        mask-image: linear-gradient(to right,
            transparent 0,
            #000 calc(var(--scroll-left) * var(--scroll-fade-left)),
            #000 calc(100% - var(--scroll-right) * var(--scroll-fade)),
            transparent 100%);
    }

    .table-scroll:has(> .table-pin) {
        --scroll-fade-left: 0px;
    }
}

/* Заголовок столбца — в одну строку, и столбец не уже своего
   заголовка: так решено — заголовок читается целиком, без переноса по
   словам. Не помещается таблица — она шире окна, и снизу полоса
   прокрутки. min-width держит узкий заголовок («№») от столбца в
   палец шириной; наименования — главное, что читают в строке, — шире:
   .col-name.

   Раньше заголовок переносился в две-три строки, чтобы «Суммарная
   стоимость, руб» не растягивал столбец втрое против числа под ним, —
   от этого отказались. Закреплённые столбцы с заданной шириной (номер,
   кнопки — .table-pin) переносят заголовок по-прежнему: их ширина
   посчитана заранее. */
.table-scroll th {
    min-width: 6em;
    white-space: nowrap;
}

.table-scroll th.col-name {
    min-width: 14em;
}

/* Пустой заголовок — столбец кнопок или пустой по замыслу (у позиции
   номенклатуры нет наименования поставщика): ширину ему задаёт
   содержимое, а не 6em пустоты. */
.table-scroll th:empty {
    min-width: 0;
}

/* separate, а не collapse: у закреплённого столбца (.table-pin) при
   collapse рамки не держатся и уезжают вместе с прокруткой. Рамки
   стоят только снизу и слева ячеек, поэтому двойных линий не бывает, и
   выглядит это как прежде. */
table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--fs-control);
}

th, td {
    text-align: left;
    padding: 7px;
    border-bottom: 1px solid var(--border);
    vertical-align: top;
}

/* Заголовок — обычным регистром, а не заглавными: заглавные с
   разрядкой шире на треть и читаются медленнее, а от строк заголовок
   и так отделён заливкой и чертой. Многострочные заголовки прижаты к
   низу — к данным, которые подписывают. */
th {
    color: var(--text-muted);
    font-weight: 800;
    font-size: var(--fs-meta);
    vertical-align: bottom;
    text-transform: uppercase;
}

/* Текст заголовков — по центру столбца, и у столбцов чисел тоже: числа
   под ним по-прежнему выровнены вправо. */
thead th,
thead th.num {
    text-align: center;
}

thead th {
    background: var(--surface-2);
    border-bottom: 2px solid var(--border-strong);
}

/* Цифры одной ширины: в Manrope «1» уже «8», и без этого разряды в
   столбце не стоят друг под другом даже при выравнивании вправо. */
td.num, th.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

tbody tr {
    transition: background-color .15s ease;
}

tbody tr:hover {
    background: var(--row-hover);
}

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

   Чередование, потому что строка такой таблицы длинная и в несколько
   столбцов: глаз теряет её на полпути и съезжает на соседнюю, а по
   спецификации сверяют количество и цену — съехать там дорого. Первая
   строка белая: заливка отмечает каждую вторую, а не каждую первую, иначе
   таблица начиналась бы серой полосой под заголовком и выглядела бы
   продолжением его.

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

   Нельзя просто покрасить все <table> контура: таблицей выводятся и пары
   «подпись — значение» (.chat-fields в панели помощника), где полосы
   были бы шумом. */
/* Нечётные — белые явно, а не прозрачные: таблица стоит и на сером
   (.catalog-list, страница), а закреплённые ячейки (.table-pin) белые
   всегда, и строка выходила бы двух цветов. */
.table-striped tbody tr {
    background: var(--surface);
}

.table-striped tbody tr:nth-child(even) {
    background: var(--surface-2);
}

.table-striped tbody tr:hover {
    background: var(--row-hover);
}

/* Черта между столбцами — у тех же таблиц-спецификаций: по строке ведёт
   заливка, по столбцу — черта, и число не съезжает в соседний столбец,
   когда ячейки разной ширины, а соседние пусты. У пар «подпись —
   значение» (.chat-fields) черт нет, как и полос. */
.table-striped th + th,
.table-striped td + td {
    border-left: 1px solid var(--border);
}

/* Закреплённые столбцы: «№» и наименование стоят на месте, пока таблицу
   прокручивают вбок. Без этого на пятнадцатом столбце «Товаров тендера»
   не видно, к какому товару относится цена. Применяется там, где первые
   два столбца — номер и наименование: товары тендера, объекты закупки,
   возможные участники.

   Ширина первого столбца задана жёстко (--pin-first): второй встаёт на
   отступ, равный ей, а измерить её без скрипта нельзя. Номер поэтому
   переносится, если не влез, вместо того чтобы раздвинуть столбец и
   заехать под наименование.

   Фон у закреплённых ячеек свой и непрозрачный — под ними проезжают
   остальные столбцы, — и повторяет заливку строки: белая, серая через
   одну, подсветка под курсором. Правый край последнего закреплённого —
   жирной чертой, той же, что отделяет заголовок от строк (2px,
   --border-strong): закреплённая часть отделена от прокручиваемой так
   же, как заголовок от данных. Когда таблицу уже прокрутили, к черте
   добавляется тень (--scroll-left, см. размытие краёв выше).

   Таблица с кнопками в строках (.table-pin-actions) закрепляет ещё и
   столбец кнопок — он первый, перед номером и наименованием. Его ширина
   задаётся числом кнопок в строке (.pin-actions-1…4), а не измеряется:
   следующий столбец встаёт на отступ, равный ей. */
/* 4.5em — по «№ п/п» в одну строку и номеру из документа вида
   «2.1.10»: уже — и то и другое ломалось посреди. */
.table-pin {
    --pin-first: 4.5em;
    --pin-buttons: 1;
    /* Кнопки — столбиками по три (.row-icon-actions): до трёх кнопок —
       один столбик, четыре — два. Кнопка 28px, между кнопками 4px, поля
       ячейки по 7px. */
    --pin-columns: 1;
    --pin-actions: calc(var(--pin-columns) * 32px + 10px);
}

.pin-actions-2 { --pin-buttons: 2; }
.pin-actions-3 { --pin-buttons: 3; }
.pin-actions-4 { --pin-buttons: 4; --pin-columns: 2; }

/* Позиции в «Подборе товара» (in-work/catalog-candidates): четыре столбца
   и кнопки с подписью первым столбцом — «Сделать основной», «Убрать»,
   «Выбрать» столбиком. Без закрепления: таблица узкая и в панель
   помещается целиком. */
.catalog-candidates .catalog-actions-col {
    width: 1%;
    white-space: nowrap;
}

.catalog-candidate-actions {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    margin: 0;
}

/* «почему выбрала система» — обоснование ИИ у подобранной копии, свёрнуто. */
.catalog-ai-reason {
    margin-top: 4px;
}

.catalog-ai-reason summary {
    cursor: pointer;
    color: var(--accent-text);
    font-size: var(--fs-meta);
}

/* Столбец «Оценки» найденного в «Подборе товара» (in-work/catalog-candidates):
   по строке на метод — смысл, слова, цифры, итог, rerank, — числа одной
   ширины и без переноса, подпись метода серой (.muted-note). */
.catalog-scores {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.table-pin :is(th, td):is(:first-child, :nth-child(2)),
.table-pin-actions :is(th, td):nth-child(3) {
    position: sticky;
    z-index: 2;
}

/* table. в селекторе — чтобы перебить white-space: nowrap у
   .tender-items td.num, объявленный ниже по файлу. */
table.table-pin :is(th, td):first-child {
    left: 0;
    width: var(--pin-first);
    min-width: var(--pin-first);
    max-width: var(--pin-first);
    white-space: normal;
    overflow-wrap: anywhere;
}

.table-pin :is(th, td):nth-child(2) {
    left: var(--pin-first);
    min-width: 14em;
}

/* Столбец кнопок — первым, номер — вторым, наименование — третьим. */
table.table-pin-actions :is(th, td):first-child {
    width: var(--pin-actions);
    min-width: var(--pin-actions);
    max-width: var(--pin-actions);
    white-space: nowrap;
    overflow-wrap: normal;
}

table.table-pin-actions :is(th, td):nth-child(2) {
    left: var(--pin-actions);
    width: var(--pin-first);
    min-width: var(--pin-first);
    max-width: var(--pin-first);
    white-space: normal;
    overflow-wrap: anywhere;
}

.table-pin-actions :is(th, td):nth-child(3) {
    left: calc(var(--pin-actions) + var(--pin-first));
    min-width: 14em;
}

/* Жирная черта и тень — у последнего закреплённого столбца. */
.table-pin:not(.table-pin-actions) :is(th, td):nth-child(2),
.table-pin-actions :is(th, td):nth-child(3) {
    box-shadow:
        2px 0 0 var(--border-strong),
        8px 0 8px -6px rgb(0 0 0 / calc(var(--scroll-left) * .25));
}

.table-pin tbody td:is(:first-child, :nth-child(2)),
.table-pin-actions tbody td:nth-child(3) {
    background: var(--surface);
    transition: background-color .15s ease;
}

.table-striped.table-pin tbody tr:nth-child(even) td:is(:first-child, :nth-child(2)),
.table-striped.table-pin-actions tbody tr:nth-child(even) td:nth-child(3) {
    background: var(--surface-2);
}

.table-striped.table-pin tbody tr:hover td:is(:first-child, :nth-child(2)),
.table-striped.table-pin-actions tbody tr:hover td:nth-child(3) {
    background: var(--row-hover);
}

/* Таблица «Товаров тендера» — Tabulator (in-work/products,
   public/js/products-grid.js), оформленный как остальные таблицы контура
   (.table-striped): заголовок на заливке --surface-2 с чертой 2px,
   чередование строк, подсветка строки под курсором, черты между
   столбцами, жирная черта справа от закреплённых. Цвета — переменными,
   поэтому тёмная тема работает сама. Тема Tabulator
   (public/vendor/tabulator) подгружается позже этого файла, поэтому
   каждое правило начинается с .products-grid — иначе её правила
   перебили бы эти.

   Текст в ячейке переносится (у Tabulator по умолчанию — в одну строку с
   многоточием) и обрезается на --cell-lines строках обычной .cell-clamp:
   наведение показывает его целиком, как в других таблицах. */
.products-grid .tabulator {
    font-family: inherit;
    font-size: var(--fs-meta);
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

.products-grid .tabulator .tabulator-header,
.products-grid .tabulator .tabulator-header .tabulator-col {
    background: var(--surface-2);
    color: var(--text-muted);
    border-color: var(--border);
}

.products-grid .tabulator .tabulator-header {
    border-bottom: 2px solid var(--border-strong);
}

.products-grid .tabulator .tabulator-header .tabulator-col .tabulator-col-content {
    padding: 7px;
}

.products-grid .tabulator .tabulator-tableholder .tabulator-table {
    background: var(--surface);
    color: var(--text);
}

.products-grid .tabulator-row,
.products-grid .tabulator-row.tabulator-row-even {
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}

.products-grid .tabulator-row.row-even {
    background: var(--surface-2);
}

.products-grid .tabulator-row:hover {
    background: var(--row-hover);
}

/* Ячейка — во всю высоту строки, что бы в ней ни лежало: черты между
   столбцами, заливка строки и серый неправимых столбцов не обрываются
   посреди строки. Строка — гибкая, ячейки растягиваются по самой высокой;
   высоту, которую Tabulator ставит ячейкам числом при отрисовке, правило
   перебивает: выросшее потом содержимое (шрифт, шаблон после перерисовки)
   оставляло бы соседей прежней высоты. Строку, вытянутую за край, держит
   её собственная высота (products-grid.js, rowResized), ячейки — по ней. */
.products-grid .tabulator-row {
    display: flex;
}

.products-grid .tabulator-row .tabulator-cell {
    flex: none;
    align-self: stretch;
    height: auto !important;
}

.products-grid .tabulator-row .tabulator-cell {
    padding: 7px;
    white-space: normal;
    border-right: 1px solid var(--border);
    font-variant-numeric: tabular-nums;
}

.products-grid .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left,
.products-grid .tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left {
    border-right: 2px solid var(--border-strong);
}

/* Край для высоты строки (resizableRows) — над закреплёнными ячейками:
   иначе в закреплённых столбцах его перекрывали они, и строку можно было
   тянуть только справа от них. */
.products-grid .tabulator-row .tabulator-row-resize-handle {
    z-index: 12;
}

.products-grid .grid-cell {
    width: 100%;
    min-width: 0;
}

/* Заголовок — в одну строку целиком, как у остальных таблиц контура:
   ширину столбца Tabulator считает по заголовку и содержимому
   (layout: fitData), длинным столбцам ставится предел начальной ширины (maxInitialWidth):
   растянуть столбец руками можно и шире. */
.products-grid .tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title {
    overflow: visible;
    text-overflow: clip;
    font-size: var(--fs-meta);
    font-weight: 800;
    text-transform: uppercase;
    text-align: center;
}

.products-grid .tabulator-row .tabulator-cell.cell-calc {
    color: var(--text-muted);
}

/* Столбец, который в таблице не правится (поставщик — выбирают подбором,
   суммарная стоимость — считается), — серым: видно до двойного щелчка,
   куда вводить нельзя. Только у того, кто правит товары: у остальных не
   правится ничего, и серой была бы вся таблица. */
.products-grid .tabulator-row .tabulator-cell.cell-locked {
    background-image: linear-gradient(var(--cell-locked-shade), var(--cell-locked-shade));
}

.products-grid .tabulator-row .tabulator-cell.cell-markdown-editable {
    cursor: pointer;
}

.products-grid .tabulator-row .tabulator-cell.tabulator-editing {
    border: 1px solid var(--accent);
    padding: 0;
}

.products-grid .tabulator-row .tabulator-cell.tabulator-editing :is(input, textarea) {
    width: 100%;
    padding: 6px 7px;
    color: var(--text);
    background: var(--surface);
    border: 0;
    border-radius: 0;
    height: auto;
    min-height: 0;
    font: inherit;
}

/* Выделенный диапазон — цветом акцента, а не синим Tabulator. */
.products-grid .tabulator-row .tabulator-cell.tabulator-range-selected:not(.tabulator-range-only-cell-selected):not(.tabulator-range-row-header) {
    background: var(--accent-wash);
}

.products-grid .tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range,
.products-grid .tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range-cell-active {
    border-color: var(--accent);
}

.products-grid .tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range.tabulator-range-active::after {
    background: var(--accent);
}

.products-grid .tabulator .tabulator-tableholder {
    background: var(--surface);
    scrollbar-color: var(--border-strong) var(--surface);
}

/* Заголовок и ячейка строки над выделенным диапазоном — тоном акцента,
   а не светло-серым Tabulator: в тёмной теме серый горел пятном. */
.products-grid .tabulator .tabulator-header .tabulator-col.tabulator-range-highlight,
.products-grid .tabulator-row.tabulator-range-highlight .tabulator-cell.tabulator-range-row-header,
.products-grid .tabulator-row .tabulator-cell.tabulator-range-only-cell-selected {
    background: var(--accent-wash);
    color: var(--text);
}

.products-grid .tabulator .tabulator-header .tabulator-col.tabulator-range-selected {
    background: var(--accent);
    color: #fff;
}

.products-grid .tabulator .tabulator-tableholder .tabulator-placeholder .tabulator-placeholder-contents {
    color: var(--text-muted);
    font-size: var(--fs-body);
    font-weight: 400;
}

/* Отбор над списком: подпись и поле в одну строку.

   .field здесь не годится — он колоночный и растягивает поле на всю
   ширину, а отбор стоит в одной строке со счётчиком найденного. */
.filter {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: var(--fs-meta);
}

.filter > span {
    font-weight: 700;
}

/* Строка текстового поиска над списком («Подобранные тендеры»): своя
   строка, поле тянется на всю ширину после подписи. */
.filter-search {
    display: flex;
    width: 100%;
}

.search-field {
    position: relative;
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
}

.filter-search input {
    flex: 1 1 auto;
    min-width: 0;
}

/* Крестик сброса поиска (<x-search-input>): внутри поля у правого края,
   поле освобождает под него место; родной крестик браузера скрыт. */
.search-field input {
    width: 100%;
    padding-right: calc(var(--control-h) - 4px);
}

.search-field input::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
}

.search-field input:placeholder-shown ~ .search-clear {
    display: none;
}

.search-clear {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--text-faint);
    cursor: pointer;
}

.search-clear:hover,
.search-clear:focus-visible {
    background: var(--surface-2);
    color: var(--text);
}

.search-clear .icon {
    width: 14px;
    height: 14px;
}

.filter select {
    /* Названия ключей бывают длинными, и без предела список растягивал бы
       строку отбора до края экрана. */
    max-width: 260px;
}

/* Вкладки над списком (подобранные тендеры: тендеры и планы-графики).
   Сегментами на серой подложке, выбранная — белой плашкой с цветом
   акцента, как в дизайне. Число — сколько во вкладке всего. */
.tabs {
    display: flex;
    flex-wrap: wrap;
    width: fit-content;
    max-width: 100%;
    gap: 4px;
    padding: 4px;
    border-radius: 11px;
    background: var(--tab-track);
}

.tab {
    padding: 8px 14px;
    border: 0;
    border-radius: 8px;
    background: none;
    font: inherit;
    font-size: var(--fs-control);
    font-weight: 700;
    color: var(--text-muted);
    cursor: pointer;
}

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

.tab:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 0;
}

/* Быстрые отборы без подложки (.tabs-plain) — как в дизайне «Тендеров в
   работе»: выбранный — заливкой акцента, остальные — текстом. */
.tabs.tabs-plain {
    padding: 0;
    background: none;
}

.tabs-plain .tab-active,
.tabs-plain .tab-active:hover {
    background: var(--accent-wash);
    box-shadow: none;
}

.tab-active,
.tab-active:hover {
    background: var(--surface);
    color: var(--accent-text);
    box-shadow: 0 4px 12px rgba(11, 23, 57, .06);
}

/* Число записей рядом с названием — на вкладке и в заголовке
   сворачиваемого блока карточки тендера — одним видом. */
.tab-count,
.fold-count {
    font-weight: 400;
    color: var(--text-muted);
}

/* Отбор, который на этой вкладке не действует (окончание подачи на
   вкладке планов-графиков): на месте, но приглушён и выключен. */
.filter-disabled {
    opacity: .5;
}

.filter-disabled input {
    cursor: not-allowed;
}

/* Alpine прячет такие элементы до своего запуска: без этого выпадающий
   список мелькал бы раскрытым при загрузке страницы. */
[x-cloak] {
    display: none !important;
}

.combo {
    position: relative;
    width: 320px;
    max-width: 100%;
}

.combo-field {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    min-height: var(--control-h);
    padding: 3px 6px;
    /* Выглядит и отзывается как обычное поле ввода: это оно и есть,
       только с метками внутри. */
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: var(--surface);
    cursor: text;
    transition: border-color .15s ease;
}

.combo-field:hover {
    border-color: var(--accent);
}

.combo-field:focus-within {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.combo-input {
    flex: 1 1 80px;
    min-width: 80px;
}

/* Поле ввода внутри выбора ключей — без своей высоты: высоту держит
   рамка вокруг (.combo-field). Селектор с :not(), чтобы перебить общее
   правило высоты поля выше. */
.combo-input input:not([type="checkbox"]) {
    width: 100%;
    height: auto;
    border: 0;
    outline: 0;
    padding: 3px 2px;
    background: none;
    font: inherit;
    font-size: var(--fs-control);
    color: var(--text);
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    max-width: 100%;
    padding: 1px 2px 1px 8px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-2);
    font-size: var(--fs-meta);
}

/* Название ключа пишет человек, длина любая: метка обрезает его. */
.chip-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.chip-remove {
    border: 0;
    padding: 0 5px;
    background: none;
    font-size: 18px;
    line-height: 1;
    color: var(--text-muted);
    cursor: pointer;
}

.chip-remove:hover,
.chip-remove:focus-visible {
    color: var(--text);
}

.combo-list {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 50;
    max-height: 280px;
    overflow-y: auto;
    margin: 0;
    padding: 4px 0;
    list-style: none;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    box-shadow: var(--shadow);
}

.combo-option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    font-size: var(--fs-control);
    cursor: pointer;
}

/* .combo-option-active — пункт, выбранный стрелками в подсказках адреса
   (<x-address-suggest>): подсвечен так же, как под курсором. */

.combo-option:hover,
.combo-option:focus-within,
.combo-option-active {
    background: var(--surface-2);
}

/* Пункт списка-кнопки (подсказки ОКПД2 на форме ключа): та же строка, что
   у пункта с флажком, но нажимается целиком. */
button.combo-option {
    width: 100%;
    border: 0;
    background: none;
    font: inherit;
    font-size: var(--fs-control);
    color: var(--text);
    text-align: left;
}

/* В форме выбор занимает всю ширину поля, а не 320px, как в строке отбора. */
.field .combo {
    width: 100%;
}

.combo-empty {
    padding: 6px 10px;
    font-size: var(--fs-meta);
    color: var(--text-muted);
}

/* Отбор по датам: подпись и два поля «с — по». */
.filter-range {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

/* Кнопка, которая ведёт себя как ссылка: действие внутри предложения или
   в строке действий записи, где .btn выглядел бы инородно. Выглядит ровно
   как ссылка — без подчёркивания, с подчёркиванием при наведении: рядом
   стоят и ссылки («Открыть», «Скачать»), и кнопки («Изменить»,
   «Удалить»), и различать их по виду человеку незачем. */
.btn-link {
    border: 0;
    padding: 0;
    background: none;
    color: var(--accent-text);
    font: inherit;
    text-decoration: none;
}

.btn-link:hover,
.btn-link:focus-visible {
    color: var(--accent-strong-text);
    text-decoration: underline;
}

/* Красная ссылка-кнопка — отладочное действие «Сбросить тендер» в подвале
   карточки (in-work/modal, только при APP_DEBUG). */
.btn-link.link-danger,
.btn-link.link-danger:hover,
.btn-link.link-danger:focus-visible {
    color: var(--danger-text);
}

/* Зелёная ссылка-кнопка — «Подтвердить» у документа в строке подбора
   (shipment-documents-table), парная красной .link-danger. */
.btn-link.link-ok,
.btn-link.link-ok:hover,
.btn-link.link-ok:focus-visible {
    color: var(--success-text);
}

/* ---------- карточки списков ----------

   Список записей — карточки, а не строки таблицы. Причина та же, что в
   админской панели: колонки не помещаются по ширине, а на телефоне
   таблица либо уезжает за край, либо сжимается до столбика по букве.
   Карточка одна в ряд и во всю ширину — ровно то место, что занимала
   строка таблицы.

   Подписей у полей нет: главное поле идёт жирным сверху вместе с
   бейджами состояния, остальные — мелкими серыми строками с приставкой
   («ключ: Посуда», «подача до 14.10.2026»), а не голым значением. Поле
   без значения просто не выводится, вместо прочерка в пустой колонке. */
/* minmax(0, 1fr), а не колонка по умолчанию: та не сужается меньше
   содержимого, и строка без переноса (ключ поиска с многоточием) растягивала
   карточку, а с ней и страницу, за край узкого экрана. */
.cards {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
}

/* Карточка — белая, со скруглением и мягкой синеватой тенью; под курсором
   рамка темнеет, а тень растёт. Сама карточка не нажимается (см. CLAUDE.md
   «Карточка ссылкой не бывает»), поэтому без сдвига вверх, который в
   дизайне обещает нажатие. */
.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 15px;
    box-shadow: var(--shadow);
    padding: 16px 18px;
    transition: border-color .17s ease, box-shadow .17s ease;
}

.card:hover {
    border-color: var(--border-hover);
    box-shadow: 0 13px 32px rgba(11, 23, 57, .07);
}

/* Ключ поиска под названием, ссылкой на его карточку. Название ключа
   пишет человек, длина произвольная — строка держится одной и обрезает
   лишнее многоточием, а не переносится и не растягивает карточку. */
.card-key {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Верхняя строка: главное поле слева, бейджи прижаты вправо. При нехватке
   ширины бейджи переносятся под заголовок, а не режут его. */
/* Главное поле — первой строкой, метки (.card-badges) — под ним, по левому
   краю: так на всех карточках контура, как в карточке тендера. */
.card-head {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
}

/* Название записи, которое открывает её окном, — кнопка вида ссылки
   (карточка тендера). Своё выравнивание у кнопки по центру, поэтому
   длинное название в две строки встало бы посередине. */
.card-title.btn-link {
    text-align: left;
}

.card-title {
    font-weight: 400;
    font-size: var(--fs-card-title);
    line-height: 1.38;
    letter-spacing: -.02em;
    /* Названия закупок длинные и без пробелов не переносятся сами. */
    overflow-wrap: anywhere;
}

/* Название-ссылка цветом текста, как название ключа в дизайне: что оно
   открывает карточку, видно по подчёркиванию при наведении. */
.card-title.card-title-plain {
    color: var(--text);
    font-size: var(--fs-section);
}

.card-title.card-title-plain:hover {
    color: var(--accent-text);
}

.card-badges {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    /* Сжимается: в бейджах стоит ключ поиска, и его название бывает
       длинным — без этого блок уезжал бы за край узкого экрана. */
    flex: 0 1 auto;
    min-width: 0;
}

.card-line {
    margin-top: 4px;
    font-size: var(--fs-meta);
    color: var(--text-muted);
    line-height: 1.45;
    overflow-wrap: anywhere;
}

/* Синонимы позиции номенклатуры — второстепенное к наименованию: сразу
   под ним, мелко и бледнее строк карточки, не больше двух строк
   (catalog/index, in-work/catalog-candidates, card-synonyms). */
.card-synonyms {
    margin-top: 2px;
    font-size: var(--fs-meta);
    color: var(--text-faint);
    line-height: 1.4;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Несколько мелких полей в одну строку: по отдельности они превращаются
   в столбик коротких значений и растягивают карточку по высоте. */
.card-line-split {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 14px;
}

.card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
}

/* .card-clickable убран вместе с кликабельными карточками: запись
   открывает ссылка на её названии (или кнопка, если открывается окно),
   а не вся площадь карточки. Стиль не оставлен «на случай»: правило без
   разметки со временем возвращает и разметку. */

/* ---------- вид «По ключам» на «Подобранных» ----------

   Столбец на ключ поиска (MatchedTenders::columns()), по образцу доски
   столбцов из дизайна: серая подложка со скруглением, белая шапка с
   названием и числом, карточки стопкой. Ширина столбца постоянная —
   ключей бывает больше, чем помещается, и доска тогда прокручивается
   вбок внутри себя, а не растягивает страницу. Ключ в карточке не
   повторяется: он в шапке столбца. */
.view-switches {
    justify-content: space-between;
}

.key-board {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    overflow-x: auto;
    padding-bottom: 10px;
    overscroll-behavior-x: contain;
}

.key-column {
    flex: 0 0 340px;
    min-width: 0;
    border: 1px solid var(--border);
    border-radius: 15px;
    background: var(--surface-2);
}

.key-column-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--border);
    border-radius: 15px 15px 0 0;
    background: var(--surface);
}

/* Название столбца — меткой, как в дизайне: синей у ключа и стадии «В
   работе», зелёной у «На подачу» (.key-column-label-ok). Длинное название
   ключа обрезается многоточием, целиком — в подсказке. */
.key-column-head h2 {
    justify-self: start;
    max-width: 100%;
    min-width: 0;
    margin: 0;
    padding: 4px 10px;
    overflow: hidden;
    border-radius: 999px;
    background: var(--accent-wash);
    color: var(--accent-text);
    font-size: var(--fs-meta);
    font-weight: 800;
    letter-spacing: normal;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.key-column-head h2.key-column-label-ok {
    background: var(--success-wash);
    color: var(--success-text);
}

.key-column-count {
    flex: 0 0 auto;
    min-width: 28px;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--tab-track);
    color: var(--text-muted);
    font-size: var(--fs-meta);
    font-weight: 800;
    text-align: center;
}

.key-column-body {
    display: grid;
    gap: 10px;
    padding: 10px;
}

.key-column .card-key {
    display: none;
}

.key-column .card {
    padding: 14px;
}

/* В узком столбце строки «загружен / изменён» и даты встают столбиком. */
.key-column .card-line-split {
    flex-direction: column;
    gap: 2px;
}

.key-column .mt {
    margin-top: 0;
}

/* «Тендеры в работе» — два столбца по стадии («В работе», «На подачу»)
   той же доской: столбцов всегда два, и они делят ширину поровну, а не
   стоят по 340px. Под названием — подпись стадии из дизайна. */
.stage-board .key-column {
    flex: 1 1 340px;
}

.stage-column-title {
    display: grid;
    gap: 2px;
    min-width: 0;
}

/* ---------- карточка тендера в списке (x-tender-card) ----------

   По карточке сделки из дизайна: номер и метки сверху, название, ключ и
   заказчик, срок подачи меткой, сведения мелкими строками, внизу — НМЦК и
   «Подробнее». */
.deal-card {
    display: flex;
    flex-direction: column;
}

.deal-card-top {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-start;
    gap: 6px 12px;
    margin-bottom: 10px;
}

/* Левая часть верха — номер и метки закупки столбиком; справа — метки
   тендера (.tender-labels). На узкой карточке метки тендера уходят под неё. */
.deal-card-head {
    display: flex;
    flex: 1 1 14em;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    min-width: 0;
}

/* Метки (закон, способ закупки, «изменён») — своей строкой под номером,
   прижаты к левому краю карточки (так решено; раньше стояли у правого
   края строки с номером, как в дизайне). */
.deal-card-top .card-badges {
    justify-content: flex-start;
    margin-left: 0;
}

/* Номер — кнопкой вида ссылки: открывает ту же панель, что «Подробнее». */
.deal-card-lead .deal-number-link {
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

.deal-card-lead .deal-number-link:hover,
.deal-card-lead .deal-number-link:focus-visible {
    color: var(--accent-text);
}

/* Название — цветом текста, как в дизайне: синим в карточке были бы
   и ключ, и заказчик, и название разом. Под курсором — акцентом. */
.deal-card .card-title {
    color: var(--text);
}

.deal-card .card-title:hover,
.deal-card .card-title:focus-visible {
    color: var(--accent-text);
}

.deal-card-lead {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

/* ---------- метки тендеров (x-tender-labels, LabelsManager) ----------

   Метка тендера — пилюля, но бледнее и без скругления: на карточке рядом
   с метками закупки (.pill) она должна читаться как пометка человека, а не
   как свойство закупки. Цвета — десять: по два оттенка жёлтого, зелёного,
   красного, синего и серого (App\Enums\TenderLabelColor); светлый —
   заливка состояния, тёмный — его рамка; текст всегда своего цвета.
   Тот же класс цвета несёт квадратик выбора цвета (.tender-swatch). */
.tender-label-yellow-1 { background: var(--warn-wash); color: var(--warn-text); }
.tender-label-yellow-2 { background: var(--warn-line); color: var(--warn-text); }
.tender-label-green-1 { background: var(--success-wash); color: var(--success-text); }
.tender-label-green-2 { background: var(--success-line); color: var(--success-text); }
.tender-label-red-1 { background: var(--danger-wash); color: var(--danger-text); }
.tender-label-red-2 { background: var(--danger-line); color: var(--danger-text); }
.tender-label-blue-1 { background: var(--accent-wash); color: var(--accent-strong-text); }
.tender-label-blue-2 { background: var(--accent-line); color: var(--accent-strong-text); }
.tender-label-gray-1 { background: var(--surface-2); color: var(--text-muted); }
.tender-label-gray-2 { background: var(--border); color: var(--text-muted); }

.tender-label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    max-width: 100%;
    padding: 2px 6px;
    border-radius: 0;
    font-size: var(--fs-meta);
    font-weight: 700;
    line-height: 1.3;
    letter-spacing: normal;
    white-space: nowrap;
}

/* Длинное название обрезается многоточием (до 20 знаков оно редко
   длиннее ячейки, но карточка бывает узкой); целиком — в title. */
.tender-label-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Крестик «снять» — крупный: попасть в мелкий на карточке трудно.
   Размер — размер знака, а не текста (исключение из токенов шрифта). */
.tender-label-remove {
    margin: -2px -4px -2px 0;
    padding: 0 5px;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    font-size: 18px;
    font-weight: 700;
    line-height: 1;
    opacity: .7;
    cursor: pointer;
}

.tender-label-remove:hover,
.tender-label-remove:focus-visible {
    opacity: 1;
}

/* Блок меток на карточке — справа вверху: стоящие метки и «+ метка»
   последней, одним рядом, который переносится и прижат к правому краю. */
.tender-labels {
    display: flex;
    flex: 0 1 auto;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
    max-width: 55%;
    min-width: 0;
}

.tender-label-add {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 6px;
    border: 1px dashed var(--border-strong);
    border-radius: 0;
    background: none;
    color: var(--text-muted);
    font: inherit;
    font-size: var(--fs-meta);
    font-weight: 700;
    line-height: 1.3;
    cursor: pointer;
}

.tender-label-add:hover,
.tender-label-add:focus-visible,
.tender-label-add[aria-expanded="true"] {
    border-color: var(--accent-line);
    color: var(--accent-text);
}

/* Список меток растворён: пилюли встают в общий ряд .tender-labels
   вместе с «+ метка». */
.tender-label-stack {
    display: contents;
    list-style: none;
}

.tender-label-stack > li {
    display: flex;
    min-width: 0;
}

/* Выпадающий список — fixed от кнопки (координаты ставит Alpine): столбец
   доски прокручивается, и список внутри карточки обрезался бы его краем. */
.tender-label-panel {
    position: fixed;
    z-index: 70;
    display: grid;
    gap: 8px;
    width: min(300px, calc(100vw - 16px));
    padding: 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-lg);
    text-align: left;
}

/* Отбор по меткам в строке быстрых отборов (<x-label-filter>): кнопка
   «Метки · N» стоит среди соседних отборов, список с флажками — тот же
   fixed-список, что у карточки, только от левого края кнопки. */
.label-filter {
    display: inline-block;
}

.label-filter-panel {
    right: auto;
}

.label-filter-choice {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 5px 4px;
    cursor: pointer;
}

.tender-label-choices {
    display: grid;
    gap: 2px;
    max-height: 220px;
    margin: 0;
    padding: 0;
    overflow-y: auto;
    list-style: none;
}

.tender-label-choice {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 4px 6px;
    border: 0;
    background: none;
    color: var(--text);
    font: inherit;
    cursor: pointer;
}

.tender-label-choice:hover:not(:disabled),
.tender-label-choice:focus-visible {
    background: var(--surface-2);
}

.tender-label-choice:disabled {
    opacity: .5;
    cursor: not-allowed;
}

.tender-label-new {
    display: grid;
    gap: 6px;
    padding-top: 8px;
    border-top: 1px solid var(--border);
}

.tender-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.tender-swatch {
    position: relative;
    width: 22px;
    height: 22px;
    border: 1px solid var(--border);
}

.tender-swatch input {
    position: absolute;
    inset: 0;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.tender-swatch:has(input:checked),
.tender-swatch:has(input:focus-visible) {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

/* Окно «Метки тендеров»: форма новой метки и список справочника. */
.tender-label-form {
    display: grid;
    gap: 8px;
    margin-top: 8px;
}

.tender-label-rows {
    display: grid;
    gap: 0;
    margin: 12px 0 0;
    padding: 0;
    list-style: none;
}

.tender-label-rows > li {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 8px 0;
    border-top: 1px solid var(--border);
}

.tender-label-rows > li > .row-actions {
    margin: 0 0 0 auto;
}

.tender-label-rows > li > .tender-label-form {
    flex: 1 1 100%;
    margin: 0;
}

@media (max-width: 720px) {
    .tender-labels {
        max-width: 100%;
    }
}

/* Звёздочка «избранное» у тендера в работе (partials/favorite-toggle) —
   на карточке списка и в шапке панели. Без рамки и заливки, значком:
   неотмеченная серая, отмеченная — цветом предупреждения. */
.btn-favorite {
    display: inline-flex;
    align-items: center;
    padding: 2px;
    border: 0;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--text-faint);
    cursor: pointer;
}

.btn-favorite:hover,
.btn-favorite:focus-visible {
    color: var(--warn);
}

.btn-favorite.is-favorite {
    color: var(--warn);
}

.btn-favorite .icon {
    width: 18px;
    height: 18px;
}

.deal-number {
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

/* Заказчик — пунктиром, как в дизайне: читается сведением, а не
   обычной ссылкой посреди текста. */
.customer-link,
.customer-name {
    color: var(--text-muted);
    font-size: var(--fs-control);
}

.customer-link {
    border-bottom: 1px dotted var(--text-faint);
    text-decoration: none;
}

.customer-link:hover,
.customer-link:focus-visible {
    color: var(--accent-text);
    border-bottom-color: var(--accent);
    text-decoration: none;
}

.deal-signals {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 10px;
}

.deal-signals:empty {
    display: none;
}

.deal-card-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}

.deal-price {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
}

.deal-price strong {
    font-size: var(--fs-card-title);
    font-weight: 800;
}

/* «Подбор» и «Подробнее» в подвале карточки — рядом, справа. */
/* Экран «Подробнее» кабинета «Подача» (tender-modal/submission/modal) —
   во весь экран, разметкой панели карточки (.drawer-topbar, .drawer-head,
   .drawer-tabs, .drawer-panel): шапка, вкладки и подвал не сжимаются,
   прокручивается тело. */
.modal.submission-screen {
    background: var(--bg);
}

.submission-screen .drawer-head,
.submission-screen .drawer-tabs,
.submission-screen .drawer-footer {
    flex-shrink: 0;
}

.submission-screen .modal-body {
    flex: 1 1 auto;
    padding: 20px 22px 28px;
}

/* Формат заявки — два варианта карточками; выбранный — рамкой акцента. */
.application-format {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 10px;
    margin-bottom: 16px;
}

.application-format-option {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    cursor: pointer;
}

.application-format-option > span {
    display: grid;
    gap: 3px;
}

.application-format-active {
    border-color: var(--accent);
    background: var(--accent-wash);
}

/* Разбор извещения — первым во вкладке «Документы». */
.notice-analysis-text {
    line-height: 1.55;
}

/* Структурированная заявка (submission/application-structured): сводка с
   «Заявка проверена» полосой сверху, позиции слева для перехода, справа —
   блоками, как в форме площадки. */
.application-verify-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 18px;
    padding: 12px 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow);
    font-variant-numeric: tabular-nums;
}

/* Плашки сводки — отбор строк заявки по итогу проверки: кнопкой вида
   плашки, выбранная — обведена рамкой своего цвета. */
.application-filter-pill {
    border: 1px solid transparent;
    font-family: inherit;
    line-height: inherit;
    cursor: pointer;
}

.application-filter-pill:hover,
.application-filter-active {
    border-color: currentColor;
}

.application-verify-action {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin-left: auto;
}

/* Рабочая область — по высоте экрана (public/js/application-area.js):
   колонки прокручиваются внутри, верхний край тянется. */
.application-area {
    display: flex;
    flex-direction: column;
    margin-top: 14px;
}

.application-layout {
    display: grid;
    flex: 1 1 auto;
    min-height: 0;
    grid-template-columns: 260px minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    gap: 16px;
}

/* Панель области: в потоке заполняет элемент; поднятая выше тела экрана —
   position: fixed поверх шапки и вкладок (стиль ставит скрипт), на белом
   фоне с тенью. Подвал экрана ниже неё и не перекрывается. */
.application-area-panel {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.application-area-raised .application-area-panel {
    z-index: 20;
    box-sizing: border-box;
    padding: 0 12px 12px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 12px 40px rgba(11, 23, 57, .22);
}

/* Сводка заявки — первой строкой панели области: видна и в поднятой. */
.application-area-panel > .application-verify-bar {
    flex-shrink: 0;
    margin: 0 0 8px;
}

.application-area-raised .application-area-panel > .application-verify-bar {
    margin-top: 12px;
}

/* Край области: ручка во всю ширину и значок «на весь экран» справа. */
.application-area-top {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    margin-bottom: 4px;
}

.application-area-max {
    flex-shrink: 0;
}

.application-area-resize {
    flex: 1 1 auto;
    align-self: stretch;
    display: flex;
    align-items: center;
    min-height: 12px;
    /* Полоска — посередине области, а не остатка рядом со значком. */
    padding-left: calc(var(--control-h) + 8px);
    cursor: ns-resize;
    touch-action: none;
}

.application-area-resize::after {
    content: "";
    display: block;
    width: 48px;
    height: 4px;
    margin: 0 auto;
    border-radius: 2px;
    background: var(--border-strong);
}

.application-area-resize:hover::after {
    background: var(--accent);
}

html.application-area-resizing,
html.application-area-resizing * {
    cursor: ns-resize !important;
    user-select: none;
}

.application-nav {
    display: grid;
    align-content: start;
    gap: 2px;
    overflow-y: auto;
    padding: 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
}

.application-nav-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border-radius: var(--radius-sm);
    color: var(--text);
    font-size: var(--fs-control);
    text-decoration: none;
}

.application-nav-item:hover {
    background: var(--row-hover);
}

.application-nav-name {
    flex: 1;
    min-width: 0;
}

.application-nav-done {
    color: var(--text-muted);
}

.application-nav-done .icon {
    color: var(--success-text);
}

.application-positions {
    display: grid;
    align-content: start;
    gap: 14px;
    min-width: 0;
    overflow-y: auto;
    padding-right: 4px;
}

.application-position {
    scroll-margin-top: 12px;
}

.application-position-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px 14px;
    margin-bottom: 10px;
}

.application-position-head h3 {
    margin: 0;
    font-size: var(--fs-card-title);
}

.application-transferred {
    margin-left: auto;
}

/* Характеристика и требование — по четверти, значение — пошире: его
   правят и копируют. */
.application-form-table th:nth-child(1),
.application-form-table th:nth-child(2) {
    width: 24%;
}

.application-form-table th:nth-child(3) {
    width: 28%;
}

.application-form-table .application-value input {
    width: 100%;
    min-width: 8em;
}

@media (max-width: 720px) {
    .application-layout {
        grid-template-columns: minmax(0, 1fr);
    }

    .application-layout {
        grid-template-rows: none;
    }

    .application-nav,
    .application-positions {
        overflow: visible;
    }

    .application-area-top {
        display: none;
    }
}

/* Вкладка «1С» «Исполнения» (tender-modal/execution/onec): шаги с номером,
   итог машинной сверки, таблица цен в области по высоте экрана
   (.application-area, верхний край тянется), расхождение с контрактом. */
.onec-step-num {
    display: inline-grid;
    place-items: center;
    width: 22px;
    height: 22px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--accent-wash);
    color: var(--accent-text);
    font-size: var(--fs-meta);
    font-weight: 800;
}

.onec-step-done .onec-step-num {
    background: var(--success-wash);
    color: var(--success-text);
}

.onec-check {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 8px 14px;
    margin-bottom: 10px;
    padding: 10px 14px;
    border-radius: var(--radius-sm);
}

.onec-check ul,
.onec-reasons ul {
    margin: 0;
    padding-left: 18px;
}

.onec-check-ok {
    background: var(--success-wash);
}

.onec-check-bad {
    background: var(--danger-wash);
    color: var(--danger-text);
}

.onec-area {
    margin-top: 0;
}

.onec-table-wrap {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

/* УИД номенклатуры 1С в таблице цен — моноширинным, не шире 20em:
   36 знаков GUID целиком видны при наведении (title). */
.onec-table td.onec-uuid {
    max-width: 20em;
    font-size: var(--fs-meta);
    word-break: break-all;
}

.onec-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    white-space: nowrap;
}

.onec-table td.num {
    white-space: nowrap;
}

.onec-table tr.onec-row-bad td {
    background: var(--danger-wash);
}

.onec-price {
    width: 8em;
    text-align: right;
}

.onec-diff {
    display: block;
    color: var(--danger-text);
    font-weight: 700;
}

/* «Найти по номерам закупок» на «Ключах поиска»: итог по номеру строкой. */
.number-search-list {
    display: grid;
    gap: 4px;
    margin: 6px 0 0;
    padding-left: 18px;
}

/* Корзина «Удалить» посередине подвала карточки (<x-tender-trash>) на
   «Подобранных», «В работе» и в очереди «Подачи»: тихая, красная при
   наведении. Подвал с корзиной — три колонки (цена, корзина, «Подробнее»),
   крайние равные и сжимаемые (minmax(0, 1fr)), — корзина всегда ровно по
   центру карточки и не растягивает её шире столбца доски. */
.deal-card-footer:has(> .deal-remove) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
}

.deal-card-footer:has(> .deal-remove) > .deal-card-actions {
    justify-self: end;
}

.deal-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--text-faint);
    cursor: pointer;
}

.deal-remove:hover,
.deal-remove:focus-visible {
    color: var(--danger-text);
    background: var(--danger-wash);
}

.deal-remove .icon {
    width: 18px;
    height: 18px;
}

.deal-card-actions {
    display: inline-flex;
    align-items: center;
    gap: 14px;
}

.deal-more {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--text);
    font-weight: 800;
    font-size: var(--fs-control);
}

.deal-more:hover,
.deal-more:focus-visible {
    color: var(--accent-text);
}

/* Срок подачи меткой (x-deadline): цвет — по запасу времени. */
.deadline {
    display: inline-flex;
    align-items: center;
    width: fit-content;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: var(--fs-meta);
    font-weight: 800;
    white-space: nowrap;
}

.deadline-normal {
    background: var(--calm-wash);
    color: var(--calm-text);
}

.deadline-soon {
    background: var(--warn-wash);
    color: var(--warn-text);
}

.deadline-critical,
.deadline-expired {
    background: var(--danger-wash);
    color: var(--danger-text);
}

/* ---------- пояснения ----------

   Уведомлений и оповещений в странице нет: все они — во всплывающем
   окне слева внизу (.v-toast, <x-toasts />, <x-notify>). Здесь — только
   пояснения, которые остаются частью страницы: почему список пуст, что
   не вошло в разбор, какие строки файла с замечаниями. .callout — к
   сведению, .callout.warn — стоит обратить внимание. Вид тот же, что у
   всплывающих уведомлений: полоса слева и фон её цвета.

   Плашек .alert (итог действия, ошибки формы, состояние записи) больше
   нет — они переехали во всплывающие уведомления. */

/* Плашкой с тонкой рамкой её же цвета и скруглением, как пояснения в
   дизайне. Текст — основным цветом: пояснение читают, а не замечают. */
.callout {
    padding: 11px 14px;
    border: 1px solid var(--accent-line);
    border-radius: 10px;
    background: var(--accent-wash);
    color: var(--text);
    font-size: var(--fs-body);
    line-height: 1.6;
    margin-bottom: 12px;
}

/* Последний абзац или список не добавляет свой отступ к внутреннему
   полю — иначе снизу у сообщения поле вдвое больше, чем сверху. */
.callout > :last-child {
    margin-bottom: 0;
}

.callout.warn {
    border-color: var(--warn-line);
    background: var(--warn-wash);
    color: var(--warn-text);
}

.callout ul {
    margin: 0;
    padding-left: 18px;
}

/* ---------- метки ---------- */

.pill {
    display: inline-block;
    font-size: var(--fs-meta);
    font-weight: 800;
    padding: 3px 10px;
    border-radius: 999px;
    white-space: nowrap;
    background: var(--accent-wash);
    color: var(--accent-strong-text);
    letter-spacing: normal;
}


.pill-muted {
    background: var(--surface-2);
    color: var(--text-muted);
    font-weight: 600;
}

.pill-warn {
    background: var(--warn-wash);
    color: var(--warn-text);
}

.pill-danger {
    background: var(--danger-wash);
    color: var(--danger-text);
}

.pill-ok {
    background: var(--success-wash);
    color: var(--success-text);
}

/* Карточка входа и регистрации: узкая колонка по центру экрана. */
.auth-card {
    max-width: 420px;
    margin: 48px auto;
    padding: 28px;
}

/* ---------- оболочка: боковая панель, верхняя строка, рабочая область ----------

   Раскладка по дизайну Vectra: навигация — боковой панелью слева
   (x-sidebar), над содержимым — верхняя строка с именем и «Выйти»
   (x-topbar), содержимое — колонкой в рабочей области (.workspace)
   справа от панели. Панель вне потока (position: fixed), рабочая
   область отодвинута от неё полем слева: прокручивается только
   содержимое, панель стоит на месте.

   z-index панели и строки — 500, ниже панели ИИ (800) и окон (900). */

.sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 500;
    display: flex;
    flex-direction: column;
    width: var(--sidebar-w);
    border-right: 1px solid var(--border);
    background: var(--surface);
}

.sidebar-brand {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    height: 76px;
    padding: 6px 23px;
}

.sidebar-brand img {
    width: 132px;
    height: auto;
}

/* Разделы прокручиваются внутри панели, если не уместились по высоте:
   кто вошёл — внизу, и низкое окно не должно его прятать. */
/* Меню уплотнено, чтобы на экране 1366×768 помещаться без прокрутки
   (так решено): прокрутка сбрасывалась при каждом переходе, и меню
   «прыгало». На окнах ниже прокрутка есть, и её держит
   public/js/sidebar-scroll.js. */
.sidebar-nav {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 10px 14px 8px;
}

.sidebar-group {
    display: grid;
    gap: 2px;
    /* Промежуток между разделами меню (так решено: прежние 16px читались
       слитно; 22px сменились 18px, когда встала группа «Дополнительные
       функции», — вместе с пунктами ниже 6px отступа и шагами маршрута в
       34px меню снова помещается на 1366×768 без прокрутки) —
       «Операции», «Справочники», «DEV» отделены от соседей. */
    margin-top: 18px;
}

.sidebar-group-title {
    margin: 0 11px 5px;
    color: var(--text-faint);
    font-size: var(--fs-meta);
    font-weight: 800;
    letter-spacing: .11em;
    text-transform: uppercase;
}

/* Пункт меню (x-nav-link) — строкой во всю ширину панели. Текущий —
   заливкой акцента и цветом акцента, а не чертой под словом, как было
   в полосе меню: в столбце пунктов черта читалась бы разделителем. */
.sidebar-nav a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 6px 12px;
    border-radius: 10px;
    color: var(--text-muted);
    font-size: var(--fs-subsection);
    font-weight: 700;
    text-decoration: none;
}

.sidebar-nav a:hover,
.sidebar-nav a:focus-visible {
    background: var(--surface-2);
    color: var(--text);
    text-decoration: none;
}

.sidebar-nav a.active {
    background: var(--accent-wash);
    color: var(--accent-text);
}

/* «Ключи поиска» — выделенной карточкой над группами: с них начинается
   работа, по ключам подбираются тендеры. */
.sidebar-group-accent {
    margin-top: 0;
    padding: 5px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: linear-gradient(135deg, var(--accent-wash), var(--surface));
}

.sidebar-group-accent a {
    color: var(--accent-text);
}

.sidebar-group-accent a:hover,
.sidebar-group-accent a:focus-visible {
    background: rgba(255, 255, 255, .72);
    color: var(--accent-text);
}

.sidebar-group-accent a.active {
    background: var(--surface);
    box-shadow: 0 4px 14px rgba(36, 85, 214, .09);
}

/* «Тендеры» — маршрутом из четырёх шагов, как в дизайне: кружок с буквой
   этапа своего цвета, кружки соединены вертикальной линией, у текущего —
   заливка цвета шага и черта слева. Шаг без доступа — приглушённым
   текстом, не ссылкой. Счётчик (.sidebar-count) — пилюлей справа. */
.sidebar-nav .sidebar-step {
    --step-color: var(--accent);
    --step-wash: var(--route-blue-wash);
    position: relative;
    justify-content: flex-start;
    gap: 10px;
    min-height: 34px;
    padding: 4px 10px;
}

.sidebar-step-cyan {
    --step-color: var(--route-cyan);
    --step-wash: var(--route-cyan-wash);
}

.sidebar-step-violet {
    --step-color: var(--route-violet);
    --step-wash: var(--route-violet-wash);
}

.sidebar-step-green {
    --step-color: var(--route-green);
    --step-wash: var(--route-green-wash);
}

.sidebar-step-marker {
    position: relative;
    z-index: 2;
    display: grid;
    place-items: center;
    flex: 0 0 24px;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--step-wash);
    color: var(--step-color);
    font-size: var(--fs-meta);
    font-weight: 900;
}

.sidebar-step-label {
    flex: 1;
    min-width: 0;
}

/* Линия между кружками — от низа кружка до верха следующего. */
.sidebar-route .sidebar-step:not(:last-child)::after {
    content: "";
    position: absolute;
    z-index: 1;
    top: 32px;
    left: 21px;
    width: 1px;
    height: 18px;
    background: var(--route-line);
    pointer-events: none;
}

.sidebar-nav a.sidebar-step:hover,
.sidebar-nav a.sidebar-step:focus-visible {
    background: var(--step-wash);
    color: var(--text);
}

.sidebar-nav a.sidebar-step.active {
    background: var(--step-wash);
    box-shadow: inset 3px 0 0 var(--step-color);
    color: var(--text);
}

.sidebar-step-locked {
    display: flex;
    align-items: center;
    border-radius: 10px;
    color: var(--text-faint);
    font-size: var(--fs-subsection);
    font-weight: 700;
    cursor: not-allowed;
}

.sidebar-step-locked .sidebar-step-marker {
    opacity: .5;
}

.sidebar-count {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    min-width: 24px;
    height: 22px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--nav-count-bg);
    color: var(--text-muted);
    font-size: var(--fs-meta);
    font-weight: 800;
}

.sidebar-nav a.active .sidebar-count {
    background: var(--surface);
    color: var(--step-color, var(--accent-text));
}

/* Блок реквизитов досье (organization/dossier): форма и просмотр одной
   колонкой, блоки по смыслу — «Организация», «Адреса», «Руководитель»,
   «Контакты», «Банк»; между блоками черта и отступ, заголовок — h3. */
.requisites-block + .requisites-block {
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
}

.requisites-block > h3 {
    font-size: var(--fs-card-title);
    margin-bottom: 10px;
}

/* Кто вошёл — внизу панели: имя ссылкой на профиль и рядом значками
   «Главная» и «Организация» (из разделов меню они перенесены сюда). */
.sidebar-user {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    gap: 2px;
    padding: 10px 8px;
    border-top: 1px solid var(--border);
    background: var(--surface);
}

.sidebar-user-profile {
    display: flex;
    align-items: center;
    flex: 1 1 auto;
    gap: 8px;
    min-width: 0;
    padding: 4px;
    border-radius: 10px;
    color: var(--text);
    text-decoration: none;
}

a.sidebar-user-profile:hover,
a.sidebar-user-profile:focus-visible,
.sidebar-user-profile.active {
    background: var(--accent-wash);
    text-decoration: none;
}

.sidebar-home {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    border-radius: 10px;
    color: var(--text-muted);
}

.sidebar-home .icon {
    width: 18px;
    height: 18px;
}

.sidebar-home:hover,
.sidebar-home:focus-visible {
    background: var(--surface-2);
    color: var(--text);
}

.sidebar-home.active {
    background: var(--accent-wash);
    color: var(--accent-text);
}

.sidebar-avatar {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--accent), var(--ai));
    color: #fff;
    font-size: var(--fs-body);
    font-weight: 800;
}

.sidebar-user-text {
    display: grid;
    min-width: 0;
}

.sidebar-user-text strong,
.sidebar-user-text small {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sidebar-user-text strong {
    font-size: var(--fs-lead);
    font-weight: 700;
}

.sidebar-user-text small {
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

/* Подложка под открытой на телефоне панелью — только там. */
.sidebar-scrim {
    display: none;
}

.workspace {
    min-height: 100vh;
    min-height: 100dvh;
    padding-left: var(--sidebar-w);
}

/* Верхняя строка держится у верхнего края при прокрутке. */
.topbar {
    position: sticky;
    top: 0;
    z-index: 500;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 16px;
    min-height: 68px;
    padding: 10px 34px;
    border-bottom: 1px solid rgba(220, 227, 238, .85);
    background: rgba(255, 255, 255, .9);
    backdrop-filter: blur(18px);
}

/* Логотип в строке — только на телефоне: на широком экране он в панели. */
.topbar-logo {
    display: none;
    width: 96px;
    height: auto;
}

.topbar-right {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
    font-size: var(--fs-body);
    color: var(--text-muted);
}

/* Имя пользователя не переносит строку и не растягивает строку:
   длинное ФИО обрезается многоточием. */
.topbar-user {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 700;
}

/* Кнопка меню и её состояние.

   Состояние держит чекбокс, а не скрипт: оболочка лежит в layout, вне
   Livewire-компонентов, и меню должно открываться даже до того, как
   загрузятся скрипты. Сам чекбокс не прячется через display: none —
   так он остаётся доступен с клавиатуры, — а выводится за пределы
   экрана. */
.nav-state {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
}

.nav-button {
    display: none;
    align-items: center;
    gap: 8px;
    min-height: var(--control-h);
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    font-size: var(--fs-control);
    font-weight: 800;
    cursor: pointer;
    user-select: none;
}

/* Три полоски: средняя — сам элемент, крайние — его псевдоэлементы. */
.nav-bars,
.nav-bars::before,
.nav-bars::after {
    display: block;
    width: 17px;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
    content: '';
}

.nav-bars {
    position: relative;
}

.nav-bars::before {
    position: absolute;
    top: -6px;
}

.nav-bars::after {
    position: absolute;
    top: 6px;
}

/* ---------- раскладка ---------- */

/* Колонка содержимого — по дизайну: до 1180px, поля по 30px с каждой
   стороны, сверху и снизу просторнее, чем по бокам. */
.page {
    width: min(1180px, calc(100% - 60px));
    margin: 0 auto;
    padding: 40px 0 72px;
}

.page-narrow {
    max-width: 420px;
}

/* Гостю (вход, регистрация, сброс пароля) — логотип над карточкой
   формы, без панели и строки. */
.auth-page {
    padding-top: 32px;
}

.auth-logo {
    display: block;
    width: 168px;
    height: auto;
    margin: 0 auto;
}

.auth-page .auth-card {
    margin-top: 16px;
}

/* ---------- уведомления ----------

   Область вне потока: сколько бы сообщений ни появилось, содержимое
   страницы не сдвигается — это главное требование. Перекрытие допускается;
   уведомления прижаты к левому нижнему углу всего экрана (правый край
   занят панелью тендера) и лежат поверх боковой панели навигации.

   pointer-events отключены у контейнера и включены у самих уведомлений:
   пустая область не перехватывает клики по странице под собой. */

.v-toasts {
    position: fixed;
    bottom: 16px;
    left: 16px;
    z-index: 1000;
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: min(360px, calc(100vw - 32px));
    pointer-events: none;
}

.v-toast {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    border: 1px solid;
    border-radius: 12px;
    padding: 12px 14px;
    font-size: var(--fs-body);
    font-weight: 700;
    line-height: 1.45;
    box-shadow: 0 13px 32px rgba(11, 23, 57, .12);
    pointer-events: auto;
}

/* Цвет всего окошка, а не только полоски слева: характер сообщения должен
   читаться до того, как прочитан текст. */
.v-toast-info {
    background: var(--accent-wash);
    border-color: var(--accent-line);
    color: var(--accent-strong-text);
}

.v-toast-success {
    background: var(--success-wash);
    border-color: var(--success-line);
    color: var(--success-text);
}

.v-toast-warning {
    background: var(--warn-wash);
    border-color: var(--warn-line);
    color: var(--warn-text);
}

.v-toast-error {
    background: var(--danger-wash);
    border-color: var(--danger-line);
    color: var(--danger-text);
}

/* Несколько строк — ошибки формы списком — каждая своей строкой. */
.v-toast-text {
    white-space: pre-line;
}

.v-toast-action {
    flex-shrink: 0;
    background: none;
    border: 1px solid currentColor;
    border-radius: var(--radius-sm);
    color: inherit;
    font: inherit;
    padding: 2px 10px;
    cursor: pointer;
}

.v-toast-action:hover {
    background: var(--surface);
}

.v-toast-close {
    background: none;
    border: none;
    color: inherit;
    opacity: .6;
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    padding: 0 2px;
}

.v-toast-close:hover {
    opacity: 1;
}

/* ---------- отступы ----------

   Небольшой набор взамен утилит w3.css: он нужен там, где отступ — свойство
   конкретного места, а не компонента. */

/* Переход на соседний экран — строкой над заголовком страницы. Раньше эти
   ссылки стояли под содержимым, и чтобы уйти с длинного списка тендеров,
   его приходилось пролистывать до конца. Шрифт мельче основного: это
   служебная навигация, а не часть содержимого. */
.page-nav {
    margin: 0 0 10px;
    font-size: var(--fs-control);
    font-weight: 800;
}

/* Скрыты на всех страницах (так решено): переходы между разделами — в
   боковой панели. Разметка в шаблонах осталась; вернуть — убрать это
   правило. Ссылки на справочники логистики, жившие здесь, вынесены
   кнопками в действия её страницы. */
.page-nav {
    display: none;
}

/* ---------- окно ИИ-помощника ----------
   Панель у правого края, вне потока: её появление не двигает вёрстку.
   z-index ниже уведомлений (1000), чтобы сообщения оставались видны поверх
   неё, но выше обычного содержимого. */
.ai-toggle {
    position: fixed;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 800;
    border: 1px solid var(--border);
    border-right: none;
    border-radius: var(--radius-sm) 0 0 var(--radius-sm);
    background: linear-gradient(135deg, var(--accent), var(--ai));
    color: #fff;
    font: inherit;
    font-size: var(--fs-control);
    font-weight: 800;
    padding: 10px 12px;
    cursor: pointer;
    box-shadow: 0 7px 18px rgba(36, 85, 214, .2);
}

.ai-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 800;
    width: min(460px, 100vw);
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border-left: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
}

/* Заголовок панели — как у модального окна (.modal-head): поля,
   кегль и крестик те же, панель — то же окно, только у края. */
.ai-panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 16px 18px;
    border-bottom: 1px solid var(--border);
}

/* Прокручивается только содержимое: заголовок с крестиком остаётся на
   месте, сколько бы ни было переписки. */
.ai-panel-body {
    flex: 1;
    overflow-y: auto;
    padding: 16px 18px;
}

/* Кнопки заголовка (очистить переписку) — слева от крестика, одной группой. */
.ai-panel-head-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Низ панели — поле ввода переписки. Не прокручивается вместе с
   содержимым: как в мессенджере, оно всегда под рукой. */
.ai-panel-foot {
    flex-shrink: 0;
    padding: 12px 18px 14px;
    border-top: 1px solid var(--border);
    background: var(--surface);
}

/* ---------- переписка с помощником ----------
   Своя разметка, а не таблица: реплики разной длины, и у ответа помощника
   под текстом идёт таблица предложенных значений. Прокручивается
   содержимое панели (.ai-panel-body), поле ввода стоит под ним в
   закреплённом низу (.ai-panel-foot) — как в мессенджере. */
.chat {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 14px;
}

.chat-msg {
    border-radius: var(--radius);
    padding: 9px 12px;
    max-width: 80%;
    font-size: var(--fs-control);
    line-height: 1.55;
}

/* Запрос человека прижат вправо, ответ помощника влево — как в
   мессенджере. Сверх стороны у каждой реплики подпись автора
   (.chat-author): почта человека или «Vectra». */
.chat-user {
    align-self: flex-end;
    background: var(--surface-2);
}

.chat-assistant {
    align-self: flex-start;
    background: var(--surface);
    border: 1px solid var(--border);
}

/* Подпись автора — первой строкой внутри реплики. Почта бывает длинной и
   без пробелов, поэтому переносится где угодно, а не растягивает
   реплику. */
.chat-author {
    margin: 0 0 3px;
    font-size: var(--fs-meta);
    font-weight: 600;
    overflow-wrap: anywhere;
}

/* Поле ввода и кнопка — одной строкой, кнопка по нижнему краю поля. */
.chat-composer {
    display: flex;
    align-items: flex-end;
    gap: 8px;
    margin: 0 0 6px;
}

.chat-input {
    flex: 1;
    min-width: 0;
}

/* Переносы строк из ответа модели сохраняются: она разделяет ими мысли. */
.chat-text {
    margin: 0;
    white-space: pre-line;
}

.chat-fields {
    margin-top: 8px;
    font-size: var(--fs-control);
}

.chat-fields td {
    padding: 2px 10px 2px 0;
    vertical-align: top;
}

.chat-fields td:first-child {
    font-weight: 600;
}

.mt { margin-top: 14px; }
.mt-sm { margin-top: 8px; }
.mb { margin-bottom: 14px; }
.row-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

/* Кнопки поровну делят строку — «Отклонить»/«Взять в работу» и
   «Отклонить»/«Отменить» в окне отклонения должны быть одного размера, а
   .btn по умолчанию сидит по ширине своего текста. */
.row-actions-even { display: flex; gap: 8px; }
.row-actions-even .btn { flex: 1 1 0; min-width: 0; }

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

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

   Страница под окном не сдвигается — окно вне потока. */

.modal-scrim {
    position: fixed;
    inset: 0;
    z-index: 900;
    background: var(--scrim);
    backdrop-filter: blur(2px);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}

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

   :has() на теле документа, а не класс скриптом: окно живёт внутри
   Livewire-компонента и телу не родитель, а состояние «окно открыто» и так
   выражено его присутствием в разметке. */
body:has(.modal-scrim) {
    overflow: hidden;
}

/* Место под полосу прокрутки страницы держится всегда: иначе окно,
   отключив прокрутку тела, убирало полосу, и содержимое под ним
   раздвигалось на её ширину — при открытии карточки таблица сдвигалась,
   при закрытии возвращалась. */
html {
    scrollbar-gutter: stable;
}

/* Ширина — 90% от списка карточек (.page: max-width 1200px), а не своя
   постоянная величина: 90vw даёт ту же долю, пока страница ещё не
   упёрлась в свой предел, 90% от 1200px — после. Окно и так лежит в центре
   экрана (.modal-scrim это выставляет), а список карточек тоже отцентрован
   в .page — довод «по центру списка» и «по центру экрана» здесь один и тот
   же довод. На узком экране (720px и ниже) правило перекрывается ниже —
   там нужна вся ширина, а не пропорция. */
.modal {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 30px 80px rgba(11, 23, 57, .22);
    width: min(1080px, 90vw);
    max-height: calc(100vh - 40px);
    max-height: calc(100dvh - 40px);
    display: flex;
    flex-direction: column;
}

/* Модификатор для короткого текстового окна вроде подтверждения удаления —
   доля от списка карточек здесь ни при чём, а 864px для одной фразы и
   двух кнопок был бы пустым полем по сторонам. Окно всё равно накрывает
   уже открытую карточку тендера: оба .modal-scrim — position: fixed с
   одним z-index, и то, что позже в DOM, ложится сверху само. */
.modal-sm {
    width: min(420px, 90vw);
}

/* Окно, открытое из другого окна (форма товара и «Подобрать из
   номенклатуры» поверх карточки тендера), — 90% от окна-родителя:
   min(1080px, 90vw) × 0,9 = min(972px, 81vw). По 5% с каждого края
   родитель виден рамкой вокруг, и понятно, что окно открыто поверх него.
   Подтверждения (.modal-sm) правилом не затронуты — они маленькие на любом
   уровне; просмотр документа (.modal-full) — во весь экран. На узком
   экране — вся ширина, как у любого окна (медиазапрос ниже). */
.modal-nested {
    width: min(972px, 81vw);
}

.modal-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    padding: 18px 22px;
    border-bottom: 1px solid var(--border);
}

.modal-head h2,
.ai-panel-head h2 {
    margin: 0;
    font-size: var(--fs-title);
    line-height: 1.3;
    letter-spacing: -.035em;
}

/* Кнопка закрытия — в правом верхнем углу окна и панели помощника,
   одна на оба. */
.modal-close,
.modal-size,
.ai-panel-close {
    flex-shrink: 0;
    background: none;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text-muted);
    font-size: 24px;
    line-height: 1;
    padding: 2px 8px 5px;
    cursor: pointer;
    transition: background-color .15s ease, color .15s ease;
}

.modal-close:hover,
.modal-close:focus-visible,
.modal-size:hover,
.modal-size:focus-visible,
.ai-panel-close:hover,
.ai-panel-close:focus-visible {
    background: var(--surface-2);
    color: var(--text);
}

.modal-close:focus-visible,
.modal-size:focus-visible,
.ai-panel-close:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* Кнопки в правом верхнем углу окна: «на весь экран» и закрытие.
   «На весь экран» (<x-modal-size-toggle>) — у любого окна, кроме
   подтверждений (.modal-sm) и просмотра документа (он и так во весь
   экран). Вид — как у крестика; значок по высоте крестика. */
.modal-head-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

/* «На весь экран» и крестик — одной высоты и квадратом, высотой кнопки
   (--control-h): в строке они стоят рядом и с кнопками действий окна
   («Запустить AI-подбор»). */
.modal-close,
.modal-size {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: var(--control-h);
    height: var(--control-h);
    padding: 0;
}

.modal-size .icon {
    display: block;
    width: 20px;
    height: 20px;
}

/* Крестик маленького всплывающего окна — выпадающего списка меток, отбора
   по меткам, адресов поставки, подбора наценки. Вид тот же, что у
   .modal-close, размер — по окну: квадрат 28px вместо --control-h, окно
   в 300–420px не должно нести крестик в 40px. Стоит справа в строке
   заголовка окна (.popover-head). */
.modal-close.popover-close {
    width: 28px;
    height: 28px;
    font-size: 20px;
    border-radius: var(--radius-sm);
}

.popover-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px;
}

.popover-head > :first-child {
    min-width: 0;
    margin: 0;
}

/* Окно, раскрытое на весь экран, — во всю площадь, без полей вокруг, как
   просмотр документа (.modal-full). Состояние держит Alpine на самом окне
   (x-data), а не сервер: это вид, а не данные, и закрытое окно в
   следующий раз открывается обычного размера. */
.modal.modal-max {
    width: 100%;
    height: 100vh;
    height: 100dvh;
    max-height: none;
    border: none;
    border-radius: 0;
}

.modal-scrim:has(> .modal-max) {
    padding: 0;
}

/* ---------- карточка тендера — панель у правого края ----------

   По дизайну: карточка закупки выезжает справа во всю высоту экрана, а не
   стоит окном посередине. Наверху — номер, название, срок подачи и
   вкладки (tender-modal/…/head), ниже прокручивается содержимое вкладки,
   внизу — подвал с действиями (на «Подобранных»). Вложенные окна (форма
   товара, подтверждения) по-прежнему открываются посередине, поверх
   панели. */
.drawer-scrim {
    justify-content: flex-end;
    align-items: stretch;
    padding: 0;
}

.modal.drawer {
    width: min(720px, 100%);
    height: 100vh;
    height: 100dvh;
    max-height: none;
    border: none;
    border-left: 1px solid var(--border);
    border-radius: 0;
    background: var(--bg);
    box-shadow: var(--shadow-lg);
    animation: drawer-in .22s ease-out;
}

/* Раскрытая на весь экран панель — во всю ширину. */
.modal.drawer.modal-max {
    width: 100%;
}

@keyframes drawer-in {
    from { transform: translateX(40px); opacity: 0; }
    to { transform: none; opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .modal.drawer {
        animation: none;
    }
}

/* Верхняя строка панели — белая, с метками слева и «Закрыть» справа;
   ниже на сером фоне панели — номер, название, заказчик, срок и вкладки. */
.drawer-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-shrink: 0;
    padding: 14px 22px;
    border-bottom: 1px solid var(--border);
    background: var(--surface);
}

.drawer-topbar-start {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.drawer-topbar .drawer-badges {
    margin: 0;
}

.drawer-head {
    padding: 26px 22px 8px;
    border-bottom: none;
    background: none;
}

.drawer-title {
    min-width: 0;
}

.drawer-title .deal-number {
    margin: 0 0 10px;
}

.drawer-title h2 {
    overflow-wrap: anywhere;
}

/* Шапка, вкладки и подвал панели не сжимаются: панель — колонка флексом,
   и у полосы вкладок с overflow-x: auto минимальная высота — ноль. На
   длинной вкладке («Документы», «Позиции») браузер ужимал полосу вместе с
   прокручиваемым телом, и пункты меню срезались наполовину. Прокручивается
   только тело (.modal-body). */
.drawer .drawer-head,
.drawer .drawer-tabs,
.drawer .drawer-footer {
    flex-shrink: 0;
}

/* Вкладки панели — строкой с чертой акцента под выбранной, как в
   дизайне (вкладки списков — сегментами, .tabs). */
.drawer-tabs {
    display: flex;
    gap: 3px;
    overflow-x: auto;
    margin: 0 22px;
    padding: 0;
    border-bottom: 1px solid var(--border);
    background: none;
    scrollbar-width: none;
}

.drawer-tabs button {
    position: relative;
    flex: 0 0 auto;
    padding: 12px 13px 13px;
    border: 0;
    background: none;
    font: inherit;
    font-size: var(--fs-control);
    font-weight: 800;
    color: var(--text-muted);
    cursor: pointer;
}

.drawer-tabs button:hover {
    color: var(--text);
}

.drawer-tabs button:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: -3px;
    border-radius: 8px;
}

.drawer-tabs .drawer-tab-active,
.drawer-tabs .drawer-tab-active:hover {
    color: var(--accent-text);
}

.drawer-tab-active::after {
    position: absolute;
    right: 10px;
    bottom: -1px;
    left: 10px;
    height: 2px;
    background: var(--accent);
    content: '';
}

.drawer .modal-body {
    flex: 1 1 auto;
    padding: 20px 22px 28px;
}

/* Вкладка — белой карточкой на сером фоне панели, как разделы панели в
   дизайне. Последняя черта во вкладке не нужна — её край и так виден. */
.drawer-panel {
    padding: 18px 20px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    box-shadow: var(--shadow);
}

.drawer-panel > hr:last-child {
    display: none;
}

/* Граница «Работа с тендером» первой во вкладке — объектов закупки
   нет, и отделять товары не от чего. */
.drawer-panel > .section-divider:first-child {
    display: none;
}

/* Окно, открытое из панели (форма товара, «Подобрать товары»,
   подтверждения), — посередине самой панели, а не экрана, и 90% её
   ширины: родитель виден рамкой по краям, как у окна из окна
   (.modal-nested). Затемнение — во весь экран, а место для окна —
   полоса панели справа. */
.drawer-scrim > .modal-scrim {
    padding-left: calc(100vw - min(720px, 100vw) + 20px);
}

.drawer-scrim .modal-nested {
    width: min(648px, 90vw);
}

/* Подтверждение (.modal-sm) — всегда посередине экрана, откуда бы его ни
   открыли: из панели тоже, а не посередине её полосы. Одна фраза и две
   кнопки — не продолжение панели, а вопрос, который нельзя пропустить, и
   место у него одно на все случаи. */
.drawer-scrim > .modal-scrim:has(> .modal-sm),
.modal-scrim:has(> .modal-sm) {
    padding: 20px;
    align-items: center;
    justify-content: center;
}

/* Подвал с действиями — вне прокрутки, кнопки прижаты вправо. */
.drawer-footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 10px;
    padding: 14px 22px;
    border-top: 1px solid var(--border);
    background: var(--surface);
}

.drawer-footer > p {
    margin: 0;
}

/* Длинная карточка прокручивается внутри окна, а не растягивает его:
   высота окна ограничена высотой экрана, а лишнее уезжает в прокрутку
   этого блока. Инерционная прокрутка пальцем — для старых WebKit. */
.modal-body {
    padding: 16px 18px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
}

.modal-body h3 {
    margin-bottom: 8px;
}

/* Разделяет блоки карточки тендера (информация / действия / комментарии
   или причины отклонения) — своя черта, а не отступ: отступ сам по себе не
   читается как граница между разделами. */
.modal-body hr {
    border: none;
    border-top: 1px solid var(--border);
    margin: 16px 0;
}

/* Граница двух родов блоков карточки тендера (summary всех трёх страниц):
   выше — данные из источника, ниже — работа с тендером (товары, действия,
   обсуждение, причины). Толще обычной черты, цвета акцента и с подписью —
   иначе она терялась бы среди черт между блоками. Обычная черта прямо
   перед ней не выводится: две подряд читались бы сдвоенным штрихом. */
.section-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 24px 0 16px;
    font-size: var(--fs-meta);
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .04em;
}

.section-divider::after {
    content: "";
    flex: 1;
    border-top: 2px solid var(--accent);
}

.modal-body hr:has(+ .section-divider) {
    display: none;
}

/* ---------- сворачиваемые блоки карточки тендера ----------

   Участники, документы и объекты закупки — длинные списки, и открытая
   карточка читалась бы прокруткой мимо них. Свёрнуты по умолчанию,
   раскрываются заголовком. <details>, а не скрипт: работает до загрузки
   Livewire. Число в заголовке — чтобы по свёрнутому было видно, есть ли
   что раскрывать. */
.fold {
    margin-top: 14px;
}

.fold > summary {
    display: flex;
    align-items: center;
    gap: 8px;
    list-style: none;
    cursor: pointer;
    user-select: none;
}

.fold > summary::-webkit-details-marker {
    display: none;
}

/* Стрелка: вправо у свёрнутого, вниз у раскрытого. */
.fold > summary::before {
    content: '';
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    margin: 0 2px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(-45deg);
    transition: transform .15s;
}

.fold[open] > summary::before {
    transform: rotate(45deg);
}

.fold > summary:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

.fold > summary h3 {
    margin: 0;
}

.fold[open] > summary {
    margin-bottom: 12px;
}

/* Блок без заголовка: «Подбор товара» в панели рабочей таблицы — сразу
   поле поиска, как в дизайне. Раскрыт всегда, свернуть нечем. */
.fold.fold-bare {
    margin-top: 0;
}

.fold.fold-bare > summary {
    display: none;
}

/* ---------- документы тендера ----------

   Тот же строй, что у комментариев: карточка на запись, название сверху,
   серая строка под ним, действия внизу. Отдельные классы, а не общие с
   комментариями: у документа в шапке бейдж источника, и стоит ему
   разойтись с комментарием хоть в одном месте, общий набор селекторов
   пришлось бы растаскивать обратно. */
.docs {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    /* minmax(0, 1fr): иначе колонка растёт под длинное слово или MIME-тип
       и карточка уходит за край панели. */
    grid-template-columns: minmax(0, 1fr);
    gap: 6px;
}

.doc {
    min-width: 0;
    overflow-wrap: anywhere;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
}

.doc-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 10px;
    /* Без переноса: кнопка «исследовать ИИ» держится справа от названия и
       на узком экране, а сужается название (min-width: 0 у .doc-title). */
    flex-wrap: nowrap;
    margin-bottom: 4px;
    overflow-wrap: anywhere;
}

/* Значок типа файла рядом с названием — своя строка, а не второй ребёнок
   .doc-head: там уже действует justify-content: space-between под будущее
   содержимое справа, и второй прямой потомок разъехался бы по краям
   вместо того, чтобы стоять рядом с названием. */
.doc-title {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    font-size: var(--fs-control);
}

.doc-icon {
    width: 22px;
    height: 22px;
    flex: 0 0 auto;
}

/* Строки под названием — одним шагом 4px, тем же, что между названием
   и первой строкой: общий отступ абзаца (10px) разрывал карточку. */
.doc p {
    margin: 0;
}

.doc p + p {
    margin-top: 4px;
}


/* Файл, распакованный из архива, — под архивом со сдвигом вправо на
   каждый уровень вложенности. Сдвиг меньше на узком экране: три уровня
   по 24px съели бы четверть ширины телефона. */
.doc-unpacked {
    margin-left: calc(var(--depth, 1) * 24px);
}

@media (max-width: 720px) {
    .doc-unpacked {
        margin-left: calc(var(--depth, 1) * 12px);
    }
}

/* Кнопка без подписи, одним значком — «исследовать ИИ» у документа.
   Квадратная мишень не меньше 32px: в неё попадают пальцем. */
.btn-icon {
    padding: 6px;
    min-width: var(--control-h);
    min-height: var(--control-h);
    flex: 0 0 auto;
}

.btn-icon:disabled {
    opacity: .5;
    cursor: progress;
}

/* Строка о работе ИИ над разделом — «VECTRA сопоставила N из M» под
   списком «Номенклатура по ТЗ» во вкладке «Позиции»: мягкой заливкой
   акцента и серым текстом, как .positions-note в дизайне. */
.ai-note {
    margin: 12px 0;
    padding: 11px;
    border-radius: var(--radius-sm);
    background: var(--accent-wash);
    color: var(--text-muted);
    font-size: var(--fs-meta);
    line-height: 1.55;
}

/* Список «Номенклатура по ТЗ» во вкладке «Позиции» карточки тендера в
   работе (in-work/products), как .positions-list в дизайне: номер,
   наименование с примечанием и пилюлями, количество справа; строки
   разделены чертой. Наименование — кнопкой вида ссылки цветом текста:
   открывает «Подробнее». */
.positions-list {
    border-top: 1px solid var(--border);
}

.positions-list article {
    display: grid;
    grid-template-columns: 26px minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border);
}

.positions-list article > div {
    display: grid;
    gap: 3px;
    min-width: 0;
}

.positions-number,
.positions-quantity {
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

.positions-quantity {
    white-space: nowrap;
    text-align: right;
}

.btn-link.positions-name {
    justify-self: start;
    color: var(--text);
    font-size: var(--fs-control);
    font-weight: 700;
    text-align: left;
}

.positions-list small {
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

.positions-list .tender-product-mark {
    margin-top: 0;
}

/* Тот же список у объектов закупки и возможных участников
   (tender-modal/…/items, summary): наименование — текстом, а не кнопкой
   (подробнее открывать нечего), описание — не больше пяти строк, коды
   ОКПД2 и КТРУ — в одну строку мелким. */
.positions-list strong.positions-name {
    color: var(--text);
    font-size: var(--fs-control);
    font-weight: 700;
    overflow-wrap: anywhere;
}

.positions-detail,
.positions-codes {
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

.positions-codes {
    display: flex;
    flex-wrap: wrap;
    gap: 0 6px;
}

.positions-list .tender-product-mark:empty {
    display: none;
}

/* Оценка ИИ под строками документа — своим блоком за пунктирной чертой:
   это сказанное о документе, а не его свойства из источника. */
.doc-assessment {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed var(--border);
    font-size: var(--fs-meta);
    line-height: 1.55;
}

/* Суть документа — Markdown (Markdown::html): разделы жирным, списки.
   Старые справки простым текстом читаются так же — переносы сохраняются. */
.doc-assessment.fold {
    margin-top: 8px;
}

.doc-assessment.fold > summary {
    font-size: var(--fs-control);
}

.doc-assessment-summary {
    white-space: normal;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Пилюли типа документа (<x-document-type-pills>) — в строке документа,
   рядом с названием; не помещаются — переносятся под него. */
.doc-title {
    flex-wrap: wrap;
}

.doc-types {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 6px;
}

.doc-analysis-text {
    margin-top: 16px;
}

/* Заголовок анализа договора под справкой — крупнее её разделов. */
.doc-analysis-title {
    margin: 0 0 6px;
    font-size: var(--fs-subsection);
    font-weight: 800;
}

.doc-assessment-warning {
    font-size: var(--fs-meta);
    padding: 6px 10px;
}

/* Второй шаг анализа документа (анализ договора, НМЦ из обоснования) —
   свёрнутыми блоками под оценкой (tender-modal/in-work/documents). */
.doc-analysis {
    margin-top: 6px;
}

/* ---------- расчёты доставки в карточке тендера ----------
   Блок «Доставка» (tender-modal/in-work/delivery): строка на расчёт —
   дата кнопкой «Подробнее», маршрут и самый дешёвый тариф. */

.delivery-calculations {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 6px;
}

/* ---------- комментарии к тендеру ---------- */

.comments {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 10px;
}

.comment {
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.comment-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
    margin-bottom: 4px;
    font-size: var(--fs-meta);
}

.comment-body {
    margin: 0;
    white-space: pre-line;
    overflow-wrap: anywhere;
    font-size: var(--fs-meta);
    line-height: 1.55;
}

/* Строка действий записи — у документа («Открыть», «Скачать»,
   «Открыть на площадке») и у комментария или причины отклонения
   («Изменить», «Удалить») — одним видом: ссылки и кнопки-ссылки в ряд,
   мельче основного текста. */
.doc-actions,
.comment-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    font-size: var(--fs-meta);
}

.comment-actions {
    margin: 6px 0 0;
}

/* «Загрузить файл» у нескачавшегося документа — подпись-ссылка, а поле
   выбора файла под ней скрыто: щелчок по подписи открывает выбор файла
   сам, без скрипта. Скрыто не display: none — так поле остаётся в порядке
   Tab, и с клавиатуры до него можно дойти. */
.doc-upload {
    position: relative;
    cursor: pointer;
}

.doc-upload input[type="file"] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    overflow: hidden;
}

/* Действия правила подбора — малыми кнопками разного вида по последствию
   (Редактировать — .btn-primary, Отключить — .btn-warn, Удалить —
   .btn-danger), а не ссылками: так попросили, чтобы не промахнуться.

   Ряд — сеткой на три ячейки, а не переносом: в правке кнопок две
   («Сохранить», «Отмена») и третья ячейка пустая (.rule-actions-gap), так
   что строк в ряду столько же, сколько в просмотре, при любой ширине, — и
   по «Редактировать» ничего не смещается. На узком экране — по две в
   строку во всю ширину: три в ряд на 360px не помещаются. */
.comment-actions.rule-actions {
    display: grid;
    grid-template-columns: repeat(3, max-content);
    gap: 8px;
}

.rule-actions-gap {
    visibility: hidden;
}

@media (max-width: 720px) {
    .comment-actions.rule-actions {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* ---------- правка записи на месте ----------

   Правило подбора, комментарий к тендеру, причина отклонения правятся
   прямо в списке, и по «Редактировать» ничего не должно сместиться: ни
   сама запись, ни записи под ней, ни кнопки. Поэтому разметка записи в
   обоих режимах одна (шапка, текст, строка действий), а меняется только
   содержимое: абзац .inline-text становится полем .inline-text-input той
   же геометрии (компонент <x-inline-text>).

   Поле повторяет абзац: без своих отступов и рамки, со шрифтом и
   межстрочным интервалом записи, с теми же переносами (pre-wrap), высотой
   ровно по тексту (field-sizing: content, где его нет — скрипт
   компонента). Рамку рисует outline — он места не занимает. Правило
   «многострочное поле — не меньше пяти строк» здесь снято: пять строк под
   короткий комментарий и есть сдвиг. Поле растёт вниз при наборе — это
   правка, а не сдвиг от нажатия.

   Селекторы с textarea — чтобы перебить общие правила полей
   (textarea:not(.chat-input) и input, select, textarea выше в файле). */
.inline-text {
    margin: 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.inline-text-strong {
    font-weight: 600;
}

textarea.inline-text-input {
    display: block;
    width: 100%;
    max-width: 100%;
    min-height: 0;
    height: auto;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    font: inherit;
    line-height: inherit;
    color: inherit;
    resize: none;
    overflow: hidden;
    field-sizing: content;
    outline: 1px solid var(--border-strong);
    outline-offset: 2px;
}

textarea.inline-text-input.inline-text-strong {
    font-weight: 600;
}

textarea.inline-text-input:focus {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Шапка записи с правкой названия (правило подбора): название слева
   занимает всё свободное место — и в просмотре, и в правке одной ширины,
   поэтому переносится одинаково; прижато к верху, а не по базовой линии:
   у поля базовая линия своя, и шапка прыгала бы на пару пикселей. */
.comment-head.inline-head {
    align-items: flex-start;
    flex-wrap: wrap;
}

/* Не уже 14em: на узком экране метка и автор с датой иначе забирали всю
   строку, и название сжималось до столбика по букве, — теперь они
   уходят под него. */
.comment-head-main {
    flex: 1 1 14em;
    min-width: 0;
}

.comment-head-meta {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: baseline;
    gap: 4px 8px;
    min-width: 0;
}

/* Запись списка, которая сейчас не действует, — отключённое правило
   подбора (catalog/match-rules). Приглушена фоном и пунктирной рамкой, а
   не цветом букв: текст в контуре одного цвета; что именно с ней — пишет
   метка .pill-muted рядом с названием. */
.comment.comment-off {
    background: var(--surface-2);
    border-style: dashed;
}

/* ---------- средние экраны ----------

   От 721 до 1050px панель уже: содержимому на планшете нужно место. */
@media (max-width: 1050px) {
    :root {
        --sidebar-w: 210px;
    }

    .page {
        width: min(100% - 38px, 1180px);
    }

    .topbar {
        padding-left: 19px;
        padding-right: 19px;
    }
}

/* ---------- узкие экраны ----------

   Вторая точка перелома, а не единственная: до 720px это телефон или
   узкое окно, и разница в раскладке одна и та же на всём этом диапазоне —
   дробить его на несколько порогов незачем, вёрстка здесь колоночная и
   сама тянется. Выше уже стоит порог в 1024px — под мониторы, для
   которых вёрстка теперь и рассчитана в первую очередь; между 721px и
   1023px (планшет, нешироко открытое окно) действуют те же правила, что
   и от 1024px и выше, — раскладка одна, меняется только её ширина.

   Правило на будущее: новые страницы пользовательского контура проверять
   на этой ширине. Оно записано и в CLAUDE.md. */
/* ---------- «Подобранные»: ключевые запросы и быстрый переход ---------- */

/* «Ключевые запросы» — основная навигация раздела, как в дизайне
   (.general-key-navigation прототипа): подпись слева, кнопки ключей
   посередине (лишние прокручиваются вбок, страница не растягивается),
   ссылка на ключи справа. Кнопка ключа — название, бегущие точки, пока
   по нему идёт загрузка, и число тендеров. */
.key-queries {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 14px;
    border: 1px solid var(--accent-line);
    border-radius: var(--radius);
    background: var(--surface);
    padding: 10px;
    box-shadow: var(--shadow);
}

.key-queries-title {
    display: grid;
    gap: 2px;
    padding: 0 4px;
}

.key-queries-title span {
    color: var(--accent-text);
    font-size: var(--fs-control);
    font-weight: 800;
}

.key-queries-title small {
    color: var(--text-muted);
    font-size: var(--fs-meta);
    font-weight: 600;
}

.key-queries-tabs {
    display: flex;
    min-width: 0;
    gap: 4px;
    overflow-x: auto;
}

.key-query {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 7px;
    max-width: 280px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    padding: 8px 9px;
    color: var(--text-muted);
    font: inherit;
    font-size: var(--fs-meta);
    font-weight: 800;
    cursor: pointer;
}

.key-query:hover {
    background: var(--surface-2);
    color: var(--text);
}

.key-query-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.key-query-count {
    display: grid;
    flex: 0 0 auto;
    min-width: 22px;
    height: 22px;
    place-items: center;
    border-radius: 999px;
    background: var(--surface-2);
    padding: 0 5px;
    font-size: var(--fs-meta);
}

.key-query-active,
.key-query-active:hover {
    border-color: var(--accent-line);
    background: var(--accent-wash);
    color: var(--accent-text);
}

.key-query-active .key-query-count {
    background: var(--surface);
}

.key-queries-manage {
    padding: 8px;
    font-size: var(--fs-meta);
    font-weight: 800;
    white-space: nowrap;
}

/* «Быстрый переход» (.matched-navigation прототипа): подпись заглавными и
   строка переходов. Выключенный переход — на месте, приглушённым, с
   причиной в подсказке. */
.quick-routes {
    display: flex;
    align-items: center;
    gap: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    padding: 9px 10px;
}

.quick-routes-title {
    flex: 0 0 auto;
    color: var(--text-muted);
    font-size: var(--fs-meta);
    font-weight: 800;
    text-transform: uppercase;
}

.quick-routes-list {
    display: flex;
    flex: 1;
    min-width: 0;
    gap: 3px;
    overflow-x: auto;
}

.quick-route {
    flex: 0 0 auto;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    padding: 8px 9px;
    color: var(--text-muted);
    font: inherit;
    font-size: var(--fs-meta);
    font-weight: 800;
    white-space: nowrap;
    cursor: pointer;
}

.quick-route:hover:not(:disabled) {
    background: var(--surface-2);
    color: var(--text);
}

.quick-route-active,
.quick-route-active:hover:not(:disabled) {
    background: var(--accent-wash);
    color: var(--accent-text);
}

.quick-route:disabled {
    color: var(--text-faint);
    cursor: not-allowed;
    opacity: .6;
}

@media (max-width: 720px) {
    /* Ключевые запросы и быстрый переход — столбиком: подпись над
       кнопками, кнопки прокручиваются вбок. */
    .key-queries {
        grid-template-columns: minmax(0, 1fr);
        align-items: stretch;
    }

    .key-queries-manage {
        justify-self: start;
    }

    .quick-routes {
        flex-direction: column;
        align-items: stretch;
    }

    /* Поля страницы — 16px: на 360px экране каждый лишний пиксель
       отступа отъедается у содержимого. */
    .page {
        width: calc(100% - 32px);
        padding: 24px 0 56px;
    }

    /* Панель уезжает за левый край и выезжает по кнопке «Меню» в
       верхней строке; под ней — подложка, нажатие на которую закрывает. */
    .sidebar {
        width: min(300px, 86vw);
        z-index: 950;
        transform: translateX(-100%);
        transition: transform .2s ease;
        box-shadow: none;
    }

    .nav-state:checked ~ .sidebar {
        transform: none;
        box-shadow: 22px 0 60px rgba(11, 23, 57, .18);
    }

    .nav-state:checked ~ .sidebar-scrim {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 940;
        background: var(--scrim);
    }

    .workspace {
        padding-left: 0;
    }

    .topbar {
        justify-content: space-between;
        gap: 10px;
        min-height: 60px;
        padding: 8px 16px;
    }

    .nav-button,
    .topbar-logo {
        display: inline-flex;
    }

    .topbar-logo {
        margin-right: auto;
    }

    /* Пункт меню — высотой под палец. */
    .sidebar-nav a {
        padding: 12px;
    }

    /* Обводка при переходе с клавиатуры: сам чекбокс за пределами
       экрана, и без этого фокус на кнопке был бы не виден. */
    .nav-state:focus-visible ~ .workspace .nav-button {
        outline: 3px solid var(--focus-ring);
        outline-offset: 2px;
    }

    @media (prefers-reduced-motion: reduce) {
        .sidebar {
            transition: none;
        }
    }

    /* На телефоне заголовок страницы — ступенью мельче: и 28 px на 390 px
       ширины переносят длинное «Подобранные тендеры» на две строки. */
    :root {
        --fs-page: 24px;
    }

    .panel {
        padding: 12px 14px;
    }

    .auth-card {
        margin: 20px auto;
        padding: 20px;
    }

    /* Минимальная ширина включает прокрутку: без неё таблица сожмётся по
       ширине экрана и станет нечитаемой. */
    .table-scroll table {
        min-width: 560px;
    }

    /* Закреплённое наименование — уже: на 360px при 14em оно заняло бы
       почти весь экран, и прокручивать было бы нечего видеть. */
    .table-pin :is(th, td):nth-child(2),
    .table-pin-actions :is(th, td):nth-child(3),
    .table-scroll th.col-name {
        min-width: 9em;
    }

    /* Таблица с кнопками в строках: закреплён только столбец кнопок
       (кнопки в нём — столбиками по три, как и на широком экране). Три
       закреплённых столбца (кнопки, номер, наименование) занимали на
       390px около 300px, и на прокрутку оставалась полоса в палец
       шириной. Жирная черта и тень — у столбца кнопок, он теперь
       последний закреплённый. */

    .table-pin-actions :is(th, td):is(:nth-child(2), :nth-child(3)) {
        position: static;
        box-shadow: none;
    }

    /* Сбоку номер и наименование здесь не закреплены, но заголовок над
       ними — закреплён сверху, как вся строка заголовков. */
    .table-scroll .table-pin-actions thead th:is(:nth-child(2), :nth-child(3)) {
        position: sticky;
        left: auto;
        z-index: 3;
    }

    .table-pin-actions :is(th, td):first-child {
        box-shadow:
            2px 0 0 var(--border-strong),
            8px 0 8px -6px rgb(0 0 0 / calc(var(--scroll-left) * .25));
    }

    /* Карточка занимает ширину экрана целиком, поля внутри — поменьше. */
    .card {
        padding: 12px;
    }

    /* Отбор во всю ширину: выпадающий список с названиями ключей на 360px
       иначе ужимается до нечитаемого. */
    .filter {
        display: flex;
        width: 100%;
    }

    /* Поле с выпадающим списком (ключ поиска, адрес) — во всю ширину. */
    .combo {
        width: 100%;
    }

    /* Отбор по датам на узком экране: подпись над полями, поля делят
       строку поровну — два поля даты рядом с подписью на 360px не
       помещаются. */
    .filter-dates {
        flex-wrap: wrap;
    }

    .filter-range {
        display: flex;
        width: 100%;
    }

    .filter-range input[type="date"] {
        flex: 1 1 0;
        min-width: 0;
    }

    /* min-width: 0 — иначе список не сужается меньше самого длинного
       названия ключа и уводит строку отбора за край экрана. */
    .filter select {
        flex: 1 1 auto;
        min-width: 0;
        max-width: none;
    }

    /* Кнопки в карточке растягиваются на всю строку: три штуки рядом
       («Изменить», «Отключить», «Удалить») на 360px сходятся в узкие
       мишени, в которые пальцем не попасть. */
    .card-actions .btn {
        flex: 1 1 auto;
    }

    /* Подпись над значением, а не слева: на 360px колонка подписей
       отнимала бы у значений половину экрана. */
    .kv {
        grid-template-columns: 1fr;
        gap: 2px;
    }

    .kv dt {
        margin-top: 8px;
    }

    /* Карточка тендера занимает экран целиком: поля вокруг окна на
       телефоне — потерянное место, а содержимое там длинное. */
    .modal-scrim {
        padding: 0;
    }

    .modal {
        width: 100%;
        max-height: 100vh;
        max-height: 100dvh;
        height: 100dvh;
        border: none;
        border-radius: 0;
    }

    /* На узком экране любое окно и так во весь экран — раскрывать нечего. */
    .modal-size {
        display: none;
    }

    .drawer-scrim > .modal-scrim {
        padding-left: 0;
    }

    /* Столбец на телефоне — почти во всю ширину: соседний виден краем,
       и понятно, что доска листается вбок. */
    .key-column,
    .stage-board .key-column {
        flex: 0 0 min(320px, 86vw);
    }

    .drawer-scrim .modal-nested {
        width: 100%;
    }

    .drawer .modal-body {
        padding: 14px 12px 24px;
    }

    .drawer-panel {
        padding: 14px;
    }

    .drawer-footer {
        padding: 12px 16px;
    }

    .drawer-footer .btn {
        flex: 1 1 0;
    }

    /* Панель помощника во всю ширину: 460px на телефоне всё равно не
       помещаются, а щель слева только мешала бы. */
    .ai-panel {
        width: 100%;
    }

    .chat-msg {
        max-width: 92%;
    }

    /* Длинные значения в таблице предложений — списки слов без пробелов
       после запятых — иначе растягивают панель вбок. */
    .chat-fields td {
        overflow-wrap: anywhere;
    }
}

/* Просмотр документа — окно во весь экран поверх карточки тендера
   (tender-modal/…/document-viewer). Полей вокруг нет и на широком экране:
   документу нужна вся площадь, а карточка под окном всё равно не видна.
   Высота задана явно, а не max-height, как у .modal: фрейму с редактором
   тянуться не за чем — содержимое своей высоты у него нет. */
.modal-scrim-full {
    padding: 0;
}

.modal-full {
    width: 100%;
    height: 100vh;
    height: 100dvh;
    max-height: none;
    border: none;
    border-radius: 0;
}

.modal-full .modal-head h2 {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Фрейм занимает всё под заголовком: flex: 1 в колонке .modal, а
   min-height: 0 — чтобы блок мог сжаться меньше содержимого фрейма. */
.modal-viewer {
    flex: 1;
    min-height: 0;
}

.modal-viewer iframe {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
}

/* Рабочая таблица подбора (tender-modal/in-work/matching-workspace) — окно
   во весь экран, по дизайну «Подбор номенклатуры». Тело прокручивается
   целиком; таблица — своей прокруткой (.table-scroll), панель подбора
   товара — справа от неё, своей. Внутри панели карточки тендера окно во
   весь экран тоже: поля .drawer-scrim к нему не относятся. */
.drawer-scrim > .modal-scrim-full {
    padding: 0;
}

.matching-body {
    flex: 1;
    background: var(--bg);
}

.matching-title {
    display: grid;
    gap: 2px;
    min-width: 0;
}

.matching-title h2 {
    margin: 0;
}

.matching-title .muted {
    margin: 0;
}

/* Заказчик и плашки закона и способа закупки под названием тендера в шапке
   рабочей таблицы подбора — те же .pill-law и .pill-procedure, что в карточке. */
.matching-tender-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin: 2px 0 0;
    min-width: 0;
}

.matching-customer {
    color: var(--text-muted);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Сводка — одной полосой, как в дизайне: ячейки разделены чертой, а не
   отдельными карточками; готовность — шире, с полосой хода. */
.matching-summary {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr)) minmax(0, 2.4fr);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow);
    overflow: hidden;
}

.matching-summary > :is(div, button) {
    display: grid;
    gap: 2px;
    padding: 8px 14px;
}

.matching-summary > * + * {
    border-left: 1px solid var(--border);
}

/* Плитка сводки — она же отбор (кнопка): нажатая — заливкой акцента. Полоса
   слева — цвет статуса, как у строк таблицы (.row-tone-*). */
.matching-summary > .matching-tile {
    /* Подпись и число — в одной строке, число прижато вправо. */
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

.matching-tile {
    align-content: start;
    text-align: left;
    font: inherit;
    color: inherit;
    background: none;
    border: 0;
    cursor: pointer;
    box-shadow: inset 4px 0 0 transparent;
}

.matching-tile:hover {
    background: var(--row-hover);
}

.matching-tile-active,
.matching-tile-active:hover {
    background: var(--accent-wash);
}

.matching-tile-ready { box-shadow: inset 4px 0 0 var(--success); }
.matching-tile-review { box-shadow: inset 4px 0 0 var(--warn); }
.matching-tile-empty { box-shadow: inset 4px 0 0 var(--danger); }

/* Готовность — одной строкой: подпись, число, полоса, кнопка. Высота
   сводки — по плиткам, а не по столбику из четырёх строк. */
.matching-summary > .matching-progress {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 10px;
}

.matching-progress progress {
    flex: 1 1 60px;
    min-width: 60px;
}

/* Кнопка «Подтвердить все подобранные ИИ» — в заголовке столбца «Наша
   номенклатура» (products-grid.js, refreshHeaderAction()), под названием,
   по центру. */
.products-grid .match-header-title {
    display: block;
}

.products-grid .match-header-action {
    display: flex;
    justify-content: center;
    margin-top: 6px;
    text-transform: none;
    letter-spacing: normal;
}

.products-grid .match-header-action:empty {
    display: none;
}

.products-grid .match-header-action .btn {
    white-space: normal;
    text-wrap: balance;
}

.matching-summary span {
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

.matching-summary strong {
    font-size: var(--fs-stat);
    letter-spacing: -.04em;
}

.matching-progress progress {
    width: 100%;
    height: 6px;
    border: 0;
    border-radius: 999px;
    background: var(--tab-track);
    accent-color: var(--success);
    appearance: none;
}

.matching-progress progress::-webkit-progress-bar {
    border-radius: 999px;
    background: var(--tab-track);
}

.matching-progress progress::-webkit-progress-value {
    border-radius: 999px;
    background: var(--success);
}

.matching-progress progress::-moz-progress-bar {
    border-radius: 999px;
    background: var(--success);
}

/* Окно не прокручивается целиком: сводка, поиск и массовые действия
   стоят сверху, итог — внизу, а таблица занимает всё между ними и
   прокручивается сама, со своей строкой заголовков. Действие в таблице
   не уносит сводку и не сбивает место. На телефоне — обычная прокрутка
   окна. */
.matching-workspace .matching-body {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Реквизиты закупки в шапке рабочей таблицы — строкой ячеек, как в
   дизайне: подпись заглавными над значением, ячейки разделены чертой. */
/* Шапка окна: первой строкой — «Подбор номенклатуры» слева и кнопки справа,
   ниже — ряд реквизитов закупки во всю ширину окна: кнопки не заходят на
   него. .matching-title растворён (display: contents), чтобы заголовок и
   ряд реквизитов встали в разные строки одной сетки с кнопками. */
.matching-heading {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 6px 16px;
}

.matching-heading .matching-title {
    display: contents;
}

.matching-heading .matching-title h2 {
    grid-column: 1;
    grid-row: 1;
}

.matching-heading .modal-head-actions {
    grid-column: 2;
    grid-row: 1;
}

.matching-heading .matching-heading-details {
    grid-column: 1 / -1;
    grid-row: 2;
}

.matching-heading-details {
    display: grid;
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 1.2fr) minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, 1.1fr) minmax(0, .8fr);
    gap: 6px;
    margin-top: 8px;
}

.heading-detail {
    display: grid;
    align-content: start;
    gap: 4px;
    min-width: 0;
    padding-left: 10px;
    border-left: 1px solid var(--border);
}

.heading-detail:first-child {
    padding-left: 0;
    border-left: 0;
}

.heading-detail > span {
    color: var(--text-faint);
    font-size: var(--fs-meta);
    font-weight: 800;
    letter-spacing: .04em;
    text-transform: uppercase;
}

/* Подпись первой ячейки — «Закупка <номер>» — синей и с разрядкой, как был
   надзаголовок окна (.eyebrow). */
.heading-detail-tender > span {
    color: var(--accent-text);
    font-size: var(--fs-eyebrow);
    letter-spacing: .12em;
}

/* Название закупки в первой ячейке — до двух строк, целиком в title. */
.heading-detail > .heading-detail-name {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    white-space: normal;
    overflow-wrap: anywhere;
}

.heading-detail > strong,
.heading-detail-value {
    overflow: hidden;
    font-size: var(--fs-control);
    font-weight: 700;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.heading-detail-value {
    width: fit-content;
    max-width: 100%;
    padding: 0;
    border: 0;
    border-bottom: 1px dotted var(--text-faint);
    background: transparent;
    color: var(--text);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}

.heading-detail > div {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    min-width: 0;
}

.heading-detail .pill {
    border: 1px solid transparent;
    font-family: inherit;
    cursor: pointer;
}

/* Пилюли в ячейке шапки не умещаются — ячейки узкие, а .pill не переносит
   текст. Пилюли встают в следующую строку (flex-wrap у .heading-detail > div),
   а пилюля длиннее самой ячейки обрезается многоточием в одну строку; полный
   текст — в title. */
.heading-detail > div > .pill {
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}

span.pill.pill-law,
span.pill.pill-procedure {
    cursor: default;
}

.pill-neutral {
    border-color: var(--border) !important;
    background: var(--surface);
    color: var(--text-muted);
}

/* Адрес поставки — первым, «Ещё N» рядом; список всех и условия — во
   всплывающем окне под ними. */
.heading-address-control {
    position: relative;
    flex-wrap: nowrap !important;
}

.heading-address-control > .pill:first-child {
    min-width: 0;
    flex: 1;
    overflow: hidden;
    justify-content: flex-start;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.heading-address-control > .pill + .pill {
    flex: 0 0 auto;
}

.delivery-address-popover {
    position: absolute;
    top: calc(100% + 7px);
    left: 0;
    z-index: 70;
    width: min(420px, 72vw);
    overflow: hidden;
    border: 1px solid var(--accent-line);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-lg);
}

.delivery-address-popover > header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 11px 12px;
    border-bottom: 1px solid var(--border);
}

.delivery-address-popover > header > div {
    display: grid;
    gap: 3px;
}

.delivery-address-popover > header span {
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

.delivery-address-popover ol {
    display: grid;
    margin: 0;
    padding: 4px 12px 4px 34px;
}

.delivery-address-popover li {
    padding: 8px 0 8px 3px;
    border-bottom: 1px solid var(--border);
    font-size: var(--fs-control);
    line-height: 1.45;
}

.delivery-address-popover li:last-child {
    border-bottom: 0;
}

.delivery-address-popover dl {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin: 0;
    padding: 10px 12px;
    background: var(--surface-2);
}

.delivery-address-popover dl > div {
    display: grid;
    gap: 3px;
}

.delivery-address-popover dt {
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

.delivery-address-popover dd {
    margin: 0;
    font-size: var(--fs-control);
    font-weight: 700;
    line-height: 1.4;
}

/* Свёрнутый уровень окна (шапка, сводка, инструменты) — узкой полосой
   «Развернуть». */
.collapsed-workspace-bar {
    display: grid;
    grid-template-columns: 90px minmax(0, 1fr) auto;
    flex: 0 0 auto;
    align-items: center;
    gap: 10px;
    min-height: 30px;
    padding: 5px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}

.matching-workspace > .collapsed-workspace-bar {
    margin: 8px 18px 0;
}

.collapsed-workspace-bar:hover {
    border-color: var(--accent-line);
    background: var(--accent-wash);
}

.collapsed-workspace-bar > span,
.collapsed-workspace-bar > em {
    color: var(--accent-text);
    font-size: var(--fs-meta);
    font-style: normal;
    font-weight: 800;
    text-transform: uppercase;
}

.collapsed-workspace-bar > strong {
    overflow: hidden;
    font-size: var(--fs-control);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Ручка над таблицей — тянут вверх, и уровни сворачиваются. */
.table-resize-handle {
    position: relative;
    display: grid;
    flex: 0 0 auto;
    place-items: center;
    height: 12px;
    margin: -6px 0 2px;
    padding: 0;
    border: 0;
    background: transparent;
    cursor: ns-resize;
    touch-action: none;
    user-select: none;
}

.table-resize-handle > span {
    width: 54px;
    height: 3px;
    border-radius: 999px;
    background: var(--border-strong);
    transition: width 140ms ease, background 140ms ease;
}

.table-resize-handle:hover > span,
.table-resize-handle:focus-visible > span {
    width: 80px;
    background: var(--accent);
}

.matching-sticky {
    flex-shrink: 0;
    display: grid;
    gap: 10px;
    margin-bottom: 12px;
}

.matching-workspace .matching-layout {
    flex: 1;
    min-height: 0;
    grid-template-rows: minmax(0, 1fr);
}

.matching-workspace .matching-layout > div,
.matching-workspace .products-grid,
.matching-workspace .products-grid-table {
    height: 100%;
    min-height: 0;
}

.matching-workspace .matching-footer {
    flex-shrink: 0;
    margin-top: 8px;
}

@media (max-width: 720px) {
    .matching-heading-details {
        grid-template-columns: 1fr 1fr;
    }

    .heading-detail-tender {
        grid-column: 1 / -1;
    }

    /* Первая ячейка — закупка — на всю строку, дальше с левого края
       стоят чётные. */
    .heading-detail:nth-child(even) {
        padding-left: 0;
        border-left: 0;
    }

    .table-resize-handle {
        display: none;
    }

    .matching-workspace .matching-body {
        display: block;
        overflow: auto;
    }

    .matching-workspace .matching-layout > div,
    .matching-workspace .products-grid,
    .matching-workspace .products-grid-table {
        height: auto;
    }
}

.matching-state:empty {
    display: none;
}

/* Поиск и отбор — одной белой панелью, как в дизайне. */
.matching-toolbar {
    align-items: flex-end;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow);
}

.matching-search {
    flex: 1 1 320px;
    min-width: 0;
    margin: 0;
    /* Подпись «Поиск» — слева от поля, в одной строке с ним. */
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 10px;
}

.matching-search > span:first-child {
    flex: none;
}

.matching-search > .search-field {
    flex: 1 1 auto;
    font-weight: 400;
}

.matching-search input {
    flex: 1 1 auto;
    min-width: 0;
}

/* Массовые действия — строкой на заливке акцента, пока строки выделены. */
.matching-bulk {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    border: 1px solid var(--accent-line);
    border-radius: var(--radius-sm);
    background: var(--accent-wash);
}

/* Таблица во всю ширину окна: подбор одного товара — не колонкой рядом,
   а панелью у правого края (.matching-drawer). */
.matching-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
    align-items: start;
}

/* Вид «Подбор» рабочей таблицы — тот же Tabulator, что «Все столбцы»
   (.products-grid): ширину делят столбцы (fitColumns), характеристики и
   примечание вдвое шире. Строка, чей подбор открыт панелью справа, —
   заливкой акцента, вместе с закреплёнными ячейками. Своих правил ячеек у
   вида нет: «Цена закупки» — обычная ячейка таблицы, как остальные. */
.products-grid .tabulator-row.matching-row-active,
.products-grid .tabulator-row.matching-row-active .tabulator-cell.tabulator-frozen {
    background: var(--accent-wash);
}

.products-grid .grid-cell .doc-actions {
    margin: 4px 0 0;
}

/* Действие строки под нашей номенклатурой — одно по статусу («Подтвердить»
   и «Заменить», «Найти» и «Создать позицию») — в один ряд: строка не
   растёт в высоту. */
.products-grid .grid-cell .match-links {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 10px;
}

/* Вид «Подбор»: лимит строк текста ячейки — общий (--cell-lines), как у
   всех таблиц контура; целиком текст виден во всплывающей панели при
   наведении (.cell-peek); пилюли статуса — в ряд. */

.products-grid-match .catalog-status {
    flex-direction: row;
    flex-wrap: wrap;
}

/* Статус и действие строки — одним рядом под наименованием. */
.products-grid-match .match-cell-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    margin-top: 4px;
}

.products-grid-match .match-cell-foot > * {
    margin: 0;
}

.products-grid-match .match-cell-foot .catalog-status:not(:has(*)) {
    display: none;
}

/* Полоса статуса подбора слева у строки (ProductMatchResult::tone()) —
   на первой ячейке, в том числе закреплённой: зелёная — подтверждено,
   синяя — подобрано ИИ, жёлтая — требует решения, красная — не подобрано. */
.products-grid .tabulator-row.row-tone-ok .tabulator-cell:first-child { box-shadow: inset 3px 0 0 var(--success); }
.products-grid .tabulator-row.row-tone-ai .tabulator-cell:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.products-grid .tabulator-row.row-tone-warn .tabulator-cell:first-child { box-shadow: inset 3px 0 0 var(--warn); }
.products-grid .tabulator-row.row-tone-none .tabulator-cell:first-child { box-shadow: inset 3px 0 0 var(--danger); }
.products-grid .tabulator-row.row-tone-running .tabulator-cell:first-child { box-shadow: inset 3px 0 0 var(--text-faint); }

/* Флажки строк (вид «Подбор») — по центру ячейки. */
.products-grid .tabulator-cell.col-select,
.products-grid .tabulator-col.col-select .tabulator-col-content {
    display: flex;
    justify-content: center;
    padding-left: 8px;
}

.products-grid .grid-check {
    width: 16px;
    height: 16px;
    margin: 0;
    cursor: pointer;
}

/* Правимая ячейка — рамкой при наведении: видно, куда можно вводить,
   до двойного щелчка. */
.products-grid .tabulator-row .tabulator-cell.cell-editable:hover {
    outline: 1px dashed var(--accent-line);
    outline-offset: -3px;
    cursor: text;
}

/* Варианты «требует решения» прямо в ячейке «Наша номенклатура»: название,
   поставщик с ценой и «Выбрать» — столбиком под плашкой статуса. */
.products-grid .grid-cell .match-options {
    list-style: none;
    margin: 6px 0 0;
    padding: 0;
    display: grid;
    gap: 6px;
}

.products-grid .grid-cell .match-options li {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 8px;
}

.products-grid .grid-cell .match-option-name {
    font-weight: 700;
}

/* Подбор одного товара и форма позиции номенклатуры из рабочей таблицы
   — панелями у правого края, как карточка тендера (.modal.drawer).
   Форма позиции уже на 80px, как «Проверка заказчика»: открытая из
   панели подбора, она оставляет её край видным. Затемнение второго слоя
   не сгущается. Панель, открытая прямо из панели тендера, не получает
   полосы под окно (.drawer-scrim > .modal-scrim) — она сама у края. */
.drawer-scrim > .drawer-scrim {
    padding: 0;
}

.catalog-drawer-scrim {
    background: transparent;
}

.modal.drawer.catalog-drawer {
    width: min(640px, 100%);
}

.modal.drawer.catalog-drawer.modal-max {
    width: 100%;
}

.matching-footer {
    justify-content: space-between;
}

/* Финансовый итог — строкой внизу окна, вне прокрутки: всегда на виду. */
.matching-finance {
    flex-shrink: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 28px;
    padding: 10px 22px;
    border-top: 1px solid var(--border);
    background: var(--surface);
    box-shadow: 0 -4px 12px rgb(11 23 57 / .06);
}

.matching-finance > div {
    display: grid;
    gap: 2px;
}

.matching-finance span {
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

.matching-finance strong {
    font-variant-numeric: tabular-nums;
}

.matching-finance small {
    color: var(--text-faint);
    font-size: var(--fs-meta);
    font-weight: 400;
}

.matching-finance-main strong {
    font-size: var(--fs-card-title);
}

.matching-finance-margin strong {
    color: var(--success-text);
}

.matching-finance-loss strong {
    color: var(--danger-text);
}

/* Кнопки итога — справа, одной группой. */
.matching-finance-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-left: auto;
}

/* Наценка: ползунок до 300% и поле точного значения (можно больше). */
.matching-markup-control {
    display: flex;
    align-items: center;
    gap: 6px;
}

.matching-markup-control input[type="range"] {
    width: 140px;
    accent-color: var(--accent);
}

.matching-finance .matching-markup-input {
    width: 4.5em;
    height: 26px;
    padding: 2px 6px;
    text-align: right;
}

/* «Подогнать» — форма над кнопкой, вне потока: итог не сдвигается. */
.markup-fit {
    position: relative;
}

.markup-fit-popover {
    position: absolute;
    right: 0;
    bottom: calc(100% + 8px);
    z-index: 5;
    display: grid;
    gap: 8px;
    width: min(320px, 90vw);
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-lg);
}

.markup-fit-popover .row-actions {
    margin: 0;
}

/* Ячейка «Цена подачи»: ниже цены закупки — красным, отметки рядом. */
.bid-loss {
    color: var(--danger-text);
}

.bid-flag {
    margin-left: 4px;
}

button.bid-reset {
    cursor: pointer;
    border: 0;
    font-family: inherit;
}

/* Панель подбора одного товара: переходы по строкам в шапке и что выбрано
   сейчас — строкой под наименованием. */
.matching-drawer-nav {
    display: flex;
    align-items: center;
    gap: 8px;
}

.matching-drawer-status {
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
}

.matching-drawer-choice {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    margin: 6px 0 0;
}

/* Короткая форма новой позиции в панели подбора: поставщик и цена — рядом. */
.catalog-quick-row {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 12px;
}

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

    /* Заголовок и две кнопки на телефоне не помещаются в ряд — кнопки
       уходят строкой ниже, название не обрезается. */
    .matching-heading {
        grid-template-columns: minmax(0, 1fr);
    }

    .matching-heading .modal-head-actions {
        grid-column: 1;
        grid-row: 2;
    }

    .matching-heading .matching-heading-details {
        grid-row: 3;
    }

    .matching-summary > * + * {
        border-left: 0;
    }

    .matching-summary > :nth-child(n + 3) {
        border-top: 1px solid var(--border);
    }

    .matching-summary > :nth-child(even) {
        border-left: 1px solid var(--border);
    }

    .matching-summary .matching-progress {
        grid-column: 1 / -1;
        border-left: 0;
        flex-wrap: wrap;
    }
}

/* Объекты закупки в карточке тендера (tender-modal/…/items) — таблицей:
   это спецификация закупки, её сверяют по строкам. Тот же класс у
   возможных участников (tender-modal/…/summary): их сравнивают так же,
   по строкам и столбцам чисел. Номер — порядок в
   перечне закупки, по нему позицию называют в документации. Числа не
   переносятся: «1 250,00» в два ряда не читается. */
.tender-items td.num {
    white-space: nowrap;
}

.tender-items td {
    font-size: var(--fs-control);
}

/* Предпросмотр импорта номенклатуры (catalog/index, окно импорта) —
   таблицей, как объекты закупки: строки сверяют с файлом. Номер строки и
   числа не переносятся; пометка «что будет» — пилюля и под ней мелко,
   какие поля изменятся или почему строка пропущена. Ячейка, которую
   импорт поменяет, выделена фоном — видно, что именно перепишется. */
.import-preview td.num {
    white-space: nowrap;
}

.import-preview td .muted-note {
    display: block;
    margin-top: 2px;
}

.import-preview td.import-changed {
    background: var(--accent-wash);
}

/* Переход по страницам — только в предпросмотре импорта: в списках
   контура страниц нет, там «Загрузить ещё». Малые кнопки строкой, текущая
   страница — залитой. */
.pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin: 12px 0;
}

/* Коды классификаторов — мелко и без переноса внутри кода. */
.tender-item-codes {
    white-space: nowrap;
    font-size: var(--fs-meta);
}

/* Описание пишет заказчик абзацами — переносы сохраняются. */
.tender-item-description {
    margin-top: 4px;
    font-size: var(--fs-control);
    white-space: pre-line;
}

/* Оформленный Markdown внутри описания — переносы между тегами HTML
   (после каждого <li>, <p>) не показываются пустыми строками: pre-line
   родителя иначе превращал их в лишние строки между пунктами. Абзац
   внутри пункта «рыхлого» списка (пустая строка между пунктами в тексте)
   полей не добавляет. */
.tender-item-description .markdown-view {
    white-space: normal;
}

/* Таблица в сути документа (Markdown::assessment()): шире блока — прокрутка
   внутри себя, а не вылет за край панели. */
.markdown-view table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
    border-collapse: collapse;
    margin: 0 0 8px;
}

.markdown-view :is(th, td) {
    border: 1px solid var(--border);
    padding: 4px 8px;
    text-align: left;
    vertical-align: top;
}

.markdown-view th {
    background: var(--surface-2);
    white-space: nowrap;
}

.markdown-view li > p {
    margin: 0;
}

/* Ячейка таблицы — не больше пяти строк текста. Длинные характеристики и
   названия иначе растягивали строку на экран, и таблицу нельзя было
   окинуть взглядом. Обрезанное — многоточием, целиком — во всплывающей
   панели (.cell-peek, public/js/cell-clamp.js): при наведении, на
   телефоне — по нажатию. Обёртка — вокруг текста ячейки, а не вокруг
   пилюль и кнопок под ним: их обрезать нельзя.

   .cell-text — у обёртки, где лежит один текст, как его ввели
   (характеристики): переносы строк в нём сохраняются. Вокруг разметки
   из нескольких элементов её не ставят — перевод строки между тегами
   стал бы пустой строкой. */
.cell-clamp {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: var(--cell-lines);
    line-clamp: var(--cell-lines);
    overflow: hidden;
    overflow-wrap: anywhere;
}

.cell-text {
    white-space: pre-line;
}

/* Ширина боковой панели перетаскиванием левого края
   (public/js/drawer-resize.js, ширина — инлайновым width на панели).
   Раскрытая на весь экран и на узком экране панель — во всю ширину,
   поверх запомненной. */
html.drawer-resize,
html.drawer-resize * {
    cursor: ew-resize !important;
}

html.drawer-resizing {
    user-select: none;
}

.modal.drawer.modal-max {
    width: 100% !important;
}

@media (max-width: 720px) {
    .modal.drawer[style*="width"],
    .ai-panel[style*="width"] {
        width: 100% !important;
    }
}

/* Ширина столбца и высота строки перетаскиванием края
   (public/js/table-resize.js): курсор над краем — на всём документе,
   иначе над соседней ячейкой он сбрасывался бы на полпути; во время
   перетаскивания текст не выделяется. */
html.table-resize-col,
html.table-resize-col * {
    cursor: col-resize !important;
}

html.table-resize-row,
html.table-resize-row * {
    cursor: row-resize !important;
}

html.table-resizing {
    user-select: none;
}

/* Над окном (900), под уведомлениями (1000): уведомление важнее. */
.cell-peek {
    position: fixed;
    z-index: 950;
    max-width: min(560px, calc(100vw - 32px));
    max-height: 60vh;
    overflow: auto;
    padding: 8px 10px;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    box-shadow: 0 6px 20px rgb(0 0 0 / .15);
    font-size: var(--fs-control);
    overflow-wrap: anywhere;
}

.cell-peek[hidden] {
    display: none;
}

/* Кнопки в строке таблицы — квадратные, значком, в один ряд, в первом
   столбце (.col-actions). Подпись кнопки — в title и aria-label: её видно
   при наведении и её читает экранный диктор. Вид (ghost, primary, danger)
   — как у кнопок с подписью: смотреть — нейтральная, менять — акцентная,
   удалять — красная. Размер — .btn-sm, 28px: столбец кнопок закреплён, и
   его ширина считается от этого числа (--pin-actions у .table-pin).
   Кнопки встают столбиком сверху вниз, по три: первые три — в первый
   столбик, четвёртая начинает второй, и дальше так же. Четыре в ряд
   растягивали закреплённый столбец и отнимали место у прокручиваемой
   части. Рядов столько, сколько кнопок, но не больше трёх: одна-две
   кнопки не растягивают строку в высоту пустыми рядами. */
.col-actions {
    white-space: nowrap;
}

.row-icon-actions {
    display: grid;
    grid-auto-flow: column;
    grid-template-rows: 28px;
    grid-auto-columns: 28px;
    justify-content: start;
    gap: 4px;
    margin: 0;
}

.row-icon-actions:has(> :nth-child(2)) {
    grid-template-rows: repeat(2, 28px);
}

.row-icon-actions:has(> :nth-child(3)) {
    grid-template-rows: repeat(3, 28px);
}

.btn-icon.btn-sm {
    width: 28px;
    height: 28px;
    min-width: 28px;
    min-height: 28px;
    padding: 0;
}

.btn-icon.btn-sm:disabled {
    cursor: not-allowed;
}

.tender-product-buttons {
    flex-wrap: nowrap;
    margin: 0 0 6px;
}

/* Окно «Подобрать товары» (in-work/catalog-picker): товар — номер и
   наименование строкой, под ним «Подбор товара», выровненный по
   наименованию: номер стоит своим столбцом слева, поле — во втором,
   под названием. Между товарами — черта. */
.catalog-picker-item {
    display: grid;
    grid-template-columns: 3.5em minmax(0, 1fr);
    column-gap: 8px;
    padding: 10px 0;
    border-top: 1px solid var(--border);
}

.catalog-picker-num {
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.catalog-picker-body {
    grid-column: 2;
}

.catalog-picker-body > .fold {
    margin-top: 6px;
}


/* Метка «есть предложения» под наименованием и само предложение
   загрузки под значением поля (in-work/product-proposal): кто предлагает,
   значение и «Заменить / Отказаться». Чертой цвета предупреждения слева —
   чтобы предложение не читалось как значение строки. */
.tender-product-mark {
    margin-top: 4px;
}

.tender-product-proposal {
    margin-top: 6px;
    padding-left: 8px;
    border-left: 3px solid var(--warn);
    font-size: var(--fs-meta);
}

.tender-product-proposal .tender-product-buttons {
    margin: 4px 0 0;
    white-space: nowrap;
}

/* Форма из нескольких коротких полей — сеткой, по два-три в ряд, длинные
   (.form-grid-wide) — во всю ширину. Сейчас — форма товара тендера.
   На узком экране колонка одна: auto-fit сам сводит сетку к ней. */
.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    column-gap: 12px;
}

.form-grid-wide {
    grid-column: 1 / -1;
}

/* Повторяющаяся группа полей внутри формы — контактное лицо поставщика,
   цена позиции у поставщика: рамкой, как .panel, чтобы было видно, какие
   поля вместе, а убрать группу — кнопкой в её шапке. */
.form-group {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 10px 12px 2px;
    margin-bottom: 12px;
}

.form-group-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 8px;
    font-weight: 600;
}

/* Поле со своей кнопкой «Убрать» в строку — телефон, почта контактного
   лица: полей в списке сколько угодно, и каждое убирается отдельно. */
.field-line {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-bottom: 6px;
}

.field-line input {
    flex: 1;
    min-width: 0;
}

.field-line .btn {
    flex: none;
}

/* Строка поиска по номенклатуре в «Подборе товара» (in-work/catalog-search):
   поле с подписью занимает всю свободную ширину, кнопка «Автоматический
   поиск» — по своему тексту. */
.catalog-search-row .filter {
    flex: 1 1 16em;
    min-width: 0;
}

.catalog-search-row .filter {
    position: relative;
}

/* «Ищу…» поверх правого края поля, вне потока: в потоке она сдвигала
   таблицы «Подобрано» и «Найдено» вниз на время каждого запроса. */
.catalog-search-loading {
    position: absolute;
    right: 2.6em;
    bottom: 0.55em;
    margin: 0;
    pointer-events: none;
}

.catalog-search-row .filter input {
    flex: 1 1 auto;
    min-width: 0;
    width: 100%;
}

/* Поиск по номенклатуре в товаре тендера (in-work/catalog-search) — список
   своей панелью: фон --surface-2, рамка и полоса акцента сверху, заголовок
   («По смыслу» или «По названию и ОКПД2») отчёркнут от содержимого.
   Позиции внутри — таблицей, как все таблицы-спецификации
   (in-work/catalog-candidates, .tender-items .table-striped), на белом
   фоне: иначе нечётные строки без своей заливки были бы серыми, как
   панель, и таблица выглядела бы не как остальные. */
.catalog-list {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-top: 3px solid var(--accent);
    border-radius: var(--radius);
    padding: 10px 12px 2px;
    margin-bottom: 12px;
}

.catalog-list .tender-items {
    background: var(--surface);
}


.catalog-list-title {
    font-weight: 800;
    font-size: var(--fs-control);
    margin: 0 0 8px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border);
}


/* Пилюли состояния подбора из номенклатуры под наименованием товара
   (in-work/catalog-status) — в ряд, с переносом. */
.catalog-status {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

/* В рабочей таблице подбора — по одной пилюле на строке, прижаты влево. */
.products-grid .catalog-status {
    flex-direction: column;
    align-items: flex-start;
}

/* Окно «Логистика» по тендеру (tender-modal/in-work/logistics-workspace) и
   финансовый итог рабочей таблицы подбора — по экрану дизайна
   «Логистика». Фон окна и заголовок — общие с рабочей таблицей подбора
   (.matching-body, .matching-title). Маршрут — плашками в ряд, тарифы —
   карточками, выбранная — рамкой акцента. */
.logistics-route {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 10px;
}

.logistics-route > div,
.logistics-route > .field {
    display: grid;
    align-content: start;
    gap: 4px;
    margin: 0;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow);
}

.logistics-route span,
.selected-delivery > div > span {
    color: var(--text-muted);
}

.logistics-route strong {
    font-size: var(--fs-control);
    line-height: 1.45;
}

.logistics-route small {
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

.logistics-section-title {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}

.logistics-section-title h3,
.logistics-section-title p {
    margin: 0;
}

.logistics-empty {
    padding: 18px;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    color: var(--text-muted);
    text-align: center;
}

.tariff-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 10px;
}

.tariff-card {
    display: grid;
    gap: 4px;
    padding: 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.tariff-card:hover {
    border-color: var(--border-hover);
}

.tariff-card:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 0;
}

.tariff-card strong {
    font-size: var(--fs-stat);
    letter-spacing: -.04em;
}

.tariff-card small {
    color: var(--text-muted);
    font-size: var(--fs-meta);
    line-height: 1.5;
}

.tariff-card em {
    color: var(--accent-text);
    font-style: normal;
    font-weight: 800;
    font-size: var(--fs-meta);
}

.tariff-card-selected {
    border: 2px solid var(--accent);
    background: var(--accent-wash);
}

.tariff-company {
    font-weight: 700;
    font-size: var(--fs-meta);
}

.selected-delivery {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 14px;
    border: 1px solid var(--accent-line);
    border-radius: var(--radius-sm);
    background: var(--accent-wash);
}

.selected-delivery > div {
    display: grid;
    gap: 2px;
}

/* Метка способа закупки в карточке тендера (x-tender-card) — как
   .procedure в дизайне: серая, обычной насыщенности, чтобы не спорить с
   метками состояния рядом. */
.pill-procedure {
    background: var(--surface-2);
    color: var(--text-faint);
    font-weight: 600;
}

/* Закон закупки («44-ФЗ», «коммерческие РФ») — .law-badge дизайна: спокойная
   бирюзовая метка в карточке списка и в шапке панели тендера. */
.pill-law {
    background: var(--calm-wash);
    color: var(--calm-text);
}

/* Ход работы над тендером в карточке («Позиции: 2 из 3», «Совпадение:
   88%») — строкой мелкого текста, как .deal-progress-copy в дизайне. */
.deal-progress-copy {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 14px;
    margin-top: 10px;
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

/* Заголовок раздела в панели тендера — название слева, пояснение справа
   («Основная информация о закупке / По данным извещения»), как
   .drawer-section-heading в дизайне. */
.drawer-section-heading {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 4px 12px;
    margin-bottom: 12px;
}

.drawer-section-heading h3 {
    margin: 0;
    font-size: var(--fs-subsection);
}

/* Заголовок и ссылка действия раздела рядом, слева («Тендерная документация
   · Изучить все документы»); число файлов остаётся справа. */
.drawer-section-heading .heading-main {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 16px;
}

/* Ссылка на закупку — строкой под сведениями, как в дизайне. */
.procurement-link {
    margin: 12px 0 0;
    font-size: var(--fs-control);
    font-weight: 800;
}

/* Сведения о закупке в «Обзоре» (tender-modal/…/summary) — сеткой в две
   колонки, по ячейке на пару «подпись — значение», подпись над значением:
   .procurement-details в дизайне. Длинные поля — во всю ширину
   (.detail-wide). На узком экране — в одну колонку. */
.kv.procurement-details {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    overflow: hidden;
}

.procurement-details > div {
    display: grid;
    align-content: start;
    gap: 3px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border);
    background: var(--surface);
}

.procurement-details > div:nth-child(odd):not(.detail-wide) {
    border-right: 1px solid var(--border);
}

.procurement-details > .detail-wide {
    grid-column: 1 / -1;
}

.procurement-details dt {
    font-size: var(--fs-meta);
    font-weight: 400;
}

.procurement-details dd {
    overflow-wrap: anywhere;
    font-size: var(--fs-control);
    font-weight: 700;
    line-height: 1.5;
}

@media (max-width: 720px) {
    .kv.procurement-details {
        grid-template-columns: minmax(0, 1fr);
    }

    .procurement-details > div:nth-child(odd):not(.detail-wide) {
        border-right: 0;
    }
}

/* Шапка панели тендера (tender-modal/…/head): метка стадии над номером и
   заказчик под названием — как шапка карточки сделки в дизайне.
   «найдено» — цветом акцента: стадия «Найдено» в дизайне синяя. */
.pill-accent {
    background: var(--accent-wash);
    color: var(--accent-text);
}

.drawer-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0 0 8px;
}

.drawer-customer {
    margin: 6px 0 0;
    font-size: var(--fs-control);
}

/* Город в плашке маршрута окна «Логистика» — полем во всю ширину плашки. */
.logistics-route-city {
    width: 100%;
    min-width: 0;
    margin-top: 4px;
    font-weight: 700;
}

/* Вкладки раздела «Организация» (<x-organization-tabs>) — под шапкой. */
.organization-tabs {
    margin-bottom: 16px;
}

/* «Главная» — чек-лист «Первые шаги» (dashboard): шаг строкой — номер или
   галочка, что сделать, кнопка туда, где это делают. Сделанный — серым. */
.first-steps-list {
    display: grid;
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.first-step {
    display: flex;
    align-items: center;
    gap: 12px;
}

.first-step-mark {
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--accent-wash);
    color: var(--accent-text);
    font-weight: 800;
}

.first-step-text {
    display: grid;
    flex: 1 1 auto;
    min-width: 0;
}

.first-step-done .first-step-mark {
    background: var(--success-wash);
    color: var(--success-text);
}

.first-step-done .first-step-text strong {
    color: var(--text-muted);
}

/* «Номенклатура» — компактный список таблицей (catalog/index): название —
   кнопкой вида ссылки, жирным, характеристики под ним мелко. Поле поиска
   над списком — широкое: подсказка в 180 px обрезалась. */
.catalog-list-name {
    font-weight: 700;
    text-align: left;
}

.catalog-list .row-icon-actions {
    /* Строка списка — в одну линию: кнопки в ряд, а не столбиком по три,
       иначе их столбик и задавал высоту строки. */
    grid-template-rows: 28px;
}

.catalog-list td {
    padding-top: 6px;
    padding-bottom: 6px;
}

.catalog-search-wide {
    flex: 1 1 420px;
    min-width: 0;
}

.catalog-search-wide .search-field,
.catalog-search-wide input {
    width: 100%;
}

/* Форма позиции номенклатуры (partials/catalog-product-form): «+ Новый
   поставщик» под выбором поставщика и поле его названия; кнопки —
   подвалом, прилипшим к низу окна. */
.catalog-new-supplier {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: 6px;
}

.catalog-new-supplier input {
    flex: 1 1 200px;
    min-width: 0;
}

.catalog-new-supplier-link {
    align-self: flex-start;
    margin-top: 4px;
}

.catalog-form-more > summary h3 {
    font-weight: 700;
}

.catalog-form-actions {
    position: sticky;
    bottom: -1px;
    z-index: 2;
    margin: 12px -20px -20px;
    padding: 12px 20px;
    border-top: 1px solid var(--border);
    background: var(--surface);
}

/* Звёздочка у подписи поля, без которого шаг не завершится (контракт:
   поля, нужные для перехода в «Исполнение»). */
.field-required {
    color: var(--danger-text);
}

/* Сводка готовности в подтверждении «Передать на подачу»
   (tender-modal/in-work/pass-to-submission): недоделанное — цветом
   предупреждения. */
.pass-facts {
    margin: 8px 0;
    padding-left: 18px;
}

.pass-fact-warn {
    color: var(--warn-text);
    font-weight: 700;
}

/* Действие подвала, стоящее отдельно от главного решения (удаление
   тендера) — прижато к левому краю. */
.drawer-footer-aside {
    margin-right: auto;
    order: -1;
}

/* Окно отклонения тендера (tender-modal/matched/reject): причина отказа —
   плашками-переключателями без предвыбора. Тот же вид годится любому
   выбору одного из нескольких коротких вариантов (.chip-choices). */
.reject-causes {
    margin: 0 0 14px;
    padding: 0;
    border: 0;
}

.reject-causes legend {
    padding: 0;
    margin-bottom: 6px;
    font-size: var(--fs-control);
    font-weight: 800;
}

.chip-choices {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0;
}

.chip-choice {
    position: relative;
    cursor: pointer;
}

.chip-choice input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.chip-choice span {
    display: inline-block;
    padding: 4px 12px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    font-size: var(--fs-control);
    font-weight: 700;
}

.chip-choice:hover span {
    border-color: var(--accent-line);
}

.chip-choice input:checked + span {
    border-color: var(--accent);
    background: var(--accent-wash);
    color: var(--accent-text);
}

.chip-choice input:focus-visible + span {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Поля отбора — мельче полей формы, как в строке отборов дизайна
   (.tender-filters: подпись 8 px, поле 9 px в прототипе). */
.filter input,
.filter select {
    font-size: var(--fs-control);
}

.logistics-section-title h3 {
    font-size: var(--fs-section);
    letter-spacing: -.025em;
}

.logistics-section-title p {
    font-size: var(--fs-meta);
}

/* Пояснение справа в заголовке раздела панели («По данным извещения»). */
.drawer-section-heading > span {
    font-size: var(--fs-meta);
}

/* ---------- вкладка «Контроль» карточки тендера ----------
   По дизайну: блоки «Ответственный и метки» (in-work/control),
   «Обсуждение» (…/comments) и «История действий» (…/history), каждый
   своим разделом с заголовком .drawer-section-heading. */

.drawer-section + .drawer-section {
    margin-top: 18px;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}

/* Ответственный и контрольная дата — двумя столбцами, на телефоне одним. */
.control-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}

/* Метки сделки — пилюлями-кнопками; стоящая — заливкой предупреждения. */
.deal-labels {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: 12px;
}

.deal-label {
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    padding: 6px 10px;
    color: var(--text-muted);
    font: inherit;
    font-size: var(--fs-meta);
    font-weight: 700;
    cursor: pointer;
}

.deal-label:hover {
    border-color: var(--accent-line);
    color: var(--accent-text);
}

.deal-label.deal-label-active {
    border-color: var(--warn-line);
    background: var(--warn-wash);
    color: var(--warn-text);
}

/* «Добавить метку» — поле и кнопка той же формы, что метки, в одном ряду. */
.deal-label-add {
    display: flex;
    gap: 6px;
    margin: 0;
}

.deal-label-add input {
    width: 150px;
    height: auto;
    min-height: 0;
    padding: 5px 10px;
    border-radius: 999px;
    font-size: var(--fs-meta);
}

.comment-form {
    margin-top: 12px;
}

/* История действий — строкой на событие: время слева, текст справа. */
.activity-log {
    list-style: none;
    margin: 0;
    padding: 0;
    border-top: 1px solid var(--border);
}

.activity-log li {
    display: grid;
    grid-template-columns: 110px 1fr;
    gap: 10px;
    padding: 9px 0;
    border-bottom: 1px solid var(--border);
}

.activity-log p {
    margin: 0;
    color: var(--text-muted);
    font-size: var(--fs-control);
}

@media (max-width: 720px) {
    .control-grid {
        grid-template-columns: 1fr;
    }

    .activity-log li {
        grid-template-columns: 1fr;
        gap: 2px;
    }
}

/* ---------- «Проверка заказчика» — панель у правого края ----------
   (partials/customer-check, WithCustomerCheck). Та же панель, что у
   карточки тендера (.modal.drawer), но уже на 80px: из шапки карточки
   она ложится поверх неё, и край карточки остаётся виден — понятно, что
   под панелью заказчика открыт тендер. Затемнение второго слоя не
   сгущается: подложка у панелей общая по смыслу. */
.customer-scrim {
    background: transparent;
}

.modal.drawer.customer-drawer {
    width: min(640px, 100%);
}

.modal.drawer.customer-drawer.modal-max {
    width: 100%;
}

/* Наименование заказчика — кнопкой вида ссылки (у панели нет адреса),
   выглядит как прежняя ссылка пунктиром. */
.btn-link.customer-link {
    cursor: pointer;
    text-align: left;
}

/* Разделы проверки — отдельными белыми карточками, как вкладка панели
   тендера; между ними промежуток, а не черта. */
.customer-block + .customer-block {
    margin-top: 14px;
}

/* Сигналы — метка и объяснение строкой; столбец меток — по самой
   длинной из них (строки списка — display: contents, ячейки встают в
   общую сетку списка). */
.customer-signals {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    align-items: baseline;
    gap: 8px 12px;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--fs-control);
}

.customer-signals li {
    display: contents;
}

/* Исход дела — меткой, но в узкой колонке переносится: иначе «иск
   удовлетворён» уводил таблицу вбок и обрезался краем панели. */
.pill.customer-outcome {
    white-space: normal;
}

.customer-signals .pill {
    justify-self: start;
}

/* Несколько телефонов, почт, лиц в одной ячейке — по строке на каждый,
   источник серым рядом. */
.customer-contact {
    display: block;
}

.customer-contact + .customer-contact {
    margin-top: 4px;
}

.customer-contact .muted-note {
    font-weight: 400;
}

/* Сводка арбитража и госзакупок — одной полосой, как сводка подбора
   (.matching-summary): число крупно, подпись над ним, пояснение под. */
.customer-stats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    overflow: hidden;
}

.customer-stats > div {
    display: grid;
    align-content: start;
    gap: 3px;
    padding: 10px 12px;
}

.customer-stats > div + div {
    border-left: 1px solid var(--border);
}

.customer-stats span,
.customer-stats small {
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

.customer-stats strong {
    font-size: var(--fs-section);
    letter-spacing: -.025em;
}

/* Плитки сводки документов к отгрузке — кнопками: «Собрано», «Подтвердить»,
   «Не хватает» оставляют в таблице только свои строки, ещё раз — все
   (подбор документов, сделка, партия; отбор держит Alpine на .shipment-filter,
   строки — data-group у tr в shipment-documents-table). */
.customer-stats > .stat-filter {
    padding: 0;
}

.stat-filter > button {
    display: grid;
    align-content: start;
    gap: 3px;
    width: 100%;
    height: 100%;
    padding: 10px 12px;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.stat-filter > button:hover {
    background: var(--row-hover);
}

.stat-filter.is-active > button {
    background: var(--accent-wash);
    box-shadow: inset 0 -3px 0 var(--accent);
}

.shipment-filter[data-filter="ok"] tr[data-group]:not([data-group="ok"]),
.shipment-filter[data-filter="confirm"] tr[data-group]:not([data-group="confirm"]),
.shipment-filter[data-filter="short"] tr[data-group]:not([data-group="short"]) {
    display: none;
}

.shipment-filter-note {
    margin: -6px 0 10px;
}

.customer-subheading {
    margin: 0 0 8px;
    font-size: var(--fs-control);
    font-weight: 800;
}

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

    .customer-stats > div:nth-child(3) {
        border-left: 0;
    }

    .customer-stats > div:nth-child(n + 3) {
        border-top: 1px solid var(--border);
    }

    .customer-signals {
        grid-template-columns: minmax(0, 1fr);
        gap: 4px;
    }

    .customer-signals li > span:last-child {
        margin-bottom: 6px;
    }
}

/* Вывод о надёжности заказчика — первым разделом, рамкой и заливкой
   своего уровня (CustomerVerdict::level()): вывод видно до того, как
   прочитаны правила под ним. */
.customer-verdict {
    border-left-width: 4px;
}

.customer-verdict-ok {
    border-color: var(--success-line);
    background: var(--success-wash);
}

.customer-verdict-warn {
    border-color: var(--warn-line);
    background: var(--warn-wash);
}

.customer-verdict-danger {
    border-color: var(--danger-line);
    background: var(--danger-wash);
}

.customer-verdict h3 {
    font-size: var(--fs-section);
}

.customer-verdict-ok h3 {
    color: var(--success-text);
}

.customer-verdict-warn h3 {
    color: var(--warn-text);
}

.customer-verdict-danger h3 {
    color: var(--danger-text);
}

/* Коды правил — меткой на белом: заливка уровня у плашки та же, что у
   метки, и иначе код сливался с фоном. */
.customer-verdict .pill {
    background: var(--surface);
}

.customer-advice {
    margin: 0 0 12px;
    font-size: var(--fs-control);
}

.customer-incomplete {
    margin: 12px 0 0;
}

.customer-cost {
    margin: 14px 0 0;
}

/* ---------- «Документы к отгрузке» — панель партии ----------
   (partials/shipment-panel, WithShipments). Та же панель, что у проверки
   заказчика (.customer-drawer), но шире: в таблице позиций — документы
   списком с кнопками. */
.modal.drawer.shipment-drawer {
    width: min(900px, 100%);
}

.shipment-documents {
    display: grid;
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.shipment-documents li {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 3px 6px;
}

/* Строка выбора в «Добавить документ» панели партии: кнопка слева,
   описание документа — одним блоком справа, переносится внутри себя. */
.shipment-documents li.shipment-option {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: 8px;
}

/* Значение строки охвата в форме документа к отгрузке: поле во всю
   ширину ячейки, под ним — ошибка и предпросмотр «Подойдёт позиций». */
.scope-value {
    display: grid;
    gap: 4px;
    min-width: 0;
}

.scope-value input {
    width: 100%;
}

/* Загрузка документа с компьютера в строке партии — между поиском и
   списком библиотеки: подсказка, затем тип и файл в строку (на узком
   экране — друг под другом). */
.shipment-upload {
    display: grid;
    gap: 6px;
    padding-block: 8px;
    border-block: 1px solid var(--border);
}

.shipment-upload-fields {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}

.shipment-upload-fields select {
    max-width: 100%;
}

.shipment-upload-fields input[type="file"] {
    min-width: 0;
    max-width: 100%;
}

.shipment-document-line {
    flex: 0 0 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 3px 6px;
}

/* Решение по документу: «Подтвердить» и «Отклонить» ссылками на своей
   строке, зелёная и красная (.link-ok, .link-danger). */
.shipment-document-actions {
    gap: 14px;
}


/* Галочка у документа в строке подбора и строка «Подтвердить выбранное /
   Отклонить выбранное» над списком документов позиции: строка видна, пока
   отмечен хоть один документ (Alpine в ячейке, shipment-documents-table). */
.shipment-doc-check {
    flex: none;
    align-self: center;
    margin: 0;
}

.shipment-bulk {
    margin: 0 0 12px;
}

/* «Подобрать документы заново» — над таблицей подбора документов
   (partials/shipment-documents-table), у правого края. */
.shipment-rematch {
    justify-content: flex-end;
    margin: 0 0 8px;
}

/* «Добавить документ» под списком документов позиции — через промежуток
   в одну строку списка, отдельной строкой. */
.shipment-add-link {
    display: block;
    margin-top: 12px;
}

.shipment-add-document {
    display: grid;
    gap: 8px;
    margin-top: 8px;
    padding: 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}

/* Количество в окне «Новая партия» и в строке позиции сделки — узким
   полем в столбце чисел. */
.shipment-quantity {
    width: 6em;
    min-width: 0;
    text-align: right;
}

/* «Сделки» — под таблицей подбора документов: отчёт, флажок
   неподтверждённых и сборка комплекта одной строкой; ниже — собранные
   комплекты списком, строка на комплект (deals/show). */
.deal-kit-actions {
    margin-top: 12px;
    align-items: center;
}

.deal-kits {
    display: grid;
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* На узком экране любое окно — во весь экран, кроме подтверждения: оно
   остаётся маленьким окном посередине, как на широком. */
@media (max-width: 720px) {
    .drawer-scrim > .modal-scrim:has(> .modal-sm),
    .modal-scrim:has(> .modal-sm) {
        padding: 16px;
    }

    .modal.modal-sm {
        width: 100%;
        height: auto;
        max-height: calc(100dvh - 32px);
        border: 1px solid var(--border);
        border-radius: var(--radius);
    }
}

/* Плашка-кнопка: «подобрано» в столбце «Статус» рабочей таблицы подбора
   (in-work/products-grid) — нажатие подтверждает выбор системы, у
   «подтверждено» — снимает подтверждение. Вид метки, курсор кнопки. */
.pill-action {
    border: 0;
    cursor: pointer;
    font-family: inherit;
}

.pill-action:hover {
    outline: 2px solid currentColor;
    outline-offset: 1px;
}

.pill-action:disabled {
    cursor: default;
    outline: 0;
    opacity: .6;
}

/* Статус подбора в ячейке — переносится: «не обработано: <причина>»
   бывает длинной, и скругление метки на нескольких строках смотрелось бы
   овалом — у переносимой метки радиус кнопки. */
.match-result {
    white-space: normal;
    text-align: left;
    border-radius: var(--radius-sm);
}

/* ---------- кабинет «Подача» ----------
   docs/submission-cabinet.md, разметка — livewire/app/submission/ и
   tender-modal/submission/. Сроки во вкладке «Подача» — тремя плашками,
   как крупные числа сводки (.matching-summary): окончание подачи — по
   запасу дней (до недели — предупреждение, два дня и меньше — тревога),
   торги — всегда тревожным цветом, их нельзя пропустить. */
.submission-dates,
.submission-money {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px;
    margin-bottom: 10px;
}

.submission-money {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.submission-date,
.submission-money > div {
    display: grid;
    gap: 3px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
}

.submission-date span,
.submission-money span {
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

.submission-date strong {
    font-size: var(--fs-stat);
    letter-spacing: -.04em;
}

.submission-money strong {
    font-size: var(--fs-card-title);
}

.submission-date small,
.submission-money small {
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

.submission-date-warn {
    border-color: var(--warn-line);
    background: var(--warn-wash);
}

.submission-date-warn strong {
    color: var(--warn-text);
}

.submission-date-hot {
    border-color: var(--danger-line);
    background: var(--danger-wash);
}

.submission-date-hot strong,
.submission-date-hot span {
    color: var(--danger-text);
}

/* Итог калькуляции по цене подачи и «Скачать калькуляцию» — одной строкой. */
.submission-sum {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
}

.submission-sum > div {
    display: grid;
    gap: 2px;
}

.submission-sum strong {
    font-size: var(--fs-stat);
    letter-spacing: -.04em;
}

/* «Взять на подачу» под карточкой очереди — вплотную к ней. */
.submission-take {
    margin: -6px 0 10px;
}

/* Поля вкладки «Контракт» в <fieldset>: выключить все разом тому, кто
   подачу не ведёт, — без рамки и отступов fieldset. */
.form-plain {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

@media (max-width: 720px) {
    .submission-dates,
    .submission-money {
        grid-template-columns: minmax(0, 1fr);
    }

    .submission-sum {
        flex-direction: column;
        align-items: stretch;
    }
}

/* Модуль «Логистика» по дизайну (Figma Make, логистика): общая шапка с
   меткой «бета» и вкладками разделов (<x-logistics-heading>), сводка
   плитками, расчёты карточками с меткой маршрута «А → Б», калькулятор в
   два шага (.logistics-stepper) и окно выбора тарифа карточками-
   переключателями (.logistics-tariff-option). Пустой раздел — пояснением
   с кнопкой (.logistics-empty-state). */
.logistics-heading {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 24px;
}

.logistics-heading h1 {
    margin: 0;
}

.logistics-heading .lead {
    margin: 7px 0 0;
}

.logistics-title-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.logistics-title-row > span {
    padding: 4px 8px;
    border-radius: 999px;
    background: var(--accent-wash);
    color: var(--accent-text);
    font-size: var(--fs-meta);
    font-weight: 800;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.logistics-tabs {
    display: flex;
    gap: 3px;
    margin: 24px 0 18px;
    overflow-x: auto;
    border-bottom: 1px solid var(--border);
}

.logistics-tabs a {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 7px;
    padding: 10px 12px;
    border-bottom: 2px solid transparent;
    color: var(--text-muted);
    font-size: var(--fs-control);
    font-weight: 800;
    text-decoration: none;
}

.logistics-tabs a > span {
    display: grid;
    min-width: 20px;
    height: 18px;
    place-items: center;
    padding: 0 5px;
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

.logistics-tabs .logistics-tab-active {
    border-bottom-color: var(--accent);
    color: var(--accent-text);
}

.logistics-tabs .logistics-tab-active > span {
    background: var(--accent-wash);
    color: var(--accent-text);
}

.logistics-summary {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
}

.logistics-summary > div {
    display: grid;
    align-content: center;
    gap: 4px;
    min-height: 88px;
    padding: 12px 15px;
    border-right: 1px solid var(--border);
}

.logistics-summary > div:last-child {
    border-right: 0;
}

.logistics-summary span,
.logistics-summary small {
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

.logistics-summary strong {
    font-size: var(--fs-stat);
    letter-spacing: -.04em;
}

.logistics-list-heading,
.logistics-reference-heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    margin-bottom: 12px;
}

.logistics-list-heading {
    margin-top: 22px;
}

.logistics-list-heading h2,
.logistics-reference-heading h2 {
    margin: 0 0 3px;
}

.logistics-list-heading p,
.logistics-reference-heading p {
    margin: 0;
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

.logistics-calculation-list {
    display: grid;
    gap: 8px;
}

.logistics-calculation-card {
    display: grid;
    grid-template-columns: 36px minmax(0, 1fr) 190px;
    align-items: center;
    gap: 14px;
    padding: 13px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    transition: border-color 160ms ease, box-shadow 160ms ease;
}

.logistics-calculation-card:hover {
    border-color: var(--accent-line);
    box-shadow: var(--shadow);
}

.logistics-route-mark {
    display: grid;
    align-self: stretch;
    justify-items: center;
}

.logistics-route-mark span {
    display: grid;
    width: 22px;
    height: 22px;
    place-items: center;
    border-radius: 50%;
    background: var(--accent-wash);
    color: var(--accent-text);
    font-size: var(--fs-meta);
    font-weight: 800;
}

.logistics-route-mark span:last-child {
    background: var(--ai-wash);
    color: var(--ai-text);
}

.logistics-route-mark i {
    width: 1px;
    min-height: 15px;
    background: var(--border);
}

.logistics-card-main h3 {
    margin: 0;
    font-size: var(--fs-card-title);
    line-height: 1.45;
}

.logistics-card-main > p {
    margin: 7px 0 0;
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

.logistics-card-main > p.logistics-card-error {
    color: var(--warn-text);
}

.logistics-card-meta,
.logistics-picker-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    margin-top: 7px;
}

.logistics-card-meta span,
.logistics-picker-meta span {
    padding: 4px 7px;
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--text-muted);
    font-size: var(--fs-meta);
    font-weight: 700;
}

.logistics-card-quote {
    display: grid;
    justify-items: end;
    gap: 3px;
    padding-left: 14px;
    border-left: 1px solid var(--border);
}

.logistics-card-quote > span {
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

.logistics-card-quote > strong {
    font-size: var(--fs-section);
    letter-spacing: -.03em;
}

.logistics-card-quote .btn {
    margin-top: 6px;
}

.logistics-empty-state {
    display: grid;
    place-items: center;
    align-content: center;
    gap: 7px;
    min-height: 260px;
    margin-top: 12px;
    padding: 30px;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface);
    text-align: center;
}

.logistics-empty-state > span {
    display: grid;
    width: 42px;
    height: 42px;
    place-items: center;
    border-radius: 12px;
    background: var(--accent-wash);
    color: var(--accent-text);
    font-size: var(--fs-card-title);
    font-weight: 800;
}

.logistics-empty-state > strong {
    margin-top: 5px;
    font-size: var(--fs-subsection);
}

.logistics-empty-state > p {
    max-width: 440px;
    margin: 0 0 5px;
    color: var(--text-muted);
    font-size: var(--fs-meta);
    line-height: 1.55;
}

.logistics-integration-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 11px 13px;
    border: 1px solid var(--success-line);
    border-radius: var(--radius-sm);
    background: var(--success-wash);
}

.logistics-integration-summary > div {
    display: grid;
    gap: 3px;
}

.logistics-integration-summary strong {
    color: var(--success-text);
    font-size: var(--fs-control);
}

.logistics-integration-summary span {
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

.logistics-integration-summary > span {
    padding: 5px 8px;
    border-radius: 999px;
    background: var(--surface);
    color: var(--success-text);
    font-weight: 800;
}

.logistics-integration-off {
    border-color: var(--warn-line);
    background: var(--warn-wash);
}

.logistics-integration-off strong,
.logistics-integration-off > span {
    color: var(--warn-text);
}

.logistics-company-list {
    display: grid;
    gap: 8px;
    margin-top: 12px;
}

.logistics-company-list article {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    min-height: 70px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
}

.logistics-company-list h2 {
    margin: 0;
    font-size: var(--fs-card-title);
}

.logistics-company-list p {
    margin: 4px 0 0;
    color: var(--text-muted);
    font-size: var(--fs-meta);
}

/* Калькулятор — шаги «Адреса» и «Груз и перевозчики». */
.logistics-stepper {
    display: flex;
    align-items: center;
    margin-bottom: 18px;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}

.logistics-stepper > button {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-faint);
    font-family: inherit;
    font-size: var(--fs-meta);
    font-weight: 800;
    cursor: pointer;
}

.logistics-stepper > button strong {
    display: grid;
    width: 20px;
    height: 20px;
    place-items: center;
    border-radius: 50%;
    background: var(--surface);
    color: var(--text-faint);
}

.logistics-stepper > i {
    width: 48px;
    height: 1px;
    margin: 0 8px;
    background: var(--border);
}

.logistics-stepper .logistics-step-active {
    color: var(--accent-text);
}

.logistics-stepper .logistics-step-active strong {
    background: var(--accent);
    color: #fff;
}

/* Окно выбора тарифа. */
.logistics-picker-route {
    display: grid;
    grid-template-columns: minmax(0, .8fr) auto minmax(0, 1.2fr);
    align-items: center;
    gap: 12px;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}

.logistics-picker-route > div {
    display: grid;
    gap: 4px;
    min-width: 0;
}

.logistics-picker-route span {
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

.logistics-picker-route strong {
    font-size: var(--fs-control);
    line-height: 1.4;
}

.logistics-picker-route > i {
    color: var(--accent-text);
    font-style: normal;
}

.logistics-picker-toolbar {
    display: flex;
    align-items: end;
    justify-content: space-between;
    gap: 16px;
    margin-top: 18px;
}

.logistics-picker-toolbar > div {
    display: grid;
    gap: 4px;
}

.logistics-picker-toolbar > div strong {
    font-size: var(--fs-subsection);
}

.logistics-picker-toolbar > div span {
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

.logistics-tariff-options {
    display: flex;
    flex-direction: column;
    gap: 7px;
    margin-top: 10px;
}

.logistics-tariff-option {
    position: relative;
    display: grid;
    grid-template-columns: 18px minmax(0, 1fr) 80px 110px;
    align-items: center;
    gap: 10px;
    padding: 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    cursor: pointer;
    transition: border-color 150ms ease, background 150ms ease, box-shadow 150ms ease;
}

.logistics-tariff-option:hover,
.logistics-tariff-option-selected {
    border-color: var(--accent-line);
    background: var(--accent-wash);
}

.logistics-tariff-option-selected {
    box-shadow: 0 0 0 2px var(--accent-line);
}

.logistics-tariff-option > input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
}

.logistics-tariff-radio {
    width: 16px;
    height: 16px;
    border: 1px solid var(--border-strong);
    border-radius: 50%;
    background: var(--surface);
}

.logistics-tariff-option-selected .logistics-tariff-radio {
    border: 5px solid var(--accent);
}

.logistics-tariff-company {
    display: grid;
    gap: 3px;
    min-width: 0;
}

.logistics-tariff-company > strong,
.logistics-tariff-term strong {
    font-size: var(--fs-control);
}

.logistics-tariff-company > small,
.logistics-tariff-term small,
.logistics-tariff-price small {
    overflow: hidden;
    color: var(--text-faint);
    font-size: var(--fs-meta);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.logistics-tariff-company > span {
    display: flex;
    gap: 4px;
}

.logistics-tariff-company em {
    padding: 3px 6px;
    border-radius: 999px;
    background: var(--success-wash);
    color: var(--success-text);
    font-size: var(--fs-meta);
    font-style: normal;
    font-weight: 800;
}

.logistics-tariff-term,
.logistics-tariff-price {
    display: grid;
    justify-items: end;
    gap: 4px;
}

.logistics-tariff-price strong {
    font-size: var(--fs-card-title);
    letter-spacing: -.02em;
}

.logistics-picker-footer {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 18px;
    border-top: 1px solid var(--border);
    background: var(--surface);
}

.logistics-picker-footer > div {
    display: grid;
    gap: 3px;
}

.logistics-picker-footer span {
    color: var(--text-faint);
    font-size: var(--fs-meta);
}

.logistics-picker-footer strong {
    font-size: var(--fs-card-title);
}

@media (max-width: 1050px) {
    .logistics-summary {
        grid-template-columns: 1fr 1fr;
    }

    .logistics-summary > div:nth-child(2) {
        border-right: 0;
    }

    .logistics-summary > div:nth-child(-n + 2) {
        border-bottom: 1px solid var(--border);
    }
}

@media (max-width: 720px) {
    .logistics-heading,
    .logistics-list-heading,
    .logistics-reference-heading,
    .logistics-picker-toolbar,
    .logistics-picker-footer,
    .logistics-company-list article {
        flex-direction: column;
        align-items: stretch;
    }

    .logistics-summary {
        grid-template-columns: 1fr;
    }

    .logistics-summary > div,
    .logistics-summary > div:nth-child(2) {
        border-right: 0;
        border-bottom: 1px solid var(--border);
    }

    .logistics-summary > div:last-child {
        border-bottom: 0;
    }

    .logistics-calculation-card {
        grid-template-columns: 28px minmax(0, 1fr);
    }

    .logistics-route-mark {
        grid-row: span 2;
    }

    .logistics-card-quote {
        grid-column: 2;
        justify-items: start;
        padding: 10px 0 0;
        border-top: 1px solid var(--border);
        border-left: 0;
    }

    .logistics-picker-route {
        grid-template-columns: 1fr;
    }

    .logistics-picker-route > i {
        transform: rotate(90deg);
    }

    .logistics-tariff-option {
        grid-template-columns: 18px minmax(0, 1fr) auto;
    }

    .logistics-tariff-price {
        grid-column: 3;
        grid-row: 1;
    }

    .logistics-tariff-term {
        grid-column: 2 / -1;
        justify-items: start;
    }
}

/* Ячейки рабочей таблицы подбора — всё, что стоит в ячейке кнопкой или
   меткой, одного вида (так решено): метки статуса (.pill, в том числе
   «требует решения», «подтверждено», «вариантов N»), действия строки
   («Подтвердить», «Заменить», «Найти», «Создать позицию», «Выбрать»
   у варианта — .cell-chip) и поставщик меткой. Одна высота, шрифт,
   отступы и скругление; главное действие — заливкой акцента, прочие
   действия — рамкой акцента, метки — своим цветом без рамки. */
.products-grid .grid-cell :is(.pill, .cell-chip) {
    display: inline-flex;
    align-items: center;
    min-height: 22px;
    margin: 0;
    padding: 2px 9px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    font-family: inherit;
    font-size: var(--fs-meta);
    font-weight: 800;
    line-height: 1.2;
    letter-spacing: normal;
    white-space: normal;
    text-align: left;
    vertical-align: middle;
}

.products-grid .grid-cell .cell-chip {
    border-color: var(--accent-line);
    background: var(--surface);
    color: var(--accent-text);
    cursor: pointer;
    transition: background 140ms ease, border-color 140ms ease;
}

.products-grid .grid-cell .cell-chip:hover {
    border-color: var(--accent);
    background: var(--accent-wash);
}

.products-grid .grid-cell .cell-chip-primary {
    border-color: var(--accent);
    background: var(--accent);
    color: #fff;
}

.products-grid .grid-cell .cell-chip-primary:hover {
    border-color: var(--accent-strong);
    background: var(--accent-strong);
}

.products-grid .grid-cell .cell-chip:disabled {
    cursor: default;
    opacity: .5;
}

.products-grid .grid-cell .supplier-pill {
    border-color: var(--border);
    background: var(--surface);
    color: var(--text-muted);
    cursor: pointer;
}

.products-grid .grid-cell .supplier-pill:hover {
    border-color: var(--accent-line);
    color: var(--accent-text);
}

.products-grid .grid-cell .match-links {
    gap: 4px;
}

.products-grid .grid-cell .match-options li {
    align-items: center;
    gap: 4px 6px;
}

.products-grid .grid-cell .match-cell-foot > * {
    margin: 0;
}

/* Вариант «требует решения»: название и поставщик с ценой — слева,
   «Выбрать» — справа той же строкой. */
.products-grid .grid-cell .match-options li {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 6px;
    padding: 4px 0;
    border-top: 1px solid var(--border);
}

.products-grid .grid-cell .match-options li > span {
    display: grid;
    gap: 1px;
    min-width: 0;
}

/* Вкладка «Заявка» кабинета «Подача» — лист переноса в структурированную
   форму площадки (tender-modal/submission/application). Сводка пилюлями,
   товар — свёрнутым блоком .fold, значения — таблицей .table-striped:
   поле значения во всю ячейку, пояснение ИИ строкой под ним,
   подтверждённая строка — зелёной заливкой. */
.application-summary {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.application-product > summary {
    flex-wrap: wrap;
}

.application-table .application-value {
    min-width: 14em;
}

.application-table .application-value input {
    width: 100%;
}

.application-table .application-value .muted-note {
    display: block;
    margin-top: 4px;
}

.application-table tr.application-row-confirmed > td {
    background: var(--success-wash);
}

.application-table .application-check {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin: 6px 0 0;
}

/* Поле выбора файла, спрятанное за кнопкой-подписью (<label class="btn">):
   «Проверить файл первой части» во вкладке «Заявка». Не display:none —
   иначе поле не получает фокус с клавиатуры. */
.visually-hidden-input {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* Вкладка «Формы» кабинета «Подача» (tender-modal/submission/forms): поле
   вопроса запроса разъяснений — во всю строку, «Убрать» — по тексту. */
.submission-form .field-line {
    align-items: flex-end;
}

.submission-form .field-line > .field {
    flex: 1;
    min-width: 0;
}

/* Вкладка «Главное» кабинета «Подача» (tender-modal/submission/brief):
   разделы сводки и пункты карточками — заголовок с метками, текст
   Markdown, источник, предложение срока или суммы, действия строкой.
   Проверенный пункт — зелёной заливкой. */
.brief-section {
    margin-top: 18px;
}

.brief-item {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    padding: 12px 14px;
    margin-bottom: 10px;
}

.brief-item-verified {
    background: var(--success-wash);
    border-color: var(--success-line);
}

.brief-item-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin: 0 0 6px;
}

.brief-source {
    margin: 6px 0 0;
}

.brief-term {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 8px 0 0;
}

.brief-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 10px 0 0;
}

/* Калькуляция доставки по адресам закупки (TenderDeliveries): выбор
   адресов флажками — в окне адресов шапки рабочей таблицы подбора и в окне
   «Логистика» (in-work/delivery-address-picker), вкладки адресов с
   состоянием расчёта (.logistics-address-tabs), адрес под заголовком
   расчёта «Закупка № …» на странице «Логистика». */
.delivery-address-picker {
    display: grid;
    gap: 6px;
    padding: 8px 12px 10px;
}

.delivery-address-option {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 0;
    border-bottom: 1px solid var(--border);
    font-size: var(--fs-control);
}

.delivery-address-option .checkbox {
    margin: 0;
}

.delivery-address-hint {
    margin: 8px 12px 0;
}

.logistics-address-tabs {
    flex-wrap: wrap;
    margin-bottom: 10px;
}

.logistics-address-tabs .tab {
    display: grid;
    gap: 2px;
    text-align: left;
    max-width: 320px;
}

.logistics-address-tabs .tab small {
    color: var(--text-faint);
    font-size: var(--fs-meta);
    font-weight: 400;
}

.logistics-card-address {
    margin: 2px 0 6px;
    color: var(--text-muted);
    font-size: var(--fs-control);
}

/* Строка-переключатель «Создать новую позицию / Скрыть создание позиции»
   под вариантами в панели подбора рабочей таблицы (in-work/matching-workspace). */
.catalog-quick-toggle {
    width: 100%;
    margin: 12px 0;
}

/* Панель подбора рабочей таблицы: характеристики по ТЗ — отдельная карточка,
   подбор под ней — прямо на фоне панели (in-work/matching-workspace). */
.matching-requirement {
    margin-bottom: 16px;
}

.matching-requirement-label {
    display: block;
    margin-bottom: 8px;
    color: var(--text-muted);
    font-size: var(--fs-meta);
    font-weight: 800;
}

.matching-requirement .tender-item-description {
    margin-top: 10px;
}

/* Сколько строк текста показывает ячейка таблицы (.cell-clamp, у всех
   таблиц контура, и рабочей таблицы подбора тоже): чем меньше экран, тем
   меньше — 8 на широком, 6 до 1050px, 4 на телефоне (до 720px). Так решено;
   границы — те же, что у боковой панели и телефонной раскладки. */
@media (max-width: 1049px) {
    :root {
        --cell-lines: 6;
    }
}

@media (max-width: 720px) {
    :root {
        --cell-lines: 4;
    }
}

/* «Поля номенклатуры» (livewire/app/catalog/fields): группа — панелью, в ней
   поля по порядку; у поля название с метками и строка управления:
   группа, порядок, флаги участия в поиске, подборе, импорте и экспорте. */
.catalog-fields-group {
    margin-bottom: 16px;
}

.catalog-fields-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
}

.catalog-fields-head h2 {
    margin: 0;
}

.catalog-fields-rename {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.catalog-field {
    display: grid;
    gap: 8px;
    padding: 10px 0;
    border-top: 1px solid var(--border);
}

.catalog-field-main {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
}

.catalog-field-name {
    font-weight: 800;
}

.catalog-field-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 16px;
}

.catalog-field-group {
    display: flex;
    align-items: center;
    gap: 8px;
}

.catalog-field-group select {
    width: auto;
}

.catalog-field-new {
    padding-top: 10px;
    border-top: 1px solid var(--border);
}

/* Плашка демо-кабинета (components/demo-banner) — над содержимым каждой
   страницы, только в демо-режиме. В потоке и всегда на месте, поэтому
   страницу не сдвигает. Цвет — ИИ-бирюзовый: отличается и от сообщений
   (.callout), и от предупреждений. */
.demo-banner {
    display: flex;
    align-items: center;
    gap: 12px;
    width: min(1180px, calc(100% - 60px));
    margin: 16px auto 0;
    padding: 11px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--ai-wash);
    color: var(--text);
    font-size: var(--fs-body);
    line-height: 1.5;
}

.demo-banner p {
    margin: 0;
}

.demo-banner-pill {
    flex-shrink: 0;
    background: var(--surface);
    color: var(--ai-text);
}

@media (max-width: 720px) {
    .demo-banner {
        width: min(100% - 38px, 1180px);
        align-items: flex-start;
    }
}

/* Тарифы подписки («Организация» → «Подписка», organization/subscription):
   цена тарифа крупным числом (--fs-stat) с подписью срока серым, под ней —
   состав списком. Карточки — обычные .card, по одной в ряд. */
.plan-price {
    margin: 0;
    font-size: var(--fs-stat);
    font-weight: 800;
    letter-spacing: -0.04em;
}

.plan-price small {
    font-size: var(--fs-meta);
    font-weight: 400;
    letter-spacing: normal;
    color: var(--text-faint);
}

.plan-features {
    margin: 0;
    padding-left: 1.2em;
}

/* ---------- ответственные за тендер (x-tender-assignees) ----------

   Блок вкладки «Обсуждение»: по ряду на роль («Менеджер», «Подача») с
   пилюлями назначенных (тот же вид, что у меток тендера) и «+ ответственный»
   в конце. Список участников — тот же fixed-список, что у меток
   (.tender-label-panel), с переключателем роли сверху. */
.tender-assignees {
    display: grid;
    gap: 8px;
    justify-items: start;
    margin-bottom: 12px;
}

.tender-assignees-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.tender-assignees-role {
    min-width: 6em;
    color: var(--text-muted);
    font-size: var(--fs-control);
    font-weight: 700;
}

.tender-assignees-list {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.tender-assignee-name {
    display: grid;
    min-width: 0;
    text-align: left;
}

.tender-assignee-marks {
    display: inline-flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 4px;
}

/* Срок поставки по контракту (<x-delivery-term>): коротко жирным, рядом
   «Найти в документации»; в «Обзоре» под ним — формулировка как в
   документе и откуда срок. Шапка рабочей таблицы подбора, окно
   «Логистика», «Обзор» на «В работе» и в «Подаче». */
.delivery-term {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 8px;
}

.delivery-term-text,
.delivery-term > .muted-note:not([wire\:poll\.5s]) {
    flex-basis: 100%;
    font-weight: 400;
}

.logistics-delivery-term {
    margin: 0 0 12px;
}

/* В шапке рабочей таблицы подбора срок — значением ячейки, а не подписью:
   правило .heading-detail > span делает подписи серыми заглавными. */
.heading-detail > .delivery-term {
    color: var(--text);
    font-size: var(--fs-control);
    font-weight: 400;
    letter-spacing: normal;
    text-transform: none;
}

.heading-detail > .delivery-term > strong {
    font-weight: 700;
}

/* Состояние карточки на «Тендерах в работе» — цветная полоса слева
   (<x-tender-card work-state>, App\Enums\TenderWorkCardState). Только цвет, без
   подписи (так решено); что значит цвет — в подсказке полосы. Цвета — как
   у строк рабочей таблицы подбора (.row-tone-*): зелёный — подтверждено,
   синий — подобрано ИИ, жёлтый — требует решения, бирюзовый — ИИ работает
   (разбор документов — штрихом, подбор — сплошной, оба пульсируют).
   Полоса — элемент шире себя со скруглением карточки и заливкой на 5px:
   так её край повторяет скругление угла. */
.deal-card {
    position: relative;
}

.deal-state-stripe {
    --stripe: var(--border-strong);
    position: absolute;
    top: -1px;
    bottom: -1px;
    left: -1px;
    width: 16px;
    z-index: 2;
    border-radius: 15px 0 0 15px;
    overflow: visible;
    cursor: help;
}

/* Сама полоса — слоем ::before: мигает только она, а не подсказка (::after). */
.deal-state-stripe::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: linear-gradient(var(--stripe), var(--stripe)) left / 5px 100% no-repeat;
}

.deal-state-empty .deal-state-stripe { --stripe: var(--border-strong); }
.deal-state-not-matched .deal-state-stripe { --stripe: var(--accent-line); }
.deal-state-awaiting .deal-state-stripe { --stripe: var(--accent); }
.deal-state-decision .deal-state-stripe { --stripe: var(--warn); }
.deal-state-ready .deal-state-stripe { --stripe: var(--success); }
.deal-state-matching .deal-state-stripe { --stripe: var(--ai); }

/* Подсказка полосы — своя, сразу при наведении или фокусе (системная
   title появлялась с задержкой и не всегда). Справа от полосы, поверх
   карточки; светлая, с тонкой рамкой — тёмная плашка спорила с карточкой
   (так решено). */
.deal-state-stripe::after {
    content: attr(data-label);
    position: absolute;
    top: 12px;
    left: 14px;
    z-index: 5;
    width: max-content;
    max-width: 240px;
    padding: 6px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text-muted);
    font-size: var(--fs-meta);
    font-weight: 600;
    line-height: 1.35;
    white-space: normal;
    box-shadow: var(--shadow);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity .12s ease;
}

.deal-state-stripe:hover::after,
.deal-state-stripe:focus-visible::after {
    opacity: 1;
    visibility: visible;
}

.deal-state-stripe:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--focus-ring);
}

.deal-state-extracting .deal-state-stripe::before {
    background: repeating-linear-gradient(to bottom, var(--ai) 0 8px, var(--ai-wash) 8px 14px) left / 5px 100% no-repeat;
}


.deal-state-extracting .deal-state-stripe::before,
.deal-state-matching .deal-state-stripe::before {
    animation: deal-state-pulse 1.6s ease-in-out infinite;
}

@keyframes deal-state-pulse {
    50% { opacity: .45; }
}

@media (prefers-reduced-motion: reduce) {
    .deal-state-extracting .deal-state-stripe::before,
    .deal-state-matching .deal-state-stripe::before {
        animation: none;
    }
}


/* «Заявки ДЛ» (logistics/dellin-requests): строка поиска реализации 1С —
   поле и кнопки в ряд, кнопки по низу поля; найденные документы списком. */
.dellin-sale-search {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 8px;
}

.dellin-sale-search .field {
    flex: 1 1 320px;
    margin: 0;
}

.dellin-sale-list {
    margin: 6px 0 0;
    padding-left: 18px;
}

.dellin-sale-picked {
    margin: 10px 0 0;
}

/* «Заявки ДЛ»: неизменяемое «Откуда» — строкой вместо поля, той же высоты. */
.dellin-fixed {
    margin: 0;
    min-height: var(--control-h);
    display: flex;
    align-items: center;
    font-weight: 700;
}
