/* Anima КП — веб-морда kp_calc.
   ==========================================================================
   Величины берутся из дизайн-системы «ОС фабрики Anima»: цвет, кегль,
   начертание, отступ, радиус, тень и толщина рамки объявлены в
   /static/tokens.css и подключены в base.html ДО этого файла.

   Палитра исторически пришла из config.format (title_bg 2D4A6B, section
   4A7BA4) — то же решение легло и в систему: --bg-header и --accent.
   Две правки достались от неё:
     • рабочий синий притемнён #4A7BA4 → #43749B (--accent): прежний давал
       с белым текстом 4,51:1 при норме 4,50, а кнопку жмут с планшета
       в цеху, при бликах и под углом;
     • шапка таблицы отделена от кнопки (--bg-thead = #3D688C, 5,90:1):
       её разглядывают под углом чаще всего.

   Что осталось сырым НАРОЧНО и почему:
     • брейкпоинты медиазапросов — в @media переменные не работают,
       это ограничение самого CSS. Числа кабинета не трогали: смена
       брейкпоинта — это смена раскладки, а не слой токенов;
     • font-weight 600/700 — в системе токена на них нет, ui.css пишет их
       так же сырыми. Где токен есть (--t-btn-weight, --t-h1-weight и др.),
       стои́т токен;
     • 1px и clip у .visually-hidden — это приём пряток от глаза при живом
       чтении с экрана, а не размер из макета;
     • ch, %, vh, vw — относительные меры, они и есть решение.

   Классы и разметка НЕ переименовывались: это слой токенов, первый шаг
   переноса. Компоненты системы (ui.css) сюда пока не подключены — из её
   184 классов кабинету сейчас не на что надеть 167.
   ========================================================================== */

/* ── Геометрия, которой в системе нет ──────────────────────────────────────
   Восемь величин кабинета, которым в дизайн-системе не нашлось пары.
   Объявлены здесь один раз, чтобы их было видно и можно было пересчитать
   разом. Каждая — кандидат на переезд в систему.                          */
:root {
  --kp-stripe-w: 3px;        /* полоса-маркер слева: .age, .assumptions,
                                .landed, .china-filters, изменённая строка.
                                В системе линейка всегда волосяная
                                (--border-w) — здесь полоса шире нарочно:
                                она опознаётся и в ч/б печати. */
  --kp-tbl-min: 720px;       /* ниже этой ширины таблица уезжает в прокрутку */
  --kp-tbl-min-wide: 900px;  /* то же для широких: заказы, импорт, карточка */
  --kp-text-col: 720px;      /* колонка сплошного текста: опасная зона, ввод файла */
  --kp-input-narrow: 140px;  /* узкое поле в строке действий и ползунок плотности */
  --kp-origin-col: 170px;    /* колонка меток происхождения в карточке заказа */
  --kp-step-name-min: 180px; /* название шага в мастере импорта: от и до */
  --kp-step-name-max: 260px;
}

* { box-sizing: border-box; }
body { margin: 0; font-family: var(--font-sans); font-size: var(--t-body-size);
       color: var(--fg-primary); background: var(--bg-page); }
nav { display: flex; align-items: center; gap: var(--space-4);
      padding: var(--space-3) var(--pad-page);
      background: var(--bg-header); color: var(--white); flex-wrap: wrap; }
nav a { color: var(--fg-on-header); text-decoration: none; }
nav a:hover { color: var(--white); }
nav a.accent { background: var(--accent); padding: var(--space-1) var(--space-3);
      border-radius: var(--radius-md); color: var(--white); }
/* текущий раздел в верхнем меню */
nav a.nav-on { background: color-mix(in srgb, var(--white) 18%, transparent);
      padding: var(--space-1) var(--space-3); border-radius: var(--radius-md);
      color: var(--white); font-weight: 600; }
nav a.accent.nav-on { outline: var(--border-w-strong) solid var(--white); }
nav .brand { font-weight: 700; flex: 0 0 auto; }
nav .spacer { flex: 1; }
nav .who { color: var(--fg-on-header-quiet); }
nav a.who:hover { color: var(--white); text-decoration: underline; }
/* «Выйти» — кнопка-ссылка: синяя по умолчанию давала на тёмно-синей шапке 1,55:1
   (слепой критик 14.09.2026). В шапке — светлая, как пункты меню. */
nav button.link { color: var(--fg-on-header); }
nav button.link:hover { color: var(--white); }
main { width: 100%; max-width: var(--page-max); min-width: 0;
       margin: var(--space-6) auto; padding: 0 var(--pad-page); }
h1 { font-size: var(--t-h1-size); line-height: var(--t-h1-lh); letter-spacing: var(--t-h1-tracking); }
h2 { font-size: var(--t-h2-size); line-height: var(--t-h2-lh); letter-spacing: var(--t-h2-tracking); }
h3 { font-size: var(--t-h3-size); line-height: var(--t-h3-lh); }
.muted { color: var(--fg-muted); font-weight: var(--t-body-weight); }
.error { color: var(--danger-fg); font-weight: 600; background: var(--danger-bg);
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); }
.ok { color: var(--success-fg); font-weight: 600; background: var(--success-bg);
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); }
/* 🔴 Сообщение о результате прилипает к верху окна.
   Почему: после сохранения строки сервер возвращает человека К ЭТОЙ ЖЕ СТРОКЕ
   (якорь #cost-item-N-row-M), а сообщение печатается в начале страницы — за
   три тысячи точек выше. Отказ «нужна ссылка или обоснование цены» человек
   не видел вообще: экран моргал, число оставалось прежним, и правка выглядела
   молча пропавшей. Живой случай на fact-os.ru/orders/3, 28.08.2026.
   Прилипает только страничное сообщение — прямой ребёнок main; сообщения
   внутри форм и таблиц остаются на месте.
   Тень взята вторая ступень (--elev-2), а не первая: прилипшее сообщение
   едет ПОВЕРХ таблицы, и лёгкой тени под ним не видно — оно читается частью
   строки, мимо которой проезжает. */
main > .error, main > .ok {
  position: sticky; top: 0; z-index: 5; margin: 0 0 var(--space-3);
  box-shadow: var(--elev-2);
}
.badge { background: var(--danger-fg); color: var(--fg-on-accent);
  border-radius: var(--radius-full); padding: 0 var(--space-2); font-size: var(--t-label-size); }
.card { background: var(--bg-surface); border: var(--border-w) solid var(--border-hair);
  border-radius: var(--radius-lg); padding: var(--pad-card) var(--pad-card-x);
  margin: var(--space-3) 0; }
.card.center { text-align: center; padding: var(--space-8); }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-block); align-items: start; }
@media (max-width: 1000px) { .grid2 { grid-template-columns: 1fr; } }
label { display: block; margin: var(--space-2) 0; font-weight: 600; }
/* font: inherit тянет из подписи и её font-weight: 600 — от этого содержимое полей
   выглядело набранным жирным. Вес задаём явно: жирная тут только подпись.
   Рамка поля взята --border-strong, а не бледная --border-default: на разборе
   системы страница правки расчёта провалила проверку прищуром — на ней были
   видны только пояснения, а белых полей на белом фоне не было видно вообще. */
input, textarea, select { width: 100%; padding: var(--space-2) var(--row-px);
  margin-top: var(--space-1); font: inherit;
  font-weight: var(--t-body-weight); border: var(--border-w) solid var(--border-strong);
  border-radius: var(--radius-md); background: var(--bg-surface); }

/* Поля карточки клиента. Раньше стояли одной строкой через .inline-row, где ширина
   ужимается по содержимому: имя с должностью и почта не помещались и обрезались.
   Здесь ширину задаёт сетка, а не текст: узкое — ИНН, широкое — всё остальное. */
.client-fields { display: grid; gap: 0 var(--space-3);
  grid-template-columns: var(--kv-label-w) 1fr; align-items: start; }
.client-fields label { margin: var(--space-2) 0 0; min-width: 0; }
.client-fields input { width: 100%; }
@media (max-width: 720px) { .client-fields { grid-template-columns: 1fr; } }

/* Заметка показывает весь текст: высота растёт по содержимому (скрипт в client.html),
   а не режется фиксированными строками. Потолок — чтобы длинная история клиента
   не уводила кнопку «Сохранить» за пределы экрана. */
textarea.autogrow { overflow-y: auto; max-height: 70vh; resize: vertical;
  line-height: var(--t-body-lh); }

/* Комментарии к карточке клиента. Автор и время — обязательные: комментарий без
   подписи через месяц никому не помогает, а спорную договорённость не с кем сверить. */
.comments > summary { cursor: pointer; padding: var(--space-1) 0; }
.comments > summary::marker { color: var(--accent); }
.comment-add { margin: var(--space-2) 0 var(--space-1); }
.comment-list { list-style: none; margin: var(--space-3) 0 0; padding: 0;
  border-top: var(--border-w) solid var(--border-hair); }
.comment-list li { padding: var(--space-2) 0; border-bottom: var(--border-w) solid var(--border-hair); }
.comment-meta { margin: 0 0 var(--space-1); font-size: var(--t-cap-size); }
/* pre-wrap: перенос строк, набранный автором, сохраняется — комментарий часто пишут
   списком, и склеенный в абзац он теряет смысл. */
.comment-body { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }

.responsible-now { margin: 0 0 var(--space-2); }

/* Контакты сотрудника: нажал — звонишь или пишешь, а не переписываешь номер вручную. */
.contact-links { margin: 0 0 var(--space-2); display: flex; gap: var(--gap-block); flex-wrap: wrap; }
.contact-links a { text-decoration: none; }
.contact-links a:hover { text-decoration: underline; }
.user-card h2 { margin-top: 0; }
.user-actions { margin-top: var(--space-2); padding-top: var(--space-2);
  border-top: var(--border-w) solid var(--border-hair); }

/* Стадия отношений с клиентом. Цвет — подсказка, а не смысл: слово написано рядом,
   и человек, который цвета не различает, читает то же самое. Тёплое к правому краю
   воронки, серое — исходы.
   🔴 «В работе» и «Постоянный» после перевода на систему сидят на одной зелёной
   заливке и разводятся рамкой — второй ступени бледной зелени в системе нет.
   Рамка здесь законна: это метка, а не кнопка, и рамка у неё была и раньше. */
.rel-chip { display: inline-block; padding: var(--space-1) var(--row-px);
  border-radius: var(--radius-full);
  font-size: var(--t-cap-size); white-space: nowrap;
  border: var(--border-w) solid transparent; }
/* Приоритет клиента плашкой (просьба владельца 16.09.2026): в списке на тысячу строк
   слово одним начертанием не видно боковым зрением. Шкала — от красного к серому,
   как в файле ключевых клиентов: высший — тревожный, низкий — тихий. */
.prio-chip { display: inline-block; padding: 0 var(--row-px); border-radius: var(--radius-full);
  font-size: var(--t-cap-size); white-space: nowrap;
  border: var(--border-w) solid transparent; }
.prio-top  { background: var(--danger-bg);  color: var(--danger-fg);    border-color: var(--danger-border); }
.prio-high { background: var(--warning-bg); color: var(--warning-fg); }
.prio-mid  { background: var(--info-bg);    color: var(--accent-text); }
.prio-low  { background: var(--bg-inset);   color: var(--fg-secondary); }
.rel-target   { background: var(--bg-inset);    color: var(--fg-secondary); }
.rel-talks    { background: var(--info-bg);     color: var(--accent-text); }
.rel-working  { background: var(--success-bg);  color: var(--success-fg); }
.rel-regular  { background: var(--success-bg);  color: var(--success-fg);
                border-color: var(--success-border); }
.rel-sleeping { background: var(--warning-bg);  color: var(--warning-fg); }
.rel-lost     { background: var(--danger-bg);   color: var(--danger-fg); }
.site-link { text-decoration: none; margin-left: var(--space-1); }

/* Сегмент, приоритет и город в карточке клиента (14.09.2026) — три коротких поля
   одной строкой: это «кто клиент», их смотрят вместе. На телефоне — столбиком. */
.client-class { display: grid; gap: 0 var(--space-3);
  grid-template-columns: repeat(3, minmax(0, 1fr)); }
.client-class label { margin: var(--space-2) 0 0; min-width: 0; }
@media (max-width: 720px) { .client-class { grid-template-columns: 1fr; } }

/* Поиск и фильтры списка клиентов (14.09.2026). Девять фильтров сеткой, а не строкой:
   в .inline-row они разъезжались бы лесенкой. Колонка не уже подписи поля. */
.client-search label { margin: 0; min-width: 0; }
.client-search-grid { display: grid; gap: var(--space-2) var(--space-3);
  margin: var(--space-3) 0;
  grid-template-columns: repeat(auto-fill, minmax(var(--kv-label-w), 1fr)); }
.client-count { margin: var(--space-2) 0; }
.client-more-filters { margin: 0 0 var(--space-3); }
.client-more { margin: var(--space-3) 0; }
.client-back { margin: 0 0 var(--space-2); }
/* Дата и телефон рвались посреди значения: «2026-09-» / «14» (слепой критик 14.09.2026). */
.cell-nowrap { white-space: nowrap; }
/* «Целевой» получила рамку: светло-серая плашка сливалась с серой чётной строкой.
   «Первое касание» было контурным среди залитых соседей и читалось слабее «Целевого»,
   хотя стоит дальше по воронке (слепой критик 15.09.2026). Заливка усиливается по ходу
   воронки: серый → светло-голубой → голубой с рамкой → зелёный. */
.rel-touched { background: color-mix(in srgb, var(--info-bg) 55%, var(--bg-surface));
  color: var(--accent-text); }
.rel-talks   { border-color: var(--info-border); }
.rel-target { border-color: var(--border-hair); }
/* Переписка в карточке клиента (14.09.2026). Строка письма и темы — ровными колонками
   «дата · направление · тема · собеседник», чтобы глазом идти по датам столбиком.
   На телефоне — две строки: тема, под ней дата и собеседник (слепой критик 14.09.2026). */
.mail-head { margin: var(--space-2) 0; }
.mail-head input[type=search] { max-width: var(--kp-text-col); margin: 0; }
.mail-threads, .mail-list { list-style: none; margin: var(--space-2) 0; padding: 0; }
.mail-threads > li { border-top: var(--border-w) solid var(--border-hair); }
.mail-list { margin: 0 0 var(--space-2) 2ch; }
.mail-list > li { border-top: var(--border-w) solid var(--border-hair); }
#mail [data-search][hidden] { display: none; }
.mail-threads details { margin-top: 0; }
summary.mail-row { display: grid; gap: 0 var(--space-2); align-items: baseline; list-style: none;
  padding: var(--space-2) 0; color: var(--fg-primary); cursor: pointer;
  grid-template-columns: 2ch 8ch 4ch minmax(0, 1fr) minmax(0, 30%);
  grid-template-areas: "c d r s w"; }
summary.mail-row::-webkit-details-marker { display: none; }
summary.mail-row::before { content: "▸"; grid-area: c; color: var(--accent); }
details[open] > summary.mail-row::before { content: "▾"; }
.mail-date { grid-area: d; white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--fg-secondary); }
.mail-dir { grid-area: r; justify-self: start; padding: 0 var(--space-1); border-radius: var(--radius-md);
  font-size: var(--t-cap-size); text-align: center; min-width: 4ch; }
/* Направление видно не только словом: исходящее — тёмной плашкой, входящее — светлой. */
.mail-dir-out { background: var(--accent); color: var(--fg-on-accent); }
.mail-dir-in { background: var(--bg-inset); color: var(--fg-secondary); }
.mail-subj { grid-area: s; min-width: 0; overflow-wrap: anywhere; }
.mail-who { grid-area: w; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mail-body { white-space: pre-wrap; overflow-wrap: anywhere; max-width: 70ch;
  margin: 0 0 var(--space-2); padding: var(--space-2) var(--row-px); background: var(--bg-subtle);
  border-radius: var(--radius-md); font-size: var(--t-dense-size); }
.mail-quote { margin: 0 0 var(--space-2); }
.mail-quote > summary { font-size: var(--t-cap-size); }
.mail-quote .mail-body { max-height: 50vh; overflow: auto; }
@media (max-width: 720px) {
  summary.mail-row { grid-template-columns: 2ch auto minmax(0, 1fr);
    grid-template-areas: "c r s" ". d w"; }
}
.field-hint { display: block; margin-top: var(--space-1); color: var(--fg-muted);
  font-size: var(--t-cap-size); font-weight: var(--t-body-weight); }
.field-link { margin-left: var(--space-2); font-size: var(--t-cap-size);
  font-weight: var(--t-body-weight); }
/* Подвал карточки одним рядом: у «Удалить» своя линия сверху и отступ для отдельной
   зоны внизу страницы — внутри белого блока они давали ступеньку и обрывок линии. */
.card.record-actions { align-items: baseline; }
.card.record-actions .danger-zone { margin: 0; padding-top: 0; border-top: 0; }
.client-new input { min-width: 0; }
/* Список клиентов на телефоне — карточками, а не таблицей шире экрана: контакт
   с номером, ради которого кабинет открывают с телефона, уезжал за правый край. */
@media (max-width: 720px) {
  /* Двойной класс нарочно: «.list-scroll table.list { min-width }» стоит в файле ниже
     и при равном весе перебивал это правило — карточки оставались шириной 720 и
     обрезались справа, а замер ширины страницы этого не видел. */
  .list-scroll.client-list-scroll table.list { min-width: 0; border-collapse: separate;
    background: none; }
  .client-list-scroll table.list, .client-list-scroll table.list tbody,
  .client-list-scroll table.list tr, .client-list-scroll table.list td { display: block; }
  .client-list-scroll table.list tr:first-child { display: none; }
  .client-list-scroll table.list tr { margin-bottom: var(--space-2); padding: var(--space-2) var(--row-px);
    border: var(--border-w) solid var(--border-hair); border-radius: var(--radius-md);
    background: var(--bg-surface); }
  .client-list-scroll table.list tr:nth-child(n) td { border: 0; padding: var(--space-1) 0;
    background: none; }
  .client-list-scroll table.list td[data-label]::before { content: attr(data-label) ": ";
    color: var(--fg-muted); font-size: var(--t-cap-size); }
  .client-list-scroll table.list td.cell-wide-only { display: none; }
}
/* «Похоже» — опечатка, а не точное попадание: заметно, но без тревоги. */
.match-fuzzy { display: inline-block; margin-left: var(--space-1); padding: 0 var(--row-px);
  border-radius: var(--radius-full); font-size: var(--t-cap-size);
  background: var(--warning-bg); color: var(--warning-fg); }
/* Необратимое действие выделено словом и цветом: «Восстановить» и «Удалить насовсем»
   стоят рядом, и промах мышью не должен стоить расчёта. */
.danger-link { color: var(--danger-fg); }
textarea.mono, pre.summary { font-family: var(--font-mono); font-size: var(--t-cap-size); }
pre.summary { background: var(--bg-subtle); border: var(--border-w) solid var(--border-hair);
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3); white-space: pre-wrap; }
pre.issues { background: var(--warning-soft); }
/* Пропуска агентов (16.09.2026). Поле названия шире своей подсказки — в узкой ячейке
   «Где работает агент: «Codex…»» обрезалось на полуслове. Строки настроек переносятся:
   адрес кабинета одной строкой выталкивал страницу за край телефона. */
.agent-key-form input { width: 100%; }
/* Списки пропусков и стоп-листа — строками, а не таблицей: на телефоне таблица обрезала
   правые колонки вместе с кнопкой (слепой разбор 17.09.2026). */
.agent-key-list, .stop-list { list-style: none; padding: 0; margin: var(--space-2) 0; }
.agent-key-list li, .stop-list li { display: flex; flex-wrap: wrap; align-items: baseline;
  gap: var(--space-1) var(--space-3); padding: var(--space-2) 0;
  border-top: var(--border-w) solid var(--border-hair); }
.agent-key-list li > div:first-child, .stop-list li > div:first-child { flex: 1 1 16rem;
  min-width: 0; overflow-wrap: anywhere; }
.agent-key-list li.is-revoked { color: var(--fg-muted); }
.agent-keys > p.small, .stop-list-intro { max-width: var(--kp-text-col); }
.agent-key-form { margin-top: var(--space-3); }
.stop-list-form { display: grid; gap: var(--space-1); max-width: var(--kp-text-col); }
/* Предупреждение — не ошибка: красный «ошибка» на странице удачной выдачи пугал. */
.note-warn { color: var(--warning-fg); background: var(--warning-bg); font-weight: 600; max-width: var(--kp-text-col);
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); }
/* Серая плашка-пометка: «вся компания», «не использовался», «агент». */
.tag { display: inline-block; padding: 0 var(--space-2); border-radius: var(--radius-full);
  background: var(--bg-inset); color: var(--fg-secondary); font-size: var(--t-cap-size);
  font-weight: var(--t-body-weight); white-space: nowrap; }
.tag-agent { background: var(--info-bg); color: var(--accent-text); }
/* Жёлтая пометка — то, что требует внимания: запрет на всю компанию, пропуск, ни разу не
   входивший. Серая на сером фоне не читалась как пометка вовсе (слепой критик 17.09.2026). */
.tag-warn { background: var(--warning-bg); color: var(--warning-fg); }
.btn.btn-warn { background: var(--warning-bg); color: var(--warning-fg); border-color: var(--warning-fg); }
/* Хвост пропуска — моноширинным, как в файле настроек: I, l, 1 и O, 0 иначе не различить. */
code.key-tail { font-family: var(--font-mono); font-size: 0.95em; }
/* Кнопки решения — под строкой брони на любой ширине: справа через весь экран взгляд промахивался
   строкой. На телефоне — во всю ширину. */
.hold-list li > div:first-child { flex-basis: 100%; }
.agent-key-steps { max-width: var(--kp-text-col); }
.agent-key-steps li { margin: var(--space-1) 0; }
@media (max-width: 40rem) {
  .hold-decide { flex-direction: column; align-items: stretch; width: 100%; }
  .hold-decide form, .hold-decide .btn { width: 100%; }
}
.agent-key-form { display: grid; gap: var(--space-2); max-width: var(--kp-text-col); }
.agent-key-form label { display: grid; gap: var(--space-1); }
.agent-keys-intro { max-width: var(--kp-text-col); }
/* Перенос длинного пропуска — с отступом: начало каждой настоящей строки видно сразу
   (на телефоне ключ ломался на четыре строки, а текст говорил «обе строки»). Отступ — у
   каждой строки отдельно: общий на весь блок сдвигал вторую строку целиком. */
pre.agent-env .env-line { display: block; padding-left: 3ch; text-indent: -3ch; }
pre.agent-env {
  white-space: pre-wrap; overflow-wrap: anywhere; font-family: var(--font-mono);
  background: var(--bg-subtle); border: var(--border-w) solid var(--border-hair);
  border-radius: var(--radius-md); padding: var(--space-2) var(--space-3); }
.btn { display: inline-block; padding: var(--space-2) var(--space-4);
  border: var(--border-w) solid var(--border-default); border-radius: var(--radius-md);
  background: var(--bg-surface); font: inherit; font-weight: var(--t-btn-weight);
  cursor: pointer; text-decoration: none; color: var(--fg-primary); }
.btn:hover { background: var(--bg-subtle); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--fg-on-accent); }
.btn.primary:hover { background: var(--accent-hover); }
/* Выключенная главная кнопка была бледно-синей с белым текстом — 2,3:1, то есть
   подпись на ней не читалась вовсе. Система выключенное красит серым по правилу
   «выключенный контрол обязан быть прочитан, иначе непонятно, чего именно нельзя». */
.btn.primary:disabled { background: var(--bg-muted); border-color: var(--ink-200);
  color: var(--fg-disabled); cursor: not-allowed; }
.btn.danger { background: var(--danger-fg); border-color: var(--danger-fg); color: var(--fg-on-accent); }
.btn.danger:hover { background: var(--danger-hover); border-color: var(--danger-hover); }
.btn.big { font-size: var(--t-h2-size); padding: var(--space-3) var(--space-6); }
/* Кольцо фокуса. Было светло-голубым (#8AB8DE) — 1,9:1 к белому листу, то есть
   человек, который ходит по кабинету с клавиатуры, не видел, где он находится.
   Системный --focus-color даёт 5,7:1. */
.btn:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible,
button:focus-visible, a:focus-visible { outline: var(--border-w-strong) solid var(--focus-color);
  outline-offset: var(--border-w-strong); }
/* В тёмной шапке тот же тёмно-синий даёт 1,3:1 и пропадает. Там кольцо белое —
   так же, как это решено в самой системе (--focus-ring-header). */
nav a:focus-visible, nav button:focus-visible { outline-color: var(--white); }
button.link { background: none; border: none; color: var(--fg-link); cursor: pointer; font: inherit;
  text-decoration: underline; padding: 0; }
.danger-link { color: var(--danger-hover) !important; }
form.inline { display: inline; }
.visually-hidden { position: absolute !important; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
.row-action { width: 1%; white-space: nowrap; text-align: end; }
.record-actions { display: flex; align-items: flex-start; gap: var(--gap-block); flex-wrap: wrap;
  margin: var(--space-4) 0; }
.danger-zone { max-width: var(--kp-text-col); margin: var(--space-8) 0 0; padding-top: var(--space-3);
  border-top: var(--border-w) solid var(--border-hair); color: var(--fg-secondary); }
.danger-zone summary { width: fit-content; color: var(--danger-hover); font-weight: 600; }
.danger-zone p { max-width: 68ch; line-height: var(--t-body-lh); }
.inline-row { display: flex; gap: var(--gap-inline); align-items: center; flex-wrap: wrap; }
.inline-row input, .inline-row select { width: auto; margin: 0; }
.inline-row .radio { display: inline-flex; align-items: center; gap: var(--space-1);
  font-weight: var(--t-body-weight); margin: 0; }
.inline-row .radio input { width: auto; }
.toolbar { margin: var(--space-3) 0; display: flex; gap: var(--gap-inline); }
.filters { margin: var(--space-2) 0 var(--space-4); display: flex; gap: var(--gap-inline); flex-wrap: wrap; }
.filters a { padding: var(--space-1) var(--space-3); border-radius: var(--radius-full);
  background: var(--bg-muted); color: var(--fg-secondary);
  text-decoration: none; font-size: var(--t-cap-size); }
.filters a.on { background: var(--bg-header); color: var(--fg-on-accent); }
table.list { border-collapse: collapse; background: var(--bg-surface); width: 100%; }
/* Шапка таблицы — своя ступень набора (13, полужирный, волосяная разрядка),
   и своя заливка --bg-thead: 5,90:1 против 4,51:1 у заливки кнопки. Шапку
   себестоимости менеджер держит перед глазами весь рабочий день. */
table.list th { background: var(--bg-thead); color: var(--fg-on-accent);
  padding: var(--space-2) var(--row-px); text-align: left;
  font-size: var(--t-thead-size); line-height: var(--t-thead-lh);
  font-weight: var(--t-thead-weight); letter-spacing: var(--t-thead-tracking); }
table.list td { border: var(--border-w) solid var(--border-hair);
  padding: var(--row-py) var(--row-px); font-size: var(--t-dense-size); }
table.list tr:nth-child(even) td { background: var(--bg-subtle); }
/* position: relative — не украшение. Скрытая подпись колонки (.visually-hidden в
   заголовке «Действия») стоит position: absolute и без позиционированного предка
   выпадает из прокрутки таблицы: на телефоне она раздвигала ВСЮ страницу до ширины
   таблицы (список клиентов — 961 точка при экране 390). Замер 14.09.2026. */
.scroll { position: relative; width: 100%; max-width: 100%; min-width: 0; overflow-x: auto; }
.list-scroll table.list { min-width: var(--kp-tbl-min); }
.order-list-scroll table.list { min-width: var(--kp-tbl-min-wide); }
.list-scroll:focus-visible { outline: var(--border-w-strong) solid var(--focus-color);
  outline-offset: var(--border-w-strong); }
.status-line { font-size: var(--t-body-size); }

/* Строгий Excel-импорт клиентов */
.page-head { display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--gap-block); flex-wrap: wrap; margin-bottom: var(--space-3); }
.page-head h1, .page-head h2 { margin: 0 0 var(--space-1); }
.page-head.compact { align-items: center; margin-top: var(--space-6); }
.import-lead { max-width: 72ch; margin: 0; color: var(--fg-secondary); line-height: var(--t-body-lh); }
.import-steps { counter-reset: import-step; list-style: none; margin: var(--space-4) 0;
  padding: 0; background: var(--bg-surface); border: var(--border-w) solid var(--border-hair);
  border-radius: var(--radius-lg); }
.import-steps li { counter-increment: import-step; display: grid;
  grid-template-columns: var(--space-8) minmax(var(--kp-step-name-min), var(--kp-step-name-max)) 1fr auto;
  gap: var(--space-3);
  align-items: center; padding: var(--space-3) var(--pad-card-x);
  border-bottom: var(--border-w) solid var(--border-hair); }
.import-steps li > * { min-width: 0; }
.import-steps li:last-child { border-bottom: 0; }
.import-steps li::before { content: counter(import-step);
  width: var(--step-dot); height: var(--step-dot);
  display: grid; place-items: center; border-radius: 50%; background: var(--bg-header);
  color: var(--fg-on-accent); font-size: var(--t-cap-size); font-weight: 700; }
.import-steps span { color: var(--fg-muted); line-height: var(--t-dense-lh); }
.import-upload { max-width: var(--kp-text-col); }
.import-upload input[type=file] { padding: var(--space-2); background: var(--bg-subtle); }
.import-upload .muted, .import-preview .muted { color: var(--fg-muted); }
.import-summary { display: flex; gap: var(--gap-inline); flex-wrap: wrap; }
.import-count, .import-state { display: inline-flex; align-items: center; gap: var(--space-1);
  border-radius: var(--radius-full); padding: var(--space-1) var(--row-px);
  font-size: var(--t-cap-size); white-space: nowrap; }
.import-count.new, .import-state.new { background: var(--success-bg); color: var(--success-fg); }
.import-count.exists, .import-state.exists { background: var(--bg-muted); color: var(--fg-secondary); }
.import-count.error-state, .import-state.error { background: var(--danger-bg); color: var(--danger-hover); }
.import-table { min-width: var(--kp-tbl-min-wide); }
.import-table-scroll:focus-visible { outline: var(--border-w-strong) solid var(--focus-color);
  outline-offset: var(--border-w-strong); }
.import-table td { vertical-align: top; }
.import-table td.num { width: var(--cell-num-w); text-align: right;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.import-table tr.import-row-error td { background: var(--danger-row); }
/* Строк «новый» в импорте бывает вся таблица — заливка втрое тише зелёной метки,
   иначе весь лист зелёный и метка ничего не значит. */
.import-table tr.import-row-new td {
  background: color-mix(in srgb, var(--success-bg) 35%, var(--bg-surface)); }
.import-message { display: block; margin: var(--space-1) 0; color: var(--fg-secondary); }
.import-confirm { display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-6); margin-top: var(--space-4); }
.import-confirm h2, .import-confirm p { margin: 0 0 var(--space-1); }
@media (max-width: 760px) {
  .import-steps li { grid-template-columns: var(--space-8) 1fr; align-items: start; }
  .import-steps li span, .import-steps li .btn { grid-column: 2; }
  .import-steps li .btn { width: 100%; text-align: center; }
  .import-confirm { align-items: stretch; flex-direction: column; }
  .import-confirm .btn { width: 100%; text-align: center; }
}

.login-box { max-width: var(--popover-w); margin: var(--space-12) auto;
  background: var(--bg-surface); padding: var(--space-8);
  border-radius: var(--radius-lg); border: var(--border-w) solid var(--border-hair); }
.spinner { width: var(--space-8); height: var(--space-8); margin: 0 auto var(--space-3);
  border: var(--border-w-strong) solid var(--bg-muted);
  border-top-color: var(--accent); border-radius: 50%; animation: spin 0.9s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* Система запрещает движение везде, кроме знака «идёт работа», — и уважает
   системную настройку «поменьше движения»: с ней круг просто стои́т. */
@media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }
details { margin-top: var(--space-3); }
details summary { cursor: pointer; color: var(--fg-link); }
.actions form { margin-right: var(--space-3); }
.actions input { width: var(--kp-input-narrow); }

/* витрина выбора доставки (страница заказа) */
table.pick-table { border-collapse: collapse; background: var(--bg-surface);
  margin: var(--space-1) 0 var(--space-3); }
table.pick-table th { background: var(--bg-thead); color: var(--fg-on-accent);
  padding: var(--row-py) var(--row-px); text-align: left;
  font-size: var(--t-thead-size); line-height: var(--t-thead-lh);
  font-weight: var(--t-thead-weight); letter-spacing: var(--t-thead-tracking); }
table.pick-table td { border: var(--border-w) solid var(--border-hair);
  padding: var(--row-py) var(--row-px); font-size: var(--t-dense-size); }
table.pick-table td.num { text-align: right; font-family: var(--font-mono);
  font-variant-numeric: tabular-nums; }
table.pick-table tr.picked td { background: var(--success-bg); font-weight: 600; }
/* Свёрнутые варианты доставки: в строке-сводке стои́т то, что заложено в цену. */
details.pick-fold { margin: var(--space-1) 0 var(--space-3); }
details.pick-fold > summary { color: var(--fg-primary); padding: var(--space-2) var(--row-px);
  background: var(--success-bg);
  border: var(--border-w) solid var(--success-border); border-radius: var(--radius-md); }
details.pick-fold > summary:hover {
  background: color-mix(in srgb, var(--success-border) 22%, var(--bg-surface)); }
details.pick-fold > summary .muted { color: var(--fg-secondary); }

/* энциклопедия: превью файлов карточки */
.thumbs { display: flex; gap: var(--space-3); flex-wrap: wrap; }
.thumb { text-align: center; }
.thumb img { max-width: var(--tile); max-height: var(--tile);
  border: var(--border-w) solid var(--border-hair); border-radius: var(--radius-md);
  display: block; margin-bottom: var(--space-1); }

/* ползунок диапазона плотности в справочнике тканей */
.range-box { display: inline-flex; align-items: center; gap: var(--gap-inline);
  background: var(--bg-surface);
  border: var(--border-w) solid var(--border-default); border-radius: var(--radius-md);
  padding: var(--space-1) var(--space-3); flex-wrap: wrap; }
.range-box label { display: inline-flex; align-items: center; gap: var(--space-1); margin: 0;
  font-weight: var(--t-body-weight); color: var(--fg-secondary); }
.range-box input[type=range] { width: var(--kp-input-narrow); margin: 0; }

/* тендерный контур: описание закупки, документы, трек образца */
table.kv { border-collapse: collapse; background: var(--bg-surface); width: 100%; }
table.kv th { text-align: left; vertical-align: top;
  padding: var(--space-1) var(--space-3) var(--space-1) 0; color: var(--fg-secondary);
  font-weight: 600; white-space: nowrap; width: var(--kv-label-w);
  border-bottom: var(--border-w) solid var(--border-hair); }
table.kv td { padding: var(--space-1) 0; border-bottom: var(--border-w) solid var(--border-hair); }
.doc-list { margin: var(--space-2) 0; padding-left: var(--space-6); }
.doc-list li { margin: var(--space-1) 0; }
.stage { display: inline-block; padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-md); background: var(--bg-subtle);
  color: var(--fg-muted); margin: var(--space-1) 0; }
.stage.stage-done { background: var(--success-bg); color: var(--success-fg); font-weight: 600; }

/* экран «Поиск в Китае» */
.china-tabs { display: flex; flex-direction: column; gap: var(--space-1); margin-bottom: var(--space-2); }
.china-tabs label { font-weight: var(--t-body-weight); }
.china-filters { border-left: var(--kp-stripe-w) solid var(--border-hair);
  padding-left: var(--space-3); margin: var(--space-2) 0; }
.china-filters .f-row { display: flex; gap: var(--gap-inline); align-items: center;
  flex-wrap: wrap; margin: var(--space-1) 0; }
.china-filters .f-row input[type=text], .china-filters .f-row input:not([type]) {
  flex: 1 1 var(--kv-label-w); }
.china-filters label.f-on { font-weight: var(--t-body-weight); white-space: nowrap; margin: 0; }
.china-filters .f-hint { margin: var(--space-1) 0 var(--space-2) var(--space-6);
  font-size: var(--t-label-size); }
.suggest { display: block; margin: var(--space-1) 0; }
.landed { background: var(--success-bg); border-left: var(--kp-stripe-w) solid var(--success-border);
  padding: var(--space-1) var(--row-px); }
/* карточка результата — фото слева, данные справа */
.china-row { display: flex; gap: var(--space-3); align-items: flex-start; }
.china-row img.thumb { width: var(--tile); height: var(--tile); object-fit: cover; flex: 0 0 auto; }
.china-row h3 { margin: 0 0 var(--space-1); font-size: var(--t-h3-size); }
.china-row p { margin: var(--space-1) 0; }
@media (max-width: 600px) { .china-row { flex-direction: column; } }

/* пояснение при наведении (нативная подсказка браузера — без скриптов) */
.hint-hover { cursor: help; border-bottom: var(--border-w) dotted var(--border-strong); }
/* Кружок «?» вырос с 15 до 20 точек и с 11 кегля до 12: мельче 12 в системе
   нет ничего, а по этому кружку ещё и целятся мышью. */
.hint-mark {
  display: inline-block; width: var(--icon-lg); height: var(--icon-lg); line-height: var(--icon-lg);
  text-align: center; border-radius: 50%; background: var(--bg-muted); color: var(--fg-secondary);
  font-size: var(--t-label-size); font-weight: 600; margin-left: var(--space-1);
}
/* расшифровка расчёта ввоза */
.landed table { width: auto; min-width: 60%; }
.landed td { padding: var(--space-1) var(--pad-card-x) var(--space-1) 0; }
.landed td.num { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* Кнопка «✓ Проверил» — тише, чем «Сохранить»: она ничего не меняет в цифрах,
   она лишь отмечает, что человек посмотрел и согласен. */
/* 🔴 nowrap обязателен — как у соседних «Сохранить» и «×». Столбец действий узкий,
   и без него надпись рассыпается в столбик по одной букве: «П р о в е р и л». */
.kp-row-check { background: var(--bg-surface); border: var(--border-w) solid var(--success-border);
                color: var(--success-fg); white-space: nowrap;
                border-radius: var(--radius-sm); padding: var(--space-1) var(--space-2);
                font-size: var(--t-label-size); cursor: pointer; }
.kp-row-check:hover { background: var(--success-bg); }

/* ── Метка давности черновика (Ф-85, блок 1Ж) ───────────────────────────── */
/* Форма отличается от таблетки стадии НАРОЧНО: у стадии те же три цвета значат
   другое (красный = «Отказ»). Прямая плашка с числом часов и полосой слева
   опознаётся и в чёрно-белой печати, и рядом со стадией не сливается.
   Полоса слева взята --kp-stripe-w — единая с остальными полосами кабинета. */
.age { display: inline-block; padding: 0 var(--space-2) 0 var(--space-1);
       border-radius: var(--radius-sm);
       border-left: var(--kp-stripe-w) solid; font-size: var(--t-label-size); white-space: nowrap; }
.age-green  { border-color: var(--success-fg); background: var(--success-bg); color: var(--success-fg); }
.age-yellow { border-color: var(--warning-fg); background: var(--warning-soft); color: var(--warning-fg); }
.age-red    { border-color: var(--danger-fg);  background: var(--danger-row);  color: var(--danger-fg);
              font-weight: 600; }
.age-cell   { white-space: nowrap; }

/* ── Светофор заказа (Ф-12, блок 1Д) ────────────────────────────────────── */
.svetofor { padding: var(--space-3) var(--space-4); }
.stage-line { display: flex; flex-wrap: wrap; gap: var(--gap-inline); margin-bottom: var(--space-2); }
.stage-chip { padding: var(--space-1) var(--row-px);
  border: var(--border-w) solid var(--border-hair); border-radius: var(--radius-full);
  background: var(--bg-subtle); color: var(--fg-muted); font-size: var(--t-cap-size);
  white-space: nowrap; }
.stage-chip.on { background: var(--bg-header); border-color: var(--bg-header);
  color: var(--fg-on-accent); font-weight: 600; }
.stage-actions { display: flex; flex-wrap: wrap; gap: var(--gap-inline); align-items: center; }
.stale { color: var(--warning-fg); font-weight: 600; font-size: var(--t-cap-size); }
.filters-tech { margin: calc(var(--space-1) * -1) 0 var(--space-3); }
.filters-tech summary { cursor: pointer; font-size: var(--t-cap-size); }
.filters-tech a { margin-right: var(--gap-inline); font-size: var(--t-cap-size); }

/* ── Карточка заказа: метки происхождения (Ф-32) ────────────────────────── */
.card-grid-wrap { overflow-x: auto; overscroll-behavior-inline: contain; }
.card-grid { table-layout: fixed; width: 100%; min-width: var(--kp-tbl-min); }
.card-grid col.card-label { width: 42%; }
.card-grid col.card-origin { width: var(--kp-origin-col); }
.card-grid td { vertical-align: top; padding: var(--space-1) var(--row-px); overflow-wrap: anywhere; }
.card-grid th { background: var(--bg-inset); text-align: left;
  padding: var(--row-py) var(--row-px);
  font-size: var(--t-thead-size); line-height: var(--t-thead-lh);
  font-weight: var(--t-thead-weight); letter-spacing: var(--t-thead-tracking); }
.small { font-size: var(--t-label-size); }
.mk { display: inline-block; padding: 0 var(--space-2); border-radius: var(--radius-full);
  font-size: var(--t-label-size);
  white-space: nowrap; cursor: help; }
.mk-from_tz   { background: var(--success-bg); color: var(--success-fg); }   /* вычитано из документа */
.mk-manager   { background: var(--info-bg);    color: var(--accent-text); }  /* вписал человек */
.mk-engine    { background: var(--warning-bg); color: var(--warning-fg); }   /* догадка движка */
.mk-confirmed { background: var(--success-fg); color: var(--fg-on-accent); } /* человек подтвердил */
.assumptions { background: var(--warning-soft);
  border-left: var(--kp-stripe-w) solid var(--warning-border);
  padding: var(--space-2) var(--space-3); margin-top: var(--space-3); }
.assumptions ul { margin: var(--space-1) 0 0; padding-left: var(--space-6); }

/* ── Двухколоночная строка формы (label + узкое поле): быстрый ввод (Ф-65) ── */
.q-row { display: flex; gap: var(--gap-block); align-items: flex-start; padding: var(--space-2) 0;
  border-bottom: var(--border-w) solid var(--border-hair); }
.q-ask { flex: 1 1 auto; }
.q-input { flex: 0 0 var(--kv-label-w); }
.q-input input, .q-input select { width: 100%; }
@media (max-width: 640px) { .q-row { flex-direction: column; } .q-input { flex: 1 1 auto; width: 100%; } }

/* Страница задания (Ф-44…Ф-45): фотографии смотрятся не скачивая. */
.task-main { margin: var(--space-1) 0 var(--space-2); }
.task-main img { max-width: 100%; max-height: 60vh; border-radius: var(--radius-md);
  border: var(--border-w) solid var(--border-hair); }
.task-tiles { display: flex; flex-wrap: wrap; gap: var(--gap-inline); }
.task-tiles figure { margin: 0; width: var(--tile); text-align: center; }
.task-tiles img { width: var(--tile); height: var(--tile); object-fit: cover;
  border-radius: var(--radius-md); border: var(--border-w) solid var(--border-hair); }
.task-shot { cursor: zoom-in; }
.task-text { white-space: pre-wrap; word-break: break-word; font-family: inherit;
  font-size: var(--t-dense-size); margin: 0; max-height: 60vh; overflow: auto; }
.lightbox { position: fixed; inset: 0; z-index: 50; background: var(--scrim);
  display: flex; align-items: center; justify-content: center; gap: var(--gap-inline); }
.lightbox.hidden { display: none; }
.lightbox img { max-width: 88vw; max-height: 88vh; object-fit: contain; }
.lightbox button { background: color-mix(in srgb, var(--white) 14%, transparent);
  color: var(--white); border: 0;
  font-size: var(--t-h1-size); line-height: 1; padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md); cursor: pointer; }
.lightbox button:hover { background: color-mix(in srgb, var(--white) 26%, transparent); }
.lb-close { position: absolute; top: var(--space-4); right: var(--space-4); font-size: var(--t-h1-size); }
@media (max-width: 640px) {
  .task-tiles figure, .task-tiles img { width: var(--tile-sm); }
  .task-tiles img { height: var(--tile-sm); }
  .lightbox button { font-size: var(--t-h2-size); padding: var(--space-2) var(--space-3); }
}

/* Правка себестоимости (Ф-37…Ф-40) */
/* Подложки взяты из системы по смыслу: «нет цены» — красная строка (--danger-row),
   «изменена» — самая бледная ступень стали (--steel-050). Голубым в таблице
   кодируется состояние, а не подсветка под курсором, — поэтому третьего
   голубого здесь нет. */
tr.row-hole { background: var(--danger-row); }
tr.row-changed { background: var(--steel-050); }
tr.row-changed td:first-child { border-left: var(--kp-stripe-w) solid var(--accent); }

/* ── ЗНАКИ СОСТОЯНИЙ ────────────────────────────────────────────────────────
   🔴 Пришли на смену эмодзи (решение владельца 01.09.2026). Эмодзи рисует не мы,
   а машина: у менеджера на Windows, у владельца на маке и на планшете цеха один
   и тот же кружок выходит разным по размеру, весу и оттенку, а часть знаков не
   рисуется вовсе. И стадия держалась на ОДНОЙ КРАСКЕ: семь одинаковых кружков,
   отличимых только цветом. Здесь у каждой стадии СВОЯ ФОРМА — она доживает и до
   чёрно-белой печати, куда цветная плашка не доезжает (в настройках печати Chrome
   фоновая графика выключена по умолчанию, и кружок становился пустым квадратиком
   в каждой строке). Форма несёт смысл, цвет только помогает. */
/* 🔴 Размер и обводку знака задаём ЗДЕСЬ, а не наследуем от класса .icon системы:
   он живёт в её ui.css, а ui.css в кабинет пока не подключён — из 184 его классов
   кабинету не на что надеть 167. Без этих правил svg не имеет размера вовсе и
   разворачивается во всю ширину ячейки чёрным пятном: поймано снимком 01.09.2026,
   первый же кадр после замены эмодзи. Когда дойдём до шага компонентов и подключим
   ui.css целиком — этот блок уедет, а .icon возьмёт своё. */
.zn {
  width: var(--icon-md); height: var(--icon-md);
  flex: 0 0 auto; display: inline-block; vertical-align: -0.15em; margin-right: .35em;
  fill: none; stroke: currentColor; stroke-width: var(--icon-stroke);
  stroke-linecap: round; stroke-linejoin: round;
}
/* Знаки состояний — заливкой, а не штрихом: в 16 пикселях контур теряет силуэт,
   а стадию надо опознавать боковым зрением, пробегая колонку. */
.icon--solid.zn, .zn.icon--solid { fill: currentColor; stroke: none; }
.zn--calc     { color: var(--accent); }
.zn--kp_ready { color: var(--amber-800); }
.zn--kp_sent  { color: var(--accent); }
.zn--refused  { color: var(--red-600); }
.zn--in_work  { color: var(--accent); }
.zn--shipping { color: var(--accent); }
.zn--done     { color: var(--green-700); }
/* В тёмной шапке и на залитой плашке знак идёт в цвет текста рядом, а не своим:
   иначе на синем фоне он тонет, а на выбранной плашке спорит с подписью. */
nav .zn, .stage-chip.on .zn, .btn .zn, .chip.on .zn { color: currentColor; }
