/* =========================================================================
   ERP — базовая система стилей. Без зависимостей и сборки.
   ========================================================================= */

:root {
  --bg:            #f4f6f8;
  --surface:       #ffffff;
  --surface-2:     #fafbfc;
  --surface-3:     #f1f3f6;
  --border:        #e3e7ec;
  /* `--line` — то же, что `--border` (v6.132.0). Им пользовались блоки
     6.10x–6.131 (одобрения, поставщик, сверка), а объявлен он не был —
     и линии-разделители там молча не рисовались. */
  --line:          var(--border);
  --border-strong: #cfd6de;
  --text:          #10151c;
  --text-2:        #47525f;
  /* Контраст доведён до нормы 4,5:1 (v3.24, UX-033).
     Было #7a8694 — 3,71:1 на белом и 3,33:1 на сером фоне таблиц: на
     хорошем мониторе незаметно, на ноутбуке у окна подписи читались с
     трудом. Стало 5,10:1 на белом и 4,59:1 на самом светлом сером —
     то есть норма выполняется на всех фонах системы, а не только на белом.
     Разница на глаз небольшая: текст остался второстепенным. */
  --muted:         #656f7c;
  --accent:        #2563eb;
  --accent-dark:   #1d4ed8;
  --accent-soft:   #eaf1ff;

  --green:  #12855a;  --green-soft:  #e6f6ee;
  --amber:  #b06a00;  --amber-soft:  #fdf2df;
  --red:    #c02626;  --red-soft:    #fdeceb;
  --violet: #6d3ae0;  --violet-soft: #f1ecfe;
  --cyan:   #0e7490;  --cyan-soft:   #e2f5fa;
  --grey:   #64748b;  --grey-soft:   #eef1f5;
  /* Доставлен и Оплачен раньше были одного цвета и сливались (v2.2) */
  --teal:   #0f766e;  --teal-soft:   #dcf5f1;
  --pink:   #b83280;  --pink-soft:   #fce8f3;
  /* Палитра статусов заказа задана заказчиком (v2.4) */
  --yellow: #a16207;  --yellow-soft: #fef7c3;
  --orange: #c2410c;  --orange-soft: #ffece0;
  --green-bright: #15803d; --green-bright-soft: #d9f7e4;
  /* Индиго добавлен в v6.23.1: «Передан на сборку» делил красный с «Отменён» */
  --indigo: #4338ca;  --indigo-soft: #eef2ff;

  --radius:    10px;
  --radius-sm: 7px;
  --radius-lg: 14px;
  --shadow-1:  0 1px 2px rgba(16, 21, 28, .05), 0 1px 3px rgba(16, 21, 28, .04);
  --shadow-2:  0 4px 14px rgba(16, 21, 28, .08);
  --shadow-3:  0 12px 40px rgba(16, 21, 28, .16);

  --sidebar-w:   244px;
  --topbar-h:    56px;

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
          "Noto Sans", "Liberation Sans", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.45;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}

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

h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -.01em; }
h1 { font-size: 20px; }
h2 { font-size: 17px; }
h3 { font-size: 15px; }
p  { margin: 0 0 10px; }

/* Значок садится на базовую линию текста, а не на строку целиком (v6.23.0,
   замечание заказчика: «сами буквы должны чуть-чуть подняться, они ниже
   стрелки»). У svg по умолчанию `vertical-align: baseline`, и внутри кнопки
   он приподнимал строку над собой — подпись выглядела опущенной. */
.ic { width: 18px; height: 18px; flex: 0 0 auto; vertical-align: middle; }
.ic-lg { width: 22px; height: 22px; }
.ic-sm { width: 15px; height: 15px; }

.muted     { color: var(--muted); }
.text-2    { color: var(--text-2); }
.small     { font-size: 12.5px; }
.xs        { font-size: 11.5px; }
.mono      { font-family: var(--mono); font-size: 12.5px; }
.bold      { font-weight: 600; }
.right     { text-align: right; }
.center    { text-align: center; }
.nowrap    { white-space: nowrap; }
/* Ссылка, которая не выглядит ссылкой (v3.18): имя клиента в списках —
   это в первую очередь имя, а синий цвет на каждой строке рябит.
   Подчёркивание и указатель появляются при наведении, так что понять,
   что это кликабельно, по-прежнему можно. */
.lnk-plain { color: var(--text); font-weight: 600; text-decoration: none; }
.lnk-plain:hover, .lnk-plain:focus-visible { text-decoration: underline; }
.pos       { color: var(--green); }
.neg       { color: var(--red); }
.hidden    { display: none !important; }
.w-100     { width: 100%; }
.mt-0 { margin-top: 0 } .mt-1 { margin-top: 8px } .mt-2 { margin-top: 16px } .mt-3 { margin-top: 24px }
.pt-0 { padding-top: 0 }
.mb-0 { margin-bottom: 0 } .mb-1 { margin-bottom: 8px } .mb-2 { margin-bottom: 16px } .mb-3 { margin-bottom: 24px }
.gap-1 { gap: 8px } .gap-2 { gap: 16px }
.flex  { display: flex; align-items: center; min-width: 0; }
.flex-between { display: flex; align-items: center; justify-content: space-between; }
.flex-wrap { flex-wrap: wrap; }
/* Отодвинуть остаток строки вправо: опасное действие стоит на той же
   полке, что и обычные кнопки, но на другом её конце (v3.41.2) */
.push-right { margin-left: auto; }

/* Плитка-ссылка: остаток на счёте открывает операции по этому счёту (v3.42) */
a.kpi-link { text-decoration: none; color: inherit; transition: border-color .12s, transform .12s; }
a.kpi-link:hover { border-color: var(--accent); transform: translateY(-1px); }
a.kpi-link.on { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.flex-1 { flex: 1; min-width: 0; }
.grow { flex-grow: 1; }
.stack { display: flex; flex-direction: column; }

/* =========================== Каркас =========================== */

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

.sidebar {
  width: var(--sidebar-w);
  flex: 0 0 var(--sidebar-w);
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh;
  transition: width .16s ease, flex-basis .16s ease;
  z-index: 40;
}
/* Свёрнутого меню больше нет (v3.28): кнопку у поиска заказчик попросил
   убрать, а стили состояния, в которое теперь нечем перевести, — мёртвые. */

.brand {
  height: var(--topbar-h);
  display: flex; align-items: center; gap: 10px;
  padding: 0 14px;
  border-bottom: 1px solid var(--border);
  flex: 0 0 auto;
  /* Логотип — ссылка на главную, но выглядеть должен как раньше: тот же
     цвет текста, без подчёркивания. Только курсор показывает, что нажимается (v3.16) */
  color: var(--text); text-decoration: none; cursor: pointer;
}
.brand:hover { color: var(--text); text-decoration: none; }
.brand-mark {
  width: 28px; height: 28px; border-radius: 8px;
  background: linear-gradient(135deg, var(--accent), #4f7cf7);
  color: #fff; display: grid; place-items: center;
  font-weight: 700; font-size: 13px; letter-spacing: -.02em;
  flex: 0 0 auto;
}
.brand-text { font-weight: 650; font-size: 14.5px; white-space: nowrap; overflow: hidden; }

.nav { flex: 1 1 auto; overflow-y: auto; padding: 8px 8px 20px; }
.nav::-webkit-scrollbar { width: 8px; }
.nav::-webkit-scrollbar-thumb { background: #dfe4ea; border-radius: 8px; }

.nav-group { margin-bottom: 2px; }
.nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: var(--radius-sm);
  color: var(--text-2); font-weight: 500; font-size: 13.5px;
  cursor: pointer; user-select: none; white-space: nowrap;
}
/* Заголовок раздела теперь кнопка (v3.20, UX-032) — чтобы до него можно
   было добраться с клавиатуры. Выглядеть он должен ровно как раньше,
   поэтому снимаем всё, что браузер рисует кнопке по умолчанию. */
button.nav-item {
  width: 100%; margin: 0; text-align: left;
  background: none; border: 0; font-family: inherit; line-height: inherit;
}
button.nav-item:focus-visible {
  outline: 2px solid var(--accent); outline-offset: -2px;
}
.nav-item:hover { background: var(--surface-3); text-decoration: none; color: var(--text); }
.nav-item.active { background: var(--accent-soft); color: var(--accent-dark); font-weight: 600; }
.nav-item .ic { color: currentColor; opacity: .85; }
.nav-item .chev { margin-left: auto; width: 14px; height: 14px; transition: transform .15s; opacity: .5; }
.nav-group.open .chev { transform: rotate(90deg); }
.nav-sub { padding: 2px 0 6px 34px; display: none; }
.nav-group.open .nav-sub { display: block; }
.nav-sub a {
  display: block; padding: 6px 10px; border-radius: var(--radius-sm);
  color: var(--text-2); font-size: 13px;
}
.nav-sub a:hover { background: var(--surface-3); text-decoration: none; color: var(--text); }
.nav-sub a.active { color: var(--accent-dark); background: var(--accent-soft); font-weight: 600; }
/* Служебные пункты меню (v6.49.0, предложение 66): отделены чертой, подписаны
   и приглушены. Видно, что это не ежедневная работа, — но добраться до них
   по-прежнему можно в два клика. */
.nav-dev-head { margin: 6px 0 2px; padding: 4px 12px 0; border-top: 1px solid var(--border);
  font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.nav-sub a.nav-dev { opacity: .7; }
.nav-sub a.nav-dev:hover { opacity: 1; }

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

.topbar {
  height: var(--topbar-h);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 12px;
  padding: 0 16px;
  position: sticky; top: 0; z-index: 30;
}
.icon-btn {
  width: 34px; height: 34px; border-radius: var(--radius-sm);
  display: grid; place-items: center; cursor: pointer;
  color: var(--text-2); background: transparent; border: 0;
  position: relative;
}
.icon-btn:hover { background: var(--surface-3); color: var(--text); }
/* Значок «ждут вашего решения» (v3.32): пока решения ждут, он не серый —
   человек должен видеть это боковым зрением, не наводя мышь */
.icon-btn.needs-decision { color: var(--red); }
.icon-btn-dot {
  position: absolute; top: 4px; right: 4px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--red);
}

/* min-width раньше был 0 — сосед (h2/h3 в .card-head) не умеет сжиматься
   ниже своей естественной ширины, а это поле умело сжаться хоть в ноль. На
   телефоне (390) поле схлопывалось до значка лупы, набрать в нём было
   нечего (макет 24, 29.09). Теперь у поля есть свой минимум, и при нехватке
   места строка переносится (.card-head уже это умеет на ≤860px), а не давит
   на одно только поле поиска. */
.global-search { position: relative; flex: 1 1 auto; min-width: 160px; max-width: 520px; }
.global-search .ic { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); color: var(--muted); pointer-events: none; }
.global-search input[type=search],
.global-search input[type=text] {
  width: 100%; min-width: 0; height: 36px; min-height: 36px; padding: 0 12px 0 38px;
  border: 1px solid var(--border); border-radius: 9px;
  background: var(--surface-2); font-size: 13.5px; font-family: inherit; color: var(--text);
  -webkit-appearance: none; appearance: none;
}
.global-search input:focus { outline: none; border-color: var(--accent); background: #fff; box-shadow: 0 0 0 3px var(--accent-soft); }
/* Поиск товара в заказе (.ord-item-search) — тот же класс .global-search,
   что и общий поиск в шапке, но в карточке «Позиции заказа» он делит строку
   ещё и с заголовком, и с кнопкой «Плитками». На телефоне заголовку хватало
   места по своей ширине, и общий минимум 160px больше поле не получало —
   в нём самое важное действие экрана (добавить товар), а выпадающая
   подсказка результатов такой ширины нечитаема: название переносится в три
   строки и наезжает на цену. Отдаём полю всю ширину строки (найдено при
   100%-проверке мобильной версии, 29.09.2026). */
.ord-item-search { max-width: 440px; flex: 1 1 0%; }
@media (max-width: 760px) {
  .ord-item-search { flex-basis: 100%; max-width: none; }
}

.search-results {
  position: absolute; top: 42px; left: 0; right: 0;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-3);
  max-height: 70vh; overflow-y: auto; z-index: 60; padding: 6px;
}
.search-results .sr-group { padding: 6px 10px 2px; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); font-weight: 600; }
.search-results a { display: flex; gap: 8px; align-items: center; padding: 7px 10px; border-radius: var(--radius-sm); color: var(--text); }
.search-results a:hover, .search-results a.hl { background: var(--accent-soft); text-decoration: none; }
.search-results .sr-meta { margin-left: auto; color: var(--muted); font-size: 12px; text-align: right; white-space: nowrap; display: flex; flex-direction: column; gap: 1px; }
/* Картинка товара в поиске и в строках заказа (v3.4.1) */
.search-results .sr-name { display: flex; align-items: center; gap: 9px; min-width: 0; }
.sr-thumb {
  width: 30px; height: 30px; flex: none; border-radius: var(--radius-sm);
  object-fit: contain; background: var(--surface-3); border: 1px solid var(--border);
}
.sr-thumb-ph { display: block; }
/* ФОТО ТОВАРА ВПИСЫВАЕТСЯ ЦЕЛИКОМ, А НЕ ОБРЕЗАЕТСЯ (v6.9).
 *
 * Заказчик: «картинку надо сжать, чтобы она полностью помещалась в этот
 * кубик». До 6.9 везде стояло `object-fit: cover` — оно заполняет квадрат
 * и срезает всё, что не влезло. На квадратном снимке разницы нет, а на
 * вытянутом в квадратик 30 на 30 попадает середина товара без краёв: узнать
 * по такому квадрату зажигалку нельзя, а именно ради узнавания фото и стоит.
 * `contain` показывает снимок целиком; поля вокруг закрашены фоном рамки. */
.row-thumb {
  width: 30px; height: 30px; flex: none; border-radius: var(--radius-sm);
  object-fit: contain; background: var(--surface-3); border: 1px solid var(--border);
}
.cell-product { display: flex; align-items: center; gap: 9px; min-width: 0; }




/* Панель сборки: действия столбиком, чтобы таблица не уезжала вправо (v3.5.3).
   Селектор с `table.data`, иначе `table.data .col-actions { white-space: nowrap }`
   перебивает по специфичности и кнопки снова встают в одну строку. */
/* Итоговый столбец таблицы (v3.12.1).
   Ради общей суммы в отчёт и заходят: она стоит последней справа, набрана
   жирным и подложена лёгкой заливкой — глаз находит её, не читая строку. */
table.data th.col-total, table.data td.col-total {
  background: var(--accent-soft);
  font-weight: 700; color: var(--text);
  font-variant-numeric: tabular-nums;
  box-shadow: inset 1px 0 0 #c7d9fb;
}
table.data thead th.col-total { color: var(--accent-dark); background: #dbe7ff; }
table.data tfoot td.col-total { font-weight: 750; }
table.data tbody tr:hover td.col-total { background: #dbe7ff; }

/* Долги по клиентам: имя не должно ломаться на три строки (v3.13).
   Таблица помещается в экран, поэтому имени можно отдать место, а
   денежные столбцы сжать — цифры узкие. */
table.data th.debt-name, table.data td.debt-name { min-width: 190px; }
table.data td.debt-name { line-height: 1.25; }
/* «Задолженность по клиентам» — две колонки, на всю ширину они разъезжались
   (v6.102.0): имя слева, сумма за тысячу пикселей от него. */
/* «Задолженность по клиентам» во всю ширину со шторкой (v6.129.0, макет 122).
   Было: .debt-simple сжатая до 760px — страница выглядела обрезанной. */
.debt-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 760px) { .debt-tiles { grid-template-columns: 1fr; } }
.debt-head-acts { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-left: auto; }
.debt-table td.debt-chev, .debt-table th.debt-chev { width: 2.25rem; padding-right: 0; }
.debt-table tr.debt-row { cursor: pointer; }
.debt-table tr.debt-row:hover > td { background: var(--surface-2, #f7f9fd); }
.debt-table tr.debt-row.open > td { background: var(--accent-soft); border-bottom-color: transparent; }
.debt-toggle { border: 0; background: transparent; width: 1.6rem; height: 1.6rem; border-radius: 6px; display: inline-flex;
  align-items: center; justify-content: center; color: var(--muted); cursor: pointer; transform: rotate(90deg); transition: transform .2s ease; }
.debt-row.open .debt-toggle { transform: rotate(270deg); color: var(--accent-dark); }
.debt-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.debt-table tr.debt-drawer > td { padding: 0 .75rem .75rem 2.5rem; background: var(--accent-soft); }
.debt-inner { background: var(--surface, #fff); border: 1px solid var(--accent-line, #d5e0f8); border-radius: 10px; overflow: hidden; }
.debt-inner-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; padding: .5rem .75rem; border-bottom: 1px solid var(--line); }
.debt-inner-acts { display: flex; gap: 6px; flex-wrap: wrap; }
.debt-inner table.data { margin: 0; }
@media (max-width: 760px) { .debt-table tr.debt-drawer > td { padding-left: .5rem; } }
@media (prefers-reduced-motion: reduce) { .debt-toggle { transition: none; } }

/* Колонка действий в сборке (v3.12).
   Была во всю ширину: кнопка растягивалась на 170 пикселей и выглядела
   плашкой. Теперь колонка сжата по содержимому, кнопки одной ширины и
   прижаты вправо — колонка читается как ровный столбик действий. */
table.data td.pick-actions {
  width: 1%; white-space: nowrap; text-align: right; vertical-align: middle;
}
table.data td.pick-actions .pick-stack {
  display: inline-flex; flex-direction: column; align-items: stretch; gap: 5px;
  min-width: 128px;
}
table.data td.pick-actions .pick-stack > * { width: 100%; }
table.data td.pick-actions .btn { justify-content: center; }
table.data td.pick-actions .badge { text-align: center; }
table.data td.pick-actions form { display: block; }

/* Статус пользователя меняется прямо из строки (v3.5.4).
   Селектор с двумя классами: `table.data .col-actions { width: 1% }`
   иначе выигрывает по специфичности и сжимает колонку в столбик. */
table.data td.col-actions.user-actions {
  width: 1%; white-space: nowrap; text-align: right;
}
table.data td.col-actions.user-actions .row-actions {
  display: flex; justify-content: flex-end; align-items: center; gap: 4px; flex-wrap: nowrap;
}
table.data td.col-actions.user-actions form { display: inline-flex; }
table.data td.col-actions.user-actions .btn-sm { padding: 0 7px; gap: 5px; }

/* Ссылка-кнопка внутри подписи плитки (v3.4.7) */
.link-btn {
  border: 0; background: none; padding: 0; font: inherit; cursor: pointer;
  color: var(--accent); border-bottom: 1px solid transparent;
}
.link-btn:hover { color: var(--accent-dark); border-bottom-color: var(--accent); }

/* Атрибут hidden должен прятать даже flex-элементы: кнопки и строки таблиц
   мы скрываем именно им (v3.4.6) */
[hidden] { display: none !important; }

/* График ожидаемых поступлений: столбец на день, клик — счета этого дня (v3.4.6) */
/* Столбцы тянутся и ужимаются под ширину карточки, как шкала у графиков
   аналитики: горизонтальной прокрутки нет ни на 30, ни на 90 днях (v6.39.0).
   Раньше стоял `flex: 1 0 44px` с `min-width: 44px` — столбцы не ужимались,
   и на длинном горизонте график уезжал вбок под скролл. */
.pay-chart {
  display: flex; align-items: flex-end; gap: 3px;
  overflow: hidden; padding: 6px 2px 0; min-height: 200px;
}
.pay-col {
  flex: 1 1 0; min-width: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: flex-end; gap: 4px;
  height: 190px; padding: 0 0 4px; border: 0; background: none; cursor: pointer;
  border-radius: var(--radius-sm); transition: background .12s;
}
.pay-col:hover { background: var(--surface-3); }
/* Сумма над столбцом: постоянно висящие подписи соседних дней наезжали
   друг на друга, поэтому показываем их только при наведении и у выбранного
   дня, а в остальное время держим место (v3.4.9) */
.pay-sum {
  /* Сумма и число накладных читаются как цифры дня — жирным (v3.5.3) */
  font-size: 11.5px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums;
  white-space: nowrap; opacity: 0; transition: opacity .12s;
  background: var(--surface); padding: 0 3px; border-radius: 4px; position: relative; z-index: 2;
}
.pay-col:hover .pay-sum, .pay-col.is-picked .pay-sum { opacity: 1; }
.pay-bar {
  width: 60%; min-height: 3px; border-radius: 4px 4px 0 0;
  background: linear-gradient(180deg, var(--accent) 0%, #6f9bf5 100%);
  transition: background .12s, transform .12s; transform-origin: bottom;
}
.pay-col.is-empty .pay-bar { background: var(--border); }
.pay-col.is-today .pay-bar { background: linear-gradient(180deg, var(--green) 0%, #34b27b 100%); }
.pay-col.is-picked { background: var(--accent-soft); }
.pay-col.is-picked .pay-bar { transform: scaleX(1.15); }
.pay-day { font-size: 11px; color: var(--muted); white-space: nowrap; }
.pay-col.is-today .pay-day { color: var(--green); font-weight: 650; }
.pay-cnt {
  font-size: 11.5px; font-weight: 700; color: var(--text-2); min-height: 14px;
  font-variant-numeric: tabular-nums;
}
.pay-col:hover .pay-cnt, .pay-col.is-picked .pay-cnt { color: var(--accent-dark); }

/* Вкладки складов в остатках: цифра рядом с названием (v3.4.5) */
.wh-tabs a { display: inline-flex; align-items: center; gap: 8px; }
.wh-tab-qty {
  font-size: 11.8px; font-weight: 600; color: var(--text-2);
  background: var(--surface-3); border-radius: 20px; padding: 1px 8px;
  font-variant-numeric: tabular-nums;
}
.wh-tabs a.active .wh-tab-qty { background: var(--accent-soft); color: var(--accent-dark); }

/* Раскладка остатка по складам в списке остатков (v3.4.4) */
/* Ячейка «по складам» остаётся ячейкой таблицы, раскладку делает вложенный
   блок (v6.19.0): `display:flex` на самом `td` отменял табличное поведение —
   столбец терял ширину, и плитки вылезали на соседние колонки. */
.wh-cell { max-width: 380px; }
/* Склады идут в строку, слева направо (v6.19.0, замечание заказчика: «он один
   под вторым, а не слева справа»): переносим на вторую строку только когда
   места действительно не хватает. */
.wh-chips { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.wh-chip {
  display: inline-flex; align-items: baseline; gap: 6px; white-space: nowrap;
  padding: 2px 8px; border-radius: 20px; font-size: 12.2px;
  background: var(--surface-3); color: var(--text-2);
  border: 1px solid var(--border); text-decoration: none;
  font-variant-numeric: tabular-nums;
}
.wh-chip:hover { border-color: var(--accent); color: var(--accent-dark); text-decoration: none; }
.wh-chip b { color: var(--text); }
.wh-chip:hover b { color: var(--accent-dark); }
/* Склад «Брак» — слабый красно-оранжевый фон, чтобы отличался от обычного (v6.38.0) */
.wh-chip-defect { background: var(--red-soft); border-color: var(--red); color: var(--red); }
.wh-chip-defect b { color: var(--red); }
.wh-chip-defect:hover { border-color: var(--red); color: var(--red); }
.wh-chip-defect:hover b { color: var(--red); }

/* Цель по товарам: строка «сколько достичь — товар либо категория» (v3.4.1) */
.mu-rows { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; }
.mu-row {
  display: grid; grid-template-columns: 130px 150px minmax(0, 1fr) 32px;
  gap: 8px; align-items: start;
}
.mu-row .mu-target { text-align: right; }
.mu-row .mu-del { align-self: center; }
@media (max-width: 720px) {
  .mu-row { grid-template-columns: 1fr 1fr; }
  .mu-row .mu-pick, .mu-row .combo { grid-column: 1 / -1; }
}
.search-results .sr-price { color: var(--text-2); font-weight: 600; }

.user-chip { display: flex; align-items: center; gap: 8px; padding: 4px 8px 4px 4px; border-radius: 20px; cursor: pointer; }
.user-chip:hover { background: var(--surface-3); }
.avatar {
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent-dark);
  display: grid; place-items: center; font-size: 11.5px; font-weight: 700; flex: 0 0 auto;
}
.avatar-lg { width: 44px; height: 44px; font-size: 15px; }

.dropdown { position: relative; }
.dropdown-menu {
  position: absolute; right: 0; top: calc(100% + 6px);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-3);
  min-width: 210px; padding: 6px; z-index: 70; display: none;
}
.dropdown.open .dropdown-menu { display: block; }
.dropdown-menu a, .dropdown-menu button {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 8px 10px; border-radius: var(--radius-sm);
  color: var(--text); font-size: 13.5px; background: none; border: 0;
  font-family: inherit; text-align: left; cursor: pointer;
}
.dropdown-menu a:hover, .dropdown-menu button:hover { background: var(--surface-3); text-decoration: none; }
/* Опасный пункт в выпадающем списке (v6.49.0, п.21 заказчика): «Отменить
   заказ» должна отличаться от соседних пунктов до нажатия, а не после. */
/* Настройка поводов «Обратите внимание» (v6.49.0, п.8 заказчика): роли
   стоят галочками в строку — их меньше десятка, и видно сразу, кто отмечен,
   без раскрытия списка. */
.att-table td { vertical-align: top; }
.att-roles { display: flex; flex-wrap: wrap; gap: 4px 14px; }
/* Поля чувствительности повода (v6.50.0): подпись, короткое поле и единица
   в одну строку — это не форма для заполнения, а подкрутка одного числа. */
.att-num { display: flex; align-items: center; gap: 6px; margin-bottom: 5px; }
.att-num label { font-size: 12px; color: var(--text-2); flex: 1 1 auto; min-width: 0; }
/* Селектор с двумя классами — иначе общий стиль полей (`width: 100%`)
   растягивает число на всю колонку и оно наезжает на соседнюю. */
.att-table .att-num input[type=text] { width: 74px; min-height: 28px; padding: 3px 7px;
  font-size: 13px; text-align: right; font-variant-numeric: tabular-nums; flex: 0 0 74px; }
.att-num .xs { flex: 0 0 auto; min-width: 44px; }
.att-roles .check { font-size: 12.5px; }

.dropdown-menu .menu-danger { color: var(--red); }
.dropdown-menu .menu-danger:hover { background: var(--red-soft); }
/* Лента сообщений системы (v3.19) */
.dropdown-title { padding: 8px 10px 6px; font-size: 11.5px; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted); }
.msg-dot { position: absolute; top: 4px; right: 4px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--red); }
.msg-row { display: block; padding: 8px 10px; border-radius: var(--radius-sm); font-size: 13px; line-height: 1.45; }
.msg-row + .msg-row { border-top: 1px solid var(--border); border-radius: 0; }
.msg-row .msg-when { display: block; font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.msg-row.error { border-left: 3px solid var(--red); }
/* Ошибка висит, пока её не закроют (v3.19) — но глаз к ней должен
   возвращаться, поэтому оставляем заметную рамку */
.flash.sticky { border-left-width: 4px; }
.dropdown-divider { height: 1px; background: var(--border); margin: 5px 2px; }

.content { flex: 1 1 auto; padding: 18px 20px 64px; max-width: 1720px; width: 100%; }

.page-head { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 16px; flex-wrap: wrap; }
.page-head .titles { flex: 1 1 auto; min-width: 200px; }
.page-head h1 { display: flex; align-items: center; gap: 10px; }
.page-head .sub { color: var(--muted); font-size: 13px; margin-top: 3px; }
/* Кнопки страницы всегда прижаты к правому краю — даже когда подзаголовок
   длинный и блок переносится на свою строку (v2.2.2) */
/* `align-items: center` — чтобы кнопка внутри формы не растягивалась по
   высоте строки (v6.24.3, слово заказчика: «отменить сделай в размер как
   остальные кнопки, она больше других»). Без него `<form>` как элемент
   раскладки тянулся на всю высоту ряда, и его красная кнопка выглядела
   крупнее соседних ссылок. */
.page-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-left: auto; justify-content: flex-end; }
/* Ряд действий у левого края: там, где они основные, а не дополнительные */
.page-actions.left { margin-left: 0; justify-content: flex-start; }
/* Промежуток внутри ряда: отделяет «Поставить задачу» от действий над самим
   документом (v6.25.0). Ширина — два обычных зазора, чтобы пауза читалась. */
.pa-gap { flex: 0 0 16px; }

.breadcrumbs { font-size: 12.5px; color: var(--muted); margin-bottom: 6px; display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.breadcrumbs a { color: var(--muted); }
.breadcrumbs a:hover { color: var(--accent); }

/* =========================== Кнопки =========================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 34px; padding: 0 13px;
  border-radius: var(--radius-sm); border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--text);
  font-size: 13.5px; font-weight: 550; font-family: inherit;
  cursor: pointer; white-space: nowrap; text-decoration: none;
  transition: background .12s, border-color .12s, box-shadow .12s;
}
.btn:hover { background: var(--surface-3); text-decoration: none; }
.btn:active { transform: translateY(.5px); }
.btn:disabled, .btn.disabled { opacity: .55; pointer-events: none; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-dark); border-color: var(--accent-dark); }
.btn-success { background: var(--green); border-color: var(--green); color: #fff; }
.btn-success:hover { filter: brightness(.94); }
.btn-danger { background: var(--red); border-color: var(--red); color: #fff; }
.btn-danger:hover { filter: brightness(.94); }
/* КНОПКА БЕЗ ЗАЛИВКИ — ВСЁ РАВНО С РАМКОЙ (v6.49.0, п.12 заказчика:
   «кнопка "удалить задачу" просто текст — добавить рамку; проверить всю
   систему, где есть кнопки без рамки, и исправить по всей системе»).
   Раньше рамка была прозрачной, и такая кнопка на белой карточке выглядела
   обычной надписью: человек не понимал, что по ней можно нажать, а «Удалить»
   рядом с зелёной «Выполнить» вообще терялась. Правка одна на всю систему —
   класс `.btn-ghost` стоит в 163 местах, и трогать каждое было бы и дольше,
   и опаснее. Рамка взята светлая (--border), фон остаётся прозрачным: кнопка
   становится видимой, но не спорит с главной кнопкой экрана рядом. */
.btn-ghost { border-color: var(--border); background: transparent; }
.btn-ghost:hover { background: var(--surface-3); border-color: var(--border-strong, var(--border)); }
/* Одно исключение: кнопка-иконка внутри карточки задачи (меню «…», флажок
   важности). Там рамка на каждой карточке превращает доску в решётку —
   кнопки стоят по три в ряд на каждой из десятков карточек. */
.tcard .btn-ghost, .tk-item .btn-ghost { border-color: transparent; }
.tcard .btn-ghost:hover, .tk-item .btn-ghost:hover { border-color: var(--border); }
/* РАЗМЕРОВ КНОПКИ РОВНО ТРИ (v6.23.4).
 *
 * Слово заказчика: «кнопки разные, пройдись по всей системе — пусть они будут
 * одинаковые».
 *
 * Он прав, и разброс был реальный: 28 (мелкая), 34 (обычная), 40 (крупная) —
 * это осознанные размеры, — но сверх них по экранам расползлись ещё 32 и 38,
 * заведённые под один конкретный случай и с тех пор попадавшиеся рядом с
 * обычными. Две кнопки рядом разной высоты читаются как ошибка вёрстки, и это
 * она и есть.
 *
 * Правило на будущее: высоту кнопки задают ТОЛЬКО эти три строки. Нужен
 * другой размер — значит, нужен четвёртый класс, а не правка на одном экране.
 * Тест 165 стережёт это: он не пропустит в стилях ни одной высоты `.btn`,
 * кроме 28, 34 и 40. */
.btn-sm { height: 28px; padding: 0 10px; font-size: 12.5px; }
.btn-lg { height: 40px; padding: 0 18px; font-size: 14.5px; }
.btn-block { width: 100%; }
.btn .ic { width: 16px; height: 16px; }

/* ПОДПИСЬ СЛОВОМ У КНОПКИ-ЗНАЧКА (v6.31.0).
 *
 * Слово заказчика: «кнопки с одними картинками — карандаш, корзина, глаз —
 * я не понимаю, что они делают, и боюсь нажимать». Значок сам по себе
 * ничего не называет: «корзина» — это «удалить» только для того, кто уже
 * знает. Поэтому рядом со значком стоит русский глагол.
 *
 * Имя именно `.btn-txt`: `.lbl` занят печатными формами, `.field-lbl` —
 * заголовками групп полей.
 *
 * ПОЧЕМУ НА УЗКОМ ЭКРАНЕ ПОДПИСЬ ПРЯЧЕТСЯ. Правило дома — никакой
 * горизонтальной полосы у таблиц. Два слова в колонке действий — это ещё
 * сто с лишним пикселей в каждой строке, и таблица из девяти колонок на
 * ноутбуке уезжает за край. Ниже 1100 пикселей подпись убирается, но
 * кнопка не немеет: у каждой такой кнопки рядом с подписью стоят `title` и
 * `aria-label` с тем же словом — подсказка всплывает при наведении и
 * читается экранным диктором. Прячется ПОДПИСЬ, а не действие: сама кнопка
 * остаётся на месте (ср. правило про `.col-optional` выше — цифры не
 * скрываем никогда). */
.btn-txt { display: inline; }
@media (max-width: 1100px) {
  table.data .btn-txt { display: none; }
}

/* Тональные кнопки для строк таблицы (v3.12).
   Сплошная заливка в каждой строке превращает колонку действий в стену
   цвета: глаз перестаёт различать, где что. Тональная кнопка говорит то же
   самое — «это главное действие строки», — но не кричит. */
.btn-tonal {
  background: var(--accent-soft); border-color: #c7d9fb; color: var(--accent-dark); font-weight: 600;
}
.btn-tonal:hover { background: #dbe7ff; border-color: var(--accent); color: var(--accent-dark); }
.btn-tonal.good { background: var(--green-soft); border-color: #b9e3cd; color: var(--green); }
/* Предупреждающий тон кнопки: «ждёт предоплату» стоит в том же ряду, что и
   «Собрать», и должно читаться кнопкой, а не меткой (v3.42) */
.btn-tonal.warn { background: var(--amber-soft, #fff5e0); border-color: #f0d9a8; color: var(--amber, #b26a00); }
/* Состояние, а не действие: та же форма, но не нажимается */
.pick-state { cursor: default; }
.btn-tonal.good:hover { background: #d6f0e3; border-color: var(--green); }

/* СКЛЕЕННАЯ ГРУППА — ТОЛЬКО ДЛЯ ПЕРЕКЛЮЧАТЕЛЕЙ (‹ Сегодня ›, Месяц/Неделя).
   Склейка говорит «это один орган управления с несколькими положениями».
   Для РАЗНЫХ действий в строке таблицы она не годится — см. `.row-actions`. */
.btn-group { display: inline-flex; }
.btn-group .btn { border-radius: 0; margin-left: -1px; }
.btn-group .btn:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); margin-left: 0; }
.btn-group .btn:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }

/* РЯД ДЕЙСТВИЙ В СТРОКЕ ТАБЛИЦЫ (v6.50.2, замечание заказчика: «рамки этих
   кнопок кривые… у каждой из них свои формы — исправь»).

   ЧТО БЫЛО. В справочниках действия лежали в `.btn-group`, но каждая кнопка
   сидела в СВОЕЙ форме: она отправляется на свой адрес. Правила склейки
   написаны на `:first-child`/`:last-child` КНОПКИ, а кнопка внутри формы —
   всегда и первая, и последняя. Поэтому скругления доставались каждой,
   сдвиг `-1px` не применялся нигде, и ряд выходил рваным: где-то углы
   круглые, где-то прямые, границы соседей удваивались.

   КАК ТЕПЕРЬ. Разные действия — разные кнопки: одинаковые скругления,
   ровный промежуток, опасное действие последним. `display: contents` у
   формы убирает её из раскладки, не трогая отправку: кнопки становятся
   прямыми детьми ряда, и промежуток считается между ними, а не между
   формами. */
.row-actions { display: inline-flex; flex-wrap: nowrap; gap: 6px; align-items: center; justify-content: flex-end; }
.row-actions > form { display: contents; }
.row-actions .btn { border-radius: var(--radius-sm); margin: 0; }

/* =========================== Карточки =========================== */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  margin-bottom: 16px;
}
.card-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 16px; border-bottom: 1px solid var(--border);
}
.card-head h2, .card-head h3 { flex: 1 1 auto; }
.card-head-actions { flex: 0 0 auto; margin-left: auto; }
/* ЗАКРЫТАЯ КАРТОЧКА (v6.22.2, слово заказчика: «коммерческие условия должны
   быть закрыты для редактирования — „отредактировать“, и только потом данные
   можно редактировать»). Закрытая читается, но не нажимается: поля бледнее,
   курсор обычный. Прячет её от мыши и клавиатуры атрибут `inert` — значения
   при этом остаются в форме и уходят на сервер прежними, см. `app.js`. */
.card.is-locked .card-body { opacity: .72; }
.card.is-locked .card-body input,
.card.is-locked .card-body select,
.card.is-locked .card-body textarea { background: var(--surface-2); cursor: default; }
.card-body { padding: 16px; }
.card-body.tight { padding: 0; }
.card-foot { padding: 12px 16px; border-top: 1px solid var(--border); background: var(--surface-2); border-radius: 0 0 var(--radius) var(--radius); }

.grid { display: grid; gap: 16px; }
.grid-1 { grid-template-columns: minmax(0, 1fr); }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.grid-auto { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }

/* Цветные подложки иконок разделов — используются иконками статусов
   и плитками (блок «Разделы» с главной убран в v2.7) */
/* Цветные метки категорий. Цвет текста подобран так, чтобы разница с фоном
   была не меньше 4,5:1 — порога, ниже которого мелкий текст перестаёт
   читаться на светлом экране и при плохом зрении. Пять меток из тринадцати
   до него не дотягивали (v5.0.4); оттенок остался прежним, изменилась только
   насыщенность, на глаз незаметно. */
.tone-blue   { background: #e8f0ff; color: #1d4ed8; }
.tone-violet { background: #f0ebfe; color: #6d3ae0; }
.tone-amber  { background: #fdf1dc; color: #a06000; }
.tone-teal   { background: #ddf5f0; color: #0f766e; }
.tone-green  { background: #e3f6ec; color: #117e56; }
.tone-cyan   { background: #e0f4fb; color: #0e7490; }
.tone-orange { background: #fdecdf; color: #c0400c; }
.tone-slate  { background: #eaeef3; color: #475569; }
.tone-indigo { background: #eaeafd; color: #4338ca; }
.tone-pink   { background: #fce9f2; color: #be1e63; }
.tone-red    { background: #fdeaea; color: #c02626; }
.tone-lime   { background: #eef7dc; color: #587a11; }
.tone-grey   { background: #eef1f5; color: #606f85; }

/* =========================== KPI =========================== */

.kpi-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(196px, 1fr)); gap: 12px; margin-bottom: 16px; }
.kpi {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 13px 14px; box-shadow: var(--shadow-1);
  display: flex; flex-direction: column; gap: 3px; min-width: 0;
}
.kpi .kpi-label { font-size: 11.5px; text-transform: uppercase; letter-spacing: .035em; color: var(--muted); font-weight: 600; }
/* Точные суммы длиннее сокращённых: цифра ужимается, но не обрезается —
   обрезанная сумма хуже, чем мелкая (v3.0.2) */
.kpi .kpi-value {
  font-size: clamp(17px, 1.35vw, 21px); font-weight: 640; letter-spacing: -.02em;
  white-space: nowrap; overflow: hidden; text-overflow: clip;
  font-variant-numeric: tabular-nums;
}
.kpi .kpi-sub { font-size: 12px; color: var(--muted); }
.kpi.accent .kpi-value { color: var(--accent-dark); }
.kpi.good   .kpi-value { color: var(--green); }
.kpi.bad    .kpi-value { color: var(--red); }
.kpi.warn   .kpi-value { color: var(--amber); }
.kpi a { color: inherit; }
/* Ссылкой в плитке служит только цифра: слова остаются словами, а курсор-рука
   появляется ровно там, куда можно нажать (v3.10.1) */
.kpi .kpi-value a.kpi-link { color: inherit; text-decoration: none; border-bottom: 1px solid transparent; }
.kpi .kpi-value a.kpi-link:hover { border-bottom-color: currentColor; }
.kpi .kpi-value a.kpi-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }

/* «Огляд» по бренду (v6.133.0, макет 140в): восемь плиток в два ряда по четыре,
   под процентом — сколько было в периоде сравнения, у штук — разбивка брендов. */
@media (min-width: 1100px) { .kpi-grid.kpi-eight { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.kpi .kpi-was { font-size: 12px; color: var(--muted); }
.kpi .kpi-was b { color: var(--text-2); font-weight: 600; font-variant-numeric: tabular-nums; }
.kpi .kpi-brands { display: flex; flex-wrap: wrap; gap: 2px 12px; font-size: 12px; color: var(--text-2); margin-top: 2px; }
.kpi .kpi-brands b { font-weight: 600; font-variant-numeric: tabular-nums; }
.brand-dot { display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 6px; vertical-align: 1px; }
.brand-tabs { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; margin: 4px 0 14px; }
.brand-tabs .tabs { margin-bottom: 0; }
/* Бренды на главной в настройке роли (v6.133.0, макет 141) */
.home-brands { margin-top: 10px; border: 1.5px solid #9dbcf7; background: #f5f8ff; border-radius: 9px; padding: 10px 12px;
  display: flex; flex-direction: column; gap: 8px; color: var(--text); }
.home-brands-t { font-size: 12px; font-weight: 700; color: var(--accent-dark); }
.home-brands-list { display: flex; flex-wrap: wrap; gap: 6px 18px; }
.home-brands-list .check { font-size: 13px; }
.home-brands-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
.seg-radio { display: inline-flex; gap: 2px; padding: 3px; background: #e7ebf0; border-radius: 9px; }
.seg-radio label { position: relative; cursor: pointer; }
.seg-radio input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.seg-radio span { display: block; padding: 4px 12px; font-size: 13px; font-weight: 600; color: var(--text-2); border-radius: 7px; }
.seg-radio input:checked + span { background: #fff; color: var(--accent-dark); box-shadow: 0 1px 3px rgba(16, 21, 28, .12); }
.seg-radio input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 1px; }
/* «В ряд» на главной (v6.133.1, макет 142 А): те же сегменты, но кнопками */
.metrics-head.has-perrow { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px; }
/* С 6.135.0 (макет 147б) — под стрелкой у «За период», каждому своё */
.perrow-arrow { all: unset; cursor: pointer; display: inline-grid; place-items: center; width: 24px; height: 24px;
  border-radius: 6px; color: var(--muted); }
.perrow-arrow:hover { background: #e7ebf0; color: var(--text); }
.perrow-arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.perrow-arrow svg { transition: transform .15s; }
.perrow-arrow[aria-expanded="true"] svg { transform: rotate(180deg); }
.perrow { display: flex; width: fit-content; align-items: center; flex-wrap: wrap; gap: 8px 10px; margin: 2px 0 10px;
  padding: 7px 12px; background: var(--surface, #fff); border: 1px solid var(--border); border-radius: 9px; }
.perrow[hidden] { display: none; }
.perrow-lbl { font-size: 13px; color: var(--text-2); }
@media (prefers-reduced-motion: reduce) { .perrow-arrow svg { transition: none; } }
.seg-radio button { font: inherit; font-size: 13px; font-weight: 600; color: var(--text-2); background: transparent; border: 0;
  border-radius: 7px; padding: 4px 12px; cursor: pointer; }
.seg-radio button.on { background: #fff; color: var(--accent-dark); box-shadow: 0 1px 3px rgba(16, 21, 28, .12); }
.seg-radio button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Ссылка «изменить список» рядом с подписью поля (v6.134.0, макет 143) */
.label-link { margin-left: 8px; font-weight: 600; color: var(--accent-dark); text-decoration: none; }
.label-link:hover { text-decoration: underline; }
/* Погашенный шаг графика (v6.134.0, макет 144): виден, но не нажимается; почему — в подсказке */
.seg-radio button:disabled { opacity: .4; cursor: not-allowed; }
.brand-tabs-lbl { font-size: 11.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }

/* ============== Показатели главной страницы (v2.7) ==============
   Плитки KPI были одного размера и одного веса — глаз не понимал,
   что здесь главное. Теперь два ряда с подписями: «За период» —
   итоги, которые меняются со временем и сравниваются с прошлым;
   «На сегодня» — снимок состояния, сравнивать который не с чем. */

.metrics { margin-bottom: 16px; display: flex; flex-direction: column; gap: 8px; }

.metrics-head {
  font-size: 11px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted);
  margin-top: 6px;
}
.metrics-head:first-child { margin-top: 0; }
/* Даты периода — рядом с подписью ряда, но спокойнее её (v6.49.0,
   предложение 17): подпись называет ряд, даты только уточняют. */
.metrics-period { text-transform: none; letter-spacing: 0; font-weight: 500;
  color: var(--muted); margin-left: 8px; }

.metric-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.metric-row.two { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.metric {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 14px 16px; box-shadow: var(--shadow-1);
  display: flex; flex-direction: column; gap: 4px; min-width: 0;
  border-left: 3px solid var(--border-strong);
}
.metric.accent { border-left-color: var(--accent); }
.metric.good   { border-left-color: var(--green); }
.metric.bad    { border-left-color: var(--red); }

.metric-label {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .035em;
  color: var(--muted); font-weight: 600;
}
.metric-value {
  font-size: 25px; font-weight: 660; letter-spacing: -.022em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-variant-numeric: tabular-nums; line-height: 1.15;
}
.metric.accent .metric-value { color: var(--accent-dark); }
.metric.bad    .metric-value { color: var(--red); }
.metric.good   .metric-value { color: var(--green); }
.metric a { color: inherit; }
.metric-sub { font-size: 12px; color: var(--muted); }
.metric-delta { font-size: 12.5px; display: flex; gap: 6px; align-items: baseline; flex-wrap: wrap; }

/* ПУТЬ СДЕЛКИ ВНУТРИ ПЛИТКИ «ПРОДАЖИ» (v6.50.1, выбор заказчика — вариант 2
   из пяти показанных; в v6.49.0 здесь была полоса ПОД рядом плиток, и это
   было ошибкой: ступени объясняют число в плитке и должны стоять при нём).

   Две строки, у каждой стрелка, название, сумма и сколько за ней стоит
   документов. Сумма отбита вправо табличными цифрами: так две суммы
   выстраиваются столбиком и сравниваются взглядом, без чтения.
   Черта сверху отделяет ступени от самого числа — это уже не оно.
   Ступень с нулём бледнеет, но не исчезает: «ничего не уехало» — ответ. */
.steps { margin-top: 9px; padding-top: 7px; border-top: 1px dashed var(--border);
  display: flex; flex-direction: column; gap: 4px; }
.step { display: flex; align-items: baseline; gap: 7px; font-size: 12.5px; color: var(--text-2); }
.step-a { color: var(--border-strong); flex: none; }
.step-k { color: var(--muted); flex: 1 1 auto; white-space: nowrap; }
.step b { font-variant-numeric: tabular-nums; white-space: nowrap; }
.step-n { color: var(--muted); flex: none; white-space: nowrap; }
.step.is-zero { opacity: .5; }

/* «ЗА ПЕРИОД» ПО БРЕНДАМ (v6.133.0, макет 139г). Сверху две одинаковые
   карточки — деньги и штуки всех брендов, под цифрами полоса долей брендов.
   Ниже — карточка на бренд: деньги | штуки, внизу «в работе». Сколько
   карточек в ряд — настройка роли (макет 141): hb-per-1…4. */
.hb-top { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.hb-bar { display: flex; height: 8px; border-radius: 4px; overflow: hidden; gap: 2px; margin-top: 8px; background: var(--surface-3, #f1f3f6); }
.hb-bar i { display: block; min-width: 2px; }
.hb-legend { display: flex; flex-wrap: wrap; gap: 3px 14px; margin-top: 6px; font-size: 12.5px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.hb-legend i { display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 6px; vertical-align: 1px; }
.hb-legend .hb-other { color: var(--muted); }
.hb-cards { display: grid; gap: 12px; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.hb-cards.hb-per-1 { grid-template-columns: minmax(0, 1fr); }
.hb-cards.hb-per-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.hb-cards.hb-per-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.hb-cards.hb-per-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.hb-card { background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-1); display: flex; flex-direction: column; overflow: hidden; min-width: 0; }
.hb-main { padding: 12px 16px 14px; flex: 1; }
.hb-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
.hb-name { font-weight: 700; display: flex; align-items: center; min-width: 0; }
.hb-name i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 7px; flex: none; }
.hb-ring { flex: none; }
.hb-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.hb-units { border-left: 1px solid var(--border); padding-left: 14px; }
.hb-val { font-size: 18px; font-weight: 680; font-variant-numeric: tabular-nums; white-space: nowrap; margin: 2px 0; }
.hb-d { display: inline-flex; align-items: center; gap: 2px; font-size: 12px; font-weight: 700; white-space: nowrap;
  border-radius: 999px; padding: 1px 7px; margin-bottom: 2px; }
.hb-d.up { color: var(--green); background: #e6f6ee; }
.hb-d.dn { color: var(--red); background: #fdeceb; }
.hb-d.flat { color: var(--muted); background: var(--surface-3, #f1f3f6); }
.hb-work { background: var(--surface-2, #fafbfc); border-top: 1px solid var(--border); padding: 10px 16px 12px; }
.hb-work-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.hb-wsum { font-size: 15px; font-variant-numeric: tabular-nums; }
.hb-wbar { margin: 7px 0 6px; }
.hb-work-foot { display: flex; justify-content: space-between; gap: 4px 12px; flex-wrap: wrap; font-size: 12.5px; }
.hb-work-foot a { color: var(--muted); text-decoration: none; white-space: nowrap; }
.hb-work-foot a:hover { color: var(--accent-dark); }
.hb-work-foot a b { color: var(--text-2); font-variant-numeric: tabular-nums; }
.hb-work-foot i { display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 5px; vertical-align: 0; }
/* v6.138.0, макет 155 (вариант 2): без цветных полосок, сумма тёмным, «в пути» /
   «не в пути» — цветами вне палитры брендов */
.metric.hb-sum { border-left: 1px solid var(--border); }
.hb-tr { background: #4f98a8; }
.hb-nw { background: #7b8796; }
@media (max-width: 1100px) {
  .hb-cards.hb-per-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 860px) {
  .hb-top, .hb-cards, .hb-cards.hb-per-2, .hb-cards.hb-per-3, .hb-cards.hb-per-4 { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 860px) {
  /* На телефоне плитка узкая: число отправок уводим, оставляя главное —
     название ступени и сумму. */
  .step-n { display: none; }
}

.delta { font-weight: 650; font-variant-numeric: tabular-nums; }
.delta.up   { color: var(--green); }
.delta.down { color: var(--red); }
.delta.flat { color: var(--muted); font-weight: 500; }
.delta-base { color: var(--muted); font-size: 12px; }
.warn-note { color: var(--amber); }
.warn-note.bad { color: var(--red); font-weight: 600; }

/* Выбор периода прямо в строке быстрых кнопок */
.period-form { display: inline-flex; align-items: center; gap: 6px; margin-left: 4px; }
.period-form input[type=date] {
  padding: 5px 8px; font-size: 12.5px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface); color: var(--text);
}
/* Обёртка даты в строке периода: размер держит она, поле внутри — по ней */
.period-form .dt { flex: 0 0 auto; width: 140px; }

/* ================= Состояние заказов (v2.7) =================
   Полоса — это путь заказа слева направо, ширина сегмента равна
   доле статуса. Цвета те же, что у бейджей в списках, иначе
   пришлось бы держать в голове две легенды. */

.state-bar {
  display: flex; height: 12px; border-radius: 6px; overflow: hidden;
  background: var(--surface-2); margin-bottom: 14px; gap: 2px;
}
.state-seg { display: block; min-width: 6px; transition: .14s; }
.state-seg:hover { filter: brightness(1.12); }
.state-seg.tone-blue         { background: var(--accent); }
.state-seg.tone-red          { background: var(--red); }
.state-seg.tone-yellow       { background: var(--yellow); }
.state-seg.tone-orange       { background: var(--orange); }
.state-seg.tone-violet       { background: var(--violet); }
.state-seg.tone-green-bright { background: var(--green-bright); }
.state-seg.tone-grey         { background: var(--grey); }

.state-list { display: flex; flex-direction: column; }
.state-row {
  display: grid;
  grid-template-columns: 10px 1fr auto 52px auto;
  align-items: center; gap: 10px;
  padding: 8px 6px; border-radius: var(--radius-sm);
  color: var(--text); font-size: 13.4px;
  border-bottom: 1px solid var(--border);
}
.state-row:last-child { border-bottom: 0; }
.state-row:hover { background: var(--surface-2); text-decoration: none; }

.state-dot { width: 10px; height: 10px; border-radius: 3px; }
.state-dot.tone-blue         { background: var(--accent); }
.state-dot.tone-red          { background: var(--red); }
.state-dot.tone-yellow       { background: var(--yellow); }
.state-dot.tone-orange       { background: var(--orange); }
.state-dot.tone-violet       { background: var(--violet); }
.state-dot.tone-green-bright { background: var(--green-bright); }
.state-dot.tone-grey         { background: var(--grey); }

/* ПОМЕТКА ТОЧКОЙ, А НЕ НАДПИСЬЮ (v6.24.1, слово заказчика: «не надо, чтобы
   это подсвечивалось… просто рядом точечку, фиолетовую; при наведении пусть
   будет написано, работает только по маркетингу»).
   Свойство строки, а не предупреждение о ней: занимает место знака
   препинания, объяснение приходит по наведению — тому, кому оно понадобилось.
   Курсор со знаком вопроса говорит, что наводить есть смысл. */
.mark-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  margin-left: 7px; vertical-align: middle; cursor: help; flex: none;
}
.mark-dot.violet { background: var(--violet); }
.mark-dot.cyan   { background: var(--cyan); }

.state-name  { font-weight: 500; }
.state-share { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.state-cnt   { font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; }
.state-amount{ color: var(--muted); font-size: 12.5px; text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ================= Ожидаемые платежи (v2.7) ================= */

/* «НА СЕГОДНЯ» (v6.136.0, макет 149 А): долг полукругом слева, ожидаемые
   платежи справа — сегодня и ближайшие 7 дней. */
.today-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.today-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 14px 16px; box-shadow: var(--shadow-1); min-width: 0; display: flex; flex-direction: column; gap: 6px;
}
.today-gauge { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
.today-svg { flex: 0 0 auto; display: block; line-height: 0; }
.today-svg:hover { text-decoration: none; }
.today-svg svg { display: block; max-width: 100%; height: auto; }
.today-svg path { fill: none; stroke-width: 18; }
.tg-track { stroke: #e7ebf0; }
.tg-ok    { stroke: var(--accent); }
.tg-late  { stroke: var(--red); }
.tg-sum   { font-size: 19px; font-weight: 700; fill: var(--text); font-variant-numeric: tabular-nums; }
.tg-under { font-size: 11.5px; fill: var(--muted); }
.today-leg { display: grid; gap: 6px; min-width: 190px; flex: 1; }
.today-leg > a { display: flex; justify-content: space-between; gap: 10px; font-size: 13px; color: var(--text-2);
  padding: 3px 6px; margin: 0 -6px; border-radius: 6px; }
.today-leg > a:hover { background: var(--surface-2); text-decoration: none; }
.today-leg > a b { color: var(--text); font-variant-numeric: tabular-nums; }
.today-leg > a.late b { color: var(--red); }
.today-leg i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; }
.tl-ok { background: var(--accent); } .tl-late { background: var(--red); }
.today-note { display: flex; justify-content: space-between; gap: 10px; font-size: 12px; color: var(--muted); }
.today-counts { font-size: 12.5px; }
.today-note.today-transit { display: block; }
/* «В срок» / «просрочено» со своими счетами и клиентами (v6.138.0, макет 156) */
.today-leg > a.today-line { display: grid; grid-template-columns: 1fr auto; gap: 1px 10px; padding: 7px 10px; margin: 0 -10px;
  border-radius: 8px; border: 1px solid transparent; }
.today-leg > a.today-line:hover { border-color: var(--border); }
.today-line b { font-size: 16px; text-align: right; }
.today-leg > a.today-line.zero b { color: var(--muted); }
.today-line .tl-c { grid-column: 1 / -1; font-size: 12px; color: var(--muted); padding-left: 16px; }
.today-counts a { color: var(--accent-dark); }
.today-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.today-ex { display: grid; gap: 8px; margin-top: 4px; }
.today-ex a { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2); color: var(--text); }
.today-ex a:hover { text-decoration: none; border-color: var(--border-strong); background: var(--surface); }
.today-ex a.on { background: var(--accent-soft); border-color: rgba(37,99,235,.35); }
.today-ex a.empty-row { opacity: .62; }
.today-ex-t { display: block; font-weight: 640; }
.today-ex-m { display: block; font-size: 12px; color: var(--muted); }
.today-ex-a { font-size: 20px; font-weight: 660; font-variant-numeric: tabular-nums; white-space: nowrap; }
.today-ex a.on .today-ex-a { color: var(--accent-dark); }
@media (max-width: 900px) { .today-row { grid-template-columns: minmax(0, 1fr); } }

/* Три плитки в ряд: блок стоит во всю ширину, и колонкой он пустовал (v2.8) */
.expect { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.expect-row {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-areas: "title" "amount" "meta";
  gap: 4px; align-items: baseline;
  padding: 12px 14px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--surface-2);
  color: var(--text); transition: .14s;
}
.expect-row:hover { text-decoration: none; border-color: var(--border-strong); background: var(--surface); }
.expect-row.accent { border-color: rgba(37,99,235,.35); background: var(--accent-soft); }
.expect-row.empty-row { opacity: .62; }

.expect-title  { grid-area: title;  font-weight: 640; font-size: 14px; }
.expect-meta   { grid-area: meta;   font-size: 12.2px; color: var(--muted); }
.expect-amount {
  grid-area: amount;
  font-size: 22px; font-weight: 660; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.expect-row.accent .expect-amount { color: var(--accent-dark); }

/* Полоска доли в таблице менеджеров */
.mini-bar {
  height: 8px; border-radius: 4px; background: var(--surface-2);
  overflow: hidden; min-width: 60px;
}
.mini-bar span { display: block; height: 100%; background: var(--accent); border-radius: 4px; }

/* ЗАГРУЗКА ЛИМИТА ЗАЛИВКОЙ ЯЧЕЙКИ (v6.33.0, п.66).

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

   Здесь доля показана самой ячейкой: цифра остаётся обычным числом по правому
   краю, как все числа таблицы, а заливка идёт за ней — своего места не
   занимает вовсе. Ширину заливки задаёт `--load` из разметки, цвет — класс
   зоны: до 50 % спокойно, до 75 % внимание, дальше красное.

   Заливка нарисована через `::before` и лежит ПОД цифрой (`z-index`), иначе
   она перекрыла бы её на тёмных концах шкалы. */
table.data td.limit-load { position: relative; }
table.data td.limit-load::before {
  content: ''; position: absolute; left: 0;
  /* Полоса СТАЛА НИЖЕ, но снова во всю ширину доли (v6.40.0, п.7, слово
     заказчика: «полоску лимита сделать ниже примерно на треть»). В 6.38.0 её
     ужали по ШИРИНЕ до 0.66 — но мешала не ширина (она и есть процент), а
     высота: заливка занимала почти всю строку и спорила с цифрой. Теперь это
     тонкая линия по центру ячейки, а её длина снова точно равна доле. */
  top: 50%; height: 9px; transform: translateY(-50%);
  width: var(--load, 0%); max-width: 100%;
  border-radius: 3px; background: var(--surface-3); z-index: 0;
}
table.data td.limit-load.limit-load-green::before  { background: var(--green-soft); }
table.data td.limit-load.limit-load-amber::before  { background: var(--amber-soft); }
table.data td.limit-load.limit-load-red::before    { background: var(--red-soft); }
table.data td.limit-load .limit-val { position: relative; z-index: 1; font-weight: 650; }
table.data td.limit-load.limit-load-green .limit-val { color: var(--green); }
table.data td.limit-load.limit-load-amber .limit-val { color: var(--amber); }
table.data td.limit-load.limit-load-red   .limit-val { color: var(--red); }

/* СОСУД КРЕДИТНОГО ЛИМИТА — горизонтальный, процент внутри (вариант 3, v6.44.0).
   Выбор заказчика: «горизонтальный с процентом внутри и без доп данных, они
   есть в отдельных столбцах в таблице». Поэтому подписи «своб.» под дорожкой
   больше нет — «Свободно» и «Лимит» стоят своими колонками рядом.

   Дорожка `.cl-track` всегда во всю ширину — это и есть шкала 100 %, её граница
   видна всегда. `.cl-fill` — занятая доля (ширина капается на 100 % в разметке),
   цвет инлайном: зелёный <70 %, жёлтый 70–90 %, красный >90 %. Процент написан
   ВНУТРИ заливки… — так было до v6.46.3. С 6.46.3 процент стоит СПРАВА от
   сосуда, всегда в одном месте и цветом загрузки (п.1: «цифра то белая, то
   чёрная, криво»). Сосуд — тонкая капсула на всю шкалу 100 %. */
.cl-vessel { min-width: 150px; display: flex; align-items: center; gap: 10px; }
.cl-track { position: relative; flex: 1; height: 10px; border-radius: 999px; background: #e8ecf1; box-shadow: inset 0 0 0 1px rgba(15,23,42,.06); overflow: hidden; }
.cl-fill { height: 100%; border-radius: 999px; background: var(--cl-c); transition: width .3s; }
.cl-pct { width: 44px; flex: none; text-align: right; font-weight: 700; font-size: 13px; font-variant-numeric: tabular-nums; color: var(--cl-c); }
.cl-green { --cl-c: #16a34a; }
.cl-amber { --cl-c: #d97706; }
.cl-red   { --cl-c: #dc2626; }
.cl-over .cl-track { box-shadow: inset 0 0 0 1px #dc2626; }

@media (max-width: 860px) {
  .metric-row, .metric-row.two { grid-template-columns: 1fr; }
  .expect { grid-template-columns: 1fr; }
  .state-row { grid-template-columns: 10px 1fr auto auto; }
  .state-row .state-amount { grid-column: 2 / -1; text-align: left; }
}

/* ================= Цели (KPI) на главной, v2.8 =================
   Полоса выполнения плюс засечка темпа: где мы должны быть, если идти
   ровно. Без засечки процент ни о чём не говорит — 40 % в середине
   месяца это норма, а в последний день провал. */

/* auto-fill, а не auto-fit: одна карточка не должна растягиваться
   на всю ширину экрана — она читается как таблица, а не как плитка */
.goal-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 14px; }

.goal {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 14px 16px; background: var(--surface-2);
  display: flex; flex-direction: column; gap: 8px;
  border-left: 3px solid var(--grey);
}
.goal-ok     { border-left-color: var(--accent); }
.goal-done   { border-left-color: var(--green); }
.goal-behind { border-left-color: var(--amber); }

.goal-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.goal-name { font-weight: 650; font-size: 14px; }
.goal-owner { font-size: 11.5px; color: var(--muted); white-space: nowrap; }

.goal-nums { display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap; }
.goal-fact { font-size: 20px; font-weight: 660; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.goal-target { font-size: 12.5px; color: var(--muted); }

.goal-bar {
  position: relative; height: 9px; border-radius: 5px;
  background: var(--surface-3); overflow: visible;
}
.goal-fill { display: block; height: 100%; border-radius: 5px; background: var(--accent); }
.goal-done   .goal-fill { background: var(--green); }
.goal-behind .goal-fill { background: #d64545; }
/* Засечка темпа */
.goal-pace {
  position: absolute; top: -3px; width: 2px; height: 15px;
  background: var(--text); opacity: .45; border-radius: 1px;
}

.goal-foot { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.goal-pct { font-weight: 700; font-size: 13px; font-variant-numeric: tabular-nums; }
.goal-done   .goal-pct { color: var(--green); }
.goal-behind .goal-pct { color: var(--amber); }
.goal-note { font-size: 11.8px; color: var(--muted); }

/* --- Цель как блок: шапка + карточка на каждого исполнителя (v3.1) ---
   Одна цель может держать несколько показателей и несколько менеджеров.
   Карточка — это человек, строки в ней — показатели. */

.goal-set { margin-bottom: 18px; }
.goal-set + .goal-set { padding-top: 16px; border-top: 1px dashed var(--border); }
.goal-set-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 10px;
}
.goal-set-name { font-weight: 680; font-size: 15px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.goal-set-sub { font-size: 11.8px; color: var(--muted); margin-top: 2px; }

.goal-total { border-left-color: var(--violet); background: var(--surface-3); }

.gm { display: flex; flex-direction: column; gap: 5px; }
.gm + .gm { margin-top: 4px; padding-top: 9px; border-top: 1px dashed var(--border); }
/* Подпись показателя бывает длинной («штук по выбранным товарам · Картридж
   Aria 1.2 Ом») и переносится на две строки. Процент при этом ломался на
   «17» и «%» — поэтому подпись сжимаемая, а процент не переносится (v3.4.8) */
.gm-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.gm-label {
  font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em;
  min-width: 0; flex: 1 1 auto; line-height: 1.3;
}
.gm-pct {
  font-weight: 700; font-size: 12.5px; font-variant-numeric: tabular-nums; color: var(--accent);
  flex: 0 0 auto; white-space: nowrap; line-height: 1.3;
}
/* Объект цели — товар или категория — читается как обычный текст, а не капсом */
.gm-obj {
  display: block; margin-top: 2px; text-transform: none; letter-spacing: 0;
  font-size: 12.6px; font-weight: 620; color: var(--text);
}
.gm-pct.done   { color: var(--green); }
.gm-pct.behind { color: var(--red); }
.gm-nums { font-size: 13px; font-variant-numeric: tabular-nums; display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.gm-nums b { font-size: 16px; font-weight: 660; letter-spacing: -.01em; }
.gm-edit { color: var(--muted); display: inline-flex; align-items: center; }
.gm-edit:hover { color: var(--accent); }
.goal-fill.done   { background: var(--green); }
.goal-fill.behind { background: #d64545; }
/* Одна своя цель — на всю ширину, показатели рядом (v6.125.0, макет 119) */
.goal-grid-wide { grid-template-columns: 1fr; }
.gm-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 22px; }
.gm-row .gm + .gm { margin-top: 0; padding-top: 0; border-top: 0; }
/* Пояснение к черте темпа (v6.125.0) */
.goal-legend { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); margin-top: 10px; }
.goal-legend i { display: inline-block; width: 2px; height: 13px; background: var(--text); opacity: .45; border-radius: 1px; flex: 0 0 auto; }

/* ================= Продажи по менеджерам, v2.8 ================= */

.mgr-split { display: flex; gap: 22px; align-items: flex-start; flex-wrap: wrap; }
/* Продаж за период нет — кольца нет, и таблица занимает всю ширину, а не
   жмётся к пустому месту слева, где оно было бы (v6.6.1) */
.mgr-split-flat { display: block; }
.mgr-split-flat .mgr-table { width: 100%; }
.mgr-split-flat .empty { margin-bottom: 10px; }
.mgr-donut { flex: 0 0 auto; display: grid; place-items: center; padding-top: 4px; }
.mgr-table { flex: 1 1 420px; min-width: 0; }

.donut-top { font-size: 15px; font-weight: 700; fill: var(--text); }
.donut-sub { font-size: 8.5px; fill: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
/* Штуки под суммой в кольце «Продажи по менеджерам» (v6.142.2) */
.donut-qty { font-size: 10px; font-weight: 600; fill: var(--muted); }

.mgr-dot {
  display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  margin-right: 7px; vertical-align: baseline;
}

.share-line { display: flex; align-items: center; gap: 8px; margin: 2px 0; }
.share-line .mini-bar { flex: 1 1 auto; min-width: 40px; }
.share-val { font-size: 11.8px; font-weight: 650; font-variant-numeric: tabular-nums; min-width: 42px; text-align: right; }
.share-tag { font-size: 10.5px; color: var(--muted); min-width: 40px; }

/* Полный показатель прошлого месяца отдельной строкой (v2.8) */
.metric-full {
  font-size: 11.8px; color: var(--muted);
  border-top: 1px dashed var(--border); padding-top: 6px; margin-top: 2px;
}
.metric-full b { color: var(--text-2); font-weight: 650; }

@media (max-width: 720px) {
  .mgr-split { gap: 14px; }
  .mgr-donut { width: 100%; }
}

/* ====== Подтверждение получения (v2.9, переписано в v6.0) ====== */

.deliver-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.deliver-move { display: flex; gap: 6px; align-items: center; margin-top: 6px; }
.deliver-move input[type=date],
.receipt-row input[type=date] {
  padding: 5px 8px; font-size: 12.5px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface); color: var(--text);
}

/* Два ответа на один вопрос — и ровно два (v6.0.2, доведено в v6.0.3).
   «Да, получил такого-то» и «Получил другой датой» стоят в одной строке и
   с места не двигаются: календарь дорисовывается ПОД ними, а не расталкивает
   их. Как только выбор другой даты открыт, зелёная кнопка гаснет — нажать её
   случайно значит записать продажу не тем числом; а красная превращается в
   «Отмену» и возвращает всё обратно. */
.receipt-cell { position: relative; }
/* Переключатель вне потока: обычным полем он занимал в ячейке целую строку,
   и все кнопки съезжали ниже середины. Не display:none — иначе его нельзя
   поймать клавиатурой. */
.receipt-toggle {
  position: absolute; top: 0; left: 0;
  appearance: none; -webkit-appearance: none;
  width: 1px; height: 1px; margin: 0; padding: 0; border: 0; opacity: 0;
}
.receipt-answers { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

.receipt-other-btn {
  cursor: pointer; user-select: none;
  color: var(--red); border-color: #f0c4c4; background: var(--red-soft, #fdeceb); font-weight: 600;
}
.receipt-other-btn:hover { border-color: var(--red); background: #fbdedc; }
.receipt-other-btn .on-open { display: none; }

/* Открыто: красная кнопка становится «Отменой» — обычной, не тревожной,
   потому что отмена ничего не портит. */
.receipt-toggle:checked + .receipt-answers .receipt-other-btn {
  color: var(--text-2); border-color: var(--border); background: var(--surface-2); font-weight: 500;
}
.receipt-toggle:checked + .receipt-answers .receipt-other-btn:hover { color: var(--text); border-color: var(--text-3, #9aa3ad); }
.receipt-toggle:checked + .receipt-answers .receipt-other-btn .on-closed { display: none; }
.receipt-toggle:checked + .receipt-answers .receipt-other-btn .on-open { display: inline; }

/* Зелёная кнопка гаснет и перестаёт нажиматься. Атрибут disabled ставит
   скрипт; это — та же защита без него. */
.receipt-toggle:checked + .receipt-answers .receipt-yes,
.receipt-yes[disabled] {
  opacity: .4; pointer-events: none; filter: grayscale(1); cursor: default;
}
.receipt-toggle:focus-visible + .receipt-answers .receipt-other-btn {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

.receipt-panel { display: none; margin-top: 8px; }
.receipt-toggle:checked ~ .receipt-panel { display: flex; flex-direction: column; gap: 6px; }

/* Вопрос и оба ответа в одной строке: «да, этим числом» — кнопкой,
   «другим» — календарём рядом, без перехода на другую страницу. */
.receipt-form { display: flex; flex-direction: column; gap: 5px; }
.receipt-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.receipt-redate { display: flex; gap: 6px; align-items: flex-start; line-height: 1.35; }
.receipt-redate input[type=checkbox] { margin-top: 2px; flex: 0 0 auto; }
/* Дата — по содержимому, причина — на оставшееся место: иначе поле даты
   растягивалось на всю строку и форма разъезжалась на три этажа. */
.receipt-row input[type=date] { flex: 0 0 auto; width: 160px; }
.receipt-row input[type=text] { flex: 1 1 240px; min-width: 200px; }

/* Редкое действие живёт под раскрывающимся заголовком */
.redate-block > summary {
  display: flex; gap: 10px; align-items: baseline; cursor: pointer;
  padding: 14px 18px; font-weight: 600; user-select: none;
}
.redate-block > summary::-webkit-details-marker { display: none; }
.redate-block > summary::before {
  content: '▸'; color: var(--text-2); font-weight: 400; transition: transform .15s;
}
.redate-block[open] > summary::before { content: '▾'; }
.redate-block > summary:hover { background: var(--surface-2); }
.redate-block > .card-body { padding-top: 0; }
/* Тот же приём внутри уже открытой карточки: заголовок без своей рамки */
.redate-block.plain > summary { padding: 10px 0 0; font-weight: 500; font-size: 13px; color: var(--text-2); }
.redate-block.plain > summary:hover { background: none; color: var(--text); }

/* =========================== Таблицы =========================== */

.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* ============ Тень «можно пролистать вбок» (v6.65.0) ============
   Заказчик: «сделай чтобы удобно было пользоваться всеми разделами» —
   проверка мобильной версии показала, что виноваты не потерянные данные
   (широкие таблицы и полоса отборов на доске задач и так скроллятся пальцем
   давно), а то, что обрезанный край никак не подписан и выглядит поломкой.
   `initScrollHints` в app.js сам решает, кому нужна тень (сравнивает
   scrollWidth и clientWidth), и вешает data-more-left/right — здесь только
   отрисовка. Ничего не меняет в разметке и данных. */
[data-scroll-hint] { position: relative; }
[data-scroll-hint][data-more-left]::before,
[data-scroll-hint][data-more-right]::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 28px;
  z-index: 2; pointer-events: none;
}
[data-scroll-hint][data-more-left]::before {
  left: 0; background: linear-gradient(to left, rgba(20, 26, 38, 0), rgba(20, 26, 38, .20));
}
[data-scroll-hint][data-more-right]::after {
  right: 0; background: linear-gradient(to right, rgba(20, 26, 38, 0), rgba(20, 26, 38, .20));
}
table.data { width: 100%; border-collapse: collapse; font-size: 13.2px; }
/* Уголки заголовка таблицы под уголки карточки (макет 25, 29.09) — иначе
   прямоугольная серая «шапка» таблицы стоит вплотную к скруглённому углу
   карточки, и «круглое снаружи, квадратное внутри» бросается в глаза. Только
   там, где таблица занимает карточку целиком без отступов (.card-body.tight
   — это все списки). Низ таблицы отдельно не трогаем: там нет сплошной
   заливки цветом до самого края, скруглённый угол карточки и так виден. */
.card-body.tight table.data thead tr:first-child th:first-child { border-top-left-radius: var(--radius); }
.card-body.tight table.data thead tr:first-child th:last-child { border-top-right-radius: var(--radius); }
table.data th, table.data td { padding: 9px 12px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: middle; }
/* ПОЛЯ У КРАЁВ ТАБЛИЦЫ (v6.16.4, слово заказчика: «название клиента вплотную
   к левому борту, и последний столбец практически вплотную к правому —
   исправь везде»). Одно правило на все таблицы системы: первый столбец
   отступает слева, последний — справа. Внутренние отступы не трогаем, иначе
   поехали бы все ширины. */
table.data th:first-child, table.data td:first-child { padding-left: 16px; }
table.data th:last-child,  table.data td:last-child  { padding-right: 16px; }
table.data tfoot td:first-child { padding-left: 16px; }
table.data tfoot td:last-child  { padding-right: 16px; }
/* У узкой колонки действий свой отступ: там кнопки, и лишние 16 px сдвинули
   бы их от края строки сильнее, чем нужно. */
table.data th.col-actions, table.data td.col-actions { padding-right: 10px; }
table.data.compact th:first-child, table.data.compact td:first-child { padding-left: 12px; }
table.data.compact th:last-child,  table.data.compact td:last-child  { padding-right: 12px; }
table.data thead th {
  background: var(--surface-2); font-weight: 600; font-size: 12px; color: var(--text-2);
  text-transform: uppercase; letter-spacing: .03em; white-space: nowrap; position: sticky; top: 0; z-index: 5;
}
table.data tbody tr:hover { background: var(--surface-2); }
table.data tbody tr.clickable { cursor: pointer; }
/* Товар, который прямо сейчас держит другой заказ (v3.19) */
table.data tbody tr.row-busy { background: var(--amber-soft); }
.busy-note { margin-top: 3px; color: var(--amber); line-height: 1.35; }
.busy-note.busy-tight { color: var(--red); }
/* Фокус на строке виден (v3.19): по таблице теперь ходят с клавиатуры,
   и человек должен видеть, где он стоит */
table.data tbody tr.clickable:focus-visible {
  outline: 2px solid var(--accent); outline-offset: -2px; background: var(--surface-2);
}
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
table.data tfoot td { padding: 10px 12px; font-weight: 650; background: var(--surface-3); border-top: 2px solid var(--border-strong); font-variant-numeric: tabular-nums; }
table.data .th-sort { color: inherit; }
table.data .th-sort:hover { color: var(--accent); text-decoration: none; }
table.data tr.row-total td { font-weight: 650; background: var(--surface-3); }
table.data.compact th, table.data.compact td { padding: 6px 7px; font-size: 12.4px; }
/* Длинные названия переносятся, чтобы широкие таблицы влезали без горизонтальной прокрутки */
/* Первая колонка переносится по словам, но не тогда, когда её явно просили
   не переносить: номера вида «ЗК-00048/26» рвались на три строки (v2.2.1) */
table.data.compact td:first-child:not(.nowrap) { white-space: normal; overflow-wrap: anywhere; }

/* ------------------------------------------------------------------
   Таблица не должна ехать вбок (v3.19)
   ------------------------------------------------------------------
   Правило «без горизонтальной прокрутки» нарушалось давно и молча: на
   экране 1024 px дебиторка вылезала за край на 184 px, отчёт по клиентам —
   на 672 px. Аудит это записал (UX/PERF), но чинить было нечем: колонок в
   этих таблицах действительно много, и все нужны.

   Лечим тем, что дёшево и ничего не прячет:
   1. на узком экране колонки ужимаются в отступах и кегле, а не режутся;
   2. денежные колонки перестают быть шире, чем нужно цифрам;
   3. текстовые колонки получают потолок ширины и переносятся по словам.

   Скрывать колонки классом .col-optional можно там, где колонка правда
   вторична — но по умолчанию не скрывается ничего: пропавшая цифра хуже
   прокрутки. */
@media (max-width: 1280px) {
  table.data th, table.data td { padding: 8px 8px; }
  table.data.compact th, table.data.compact td { padding: 5px 5px; font-size: 12px; }
}
@media (max-width: 1100px) {
  table.data { font-size: 12.6px; }
  table.data th, table.data td { padding: 7px 6px; }
  table.data.compact th, table.data.compact td { padding: 4px 4px; font-size: 11.6px; }
  table.data thead th { letter-spacing: 0; }
  /* Заголовок в две строки вместо одной длинной: «Ожидаемая оплата»
     держал колонку шире, чем сама дата */
  table.data thead th { white-space: normal; }
  table.data td.col-optional, table.data th.col-optional { display: none; }
}
/* Колонка действий, приклеенная к правому краю (v3.24, UX-041).

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

   Колонка держится у правого края и не уезжает. Фон обязателен: без него
   сквозь неё просвечивают проезжающие цифры. */
table.data th.col-sticky, table.data td.col-sticky {
  position: sticky; right: 0; z-index: 2;
  background: var(--surface);
  border-left: 1px solid var(--border);
}
table.data thead th.col-sticky { background: var(--surface-3); }
table.data tbody tr:nth-child(even) td.col-sticky { background: var(--surface-2); }
table.data tbody tr:hover td.col-sticky { background: var(--accent-soft); }
table.data tfoot td.col-sticky { background: var(--surface-3); }

/* Денежная колонка ровно под цифры: моноширинные цифры дают одинаковую
   ширину знака, поэтому колонку можно не расширять «на всякий случай» */
table.data td.num, table.data th.num { font-variant-numeric: tabular-nums; }
/* Длинному тексту — потолок и перенос, иначе одно название товара
   растягивает всю таблицу */
table.data td.wrap-max { max-width: 260px; white-space: normal; overflow-wrap: anywhere; }
table.data .col-actions { width: 1%; white-space: nowrap; text-align: right; }

/* Пустой блок: надпись стоит посередине, а не липнет к верху (v6.17.0,
   замечание заказчика по карточке клиента). Работает и в невысоких блоках:
   в них место просто занимает вся высота. */
.empty {
  padding: 44px 20px; text-align: center; color: var(--muted);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 140px; height: 100%;
}
.empty .ic { width: 40px; height: 40px; opacity: .35; margin-bottom: 10px; }

.pagination { display: flex; align-items: center; gap: 10px; padding: 12px 16px; flex-wrap: wrap; }
.pagination .pages { display: flex; gap: 4px; margin-left: auto; flex-wrap: wrap; }
.pagination .pages a, .pagination .pages span {
  min-width: 30px; height: 30px; padding: 0 8px; border-radius: var(--radius-sm);
  display: inline-grid; place-items: center; font-size: 13px;
  border: 1px solid var(--border); color: var(--text-2); background: var(--surface);
}
.pagination .pages a:hover { background: var(--surface-3); text-decoration: none; }
.pagination .pages .cur { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
.pagination .pages .gap { border: 0; background: none; }

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

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: 20px;
  font-size: 11.8px; font-weight: 600; white-space: nowrap; line-height: 1.7;
  /* Прозрачная рамка по умолчанию (v6.23.1): цветные значки ставят её своим
     цветом, а размер при этом не прыгает у тех, кто её не ставит. */
  border: 1px solid transparent;
}
/* Столбик значков: между ними всегда есть воздух, даже когда второй
   переносится на свою строку (v6.23.0). */
.badge-stack { display: flex; flex-wrap: wrap; gap: 4px 6px; align-items: flex-start; }
/* «Ни разу не отправляли» — красным прямо в отборе (v6.23.1, слово
   заказчика): это худший из ответов списка, и видеть его надо не читая. */
.pt-never, option.pt-never { color: var(--red); font-weight: 600; }
/* КАРАНДАШ — ВНУТРИ ПОЛЯ, СПРАВА, КАК ЗНАЧОК КАЛЕНДАРЯ (v6.23.0).
   Слово заказчика: «карандашик внизу — найди лучшее место… либо он должен
   быть внутри поля, как календарь справа». Кнопка стояла обычным элементом
   после поля и на узкой колонке падала под него отдельной строкой: связь с
   номером терялась, и подпись приходилось читать, чтобы понять, к чему
   карандаш относится. */
.numlock { position: relative; }
.numlock > input { width: 100%; padding-right: 34px; }
.numlock > #numberEdit {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  height: 26px; width: 26px; padding: 0; border: 0; background: none;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--muted); cursor: pointer; border-radius: 6px;
}
.numlock > #numberEdit:hover { color: var(--accent); background: var(--surface-3); }
/* ЗНАЧОК: СВЕТЛАЯ ЗАЛИВКА, НО РАМКА И ТЕКСТ — ПОЛНЫМ ЦВЕТОМ (v6.23.1).
   Выбор заказчика из трёх предложенных наборов: «вариант B, светлая заливка,
   но с рамкой и жирным цветом». Прежние значки были только заливкой, и на
   светлом фоне соседние оттенки сливались — в таблице на тысячу строк
   отличить «Собран» от «Ждёт проверки» было нельзя. Рамка даёт границу
   полным цветом, а фон остаётся мягким и не рябит. */
.badge-green  { background: var(--green-soft);  color: var(--green);  border: 1px solid var(--green); }
.badge-amber  { background: var(--amber-soft);  color: var(--amber);  border: 1px solid var(--amber); }
.badge-red    { background: var(--red-soft);    color: var(--red);    border: 1px solid var(--red); }
.badge-blue   { background: var(--accent-soft); color: var(--accent-dark); border: 1px solid var(--accent); }
.badge-violet { background: var(--violet-soft); color: var(--violet); border: 1px solid var(--violet); }
.badge-cyan   { background: var(--cyan-soft);   color: var(--cyan);   border: 1px solid var(--cyan); }
.badge-grey   { background: var(--grey-soft);   color: var(--grey);   border: 1px solid var(--grey); }
.badge-teal   { background: var(--teal-soft);   color: var(--teal);   border: 1px solid var(--teal); }
.badge-pink   { background: var(--pink-soft);   color: var(--pink);   border: 1px solid var(--pink); }
.badge-yellow { background: var(--yellow-soft); color: var(--yellow); border: 1px solid var(--yellow); }
.badge-orange { background: var(--orange-soft); color: var(--orange); border: 1px solid var(--orange); }
.badge-indigo { background: var(--indigo-soft); color: var(--indigo); border: 1px solid var(--indigo); }
.badge-green-bright {
  background: var(--green-bright-soft); color: var(--green-bright);
  border: 1px solid var(--green-bright); font-weight: 650;
}

/* Дерево групп клиентов (v2.2) */
.tree-pad { display: inline-block; }

/* Строка списания, где просят больше, чем лежит на складе (v2.2) */
tr.row-bad > td { background: var(--red-soft); }
tr.row-bad input { border-color: var(--red); }
.badge-dot::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 9px; border-radius: 7px; background: var(--surface-3);
  font-size: 12.2px; color: var(--text-2);
}
.chip a { color: var(--muted); display: grid; place-items: center; }
/* Чип-ссылка: выглядит как обычный чип, но кликается (v2.5) */
a.chip { color: var(--text-2); text-decoration: none; }
a.chip:hover { background: var(--accent-soft); color: var(--accent-dark); text-decoration: none; }

/* Строка фильтра чипами: «Важность: все / Важно / Обычный …» (v3.16).
   Тот же чип, что и везде, только выбранный залит акцентом */
.chip-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; margin: -4px 0 14px; }
.chip-filters .chip-label { color: var(--muted); font-size: 12.5px; }
a.chip.on, a.chip.on:hover { background: var(--accent); color: #fff; }
a.chip .count { font-size: 11.5px; opacity: .72; }

/* Переключатель режимов из двух кнопок («Реальное время / При полном
   закрытии», v6.102.0). ЧТО БЫЛО: обе кнопки почти одного цвета — выбранная
   отличалась лишь белой подложкой, и Игорь не видел, какая нажата. КАК ТЕПЕРЬ:
   выбранная залита акцентным цветом с белым текстом, невыбранная — контурная
   (прозрачная, текст акцентный). Выбор ведёт aria-pressed, класс `.on` — то же. */
.seg-toggle { display: inline-flex; gap: 2px; padding: 3px; margin-bottom: 14px;
  background: var(--surface); border: 1.5px solid var(--accent); border-radius: 10px; }
.seg-toggle .seg { font: inherit; font-weight: 600; padding: 6px 14px; border: 0; border-radius: 7px;
  background: transparent; color: var(--accent-dark); cursor: pointer; }
.seg-toggle .seg:hover { background: var(--accent-soft); }
.seg-toggle .seg:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.seg-toggle .seg.on, .seg-toggle .seg[aria-pressed="true"],
.seg-toggle .seg.on:hover, .seg-toggle .seg[aria-pressed="true"]:hover { background: var(--accent); color: #fff; }

/* =========================== Формы =========================== */

.form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
.form-grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Форма читаемой ширины (v6.49.0, предложение 74): длинная строка полей
   на широком мониторе читается хуже, чем колонка нормальной ширины. */
.form-grid.form-narrow { max-width: 760px; }
/* Счётчики базы одной строкой вместо ряда плиток (v6.49.0, предложение 77) */
/* Сведения о базе на странице настроек (v6.50.2, п.7 заказчика: «верни как
   было, блоками, сейчас оно теряется»). Блоки низкие: число крупное, подпись
   рядом — читается с одного взгляда, но не занимает высоту дашбордной
   плитки и не выталкивает вкладки за нижний край экрана. */
.settings-counts { margin: 10px 0 6px; display: flex; flex-wrap: wrap; gap: 8px; }
.scount {
  display: inline-flex; align-items: baseline; gap: 7px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 8px 12px;
}
.scount-ic { color: var(--muted); align-self: center; display: inline-flex; }
.scount-n { font-weight: 700; font-size: 16px; font-variant-numeric: tabular-nums; }
.scount-l { color: var(--muted); font-size: 12.5px; }
/* Таблица нумерации (v6.49.0, предложение 75): ширина читаемая, колонки по
   содержимому, поля не растягиваются на всю ячейку. */
.seq-table { max-width: 980px; }
.seq-table input, .seq-table select { width: auto; min-width: 90px; }
.seq-table td:first-child { width: 28%; }
/* Пояснение под таблицей отодвинуто от края карточки (v6.49.0, п.17
   заказчика): карточка идёт без внутренних отступов ради таблицы, и текст
   под ней иначе упирается в самую рамку. */
.seq-note { max-width: 90ch; margin: 10px 14px 14px; }
/* Карточки-ссылки на справочники (v6.49.0, предложение 67). Не таблица и не
   список ссылок: у каждого справочника есть имя и одно предложение о том,
   что в нём лежит, — иначе «Причины списания» и «Причины возврата» на вид
   неразличимы. */
.ref-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px; }
.ref-card { display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface);
  color: inherit; text-decoration: none; }
.ref-card:hover { border-color: var(--accent); background: var(--surface-2); text-decoration: none; }
.ref-card b { display: block; }
.ref-card .xs { display: block; margin-top: 2px; }
.ref-ic { color: var(--muted); flex: none; }
.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field.span-2 { grid-column: span 2; }
.field.span-full { grid-column: 1 / -1; }
/* .lbl — заголовок группы полей (v5.0.4). Раньше это был <label>, но
   подписывать он ничего не подписывал: под ним не поле, а несколько
   переключателей или готовое значение. Выглядит так же, обещает честно.
   Имя именно .field-lbl: .lbl уже занят печатными формами. */
/* Поле пароля с глазиком (v5.0.11, просьба заказчика).
   Кнопка внутри поля, а не рядом: иначе на узком экране она уезжает от него.
   Место под неё освобождается отступом справа у самого поля. */
.pwd-field { position: relative; display: block; }
.pwd-field input { width: 100%; padding-right: 38px; }
.pwd-eye {
  position: absolute; top: 50%; right: 4px; transform: translateY(-50%);
  width: 30px; height: 30px; padding: 0; display: grid; place-items: center;
  background: none; border: 0; border-radius: var(--radius-sm);
  color: var(--muted); cursor: pointer;
}
.pwd-eye:hover { color: var(--text-2); background: var(--surface-3); }
.pwd-eye:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--accent-soft); color: var(--accent); }
.pwd-eye[aria-pressed="true"] { color: var(--accent); }

/* Подсказка под полем пароля (v5.0.10, просьба заказчика).
   Невыполненное — серое, а не красное: пока человек печатает, он ещё ничего
   не нарушил, и ругать его рано. Красным он увидит только отказ после
   «Сохранить». */
.pwd-rules { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.pwd-rule {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; line-height: 1; padding: 5px 9px; border-radius: 999px;
  background: var(--surface-3); color: var(--muted); border: 1px solid transparent;
  transition: background .15s, color .15s, border-color .15s;
}
.pwd-rule .tick { width: 13px; height: 13px; flex: none; }
.pwd-rule .tick circle { fill: var(--border-strong); }
.pwd-rule .tick path {
  stroke: var(--surface); stroke-width: 2.2; fill: none;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 14; stroke-dashoffset: 14; transition: stroke-dashoffset .18s ease;
}
.pwd-rule.done { background: var(--green-soft); color: var(--green); border-color: #bfe6d2; }
.pwd-rule.done .tick circle { fill: var(--green); }
.pwd-rule.done .tick path { stroke-dashoffset: 0; }
@media (prefers-reduced-motion: reduce) {
  .pwd-rule, .pwd-rule .tick path { transition: none; }
}

label, .field-lbl { font-size: 12.5px; font-weight: 570; color: var(--text-2); }
label .req, .field-lbl .req { color: var(--red); }

/* ============ Дата всегда день-месяц-год (v6.0.4) ============
   Текст внутри поля с календарём рисует сам браузер — по языку СВОЕГО
   интерфейса, не по языку страницы. У человека с английским Chrome там
   будет 08/30/2026, и разметкой это не лечится. Поэтому родной текст
   гасим, а свой пишем поверх: 30.08.2026, пустое — «дд.мм.гггг».
   Поле остаётся настоящим `type=date`: календарь, проверка и значение
   для сервера те же. Обёртку ставит скрипт; без него поле просто
   останется обычным. */
.dt { position: relative; display: inline-block; width: 100%; }
/* ЧУЖОЙ ФОРМАТ ГАСИТСЯ С ПЕРВОГО КАДРА (v6.22.1, замечание заказчика:
   «перепрыгивают между английской формой и русской»). Правила ниже ждут
   обёртки `.dt`, которую ставит скрипт после разбора всей страницы, — и до
   этого мига в поле успевало показаться браузерное «mm/dd/yyyy». Класс
   `js-dt` появляется в первых строках <head>, поэтому родной текст не
   рисуется ни разу. Отступ справа задан здесь же, чтобы поле не дёрнулось
   в ширину, когда скрипт дорисует значок календаря. */
html.js-dt input[type=date] { color: transparent; padding-right: 30px; }
html.js-dt input[type=date]::-webkit-datetime-edit { opacity: 0; }
html.js-dt input[type=date]::-webkit-calendar-picker-indicator { display: none; }
/* Значок календаря рисуем сами (v6.20.0). Родной убран ниже: окно выбора
   у нас своё, и родное открывалось поверх него. Но без значка поле стало
   бы неотличимо от обычного текстового — человек не понял бы, что тут
   вообще открывается календарь. Свой значок рисуется картинкой прямо в
   поле, поэтому он на месте всегда, а не только в Chrome. */
.dt > input[type=date] {
  color: transparent;
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237a8694' stroke-width='2' stroke-linecap='round'%3E%3Crect x='3' y='5' width='18' height='16' rx='2'/%3E%3Cpath d='M3 10h18M8 3v4M16 3v4'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center;
  background-size: 15px; padding-right: 30px;
}
/* Chrome рисует текст в собственной тени поля. Одного `color: transparent`
   мало: при фокусе он подсвечивает выделенный кусок даты, и сквозь нашу
   надпись проступает «30.08.20|26|». Гасим весь редактор целиком —
   значок календаря это отдельная часть, он остаётся на месте. */
.dt > input[type=date]::-webkit-datetime-edit { opacity: 0; }
/* Родной значок убран: по нему открывалось родное окно выбора — с
   английскими месяцами и поверх нашего календаря (v6.20.0). Свой значок
   нарисован выше, поэтому поле по-прежнему видно как поле с датой. */
.dt > input[type=date]::-webkit-calendar-picker-indicator { display: none; }
.dt > .dt-text {
  position: absolute; top: 50%; transform: translateY(-50%);
  /* Слева — по внутреннему отступу поля, справа — не доходя до значка
     календаря (он стоит на right 8px). Иначе «дд.мм.гггг» на узком поле
     заезжал под значок (v6.38.0, замечание заказчика). */
  left: 10px; right: 30px; overflow: hidden;
  pointer-events: none; white-space: nowrap; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.dt > .dt-text.empty { color: var(--muted); }
.dt > input[type=date]:disabled + .dt-text { color: var(--muted); }
/* Там, где поле было узким элементом строки, узкой становится обёртка —
   размер теперь держит она. */
.receipt-row .dt, .deliver-move .dt { flex: 0 0 auto; width: 160px; }
.receipt-row .dt > input[type=date], .deliver-move .dt > input[type=date] { width: 100%; }

input[type=text], input[type=email], input[type=password], input[type=number],
input[type=date], input[type=month], input[type=search], input[type=tel], input[type=file],
select, textarea {
  width: 100%; min-height: 34px; padding: 6px 10px;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text);
  font-size: 13.5px; font-family: inherit;
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
input:disabled, select:disabled, textarea:disabled { background: var(--surface-3); color: var(--muted); }
input[readonly] { background: var(--surface-3); }
textarea { min-height: 76px; resize: vertical; }
select { appearance: none; background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237a8694' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center; background-size: 15px; padding-right: 28px; }
/* ЦИФРЫ НЕ ПРИЖАТЫ К СТРЕЛКАМ (v6.23.2, замечание заказчика: «эта стрелочка
   выше-ниже стоит вплотную к цифрам — отодвинь цифры чуть-чуть левее»).
   Поле выровнено вправо, а браузер рисует свой переключатель поверх правого
   края: число упиралось в него. Отступ справа освобождает стрелкам место. */
input.num, td input.num { text-align: right; font-variant-numeric: tabular-nums; }
input.num[type=number] { padding-right: 22px; }
/* А там, где рядом ещё и «%», места нужно на оба знака */
.suffix-pct input.num[type=number] { padding-right: 38px; }
.suffix-pct::after { right: 22px; }
/* Поле с повторяющимся номером порядка (v6.13.0): «должно загореться
   красным, типа эй, тут одинаково и реши». */
input.inp-bad { border-color: var(--red); background: var(--red-soft); }

/* Срок годности в строке прихода (v6.13.6, выровнено в 6.13.7).
   Подписи одной ширины и в одну строку, поля дат одного размера — иначе
   «годен до» переносилось на две строки и обе даты стояли лесенкой. */
.exp-cell .check { margin-bottom: 5px; }
.exp-dates { display: flex; flex-direction: column; gap: 5px; }
.exp-dates label { display: grid; grid-template-columns: 78px 1fr; align-items: center; gap: 8px; }
.exp-dates label > span { white-space: nowrap; }
.exp-dates input[type="date"] { width: 100%; min-width: 0; }

/* Номер партии: система присвоит сама, поэтому поле серое и не редактируется,
   пока человек сам этого не попросит (v6.13.7). */
input.batch-no[data-auto] { color: var(--muted); cursor: pointer; background: var(--surface-2); }

/* Позиции закрыты, пока не заполнена шапка прихода (v6.13.7). */
.head-gate { display: flex; align-items: center; gap: 9px;
             padding: 12px 18px; border-top: 1px solid var(--border);
             background: var(--amber-soft); color: var(--text); font-size: 13.5px; }
.head-gate svg { flex: 0 0 auto; color: var(--amber); }
.card.gated .card-body { opacity: .45; pointer-events: none; }

/* Погашенное поле пары «либо одно, либо другое» (v6.13.0): видно, что оно
   есть, и видно, что сейчас туда нельзя. */
.field.field-off { opacity: .5; }
.field.field-off label, .field.field-off .field-lbl { color: var(--muted); }
.field .hint { font-size: 11.5px; color: var(--muted); }
/* Подсказка отдельной строкой: под полем она распирает соседей по сетке (v2.6) */
.field.hint-row { margin-top: -6px; }
.field .err  { font-size: 11.8px; color: var(--red); }
.field.has-error input, .field.has-error select { border-color: var(--red); }

.check { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13.5px; color: var(--text); }
.check input[type=checkbox], .check input[type=radio] { width: 16px; height: 16px; accent-color: var(--accent); margin: 0; }

.input-group { display: flex; }
.input-group input { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.input-group .btn { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; margin-left: -1px; }
/* ЗНАК «%» СТОИТ У ПОЛЯ, А НЕ ПОСЕРЕДИНЕ ВСЕГО БЛОКА (v6.23.2).
   Замечание заказчика: «маркетинг с наших отправок — ноль, и знак процента
   ушёл вниз».
   `top: 50%` считался от ВСЕЙ клетки — подпись сверху, поле, подсказка снизу.
   Пока подсказки не было, середина клетки совпадала с серединой поля; как
   только подсказка появилась, «%» уехал в неё. Считаем от верха: подпись —
   23 пикселя, дальше поле высотой 34, и знак встаёт ровно по его середине. */
.suffix-pct { position: relative; }
.suffix-pct::after {
  content: '%'; position: absolute; right: 10px; top: 23px; height: 34px;
  display: flex; align-items: center;
  color: var(--muted); font-size: 12.5px; pointer-events: none;
}
.suffix-pct input { padding-right: 24px; }

fieldset { border: 1px solid var(--border); border-radius: var(--radius); padding: 14px; margin: 0 0 16px; }
legend { font-size: 12.5px; font-weight: 650; color: var(--text-2); padding: 0 6px; }

/* =========================== Фильтры =========================== */

.filters {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 12px; margin-bottom: 14px; box-shadow: var(--shadow-1);
}
/* Поля выравниваются по верху: у части полей снизу подсказка, и при
   выравнивании по низу соседний список уезжал вниз (v3.4.5) */
.filters form { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-start; }
/* Кнопки без подписи — поднимаем на высоту подписи, чтобы стояли в линию с полями */
/* ПОЛЯ ОТБОРА ТЯНУТСЯ НА ВСЮ ШИРИНУ (v6.23.0).
   Замечание заказчика: «строка поиска длинная, а нижняя — где клиенты,
   холдинги, оформил, менеджер клиента, накладная — короче; выглядит
   непропорционально, наведи порядок, чтобы было одинаково всё».
   Поля стояли своей шириной и не росли: строка поиска занимала всю ширину, а
   ряд под ней кончался раньше — правый край рвался на каждой строке. Теперь
   свободное место делится между полями ряда, и все ряды кончаются на одной
   вертикали. 168px остаётся тем, с чего рост начинается: при узком экране
   поля по-прежнему переносятся, а не сжимаются в ничто. */
.filters .field { flex: 1 1 168px; }
/* Широкое поле не растягивается на пол-экрана (v6.20.0, замечание
   заказчика: «поиск и категория очень далеко друг от друга»): поля стоят
   подряд, а свободное место уходит кнопкам справа. */
.filters .field.wide { flex: 1 1 240px; max-width: 460px; }
/* Поле на всю ширину отдельной строкой: поиск в заказах (v2.5) */
.filters .field.full { flex: 1 0 100%; }
/* Диапазон дат одним блоком: «с» и «по» никогда не разъезжаются (v2.5) */
.filters .field.range { flex: 0 1 250px; }
.filters .field.range .range-row { display: flex; align-items: center; gap: 6px; }
.filters .field.range input { min-width: 0; flex: 1 1 auto; }
/* Обёртку `.dt` ставит скрипт календаря — и в узком ряду именно она, а не
   само поле, оказывается в раскладке (v6.23.0). Без этой строки поле «по»
   вылезало за свой блок и уезжало под кнопку «Найти». */
.filters .field.range .range-row > .dt { flex: 1 1 0; min-width: 0; width: auto; }
.filters .field.range .range-sep { color: var(--muted); flex: 0 0 auto; }
/* Кнопки без подписи — на высоте подписи, чтобы стояли в линию с полями */
/* Кнопки стоят на линии полей, а не ниже (v6.19.0, замечание заказчика:
   «насколько кнопка „найти“ и „сбросить“ ниже — надо поднять»): отступ
   сверху равен высоте подписи поля, поэтому они садятся ровно в строку. */
/* КНОПКИ ВСТАЮТ ПО НИЖНЕМУ КРАЮ ПОЛЕЙ, А НЕ ПО ОТСТУПУ (v6.22.1).
   Замечание заказчика (второй раз): «уже просил ранее, ты сказал что сделал,
   но по факту не сделал».
   Он прав, и вот почему прежняя починка не сработала. Отступ в 23 пикселя —
   высота подписи — годится, только пока кнопки стоят В ОДНОЙ строке с полями.
   А в договорах полей пять, они не помещаются, строка переносится — и тогда
   к переносу добавлялись ещё 23 пикселя пустоты сверху: кнопки уезжали почти
   на полстроки вниз. Сколько полей поместится, CSS заранее не знает, поэтому
   считать отступ нельзя вовсе.
   `align-self: flex-end` считать и не нужно: кнопка прижимается к нижнему
   краю СВОЕЙ строки. Стоит рядом с полями — встаёт вровень с ними; перенеслась
   на свою строку — строка ровно по высоте кнопки, и лишней пустоты нет. */
.filters .actions { display: flex; gap: 8px; margin-left: auto; align-items: flex-start; align-self: flex-end;
   /* Своё место кнопки держат сами (v6.23.0): поля теперь растягиваются, и без
      этой строки они съедали ширину кнопок, а «Найти» налезала на поле даты. */
   flex: 0 0 auto; }
/* высота у кнопок отбора обычная — задаётся самим `.btn` (v6.23.4) */
/* «Сбросить» тоже с рамкой: рядом с синей кнопкой прозрачная читалась как
   текст, а не как кнопка (v6.19.0, замечание заказчика). */
.filters .actions .btn-ghost { border-color: var(--border); background: var(--surface, #fff); }
.filters .actions .btn-ghost:hover { border-color: var(--accent); color: var(--accent); background: var(--surface, #fff); }
/* Своя строка — только там, где полей столько, что рядом уже не встать.
   Отступа сверху при этом нет: строка и так отделена промежутком формы. */
.filters .actions.actions-below { flex: 1 0 100%; justify-content: flex-end; margin-top: 0; }
/* РАЗРЫВ РЯДА В ОТБОРЕ (v6.33.0, п.56).
   Замечание заказчика по дебиторке: «даты опустить вниз — на одной строке
   будет тесно; кнопки поиска сделать второй строкой, на уровне дат, справа».
   Сам по себе перенос случается там, где кончится ширина, — а нужен он в
   заданном месте. Пустая распорка во всю ширину и нулевой высоты закрывает
   ряд, и всё, что идёт после неё, начинает новый: даты слева, кнопки
   (у `.actions` стоит `margin-left: auto`) — справа, на одной с ними линии. */
/* Распорка тянет вторую строку вверх на один интервал сетки: без этого две
   строки отбора стояли слишком далеко друг от друга (v6.38.0, замечание
   заказчика по дебиторке). */
.filters .filters-break { flex: 1 0 100%; height: 0; margin: -18px 0 0; padding: 0; }
.quick-periods { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
.quick-periods a {
  padding: 4px 10px; border-radius: 20px; font-size: 12.3px;
  border: 1px solid var(--border); color: var(--text-2); background: var(--surface);
}
.quick-periods a:hover { background: var(--surface-3); text-decoration: none; }
.quick-periods a.on { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }

/* =========================== Вкладки =========================== */

/* Вкладки переносятся на вторую строку, а не уезжают в горизонтальную прокрутку */
.tabs { display: flex; flex-wrap: wrap; gap: 2px; width: fit-content; max-width: 100%;
  padding: 4px; background: #e7ebf0; border-radius: 11px; margin-bottom: 16px; }
/* ВКЛАДКИ — СЕГМЕНТАМИ (v6.132.1, макет 137б, вариант А, выбор Игоря).
 *
 * ЧТО БЫЛО. Вкладки — текст в строку с тонкой синей линией под выбранной,
 * прямо на сером фоне под плитками. Менеджеры говорили, что строка
 * «теряется» и не читается как переключатель.
 *
 * КАК ТЕПЕРЬ. Все вкладки собраны в серую капсулу, выбранная — белая
 * «клавиша» с лёгкой тенью. Синих заливок нет нарочно: синим в системе
 * окрашены кнопки действий («Новый заказ»), вкладки с ними не спорят.
 * Одно правило на все экраны с вкладками (`.tabs`, отчёты — `.an-tabs`). */
.tabs a {
  padding: 7px 14px; font-size: 13.5px; font-weight: 600; color: var(--text-2);
  border-radius: 8px; white-space: nowrap;
}
@media (max-width: 560px) {
  .tabs a { padding: 7px 11px; font-size: 13px; }
}
.tabs a:hover { color: var(--text); background: rgba(255, 255, 255, .6); text-decoration: none; }
.tabs a.active { color: var(--accent-dark); background: #fff;
  box-shadow: 0 1px 2px rgba(16, 21, 28, .10), 0 1px 4px rgba(16, 21, 28, .06); }
.tabs a:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.tabs .count { font-size: 11.5px; color: var(--muted); margin-left: 4px; }
/* Закрытая вкладка: видна, но не нажимается (v6.23.3). Спрятать её нельзя —
   тогда возникает вопрос «а куда она делась»; погашенная с подсказкой на
   наведении отвечает на него сама. */
.tabs .tab-off {
  padding: 7px 14px; font-size: 13.5px; font-weight: 600; color: var(--muted);
  border-radius: 8px; white-space: nowrap;
  opacity: .55; cursor: not-allowed;
}

/* =========================== Уведомления =========================== */

/* Плашка не уезжает за край экрана (v3.34.1).
 *
 * Ответ банка приходит одной строкой JSON без пробелов — разорвать её браузеру
 * не по чему, и плашка растягивалась шире окна: текст обрезался, а крестик
 * уезжал за правый край. Человек видел сообщение, которое нельзя ни дочитать,
 * ни закрыть. Отсюда `overflow-wrap: anywhere` и предел по высоте: очень
 * длинный ответ прокручивается внутри плашки, а не растёт на весь экран. */
.sr-more { display: block; padding: 9px 12px; font-size: 12.5px; border-top: 1px solid var(--border);
            color: var(--accent); }
.sr-more.muted { color: var(--muted); }
.msg-empty { padding: 14px 16px; color: var(--muted); font-size: 13px; }
.flash-area { position: fixed; top: 66px; right: 18px; z-index: 200; display: flex; flex-direction: column; gap: 8px;
              max-width: min(380px, calc(100vw - 36px)); }
.flash {
  display: flex; gap: 9px; align-items: flex-start;
  padding: 11px 13px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--shadow-2); font-size: 13.3px;
  animation: slideIn .2s ease;
  min-width: 0; max-width: 100%; overflow-wrap: anywhere; overflow-wrap: anywhere;
}
.flash > div { min-width: 0; max-height: 40vh; overflow: auto; }
@keyframes slideIn { from { opacity: 0; transform: translateX(12px); } to { opacity: 1; transform: none; } }
/* ТИП СООБЩЕНИЯ ВИДЕН СРАЗУ (v6.49.0, предложение 180).
   ЧТО БЫЛО: успех от ошибки отличала полоска в три точки слева на белой
   карточке. Сообщения появляются в углу и живут пять секунд — за это время
   человек должен понять, всё прошло или нет, не вчитываясь.
   КАК ТЕПЕРЬ: полоса шире, карточка слегка подкрашена в свой цвет, а перед
   текстом стоит знак — «✓» у успеха, «!» у ошибки и предупреждения, «i» у
   сообщения. Цвет и знак вместе: одним цветом полагаться нельзя, каждый
   двенадцатый мужчина его не различает. */
.flash { position: relative; }
.flash::before { flex: 0 0 auto; width: 18px; height: 18px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; line-height: 1; margin-top: 1px; }
.flash.success { border-left: 4px solid var(--green); background: var(--green-soft); }
.flash.success::before { content: '✓'; background: var(--green); color: #fff; }
.flash.error   { border-left: 4px solid var(--red); background: var(--red-soft); }
.flash.error::before { content: '!'; background: var(--red); color: #fff; }
.flash.warning { border-left: 4px solid var(--amber); background: var(--amber-soft); }
.flash.warning::before { content: '!'; background: var(--amber); color: #fff; }
.flash.info    { border-left: 4px solid var(--accent); background: var(--accent-soft); }
.flash.info::before { content: 'i'; background: var(--accent); color: #fff; }
.flash .close { margin-left: auto; cursor: pointer; color: var(--muted); background: none; border: 0;
                flex: 0 0 auto; font-size: 18px; line-height: 1; padding: 0 2px; }
.flash .close:hover { color: var(--ink, var(--text)); }

.alert { padding: 11px 13px; border-radius: var(--radius); font-size: 13.3px; margin-bottom: 14px;
         display: flex; gap: 9px; align-items: flex-start; flex-wrap: wrap; min-width: 0; }
/* Полоски-подсказки переносятся по словам (v3.21, AUD4-006).
   Без flex-wrap строка «Задолженность: … · лимит: … · доступно к отгрузке: …»
   вытягивала страницу на телефоне до 507 точек при экране 390: вбок ездила
   вся страница, а не таблица внутри неё. */
.alert > * { min-width: 0; }
/* Текст стоит РЯДОМ со значком, а не под ним (v6.16.1, снимок заказчика с
   холдинга): без flex-basis длинный абзац переносился целиком на новую строку */
.alert > :not(svg) { flex: 1 1 220px; }
.alert-info { background: var(--accent-soft); color: #1e40af; }

/* Поле кода подтверждения — один вид на входе сотрудника и на входе
   покупателя (v6.26.0). Раньше стиль жил внутри страницы входа
   сотрудника, и второй такой экран пришлось бы описывать заново. */
.code-input{
  font-size:30px;letter-spacing:12px;text-align:center;font-weight:700;
  font-variant-numeric:tabular-nums;padding:14px 10px;
}
.code-input::placeholder{color:var(--border-strong);letter-spacing:12px}
.alert-warn { background: var(--amber-soft); color: #92400e; }
.alert-error{ background: var(--red-soft);  color: #991b1b; }
/* Кнопка, ведущая к опасному экрану (v6.49.0, предложение 121). Не красная
   заливка — она означала бы «нажми и сделай», — а красная рамка и текст:
   «здесь будет что-то необратимое». */
.btn-danger-quiet { border-color: var(--red); color: var(--red); background: transparent; }
.btn-danger-quiet:hover { background: var(--red-soft); }

/* Матрица прав роли (v6.49.0, предложения 76 и 92): шапка колонок остаётся
   на виду при прокрутке, а полоса сохранения прилипает к низу экрана —
   иначе, отметив право в нижней строке, приходится искать кнопку наверху. */
.perm-table thead th { position: sticky; top: var(--topbar-h, 56px); z-index: 4;
  background: var(--surface-2); }
.perm-save { position: sticky; bottom: 0; z-index: 5; background: var(--surface);
  border-top: 1px solid var(--border); }

/* Свёрнутая проверка (v6.49.0, предложение 86): когда замечаний нет, вместо
   таблицы видна одна спокойная строка. */
.diag-fold > summary { cursor: pointer; padding: 10px 14px; font-size: 13px; color: var(--text-2); }
.diag-fold > summary:hover { color: var(--accent-dark); }
.diag-fold[open] > summary { border-bottom: 1px solid var(--border); margin-bottom: 4px; }
.alert-good { background: var(--green-soft); color: #065f46; }

/* =========================== Модальные окна =========================== */

.modal-backdrop {
  position: fixed; inset: 0; background: rgba(16, 21, 28, .42);
  display: none; align-items: center; justify-content: center; z-index: 150; padding: 12px;
  backdrop-filter: blur(2px);
}
.modal-backdrop.open { display: flex; }
.modal {
  background: var(--surface); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3); width: 100%; max-width: 560px;
  /* Окно занимает почти всю высоту экрана: чем оно выше, тем реже внутри
     появляется собственная прокрутка (v3.5.6) */
  max-height: calc(100vh - 24px); display: flex; flex-direction: column; animation: pop .16s ease;
}
.modal.wide { max-width: 900px; }
@keyframes pop { from { opacity: 0; transform: scale(.97); } to { opacity: 1; transform: none; } }

/* Почти во всех окнах между `.modal` и его частями стоит <form>. Без этих
   трёх строк форма не подчиняется колоночному flex окна: `max-height: 90vh`
   ни на что не влияет, тело не прокручивается, и кнопки «Отмена/Сохранить»
   уезжают за нижний край экрана — прокручивается страница позади (v3.5.6) */
.modal > form { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
.modal-head, .modal-foot { flex: 0 0 auto; }
.modal-head { padding: 14px 18px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 10px; }
.modal-head h3 { flex: 1; }
.modal-body { padding: 18px; overflow-y: auto; flex: 1 1 auto; min-height: 0; overscroll-behavior: contain; }
.modal-foot { padding: 13px 18px; border-top: 1px solid var(--border); display: flex; gap: 8px; justify-content: flex-end; background: var(--surface-2); border-radius: 0 0 var(--radius-lg) var(--radius-lg); }

/* Пока окно открыто, страница под ним не прокручивается: иначе колесо
   листает фон, а не содержимое окна */
html.modal-open, body.modal-open { overflow: hidden; }
/* Место под полосу прокрутки резервируем всегда — иначе при открытии окна
   страница дёргается на ширину полосы */
html { scrollbar-gutter: stable; }

/* ===== Полоска состояния банка на финансовых страницах (v3.2.3) ===== */

.bank-strip {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 9px 13px; margin-bottom: 14px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-2); font-size: 12.8px; color: var(--text-2);
}
.bank-strip.bad { border-color: var(--red); background: var(--red-soft, #fff1f0); }
.bs-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); flex: none; }
.bank-strip.bad .bs-dot { background: var(--red); }
.bs-main { min-width: 0; }
.bs-next { font-size: 12px; }
.bs-link { margin-left: auto; display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }

/* ============ Три линии на одной картинке (v3.1) ============
   Деньги, штуки и клиенты — разные единицы и разные порядки величин.
   Каждая линия масштабируется на свой максимум: сравнивается форма —
   где растём, где просели, где деньги вверх, а клиентов всё меньше. */

.tl { display: flex; flex-direction: column; gap: 10px; }
.tl-legend { display: flex; gap: 18px; flex-wrap: wrap; }
.tl-item { display: inline-flex; align-items: center; gap: 7px; font-size: 12.6px; }
.tl-item i { width: 14px; height: 3px; border-radius: 2px; display: inline-block; }
.tl-item b { font-weight: 600; }
.tl-plot { position: relative; }
.tl-plot svg { display: block; width: 100%; height: 150px; overflow: visible; }   /* как «Обзор» (v6.144.0) */
.tl-grid { stroke: var(--border); stroke-width: 1; opacity: .6; vector-effect: non-scaling-stroke; }
.tl-guide { stroke: var(--text); stroke-width: 1; opacity: .28; vector-effect: non-scaling-stroke; }
.tl-dot { opacity: 0; transition: opacity .1s; }
.tl-dot.on { opacity: 1; }
.tl-hit { cursor: crosshair; }
.tl-axis { display: flex; justify-content: space-between; font-size: 11.5px; color: var(--muted); }
.tl-axis span { flex: 1 1 0; text-align: center; min-width: 0; }
.tl-axis span:first-child { text-align: left; }
.tl-axis span:last-child { text-align: right; }

/* Плитка-кнопка: открывает окно с детализацией, а выглядит как плитка */
button.kpi { text-align: left; cursor: pointer; font: inherit; }
button.kpi:hover { border-color: var(--border-strong); }

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

.chart-bars { display: flex; align-items: flex-end; gap: 6px; height: 190px; padding-top: 10px; }
.chart-bars .bar-col { flex: 1 1 0; display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 0; height: 100%; justify-content: flex-end; }
.chart-bars .bar {
  width: 100%; max-width: 46px; background: linear-gradient(180deg, #4f83f1, var(--accent));
  border-radius: 5px 5px 0 0; min-height: 2px; position: relative; transition: opacity .12s;
}
.chart-bars .bar:hover { opacity: .82; }
.chart-bars .bar-label { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.chart-bars .bar-value { font-size: 11px; color: var(--text-2); font-weight: 600; }
.chart-bars .bar-qty { font-size: 10px; white-space: nowrap; }

.hbar { display: flex; align-items: center; gap: 10px; padding: 5px 0; }
.hbar .hbar-name { width: 190px; flex: 0 0 auto; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbar .hbar-track { flex: 1 1 auto; height: 20px; background: var(--surface-3); border-radius: 5px; overflow: hidden; }
.hbar .hbar-fill { height: 100%; background: var(--accent); border-radius: 5px; }
.hbar .hbar-val { width: 110px; flex: 0 0 auto; text-align: right; font-size: 12.6px; font-variant-numeric: tabular-nums; font-weight: 600; }
.hbar .hbar-pct { width: 52px; flex: 0 0 auto; text-align: right; font-size: 12.6px; font-variant-numeric: tabular-nums; font-weight: 700; }   /* доля группы (v6.144.1) */

.progress { height: 7px; background: var(--surface-3); border-radius: 5px; overflow: hidden; }
.progress > div, .progress > span { display: block; height: 100%; background: var(--accent); transition: width .25s; }
.progress.good > div { background: var(--green); }
.progress.warn > div { background: var(--amber); }
.progress.bad  > div { background: var(--red); }

.sparkline { display: flex; align-items: flex-end; gap: 2px; height: 30px; }
.sparkline i { flex: 1; background: var(--accent-soft); border-radius: 2px 2px 0 0; min-height: 2px; }

/* =========================== Прочее =========================== */

.def-list { display: grid; grid-template-columns: max-content 1fr; gap: 7px 16px; font-size: 13.3px; align-items: baseline; }
.def-list dt { color: var(--muted); }
.def-list dd { margin: 0; }

.timeline { position: relative; padding-left: 20px; }
.timeline::before { content: ''; position: absolute; left: 5px; top: 4px; bottom: 4px; width: 2px; background: var(--border); }
/* Каждая запись — своим блоком, сверху вниз (v6.38.0, замечание заказчика:
   «история статусов — визуально беспорядок»). Раньше `.tl-item` доставалось
   `display:inline-flex` от соседнего правила, и записи слипались в строку. */
.timeline .tl-item { display: block; position: relative; padding-bottom: 12px; }
.timeline .tl-item::before { content: ''; position: absolute; left: -19px; top: 5px; width: 9px; height: 9px; border-radius: 50%; background: var(--accent); border: 2px solid var(--surface); }
.timeline .tl-time { font-size: 11.8px; color: var(--muted); margin-top: 2px; }

.thumb { width: 34px; height: 34px; border-radius: 6px; object-fit: contain; background: var(--surface-3); border: 1px solid var(--border); }
.thumb-ph { display: grid; place-items: center; color: var(--muted); }
.thumb-lg { width: 120px; height: 120px; }
.thumb-zoom { display: inline-block; cursor: zoom-in; position: relative; }
.thumb-zoom:hover img { border-color: var(--accent); }

/* Просмотр изображения в полном размере */
.lightbox {
  position: fixed; inset: 0; z-index: 300; display: none;
  background: rgba(15, 20, 28, .82); padding: 32px;
  align-items: center; justify-content: center; cursor: zoom-out;
}
.lightbox.on { display: flex; }
.lightbox img { max-width: 100%; max-height: 100%; border-radius: 8px; box-shadow: 0 18px 48px rgba(0,0,0,.5); background: #fff; }
.lightbox .lb-close {
  position: absolute; top: 16px; right: 20px; width: 38px; height: 38px; border-radius: 50%;
  border: none; background: rgba(255,255,255,.15); color: #fff; font-size: 22px; cursor: pointer;
}
.lightbox .lb-close:hover { background: rgba(255,255,255,.3); }

.stat-line { display: flex; justify-content: space-between; padding: 6px 0; border-bottom: 1px dashed var(--border); font-size: 13.3px; }
.stat-line:last-child { border-bottom: 0; }
/* Группы строк в карточке (v3.26.2).
   Полоса под каждой строкой разбивает список на десять равных кусков и
   ничего не говорит. Заказчик попросил порядка: делим по смыслу — документ,
   что ждём, что пришло, что осталось. Внутри группы разделителя нет,
   между группами — сплошная полоса. */
.stat-group .stat-line { border-bottom: 0; }
.stat-group { padding: 4px 0; border-bottom: 1px solid var(--border); }
.stat-group:first-child { padding-top: 0; }
.stat-group:last-child { border-bottom: 0; padding-bottom: 0; }
/* Значение записи журнала целиком (v3.18): длинный текст переносится,
   но остаётся выделяемым — его копируют, чтобы восстановить удалённое */
.audit-val { margin: 4px 0 0; padding: 8px 10px; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--radius);
  font-family: inherit; font-size: 13px; line-height: 1.5;
  white-space: pre-wrap; overflow-wrap: anywhere; max-height: 220px; overflow-y: auto; }
.stat-line .v { font-weight: 600; font-variant-numeric: tabular-nums; }
/* Длинное значение не наезжает на подпись (v6.155.0, проверка 3, Э-6): значок
   «Товар в пути — срок оплаты не начался» не переносился и перекрывал слово
   «Статус». Теперь значение переносится справа и в подпись не заходит. */
.stat-line { gap: 12px; }
.stat-line > span:first-child { min-width: 0; }
.stat-line .v { min-width: 0; text-align: right; }
.stat-line .v .badge { white-space: normal; text-align: left; }

.toolbar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 12px; }
.toolbar .spacer { flex: 1 1 auto; }

.divider { height: 1px; background: var(--border); margin: 16px 0; }

.link-muted { color: var(--muted); }
.link-muted:hover { color: var(--accent); }

.mobile-only { display: none; }
.desktop-only { display: initial; }
/* Значок «Мои задачи» в верхней панели — ссылка с классом `desktop-only`
   (v6.14.13): правило выше возвращало ей `display: initial`, то есть
   строчный вид, и галочка вставала выше соседей. Заказчик: «галочка криво
   сидит». Кнопка-значок остаётся сеткой с центровкой, чем бы её ни прятали. */
.icon-btn.desktop-only { display: grid; }

/* Нижнее меню на мобильных (§127) */
.mobile-bar {
  position: fixed; bottom: 0; left: 0; right: 0; height: 58px;
  background: var(--surface); border-top: 1px solid var(--border);
  display: none; z-index: 90; padding-bottom: env(safe-area-inset-bottom);
}
.mobile-bar a {
  flex: 1 1 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  color: var(--muted); font-size: 10.5px; font-weight: 550;
}
.mobile-bar a.active { color: var(--accent); }
.mobile-bar a:hover { text-decoration: none; }

.sheet-backdrop { position: fixed; inset: 0; background: rgba(16,21,28,.4); z-index: 100; display: none; }
.sheet-backdrop.open { display: block; }
.sheet {
  position: fixed; bottom: 0; left: 0; right: 0; max-height: 82vh; overflow-y: auto;
  background: var(--surface); border-radius: 16px 16px 0 0; z-index: 110;
  transform: translateY(100%); transition: transform .2s ease; padding-bottom: 20px;
}
.sheet.open { transform: none; }
.sheet-handle { width: 38px; height: 4px; border-radius: 3px; background: var(--border-strong); margin: 9px auto; }

/* Мобильная сборка заказа (§56) */
.pick-card { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px; margin-bottom: 10px; background: var(--surface); }
.pick-card.done { background: var(--green-soft); border-color: #bfe6d3; }
.pick-card .pc-head { display: flex; gap: 10px; align-items: flex-start; }
.pick-card .pc-qty { font-size: 19px; font-weight: 650; }

@media (max-width: 1100px) {
  .grid-4, .grid-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Табличные блоки не должны растягивать сетку шире экрана */
.grid > * { min-width: 0; }
.card { min-width: 0; }

@media (max-width: 860px) {
  .sidebar { position: fixed; left: 0; top: 0; bottom: 0; transform: translateX(-100%); transition: transform .2s ease; box-shadow: var(--shadow-3); }
  body.nav-open .sidebar { transform: none; }
  body.nav-open::after { content: ''; position: fixed; inset: 0; background: rgba(16,21,28,.4); z-index: 35; }
  /* Боковое поле на телефоне 12 → 16 точек (v6.49.0, предложение 159):
     контент упирался в самый край экрана и читался теснее, чем таблицы
     внутри него, у которых свой отступ больше. */
  .content { padding: 16px 16px 84px; }
  .grid-2, .grid-3, .grid-4, .grid-5 { grid-template-columns: minmax(0, 1fr); }
  .card, .kpi, .table-wrap { min-width: 0; }
  /* На телефоне ряды кнопок и подсказок переносятся, а не растягивают страницу
     (v3.21, AUD4-006). Проверено на шести экранах, где полоса появлялась:
     правка заказа, копия заказа, приход, аналитика по единицам, настройки,
     создание набора. */
  .flex, .flex-between, .card-foot, .card-head, .filters, .btn-group, .row-actions { flex-wrap: wrap; }
  .btn, .btn-sm { max-width: 100%; }
  .card-body > table, .card-body > form > table { display: block; overflow-x: auto; }
  .form-grid.cols-2 { grid-template-columns: 1fr; }
  .field.span-2 { grid-column: auto; }
  .mobile-bar { display: flex; }
  .mobile-only { display: initial; }
  .desktop-only { display: none !important; }
  .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kpi .kpi-value { font-size: 18px; }
  .topbar { padding: 0 10px; gap: 8px; }
  .user-chip { padding: 4px; }
  .page-head h1 { font-size: 18px; }
  .flash-area { left: 12px; right: 12px; max-width: none; top: 62px; }
  .hbar .hbar-name { width: 110px; }
  .hbar .hbar-val { width: 84px; font-size: 11.5px; }
  table.data th, table.data td { padding: 8px 9px; }
}

@media (max-width: 480px) {
  /* Плитки по две даже на узком экране (v6.51.0): одна в ряд — это
     четыре экрана прокрутки до списка, ради которого страницу и открыли.
     Числа при этом остаются читаемыми: проверено на 390 точках. */
  .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .kpi { padding: 10px 11px; }
  .kpi .kpi-value { font-size: 17px; }
  .kpi .kpi-label { font-size: 11px; }
}

/* ======================================================================
   ТАБЛИЦЫ НА ТЕЛЕФОНЕ — КАРТОЧКАМИ, А НЕ ПРОКРУТКОЙ ВБОК (v6.51.0)

   Слово заказчика: «ERP должно работать на телефоне превосходно, как
   приложение, только через веб».

   ЧТО БЫЛО. Таблица на 390 точках либо сжималась до нечитаемого, либо
   ехала вбок внутри своей обёртки. Человек видел два столбца из десяти и
   возил страницу пальцем туда-сюда, теряя, к какой строке относится
   число. На складе и в дороге — это не работа.

   КАК ТЕПЕРЬ. Каждая строка становится карточкой: первая ячейка —
   заголовком, остальные — парами «подпись: значение». Подписи берутся из
   шапки таблицы скриптом (`initMobileTables`), поэтому правило работает
   на ВСЕХ таблицах системы разом, а не на тех, которые кто-то вспомнил
   переделать. Пустые ячейки («—») в карточку не попадают: на телефоне
   каждая строка дорога.

   Колонка действий уходит вниз карточки одной полосой — по ней и
   попадают пальцем.
   ====================================================================== */
@media (max-width: 760px) {
  .table-wrap.as-cards { overflow: visible; }
  .table-wrap.as-cards table.data,
  .table-wrap.as-cards table.data tbody,
  .table-wrap.as-cards table.data tr,
  .table-wrap.as-cards table.data td { display: block; width: auto; }
  .table-wrap.as-cards table.data thead { display: none; }

  .table-wrap.as-cards table.data tr {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); padding: 12px 14px; margin: 0 0 10px;
  }
  .table-wrap.as-cards table.data tr:hover { background: var(--surface); }

  .table-wrap.as-cards table.data td {
    padding: 3px 0; border: 0; text-align: left !important; white-space: normal;
    display: flex; align-items: baseline; gap: 10px; justify-content: space-between;
    flex-wrap: wrap; min-width: 0;
  }
  /* Содержимое ячейки не должно распирать карточку: внутри бывают полоски,
     значки и длинные названия. Ширину задаёт экран, а не содержимое. */
  .table-wrap.as-cards table.data td > * { min-width: 0; max-width: 100%; }
  /* Первая ячейка — заголовок карточки: крупно, во всю ширину, без подписи. */
  .table-wrap.as-cards table.data td:first-child {
    display: block; font-size: 15.5px; font-weight: 650; margin-bottom: 6px;
    padding-bottom: 6px; border-bottom: 1px solid var(--border);
  }
  .table-wrap.as-cards table.data td:first-child::before { content: none; }
  .table-wrap.as-cards table.data td::before {
    content: attr(data-label); color: var(--muted); font-size: 12.5px;
    flex: 0 1 auto; min-width: 0; max-width: 46%;
  }
  .table-wrap.as-cards table.data td.num { font-variant-numeric: tabular-nums; }
  /* Пустая ячейка не занимает строку. */
  .table-wrap.as-cards table.data td[data-empty="1"] { display: none; }
  /* Столбец, в котором во всех строках одно и то же, на телефоне скрыт:
     см. markSameColumns() в app.js. */
  .table-wrap.as-cards table.data td[data-same="1"] { display: none; }

  .table-wrap.as-cards table.data td.col-actions {
    display: flex; justify-content: flex-start; gap: 8px; flex-wrap: wrap;
    margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border);
  }
  .table-wrap.as-cards table.data td.col-actions::before { content: none; }
  .table-wrap.as-cards table.data td.col-actions .btn,
  .table-wrap.as-cards table.data td.col-actions .icon-btn { min-height: 38px; }

  /* Подвал таблицы (итоги) остаётся таблицей: это не список, а сумма
     (см. комментарий выше). НО (v6.65.0, найдено проверкой мобильной
     версии): `.table-wrap.as-cards` выше по файлу снимает overflow
     (`overflow: visible`) — карточкам скролл ни к чему, а вот строка
     итогов с 6+ колонками цифр (зарплата, дебиторка, накладные…) при этом
     осталась широкой настоящей таблицей и просто вылезала за правый край
     экрана: ни обрезки, ни прокрутки — цифры было не увидеть и не долистать.
     Даём подвалу СВОЙ скролл, не трогая overflow всей обёртки: строка
     остаётся таблицей (сумма читается как сумма), но теперь в собственной
     рамке со скроллом, если не помещается. */
  .table-wrap.as-cards table.data tfoot {
    display: block; overflow-x: auto; -webkit-overflow-scrolling: touch;
    margin-top: 10px; border: 1px solid var(--border); border-radius: var(--radius);
  }
  .table-wrap.as-cards table.data tfoot tr { display: table; width: 100%; table-layout: auto; }
  .table-wrap.as-cards table.data tfoot th {
    display: table-cell; white-space: nowrap; text-align: left;
    border-bottom: 0; padding: 9px 12px;
  }

  /* На телефоне мелкий служебный текст поднимаем до читаемого. */
  .xs { font-size: 12.5px; }
  table.data .small, table.data .xs { font-size: 12.5px; }

  /* Кнопка «Фильтры» и свёрнутый блок отбора (см. initMobileFilters). */
  .mob-filters-btn { display: inline-flex; align-items: center; gap: 7px; margin-bottom: 10px; min-height: 40px; }
  .mob-filters-n {
    background: var(--accent); color: #fff; border-radius: 9px;
    min-width: 18px; height: 18px; padding: 0 5px; font-size: 11.5px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .filters.mob-folded { display: none; }

  /* Шапка страницы: на телефоне это три экрана до дела. Убираем лишний
     воздух, оставляя заголовок и пояснение читаемыми (v6.51.0). */
  .breadcrumbs { font-size: 12px; margin-bottom: 4px; }
  .page-head { margin-bottom: 12px; }
  .page-head .page-sub, .page-head p.muted { font-size: 13px; }

  /* Кнопки страницы на телефоне: сеткой по две, а не лесенкой (v6.51.0).
     Раньше они прижимались вправо и переносились по одной — получалась
     лестница из трёх строк, в которой главная кнопка терялась. Теперь
     главное действие стоит первым и во всю ширину: так его и находят
     большим пальцем. */
  .page-actions {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px; width: 100%; margin-left: 0;
  }
  .page-actions .btn { width: 100%; justify-content: center; min-height: 42px; }
  .page-actions .btn-primary { grid-column: 1 / -1; order: -1; }

  /* Вкладки на телефоне — в одну строку со скроллом, а не в три тесных
     ряда (v6.65.0). На широком экране правило чуть выше («переносятся на
     вторую строку») остаётся как было — там перенос на 1–2 строки не
     мешает; на телефоне 6–8 вкладок переносились в 3 ряда мелких кнопок,
     в которые легко промахнуться пальцем. Тень с края — см. data-scroll-hint
     выше, вешает её app.js сам. */
  .tabs {
    flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; margin-bottom: 14px;
  }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs a, .tabs .tab-off { flex: 0 0 auto; }
}

/* Кнопка «Фильтры» существует только на телефоне: на широком экране блок
   отбора виден весь и прятать его не за чем. */
@media (min-width: 761px) { .mob-filters-btn { display: none; } }

/* =========================== Печать =========================== */

@media print {
  .sidebar, .topbar, .mobile-bar, .page-actions, .filters, .pagination, .flash-area, .no-print { display: none !important; }
  body, html { background: #fff; font-size: 11pt; }
  .content { padding: 0; max-width: none; }
  .card { border: 0; box-shadow: none; margin: 0; }
  .card-body { padding: 0; }
  a { color: #000; text-decoration: none; }
  table.data th, table.data td { border: 1px solid #999; padding: 4px 6px; }
  table.data thead th { background: #eee !important; -webkit-print-color-adjust: exact; }
  /* Бланк печатается строго на портретный A4: без явного size браузер
     берёт последнюю настройку принтера, и накладная уезжала «поперёк» (v2.2.1)

     ПОЛЯ ЛИСТА = 0, А ОТСТУП БЛАНКА ОТ КРАЯ ДАЁТ САМ БЛАНК (v6.110.5).
     Раньше поле листа было 12 мм (`@page margin: 12mm`). Именно в это поле
     браузер (Chrome, Firefox — любой) дорисовывает свои колонтитулы: адрес
     страницы сверху, дату, время и «1 of 1» снизу. Это не часть накладной,
     ЗВІРКА их не ставит — они появляются только при печати веб-страницы, и
     лезли в каждый бланк. Теперь поле листа 0 — браузеру некуда их писать,
     и они пропадают сами, без галочек в окне печати. Отступ от края листа,
     который раньше давало поле, теперь задаёт сам бланк своим внутренним
     полем (`padding: 12mm` ниже). Для одностраничного бланка (накладная,
     счёт) результат на бумаге тот же, что и был, только без лишних меток.
     На документе в НЕСКОЛЬКО страниц у второй и дальше страниц сверху
     отступ будет меньше — если такое встретится, тот документ переведём в
     готовый PDF (там колонтитулов нет в принципе). */
  @page { size: A4 portrait; margin: 0; }
  .print-doc {
    max-width: none; width: auto;
    /* Отступ бланка от края листа задаётся ниже, в финальном блоке @media
       print (он стоит в файле последним и перебивает это правило). Здесь
       padding не трогаем, чтобы не плодить два источника одного отступа. */
    margin: 0; box-shadow: none; border-radius: 0;
  }
  .doc-form { width: 100%; }
}

/* Печатная форма документа */
/* Ширина листа — как у полосы набора A4 (210 мм минус поля), чтобы
   на экране было видно ровно то, что уйдёт на бумагу (v2.2.1) */
.print-doc {
  background: #fff; padding: 12.7mm 12mm; width: 210mm; max-width: 100%;
  margin: 0 auto; font-size: 13px; box-shadow: var(--shadow-1); border-radius: 2px;
}
.print-doc h1 { font-size: 17px; text-align: center; margin-bottom: 4px; }
.print-doc .doc-sub { text-align: center; color: var(--text-2); margin-bottom: 18px; }
.print-doc .parties { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; margin-bottom: 16px; }
.print-doc .party-title { font-size: 11.5px; text-transform: uppercase; color: var(--muted); letter-spacing: .04em; margin-bottom: 4px; }
.print-doc table { width: 100%; border-collapse: collapse; font-size: 12px; }
.print-doc table th, .print-doc table td { border: 1px solid #b8c0ca; padding: 5px 7px; }
.print-doc table th { background: #f1f3f6; font-weight: 600; text-align: center; }
.print-doc .sign-row { display: flex; justify-content: space-between; margin-top: 34px; gap: 30px; }
.print-doc .sign-box { flex: 1; }
.print-doc .sign-line { border-bottom: 1px solid #333; height: 26px; margin-bottom: 4px; }

/* ==================================================================
   ПЕЧАТНЫЕ ФОРМЫ: РАХУНОК-ФАКТУРА И ВИДАТКОВА НАКЛАДНА (v6.53.6)

   СВЁРСТАНО ПО ОБРАЗЦАМ ЗАКАЗЧИКА, ОБМЕРЕННЫМ, А НЕ СРИСОВАННЫМ НА ГЛАЗ.
   Он прислал свои накладную и счёт из прежней системы (OneBox) и потребовал
   полного совпадения: «размеры, разметка, цвета, ширина, шрифты». Прежняя
   наша форма была похожа лишь в общих чертах — другой шрифт, другой кегль,
   вдвое выше строки таблицы, нет заливки шапки, нет колонки штрихкода.

   Числа ниже взяты измерением PDF-образцов (pdfplumber), в пунктах:
     лист A4 595×842; поля слева и справа 34.5 pt (12 мм), сверху 36 pt;
     полоса набора 525.7 pt;
     шрифт Times New Roman: основной 9.6 pt, мелкий 8.4 pt, сноска 7.2 pt,
     заголовок накладной 13.2 pt (заголовок счёта — 8.4 pt, он мельче);
     колонка подписей в шапке 87 pt;
     строка блока поставщика 11.4 pt, прочие строки шапки 13.7 pt;
     строка таблицы 13.2 pt, шапка таблицы залита #E4E0E5;
     колонки счёта:     6.2 / 50.1 / 6.2 / 12.5 / 12.5 / 12.6 %
     колонки накладной: 5.4 / 43.8 / 12.7 / 5.4 / 10.9 / 11.0 / 11.0 %

   В CSS они переведены в пиксели (1 pt = 1.333 px), потому что браузер
   печатает по пикселям. МЕНЯЯ ЧТО-ЛИБО ЗДЕСЬ, СВЕРЯЙТЕСЬ С ОБРАЗЦАМИ:
   эти бумаги уходят клиентам и в бухгалтерию.
   ================================================================== */
.doc-form {
  font-family: "Times New Roman", "Liberation Serif", Times, serif;
  color: #000; font-size: 12.8px; line-height: 1.19;
}
.doc-form table { width: 100%; border-collapse: collapse; }

/* --- Шапка: рамок нет, подписи слева жирные с подчёркиванием --- */
.doc-form .hdr { margin: 0 0 6px; border: none; }
.doc-form .hdr td { border: none; padding: 0; vertical-align: top; line-height: 15.2px; }
.doc-form .hdr td.lbl {
  width: 116px; font-weight: 700; text-decoration: underline;
  white-space: nowrap; padding-right: 8px;
}
.doc-form .hdr tr.spacer td { height: 18px; padding: 0; line-height: 0; }
.doc-form .hdr .supplier { font-weight: 700; }
/* Строки «Одержувач … Умова продажу» стоят просторнее строк блока
   поставщика: в образце 13.7 pt против 11.4 pt. */
.doc-form .hdr tr.wide td { line-height: 18.3px; }

/* --- Заголовок документа --- */
/* У накладной он крупный (13.2 pt), у счёта — мелкий (8.4 pt) и в две
   строки: «Рахунок-фактура № …» и отдельной строкой дата. Так в образце. */
.doc-form .doc-title { text-align: center; font-weight: 700; font-size: 17.6px; margin: 17px 0 0; }
.doc-form .doc-title.sm { font-size: 11.2px; margin: 39px 0 0; }
.doc-form .doc-date { text-align: center; font-weight: 700; font-size: 11.2px; margin: 4px 0 0; }

/* --- Таблица товаров --- */
.doc-form .goods { border: none; margin-top: 24px; }
.doc-form .goods.tight { margin-top: 18px; }
.doc-form .goods th, .doc-form .goods td {
  border: 1px solid #000; padding: 1px 4px; font-size: 12.8px; line-height: 15px;
}
.doc-form .goods th {
  font-weight: 700; text-align: center; vertical-align: middle;
  background: #E4E0E5; -webkit-print-color-adjust: exact; print-color-adjust: exact;
}
.doc-form .goods td { vertical-align: top; }
/* Шапка счёта в образце — одна строка высотой 13.2 pt; шапка накладной две
   (там колонок больше и они уже). Поэтому перенос запрещён только в счёте. */
.doc-form .goods.tight th { white-space: nowrap; padding-left: 1px; padding-right: 1px; }
.doc-form .goods td.no { text-align: right; }
.doc-form .goods td.n { text-align: right; white-space: nowrap; }
.doc-form .goods td.c { text-align: center; }
/* Итоги: подпись без рамки справа, значение — в рамке, как в образце */
.doc-form .goods tr.sum td { border: none; padding-top: 0; }
.doc-form .goods tr.sum td.k { text-align: right; font-weight: 700; padding-right: 8px; white-space: nowrap; }
.doc-form .goods tr.sum td.v { border: 1px solid #000; text-align: right; font-weight: 700; }

/* --- Под таблицей --- */
.doc-form .after { margin-top: 9px; line-height: 15px; }
.doc-form .after.sm { font-size: 11.2px; line-height: 14.5px; }
.doc-form .after b { font-weight: 700; }
.doc-form .uktzed { font-weight: 700; margin-top: 18px; }
/* Счёт теперь тоже печатает код УКТЗЕД (v6.91.0, п. «е») — тем же мельче
   текстом, что и остальной низ счёта (.after.sm), а не размером накладной. */
.doc-form .uktzed.sm { font-size: 11.2px; }

/* --- Подписи --- */
.doc-form .place { margin: 24px 0 0 76px; }
.doc-form .signs, .doc-form .signs tr, .doc-form .signs td { border: none !important; }
.doc-form .signs { margin-top: 33px; }
.doc-form .signs td { padding: 0; vertical-align: top; font-size: 12.8px; line-height: 15px; }
.doc-form .sig-line { display: inline-block; min-width: 176px; border-bottom: 1px solid #000; height: 13px; }
.doc-form .sig-left { padding-left: 63px; }
.doc-form .sig-name { text-align: center; margin-top: 21px; padding-left: 100px; padding-right: 40px; white-space: nowrap; }
.doc-form .sig-sub { margin-top: 4px; padding-left: 8px; }
.doc-form .star { vertical-align: super; font-size: 9px; }
.doc-form .sign-invoice { margin-top: 54px; text-align: left; padding-left: 449px; font-size: 12.8px; }
.doc-form .note { font-size: 9.6px; margin-top: 22px; }

/* ==================================================================
   БЛАНК НА БУМАГЕ: БЕЗ ТЕНИ И БЕЗ ДВОЙНЫХ ПОЛЕЙ (v6.53.7)

   Заказчик прислал снимок окна печати с тонкой серой чертой во всю ширину
   листа ниже подписи и спросил, что это. Это тень «листа»: на экране бланк
   показан белой карточкой с мягкой тенью, чтобы было видно край бумаги.
   Отменять тень на печати правило выше (`@media print`) пыталось, но стояло
   в файле ВЫШЕ обычного `.print-doc`, а при равной силе побеждает то, что
   ниже. Тень возвращалась, и низ карточки печатался полоской. Поэтому все
   «экранные» свойства листа снимаются здесь, в конце файла, где их уже
   некому перебить.

   Вторая половина того же — поля. С версии 6.110.5 поле листа (`@page`)
   сделали нулевым, чтобы браузер не дорисовывал свои колонтитулы (адрес
   страницы, дату, время, номер листа) в поле. Поэтому весь отступ бланка
   от края листа теперь задаётся ЗДЕСЬ, в последнем правиле печати: сверху
   12.7 мм (как в обмеренном образце заказчика), по бокам и снизу 12 мм. */
@media print {
  .print-doc {
    box-shadow: none; border-radius: 0; background: #fff;
    width: auto; max-width: none; margin: 0;
    /* Поле листа @page = 0, весь отступ даёт бланк сам (v6.110.5). */
    padding: 12.7mm 12mm 12mm;
  }
}

/* Наценка в прайс-листе — выделенная колонка, её смотрят чаще остальных (v1.8) */
table.data th.markup-col,
table.data td.markup-col {
  font-weight: 700;
  background: var(--surface-3);
  border-left: 2px solid var(--border-strong);
}
table.data td.markup-col.pos { color: var(--green, #1a7f37); }
table.data td.markup-col.neg { color: var(--red, #c0392b); }

/* Карточка товара: основные поля слева, фото справа (v1.9) */
.form-split { display: flex; gap: 22px; align-items: flex-start; }
.form-split-main { flex: 1 1 auto; min-width: 0; }
.form-split-aside { flex: 0 0 220px; }
.form-split-aside > label { display: block; font-size: 12.5px; color: var(--muted); margin-bottom: 6px; }
.photo-box {
  width: 220px; height: 220px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--surface-2); display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.photo-box img { max-width: 100%; max-height: 100%; object-fit: contain; }
.photo-ph { text-align: center; color: var(--muted); }
@media (max-width: 900px) {
  .form-split { flex-direction: column; }
  .form-split-aside { flex: 1 1 auto; width: 100%; }
  .photo-box { width: 100%; max-width: 260px; }
}
.warn-text { color: var(--amber, #b26a00); }

/* Полоска настроек раздела (справочники товара) — v1.9 */
.subnav {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  margin: -6px 0 16px; padding: 8px 12px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px;
}
.subnav-label { font-size: 12.5px; color: var(--muted); margin-right: 4px; }
.subnav a {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 10px; border-radius: 6px; font-size: 13px;
  color: var(--text); background: var(--surface); border: 1px solid var(--border);
}
.subnav a:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }

/* Выпадающий список с поиском (v1.9) */
.combo { position: relative; }
.combo .combo-native { position: absolute; opacity: 0; pointer-events: none; height: 0; width: 0; }
.combo-input { width: 100%; }
.combo-list {
  position: absolute; z-index: 60; left: 0; right: 0; top: 100%; margin-top: 3px;
  max-height: 280px; overflow-y: auto;
  /* Поле фильтра узкое, а названия клиентов длинные: разрешаем списку быть
     шире поля, иначе каждый пункт переносится на две строки (v2.6) */
  min-width: 260px; width: max-content; max-width: 380px;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: 8px; box-shadow: 0 10px 26px rgba(0,0,0,.14);
}
.combo-item { padding: 7px 11px; font-size: 13.2px; cursor: pointer; }
.combo-item:hover, .combo-item.on { background: var(--surface-2); }
.combo-item.sel { font-weight: 650; }
.combo-empty { padding: 11px; font-size: 13px; color: var(--muted); }

/* Мультивыбор с галочками (v2.5) */
.combo-check { display: flex; align-items: center; gap: 9px; margin: 0; }
.combo-check input { width: 15px; height: 15px; margin: 0; flex: 0 0 auto; }
.combo-check span { flex: 1 1 auto; min-width: 0; }
.combo-clear {
  border-bottom: 1px solid var(--border);
  color: var(--muted); font-size: 12.5px;
}
.combo-clear:hover { color: var(--red); }

/* Промежуточный итог внутри отчёта: жирнее строк, но не как ИТОГО (v3.16) */
table.data tr.sub-total td { font-weight: 650; border-top: 1px solid var(--border-strong); }

/* Разделитель-подзаголовок внутри таблицы: «Покупали / Не покупали» (v3.16) */
table.data tr.row-group td {
  background: var(--surface-3); color: var(--text-2);
  font-size: 11.5px; font-weight: 650; letter-spacing: .03em; text-transform: uppercase;
  padding: 5px 9px;
}
table.data tr.row-group:hover td { background: var(--surface-3); }

/* Заголовок раздела в мультивыборе: нажатие отмечает весь раздел (v3.16) */
.combo-group {
  position: sticky; top: 0; z-index: 1;
  padding: 6px 11px 5px;
  background: var(--surface-3); color: var(--text-2);
  font-size: 11.5px; font-weight: 650; letter-spacing: .03em; text-transform: uppercase;
  cursor: pointer; user-select: none;
}
.combo-group:hover { background: var(--accent-soft); color: var(--accent-dark); }

/* Многолинейный SVG-график аналитики (v1.9) */
.chart-multi { width: 100%; }
.chart-svg { width: 100%; height: auto; display: block; overflow: visible; }
.chart-legend { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 10px; font-size: 12.8px; }
.cl-item { display: inline-flex; align-items: center; gap: 6px; color: var(--text); }
.cl-item i { width: 12px; height: 12px; border-radius: 3px; display: inline-block; }
.af-cmp-pair { display: flex; gap: 6px; }
table.data td .sub-d { display: block; font-size: 11.5px; line-height: 1.3; font-weight: 400; }   /* «Изменение» гривнами под процентом (v6.144.1) */   /* «Сравнить с → свои даты» (v6.144.1) */
/* Пунктир периода сравнения в легенде (v6.144.1, макет 179) */
.cl-item i.cl-dash { width: 20px; height: 0; border-radius: 0; background: none; border-top: 2px dashed var(--muted); vertical-align: middle; }
.cl-cmp { color: var(--muted); }
.cl-item small { font-size: 11px; }
.cg-line { stroke: var(--border); stroke-width: 1; }
.cg-axis { stroke: var(--border-strong); stroke-width: 1.2; }
.cg-tick { font-size: var(--cg-fs, 11px); fill: var(--muted); }
.cg-xlab { font-size: var(--cg-fs, 11px); fill: var(--muted); }

/* Вкладки настроек (v3.24, UX-035).
   Прячем только когда скрипт пометил форму: без него все разделы видны
   сразу, и страница остаётся такой, какой была. */
form.paned .settings-pane { display: none; }
form.paned .settings-pane.on { display: block; }

/* Подсказка на графиках аналитики (v3.23) */
.chart-multi, .chart-pie { position: relative; }
.cg-hair { stroke: var(--text); stroke-width: 1; opacity: .28; vector-effect: non-scaling-stroke; }
.cg-hit { cursor: crosshair; }
.cg-tip {
  position: absolute; z-index: 30; pointer-events: none;
  min-width: 180px; max-width: 320px; padding: 9px 11px;
  background: var(--surface); color: var(--muted);
  border: 1px solid var(--border-strong); border-radius: 8px;
  box-shadow: 0 6px 20px rgba(15, 23, 42, .16);
  font-size: 12.5px; line-height: 1.5;
  opacity: 0; transform: translateY(3px); transition: opacity .12s ease, transform .12s ease;
}
.cg-tip.on { opacity: 1; transform: none; }
.cg-tip .mt-name {
  display: flex; align-items: center; gap: 7px;
  color: var(--text); font-weight: 650; margin-bottom: 5px;
}
.cg-tip .mt-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.cg-tip .mt-row { display: flex; justify-content: space-between; gap: 14px; padding: 2px 0; }
.cg-tip .mt-row span { display: inline-flex; align-items: center; gap: 7px; }
.cg-tip .mt-row b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }

/* Круговая диаграмма долей */
.chart-pie { display: flex; gap: 22px; align-items: center; flex-wrap: wrap; }
.chart-pie svg { width: 180px; height: 180px; flex: none; }   /* меньше (v6.144.0) */
.pie-slice { cursor: pointer; transition: opacity .12s ease; transform-origin: 50% 50%; }
/* ГАСНУТ ОСТАЛЬНЫЕ, А НЕ ВСЁ КОЛЬЦО (v6.25.0, слово заказчика: «должно быть
   как на главной: подношу стрелку к какой-то части — выскакивает подсказка по
   этой доле, цвет выделяется, а остальное гаснет; сейчас гаснет сразу всё
   кольцо»).
   Он прав, и обе прежние попытки были мимо. Правило висело на блоке
   (`.chart-pie:hover`) — гасло от наведения на подписи; потом на `svg:hover` —
   гасло от наведения на пустое место внутри рисунка, то есть почти всегда.
   Теперь гасит САМ СЕКТОР: пока курсор на секторе, у блока стоит признак
   `.picking`, и приглушаются все, кроме помеченного `.on`. Наведение на
   подпись работает так же — она указывает на свой сектор. */
.chart-pie.picking .pie-slice { opacity: .35; }
.chart-pie.picking .pie-slice.on { opacity: 1; }
.chart-pie.picking .pl-item { opacity: .45; }
.chart-pie.picking .pl-item.on { opacity: 1; }
.pie-legend { display: flex; flex-direction: column; gap: 5px; min-width: 0; flex: 1 1 240px; max-width: 420px; font-size: 13px; }
/* Подписи ПОД кольцом и во всю ширину (v6.24.3): длинные названия товаров в
   узкой колонке сбоку обрывались многоточием — читать было нечего. */
/* ПОДПИСИ ПОД КОЛЬЦОМ — РОВНОЙ СЕТКОЙ (v6.25.0, слово заказчика: «некрасивый
   разброс моделей по блоку, сделай красиво»).
   Прежняя сетка `auto-fill minmax(280px, 1fr)` растягивала колонки по всей
   ширине экрана: у коротких названий цифра улетала к правому краю, у длинных
   жалась к тексту, и строки не выстраивались ни по левому краю, ни по
   правому. Теперь каждая подпись — карточка равной ширины со своим фоном:
   кружок, название, значение и доля стоят в одних и тех же местах, а доля
   выровнена по правому краю карточки, а не по краю экрана. */
.chart-pie.stacked { flex-direction: column; align-items: stretch; gap: 16px; }
.chart-pie.stacked svg { align-self: center; }
.chart-pie.stacked .pie-legend {
  max-width: none; flex: 1 1 auto;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 8px;
}
.chart-pie.stacked .pl-item {
  padding: 7px 10px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface-2); gap: 9px; transition: opacity .12s ease;
}
.chart-pie.stacked .pl-item .pl-val {
  font-variant-numeric: tabular-nums; text-align: right; flex: 0 0 auto;
}
.pie-legend .pl-item { display: flex; align-items: center; gap: 8px; min-width: 0; }
.pie-legend .pl-item i { width: 11px; height: 11px; border-radius: 3px; flex: none; }
/* Тот же кружок, но в таблице рядом со строкой: он связывает строку с
   сектором кольца — без него взгляд не находит соответствие (v3.28) */
.pl-dot { display: inline-block; width: 10px; height: 10px; border-radius: 3px;
          margin-right: 7px; vertical-align: baseline; }
.pie-legend .pl-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pie-legend .pl-val { margin-left: auto; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 640px) { .chart-pie svg { width: 190px; height: 190px; } }
@media (prefers-reduced-motion: reduce) { .cg-tip, .pie-slice { transition: none; } }

/* Мини-график в строке таблицы */
.spark { display: block; width: 110px; height: 26px; }
.spark path { fill: none; stroke-width: 1.8; }

/* `.is-invalid` объявлен один раз, ниже по файлу, вместе с `.invalid-note`
   (v6.58.0). Было два объявления в разных местах — одно с фоном, другое с
   рамкой и свечением; вид поля собирался из обоих, и чтобы его поменять,
   надо было помнить про оба. */

/* Водопад «из чего сложилась прибыль» (v1.9) */
.waterfall { display: flex; flex-direction: column; gap: 7px; }
.wf-row { display: grid; grid-template-columns: 190px 1fr 130px 68px; gap: 12px; align-items: center; }
.wf-name { font-size: 13px; color: var(--text); }
.wf-bar { height: 20px; background: var(--surface-2); border-radius: 4px; overflow: hidden; }
.wf-fill { height: 100%; border-radius: 4px; }
.wf-blue { background: #2563eb; } .wf-red { background: #dc2626; }
.wf-green { background: #16a34a; } .wf-amber { background: #f59e0b; }
.wf-violet { background: #7c3aed; }
.wf-val { text-align: right; font-variant-numeric: tabular-nums; font-weight: 650; font-size: 13px; }
.wf-pct { text-align: right; font-size: 12px; }
@media (max-width: 760px) {
  .wf-row { grid-template-columns: 120px 1fr 96px; }
  .wf-pct { display: none; }
}
.reserved-link { font-weight: 650; color: var(--amber, #b26a00); border-bottom: 1px dashed currentColor; }
.reserved-link:hover { text-decoration: none; opacity: .8; }

/* Подпись второй строкой в заголовке столбца (v2.1) */
table.data th .th-sub {
  display: block; font-weight: 500; text-transform: none;
  letter-spacing: 0; opacity: .65; font-size: 10.5px;
}
/* Заголовки садятся на общую нижнюю линию (v6.13.7): у колонки с подписью
   в две строки шапка выше соседних, и без этого однострочные названия
   висели по центру, а двухстрочное выступало. */
table.data thead th { vertical-align: bottom; }
/* Подпись в ТУ ЖЕ строку (v6.13.8). «Цена закупки с НДС» на экране поставки
   должна читаться одной строкой: второй строкой она поднимала название над
   соседними колонками, и вся шапка выглядела ступеньками. */
table.data th .th-sub.th-inline { display: inline; margin-left: 5px; }
table.data th.th-1line { white-space: nowrap; }
/* Ровная шапка по верхней линии (v6.35.0): на «Движениях по счёту» две
   колонки несут подпись второй строкой («Привязано / и остаток», «Остаток на
   счету / при отборе не считается»), причём вторая подпись переносится на две
   строки. При выравнивании по низу их названия вставали на разной высоте, и
   шапка читалась ступеньками. Верхняя линия ставит все названия ровно. */
table.data.th-top thead th { vertical-align: top; }

/* ================= Блок «Обрати внимание» на главной (v2.1) ================= */
/* flex:0 — иначе заголовок распирает шапку и счётчик прижимается вплотную
   к подписи «обновлено», превращаясь в одну кашу (v2.6) */
.attention .card-head h2 { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
/* Подпись «обновлено N минут назад» + ручной пересчёт (v2.6) */
.att-fresh { margin-left: auto; display: flex; align-items: center; gap: 5px; }
.att-fresh .att-refresh {
  display: grid; place-items: center; width: 22px; height: 22px;
  padding: 0; border: 0; border-radius: 6px; cursor: pointer;
  background: transparent; color: var(--muted); transition: .14s;
}
.att-fresh .att-refresh:hover { background: var(--surface-2); color: var(--text); }
.att-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
.att {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 12px 13px; border-radius: 10px; border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text); transition: .14s;
}
.att:hover { text-decoration: none; border-color: var(--border-strong); transform: translateY(-1px); }
.att-ic { flex: none; width: 30px; height: 30px; border-radius: 8px; display: grid; place-items: center; }
.att-body { flex: 1; min-width: 0; }
.att-title { font-weight: 650; font-size: 13.4px; margin-bottom: 3px; }
.att-text { font-size: 12.4px; color: var(--text-2); line-height: 1.45; }
.att-go { flex: none; color: var(--muted); opacity: .7; margin-top: 4px; }
.att:hover .att-go { opacity: 1; }
.att-bad  { border-color: rgba(200,60,50,.32); background: rgba(200,60,50,.06); }
.att-bad .att-ic  { background: rgba(200,60,50,.14); color: var(--red); }
.att-warn { border-color: rgba(200,150,20,.34); background: rgba(200,150,20,.07); }
.att-warn .att-ic { background: rgba(200,150,20,.16); color: #a8760a; }
.att-info .att-ic { background: var(--surface-3); color: var(--text-2); }
/* Новый неотработанный (v6.139.0, макет 160) */
.att-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--red); box-shadow: 0 0 0 3px var(--red-soft); margin-left: 4px; vertical-align: 1px; }
.att-note { font-size: 12px; color: var(--red); font-weight: 600; margin-top: 3px; }
@media (max-width: 900px) { .att-grid { grid-template-columns: 1fr; } }

/* Постановка целей: показатель раскрывается только когда отмечен (v2.9.1) */
/* Выбор в строку: две-четыре короткие опции, которым не нужен целый ряд (v3.2) */
.choice-row { display: flex; gap: 8px; flex-wrap: wrap; }
.choice-row .check {
  padding: 7px 11px; border: 1px solid var(--border); border-radius: 9px;
  background: var(--surface-2); cursor: pointer;
}
.choice-row .check:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }

.choice-list { display: grid; gap: 9px; }
.choice-list .check { align-items: flex-start; padding: 9px 11px; border: 1px solid var(--border); border-radius: 9px; background: var(--surface-2); }
.choice-list .check input { margin-top: 2px; }
.metric-box {
  border: 1px solid var(--border); border-radius: 10px;
  padding: 11px 13px; margin-bottom: 10px; background: var(--surface-2); transition: .14s;
}
.metric-box:last-child { margin-bottom: 0; }
.metric-box > .check { align-items: flex-start; }
.metric-box > .check input { margin-top: 2px; }
.metric-box.on { border-color: var(--accent); background: var(--accent-soft); }
.metric-body { margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--border-strong); }
.metric-box.on .metric-body { background: var(--surface); padding: 12px 12px 4px; border-radius: 8px; border-top: 0; }

/* Подсказка на кольце «Продажи по менеджерам» (v3.0.1) */
.mgr-seg { transition: opacity .12s, stroke-width .12s; pointer-events: none; }
.mgr-hit { cursor: pointer; }
/* Мышь ловит одно кольцо на всю окружность (v6.9.4): у каждой доли своя дуга
   давала стык на двенадцати часах и мёртвые тонкие доли. */
.mgr-ring { cursor: pointer; }
.mgr-donut:has(.mgr-ring:hover) .mgr-seg { opacity: .5; }
.mgr-seg.hot, .mgr-donut:has(.mgr-ring:hover) .mgr-seg.hot { opacity: 1; stroke-width: 21; }
.mgr-row.hot > td { background: var(--surface-3); }
/* Окно смены менеджера: открытые долги и не отправленные заказы списком (v6.142.1, макет 171) */
.mgr-chg { margin: 16px 0 4px; display: grid; gap: 6px; }
.mgr-chg-h { font-size: 14px; font-weight: 700; margin: 10px 0 0; }
.mgr-chg-h:first-child { margin-top: 0; }
/* «Клиенты без менеджера» — последняя строка, отделена пунктиром (v6.142.1) */
.mgr-row-none > td { border-top: 1px dashed var(--border); }
.mgr-row-none > td:first-child { color: var(--muted); }
.chart-tip {
  position: fixed; z-index: 90; pointer-events: none;
  min-width: 216px; max-width: 280px;
  padding: 11px 13px;
  border-radius: 10px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  box-shadow: 0 10px 30px rgba(16,22,29,.16);
  font-size: 12.8px; color: var(--text-2);
  opacity: 0; transform: translateY(3px); transition: opacity .12s, transform .12s;
}
.chart-tip.on { opacity: 1; transform: none; }
/* ПОДСКАЗКА НА ОБРЕЗАННОМ ТЕКСТЕ (v6.58.0). Тот же вид, что у подсказок
   графиков, но по размеру — под одну строку: там внутри таблица чисел, здесь
   одно название. Нижняя граница ширины подсказке имени не нужна, верхняя
   нужна — иначе длинное название клиента растянется во весь экран. */
.cut-tip {
  min-width: 0; max-width: 420px;
  padding: 8px 11px; font-size: 13px; color: var(--text);
  line-height: 1.45; white-space: normal; overflow-wrap: anywhere;
}
.chart-tip .mt-name {
  display: flex; align-items: center; gap: 7px;
  font-weight: 650; font-size: 13.4px; color: var(--text);
  padding-bottom: 7px; margin-bottom: 7px; border-bottom: 1px solid var(--border);
}
.chart-tip .mt-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.chart-tip .mt-row { display: flex; justify-content: space-between; gap: 14px; padding: 2px 0; }
.chart-tip .mt-row b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) {
  .chart-tip, .mgr-seg { transition: none; }
}

/* Контактные лица клиента: строка-визитка в общем стиле карточек (v3.0.4) */
.person-list { display: flex; flex-direction: column; }
.person {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 11px 0; border-bottom: 1px solid var(--border);
}
.person:first-child { padding-top: 3px; }
.person:last-child { border-bottom: 0; padding-bottom: 3px; }
.person > .avatar { margin-top: 1px; }
.person-body { flex: 1; min-width: 0; }
.person-name {
  display: flex; flex-wrap: wrap; align-items: center; gap: 7px;
  font-weight: 640; font-size: 14.2px; line-height: 1.3;
}
.person-role { font-size: 12.4px; color: var(--muted); margin-top: 2px; }
.person-lines { display: flex; flex-direction: column; gap: 4px; margin-top: 5px; font-size: 13.2px; }
.person-lines a { overflow-wrap: anywhere; }
.person-actions { display: flex; gap: 1px; flex: none; opacity: 0; transition: opacity .12s; }
.person:hover .person-actions, .person:focus-within .person-actions { opacity: 1; }
.person-actions form { display: inline-flex; }
@media (hover: none) { .person-actions { opacity: 1; } }

/* Динамика продаж по месяцам: две дорожки с общей осью месяцев (v3.0.1) */
.ms-chart { display: flex; flex-direction: column; gap: 14px; --ms-gap: 4px; }
.ms-facet { display: flex; flex-direction: column; gap: 7px; }
.ms-facet-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.ms-title { display: inline-flex; align-items: center; gap: 7px; font-size: 12.8px; font-weight: 600; color: var(--text-2); }
.ms-key { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.ms-key.money { background: var(--accent); }
.ms-key.qty { background: var(--green); }
.ms-key.profit { background: var(--violet, #6d3ae0); }
.ms-max { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }

.ms-plot { position: relative; height: 190px; }
.ms-plot.short { height: 84px; }
.ms-grid { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: space-between; pointer-events: none; }
.ms-grid i { display: block; height: 1px; background: var(--border); opacity: .55; }
.ms-cols { position: absolute; inset: 0; display: flex; align-items: flex-end; gap: var(--ms-gap); }
.ms-col { flex: 1 1 0; min-width: 0; height: 100%; display: flex; align-items: flex-end; justify-content: center; cursor: pointer; }
.ms-bar {
  /* Ширину ограничиваем: за три месяца столбец в четверть экрана перестаёт
     читаться как график и выглядит заливкой (v3.0.1) */
  width: 100%; max-width: 54px; border-radius: 4px 4px 0 0;
  transition: opacity .12s, filter .12s;
}
.ms-bar.money { background: var(--accent); }
.ms-bar.qty { background: var(--green); }
.ms-bar.profit { background: var(--violet, #6d3ae0); }
.ms-chart:hover .ms-bar { opacity: .5; }
.ms-col.hot .ms-bar, .ms-chart:hover .ms-col.hot .ms-bar { opacity: 1; }

.ms-axis { display: flex; gap: var(--ms-gap); }
.ms-tick {
  flex: 1 1 0; min-width: 0; text-align: center; cursor: pointer;
  font-size: 11px; color: var(--muted); padding: 3px 0; border-radius: 5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ms-tick.hot { background: var(--surface-3); color: var(--text); font-weight: 600; }
@media (max-width: 720px) {
  .ms-plot { height: 132px; }
  .ms-tick { font-size: 10px; }
}
@media (prefers-reduced-motion: reduce) { .ms-bar { transition: none; } }

/* Значение, которое нельзя менять: номер документа выдаёт система (v3.0.3) */
.static-value {
  padding: 9px 11px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface-2); color: var(--text); font-size: 14px;
}

/* Контакты: иконка перед номером и почтой, чтобы строки читались с одного
   взгляда, а не сливались в две одинаковые синие ссылки (v3.1) */
/* Контакты человека: иконка — часть строки, а не ссылки; телефон просто
   текст, кликается только почта. Синий цвет ссылок в карточке смотрелся
   дёшево и спорил с остальным текстом (v3.4) */
.pl-row {
  display: grid; grid-template-columns: 16px 1fr; align-items: center;
  gap: 9px; color: var(--text-2); font-variant-numeric: tabular-nums;
}
.pl-row svg { width: 15px; height: 15px; color: var(--muted); flex: none; }
.pl-val { min-width: 0; overflow-wrap: anywhere; }
.pl-mail {
  color: var(--text-2); text-decoration: none; min-width: 0; overflow-wrap: anywhere;
  /* Подчёркивание по тексту, а не по всей ячейке — иначе линия тянется в пустоту */
  justify-self: start; border-bottom: 1px solid var(--border-strong);
}
.pl-mail:hover { color: var(--accent-dark); border-bottom-color: var(--accent); }

/* Контактные лица: список слева, карточка выбранного справа (v3.4.1).
   Сплошной колонкой пять человек занимали пол-экрана и читались тяжело. */
/* Карточке контактов нужно больше места, чем соседним спискам «подпись —
   значение»: внутри неё две колонки (v3.4.1) */
.ov-top { grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr) minmax(0, 1fr); }
@media (max-width: 1200px) { .ov-top { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 900px)  { .ov-top { grid-template-columns: minmax(0, 1fr); } }

/* Карточка контактов растягивается на всю высоту ряда, а серая колонка —
   на всю высоту карточки: раньше она обрывалась по своему содержимому
   и была сдвинута от края (v3.4.2) */
.card-pp { display: flex; flex-direction: column; }
.card-pp > .card-body { flex: 1; display: flex; padding: 0; }
/* Пусто — надпись ровно посередине карточки (v6.17.0, просьба заказчика) */
.card-pp > .card-body > .empty { flex: 1; }
/* НАСТОЯЩАЯ ПРИЧИНА тесноты в карточке «Контактные лица» на телефоне
   (найдено при 100%-проверке мобильной версии, 29.09.2026): `.card-body`
   здесь — строка `display:flex` без переноса, и когда у клиента заполнена
   заметка (`.small`), она встаёт РЯДОМ с блоком контактов, а не под ним —
   делит и без того узкую карточку (341px) пополам. Виджету контактов
   оставалось ~185px, а внутри него имя/телефон/email сжимались до 35-49px
   и переносились по одной букве в строку. `.divider` между ними — обычная
   горизонтальная черта (высота 1px), рассчитанная на разрыв СТРОК, а не на
   роль вертикальной линии между колонками — в строке без переноса она
   схлопывалась в невидимую полоску нулевой ширины. Перенос строки возвращает
   каждому блоку задуманную ширину и делает саму черту видимой между ними,
   как она и задумана. */
@media (max-width: 760px) {
  .card-pp > .card-body { flex-wrap: wrap; }
  .card-pp > .card-body > .pp,
  .card-pp > .card-body > .divider,
  .card-pp > .card-body > .small { flex: 1 1 100%; }
}
.pp {
  display: grid; grid-template-columns: minmax(0, 186px) minmax(0, 1fr);
  min-height: 214px; width: 100%; margin: 0;
  border-radius: 0 0 var(--radius) var(--radius); overflow: hidden;
}
/* Список контактных лиц (слева) и карточка выбранного (справа) — на телефоне
   от общих 341px карточки список фиксированной 186px и без того забирал
   больше половины, а детали (.pp-facts — телефон, email, имя) сжимались до
   ~35px и переносились по одной букве в строку. Список — сверху,
   прокручиваемый по высоте, детали — во всю ширину снизу (найдено при
   100%-проверке мобильной версии, 29.09.2026). */
@media (max-width: 640px) {
  .pp { grid-template-columns: 1fr; }
  .pp-list { flex-direction: row; overflow-x: auto; max-height: none;
             border-right: 0; border-bottom: 1px solid var(--border); }
  .pp-item { width: auto; flex: 0 0 auto; }
}
.pp-list {
  display: flex; flex-direction: column; gap: 2px;
  padding: 8px; background: var(--surface-2);
  border-right: 1px solid var(--border);
}
.pp-item {
  display: flex; flex-direction: column; gap: 2px; width: 100%;
  padding: 8px 10px; border: 0; border-radius: var(--radius-sm);
  background: transparent; text-align: left; cursor: pointer;
  font: inherit; color: var(--text); transition: background .12s, color .12s;
}
.pp-item:hover { background: var(--surface-3); }
.pp-item.is-active { background: var(--accent-soft); color: var(--accent-dark); }
.pp-item-name { font-weight: 600; font-size: 13.2px; line-height: 1.25; }
.pp-item-role { font-size: 12.2px; color: var(--muted); line-height: 1.25; }
.pp-item.is-active .pp-item-role { color: var(--accent-dark); opacity: .78; }

.pp-panes { padding: 16px; min-width: 0; }
.pp-head { display: flex; align-items: flex-start; gap: 12px; }
.pp-title { flex: 1; min-width: 0; }
.pp-name {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-weight: 650; font-size: 15.4px; color: var(--text);
}
.pp-role { font-size: 12.8px; color: var(--muted); margin-top: 2px; }
.pp-actions { display: flex; gap: 1px; flex: none; opacity: 0; transition: opacity .12s; }
.pp-actions form { display: inline-flex; }
.pp-pane:hover .pp-actions, .pp-pane:focus-within .pp-actions { opacity: 1; }
@media (hover: none) { .pp-actions { opacity: 1; } }

.pp-facts {
  display: grid; grid-template-columns: 104px minmax(0, 1fr);
  gap: 9px 16px; margin: 18px 0 0; align-items: baseline;
}
.pp-facts dt { color: var(--muted); font-size: 12.8px; }
.pp-facts dd {
  margin: 0; min-width: 0; font-weight: 600; color: var(--text);
  overflow-wrap: anywhere; font-variant-numeric: tabular-nums;
}
.pp-facts dd.pp-note { font-weight: 400; color: var(--text-2); }
/* Почта кликабельна, но цветом не выделяется: при наведении курсор-палец
   и тонкая серая линия — синего текста в карточке быть не должно (v3.4.2) */
.pp-mail {
  color: var(--text); text-decoration: none;
  border-bottom: 1px solid transparent; cursor: pointer;
}
.pp-mail:hover, .pp-mail:focus-visible {
  color: var(--text); border-bottom-color: var(--border-strong);
}



@media (max-width: 720px) {
  .pp { grid-template-columns: 1fr; }
  .pp-list {
    flex-direction: row; overflow-x: auto; border-right: 0;
    border-bottom: 1px solid var(--border);
  }
  .pp-item { width: auto; flex: none; }
}

/* Журнал генерации демо-данных (v3.1) */
.dg-log {
  margin-top: 14px; max-height: 190px; overflow-y: auto;
  font-size: 12.6px; color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 12px;
}
.dg-log:empty { display: none; }
.dg-log div { padding: 2px 0; border-bottom: 1px dashed var(--border); }
.dg-log div:last-child { border-bottom: 0; }

/* ================= Проверка базы (v3.6) ================= */
.diag-item { padding: 14px 0; border-bottom: 1px solid var(--border); }
.diag-item:last-child { border-bottom: 0; padding-bottom: 0; }
.diag-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.diag-explain { color: var(--text-2); font-size: 13px; margin-top: 6px; max-width: 78ch; }
.diag-list { margin: 10px 0 0; padding-left: 18px; font-size: 13px; }
.diag-list li { margin-bottom: 3px; }
/* «Откуда это?» — тихая ссылка рядом с находкой (v6.1): нужна редко,
   поэтому не спорит за внимание с самой находкой. */
/* Кнопка внутри строки предупреждения: не должна рвать абзац (v6.2) */
.inline-form { display: inline; margin-left: 8px; }
.inline-form .btn { vertical-align: baseline; }

.diag-origin { margin-left: 6px; font-size: 12px; color: var(--muted); border-bottom: 1px dashed currentColor; }
.diag-origin:hover { color: var(--accent); }
.diag-fix {
  margin-top: 12px; padding: 12px 14px; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px solid var(--border);
}
.diag-fix-head { display: flex; align-items: center; gap: 8px; }
.diag-plan { margin: 8px 0 10px; padding-left: 18px; font-size: 13px; }
.diag-plan li { margin-bottom: 3px; }
.diag-proof {
  display: flex; gap: 8px; align-items: flex-start;
  font-size: 12.5px; color: var(--text-2); margin-bottom: 10px; max-width: 82ch;
}
.diag-blocked {
  display: flex; gap: 8px; align-items: flex-start; margin-top: 10px;
  font-size: 12.5px; color: var(--text-2); max-width: 82ch;
}

/* ============ Заметки и планы (v3.7) ============ */
.note-item {
  display: flex; gap: 14px; align-items: flex-start;
  padding: 14px 0; border-bottom: 1px solid var(--border);
}
.note-item:last-child { border-bottom: 0; padding-bottom: 0; }
.note-item.done .note-main { opacity: .62; }
.note-item.done .note-head b { text-decoration: line-through; }
.note-main { flex: 1 1 auto; min-width: 0; }
.note-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.note-body { color: var(--text-2); font-size: 13px; margin-top: 6px; max-width: 84ch; }
.note-actions { display: flex; gap: 4px; align-items: center; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; }
.note-actions form { display: inline-flex; }
/* На телефоне .note-actions не сжимается (flex-shrink:0) — текст заметки
   выжимался в узкую полоску, а кнопки вылезали за край экрана. Строка
   заметки и кнопки — друг под другом (найдено при 100%-проверке мобильной
   версии, 29.09.2026). */
@media (max-width: 640px) {
  .note-item { flex-direction: column; }
  .note-actions { justify-content: flex-start; width: 100%; }
}

/* Инструкция по восстановлению */
ol.steps { margin: 0; padding-left: 20px; }
ol.steps li { margin-bottom: 12px; line-height: 1.55; max-width: 88ch; }
.qa { margin-bottom: 14px; max-width: 88ch; }
.qa > div { color: var(--text-2); font-size: 13px; margin-top: 4px; }

/* Список участников цели (v3.8) */
.participants { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 8px 16px; }


/* ---------- Ход выполнения долгих операций (v3.20, UX-039) ----------
 *
 * Импорт выписки, резервная копия и выгрузка в Excel занимают секунды, а
 * иногда и минуты. Всё это время страница выглядела так же, как до нажатия:
 * человек не понимал, началось ли что-нибудь, и нажимал второй раз.
 *
 * Кнопку мы блокировали и раньше — от повторной отправки это спасало, но
 * не отвечало на вопрос «а оно вообще работает». Теперь кнопка честно
 * говорит, что занята, а на долгих операциях поверх страницы появляется
 * полоса с объяснением, что происходит и сколько это примерно займёт.
 */
/* Кружок «идёт работа» — у ЛЮБОЙ занятой кнопки, а не только у `.btn`
   (v6.9.8): стрелка «обновить сейчас» в блоке «Обрати внимание» — не `.btn`,
   и без этого правила кружок в ней оставался неоформленным. */
.btn[data-busy-label] .busy-dot,
.is-busy .busy-dot {
  width: 12px; height: 12px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  display: inline-block; animation: busy-spin .7s linear infinite;
}
/* Кнопка-значок на время работы не меняет размер: слово в неё не ставится,
   а кружок занимает место значка. Иначе шапка блока дёргалась бы. */
.is-busy-icon { display: grid; place-items: center; font-size: 0; }
.is-busy-icon .busy-dot { width: 13px; height: 13px; }
@keyframes busy-spin { to { transform: rotate(360deg); } }

.busy-overlay {
  position: fixed; inset: 0; z-index: 9000;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: blur(2px);
}
.busy-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-3);
  padding: 22px 26px; max-width: 420px; text-align: center;
}
.busy-card .busy-dot {
  width: 26px; height: 26px; color: var(--accent);
  border: 3px solid var(--accent); border-top-color: transparent;
  border-radius: 50%; display: inline-block; animation: busy-spin .7s linear infinite;
}
.busy-title { font-weight: 600; margin-top: 12px; }
/* Имя .busy-card-note, а не .busy-note (v5.0.4): последнее уже занято
   жёлтой пометкой «товар держит другой заказ» в накладной, и это описание,
   стоя ниже, молча забирало у неё цвет — пометка выходила серой. */
.busy-card-note { color: var(--text-2); font-size: 13px; margin-top: 6px; line-height: 1.5; }
@media (prefers-reduced-motion: reduce) {
  .busy-dot { animation-duration: 2s; }
}


/* Опасное действие в строке сборки (v3.20, UX-046): отделено отступом и
   тонкой чертой от обычных кнопок, чтобы промах по привычке в него не попал */
.pick-stack .pick-danger {
  margin-top: 8px; padding-top: 8px;
  border-top: 1px dashed var(--border);
  border-radius: 0;
  color: var(--red);
  opacity: .85;
}
.pick-stack .pick-danger:hover { opacity: 1; }

/* Цена в заказе (v3.37).
   «Без НДС» — соседняя графа, только показ: она приглушена, чтобы взгляд не
   путал её с полем ввода. Цена, уведённая от прайс-листа, подсвечивается: это
   решение человека, и оно должно быть заметно ему самому до сохранения. */
td.net-price { color: var(--muted); font-variant-numeric: tabular-nums; }
/* Цена после скидки (v3.38): заказчик ввёл 5 % и должен видеть, во что это
   превратилось, — а не считать в уме и не гадать, до скидки цифра или после. */
td.net-price.after-discount { color: var(--amber); font-weight: 600; }
.net-price.after-discount { color: var(--amber); }

/* ЧИСЛА БЕЗ ПОЛЯ ВВОДА — НА ОДНОЙ ЛИНИИ С НАБИРАЕМЫМИ (v6.105.0, замечание
   Игоря: «Доступно» и «Цена без НДС» стоят выше остальных цифр строки).
   Причина: текст в ячейке и текст внутри поля ввода центрируются по-разному —
   простой текст вставал на ~7px выше. Даём этим ячейкам высоту строки, равную
   высоте поля ввода (34px): число садится в такую же коробку, и центр совпадает
   с набираемыми значениями — на любой высоте строки. */
#itemsTable tbody td.avail,
#itemsTable tbody td.net-price,
#itemsTable tbody td.line-total { line-height: 34px; }

/* Колонка «СКИДКА» в позициях оформленного заказа (v6.71.0, просьба
   заказчика): раньше всегда серая, теперь — оранжевая, когда скидка есть,
   тем же цветом, что и остальные «после скидки» цифры на этом экране. */
td.disc-badge { color: var(--amber); font-weight: 600; }

input.price-off {
  border-color: var(--amber);
  background: var(--amber-soft);
  color: var(--amber);
  font-weight: 600;
}

/* Подсветка поля скидки (v6.71.0, просьба заказчика) — тем же приёмом, что
   и у input.price-off выше: скидка не спрятана в графах цены, а видна прямо
   в своём поле. */
input.disc.disc-active {
  border-color: var(--amber);
  background: var(--amber-soft);
  color: var(--amber);
  font-weight: 600;
}

/* Строка позиций заказа — выравнивание по верхнему краю, а не по центру
   (v6.71.0). ПОЧЕМУ: у поля «Цена с НДС» под инпутом появляется подпись
   «со скидкой …», и ячейка становится выше остальных в строке. При
   центрировании (обычное поведение таблиц в системе) высота ячейки цены
   «гуляла» из-за этой подписи, и поле «Скидка %» рядом либо прыгало, либо
   вставало не на одном уровне с остальной строкой (было и то, и другое —
   смотря что чинили). Верхнее выравнивание всей строки убирает и то, и
   другое разом: все поля висят на одном уровне независимо от того, есть
   скидка или нет. */
#itemsTable tbody td { vertical-align: top; }

/* Полоса тестового режима (v4.0, OPS-047).
   Красная и во всю ширину, поверх всего: если её можно не заметить, она не
   работает. Печать её не показывает — на бумаге режима не существует. */
.test-banner {
  position: sticky; top: 0; z-index: 60;
  background: #b3261e; color: #fff;
  padding: 7px 16px; text-align: center;
  font-size: 13px; font-weight: 600; letter-spacing: .2px;
}
@media print { .test-banner { display: none; } }

/* Сервер держит старый код: полоса поверх всего (v6.14.6) */
.stale-banner { background: #fff4d6; color: #6b5219; border-bottom: 1px solid #f0dfae;
                padding: 9px 16px; font-size: 13.5px; text-align: center; }
.stale-banner a { color: #6b5219; font-weight: 650; text-decoration: underline; }
@media print { .stale-banner { display: none; } }

/* ==================================================================== */
/*  Кабинет покупателя (v6.3)                                           */
/*                                                                      */
/*  Отдельный набор правил, а не переиспользование меню системы: у      */
/*  кабинета своя шапка из четырёх пунктов и свой нижний ряд с итогом.  */
/*  Классы .lbl здесь не появляются нигде — он занят печатными формами. */
/* ==================================================================== */
body.portal { background: var(--bg, #f6f8fb); }
.portal-wrap { max-width: 1180px; margin: 0 auto; padding: 0 16px; }
.portal-top { background: #fff; border-bottom: 1px solid var(--line, #e3e8ef); position: sticky; top: 0; z-index: 30; }
.portal-top-in { display: flex; align-items: center; gap: 18px; height: 56px; }
.portal-brand { font-weight: 600; color: inherit; text-decoration: none; white-space: nowrap; }
.portal-nav { display: flex; gap: 4px; flex: 1 1 auto; overflow-x: auto; }
.portal-nav a { padding: 7px 12px; border-radius: 8px; color: var(--muted, #5b6472); text-decoration: none; white-space: nowrap; }
.portal-nav a:hover { background: var(--bg, #f1f4f9); }
.portal-nav a.on { background: var(--primary-soft, #e8f0fe); color: var(--primary, #2563eb); font-weight: 600; }
.portal-who { display: flex; align-items: center; gap: 10px; }
.portal-main { padding: 20px 16px 110px; }
.portal-foot { padding: 0 16px 24px; }

.portal-group { border: 1px solid var(--line, #e3e8ef); border-radius: 10px; margin-bottom: 10px; background: #fff; }
.portal-group > summary { padding: 10px 14px; cursor: pointer; font-weight: 600; }
.portal-group[open] > summary { border-bottom: 1px solid var(--line, #e3e8ef); }

.portal-items input.qty { width: 110px; text-align: right; }
.portal-items input.qty.is-bad { border-color: var(--danger, #dc2626); background: #fff5f5; }
.portal-items .qty-err { color: var(--danger, #dc2626); min-height: 15px; text-align: right; }
.portal-items tr.row-picked { background: #f7fbff; }

.portal-bar { position: sticky; bottom: 0; display: flex; align-items: center; gap: 16px;
  justify-content: space-between; background: #fff; border-top: 1px solid var(--line, #e3e8ef);
  padding: 12px 16px; margin: 16px -16px 0; box-shadow: 0 -4px 14px rgba(16, 24, 40, .06); }
.portal-bar b { font-size: 17px; }
/* Два итога в одной строке — без НДС и с НДС (v6.9). На узком экране они
   переносятся, а не вылезают за край: сумма, которую не видно, хуже, чем
   сумма на второй строке. */
.portal-sums { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 0; min-width: 0; }
.portal-sums b { font-variant-numeric: tabular-nums; margin-left: 4px; }

@media (max-width: 720px) {
  /* МОБИЛЬНАЯ ШАПКА КАБИНЕТА (v6.155.0, проверка 3, кабинет Н-23). ЧТО БЫЛО:
     `padding: 8px 0` затирал боковые поля `.portal-wrap` — название и кнопки
     прижимались к краю экрана, а меню шире полосы обрезало «Мой долг»
     посередине. КАК ТЕПЕРЬ: поля 16 px, меню — своей строкой на всю ширину;
     не влезает в строку — переносится, а не прячется: пунктов всего четыре,
     и каждый должен быть виден целиком. */
  .portal-top-in { height: auto; padding: 8px 16px; flex-wrap: wrap; gap: 8px 12px; }
  .portal-brand { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .portal-nav { order: 3; flex: 1 1 100%; min-width: 0; flex-wrap: wrap; overflow: visible; }
  .portal-nav a { padding: 7px 10px; }
  .portal-bar { flex-wrap: wrap; gap: 8px; }
}

/* ==================================================================== */
/*  Журнал ошибок (v6.4.4)                                              */
/* ==================================================================== */
.err-entry { border-bottom: 1px solid var(--border); }
.err-entry:last-child { border-bottom: 0; }
.err-entry > summary { padding: 10px 14px; cursor: pointer; display: flex; gap: 12px; align-items: baseline; }
.err-entry > summary::-webkit-details-marker { display: none; }
.err-time { font-size: 12.5px; color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.err-msg { font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.err-entry[open] > summary .err-msg { white-space: normal; }
.err-body { padding: 0 14px 12px 14px; }
.err-trace { background: var(--surface-3); padding: 10px; border-radius: 8px;
  overflow: auto; max-height: 320px; margin-top: 8px; font-size: 12px; line-height: 1.5; }

/* ============ Выбор товара плитками — «кубики» (v6.7) ============
 *
 * Заказчик: «кубики по категориям в ширину четыре, нажимаешь категорию —
 * такие же кубики товаров: фото, название, количество».
 *
 * Ширина задаётся не числом колонок, а МИНИМАЛЬНОЙ ШИРИНОЙ ПЛИТКИ: на
 * широком экране их станет пять-шесть, на ноутбуке — четыре, на телефоне —
 * две. Жёсткие четыре колонки на телефоне дали бы плитки размером с ноготь,
 * а фото в них и есть главное, ради чего окно открывают. */
.modal.modal-wide { max-width: 960px; width: calc(100vw - 48px); }

.tiles-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
  max-height: min(60vh, 560px);
  overflow-y: auto;
  padding: 2px;
}

.tile {
  display: flex; flex-direction: column; align-items: stretch; gap: 6px;
  position: relative;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--surface); padding: 10px;
  text-align: left; font: inherit; color: var(--text);
  transition: border-color .12s, box-shadow .12s;
}
.tile:hover { border-color: var(--primary); box-shadow: 0 2px 10px rgba(0,0,0,.07); }
.tile.on { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); }

/* Категория — крупная надпись и число товаров: выбирают по слову */
.tile-cat { cursor: pointer; min-height: 84px; justify-content: center; align-items: center; text-align: center; }
.tile-cat .tile-name { font-weight: 600; font-size: 15px; line-height: 1.3; }

.tile-name {
  font-size: 13px; line-height: 1.35; font-weight: 600;
  /* Длинное название переносится, а не обрезается: обрезанное «Сок яблоч…»
     невозможно отличить от «Сок яблочный 0,2» рядом. */
  overflow-wrap: anywhere;
}
.tile-sub { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }

.tile-photo {
  display: block; width: 100%; aspect-ratio: 1 / 1;
  border: none; border-radius: 8px; padding: 0; cursor: pointer;
  background: var(--surface-3); overflow: hidden;
}
/* Название и подпись внутри ярлыка — обычными строчками, а не в ряд */
.tile-hit .tile-name, .tile-hit .tile-sub { display: block; }
.tile-photo img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* Без фото — нейтральный значок «фото нет».
 * Сначала здесь стояла первая буква названия; на живых данных оказалось, что
 * внутри категории она у всех одна и та же («Запальничка» → «З», которое ещё
 * и читается как цифра 3). Значок ничего не обещает и не мешает читать
 * название под плиткой. */
.tile-nophoto {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%; color: var(--muted); opacity: .55;
}

/* ВСЯ ПЛИТКА — ОДИН ЯРЛЫК (v6.9.2).
 *
 * Раньше на плитке было два разных нажатия друг поверх друга: квадратик
 * галочки в углу и фото под ним. Промах мимо квадратика в двадцать точек
 * попадал в другое действие. Теперь `<label>` занимает плитку целиком:
 * нажатие в любое место переключает галочку силами браузера — промахнуться
 * некуда, и с клавиатуры работает так же. */
.tile-hit {
  display: flex; flex-direction: column; align-items: stretch; gap: 6px;
  cursor: pointer; margin: 0;
}
.tile-check { position: absolute; top: 14px; left: 14px; z-index: 2; display: block; }
.tile-check input {
  width: 20px; height: 20px; cursor: pointer;
  /* Галочка лежит поверх фото — без подложки её не видно на светлом снимке */
  accent-color: var(--primary);
  box-shadow: 0 0 0 3px var(--surface); border-radius: 4px;
}
/* Видимая обводка, когда до плитки дошли клавишей, а не мышью */
.tile-hit:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 8px; }

@media (max-width: 560px) {
  .tiles-grid { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 9px; }
  .modal.modal-wide { width: calc(100vw - 20px); }
}
@media (prefers-reduced-motion: reduce) { .tile { transition: none; } }

/* Текст только для программ чтения с экрана (v6.7).
 * Галочка на плитке — просто квадратик: слепой человек услышит «флажок» и
 * не узнает, что именно он отмечает. Прятать через display:none нельзя —
 * тогда текст не прочитает и программа чтения. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Плитка товара, который уже в заказе (v6.8).
 * Заказчик: «нажал на картинку — добавилось, потом ту же картинку пометил
 * галочкой и нажал „Добавить“ — чтобы дубликатов не было».
 * Приглушаем, но НЕ прячем: спрятанная плитка выглядела бы так, будто товар
 * кончился, и человек пошёл бы искать его снова. */
/* ПЛИТКА В ЗАКАЗЕ — ОТМЕЧЕНА, НО ЖИВАЯ (v6.8.2).
 * Заказчик: «если я случайно нажал, я не могу отменить. Сейчас это серый
 * блок, я не могу ничего сделать».
 * Первая редакция приглушала плитку и выключала галочку — получался тупик:
 * снять выбор можно было только внизу, в таблице. Теперь плитка выделена
 * рамкой и остаётся нажимаемой: второе нажатие убирает позицию. */
.tile.in-order {
  border-color: var(--primary);
  box-shadow: inset 0 0 0 2px var(--primary);
}
.tile.in-order .tile-photo { cursor: pointer; }
.tile.in-order .tile-sub { color: var(--primary); }
.tile.in-order .tile-sub b { font-weight: 700; }

/* ============ Кабинет покупателя: состав заказа (v6.9) ============
 *
 * Заказчик про кабинет: «должна быть картинка каждого товара рядом, и при
 * нажатии она становилась больше».
 *
 * Колонка с фото узкая и фиксированная: она не должна отбирать ширину у
 * названия, которое здесь главное. Пустое место, когда фото нет, оставляем —
 * иначе строки поедут и глаз потеряет столбец. */
.pt-pic { width: 56px; padding-right: 0 !important; }
.pt-thumb {
  display: block; width: 44px; height: 44px; border-radius: 6px; overflow: hidden;
  background: var(--surface-3); border: 1px solid var(--border);
}
.pt-thumb img { width: 100%; height: 100%; object-fit: contain; display: block; }
.pt-thumb-empty { display: block; }

@media (max-width: 560px) {
  .pt-pic { width: 40px; }
  .pt-thumb { width: 34px; height: 34px; }
}

/* ================================================================
   ЛИЧНЫЙ СПИСОК ЗАДАЧ (v6.11.0)
   ----------------------------------------------------------------
   Заказчик: «срочная красным, средняя жёлтым, обычная бежевым; и
   можно было перетягивать каждую задачу вверх-вниз».

   Цвет здесь — не украшение, а сама важность: блок, в котором лежит
   карточка, и есть её приоритет. Поэтому перетаскивание в соседний
   блок меняет важность, а не только порядок, — позиция и есть смысл.
   ================================================================ */
.tabs-sub { margin-top: -6px; margin-bottom: 12px; }
.tabs-sub a { font-size: 13px; padding: 5px 12px; }

.task-board { display: flex; flex-direction: column; gap: 14px; }

.tprio { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--surface-2); }
.tprio-h { display: flex; align-items: center; gap: 8px; padding: 8px 12px; font-size: 13px; }
.tprio-h b { font-weight: 700; }
.tprio-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.tprio-n { margin-left: auto; color: var(--muted); font-size: 12px; }

.tprio-high    { background: var(--red-soft);   border-color: #f3c9c6; }
.tprio-high   .tprio-dot { background: var(--red); }
.tprio-high   .tprio-h b { color: var(--red); }
.tprio-mid     { background: var(--amber-soft); border-color: #f0dcb4; }
.tprio-mid    .tprio-dot { background: var(--amber); }
.tprio-mid    .tprio-h b { color: var(--amber); }
/* ОБЫЧНАЯ — СИНЯЯ (v6.13.0, слова заказчика: «обычные какие-то коричневые,
   он сильно схож со средней; сделай их другим цветом, синий например»).
   Бежевый и правда стоял в шаге от жёлтого «среднего»: две тёплые полосы
   подряд глаз не различал, и колонки читались как одна.
   Синий берём тот же, что и везде в системе, — из палитры, а не свой. */
.tprio-low     { background: var(--accent-soft); border-color: #c7d9fb; }
.tprio-low    .tprio-dot { background: var(--accent); }
.tprio-low    .tprio-h b { color: var(--accent-dark); }

.tprio-list { display: flex; flex-direction: column; gap: 6px; padding: 0 8px 8px; min-height: 46px; }
.tprio-list.drag-over { outline: 2px dashed var(--accent); outline-offset: -4px; border-radius: 6px; }

.tcard {
  display: flex; align-items: center; gap: 8px; background: var(--surface);
  border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px;
}
.tcard.dragging { opacity: .45; }
.tcard.drop-mark { box-shadow: 0 -3px 0 -1px var(--accent); }
.tgrip { color: var(--muted); cursor: grab; flex: 0 0 auto; display: flex; }
.tgrip:active { cursor: grabbing; }
.tbody { flex: 1; min-width: 0; }
.tname { display: block; font-weight: 600; color: var(--text); line-height: 1.25; }
.tname:hover { color: var(--accent-dark); }
.tmeta { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 3px; font-size: 12px; color: var(--muted); }
.tmeta span { display: inline-flex; align-items: center; gap: 3px; }
/* ВТОРАЯ СТРОКА КАРТОЧКИ (v6.49.0, предложение 26). В первой — кому, когда,
   чей клиент: по ним доску и просматривают. Здесь — всё остальное: отдел,
   документ, ожидание, чек-лист, метки, участники. Мельче и бледнее, чтобы
   при беглом взгляде читалась именно первая строка, а эта попадалась на
   глаза только когда в ней что-то есть. */
.tmeta-more { margin-top: 2px; font-size: 11px; gap: 3px 10px; opacity: .9; }
.tdone { flex: 0 0 auto; }
.tempty { color: var(--muted); font-size: 12px; padding: 10px; text-align: center; }

@media (max-width: 560px) {
  .tcard { align-items: flex-start; }
  .tmeta { gap: 2px 8px; }
}

/* Цифра невыполненных задач в верхней панели (v6.11.0). Не точка, как у
   колокольчика, а число: «есть события» и «мне сегодня делать семь дел» —
   разные сообщения, и второе без числа не передать. */
.icon-btn .tcount {
  position: absolute; top: 1px; right: 0; min-width: 15px; height: 15px;
  padding: 0 3px; border-radius: 8px; background: var(--accent); color: #fff;
  font-size: 10px; line-height: 15px; text-align: center; font-weight: 700;
}

/* Кому поручить: галочки по ролям, с «все» на роль (v6.11.1). */
.whom { border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px;
        max-height: 230px; overflow-y: auto; background: var(--surface-2); }
.whom-role + .whom-role { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border); }
.whom-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.whom-head b { font-size: 12px; letter-spacing: .04em; color: var(--muted); text-transform: uppercase; }
.whom-all { margin-left: auto; font-size: 12px; color: var(--accent-dark); }
.whom-one { display: flex; align-items: center; gap: 7px; padding: 3px 0; }

/* ================================================================
 * ПРОДАЖИ ПО МЕСЯЦАМ — столбики на главной (v6.11.2)
 * ================================================================
 * Рисуем средствами страницы: ни одной внешней библиотеки, ни одного
 * запроса наружу. Двенадцать колонок делят ширину поровну — горизонтальной
 * прокрутки на главной быть не должно ни при каком экране.
 */
.mo-chart {
  display: flex; align-items: flex-end; gap: 6px;
  height: 180px; padding: 4px 2px 0;
}
.mo-col {
  flex: 1 1 0; min-width: 0; height: 100%;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  color: var(--text); text-decoration: none; border-radius: var(--radius-sm);
  padding: 2px 1px;
}
.mo-col:hover { background: var(--surface-3); }
.mo-val {
  font-size: 11px; color: var(--muted); font-weight: 600;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.mo-bar { flex: 1 1 auto; width: 100%; display: flex; align-items: flex-end; justify-content: center; }
.mo-bar i {
  display: block; width: 68%; max-width: 46px; min-height: 2px;
  background: var(--accent); border-radius: 4px 4px 0 0;
  transition: background .12s;
}
.mo-col:hover .mo-bar i { background: var(--accent-dark); }
.mo-name { font-size: 11px; color: var(--muted); white-space: nowrap; }
/* Текущий месяц — он ещё не дописан, и столбик обязан отличаться, иначе
   его читают как провал */
.mo-col.now .mo-bar i { background: repeating-linear-gradient(
    135deg, var(--accent) 0 6px, var(--accent-soft) 6px 12px); }
.mo-col.now .mo-name { color: var(--text); font-weight: 700; }
.mo-foot { margin-top: 8px; }

@media (max-width: 720px) {
  .mo-chart { height: 150px; gap: 3px; }
  .mo-val { font-size: 10px; }
  .mo-name { font-size: 10px; }
}

/* ССЫЛКА, КОТОРАЯ НЕ КРИЧИТ (v6.11.2, просьба заказчика).
 *
 * «Клиентов 18 / 53» на главной было синим — и синим оно спорило с самими
 * цифрами, ради которых на главную заходят. Заказчик: пусть текст будет
 * чёрным и жирным, а что по нему можно нажать — видно при наведении.
 * Подчёркивание и цвет появляются вместе с курсором-рукой. */
.link-quiet {
  color: var(--text); font-weight: 700; text-decoration: none;
  font-variant-numeric: tabular-nums;
}
.link-quiet:hover, .link-quiet:focus-visible {
  color: var(--accent-dark); text-decoration: underline; cursor: pointer;
}

/* Число задач в меню под именем (v6.11.2). Та же цифра, что и в кнопке
   наверху, — и берётся она из того же счётчика. */
.dropdown-menu .menu-count {
  display: inline-block; min-width: 17px; padding: 0 4px; margin-left: 4px;
  border-radius: 9px; background: var(--accent); color: #fff;
  font-size: 11px; line-height: 17px; text-align: center; font-weight: 700;
}

/* «Сделано, но требует решения» (v6.11.3). Красная рамка на успешной
   операции: заказчик просил именно её для изменений, которые задели уже
   закрытую зарплату. Отличается от ошибки заливкой — операция прошла. */
.flash.alarm {
  border-left: 3px solid var(--red);
  background: var(--red-soft);
  color: #991b1b;
  font-weight: 600;
}

/* Плюс в заголовке блока важности (v6.12.0) */
.tprio-add {
  margin-left: 6px; width: 20px; height: 20px; padding: 0; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 6px; cursor: pointer;
  background: var(--accent); color: #fff;
}
.tprio-add:hover { background: var(--accent-dark); }

/* «Кому»: категория, потом люди (v6.12.0) */
.whom-self { margin-bottom: 8px; }
/* Выбор «Себе / Людям / Отделу» (v6.49.0, п.5 заказчика и предложение 41).
   Сделан теми же сегментами, что и «Задача / Встреча» выше в том же окне:
   одинаковый элемент для одинакового по смыслу выбора — человек узнаёт его
   сразу и не ищет, чем они отличаются. */
.whom-mode { display: inline-flex; align-self: flex-start; margin-bottom: 8px;
  border: 1px solid var(--border-strong); border-radius: 8px; overflow: hidden; }
.whom-mode-opt { position: relative; }
.whom-mode-opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.whom-mode-opt span { display: block; padding: 6px 16px; font-size: 13px; cursor: pointer; color: var(--text-2); }
.whom-mode-opt input:checked + span { background: var(--accent); color: #fff; }
.whom-mode-opt input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: -2px; }
.whom-panel[hidden] { display: none; }
.whom-pick { width: 100%; margin-bottom: 8px; }
.whom-empty { color: var(--muted); font-size: 12px; padding: 4px 0; }
.whom-chosen { margin-top: 6px; font-size: 12px; color: var(--text-2); }
.whom-chosen-empty { color: var(--muted); }

/* Ответы на задачу (v6.12.0) */
.tcomments { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; }
.tcomment { border-left: 2px solid var(--border-strong); padding: 2px 0 2px 10px; }
.tcomment-head { display: flex; gap: 8px; align-items: baseline; margin-bottom: 2px; }

/* Строка задачи в закладке «Все»: без перетаскивания, но с цветом важности */
.tcard-flat { cursor: default; }
.tcard-flat.tflat-high { border-left: 3px solid var(--red); }
.tcard-flat.tflat-mid  { border-left: 3px solid var(--amber); }
.tcard-flat.tflat-low  { border-left: 3px solid var(--border-strong); }

/* Пока большая картинка грузится — видно, что она грузится, а не прошлый
   товар (v6.12.0). */
.lightbox.lb-loading::after {
  content: 'Загружаем…';
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  color: #fff; font-size: 13px; letter-spacing: .04em; opacity: .85;
}
.lightbox.lb-loading img { visibility: hidden; }

/* Разбор списка складов: ячейку можно перетащить в соседнюю колонку своей
   строки (v6.12.1). */
.bulk-grid .bulk-cell { cursor: grab; }
.bulk-grid .bulk-cell:hover { background: var(--surface-3); }
.bulk-grid .bulk-cell.dragging { opacity: .45; }
.bulk-grid .bulk-cell.drop-here { box-shadow: inset 0 0 0 2px var(--accent); border-radius: 4px; }

/* ================== КАТАЛОГ ДЛЯ КЛИЕНТОВ (v6.14.0) ==================
   Заказчик: «отдельный модуль с левой стороны — каталог, создание каталога».
   Экран настройки и лист печати. Приставка `.cat-`/`.tpl-`/`.fld-` — чтобы
   ничего из этого не пересеклось с печатными формами накладной и счёта. */

/* ---- выбор шаблона: миниатюра листа, а не текст ---- */
.tpl-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 12px; }
@media (max-width: 1100px) { .tpl-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px)  { .tpl-grid { grid-template-columns: repeat(2, 1fr); } }
.tpl { display: block; border: 1.5px solid var(--border); border-radius: 10px;
       padding: 10px; cursor: pointer; transition: .14s; background: var(--surface); }
.tpl:hover { border-color: var(--accent); }
.tpl.on { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.tpl-mini { display: flex; flex-direction: column; gap: 4px; aspect-ratio: 210/297;
            background: #fff; border: 1px solid var(--border-soft, var(--border));
            border-radius: 4px; padding: 6px; }
.tm-head { height: 8px; border-radius: 2px; background: var(--surface-2); flex: 0 0 auto; }
.tm-body { flex: 1; display: grid; gap: 4px; min-height: 0;
           grid-template-columns: 1fr 1fr; }
.tpl-s3 .tm-body, .tpl-s4 .tm-body, .tpl-s5 .tm-body { grid-template-columns: 1fr; }
.tm-cell { background: var(--accent-soft); border: 1px solid var(--accent-line, #cddafc); border-radius: 3px; }
.tm-cell.strip { background: linear-gradient(90deg, var(--accent-soft) 0 38%, #fff 38%); }
.tpl-name { display: block; font-weight: 650; font-size: 12.5px; margin-top: 8px; }
.tpl-note { display: block; font-size: 11.5px; color: var(--muted); line-height: 1.35; }

/* ---- галочки полей ---- */
.fld-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 8px; }
.fld { display: flex; align-items: center; gap: 9px; border: 1px solid var(--border);
       border-radius: 8px; padding: 9px 11px; font-size: 13.5px; cursor: pointer; }
.fld .fl-t { font-weight: 550; }
.fld .fl-h { margin-left: auto; font-size: 11.5px; color: var(--muted); white-space: nowrap; }
/* На телефоне минимальная ширина клетки (230px) не помещается в карточку —
   подпись .fl-h не переносится (white-space:nowrap) и раздвигает строку за
   край экрана. В одну колонку и разрешаем подписи переноситься (найдено при
   100%-проверке мобильной версии, 29.09.2026). Блок должен идти ПОСЛЕ базовых
   правил выше — иначе при равном приоритете выигрывает более поздняя nowrap. */
@media (max-width: 620px) {
  .fld-grid { grid-template-columns: 1fr; }
  .fld { min-width: 0; }
  .fld .fl-t { min-width: 0; }
  .fld .fl-h { white-space: normal; text-align: right; }
}
/* Строка, которая на этом шаблоне не влезет: видно, что она есть, но бледная */
.fld.cut { opacity: .5; }
/* Переключатель состава — ссылкой, а не галочкой: он пересчитывает листы
   сразу, а не после сохранения (v6.14.0) */
a.fld { text-decoration: none; color: inherit; }
a.fld.on { border-color: var(--accent); background: var(--accent-soft); }
a.fld.on .fl-t { color: var(--accent-dark); font-weight: 650; }

/* ---- логотипы каталога ---- */
.logo-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px; }
@media (max-width: 700px) { .logo-row { grid-template-columns: 1fr; } }
.logo-box { border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px;
            display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.logo-cap { font-weight: 650; font-size: 13px; }
.logo-prev { max-height: 46px; max-width: 220px; object-fit: contain; }
.logo-none { font-size: 12.5px; color: var(--muted); }

/* ---- строки категорий ---- */
.cat-move { white-space: nowrap; }
.cat-arrow { border: 1px solid var(--border); background: var(--surface); color: var(--muted);
             border-radius: 6px; width: 22px; height: 22px; line-height: 1; cursor: pointer; padding: 0; }
.cat-arrow:hover { color: var(--text); border-color: var(--accent); }
.cat-row.cat-empty { opacity: .55; }
input.inp-thin { width: 100%; padding: 5px 8px; font-size: 13px; }

/* ================== ЛИСТ КАТАЛОГА ================== */
/* ЛИСТ ИМЕЕТ РОВНО ОДНУ ВЫСОТУ — И НА ЭКРАНЕ ТОЖЕ (исправлено в 6.14.4).
   Было `min-height`: лист рос вслед за содержимым, а не ужимал его. Отсюда
   жалоба заказчика: «выбираю три полоски, четыре, пять — а он просто удлиняет
   лист, картинка одинаковая; хотя при трёх картинка должна быть больше, при
   шести меньше». Именно так: высота листа задана, строки делят её между
   собой (`1fr`), и чем гуще шаблон, тем мельче снимок. С `min-height` строки
   считались по содержимому и делить было нечего.

   Это же чинило и печать: содержимое выше печатной области переползало на
   следующую страницу, и в PDF появлялись лишние листы. */
.cat-page { width: 190mm; max-width: 100%; height: 273mm; margin: 0 auto 16px;
            background: #fff; color: #16181d; box-shadow: var(--shadow-1);
            display: flex; flex-direction: column; padding: 8mm 8mm 6mm;
            overflow: hidden; }
.cat-head { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 6mm;
            padding-bottom: 3mm; }
.cat-org   { font-weight: 700; font-size: 12pt; letter-spacing: .02em; }
.cat-brand { font-weight: 700; font-size: 12pt; text-align: right; letter-spacing: .08em; text-transform: uppercase; }
.cat-series { text-align: center; }
.cat-series b { display: block; font-size: 14pt; letter-spacing: .16em; text-transform: uppercase; }
.cat-series span { display: block; font-size: 9.5pt; letter-spacing: .1em; color: #6b7480; }
/* ТРИ ЛИНИИ ЛИСТА (v6.14.5, по образцу заказчика).
   Сверху жёлтая полоса под шапкой, под строкой «N наборів» — тонкая серая
   черта, и внизу жёлтая полоса над подвалом. Это фирменный каркас листа: без
   нижней полосы страница висит в воздухе, а без серой черты шапка и товар
   сливаются. */
.cat-rule { height: 2mm; background: #ffd400; margin-bottom: 3mm; }
.cat-bar { display: flex; justify-content: space-between; font-size: 8.5pt; color: #6b7480;
           text-transform: lowercase; padding-bottom: 2mm; margin-bottom: 4mm;
           border-bottom: .2mm solid #dcdcd6; }
/* Между последним рядом и нижней жёлтой полосой — воздух (v6.14.11):
   на полном листе полоса упиралась прямо в клетки. */
.cat-body { flex: 1; display: grid; gap: 6mm; min-height: 0; min-width: 0; margin-bottom: 4mm; }
/* min-width: 0 — не украшение (исправлено в 6.14.2). Клетка сетки по
   умолчанию не даёт себя сжать меньше содержимого, и широкая фотография
   раздвигала колонку: лист уезжал вправо и обрезался. Заказчик: «всё уходит
   вправо, и там обрезается часть, не видно».

   СЕРОЕ ПОЛЕ ПОД НАБОРОМ (v6.14.4). Заказчик: «почему поле не серое? там,
   где кубик, сзади он должен быть серый, как на картинке». Клетка — светло-
   серая карточка, снимок лежит на ней белым прямоугольником: товар снят на
   белом, и заливать его серым нельзя — потускнеет сам товар. */
.cat-cell { display: flex; flex-direction: column; min-height: 0; min-width: 0;
            background: #f5f5f2; border: .25mm solid #e4e4de;
            border-radius: 2mm; overflow: hidden; background: #fff; }
.cat-strips .cat-cell { flex-direction: row; align-items: center; gap: 5mm; padding: 3mm; }
/* Большой набор занимает две клетки: восемь зажигалок в половину листа
   выходят вдвое мельче четырёх у соседа (v6.14.1) */
.cat-grid .cat-cell.cat-wide { grid-column: span 2; }
/* ФОН КУБИКА СЕРОВАТЫЙ, И СНИМОК НА НЁМ НЕ БЕЛЕЕТ (v6.14.5).
   Заказчик: «фон кубиков внутренних должен быть чуть-чуть сероватый, как на
   фотографиях, что я высылал». Клетка серая, но товар снят на белом, и белый
   прямоугольник кадра съедал этот серый обратно. С 6.14.5 по 6.14.10 это
   делал `mix-blend-mode: multiply`, но Firefox печатает лист с ним
   картинкой 72 dpi и без снимков. Теперь серый впечатан в саму копию
   каталога (`ImageService::build`, `CAT_CELL_RGB`), а смешивания в стилях
   нет: белое поле кадра и клетка — один и тот же цвет, шва не видно. */
.cat-shot { flex: 1; min-height: 0; min-width: 0; display: flex; align-items: center;
            justify-content: center; background: transparent; padding: 3mm; margin: 0; }
.cat-strips .cat-shot { flex: 0 0 46%; height: 100%; padding: 2mm; margin: 0; }
/* Снимок вписывается в клетку и не тянет её за собой: ширина и высота
   ограничены самой клеткой, пропорции сохраняются (v6.14.2) */
.cat-shot img { max-width: 100%; max-height: 100%; width: auto; height: auto;
                object-fit: contain; display: block; }
/* ЛОГОТИПЫ В ШАПКЕ ЛИСТА — В ЖЁСТКОЙ РАМКЕ (v6.14.2, ограничение усилено в
   6.14.3). Заказчик: «есть ограничения по размеру логотипа, чтобы опять не
   загрузил большой и это всё подвинуло?» Есть, и оно здесь: что бы ни
   загрузили — хоть снимок на 3000 точек, — на листе логотип живёт в рамке
   13 × 55 мм и сохраняет пропорции. Раздвинуть шапку он не может физически:
   размер задаёт лист, а не файл. `flex: 0 0 auto` — чтобы длинный логотип не
   отбирал место у названия серии в середине. */
.cat-logo { max-height: 13mm; max-width: 55mm; width: auto; height: auto;
            object-fit: contain; display: block; flex: 0 0 auto; }
.cat-logo.brand { margin-left: auto; }
/* Шапка листа не растёт вслед за картинкой: её высота задана рамкой выше */
.cat-head { max-height: 18mm; }
.cat-txt { padding: 2mm 3mm 3mm; }
.cat-strips .cat-txt { flex: 1; padding: 0; }
.cat-txt b { display: block; font-size: 11pt; line-height: 1.25; }
.cat-txt span { display: block; font-size: 8.5pt; line-height: 1.4; color: #55606c; }
.cat-strips .cat-txt b { font-size: 13pt; }
.cat-strips .cat-txt span { font-size: 9.5pt; }
/* Чем плотнее сетка, тем мельче подпись: восемь наборов на лист живут только так */
.cat-g6 .cat-txt b { font-size: 10pt; }
.cat-g8 .cat-txt b { font-size: 9pt; }
.cat-g8 .cat-txt span { font-size: 7.5pt; }
.cat-foot { margin-top: auto; padding-top: 3mm; border-top: 1.4mm solid #ffd400;
            display: flex; justify-content: space-between; font-size: 8pt; color: #6b7480; }
.cat-none { padding: 24px; text-align: center; color: var(--muted); }
.cat-warn { background: #fffaf0; border: 1px solid #f0e2c4; border-left: 3px solid #b8842a;
            border-radius: 8px; padding: 10px 12px; margin: 0 auto 14px; max-width: 190mm;
            font-size: 13px; color: #5c4718; }

/* ЛИСТ КАТАЛОГА ЖИВЁТ НЕ НА БЛАНКЕ (v6.14.4).
   Страница печати заворачивает содержимое в `.print-doc` — а это бланк
   накладной: своя ширина 190 мм и поля 12 × 10 мм. Лист каталога, тоже
   190 мм, оказывался внутри этих полей и уезжал вправо, а часть уходила за
   край. Заказчик: «через браузер выглядит сдвинут направо». Для каталога
   бланк снимается: лист сам себя центрирует. */
.print-doc.print-catalog { width: auto; max-width: none; padding: 0; margin: 0;
                           background: transparent; box-shadow: none; border-radius: 0; }

@media print {
  /* ЛИСТ = ФИЗИЧЕСКАЯ СТРАНИЦА (v6.14.4).
     Было `height: 100%` — сто процентов от родителя неопределённой высоты,
     то есть «по содержимому». Разрыв страницы падал куда придётся: в PDF
     половина листа уезжала на следующую страницу, а внизу оставалась пустота
     и кусок следующей шапки с жёлтой полосой. Заказчик прислал ровно это.

     273 мм — это А4 (297) минус поля печати из `@page` (12 мм сверху и
     снизу). Лист занимает страницу ровно, ни больше ни меньше. */
  /* Обёртка страницы печати на бумаге не нужна: её отступы уводили лист
     вниз, и после каждого разрыва оставалась лишняя пустая страница. */
  .print-wrap { padding: 0 !important; }
  html, body { margin: 0 !important; }
  .print-doc.print-catalog { padding: 0; margin: 0; }
  /* 270 мм, а не 273: браузер округляет миллиметры в точки, и лист ровно в
     размер печатной области иногда переваливал на страницу вперёд — в PDF
     появлялись пустые листы через один (v6.14.4). Три миллиметра запаса
     стоят дешевле, чем пустая страница в каталоге. */
  .cat-page { width: 100%; height: 270mm; min-height: 0; margin: 0; padding: 0;
              overflow: hidden; break-inside: avoid; page-break-inside: avoid;
              break-after: page; page-break-after: always; box-shadow: none; }
  .cat-page:last-child { break-after: auto; page-break-after: auto; }
  .cat-warn { display: none; }
  /* Цвет шапки и жёлтой полосы должен печататься, а не выцветать */
  .cat-rule, .cat-cell, .cat-shot, .cat-foot, .cat-shot img {
      -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ================================================================
 * ЗАДАЧИ 2.0 (v6.15.0): умные списки слева, доска по стадиям справа
 * ================================================================
 * Важность — цветом флажка на карточке, стадия — столбцом. Автозадача
 * отличается сразу: шестерёнка перед названием, пунктирная рамка, зелёная
 * подпись с причиной. Ни одной картинки и ни одного внешнего шрифта.
 */
/* ПАНЕЛЬ ОТБОРОВ УЖЕ, СТОЛБЦЫ ШИРЕ (v6.50.2, ответ заказчика «да» на
   предложение отдать место доске).

   Отборы — это список коротких слов («Сегодня», «Просрочено», «Все мои») с
   числом справа; им хватает 168 точек. Доска рядом — то, ради чего страницу
   открывают, и каждая отданная ей точка идёт в названия задач: при 200
   столбец был 247 точек, и название ломалось на три строки по одному слову.
   Ширина задана переменной: на широком мониторе панель остаётся прежней, а
   всё лишнее место опять-таки достаётся столбцам. */
.tk-wrap { display: grid; grid-template-columns: 168px minmax(0, 1fr); gap: 12px; align-items: start; }
.tk-side { position: sticky; top: 64px; display: flex; flex-direction: column; gap: 12px; }
.tk-group { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 6px; }
.tk-group-h { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); padding: 6px 8px 4px; }
.tk-list { display: flex; flex-direction: column; gap: 1px; }
.tk-list a {
  display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 6px;
  color: var(--text); font-size: 13px; text-decoration: none;
}
.tk-list a:hover { background: var(--surface-2); }
.tk-list a.active { background: var(--accent-soft); color: var(--accent-dark); font-weight: 600; }
.tk-list a .n { margin-left: auto; font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.tk-list a.active .n { color: var(--accent-dark); }
.tk-list a.neg-n .n { color: var(--red); font-weight: 700; }
.tk-tag { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; padding: 1px 7px; border-radius: 10px;
          background: var(--surface-2); color: var(--text-2); border: 1px solid var(--border); text-decoration: none; }
.tk-tag i { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }
.tk-tag.active { border-color: var(--accent); color: var(--accent-dark); }
.tk-tags { display: flex; flex-wrap: wrap; gap: 4px; padding: 2px 8px 6px; }

.tk-quick { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; }
.tk-quick input[type=text] { flex: 1; min-width: 0; }
.tk-quick .hint { display: none; }
.tk-quick-hint { font-size: 11px; color: var(--muted); margin: -6px 0 12px; }
/* Подсказка при наборе «+» / «@» и переспрос «какой Вася» (v6.15.3) */
.tk-quick-box { flex: 1; min-width: 0; position: relative; }
.tk-quick-box input[type=text] { width: 100%; }
/* НА КАРТОЧКЕ КЛИЕНТА СТРОКА КОРОЧЕ, А КНОПКА — РЯДОМ С НЕЙ (v6.22.1).
   Замечание заказчика: «кнопка „Поставить“ уехала в правый край, сделай поле
   уже и кнопку подвинь левее». Поле растягивалось на всю ширину карточки, и
   между концом набранного текста и кнопкой оставалась половина экрана
   пустоты: глаз читал их как две несвязанные вещи. */
/* Поле ввода задачи по клиенту — во всю ширину карточки (макет 78, 3-B,
   v6.105.0). Было ограничено 560px и прижато влево: на широком экране поле
   оказывалось куда короче блока. Кнопка «Поставить» держится справа. */
.tk-quick-client .tk-quick-box { flex: 1 1 auto; }
/* Пусто: компактно, без высокой «дыры» (макет 78, 3-B). */
.tk-empty { display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 7px; text-align: center; color: var(--muted); padding: 16px 0 18px; }
.tk-empty .ic { width: 26px; height: 26px; opacity: .4; }
.tk-divider { height: 1px; background: var(--border); margin: 6px 0 14px; }
/* Таблица задач во всю ширину карточки с обычными отступами тела (3-B). */
.tk-bleed { margin: -16px -16px 0; }
.tk-suggest { position: absolute; left: 0; top: 100%; z-index: 30; min-width: 240px; max-width: 100%;
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,.12); padding: 4px; margin-top: 2px; }
.tk-suggest button { display: block; width: 100%; text-align: left; background: none; border: 0;
  padding: 6px 10px; border-radius: 6px; font: inherit; color: inherit; cursor: pointer; }
.tk-suggest button:hover, .tk-suggest button.is-on { background: var(--accent-soft); }
.tk-suggest .tk-suggest-kind { font-size: 11px; color: var(--muted); padding: 4px 10px 2px; }
.tk-ambiguous { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: -4px 0 12px;
  padding: 8px 12px; border: 1px solid #f0d48a; background: var(--amber-soft); border-radius: 8px; }
.tk-ambiguous form { display: inline; }
/* Задача / встреча (v6.16.0) */
/* Свёрнутые редкие поля окна «Новая задача» (v6.49.0, п.3 заказчика:
   «слишком большая и запутанная, сделать раскрывающиеся поля»). Строка
   выглядит как строка, а не как кнопка: это не действие, а «показать
   остальное». Раскрытое содержимое отбито сверху чертой, чтобы не слипалось
   с обязательными полями. */
.tk-more { margin-top: 14px; border-top: 1px solid var(--border); padding-top: 10px; }
.tk-more > summary { cursor: pointer; font-size: 13px; color: var(--accent-dark);
  list-style: none; display: flex; align-items: center; gap: 6px; padding: 2px 0; }
.tk-more > summary::-webkit-details-marker { display: none; }
.tk-more > summary::before { content: '▸'; font-size: 11px; transition: transform .15s ease; }
.tk-more[open] > summary::before { transform: rotate(90deg); }
.tk-more[open] > summary { margin-bottom: 10px; }
.tk-kind { display: inline-flex; align-self: flex-start; border: 1px solid var(--border-strong); border-radius: 8px; overflow: hidden; }
.tk-kind-opt { position: relative; }
.tk-kind-opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.tk-kind-opt span { display: block; padding: 6px 14px; font-size: 13px; cursor: pointer; color: var(--text-2); }
.tk-kind-opt input:checked + span { background: var(--accent); color: #fff; }
.tk-kind-opt input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: -2px; }
.tk-meet-badge { color: var(--violet); margin-right: 2px; }
/* «Жду ответа: от кого и до когда» — своей строкой под полосой стадий (v6.16.0) */
.tk-waitbox { flex-basis: 100%; }
.tk-waitbox summary { display: inline-flex; list-style: none; cursor: pointer; }
.tk-waitbox summary::-webkit-details-marker { display: none; }
.tk-waitbox[open] { background: var(--surface-2); border: 1px solid var(--border); border-radius: 10px; padding: 8px 10px; }
.tk-waitbox .tk-inline { margin-top: 8px; }
.tcard.tmeet .tname { color: var(--violet); }

/* ===== КАЛЕНДАРЬ (v6.16.0) ===== */
.cal-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.cal-title { margin: 0 4px; font-size: 18px; min-width: 160px; }
.cal-month { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
.cal-wd { background: var(--surface-3); padding: 6px 8px; font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); font-weight: 600; }
.cal-day { background: var(--surface); min-height: 118px; padding: 4px 6px 6px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.cal-day.cal-out { background: var(--surface-2); }
.cal-day.cal-out .cal-num { color: var(--muted); }
.cal-day.cal-weekend .cal-num { color: var(--red); }
.cal-day.cal-today .cal-num { background: var(--accent); color: #fff; border-radius: 12px; padding: 0 7px; }
.cal-day.drop-on, .cal-allday-cell.drop-on, .cal-col.drop-on { outline: 2px dashed var(--accent); outline-offset: -3px; background: var(--accent-soft); }
.cal-day-h { display: flex; align-items: center; justify-content: space-between; }
.cal-num { font-size: 13px; font-weight: 600; line-height: 22px; }
.cal-add { border: 0; background: none; color: var(--muted); font-size: 16px; line-height: 1; width: 22px; height: 22px; border-radius: 6px; cursor: pointer; opacity: 0; }
.cal-day:hover .cal-add, .cal-wd:hover .cal-add, .cal-add:focus-visible { opacity: 1; }
.cal-add:hover { background: var(--accent-soft); color: var(--accent); }
.cal-items { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cal-item { display: flex; align-items: center; gap: 4px; min-width: 0; font-size: 12px; line-height: 1.3; padding: 2px 6px; border-radius: 6px;
  background: var(--surface-3); color: var(--text); text-decoration: none; border-left: 3px solid var(--grey); cursor: grab; }
.cal-item:hover { background: var(--accent-soft); text-decoration: none; }
.cal-item b { font-weight: 600; flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.cal-item span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-item i { font-style: normal; color: var(--muted); flex: 0 0 auto; font-size: 11px; }
.cal-item.cal-p-high { border-left-color: var(--red); }
.cal-item.cal-p-important { border-left-color: var(--amber); }
.cal-item.cal-p-mid { border-left-color: var(--accent); }
.cal-item.cal-p-low { border-left-color: var(--grey); }
.cal-item.cal-meet { background: var(--violet-soft); border-left-color: var(--violet); }
.cal-item.cal-meet span svg { color: var(--violet); vertical-align: -2px; margin-right: 2px; }
.cal-item.cal-done { opacity: .55; text-decoration: line-through; cursor: default; }
.cal-item.dragging { opacity: .4; }
.cal-more { font-size: 11px; color: var(--accent); padding-left: 6px; }
.cal-legend { display: flex; gap: 14px; font-size: 12px; color: var(--muted); margin-top: 10px; flex-wrap: wrap; }
.cal-legend span { display: inline-flex; align-items: center; gap: 5px; }
.cal-dot { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.cal-dot.cal-p-high { background: var(--red); } .cal-dot.cal-p-important { background: var(--amber); }
.cal-dot.cal-p-mid { background: var(--accent); } .cal-dot.cal-p-low { background: var(--grey); }

/* неделя по часам */
.cal-week { border: 1px solid var(--border); border-radius: 12px; overflow: hidden; background: var(--surface); }
.cal-week-head, .cal-allday, .cal-grid { display: grid; grid-template-columns: 64px repeat(7, minmax(0, 1fr)); }
.cal-week-head .cal-wd { display: flex; align-items: center; gap: 6px; border-left: 1px solid var(--border); }
.cal-week-head .cal-wd b { font-size: 14px; color: var(--text); }
.cal-week-head .cal-wd.cal-today b { background: var(--accent); color: #fff; border-radius: 12px; padding: 0 7px; }
.cal-gutter { font-size: 11px; color: var(--muted); padding: 4px 6px; text-align: right; }
.cal-allday { border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); background: var(--surface-2); }
.cal-allday-cell { min-height: 30px; padding: 3px 4px; display: flex; flex-direction: column; gap: 3px; border-left: 1px solid var(--border); min-width: 0; }
.cal-grid { position: relative; }
.cal-grid .cal-gutter { padding: 0; }
.cal-hour { height: var(--hour); font-size: 11px; color: var(--muted); text-align: right; padding-right: 6px; transform: translateY(-7px); }
.cal-col { position: relative; border-left: 1px solid var(--border); height: calc(var(--hour) * var(--hours)); min-width: 0; }
.cal-col.cal-today { background: #fbfcff; }
.cal-hline { height: var(--hour); border-top: 1px solid var(--surface-3); }
.cal-slot { position: absolute; left: 3px; right: 3px; display: flex; }
.cal-slot .cal-item { flex: 1; min-width: 0; align-items: flex-start; flex-wrap: wrap; height: 100%; overflow: hidden; }
.cal-slot .cal-item span { white-space: normal; }
@media (max-width: 900px) {
  .cal-month { grid-template-columns: repeat(7, minmax(0, 1fr)); }
  .cal-day { min-height: 70px; padding: 2px 3px; }
  .cal-item { font-size: 10px; padding: 1px 3px; }
  .cal-item b, .cal-item i { display: none; }
  .cal-week-head, .cal-allday, .cal-grid { grid-template-columns: 44px repeat(7, minmax(0, 1fr)); }
}

.tk-board { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; align-items: start; }
/* «ГОТОВО» НЕ ДЕРЖИТ ЧЕТВЕРТЬ ДОСКИ (v6.49.0, предложение 32).
   Столбец завершённых свёрнут по умолчанию, но место под себя резервировал
   всё равно — четверть ширины на широком мониторе уходила под то, что уже
   сделано. Свёрнут — становится узкой рейкой, а три рабочих столбца, между
   которыми карточки действительно таскают, забирают освободившееся место.
   Развернули — доска возвращается к четырём равным столбцам. */
/* С 6.139.0 (макет 162, слово Игоря: «прямо чисто слово готово… просто
   готово и число») — рейка по ширине «Готово 12», без стрелки. */
.tk-board-narrow { grid-template-columns: repeat(3, minmax(0, 1fr)) max-content; }
.tk-board-narrow .tk-col-done { min-height: 0; cursor: pointer; }
.tk-board-narrow .tk-col-done .tk-col-h { padding: 8px 12px; gap: 6px; }
.tk-board-narrow .tk-col-done .tk-col-h b { font-size: 12.5px; }
.tk-board-narrow .tk-col-done .tk-fold { display: none; }
.tk-board-narrow .tk-col-done .tk-col-n { margin-left: 0; }
.tk-col { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); min-height: 120px; }
.tk-col-h { display: flex; align-items: center; gap: 8px; padding: 8px 10px; font-size: 13px; border-bottom: 1px solid var(--border); }
.tk-col-h b { font-weight: 700; }
.tk-col-n { margin-left: auto; color: var(--muted); font-size: 12px; }
.tk-col-todo .tk-col-h b { color: var(--text); }
.tk-col-doing .tk-col-h b { color: var(--accent-dark); }
.tk-col-waiting .tk-col-h b { color: var(--amber); }
.tk-col-done .tk-col-h b { color: var(--green); }
.tk-col-list { display: flex; flex-direction: column; gap: 6px; padding: 8px; min-height: 60px;
  border-radius: 0 0 var(--radius) var(--radius); }
/* ЦВЕТ У КАЖДОГО СТОЛБЦА СВОЙ (v6.17.3, слово заказчика: «раньше подсвечивался
   задний фон колонки, сейчас они одинаковые»). Красится ТОЛЬКО поле под
   карточками, заголовок остаётся общим — иначе доска рябит. Тона взяты
   бледные: они подсказывают состояние боковым зрением и не спорят с
   карточками, которые на них лежат.
     Сделать    — без цвета: это «ещё не начали», и красить нечего;
     В работе   — голубой;
     Жду ответа — тёплый песочный;
     Готово     — зеленоватый. */
.tk-col-doing   .tk-col-list { background: #eef4ff; }
.tk-col-waiting .tk-col-list { background: #fdf6ea; }
.tk-col-done    .tk-col-list { background: #edf8f2; }
.tk-col-list.drag-over { outline: 2px dashed var(--accent); outline-offset: -4px; border-radius: 6px; }
.tk-col-done .tcard { opacity: .75; }
.tk-col-done .tname { text-decoration: line-through; color: var(--muted); }

.tcard-2 { display: block; padding: 7px 9px; }
.tcard-top { display: flex; align-items: flex-start; gap: 6px; }
.tcard-top .tname { flex: 1; min-width: 0; }
.tcard-top .tflag { margin-top: 2px; }
.tcard-top .tgrip { margin-top: 2px; }
.tcard-2 .tbody { padding-left: 0; }
.tcard-2 .tmeta { margin-top: 4px; }
/* ВАЖНОСТЬ ВИДНО ИЗДАЛИ (v6.15.1, просьба заказчика: «флажок сделай более
   выделенным: заполнить, потолще, или цвет рамки»). Флажок залит цветом и
   обведён толще, а слева у карточки — полоса того же цвета: её видно даже
   когда флажок не разглядеть. */
.tcard .tflag { flex: 0 0 auto; display: inline-flex; color: var(--border-strong); }
.tcard .tflag svg { fill: currentColor; stroke-width: 2.2; }
.tcard-2 { border-left-width: 4px; }
.tcard.tp-high .tflag, .tcard-legend.tp-high .tflag { color: var(--red); }
.tcard.tp-important .tflag, .tcard-legend.tp-important .tflag { color: var(--amber); }
.tcard.tp-mid .tflag, .tcard-legend.tp-mid .tflag { color: var(--accent); }
.tcard.tp-low .tflag, .tcard-legend.tp-low .tflag { color: var(--muted); }
.tcard-legend .tflag svg { fill: currentColor; stroke-width: 2.2; }
/* Тройной отбор — сильнее рамки автозадачи, которая задаёт цвет всех сторон */
.tcard.tcard-2.tp-high { border-left-color: var(--red); border-left-style: solid; }
.tcard.tcard-2.tp-important { border-left-color: var(--amber); border-left-style: solid; }
.tcard.tcard-2.tp-mid { border-left-color: var(--accent); border-left-style: solid; }
.tcard.tcard-2.tp-low { border-left-color: var(--border-strong); border-left-style: solid; }
.tcard .tname .ic-sm { vertical-align: -3px; margin-right: 3px; }
.tcard.tauto { border-style: dashed; border-color: #9fd3b8; background: #fbfefc; }
.tauto-why { display: block; font-size: 11px; color: var(--green); margin-top: 2px; }
.tk-people { display: inline-flex; gap: 2px; }
.tk-ava {
  width: 20px; height: 20px; border-radius: 50%; background: var(--accent-soft); color: var(--accent-dark);
  font-size: 10px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid #c7d9fb;
}
.tk-check { display: flex; flex-direction: column; gap: 4px; margin: 4px 0 0; padding: 0; list-style: none; font-size: 12px; }
.tk-check li { display: flex; align-items: center; gap: 6px; color: var(--text-2); }
.tk-check li.done { color: var(--muted); text-decoration: line-through; }
.tk-wait { font-size: 12px; color: var(--amber); }
.tstage-add {
  margin-left: 6px; width: 20px; height: 20px; padding: 0; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 6px; cursor: pointer; background: var(--accent); color: #fff;
}
.tstage-add:hover { background: var(--accent-dark); }

/* Продление договора одной строкой (v6.16.4) */
.renew-form { display: inline-flex; align-items: center; gap: 4px; margin-right: 4px; }
.renew-date { width: 140px; padding: 3px 6px; font-size: 12px; }

/* Доступы в кабинет: поля и кнопки на одной линии (v6.16.5) */
.pa-actions { display: flex; flex-direction: column; gap: 8px; min-width: 340px; }
.pa-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
/* Кнопки в строке — одного роста и одной «весовой категории» (v6.17.0,
   замечание заказчика: «синяя и красная большие, а белая посередине
   маленькая»): одинаковые поля и минимальная ширина. */
.pa-row .btn { min-width: 150px; justify-content: center; padding: 0 14px; }
.pa-row form { display: contents; }
.pa-field { display: flex; flex-direction: column; gap: 2px; }
.pa-field label { font-size: 11px; color: var(--muted); line-height: 1.2; }
/* Все четыре поля строки одной ширины (v6.17.0, замечание заказчика:
   «одно короче, одно длиннее») */
.pa-field input { padding: 5px 8px; font-size: 13px; height: 32px; width: 168px; }
.pa-field input:disabled { background: var(--surface-2); color: var(--muted); cursor: not-allowed; }
/* Кнопка ровно такой же высоты, как поле рядом (v6.17.0, замечание
   заказчика: «кнопка ниже, чем поле») */
.pa-row .btn, .pa-row .btn-sm { align-self: flex-end; }
/* Галочка «сменить при входе» стоит ровно по центру поля рядом (v6.17.0,
   замечание заказчика: «как-то криво стоит»): та же высота, что у поля,
   середина к середине, без чужих отступов. */
.pa-force { align-self: flex-end; height: 32px; margin: 0; padding: 0;
  display: inline-flex; align-items: center; gap: 6px; line-height: 1; }
.pa-force input { margin: 0; }
.pa-force span { line-height: 1; }
.pa-pass { display: flex; flex-direction: column; gap: 4px; }
/* Галочку «сменить при входе» это правило поднимало наверх строки (v6.17.2,
   замечание заказчика: «оно высоко, надо посередине поля»). Правило с двумя
   классами перебивало `.pa-force`, и галочка вставала вровень с подписью
   поля, а не с самим полем. Теперь исключение названо явно. */
.pa-pass .check:not(.pa-force) { align-self: flex-start; }
.pa-pass .pa-force { align-self: flex-end; }

/* Три действия одной полосой: равные по ширине и с одинаковым просветом
   (v6.17.2, замечание заказчика: «боковые кнопки больше, чем средняя, и
   расстояние разное»). Ширину задаёт полоса, а не длина слова внутри. */
.pa-btns { display: flex; gap: 14px; margin-top: 2px; }
.pa-btns .btn { flex: 1 1 0; min-width: 0; justify-content: center; }
/* На телефоне три кнопки поровну (`flex:1 1 0`) на всю ширину не делятся —
   самой длинной надписи, «Закрыть доступ», не хватало места, и она обрезалась
   до «Закрыть досту». Полоса была рассчитана на широкий стол (у `.pa-actions`
   свой минимум 340px), а не на карточку в 343px, где под неё нет запаса.
   Переносим лишние кнопки на свою строку вместо того, чтобы резать текст
   (найдено при 100%-проверке мобильной версии, 29.09.2026). */
@media (max-width: 480px) {
  .pa-actions { min-width: 0; }
  .pa-btns { flex-wrap: wrap; }
  .pa-btns .btn { flex: 1 1 auto; min-width: 130px; }
}

/* Кабинет выключен — настройки видны, но не трогаются (v6.16.5) */
.portal-off { opacity: .55; pointer-events: none; }

/* Адрес входа в кабинет с кнопкой «скопировать» (v6.16.4) */
.portal-link { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); padding: 8px 12px; }
.portal-link-url { font-family: var(--font-mono, ui-monospace, monospace); font-size: 13px; word-break: break-all; }

/* Средний срок оплаты — одной строкой (v6.16.4) */
.avg-pay .card-body { display: flex; align-items: baseline; gap: 10px 16px; flex-wrap: wrap; }
.avg-pay-label { color: var(--muted); font-size: 13px; }
.avg-pay-value { font-size: 20px; font-variant-numeric: tabular-nums; }
.avg-pay-note { color: var(--muted); font-size: 13px; }
.avg-pay-late .avg-pay-value { color: var(--amber); }

/* Список: те же столбцы друг под другом (v6.15.2) */
.tk-stack { display: flex; flex-direction: column; gap: 12px; }
/* Массовые действия и задача отдела (v6.17.0) */
.tk-bulk { position: sticky; top: 8px; z-index: 6; margin-bottom: 10px; }
.tk-bulk .card-body { align-items: flex-end; }
/* Счётчик отмеченных стоит в общей сетке полосы (v6.49.0, п.11 заказчика:
   «часть полей выше, часть ниже»). До этого он висел по центру строки
   (v6.17.3) — то есть третьим уровнем между подписями и полями. Теперь у него
   своя подпись, и полоса читается двумя ровными рядами: подписи и контролы.
   Высота значения равна высоте поля рядом, иначе число снова просядет. */
.tk-bulk-n { margin-right: 2px; }
.tk-bulk-count { height: 32px; display: flex; align-items: center;
  font-size: 18px; font-weight: 600; font-variant-numeric: tabular-nums; }
/* Тонкая черта делит полосу на группы «поле + его кнопка» (v6.49.0):
   без неё «Перенести срок» и «Передать» читались как общий ряд кнопок,
   не привязанный к полям слева. */
.pa-sep { align-self: flex-end; width: 1px; height: 24px; margin: 0 4px;
  background: var(--border); flex: none; }
.tk-pick { margin-top: 3px; flex: none; }
.tk-free { color: var(--amber); }

/* Свёрнутая секция списка (v6.16.3): видна шапка со счётчиком */
.tk-fold { border: 0; background: none; padding: 0; margin-right: 2px; color: var(--muted);
  cursor: pointer; display: inline-flex; align-items: center; transition: transform .15s ease; }
.tk-fold:hover { color: var(--text); }
.tk-sec.folded .tk-fold { transform: rotate(-90deg); }
.tk-sec.folded .tk-col-list { display: none; }
.tk-sec.folded { min-height: 0; }
.tk-sec.folded .tk-col-h { border-bottom: 0; }
.tk-stack .tk-col-list { min-height: 44px; }
.tk-stack .tcard-2 { padding: 8px 12px; }
.tk-stack .tcard-top .tname { font-size: 14px; }
.tk-stack .tmeta { gap: 4px 14px; }

/* Карточка задачи */
.tk-stages { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.tk-stages form { display: contents; }
.tk-stages button, .tk-stages span {
  border: 0; background: var(--surface); padding: 6px 12px; font-size: 13px; cursor: pointer; color: var(--text-2);
  border-right: 1px solid var(--border);
}
.tk-stages > *:last-child button, .tk-stages > span:last-child { border-right: 0; }
.tk-stages button:hover { background: var(--surface-2); }
.tk-stages .on { background: var(--accent); color: #fff; font-weight: 600; cursor: default; }
.tk-stages .on-done { background: var(--green); color: #fff; font-weight: 600; }
.tk-auto-box { border: 1px dashed #9fd3b8; background: #fbfefc; border-radius: var(--radius); padding: 10px 14px; margin-top: 12px; }
.tk-auto-box b { color: var(--green); }
.tk-hist { font-size: 12px; color: var(--muted); display: flex; flex-direction: column; gap: 4px; }
.tk-hist span b { color: var(--text-2); font-weight: 600; }
.tk-item { display: flex; align-items: center; gap: 8px; padding: 4px 0; border-bottom: 1px dashed var(--border); }
.tk-item:last-child { border-bottom: 0; }
.tk-item form { display: inline; }
.tk-item .tk-item-t { flex: 1; min-width: 0; }
.tk-item.done .tk-item-t { text-decoration: line-through; color: var(--muted); }
.tk-item .btn-ghost { padding: 2px 6px; }
.tk-mention { display: flex; gap: 6px; align-items: center; margin-top: 6px; font-size: 12px; color: var(--muted); }

.tk-legend { display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: 12px; color: var(--muted); padding: 4px 8px 6px; }
/* Важности — столбиком, как все списки слева (v6.17.3, замечание заказчика:
   «почему „Важные“ стоит справа, должно быть в ряд»). Четыре строки в две
   колонки выглядели как случайность, а не как список. */
.tk-legend.tk-prio { flex-direction: column; flex-wrap: nowrap; gap: 6px; }
.tk-legend span { display: inline-flex; align-items: center; gap: 4px; }

/* Правила автозадач */
.tk-rule { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 12px 20px; align-items: start; }
.tk-rule-when { font-size: 13px; color: var(--text-2); }
.tk-rule-when b { color: var(--text); }
.tk-rule-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 12px; }
.tk-rule-form .span-2 { grid-column: 1 / -1; }
.tk-rule-now { font-size: 12px; color: var(--muted); }
.tk-rule-now b { color: var(--accent-dark); }

/* Уже 1400 — четыре узких столбца не читаются: две строки по два */
@media (max-width: 1400px) {
  .tk-board { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.tk-inline { display: grid; grid-template-columns: minmax(180px, 1fr) 200px 150px auto; gap: 8px; align-items: center; }
.tk-inline-3 { grid-template-columns: 240px 150px auto; }
.tk-inline .combo, .tk-inline select, .tk-inline input { width: 100%; min-width: 0; }
.tk-inline .btn { width: auto; justify-self: start; }
/* Форма «поставить себе задачу» в карточке клиента (v6.16.1) */
.tk-inline-client { grid-template-columns: minmax(220px, 1fr) 160px 120px auto; padding: 10px 12px 12px; border-top: 1px solid var(--border); }
@media (max-width: 700px) { .tk-inline, .tk-inline-3 { grid-template-columns: 1fr; } }
@media (max-width: 860px) {
  .tk-wrap { grid-template-columns: 1fr; }
  /* На телефоне списки — полосой поперёк, а не столбом над доской: иначе
     до самой доски приходилось листать два экрана. Прокрутка внутри полосы,
     страница вбок не едет. */
  .tk-side { position: static; flex-direction: row; overflow-x: auto; gap: 8px; padding-bottom: 4px;
             -webkit-overflow-scrolling: touch; }
  .tk-group { flex: 0 0 auto; min-width: 150px; }
  .tk-list a { padding: 4px 8px; }
  .tk-tags { max-width: 260px; }
  .tk-rule { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .tk-board { grid-template-columns: 1fr; }
}

/* ================= ПОВЕСТКА ДНЯ (v6.17.4) =================
   Экран и бумага — одна разметка, разный вид. Экран: карточки системы,
   круглые кнопки-галочки, полоса прогресса. Бумага: документ с шапкой,
   квадратиками под ручку и подписью внизу; всё лишнее скрыто `no-print`.
   Заказчик: «чтобы форма печати была достойная, а не ободранное окошко». */
.print-only { display: none; }

.ag-day { display: inline-flex; align-items: center; gap: 6px; margin-right: 10px; }
.ag-day label { font-size: 12px; color: var(--muted); }
.ag-day input { height: 32px; padding: 4px 8px; }

.ag-top { display: grid; grid-template-columns: repeat(3, 108px) 1fr; gap: 12px;
  align-items: center; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 14px 16px; margin-bottom: 14px; box-shadow: var(--shadow-1); }
.ag-stat { text-align: center; border-right: 1px solid var(--border); }
.ag-stat:nth-child(3) { border-right: 0; }
.ag-stat-n { font-size: 24px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.ag-stat-w { font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.ag-prog { padding-left: 8px; }
.ag-prog-top { display: flex; justify-content: space-between; align-items: baseline;
  font-size: 13px; margin-bottom: 6px; }
.ag-prog-top span { color: var(--muted); font-variant-numeric: tabular-nums; }
.ag-bar { height: 8px; border-radius: 6px; background: var(--surface-3); overflow: hidden; }
.ag-bar i { display: block; height: 100%; background: var(--green); border-radius: 6px; }

.ag-grid { display: grid; grid-template-columns: 1.75fr 1fr; gap: 14px; align-items: start; }
.ag-main { display: flex; flex-direction: column; gap: 14px; }
.ag-sec { background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-1); overflow: hidden; }
.ag-h { margin: 0; padding: 11px 16px; font-size: 12.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em; color: var(--muted);
  border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 8px; }
.ag-n { margin-left: auto; font-size: 12px; font-weight: 600; color: var(--muted);
  background: var(--surface-3); border-radius: 20px; padding: 1px 9px; letter-spacing: 0; }
.ag-list { list-style: none; margin: 0; padding: 0; }
.ag-row { display: flex; gap: 12px; align-items: flex-start; padding: 11px 16px;
  border-bottom: 1px solid var(--border); }
.ag-row:last-child { border-bottom: 0; }
.ag-row:hover { background: var(--surface-2); }
.ag-body { flex: 1 1 auto; min-width: 0; }
.ag-title { font-size: 14px; font-weight: 600; line-height: 1.35; }
.ag-title a { color: var(--text); }
.ag-title a:hover { color: var(--accent); text-decoration: none; }
.ag-note { color: var(--muted); font-size: 12px; margin-top: 2px; }
.ag-empty { color: var(--muted); padding: 16px; font-size: 13px; }

/* Встреча: время — крупно и слева, как в расписании */
.ag-time { flex: none; width: 62px; text-align: right; padding-top: 1px; }
.ag-time b { display: block; font-size: 15px; font-variant-numeric: tabular-nums; }
.ag-time span { display: block; font-size: 11px; color: var(--muted); }
.ag-meet { border-left: 3px solid var(--accent); }

/* Квадратик под галочку: на экране — намёк, на бумаге — рабочее поле */
.ag-box { flex: none; width: 16px; height: 16px; margin-top: 2px;
  border: 1.6px solid var(--border-strong); border-radius: 4px;
  display: inline-flex; align-items: center; justify-content: center; color: var(--green); }
.ag-box-done { border-color: var(--green); background: var(--green-soft); }

.ag-late { border-left: 3px solid var(--red); }
.ag-late-w { color: var(--red); font-weight: 600; }

/* Кнопка «сделано» — круглая, зелёная при наведении: это главное действие */
.ag-do { flex: none; }
.ag-check, .ag-undo { width: 30px; height: 30px; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface); color: var(--muted);
  display: inline-flex; align-items: center; justify-content: center; transition: .12s; }
.ag-check:hover { border-color: var(--green); background: var(--green-soft); color: var(--green); }
.ag-undo:hover { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }

/* Кому звонить: кружок с инициалами и телефон крупнее подписи */
.ag-ava { flex: none; width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent-dark); font-size: 11.5px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center; }
.ag-phone { font-size: 13.5px; font-variant-numeric: tabular-nums; margin-top: 1px; }

.ag-done-sec { margin-top: 14px; }
.ag-done .ag-title a { color: var(--muted); }

@media (max-width: 980px) { .ag-grid { grid-template-columns: 1fr; }
  .ag-top { grid-template-columns: repeat(3, 1fr); }
  .ag-prog { grid-column: 1 / -1; padding-left: 0; } }

/* ---------- Тот же лист на бумаге ---------- */
/* Шапка документа: вид описан здесь, а ПОКАЗЫВАЕТСЯ только на печати —
   иначе правило `display` перебило бы общий `.print-only { display: none }`,
   и шапка бумаги вылезла бы на экран (поймано на проверке). */
.ag-print-head { justify-content: space-between; align-items: flex-end;
  border-bottom: 2px solid #222; padding-bottom: 10px; margin-bottom: 14px; }
.ag-ph-company { font-size: 11px; text-transform: uppercase; letter-spacing: .1em; color: #555; }
.ag-ph-title { font-size: 21px; font-weight: 700; line-height: 1.15; margin-top: 2px; }
.ag-ph-sub { font-size: 12px; color: #444; margin-top: 2px; }
.ag-ph-right { text-align: right; }
.ag-ph-count { font-size: 30px; font-weight: 700; line-height: 1; }
.ag-ph-word { font-size: 10px; text-transform: uppercase; letter-spacing: .08em; color: #666; }
.ag-print-foot { margin-top: 16px; padding-top: 8px; border-top: 1px solid #bbb;
  font-size: 10px; color: #666; }

@media print {
  .print-only { display: block; }
  .ag-print-head { display: flex; }
  .ag-box.print-only { display: inline-flex; }

  .ag-grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: 16px; }
  .ag-main { gap: 12px; }
  /* Карточек на бумаге нет: секция — это заголовок и список под линейкой */
  .ag-sec { border: 0; border-radius: 0; box-shadow: none; background: none; }
  .ag-h { padding: 0 0 4px; border-bottom: 1px solid #333; color: #000; font-size: 10.5px; }
  .ag-n { background: none; color: #333; padding: 0; }
  .ag-row { padding: 5px 0; border-bottom: 1px solid #e0e0e0; background: none !important; }
  .ag-meet, .ag-late { border-left: 0; padding-left: 0; }
  .ag-title { font-size: 11.5pt; font-weight: 600; }
  .ag-title a, a { color: #000; text-decoration: none; }
  .ag-note { color: #555; font-size: 8.5pt; }
  .ag-time { width: 54px; }
  .ag-time b { font-size: 11.5pt; }
  .ag-box { width: 13px; height: 13px; border: 1.2px solid #333; border-radius: 2px; }
  .ag-ava { display: none; }
  .ag-phone { font-size: 10pt; font-weight: 600; }
  .ag-late-w { color: #000; font-weight: 700; }
  .ag-empty { padding: 6px 0; color: #666; font-size: 9pt; }
  /* Своего `@page` у плана дня больше нет (v6.53.7): это правило про весь
     лист, а не про раздел, и последнее в файле перебивало поля у бланков и
     у каталога. Поля задаются один раз, в общем блоке печати выше. */
}

/* Неразобранные списания (v6.17.6): действия в строку, чтобы разбирать
   быстро — сверху вниз, не открывая каждую операцию */
.sp-acts { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.sp-form { display: flex; gap: 6px; align-items: center; }
.sp-form select { height: 30px; padding: 3px 6px; font-size: 12.5px; max-width: 170px; }

/* Проведение возврата: выбор про остаток стоит рядом с кнопкой (v6.18.0).
   Заказчик: «либо оно может сразу при проводе ВН спрашивать». Вопрос — там
   же, где ответ: галочка слева от «Провести», одной высоты с кнопкой. */
.ret-post { display: inline-flex; align-items: center; gap: 10px; }
.ret-offset { display: inline-flex; align-items: center; gap: 6px; margin: 0;
  padding: 4px 10px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface-2); line-height: 1.15; cursor: pointer; }
.ret-offset input { margin: 0; }
.ret-offset .xs { display: block; }

/* ВОЗВРАТ ИДЁТ С НАКЛАДНОЙ, А НЕ С ЦЕНЫ (v6.24.0, слово заказчика: «цена
   возврата тут вообще не нужна… а если он товар этот покупал по нескольким
   разным ценам?»). В строке возврата теперь выбирают документ, а цена
   приезжает из него — значит цена больше не поле, а число, и выглядеть она
   должна как число, а не как приглашение печатать. */
.ret-fromdoc { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ret-fromdoc select { flex: 1 1 280px; min-width: 0; max-width: 460px; }
/* Красным помечается то, что система не примет: пустая цена, цена, по которой
   продаж не было, товар, который клиент вовсе не покупал, и количество больше
   отправленного. Форма с такой строкой не отправляется (v6.24.2). */
#itemsBody .price.is-bad,
#itemsBody .qty.is-bad { border-color: var(--danger, #dc2626); background: #fff5f5; }
.price-note { display: block; text-align: right; margin-top: 2px; }

/* Цена прайса ниже закупки видна в самом поле (v6.24.2, слово заказчика:
   «если я задаю прайс, который ниже себестоимости, чтобы оно мне прыгало
   сразу»). Красная наценка в колонке через две от поля этого не делала:
   при вводе смотрят на поле. */
input.pl-price.is-bad { border-color: var(--danger, #dc2626); background: #fff5f5; }

/* «Удалить заказ» и объяснение рядом (v6.24.2, вопрос заказчика: «в чём
   отличается отменить заказ сверху и удалить заказ снизу?»). Кнопка стоит
   внизу и отдельно нарочно: удаление — не шаг сделки, а признание, что
   заказа не должно было быть. */
.order-danger { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 14px; }
.order-danger .xs { max-width: 640px; }
.qty-max { display: block; text-align: right; margin-top: 2px; }
/* «Кому мы должны»: взаимозачёт отдельной строкой под выплатой (v6.18.0) —
   это другое действие, и слипаться с кнопкой «Выплачено» оно не должно */
.pa-offset { margin-top: 8px; }
/* .pa-offset .btn — высота обычная (v6.23.4) */

/* «Кубиками» — в строке с подписью поля, у правого края (v6.24.3, слово
   заказчика: «кубиками плохо расположено»). Под полем поиска кнопка читалась
   как «применить поиск», а это второй способ выбрать тот же товар. */
.tr-pick-head { display: flex; align-items: center; gap: 10px; }
.tr-pick-head label { margin: 0; }
.tr-pick-head .btn { margin-left: auto; }

/* Строка «Добавить товар» у поставщика (макет 38, 01.10.2026): подпись
   отдельной строкой, ниже — поиск на всю ширину карточки и кнопки у правого
   края. Не .tr-pick-head — там правило margin-left:auto на кнопке рассчитано
   на одну кнопку и ломается, если их две (см. комментарий в
   views/suppliers/show.php). На узких экранах строка переносится так же, как
   .card-head. */
.tr-pick-row { margin-top: 14px; padding: 0 16px 16px; }
.tr-pick-row > label { display: block; margin: 0 0 8px; font-weight: 600; }
.tr-pick-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.tr-pick-bar .global-search { flex: 1 1 auto; max-width: none; }
.tr-pick-actions { display: flex; gap: 10px; flex: 0 0 auto; }

/* Группировка «бренд → категория» в товарах поставщика (v6.86.0, фон строки
   категории — v6.91.0, п. «й» разбора 02.10, слово заказчика: «строки
   категорий — жирным и с серым фоном»). Бренд — заметнее (фон темнее,
   прописные), категория — своим, светлее, фоном и отступом, чтобы было
   видно, что она вложена в бренд, а не стоит с ним на равных; жирность у
   обеих теперь одинаковая. */
.tr-group td { padding: 7px 10px; font-weight: 600; }
.tr-group-brand td { background: var(--surface-3); text-transform: uppercase; font-size: 12px; letter-spacing: .02em; }
.tr-group-category td { padding-left: 26px; background: var(--surface-2); color: var(--text); font-size: 12.5px; }
.col-photo { width: 52px; }

/* Категория товаров поставщика — схлопнута по умолчанию, раскрывается
   кликом (v6.94.1, слово заказчика: «список может быть бесконечный»). */
.tr-group-category[data-cat-toggle] { cursor: pointer; user-select: none; }
.tr-group-category[data-cat-toggle]:hover td { background: var(--surface-3); }
.tr-group-category .cat-chevron { transition: transform .12s ease; vertical-align: -2px; }
.tr-group-category.is-open .cat-chevron { transform: rotate(90deg); }

/* Перемещение между складами: нехватка видна ДО кнопки (v6.19.0).
   Заказчик: «мне надо уже на этапе до нажатия „Переместить“, чтобы красным
   подсвечивалось: столько остатка нет». */
.tr-qty.is-bad { border-color: var(--danger, #dc2626); background: #fff5f5; }
.tr-err { color: var(--danger, #dc2626); font-size: 11.5px; min-height: 14px; text-align: right; }
.tr-note { color: var(--danger, #dc2626); font-size: 12.5px; margin-right: auto; }
/* «Этот товар есть ещё на другом складе» (v6.19.0). Серым это читалось как
   справка и проходило мимо; оранжевым — как замечание, ради которого стоит
   заглянуть на соседний склад. */
.wh-else { display: block; color: var(--amber, #b45309); font-weight: 600; text-decoration: none; }
.wh-else:hover { text-decoration: underline; color: var(--amber, #b45309); }

/* ПЕРЕКЛЮЧАТЕЛЬ СКЛАДОВ — СЕГМЕНТИРОВАННЫЙ (v6.20.0, выбор заказчика из пяти
   показанных вариантов). Одна группа-тумблер: видно, что это кнопки, а не
   строка текста; выбранный склад — белой плашкой, у каждого свой остаток.
   Верх страницы остался прежними плитками — «верхнюю часть не трогай». */
.wh-seg { display: inline-flex; flex-wrap: wrap; gap: 2px; padding: 4px; margin-bottom: 14px;
  background: var(--surface-3, #eef0f4); border-radius: 11px; }
.wh-seg-u { display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px;
  border-radius: 8px; font-size: 13.5px; color: var(--text-2, #4b5563); text-decoration: none; }
.wh-seg-u:hover { color: var(--text); text-decoration: none; }
.wh-seg-u.on { background: var(--surface, #fff); color: var(--text); font-weight: 600;
  box-shadow: 0 1px 3px rgba(16,24,40,.12); }
.wh-seg-u .b { background: var(--border); color: var(--text); border-radius: 20px;
  padding: 1px 8px; font-size: 12px; font-variant-numeric: tabular-nums; }
.wh-seg-u.on .b { background: var(--accent); color: #fff; }
.wh-seg-u.zero .b { color: var(--muted); }
.wh-seg-u.on.zero .b { color: #fff; }

/* Календарь: понедельник первым, по-русски, только дни своего месяца
   (v6.19.0, слово заказчика). Родное окно браузера этого не умеет —
   ни первого дня недели, ни языка, ни «без чужих чисел». */
/* Родное окно выбора даты не открывается нигде: календарь у нас свой
   (v6.19.0, ставится до разбора страницы с v6.20.0 — иначе первые мгновения
   после загрузки клик открывал родное окно, «сентябрь на английском»). */
input[type=date]::-webkit-calendar-picker-indicator { display: none; }
/* ОКНО ВЫБОРА ДАТЫ. ВСЕ ПРАВИЛА — ТОЛЬКО ВНУТРИ НЕГО (v6.22.3).
 *
 * Замечание заказчика со снимком: «посмотри календарь, неделя — очень криво
 * выглядит».
 *
 * Причина не в неделе. Окно выбора даты (v6.20.0) назвало свои части теми же
 * словами, что и календарь задач: `.cal-grid`, `.cal-head`, `.cal-foot`,
 * `.cal-title`, `.cal-nav`. Строка `.cal-dow, .cal-grid { grid-template-
 * columns: repeat(7, 1fr) }` стоит НИЖЕ по файлу, чем сетка недели
 * (`64px repeat(7, …)`), — и переопределяла её.
 *
 * Получалось так: шапка недели оставалась с колонкой времени слева, а сама
 * сетка часов — без неё. Дни разъезжались с числами над ними, полоса «07:00»
 * налезала на понедельник. На месяце и на доске этого не видно: там сетка
 * другая, — поэтому и заметили только сейчас.
 *
 * Лечение — приписка `.cal` перед каждым правилом окна: они перестают
 * доставать до чего-либо за его пределами. Само окно — `<div class="cal">`,
 * так что ничего в разметке менять не пришлось. */
.cal {
  position: fixed; z-index: 2200; width: 258px; padding: 10px;
  background: var(--surface, #fff); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: 0 12px 32px rgba(16,24,40,.18);
}
.cal .cal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.cal .cal-title { font-weight: 700; font-size: 13.5px; }
.cal .cal-nav {
  width: 26px; height: 26px; border: 1px solid var(--border); border-radius: 7px;
  background: var(--surface, #fff); color: var(--text); cursor: pointer; font-size: 15px; line-height: 1;
}
.cal .cal-nav:hover { border-color: var(--accent); color: var(--accent); }
.cal .cal-dow, .cal .cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal .cal-dow span { text-align: center; font-size: 11px; color: var(--muted); padding: 2px 0 4px; }
.cal .cal-dow span.we { color: var(--red, #dc2626); }
.cal .cal-d {
  height: 30px; border: 0; border-radius: 8px; background: transparent; cursor: pointer;
  font-size: 13px; color: var(--text); font-variant-numeric: tabular-nums;
}
.cal .cal-d:hover { background: var(--surface-3, #eef0f4); }
.cal .cal-d.we { color: var(--red, #dc2626); }
.cal .cal-d.now { box-shadow: 0 0 0 1px var(--accent) inset; }
.cal .cal-d.on { background: var(--accent); color: #fff; font-weight: 700; }
.cal .cal-d.off { color: var(--border); cursor: not-allowed; }
.cal .cal-d.off:hover { background: transparent; }
.cal .cal-x { height: 30px; }
.cal .cal-foot { display: flex; gap: 8px; margin-top: 8px; border-top: 1px solid var(--border); padding-top: 8px; }
.cal .cal-btn {
  flex: 1; height: 28px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface, #fff); color: var(--text); cursor: pointer; font-size: 12.5px;
}
.cal .cal-btn:hover { border-color: var(--accent); color: var(--accent); }
/* Кнопки под формой — одного роста и ширины (v6.19.0, замечание заказчика:
   «кнопка отмены меньше, чем „Списать“ — сделай равномерные») */
/* Кнопки под формой — одной ширины и обычной высоты (v6.19.0, замечание
   заказчика «кнопка отмены меньше, чем „Списать“»; высота выровнена в
   v6.23.4: своя, 38-я, была четвёртым размером в системе). */
.form-actions .btn { min-width: 150px; justify-content: center; }
/* Галочка в ряду фильтров стоит на линии полей, а не над ними (v6.19.0) */
.filters .pt-chk { display: flex; align-items: center; gap: 8px; height: 38px; margin: 0; }
/* Цена для излишка, которого не закупали (v6.19.1): отдельным блоком под
   таблицей, а не колонкой в каждой строке — спрашивают её редко. */
.cnt-price { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px; }
.cnt-price label { font-size: 12.5px; }

/* Таблица остатков: название тянется, служебные колонки не пляшут (v6.20.0,
   замечание заказчика: «зачем товар делает таким узким, а по складам таким
   широким… себестоимость ломается на два»). Заголовки не переносятся, ширина
   отдана названию — оно длинное и читается чаще всего. */
.stock-tbl th { white-space: nowrap; }
.stock-tbl .col-name { width: 40%; min-width: 260px; white-space: normal; }
.stock-tbl td.wh-cell { width: 250px; }
.stock-tbl th.num, .stock-tbl td.num { width: 120px; }
/* Отмена описи спрашивает причину в одну строку (v6.20.0) */
.cnt-cancel { display: inline-flex; gap: 6px; align-items: center; }
.cnt-cancel input { height: 34px; width: 190px; padding: 4px 8px; font-size: 13px; }

/* Синяя полоса с долгом клиента в новом заказе (v6.22.0).
 *
 * Заказчик, второй раз и со снимком: «наведи порядок, пусть это будет в одной
 * строке». Первая правка не сработала, и вот почему: полоса — это `.alert`, а
 * у него есть общее правило `.alert > :not(svg) { flex: 1 1 220px }` — оно
 * растягивает КАЖДОГО прямого ребёнка минимум на двести двадцать пикселей.
 * Куски «Задолженность: 44 902,08» и точки-разделители стали такими детьми и
 * расползлись по всей ширине, а между ними повисли одинокие точки.
 *
 * Здесь это правило перебивается: куски занимают ровно свою ширину и стоят
 * подряд, одной строкой. Перенос остаётся только на узком экране — и тогда
 * переносится целая пара «подпись — число», а не половина. */
.ci-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; }
.ci-line > .ci-part,
.ci-line > .ci-sep { flex: 0 0 auto; }
.ci-part { white-space: nowrap; }
.ci-sep { color: var(--muted); opacity: .6; }

/* Листание длинной таблицы в браузере (v6.21.3, просьба заказчика про
   склады доставки: «если там больше 10, сделай список страниц»). */
.tbl-pager { display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--border); }
.tbl-pager-count { font-size: 12.5px; color: var(--muted); }
.tbl-pager-btns { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.tbl-pager-gap { color: var(--muted); padding: 0 2px; }

/* Переключатель вида в левой колонке задач (v6.21.3, просьба заказчика
   «убрать налево»). Кнопки в столбик: колонка узкая, в строку они не
   помещаются и переносятся вразнобой. */
/* СПИСОК ОБОРУДОВАНИЯ В ОКНЕ ПЕРЕДАЧИ — СВОЯ ВЫСОТА И СВОЯ ПРОКРУТКА
   (v6.22.2, слово заказчика: «сделай ограниченное размером окно, где 5–8
   позиций, чтобы не уходило ниже страницы, плюс возможность прокручивать —
   сразу чтобы было видно, кто есть куда»). 300 пикселей — это ровно семь
   строк плюс шапка: восьмая видна наполовину, и по ней сразу понятно, что
   список продолжается. Шапка при прокрутке остаётся на месте. */
.eq-scroll { max-height: 300px; overflow-y: auto; }
.eq-scroll thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--surface-3, #f1f3f6);
}

.tk-views { display: flex; flex-direction: column; gap: 4px; }
.tk-views .btn { justify-content: flex-start; }
/* Переключатель вида — строкой у левого края (v6.22.1, слово заказчика:
   «вернуть как было ранее и просто сдвинуть строку переключения вида к
   левому углу»). Три кнопки в столбик перестали читаться как один
   переключатель — а это именно он. */
.tk-views-row { flex-direction: row; gap: 6px; margin: 0 0 12px; }
.tk-views-row .btn { justify-content: center; }
/* Блок отборов на самом экране, а не окном поверх списка (v6.22.1).
   РАМКА КОНЧАЕТСЯ ТАМ ЖЕ, ГДЕ КНОПКИ (v6.22.2, замечание заказчика: «подогнать
   рамки блока выше, ближе к кнопкам показать/сбросить, а то он сильно уходит
   вниз ниже этих кнопок»). Уходила вниз подсказка про задачи без срока — её
   заказчик просил убрать, — а вместе с ней и низ рамки. */
.tk-filters { margin-bottom: 12px; padding-bottom: 12px; }

/* Подпись у поля «продлить до» в договорах (v6.21.3, вопрос заказчика). */
.renew-lbl { font-size: 11.5px; color: var(--muted); white-space: nowrap; }

/* ================================================================
   СИСТЕМА ГЛАЗАМИ ДРУГОГО (v6.28.0)
   Полоса вверху каждой страницы, пока включён режим просмотра.
   Цвет намеренно тревожный и не совпадает ни с одним рабочим
   состоянием: забытый режим не должен выглядеть частью интерфейса.
   ================================================================ */
.view-as-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 16px; padding: 10px 14px;
  border: 1px solid #b45309; border-left-width: 4px; border-radius: 8px;
  background: #fff7ed; color: #7c2d12; font-size: 13.5px;
}
.view-as-bar .view-as-eye { display: inline-flex; flex: 0 0 auto; }
.view-as-bar .muted { color: #9a5b32; }
.view-as-bar .btn { flex: 0 0 auto; }
[data-theme="dark"] .view-as-bar { background: #2a1a0d; color: #fbd7a5; border-color: #b45309; }
[data-theme="dark"] .view-as-bar .muted { color: #d8a878; }

/* Режим «глазами другого» с разрешёнными действиями (v6.29.0):
   цвет резче обычного — это уже не просмотр, а настоящая работа чужими
   правами, и путать её с безопасным режимом нельзя. */
.view-as-bar.view-as-live { background: #fee4e2; border-color: #b42318; color: #7a271a; }
[data-theme="dark"] .view-as-bar.view-as-live { background: #2e1210; color: #fbc9c4; border-color: #b42318; }

/* ------------------------------------------------------------------
   Логотип компании и цвет входа — настройки (v6.46.2)
   ------------------------------------------------------------------ */
.brand-set { display: flex; flex-direction: column; gap: 10px; }
.brand-preview {
  height: 110px; border: 1px dashed var(--border-strong); border-radius: var(--radius);
  display: flex; align-items: center; justify-content: center; padding: 14px;
  background: repeating-conic-gradient(var(--surface-3) 0% 25%, var(--surface) 0% 50%) 50% / 18px 18px;
}
.brand-preview img { max-height: 80px; max-width: 100%; object-fit: contain; }
.brand-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.brand-actions input[type=file] { width: auto; max-width: 420px; flex: 1 1 260px; }
/* Логотип в тёмной теме — образец на фоне меню «Графита» (v6.159.7) */
.brand-night { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border); }
.brand-preview.brand-preview-night { background: #3c3d40; border-color: #3c3d40; }
.brand-color { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 8px; }
.brand-color-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.brand-swatch { width: 28px; height: 28px; border-radius: 7px; border: 1px solid rgba(0,0,0,.08); flex: 0 0 auto; }

/* ------------------------------------------------------------------
   Страницы входа в стиле B3 (v6.46.2): логотип компании сверху,
   «працює на ЗВІРКА» снизу, кнопка и ссылки — в цвете компании.
   Цвет приходит переменными --brand / --brand-dark из BrandService.
   ------------------------------------------------------------------ */
.login-page {
  --brand: #00806A; --brand-dark: #006957;
  min-height: 100vh; display: grid; place-items: center; padding: 20px;
}
.login-wrap { width: 100%; max-width: 400px; }
.login-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-2); padding: 30px 28px 18px; text-align: center;
}
/* Логотипы бывают вытянутые (Shoy) и почти квадратные (AIM): ограничение по
   ширине и высоте сразу даёт им примерно одинаковый «вес» на карточке. */
.login-logo { display: block; margin: 0 auto 16px; max-width: 150px; max-height: 80px; width: auto; height: auto; object-fit: contain; }
.login-title { font-size: 20px; line-height: 1.25; margin: 0 0 3px; text-wrap: balance; }
.login-sub { font-size: 14px; font-weight: 600; color: var(--text-2); margin-bottom: 20px; }
.login-form { text-align: left; }
.login-row { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 6px 10px; font-size: 13px; }
.login-row.end { justify-content: flex-end; }
.login-row .check, .login-link { white-space: nowrap; }
.login-link { color: var(--brand); font-weight: 600; }
.login-link:hover { color: var(--brand-dark); }
.btn-brand { background: var(--brand); border-color: var(--brand); color: #fff; }
.btn-brand:hover, .btn-brand:focus-visible { background: var(--brand-dark); border-color: var(--brand-dark); color: #fff; }
.login-page input:focus { border-color: var(--brand); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 18%, transparent); }
.login-by {
  /* v6.78.2 (макет 32): подписи «працює на» больше нет, осталась одна
     маленькая картинка. Отступы и рамка карточки не менялись — окно входа
     той же ширины, что и раньше, уменьшилась только эта картинка. */
  margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--border);
  display: flex; justify-content: center;
}
.login-by img { height: 18px; width: auto; max-width: 100%; }
@media (max-width: 420px) {
  .login-card { padding: 22px 18px 14px; }
  .login-by img { height: 16px; }
}
.login-tile { display: block; width: 52px; height: 52px; border-radius: 14px; margin: 0 auto 12px; }
.login-page .login-logo + h1 { margin-top: 0; }
.brand-tile { display: block; width: 30px; height: 30px; border-radius: 8px; flex: 0 0 auto; }

/* Плашка «N накладных в пути не вошли · Показать» над списком заказов (v6.46.3, п.12) */
.transit-note { display: inline-flex; align-items: center; gap: 8px; margin: 10px 12px 6px; padding: 5px 12px; border-radius: 999px; background: #eef4fb; color: #1e3a5f; font-size: 12.5px; }
.transit-note a { font-weight: 600; }
.kw-chip { font-weight: 600; margin: 1px 2px 1px 0; }

/* Логотип ЗВІРКИ последним пунктом меню (v6.46.3) */
.sidebar-by { flex: none; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 5px; padding: 14px 12px 16px; border-top: 1px solid var(--border); background: var(--surface); }
.sidebar-by img { display: block; height: 22px; width: auto; }
/* Слоган под логотипом (6.46.7, выбор заказчика: вариант «Б»): чёрным, мелко,
   чуть уже самого логотипа. */
.sidebar-slogan { font-size: 6px; line-height: 1; letter-spacing: .12em; text-transform: uppercase; color: var(--text); font-weight: 600; white-space: nowrap; }
.top-name { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; white-space: normal; line-height: 1.3; }

/* Легенда кольца табличкой с шапкой (v6.46.3): название · значение · доля */
.chart-pie:not(.stacked) { justify-content: center; gap: 40px; }
.chart-pie:not(.stacked) .pie-legend { flex: 0 1 560px; max-width: 560px; gap: 0; font-size: 13.5px; }
.chart-pie:not(.stacked) .pl-head,
.chart-pie:not(.stacked) .pl-item { display: grid; grid-template-columns: 12px minmax(0,1fr) 110px 150px; align-items: center; gap: 12px; }
.chart-pie:not(.stacked) .pl-head { padding: 0 6px 8px; border-bottom: 1px solid var(--border); font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.chart-pie:not(.stacked) .pl-head .r { text-align: right; }
.chart-pie:not(.stacked) .pl-item { padding: 7px 6px; border-bottom: 1px solid var(--border); border-radius: 0; transition: opacity .12s ease; }
.chart-pie:not(.stacked) .pl-item:last-child { border-bottom: 0; }
.pl-num { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pl-share { display: flex; flex-direction: row-reverse; align-items: center; gap: 8px; }
.pl-share b { flex: 0 0 46px; text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--muted); font-size: 12.5px; }
.pl-share em { display: block; flex: 1 1 auto; height: 6px; border-radius: 999px; background: var(--surface-2, #eef1f5); overflow: hidden; }
.pl-share u { display: block; height: 100%; border-radius: 999px; }
@media (max-width: 640px) { .chart-pie:not(.stacked) .pl-head, .chart-pie:not(.stacked) .pl-item { grid-template-columns: 12px minmax(0,1fr) auto 70px; } }

/* Подпись единицы под числом в таблице (v6.50.2, п.13 заказчика: «у каждой
   цифры ниже поставь „шт.“»). Отдельной строкой и мельче: число остаётся
   главным, а подпись отвечает на вопрос «чего именно столько». */
.unit { display: block; font-size: 11px; line-height: 1.2; color: var(--muted); font-weight: 400; }

/* Незаполненное обязательное поле (v6.50.2): подпись по-русски вместо
   браузерного пузырька на языке браузера. Красная рамка и строка под полем —
   там же, где человек его и ищет. */
.is-invalid {
  border-color: var(--red, #c62026) !important;
  background: rgba(200,0,0,.05);
  box-shadow: 0 0 0 3px rgba(198,32,38,.12);
}
.invalid-note { margin-top: 4px; font-size: 12.5px; color: var(--red, #c62026); }


/* Сканер штрихкода камерой убран в 6.53.4 — см. пояснение в app.js.
   Своего оформления здесь не осталось: глобальный поиск и без него стоит
   на `position: relative` (строка 228), а отступ справа был нужен только
   под кнопку сканера. */

/* Подсказка «поставить на телефон» в мобильном меню (v6.52.0). */
.sidebar-pwa {
  margin: 10px 12px 0; padding: 11px 13px; border-radius: var(--radius);
  background: var(--accent-soft); font-size: 12.5px; line-height: 1.45;
}
.sidebar-pwa b { display: block; font-size: 13.5px; margin-bottom: 3px; }
.sidebar-pwa span { display: block; color: var(--muted); }
.sidebar-pwa .pwa-how { margin-top: 6px; color: var(--ink); }
.sidebar-pwa .pwa-how b { display: inline; font-size: inherit; }


/* ======================================================================
   КРУПНЫЕ ЦЕЛИ НАЖАТИЯ В КАТАЛОГЕ НА ТЕЛЕФОНЕ (v6.52.0, находка QA).

   Обход 160 страниц нашёл на странице каталога 42 элемента высотой меньше
   28 точек — это галочки выбора категорий и стрелки «выше/ниже». Мышью
   попадаешь, пальцем — через раз.

   Сетка при этом плотная намеренно: там помещается много категорий сразу,
   и растягивать строки — значит показывать меньше. Поэтому увеличена не
   сама галочка, а область нажатия вокруг неё: невидимое поле поверх, через
   псевдоэлемент. Плотность остаётся прежней, попадать становится можно.
   ====================================================================== */
@media (max-width: 760px) and (pointer: coarse) {
  .cat-row td { position: relative; }
  .cat-row input[type="checkbox"],
  .cat-row .cat-arrow { position: relative; }
  .cat-row input[type="checkbox"]::after,
  .cat-row .cat-arrow::after {
    content: ''; position: absolute; left: 50%; top: 50%;
    width: 44px; height: 44px; transform: translate(-50%, -50%);
  }
  .cat-row .cat-arrow { min-width: 30px; min-height: 30px; }
}

/* Полоса этапов заказа (v6.98.0): весь путь «Создан → Оплачен» в одном ряду.
   Пройденные — с галочкой и датой, текущая — выделена, будущие — бледные. */
.ord-chain { display: flex; gap: 6px; margin: 0 0 14px; overflow-x: auto; padding-bottom: 2px; }
.oc-step { flex: 1 1 0; min-width: 118px; display: grid; grid-template-columns: 24px 1fr; grid-template-rows: auto auto;
  column-gap: 8px; align-items: center; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface); }
.oc-dot { grid-row: 1 / span 2; width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center;
  justify-content: center; font-size: 12px; font-weight: 700; background: var(--surface-3); color: var(--muted);
  border: 1px solid var(--border-strong); }
.oc-name { font-size: 13px; font-weight: 600; color: var(--text-2); line-height: 1.2; }
.oc-date { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.oc-step.done { background: var(--green-soft); border-color: var(--green); }
.oc-step.done .oc-dot { background: var(--green); border-color: var(--green); color: #fff; }
.oc-step.done .oc-name { color: var(--green); }
/* v6.153.2: нынешняя ступень тоже зелёная (слово Игоря 20.10), от пройденных её отличает только кольцо */
.oc-step.done.now { box-shadow: 0 0 0 2px var(--green-soft), 0 0 0 3px var(--green); }
.oc-step.todo { opacity: .72; }
.ord-chain-note { margin: -6px 0 14px; font-size: 12.6px; color: var(--text-2); display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
/* ЭТАПЫ НА ТЕЛЕФОНЕ — ПЕРЕНОСОМ, А НЕ ЗА КРАЙ (v6.154.0, вторая проверка
   6.153.2, находка 2.17). Было: шесть плиток по 118 px уходили за правый край
   экрана, даты обрезались («20.10.2026 21:3»), а что полосу можно листать, не
   было видно. Стало: на узком экране плитки встают по две в ряд, дата
   переносится — весь путь виден без прокрутки. */
@media (max-width: 560px) {
  .ord-chain { flex-wrap: wrap; overflow-x: visible; }
  .oc-step { flex: 1 1 calc(50% - 6px); min-width: 0; }
  .oc-date { white-space: normal; }
}

/* =================== Форма «Новый клиент» (v6.99.0, макеты 54–55) ===================
   Коммерческие условия и Маркетинг — два отдельных блока. Маркетинг «закрыт»
   (поля выключены), пока не введена ставка: ноль — маркетинга нет, и всё
   остальное в блоке только путало бы. */
.form-grid .col-l { grid-column: 1; }
.form-grid .col-r { grid-column: 2; }
.form-grid .mk-sep {
  grid-column: 1 / -1; border-top: 1px dashed var(--border-strong, var(--border));
  padding-top: 12px; margin-top: 2px; font-size: 12.5px; color: var(--text-2); font-weight: 600;
}
.form-grid .mk-sep .muted { font-weight: 400; }
.sub-box { margin-top: 18px; border: 1px solid var(--border); border-radius: var(--radius, 10px); background: var(--surface-2); padding: 14px; }
.sub-box h3 { margin: 0 0 10px; font-size: 13.5px; display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.sub-box h3 .muted { font-weight: 400; font-size: 12px; }
.field[hidden] { display: none; }
/* Число с единицей прямо на поле: «20 %» или «20 грн» */
.unit-wrap { display: flex; height: 36px; border: 1px solid var(--border-strong, var(--border)); border-radius: 8px; background: #fff; overflow: hidden; }
.unit-wrap input { border: 0; border-radius: 0; flex: 1 1 auto; min-width: 0; height: 34px; text-align: right; font-variant-numeric: tabular-nums; }
.unit-wrap input:focus { outline: none; box-shadow: none; }
.unit-wrap:focus-within { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.unit-wrap .unit {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center; min-width: 44px; padding: 0 10px;
  background: var(--accent-soft); color: var(--accent-dark); font-weight: 700; font-size: 13px;
  border-left: 1px solid var(--border-strong, var(--border));
}
.unit-wrap .unit.is-empty { background: var(--surface-3, #eef0f3); color: var(--muted); font-weight: 600; font-size: 12px; min-width: 62px; }
.rate-pair { display: flex; gap: 8px; flex-wrap: wrap; }
.rate-pair[hidden] { display: none; }
.lockbar { margin-bottom: 14px; background: var(--amber-soft); color: #6b4a00; border: 1px solid var(--border); border-radius: 8px; padding: 9px 12px; font-size: 13px; }
.lockbar.is-open { background: var(--green-soft); color: #0c5c3e; }
.field.mk-closed > label, .field.mk-closed > .field-lbl, .field.mk-closed > .hint { opacity: .55; }
.choice-row .check:has(input:disabled) { opacity: .5; cursor: not-allowed; background: var(--surface-3, #f1f3f5); }
input:disabled, select:disabled { cursor: not-allowed; }
.payee-box { grid-column: 1 / -1; border: 1px solid var(--amber); border-radius: var(--radius, 10px); background: #fffaf0; padding: 14px; }
.payee-box[hidden] { display: none; }
.payee-box h3 { margin: 0 0 4px; font-size: 13.5px; }
.payee-box .sub-h { color: var(--text-2); font-size: 12.5px; margin-bottom: 12px; }
/* Пометка клиента, которому маркетинг платится не напрямую (карточка клиента) */
.payee-chip { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: 999px; font-size: 12px; font-weight: 600;
  background: var(--amber-soft); color: #6b4a00; border: 1px solid #f0d9a8; }
.payee-plaque { margin-bottom: 14px; padding: 12px 14px; border: 1px solid #f0d9a8; border-left: 4px solid var(--amber);
  border-radius: 8px; background: #fff8e6; color: #5a3f00; font-size: 13.5px; }
.payee-plaque b { color: #3d2a00; }
.payee-plaque .payee-sub { margin-top: 4px; font-size: 12.5px; color: #7a5a14; }
@media (max-width: 640px) { .form-grid .col-l, .form-grid .col-r { grid-column: 1; } }

/* Вкладка «Коммерческие условия»: договор строкой (v6.99.3, макет 57) */
.contract-line { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; background: var(--green-soft, #e6f6ee);
  border: 1px solid #bfe3d0; color: #0c5c3e; border-radius: var(--radius-sm, 7px); padding: 9px 12px; font-size: 13px; }
.contract-line[hidden] { display: none; }
.contract-line a { font-weight: 600; }

/* Раздел «Маркетинг» (6.100.0, макеты 56/58/59): плашка «Как это работает», кнопки месяцев, вкладки партнёров */
.howto { border: 1px solid #c9dafc; border-radius: var(--radius, 10px); background: var(--accent-soft); margin-bottom: 14px; }
.howto > summary { display: flex; align-items: center; gap: 10px; padding: 10px 14px; cursor: pointer; list-style: none; }
.howto > summary::-webkit-details-marker { display: none; }
.howto-q { flex: 0 0 22px; height: 22px; border-radius: 50%; background: var(--accent); color: #fff; font-weight: 700; font-size: 13px;
  display: inline-flex; align-items: center; justify-content: center; }
.howto-title { font-weight: 600; color: var(--accent-dark); }
.howto-hint { margin-left: auto; font-size: 12px; color: var(--muted); }
.howto-body { padding: 4px 16px 14px; font-size: 13.5px; line-height: 1.55; border-top: 1px solid #d9e5fd; background: var(--surface); border-radius: 0 0 var(--radius, 10px) var(--radius, 10px); }
.howto-body p { margin: 10px 0 0; }
.howto-ex { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 10px; margin-top: 12px; }
.howto-ex > div { border: 1px solid var(--border); border-radius: var(--radius-sm, 7px); padding: 10px 12px; background: var(--surface-2); }
.howto-ex b.h { display: block; margin-bottom: 3px; }
.howto-body ol, .howto-body ul { margin: 8px 0 0 20px; padding: 0; }
.howto-body .pos { color: var(--green); font-weight: 600; }
.howto-body .neg { color: var(--red); font-weight: 600; }
.month-pills { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0 0 14px; }
.month-pills .lbl { color: var(--muted); font-size: 13px; }
.month-pills a { padding: 5px 13px; border: 1px solid var(--border-strong); border-radius: 999px; font-size: 13px; color: var(--text); background: var(--surface); text-decoration: none; }
.month-pills a:hover { border-color: var(--accent); text-decoration: none; }
.month-pills a.on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-dark); font-weight: 600; }
.month-pills .note { color: var(--muted); font-size: 12.5px; }
.partner-tabs { margin-top: 2px; }
.mk-all-payouts > summary { cursor: pointer; padding: 12px 16px; font-weight: 600; }
.mk-stats { display: flex; flex-wrap: wrap; gap: 6px 28px; padding: 10px 16px; background: var(--surface-2); border-bottom: 1px solid var(--border); font-size: 13px; }
.mk-stats .l { color: var(--muted); margin-right: 6px; }
.mk-stats b { font-size: 14.5px; font-variant-numeric: tabular-nums; }
.mk-stats .s { color: var(--muted); font-size: 12px; margin-left: 4px; }
.mk-stats .pos { color: var(--green); }
.mk-stats .neg { color: var(--red); }
/* Таблицы точек: цифры не рвутся на строки, имя — не уже 220px */
.mk-points td.num, .mk-points th.num { white-space: nowrap; }
.mk-points td:first-child { min-width: 220px; }
.mk-points .report-cell { white-space: nowrap; }

/* v6.101.0: форма «Новый возврат» — две колонки вместо auto-fill. Раньше число колонок
   зависело от ширины окна, и поля «играли» (слева ширина менялась, подсказки
   разной высоты сдвигали ряды). Теперь сетка стабильна: две колонки, на узком
   экране одна; подпись и звёздочка не разрываются (в разметке неразрывный пробел). */
.form-grid.form-cols2 { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
.form-grid.form-cols2 .span-2 { grid-column: 1 / -1; }
@media (max-width: 720px) { .form-grid.form-cols2 { grid-template-columns: 1fr; } }

/* v6.101.0, макет 60 (вариант Б): условия реализации — серая вставка под типом оплаты */
.stat-sub { margin: 6px 0 4px; padding: 6px 12px 8px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; }
.stat-sub .stat-line { padding: 4px 0; gap: 16px; }
.stat-sub .stat-line .v { text-align: right; }
.stat-sub .stat-rule { font-size: 12px; color: var(--muted); margin-top: 2px; line-height: 1.35; }

/* «Оплачено когда» в дебиторке (v6.109.0): разбивка по платежам под строкой */
.rcv-pays{margin-top:3px;border-left:2px solid var(--border);padding-left:7px;display:flex;flex-direction:column;gap:2px;font-size:11px;color:var(--muted)}
.rcv-pays .neg{color:var(--red);font-weight:600}
.data th.rcv-client{min-width:15rem}

/* Запросы на изменение — «что — было — станет» (v6.129.0, макет 124) */
.cr-list { display: grid; gap: 12px; margin-bottom: 16px; }
.cr-card { margin: 0; }
.cr-card.cr-pending { border-color: var(--amber); }
.cr-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; padding: .75rem 1rem; border-bottom: 1px solid var(--line); }
.cr-kind { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--amber); }
.cr-title { font-weight: 700; margin: 2px 0; }
.cr-title a { color: inherit; }
.cr-diff s { text-decoration-color: var(--muted); }
.cr-note, .cr-error { padding: .5rem 1rem; font-size: 13px; }
.cr-error { color: var(--red); background: var(--red-soft); }
.cr-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; padding: .6rem 1rem; border-top: 1px solid var(--line); background: var(--surface-2); }
.cr-actions form { display: flex; gap: 6px; align-items: center; margin: 0; }
.cr-reject input[type=text] { min-width: 16rem; }
@media (max-width: 760px) { .cr-reject { flex-wrap: wrap; } .cr-reject input[type=text] { min-width: 0; width: 100%; } }
.cr-banner { margin-bottom: 14px; }
.cr-banner > .cr-banner-title { font-weight: 700; color: var(--amber); margin: 0 0 6px; }
/* «Одобрения по менеджерам» */
.appr-dot { display: inline-flex; width: 1.4rem; height: 1.4rem; border-radius: 6px; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; }
.appr-dot.on { background: var(--amber-soft); color: var(--amber); }
.appr-dot.off { background: var(--grey-soft); color: var(--muted); }
.appr-grid { display: grid; gap: 0; }
/* Две равные колонки, как в макете 131 (вариант А): правило слева, уточнение
   справа от середины, между правилами — линия (v6.132.0, замечание Игоря). */
.appr-rule { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 2rem; padding: .9rem 0; border-top: 1px solid var(--line); align-items: start; }
.appr-rule:first-child { border-top: 0; }
.appr-rule .appr-opts { display: grid; gap: 6px; font-size: 13px; }
.appr-rule .appr-opts.off { opacity: .45; }
.appr-rule .appr-opts label.check span { font-weight: 400; }
.appr-rule > div:first-child .hint { font-size: 13px; color: var(--muted); margin-top: 4px; }
.appr-rule input.appr-amount { width: 8rem; }
@media (max-width: 760px) { .appr-rule { grid-template-columns: 1fr; } }

/* Панель отбора аналитики — одна на все экраны (v6.129.0, макет 123) */
.af-panel form { display: block; }
.af-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
.af-row1 { padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px dashed var(--border); }
.af-row1 .quick-periods { margin: 4px 0 0; }
.af-field { display: flex; flex-direction: column; min-width: 0; }
.af-periods { flex: 1 1 auto; }
.af-dates { display: flex; gap: 10px; flex-wrap: nowrap; margin-left: auto; align-items: flex-end; flex: 0 0 auto; }
.af-panel .af-dates .field { flex: 0 0 10.5rem; }
.af-row2 .field { flex: 1 1 150px; min-width: 0; }
.af-row2 .field.wide { flex: 1.6 1 220px; max-width: none; }
.af-row2 .field.af-na { opacity: .5; }
.af-row2 .field.af-na input[disabled] { font-style: italic; }
.af-row3 { margin-top: 10px; align-items: center; gap: 6px 8px; min-height: 22px; }
.af-chip { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; background: var(--accent-soft); color: var(--accent-dark);
  border-radius: 6px; padding: 2px 4px 2px 8px; }
.af-chip.af-chip-na { background: var(--grey-soft); color: var(--muted); }
.af-chip a { color: inherit; text-decoration: none; font-weight: 700; padding: 0 4px; }
.af-note { font-size: 12px; color: var(--muted); }
.af-dirty { font-size: 12px; color: var(--accent-dark); font-weight: 600; margin-left: auto; }
.btn.af-dirty-btn { box-shadow: 0 0 0 3px var(--accent-soft); }
.af-mini { position: sticky; top: 0; z-index: 20; display: flex; align-items: center; gap: 10px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius); padding: 6px 12px; margin: 0 0 12px; font-size: 13px; box-shadow: var(--shadow-1); }
.af-mini[hidden] { display: none; }
.af-mini .muted { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.af-mini .btn { margin-left: auto; }
@media (max-width: 760px) { .af-dates { margin-left: 0; flex-wrap: wrap; flex: 1 1 100%; } .af-panel .af-dates .field { flex: 1 1 45%; } .af-row2 .field { flex: 1 1 45%; } }
/* Вкладки отчётов + «Деньги / Штуки» (v6.129.0) */
.an-tabs { display: flex; gap: 2px; flex-wrap: wrap; width: fit-content; max-width: 100%; margin: 0 0 16px;
  padding: 4px; background: #e7ebf0; border-radius: 11px; align-items: center; }
.an-tabs a.an-tab { text-decoration: none; padding: 7px 14px; color: var(--text-2); font-weight: 600; border-radius: 8px; }
.an-tabs a.an-tab:hover { color: var(--text); background: rgba(255, 255, 255, .6); }
.an-tabs a.an-tab.on { color: var(--accent-dark); background: #fff;
  box-shadow: 0 1px 2px rgba(16, 21, 28, .10), 0 1px 4px rgba(16, 21, 28, .06); }
.an-tabs .an-unit { margin-left: 8px; margin-bottom: 0; }
/* Аналитика → Задолженность (v6.129.0, макет 123) */
.debt-legend { display: flex; gap: 14px; flex-wrap: wrap; font-size: 12.5px; color: var(--muted); }
.debt-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; }
.debt-bar { display: flex; height: 26px; border-radius: 7px; overflow: hidden; gap: 2px; margin: 4px 0 10px; }
.debt-bar > div { display: flex; align-items: center; justify-content: center; font-size: 11.5px; font-weight: 700; color: #fff; min-width: 0; overflow: hidden; white-space: nowrap; }
.hbar-paid { position: absolute; left: 0; top: 0; height: 100%; background: var(--green); opacity: .85; border-radius: 5px; }
.af-panel .af-dates .field.af-cmp { flex: 0 0 14rem; }
.quick-periods a.qp-attn:not(.on) { border-color: var(--amber); color: var(--amber); font-weight: 600; }

/* Полная проверка нового клиента перед одобрением (v6.130.0) */
.apr-head { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; align-items: baseline; margin-bottom: 12px; }
.apr-count { font-variant-numeric: tabular-nums; white-space: nowrap; }
.apr-similar ul { margin: 6px 0 0; padding-left: 18px; }
.apr-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 12px; margin-bottom: 14px; }
.apr-sec { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; background: var(--surface); display: flex; flex-direction: column; gap: 8px; transition: border-color .15s, background .15s; }
.apr-sec.has-bad { border-color: var(--red); }
.apr-sec.has-warn { border-color: var(--amber); }
.apr-sec.is-ok { border-color: var(--green); background: var(--green-soft); }
.apr-sec-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.apr-sec-head h3 { margin: 0; font-size: 15px; }
.apr-dl { display: grid; grid-template-columns: max-content 1fr; gap: 3px 14px; margin: 0; font-size: 13px; }
.apr-dl dt { color: var(--muted); }
.apr-dl dd { margin: 0; overflow-wrap: anywhere; }
.apr-list { margin: 0; padding-left: 18px; font-size: 13px; display: grid; gap: 3px; }
.apr-issue { display: flex; gap: 6px; align-items: flex-start; font-size: 13px; padding: 5px 8px; border-radius: var(--radius-sm); }
.apr-issue.apr-bad { background: var(--red-soft); color: var(--red); }
.apr-issue.apr-warn { background: var(--amber-soft); color: var(--amber); }
.apr-ok { margin-top: auto; padding-top: 6px; border-top: 1px dashed var(--border); font-weight: 600; }
/* Ссылка «карточка» в строке отчёта: строка сужает отбор, карточка — отдельно (v6.130.0) */
.an-card { font-weight: 400; margin-left: 6px; white-space: nowrap; }

/* v6.131.0 — линия между условиями клиента и бонусами менеджера (макет 131, раздел 4) */
.stat-sep { border-top: 2px solid var(--border-strong); margin: 8px 0 2px; padding-top: 6px;
  font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }

/* v6.131.0 — склады доставки в форме «Новый клиент»: каждая строка — своя рамка */
.wh-rows { display: grid; gap: 10px; }
.wh-rows .wh-row { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; background: var(--surface-2); }
.wh-rows .wh-row:has(input[name="wh_main"]:checked) { border-color: var(--teal); background: var(--teal-soft); }
.wh-row-top { margin-bottom: 6px; }
.wh-rows textarea { min-height: 36px; resize: vertical; }

/* v6.131.0 — каталог: полоса «есть несохранённые изменения» */
.unsaved-bar { position: sticky; top: calc(var(--topbar-h) + 6px); z-index: 5; display: flex; gap: 10px;
  align-items: center; justify-content: space-between; flex-wrap: wrap; margin-bottom: 12px;
  background: var(--amber-soft); border: 1px solid #f0cf98; color: #6b4100; border-radius: var(--radius); padding: 8px 12px; font-size: 13px; }
.unsaved-bar[hidden] { display: none; }

/* v6.131.0 — своя кнопка у блока «Одобрения» (макет 131, раздел 9, вариант А) */
.appr-savebar { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap;
  border-top: 1px solid var(--border); padding: 10px 16px; background: var(--surface-2); border-radius: 0 0 var(--radius) var(--radius); }
.appr-savebar.dirty { background: var(--amber-soft); }

/* v6.131.2 — «Доступно» в заказе: «(всего N)» мелко, разбивка по складам при наведении (макет 133, вариант 3) */
.avail .av-pop { position: relative; display: inline-block; margin-left: 4px; cursor: help; outline: none; }
.avail .av-tot { font-size: 12px; font-weight: 400; color: var(--muted); border-bottom: 1px dotted var(--muted); white-space: nowrap; }
.avail .av-pop.help .av-tot { color: var(--green); border-bottom-color: var(--green); }
.avail .av-box { display: none; position: absolute; right: 0; top: calc(100% + 6px); z-index: 30; min-width: 220px;
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius); box-shadow: var(--shadow-3);
  padding: 6px 8px; text-align: left; font-weight: 400; color: var(--text); }
.avail .av-pop:hover .av-box, .avail .av-pop:focus .av-box, .avail .av-pop:focus-within .av-box { display: block; }
.avail .av-box table { width: 100%; border-collapse: collapse; font-size: 12px; font-variant-numeric: tabular-nums; }
.avail .av-box td { padding: 4px 6px; border-bottom: 1px solid var(--surface-3); white-space: nowrap; }
.avail .av-box tr.here td { background: var(--accent-soft); font-weight: 700; }
.avail .av-box tr.tot td { font-weight: 700; border-top: 2px solid var(--border-strong); border-bottom: 0; }
/* Поиск товара в заказе: другие склады мелко в скобках; товар только на других складах — серым, не выбирается */
.search-results .sr-oth { font-size: 11px; color: var(--muted); margin-left: 4px; white-space: nowrap; }
.search-results .sr-oth.help { color: var(--green); }
.search-results .sr-off { display: flex; justify-content: space-between; gap: 10px; padding: 8px 12px; opacity: .6; cursor: not-allowed; }

/* «Молчат» — разбор молчащих клиентов (v6.139.0, макеты 160–161) */
.sl-sec { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; }
.sl-sec b { font-size: 15px; }
.sl-sec-2 { margin-top: 20px; }
.sl-cnt { font-size: 12px; font-weight: 700; padding: 1px 8px; border-radius: 999px; background: var(--surface-3); color: var(--text-2); }
.sl-cnt.warn { background: var(--amber-soft); color: var(--amber); }
.sl-right, table.data th.sl-right { text-align: right; }
.sl-acts { display: flex; gap: 4px; flex-wrap: wrap; justify-content: flex-end; align-items: center; margin: 0; }
.sl-acts + .sl-acts { margin-top: 4px; }
.sl-chip { border: 1px solid var(--border-strong); background: var(--surface); border-radius: 999px; padding: 3px 9px;
  font: inherit; font-size: 12px; color: var(--text); cursor: pointer; white-space: nowrap; list-style: none; }
.sl-chip::-webkit-details-marker { display: none; }
.sl-chip:hover { border-color: var(--accent); }
.sl-chip.dk { background: var(--surface-3); }
.sl-chip.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.sl-why { position: relative; }
.sl-pop { position: absolute; right: 0; top: 30px; z-index: 5; width: 280px; background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: 9px; box-shadow: var(--shadow-2); padding: 10px; display: grid; gap: 4px; }
.sl-pop input { width: 100%; }
/* v6.144.0, макет 177 v3: одна таблица, списки — заголовками внутри неё;
   новые и вернувшиеся — только чертой слева, без заливки строки */
tr.sl-fresh td:first-child { box-shadow: inset 3px 0 0 var(--red); }
table.data tr.sl-grp td { background: var(--surface-2); font-weight: 700; font-size: 14.5px; padding-top: 9px; padding-bottom: 9px; }
tr.sl-grp .sl-cnt { margin-left: 8px; vertical-align: 1px; }
.sl-hl { background: none; border: 0; padding: 0; font: inherit; font-size: 12px; font-weight: 600; color: var(--accent); cursor: pointer; }
.sl-hl:hover { text-decoration: underline; }
table.data tr.sl-hrow td { background: var(--surface-2); font-size: 13px; padding-top: 6px; padding-bottom: 6px; }
td.sl-hwhat { padding-left: 28px !important; color: var(--muted); }
.sl-out { display: inline-block; font-size: 12px; border-radius: 999px; padding: 0 8px; border: 1px solid; white-space: nowrap; }
.sl-o1 { background: var(--amber-soft); color: var(--amber); border-color: var(--amber); }
.sl-o2 { background: var(--green-soft); color: var(--green); border-color: var(--green); }
.sl-o3 { background: var(--surface-3); color: var(--text-2); border-color: var(--border-strong); }
.sl-o4 { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); }
.sl-until { display: inline-block; background: var(--amber-soft); color: var(--amber); border: 1px solid var(--amber); border-radius: 6px; padding: 0 7px; font-size: 12.5px; white-space: nowrap; }
.sl-kinds { justify-content: flex-start; margin-bottom: 12px; }
.sl-gap { flex: 1; }
.sl-newb.ret { color: var(--amber); border-color: var(--amber); }
.sl-newb { display: inline-block; font-size: 10.5px; font-weight: 800; color: var(--red); background: var(--surface); border: 1px solid var(--red);
  border-radius: 4px; padding: 0 5px; margin-left: 6px; vertical-align: 1px; }

/* ===== Оборудование у клиентов деревом (v6.139.1, макет 164) =====
   По клиентам / по оборудованию; раскрытие — <details>. Колонки одной
   сеткой в шапке и в строках. Ширины в rem, а не в ch: у шапки шрифт
   мельче, и ch в ней уже — колонки шапки и строк разъезжались. */
.eqt-bar { display: flex; flex-wrap: wrap; gap: 10px 14px; align-items: center; justify-content: flex-start; }
.eqt-seg a { display: block; padding: 4px 12px; font-size: 13px; font-weight: 600; color: var(--text-2); border-radius: 7px; text-decoration: none; }
.eqt-seg a.active { background: #fff; color: var(--accent-dark); box-shadow: 0 1px 3px rgba(16, 21, 28, .12); }
.eqt-search { min-width: 0; flex: 0 1 32ch; }
.eqt-journal { margin-left: auto; color: var(--text-2); display: inline-flex; gap: 4px; align-items: center; }
.eqt-row { display: grid; gap: 12px; align-items: center; padding: 10px 16px; }
.eqt-c { grid-template-columns: minmax(0, 3fr) minmax(0, 1.6fr) 5.5rem 4.5rem 9.5rem; }
.eqt-e { grid-template-columns: minmax(0, 3fr) minmax(0, 1.4fr) 7rem 6rem 7rem; }
.eqt-p { grid-template-columns: minmax(0, 1fr) 6.5rem 5.5rem 8.5rem; }
.eqt-row .num { text-align: right; font-variant-numeric: tabular-nums; }
.eqt-head { font-size: 11.5px; text-transform: uppercase; letter-spacing: .03em; color: var(--muted); font-weight: 600;
            background: var(--surface-2); border-bottom: 1px solid var(--border); padding-top: 8px; padding-bottom: 8px; }
.eqt-l1 { border-bottom: 1px solid var(--border); }
.eqt-l1 > summary, .eqt-l2 > summary { list-style: none; cursor: pointer; }
.eqt-l1 > summary::-webkit-details-marker, .eqt-l2 > summary::-webkit-details-marker { display: none; }
.eqt-l1 > summary:hover, .eqt-l2 > summary:hover { background: var(--surface-2); }
.eqt-l1 > summary:focus-visible, .eqt-l2 > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.eqt-name { display: flex; gap: 8px; align-items: baseline; min-width: 0; overflow-wrap: anywhere; }
.eqt-chev { display: inline-block; width: 1ch; color: var(--muted); font-weight: 700; transition: transform .12s; flex: none; }
details[open] > summary .eqt-chev { transform: rotate(90deg); }
.eqt-link { color: var(--muted); display: inline-flex; align-self: center; }
.eqt-link:hover { color: var(--accent-dark); }
.eqt-in { margin: 0 16px 12px 34px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: #fff; overflow: hidden; }
.eqt-in .eqt-row { padding: 8px 12px; }
.eqt-l2 + .eqt-l2 { border-top: 1px solid #eef1f4; }
.eqt-hist { padding: 4px 12px 12px 30px; overflow-x: auto; }
.eqt-hist table { background: var(--surface-2); border-radius: var(--radius-sm); }
.eqt-hist tfoot td { border-top: 1px solid var(--border); }
.eqt-ret { color: var(--red, #c02626); }
.eqt-qty { display: flex; gap: 8px; align-items: center; }
.eqt-qty input { max-width: 10ch; }
@media (max-width: 760px) {
  .eqt-c, .eqt-e { grid-template-columns: minmax(0, 1fr) 4.5rem; }
  .eqt-c > :nth-child(2), .eqt-c > :nth-child(4), .eqt-c > :nth-child(5),
  .eqt-e > :nth-child(2), .eqt-e > :nth-child(4), .eqt-e > :nth-child(5) { display: none; }
  .eqt-p { grid-template-columns: minmax(0, 1fr) 6rem; }
  .eqt-p > :nth-child(3) { display: none; }
  .eqt-p > .col-actions { grid-column: 1 / -1; }
  .eqt-in { margin-left: 12px; margin-right: 12px; }
  .eqt-journal { margin-left: 0; }
}

/* ===== День рождения контактного лица (v6.140.0, макет 165 v2) =====
   Дата — обычной строкой, как телефон; «через 3 дня» жёлтым под ней только
   в последнюю неделю. В списке слева — «ДР через 3 дн.» тоже только тогда.
   Колонка подписей в .pp-facts — 104px: «День рождения» в 88px ломалась. */
/* Несколько телефонов у контактного лица (v6.157.0, макет 195) */
.pp-phone-rows { display: grid; gap: 6px; }
.pp-phone-row { display: grid; grid-template-columns: 8.5rem minmax(0, 1fr) auto auto; gap: 8px; align-items: center; }
.pp-phone-row .check { white-space: nowrap; }
@media (max-width: 560px) { .pp-phone-row { grid-template-columns: 1fr auto; } .pp-phone-row input[type=text] { grid-column: 1 / -1; grid-row: 1; } }
.pp-phones { display: grid; gap: 2px; }
.pp-phone a { color: inherit; text-decoration: none; border-bottom: 1px dotted var(--muted); font-variant-numeric: tabular-nums; }
.pp-phone.is-main a { font-weight: 700; }
.pp-phone-kind { color: var(--muted); font-size: 12px; margin-left: 4px; }
.pp-bday-pick { display: flex; gap: 8px; }
.pp-bday-pick select:first-child { flex: 0 0 6.5rem; }
.pp-bday-pick select:last-child { flex: 1 1 auto; min-width: 0; }
.pp-bday-soon, .pp-item.is-active .pp-bday-soon { color: var(--amber); opacity: 1; font-weight: 600; font-size: 12.2px; }

/* ===== «Показать, кто не покупал» в «Отчёты → По клиентам» (v6.140.1, макет 166) ===== */
.an-nobuy { display: inline-flex; gap: 8px; align-items: center; font-size: 13px; font-weight: 600;
            color: var(--text-2); text-decoration: none; padding: 4px 8px; border-radius: var(--radius-sm); }
.an-nobuy:hover { background: var(--surface-3); color: var(--text); }
.an-nobuy:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.an-nobuy-box { width: 16px; height: 16px; border: 1.5px solid var(--border-strong); border-radius: 4px;
                position: relative; background: var(--surface); flex: none; }
.an-nobuy.is-on .an-nobuy-box { background: var(--accent); border-color: var(--accent); }
.an-nobuy.is-on .an-nobuy-box::after { content: ""; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px;
                                       border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }
table.data tr.row-group.an-nobuy-group td { background: var(--amber-soft); color: var(--amber); }
.kpi-of { font-size: 15px; font-weight: 600; color: var(--muted); }
.kpi-link { color: var(--accent-dark); font-weight: 600; }

/* ===== «Мои начисления» (v6.140.1, макет 167) ===== */
.acc-kpis { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 900px) { .acc-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.acc-card { margin-top: 16px; scroll-margin-top: 72px; }
.acc-table td.acc-client { min-width: 0; overflow-wrap: anywhere; }

/* ===== Выбор темы в профиле (v6.140.2, макет 168) =====
   Превью нарисовано своими цветами, а не переменными темы: «Светлая» и
   «Графит» должны выглядеть собой при любой включённой теме. */
.theme-pick { display: flex; gap: 12px; flex-wrap: wrap; }
.theme-opt { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; width: 14rem; max-width: 100%;
             padding: 10px; border: 1.5px solid var(--border); border-radius: var(--radius); background: var(--surface);
             color: var(--text); font: inherit; cursor: pointer; text-align: left; }
.theme-opt:hover { border-color: var(--border-strong); }
.theme-opt.is-on { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.theme-opt:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.theme-prev { display: grid; grid-template-columns: 30% 1fr; grid-template-rows: 1fr 1fr; gap: 4px; width: 100%; height: 4.5rem;
              padding: 6px; border-radius: var(--radius-sm); }
.theme-prev span:first-child { grid-row: 1 / 3; border-radius: 4px; }
.theme-prev span { border-radius: 4px; }
.theme-opt-light .theme-prev { background: #f4f6f8; border: 1px solid #e3e7ec; }
.theme-opt-light .theme-prev span { background: #ffffff; border: 1px solid #e3e7ec; }
.theme-opt-light .theme-prev span:last-child { background: #2563eb; border-color: #2563eb; width: 40%; }
.theme-opt-graphite .theme-prev { background: #2e2f31; border: 1px solid #58595e; }
.theme-opt-graphite .theme-prev span { background: #3c3d40; border: 1px solid #58595e; }
.theme-opt-graphite .theme-prev span:last-child { background: #1fa67e; border-color: #1fa67e; width: 40%; }
.theme-name { font-weight: 600; }

/* ==== Активность сотрудников (v6.143.0, макет 174 v2) ==== */
.act-filters { margin-top: -6px; }
.act-me { align-self: end; padding-bottom: 8px; }
.act-kpis { margin-bottom: 14px; }
.act-green { color: var(--green); }
.act-red { color: var(--red); }
.act-d { font-weight: 650; font-variant-numeric: tabular-nums; }
.act-d.up { color: var(--green); }
.act-d.dn { color: var(--red); }
.act-live { display: flex; flex-wrap: wrap; gap: 10px; }
.act-who { display: flex; gap: 10px; align-items: center; border: 1px solid var(--border); border-radius: 10px; padding: 8px 12px; min-width: 260px; color: var(--text); text-decoration: none; }
.act-who:hover { background: var(--surface-3); text-decoration: none; }
.act-who .xs { display: block; }
.act-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--green); box-shadow: 0 0 0 3px var(--green-soft); flex: 0 0 auto; }
.act-dot.idle { background: var(--amber); box-shadow: 0 0 0 3px var(--amber-soft); }
.act-sw { display: inline-block; width: 9px; height: 9px; border-radius: 3px; margin-right: 7px; vertical-align: 1px; }
.act-off td { color: var(--muted); }
.act-bar { height: 5px; background: var(--surface-3); border-radius: 3px; margin-top: 5px; min-width: 80px; }
.act-bar span { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
.act-bar.big { height: 10px; flex: 1; margin-top: 0; }
.act-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 13px; margin-bottom: 8px; }
.act-legend span { display: inline-flex; align-items: center; gap: 6px; }
.act-legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.act-chart { display: block; overflow: visible; }
.act-chart .act-grid { stroke: var(--border); stroke-width: 1; }
.act-chart .act-tick { font-size: var(--cg-fs, 11px); fill: var(--muted); }
.act-chart rect { cursor: default; }
.act-chart g:hover rect { opacity: .82; }
.act-chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.act-chips a, .act-chips span { border: 1px solid var(--border); background: var(--surface); border-radius: 999px; padding: 3px 11px; font-size: 13px; color: var(--text); text-decoration: none; }
.act-chips .on { background: var(--accent); border-color: var(--accent); color: #fff; }
.act-hm { display: grid; grid-template-columns: 28px repeat(16, 1fr); gap: 3px; font-size: 11px; color: var(--muted); }
.act-hh { text-align: center; }
.act-hd { display: flex; align-items: center; }
.act-hc { height: 22px; border-radius: 4px; background: var(--surface-3); }
.act-sec { display: flex; align-items: center; gap: 10px; margin: 8px 0; font-size: 13px; }
.act-sec > span { width: 160px; flex: 0 0 auto; }
.act-sec b { width: 48px; text-align: right; font-variant-numeric: tabular-nums; }
.act-eff { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px; }
.act-al { list-style: none; margin: 0; padding: 0; }
.act-al li { padding: 6px 0; border-top: 1px solid var(--border); }
.act-al li:first-child { border-top: 0; }
.act-al a { color: var(--text); text-decoration: none; }
.act-al .badge { margin-right: 6px; }
.act-calpick { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; max-width: 420px; }
.act-ln { display: grid; grid-template-columns: 84px 1fr 86px; gap: 12px; align-items: center; padding: 4px 6px; border-radius: 8px; color: var(--text); text-decoration: none; }
a.act-ln:hover, .act-ln.on { background: var(--surface-3); text-decoration: none; }
.act-lnd { font-size: 13px; font-weight: 600; }
.act-lnv { font-size: 13px; text-align: right; font-variant-numeric: tabular-nums; }
.act-tl { position: relative; height: 20px; background: var(--surface-3); border-radius: 5px; overflow: hidden; }
.act-tl.none { background: none; height: 16px; overflow: visible; }
.act-tl i { position: absolute; top: 0; bottom: 0; border-radius: 5px; }
.act-tl i.s { background: var(--border-strong); opacity: .55; }
.act-tl i.a { background: var(--accent); }
.act-axis i { font-style: normal; font-size: 11px; color: var(--muted); transform: translateX(-50%); top: 0; }
.act-month { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.act-mh { font-size: 11px; color: var(--muted); text-align: center; }
.act-md { border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px; min-height: 52px; color: var(--text); text-decoration: none; display: flex; flex-direction: column; font-size: 12px; }
.act-md.has { background: var(--accent-soft); }
.act-md.on { outline: 2px solid var(--accent); }
.act-md span { font-variant-numeric: tabular-nums; color: var(--text-2, var(--text)); margin-top: auto; }
.act-feed-wrap { border-top: 1px solid var(--border); }
.act-h3 { font-size: 16px; margin: 0 0 10px; }
.act-evs { list-style: none; margin: 0; padding: 0; }
.act-ev { display: flex; gap: 14px; padding: 7px 0; border-top: 1px solid var(--border); }
.act-ev time { width: 44px; flex: 0 0 auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.act-ev > div { border-left: 3px solid var(--border); padding-left: 10px; }
.act-ev-in > div, .act-ev-out > div { border-color: var(--green); }
.act-ev-act > div { border-color: var(--accent); }
.act-ev-exp > div { border-color: var(--amber); }
.act-ev-idle { opacity: .65; }
.act-ev-compact { padding: 3px 0; }
.act-ev-compact > div { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.act-ev-compact > div b { font-weight: 500; }
.act-people td:first-child { min-width: 190px; }
.act-people th { white-space: nowrap; }
@media (max-width: 700px) {
  .act-ln { grid-template-columns: 62px 1fr 64px; gap: 8px; }
  .act-sec > span { width: 110px; }
}

/* Образец кнопки тёмной темы в «Настройки → Компания» (v6.143.1) — фон
   «Светлого графита», чтобы было видно, как кнопка будет выглядеть */
.brand-dark-sample { display: inline-flex; align-items: center; gap: 10px; background: #3c3d40; border: 1px solid #58595e; border-radius: 8px; padding: 6px 10px; }
.brand-dark-sample span { color: #fff; font-weight: 600; font-size: 13px; border-radius: 6px; padding: 4px 10px; }
.brand-dark-sample i { font-style: normal; font-size: 13px; text-decoration: underline; }

/* ---------- Разбор списаний (v6.145.0, макет 176 v4) ---------- */
.sp-acc { display: flex; flex-wrap: wrap; gap: 4px; margin: 10px 0 0; }
.sp-acc a { font-size: 12.5px; font-weight: 600; padding: 4px 11px; border: 1px solid var(--border); border-radius: 999px; color: var(--text-2); background: var(--surface); }
.sp-acc a:hover { text-decoration: none; border-color: var(--border-strong); }
.sp-acc a.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.sp-table td { vertical-align: top; }
.sp-who b { display: block; font-weight: 600; font-size: 13px; }
.sp-who small { display: block; color: var(--muted); font-size: 11.5px; }
.sp-purp { max-width: 300px; }
.sp-sugg { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; }
.sp-why { font-size: 11.5px; color: var(--muted); }
.sp-pick { display: flex; gap: 6px; align-items: center; }
.sp-pick select { height: 30px; padding: 3px 6px; font-size: 12.5px; max-width: 230px; }
.sp-period { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; font-size: 13px; }
.sp-period input { height: 30px; }
.sp-cond { display: flex; flex-wrap: wrap; gap: 4px 10px; font-size: 12.5px; }
.sp-c b { font-weight: 600; }
.sp-off td { opacity: .55; }
.sp-hint { font-size: 12.5px; color: var(--text-2); max-width: 100ch; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 14px; }
.sp-grid { display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: 8px 12px; align-items: center; }
.sp-grid label, .sp-l { font-size: 13px; font-weight: 600; color: var(--text-2); }
.sp-grid input, .sp-grid select { width: 100%; }
.sp-mode { display: inline-flex; gap: 2px; padding: 3px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 9px; flex-wrap: wrap; }
.sp-mode button { font: inherit; font-size: 12.5px; font-weight: 600; border: 0; background: transparent; color: var(--text-2); border-radius: 7px; padding: 4px 10px; cursor: pointer; }
.sp-mode button.on { background: var(--surface); color: var(--accent); box-shadow: 0 1px 3px rgba(16, 21, 28, .12); }
.sp-prev { margin-top: 14px; border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; background: var(--surface-2); }
.sp-prev .table-wrap { max-height: 220px; overflow-y: auto; margin-top: 6px; }
.sp-check { display: flex; gap: 8px; align-items: center; font-size: 13px; margin-top: 10px; }
.sp-radio { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
.sp-radio label { display: flex; gap: 8px; align-items: center; font-size: 13px; padding: 5px 8px; border: 1px solid var(--border); border-radius: 8px; cursor: pointer; }
.sp-radio label:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
.sp-info { font-size: 13px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; }
@media (max-width: 700px) { .sp-grid { grid-template-columns: 1fr; } }
.sp-period label { margin: 0; font-weight: 600; color: var(--text-2); }
.sp-period input[type=date] { width: 165px; max-width: 165px; }

/* ---------- Ставки по брендам (v6.146.0, макет 151+152 v3) ---------- */
.br-table th.br-grp { text-align: center; border-left: 1px solid var(--border); }
.br-table .br-l { border-left: 1px solid var(--border); }
.br-table select { height: 30px; padding: 3px 6px; font-size: 12.5px; }
.br-table .br-in { width: 86px; text-align: right; }
.br-table tr.br-def td { background: var(--surface-2); }
.br-mini { font-size: 12.5px; }
.br-mini th, .br-mini td { padding: 5px 8px; }
.br-wait { color: var(--muted); opacity: .6; }
.br-note { padding: 6px 12px 10px; }
.br-details { padding: 0 12px 10px; }
.br-details summary { cursor: pointer; color: var(--muted); }
.br-sum { max-width: 640px; }
.br-mini tr.is-active td { background: var(--accent-soft); }
/* Имя бренда переносится по словам, а не по буквам (v6.155.0, проверка 3, Э-5):
   с `anywhere` колонка сжималась ниже ширины слова, и «CLIPPER» рвалось на
   «CLIPPE / R» даже на широком экране. */
table.data.br-mini td:first-child:not(.nowrap) { overflow-wrap: break-word; }
/* Начисленное и «+ ещё не начислено» — одним блоком справа (v6.155.0, Э-5) */
.br-mini .br-cell { display: inline-flex; flex-direction: column; align-items: flex-end; text-align: right; }
.br-num { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; height: 24px; border-radius: 6px; color: #fff; font-weight: 800; font-size: 12.5px; }

/* ===== v6.148.0 — макет 182: бренды, начисления по брендам, логистика ===== */
/* Справочник брендов: цвет — набор кружков, роли — галочки */
.bc-chain { border-left: 3px solid var(--accent); }
.bc-table td { vertical-align: top; }
.bc-off td { opacity: .55; }
.bc-pal { display: grid; grid-template-columns: repeat(4, 22px); gap: 5px; width: max-content; }
.bc-sw { position: relative; display: inline-block; width: 22px; height: 22px; border-radius: 6px; background: var(--c); cursor: pointer; box-shadow: 0 0 0 1px var(--border); }
.bc-sw input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.bc-sw:has(input:checked), .bc-sw.on { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--text); }
.bc-sw:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.bc-roles { display: flex; flex-wrap: wrap; gap: 4px 6px; max-width: 460px; min-width: 260px; }
.bc-role { display: inline-flex; align-items: center; gap: 4px; font-size: 12.2px; padding: 1px 8px; border: 1px solid var(--border); border-radius: 999px; cursor: pointer; }
.bc-role:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-dark); }
.bc-role input { margin: 0; }
/* «Мои начисления»: кнопки брендов */
.acc-dot { display: inline-block; width: 9px; height: 9px; border-radius: 3px; margin-right: 6px; vertical-align: 0; }
a.chip.on .acc-dot { outline: 1.5px solid #fff; }
/* Логистика: «указать клиентов и суммы» — строки видны только при этом выборе */
.lp-pick { display: none; margin: 6px 0 0 26px; }
.lp-modes:has(input[value="pick"]:checked) .lp-pick { display: block; }
.lp-pick-row { display: grid; grid-template-columns: minmax(0, 340px) 140px; gap: 8px; margin-bottom: 6px; }
@media (max-width: 640px) { .lp-pick-row { grid-template-columns: 1fr; } .lp-pick { margin-left: 0; } }

/* ===== v6.149.0 — «Финансы» 14 → 5: ряд вкладок раздела ===== */
.fin-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }
.fin-tabs a { display: inline-flex; align-items: center; padding: 6px 13px; border-radius: 9px; border: 1px solid var(--border); background: var(--surface); color: var(--text-2); font-weight: 600; font-size: 13px; text-decoration: none; }
.fin-tabs a:hover { border-color: var(--accent); color: var(--accent-dark); text-decoration: none; }
.fin-tabs a.on { background: var(--accent); border-color: var(--accent); color: #fff; }
/* «Расходы»: график по месяцам и структура деревом (v6.149.0) */
.exp-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12.5px; color: var(--text-2); }
.exp-legend span { display: inline-flex; align-items: center; gap: 5px; }
.exp-legend i, .exp-dot { display: inline-block; width: 10px; height: 10px; border-radius: 3px; flex: 0 0 auto; }
.exp-dot { margin-right: 7px; vertical-align: 0; }
.exp-svg { display: block; width: 100%; height: auto; }
.exp-grid { stroke: var(--border); stroke-width: 1; }
.exp-ax { font-size: 11px; fill: var(--muted); }
.exp-hit { fill: transparent; }
.exp-col:hover .exp-hit { fill: var(--accent-soft); }
.exp-tree > summary { list-style: none; cursor: pointer; }
.exp-tree > summary::-webkit-details-marker { display: none; }
.exp-tree > summary .hbar-name::before { content: '▸'; color: var(--muted); margin-right: 6px; display: inline-block; width: 10px; }
.exp-tree[open] > summary .hbar-name::before { content: '▾'; }
.exp-child .hbar-name { padding-left: 34px; color: var(--text-2); font-size: 13px; }
/* «Разобрано» по статьям, правила по дереву (v6.149.0) */
tr.sp-grp td { background: var(--surface-2); }
tr.sp-norule td { color: var(--muted); }
.pay-dir { margin-bottom: 10px; }

/* Пустая рамка под кнопкой «Сохранить условия» — не показывать, пока кнопка спрятана (v6.149.0) */
.lock-save-card:has([data-lock-save][hidden]) { display: none; }

/* Справочник брендов одной формой (v6.149.0, макет 184 раздел 3) */
.bc-pal { grid-template-columns: repeat(6, 22px); }
.bc-sw.bc-taken { opacity: .25; cursor: not-allowed; }
.bc-sw.bc-taken::after { content: ""; position: absolute; left: -2px; right: -2px; top: 10px; height: 2px; background: var(--text); transform: rotate(-45deg); }
.bc-dd { position: relative; display: inline-block; }
.bc-dd > summary { list-style: none; min-width: 180px; text-align: left; justify-content: space-between; }
.bc-dd > summary::-webkit-details-marker { display: none; }
.bc-dd > summary::after { content: "▾"; margin-left: 6px; color: var(--muted); }
.bc-dd-menu { position: static; margin-top: 4px; min-width: 230px; background: var(--surface); border: 1px solid var(--border-strong, var(--border)); border-radius: 8px; box-shadow: 0 8px 24px rgba(16,21,28,.14); padding: 6px 8px; display: grid; gap: 2px; }
.bc-dd-menu .check { margin: 0; padding: 3px 4px; font-size: 13px; }
.bc-dd-all { border-bottom: 1px solid var(--border); padding-bottom: 6px !important; margin-bottom: 2px !important; font-weight: 600; }
.bc-save { background: var(--surface); }
.bc-dd-menu .bc-person { padding-left: 28px; font-weight: 400; }
.bc-dd-menu .bc-role-row { margin-top: 4px; }
.bc-dd-menu .bc-person span { font-weight: 400; }

/* Ставки клиента: «одинаково / по брендам» в блоках менеджера и маркетинга (v6.149.0, макет 186) */
.rt-mode { display: flex; gap: 16px; flex-wrap: wrap; margin: 4px 0 8px; }
.rt-mode .check { margin: 0; }
.rt-table { width: auto; min-width: min(560px, 100%); }
.rt-table td, .rt-table th { padding: 6px 10px; }
.rt-table .rt-in { width: 96px; }
.rt-dot { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 7px; vertical-align: -1px; }
.rt-off { margin-top: 8px; font-size: 12.5px; color: var(--text-2); border-top: 1px dashed var(--border); padding-top: 8px; max-width: 110ch; }

/* Категории деревом по брендам (v6.150.0, макет 188 v2) */
.cat-tree .ct-head td { background: var(--surface-2); border-top: 1px solid var(--border); }
.cat-tree .ct-dot, .pt-dot { display: inline-block; width: 11px; height: 11px; border-radius: 3px; margin-right: 8px; vertical-align: -1px; }
.cat-tree .ct-empty td { padding-left: 34px; }

/* «Товары» деревом от бренда (v6.150.0, макет 188 v2) */
.pt-switch { display: flex; gap: 10px; align-items: center; margin: 0 0 10px; flex-wrap: wrap; }
.pt-switch .seg-group { display: inline-flex; gap: 4px; }
.pt-tree details > summary { list-style: none; cursor: pointer; display: flex; gap: 8px; align-items: center; padding: 8px 10px; border-radius: 8px; }
.pt-tree details > summary::-webkit-details-marker { display: none; }
.pt-tree details > summary::before { content: "▸"; color: var(--muted); width: 12px; flex: 0 0 12px; }
.pt-tree details[open] > summary::before { content: "▾"; }
.pt-tree details > summary:hover { background: var(--surface-2); }
.pt-brand { border-top: 1px solid var(--border); }
.pt-brand:first-child { border-top: 0; }
.pt-brand > summary { font-size: 15px; }
.pt-cat > summary { padding-left: calc(28px + var(--lvl, 0) * 22px); }
.pt-n { margin-left: auto; color: var(--text-2); font-variant-numeric: tabular-nums; }
.pt-add { margin-left: 8px; }
.pt-prod { margin: 0 0 6px; width: 100%; }
.pt-prod td:first-child { padding-left: calc(48px + var(--lvl, 0) * 22px); }
/* Строка товара в дереве: миниатюра вместо артикула (v6.153.0, задача Игоря №1) */
.pt-prow { display: inline-flex; align-items: center; gap: 10px; min-width: 0; }
.pt-prow .pt-ph { flex: 0 0 34px; }
.pt-prow .thumb-ph { display: grid; }
.pt-empty { padding: 4px 0 10px 40px; }

/* Карточка вкладками (v6.151.0, макет 189 v2) */
.ctabs { margin-bottom: 14px; }
.tabs a[hidden] { display: none !important; }
[data-ctab-off] { display: none !important; }
.ub-list { display: grid; max-width: 520px; border: 1px solid var(--border); border-radius: 8px; }
.ub-row { display: flex; align-items: center; gap: 8px; padding: 9px 12px; border-top: 1px solid var(--border); }
.ub-row:first-child { border-top: 0; }
.ub-row .xs { margin-left: auto; }
.ub-dot { display: inline-block; width: 10px; height: 10px; border-radius: 3px; flex: none; }
.seg-links { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.seg-links a { padding: 5px 12px; font-size: 13px; color: var(--text); text-decoration: none; border-left: 1px solid var(--border); }
.seg-links a:first-child { border-left: 0; }
.seg-links a:hover { background: var(--surface-2, #f3f5f8); text-decoration: none; }
.seg-links a.on { background: var(--accent-soft, #e8f0fe); color: var(--accent-dark); font-weight: 600; }

/* Бонусы по брендам в расчёте зарплаты (v6.152.0, макет 191 v2) */
.pb-grid { display: grid; grid-template-columns: minmax(220px, 2fr) repeat(4, minmax(90px, 1fr)) minmax(120px, 1.4fr); gap: 12px; align-items: center; padding: 9px 16px; }
.pb-head { font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); border-bottom: 1px solid var(--border); }
.pb-grid .num { text-align: right; font-variant-numeric: tabular-nums; }
.pb-brand { border-bottom: 1px solid var(--border); }
.pb-brand > summary { cursor: pointer; list-style: none; }
.pb-brand > summary::-webkit-details-marker { display: none; }
.pb-brand > summary:hover { background: var(--surface-2); }
.pb-brand > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.pb-name { display: flex; align-items: center; gap: 6px; min-width: 0; }
.pb-car { display: inline-block; width: 12px; color: var(--muted); transition: transform .15s; }
.pb-brand[open] .pb-car { transform: rotate(90deg); }
.pb-bar { display: block; height: 8px; border-radius: 4px; background: var(--surface-2); overflow: hidden; }
.pb-bar i { display: block; height: 100%; }
.pb-inv { padding: 4px 16px 14px 34px; background: var(--surface-2); }
.pb-inv table { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; }
.pb-foot { background: var(--surface-2); }
@media (max-width: 760px) { .pb-grid { grid-template-columns: 1fr repeat(3, auto); } .pb-grid > :nth-child(5), .pb-grid > :nth-child(6) { display: none; } }

/* «Клиенты закупают меньше обычного» — окно на главной (v6.152.0, макет 192 v2) */
#modalDips .modal.wide { max-width: 1120px; }
.dip-table .dip-group th { background: var(--surface-2); text-align: left; font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.data.dip-table td { vertical-align: top; }
.dip-client { min-width: 240px; }
.dip-new .dip-client a { color: var(--text); }
.dip-acts { white-space: nowrap; text-align: right; width: 1%; }
.dip-acts .dip-snz[open] { display: block; }
.dip-inline { display: inline; }
.dip-snz { display: inline-block; text-align: left; vertical-align: top; }
.dip-snz > summary { list-style: none; cursor: pointer; }
.dip-snz > summary::-webkit-details-marker { display: none; }
.dip-snz[open] > summary { background: var(--surface-2); }
/* Раскрывается в самой строке, а не всплывашкой: окно прокручивает таблицу
   внутри себя, и всплывашку обрезало бы краем таблицы */
.dip-form { margin-top: 6px; width: 230px; margin-left: auto; background: var(--surface); border: 1px solid var(--border);
  border-radius: 10px; padding: 10px 12px; display: grid; gap: 8px; white-space: normal; }
.dip-kinds { display: grid; gap: 4px; }
.dip-kinds .check span { white-space: normal; }
.dip-form input[type=text] { width: 100%; }
.dip-rule { padding: 10px 16px 14px; }

/* «Решения по этому возврату» — подписи и значения слипались: у блока не было
   стилей (v6.153.1, замечено на снимке для отчёта Игорю) */
.ret-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px 24px; }
.ret-facts > div { display: flex; flex-direction: column; gap: 2px; }
.ret-facts .l { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .03em; }
.ret-facts .v { font-weight: 600; }
.ret-facts .v .small, .ret-facts .v .xs { font-weight: 400; }

/* Файл перевозчика: проверка строк (v6.159.0, макет 198 v3) */
table.data.lf-table td { vertical-align: top; }
table.data.lf-table tr.lf-dup td { opacity: .55; background: var(--surface-2); }
table.data.lf-table tr.lf-dup td:nth-child(6) { opacity: 1; }
.lf-table select { max-width: 34ch; }
.lf-table select.lf-open { border-color: var(--amber); box-shadow: 0 0 0 2px var(--amber-soft); }
.lf-table input[type=date] { width: 15ch; }
.lf-table .lf-warn { color: var(--amber); font-weight: 600; }
.lf-table .lf-good { color: var(--green); }

/* Логотип компании над меню (v6.159.3, макет 203; полоса меню убрана в 6.159.4) */
/* Без линии под логотипом — нет «ступеньки» с шапкой 56 точек; размер — по
   «весу» из BrandService::logoBox (v6.159.7, макет 206, вариант 2) */
.brand.brand-co { height: 88px; justify-content: center; padding: 0 14px; border-bottom-color: transparent; }
.brand-co-logo { max-width: 100%; height: auto; display: block; object-fit: contain; }

/* Сверка «файл ↔ платежи» внизу (v6.159.7, макет 199) */
.lp-sverka { display: grid; gap: 4px; max-width: 520px; padding: 10px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2); }
.lp-sv-row { display: flex; justify-content: space-between; gap: 12px; font-variant-numeric: tabular-nums; }
.lp-sv-diff { border-top: 1px solid var(--border); padding-top: 4px; margin-top: 2px; }
.lp-sverka.is-ok .lp-sv-diff b { color: var(--green); }
.lp-sverka.is-over .lp-sv-diff b { color: var(--amber); }
.lp-sverka.is-under .lp-sv-diff b { color: var(--amber); }
.lp-sv-note { color: var(--text-2); margin-top: 4px; }
.lp-where { margin-top: 14px; }
.lp-extra { color: var(--text-2); }
/* Запомненные названия: «Изменить» раскрывает выбор на месте */
.lm-edit { display: inline-block; vertical-align: top; }
.lm-edit > summary { list-style: none; cursor: pointer; }
.lm-edit > summary::-webkit-details-marker { display: none; }
.lm-edit-form { display: flex; gap: 6px; margin-top: 6px; }
.lm-edit-form select { max-width: 32ch; }
.lp-left { color: var(--amber); font-weight: 600; }
