/* ============================================================================
   DR.Electric — Design System  (ds.css)
   Профессиональный B2B-инструмент. Светлая тема. Бренд-зелёный #226f54.
   Плоско, плотно, без AI-эстетики. Всё на 4/8-сетке.
   ============================================================================ */

/* ---- 1. Токены --------------------------------------------------------- */
:root {
  color-scheme: light;

  /* Поверхности (нейтрально-холодные, насыщенность < 0.02) */
  --bg:           oklch(97.6% 0.003 250);   /* рабочий фон  */
  --panel:        #ffffff;                  /* карточки/панели */
  --panel-2:      oklch(98.2% 0.004 250);   /* вложенные блоки */
  --panel-3:      oklch(96.4% 0.005 250);   /* шапки таблиц */

  /* Текст */
  --ink:          oklch(28% 0.012 255);     /* основной */
  --ink-2:        oklch(42% 0.012 255);     /* вторичный сильный */
  --muted:        oklch(55% 0.014 255);     /* подписи */
  --faint:        oklch(58% 0.012 255);     /* плейсхолдеры (AA на белом) */

  /* Линии */
  --line:         oklch(90% 0.006 255);     /* основная граница */
  --line-strong:  oklch(83% 0.008 255);     /* акцентная граница */

  /* Бренд */
  --accent:       #226f54;
  --accent-strong:#18583f;
  --accent-tint:  oklch(96% 0.03 158);      /* зелёная подложка */
  --accent-tint-2:oklch(92% 0.05 158);

  /* Семантика статусов — доверие. Одинаковая L/C, разный hue. */
  --ok:           oklch(52% 0.13 155);      /* зелёный — подобрано  */
  --ok-tint:      oklch(95% 0.04 155);
  --ok-line:      oklch(85% 0.07 155);

  --warn:         oklch(58% 0.13 75);       /* жёлтый — проверь */
  --warn-tint:    oklch(96% 0.05 85);
  --warn-line:    oklch(85% 0.09 80);

  --danger:       oklch(53% 0.17 28);       /* красный — не найдено */
  --danger-tint:  oklch(96% 0.03 28);
  --danger-line:  oklch(86% 0.07 28);

  --review:       oklch(52% 0.012 255);     /* серый — ИИ не уверен */
  --review-tint:  oklch(94% 0.004 255);
  --review-line:  oklch(84% 0.008 255);

  --info:         oklch(52% 0.12 250);      /* синий — нейтр. инфо */
  --info-tint:    oklch(96% 0.03 250);
  --info-line:    oklch(85% 0.06 250);

  /* Типографика */
  --font-sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;

  --fs-xs:   11px;  /* кикеры, бэйджи */
  --fs-sm:   12px;  /* мета, вторичный текст таблиц */
  --fs-base: 13px;  /* тело, основной текст таблиц */
  --fs-md:   15px;  /* заголовки панелей */
  --fs-lg:   18px;  /* заголовки секций */
  --fs-xl:   22px;  /* заголовок страницы */

  --lh-tight: 1.25;
  --lh-base:  1.5;

  /* Шаг 4/8 */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-7: 32px; --sp-8: 40px;

  /* Радиусы — 2 уровня */
  --r-sm: 6px;
  --r-md: 10px;
  --r-pill: 999px;

  /* Тени — едва заметные, без перегруза */
  --shadow-1: 0 1px 2px oklch(40% 0.02 255 / 0.06);
  --shadow-2: 0 4px 14px oklch(40% 0.02 255 / 0.10);
  --ring: 0 0 0 3px oklch(52% 0.13 155 / 0.30);

  /* Геометрия раскладки */
  --rail-w: 232px;
  --topbar-h: 60px;
  --row-h: 44px;            /* плотность таблицы по умолчанию */
}

/* ---- 2. Сброс / база --------------------------------------------------- */
* { box-sizing: border-box; }

[hidden] { display: none !important; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

h1 { font-size: var(--fs-xl); font-weight: 600; letter-spacing: -0.01em; }
h2 { font-size: var(--fs-md); font-weight: 600; }
h3 { font-size: var(--fs-base); font-weight: 600; }

a { color: var(--accent-strong); }

::selection { background: var(--accent-tint-2); }

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

.mono { font-family: var(--font-mono); font-feature-settings: "tnum" 1; }
.num  { font-variant-numeric: tabular-nums; }
.right { text-align: right; }
.kicker {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.muted { color: var(--muted); }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* ---- 3. Кнопки --------------------------------------------------------- */
.btn {
  --bg-btn: var(--panel);
  --fg-btn: var(--ink);
  --bd-btn: var(--line-strong);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 34px;
  padding: 0 var(--sp-3);
  border: 1px solid var(--bd-btn);
  border-radius: var(--r-sm);
  background: var(--bg-btn);
  color: var(--fg-btn);
  font: inherit;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.btn:hover { background: var(--panel-3); border-color: var(--ink-2); }
.btn:active { background: var(--panel-2); }
.btn:disabled { cursor: not-allowed; opacity: .5; }
/* Disabled-кнопка не должна читаться активной: primary теряет заливку
   (критика 15.08: зелёная неактивная кнопка «Загрузить…» выглядела рабочей). */
.btn--primary:disabled { background: var(--panel-2, #e5e7eb); border-color: var(--line, #d1d5db); color: var(--muted, #6b7280); opacity: 1; }
.btn svg { flex: none; }

.btn--primary {
  --bg-btn: var(--accent);
  --fg-btn: #fff;
  --bd-btn: var(--accent);
}
.btn--primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); }
.btn--primary:active { background: var(--accent-strong); }

.btn--danger {
  --fg-btn: var(--danger);
  --bd-btn: var(--danger-line);
}
.btn--danger:hover { background: var(--danger); color: #fff; border-color: var(--danger); }

.btn--ghost { --bd-btn: transparent; --bg-btn: transparent; }
.btn--ghost:hover { background: var(--panel-3); border-color: transparent; }

.btn--sm { min-height: 28px; padding: 0 var(--sp-2); font-size: var(--fs-sm); }
.btn--icon { padding: 0; width: 34px; }
.btn--icon.btn--sm { width: 28px; }

/* ---- 4. Поля ----------------------------------------------------------- */
.field { display: grid; gap: var(--sp-1); min-width: 0; }
.field > .label {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--muted);
}
.input, .select, .textarea {
  width: 100%;
  min-height: 34px;
  padding: 6px var(--sp-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--panel);
  color: var(--ink);
  font: inherit;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.textarea { padding: var(--sp-2); resize: vertical; min-height: 56px; line-height: var(--lh-base); }
.input::placeholder, .textarea::placeholder { color: var(--faint); }
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.input:disabled, .select:disabled, .textarea:disabled {
  background: var(--panel-3);
  color: var(--muted);
  cursor: not-allowed;
}
.select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-2) center;
  padding-right: var(--sp-7);
}
.select--sm { min-height: 28px; padding-top: 3px; padding-bottom: 3px; font-size: var(--fs-sm); }
.input--search {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.2-3.2'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: var(--sp-2) center;
  padding-left: var(--sp-7);
}
.input--mono { font-family: var(--font-mono); }

/* ---- 5. Панели / карточки --------------------------------------------- */
.panel {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
  box-shadow: var(--shadow-1);
}
.panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line);
}
.panel__head .titlewrap { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.panel__head .titlewrap h2 { white-space: nowrap; }
.panel__head .titlewrap svg { color: var(--muted); flex: none; }
.panel__body { padding: var(--sp-4); }
.panel__body--flush { padding: 0; }
.panel__count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 20px; padding: 0 6px;
  border-radius: var(--r-pill);
  background: var(--panel-3); color: var(--ink-2);
  font-size: var(--fs-xs); font-weight: 600;
}

/* ---- 6. Статус-язык (color + icon + text) ------------------------------ */
.status {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 22px;
  padding: 0 8px 0 6px;
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  font-size: var(--fs-xs);
  font-weight: 600;
  white-space: nowrap;
}
.status svg { width: 13px; height: 13px; }
.status--ok     { background: var(--ok-tint);     color: var(--ok);     border-color: var(--ok-line); }
.status--warn   { background: var(--warn-tint);   color: var(--ds-warn-ink, oklch(40% 0.12 58)); border-color: var(--warn-line); }
.status--danger { background: var(--danger-tint); color: var(--danger); border-color: var(--danger-line); }
.status--review { background: var(--review-tint); color: var(--review); border-color: var(--review-line); }
.status--neutral{ background: var(--panel-3);     color: var(--muted);  border-color: var(--line); }
.status--info   { background: var(--info-tint);   color: var(--info);   border-color: var(--info-line); }

/* левая цветовая риска строки таблицы по статусу */
.rowflag-ok     { box-shadow: inset 3px 0 0 var(--ok); }
.rowflag-warn   { box-shadow: inset 3px 0 0 var(--warn); }
.rowflag-danger { box-shadow: inset 3px 0 0 var(--danger); }
.rowflag-review { box-shadow: inset 3px 0 0 var(--review); }

/* счётчик-чип статуса (шапка таблицы / фильтры) */
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 30px; padding: 0 var(--sp-2) 0 var(--sp-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--panel);
  font-size: var(--fs-sm); font-weight: 500; color: var(--ink-2);
  cursor: pointer; white-space: nowrap;
  transition: background .12s, border-color .12s;
}
.chip:hover { background: var(--panel-3); }
/* Волна C: активные оси дропдауна видимы на самом чипе «Фильтры · N ▾». */
.chip.is-active { border-color: var(--accent); color: var(--accent); background: var(--accent-tint); font-weight: 600; }
.chip .dot { width: 9px; height: 9px; border-radius: var(--r-pill); flex: none; }
.chip .chip__n { font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.chip[aria-pressed="true"] { border-color: var(--ink-2); background: var(--panel-3); box-shadow: var(--shadow-1); }
.chip.is-empty { opacity: .55; }
.dot--ok { background: var(--ok); } .dot--warn { background: var(--warn); }
.dot--danger { background: var(--danger); } .dot--review { background: var(--review); }
.dot--neutral { background: var(--muted); } .dot--all { background: var(--accent); }

/* ---- 7. Таблицы -------------------------------------------------------- */
.tablewrap { width: 100%; overflow: auto; }
table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-base);
}
table.data thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--panel-3);
  color: var(--ink-2);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  text-align: left;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line-strong);
  white-space: nowrap;
}
table.data thead th.right { text-align: right; }
table.data tbody td {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
  color: var(--ink);
}
table.data tbody tr { background: var(--panel); transition: background .1s; }
table.data tbody tr:hover { background: var(--panel-2); }
table.data tbody tr.is-selected { background: var(--accent-tint); }
table.data tbody tr.is-selected:hover { background: var(--accent-tint-2); }
table.data.is-compact { --row-h: 36px; font-size: var(--fs-sm); }
table.data.is-compact tbody td { padding: 5px var(--sp-3); }
table.data tbody tr td:first-child,
table.data thead th:first-child { padding-left: var(--sp-4); }
table.data tbody tr td:last-child,
table.data thead th:last-child { padding-right: var(--sp-4); }
.cell-strong { font-weight: 600; }
.cell-sub { color: var(--muted); font-size: var(--fs-sm); margin-top: 1px; }

/* ---- 8. Toast ---------------------------------------------------------- */
.toast-stack {
  position: fixed; right: var(--sp-4); bottom: var(--sp-4);
  display: grid; gap: var(--sp-2); z-index: 60; max-width: min(420px, calc(100vw - 32px));
}
.toast {
  display: flex; align-items: flex-start; gap: var(--sp-2);
  padding: var(--sp-3); border-radius: var(--r-md);
  background: oklch(26% 0.012 255); color: #fff;
  box-shadow: var(--shadow-2);
  animation: toast-in .18s ease;
}
.toast svg { flex: none; margin-top: 1px; }
.toast--ok svg { color: oklch(78% 0.13 155); }
.toast--danger svg { color: oklch(75% 0.14 28); }
.toast--warn svg { color: oklch(80% 0.13 75); }
.toast--info svg { color: oklch(78% 0.11 250); }
.toast__body { font-size: var(--fs-sm); line-height: var(--lh-base); }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } }

/* ---- 9. Empty / Error / Skeleton -------------------------------------- */
.empty {
  display: grid; justify-items: center; gap: var(--sp-3);
  padding: var(--sp-8) var(--sp-4);
  text-align: center;
}
.empty__icon {
  display: grid; place-items: center;
  width: 48px; height: 48px; border-radius: var(--r-md);
  background: var(--panel-3); color: var(--muted);
}
.empty__title { font-size: var(--fs-md); font-weight: 600; }
.empty__text { color: var(--muted); max-width: 42ch; text-wrap: pretty; }
.empty--error .empty__icon { background: var(--danger-tint); color: var(--danger); }

.skeleton {
  position: relative; overflow: hidden;
  background: var(--panel-3); border-radius: var(--r-sm);
}
.skeleton::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, oklch(100% 0 0 / .55), transparent);
  transform: translateX(-100%);
  animation: sk 1.25s infinite;
}
@keyframes sk { to { transform: translateX(100%); } }
.sk-line { height: 12px; }
.sk-row td { padding: var(--sp-3); }

@media (prefers-reduced-motion: reduce) {
  .skeleton::after { animation: none; }
  * { transition: none !important; }
}

/* ---- 10. Прогресс ------------------------------------------------------ */
.progress {
  height: 6px; border-radius: var(--r-pill);
  background: var(--panel-3); overflow: hidden;
}
.progress__bar {
  height: 100%; border-radius: inherit;
  background: var(--accent);
  transition: width .4s ease;
}
.progress--indeterminate .progress__bar {
  width: 35% !important;
  animation: indet 1.2s ease-in-out infinite;
}
@keyframes indet {
  0% { margin-left: -35%; } 100% { margin-left: 100%; }
}
.spin { animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- 11. Постраничный вид (Блок C) ------------------------------------ */
/* Под-режим экрана «Проект»: слева рендер страницы PDF + bbox-оверлеи,
   справа карточки позиций страницы. Реюзает .evidence-page-frame/.bbox-highlight
   (app.css). Двусторонняя связь карточка↔бокс — классы .is-active/.is-hover. */
.pages-view { display: grid; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); }

.pages-head { display: grid; gap: var(--sp-2); }
.pages-doc-tabs { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.pages-doc-tabs__name { max-width: 28ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pages-head__nav { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }

.page-nav { display: inline-flex; align-items: center; gap: var(--sp-2); }
.page-nav__pos { font-size: var(--fs-sm); }
.page-nav__pos .num { font-variant-numeric: tabular-nums; }
.page-nav__meta { font-size: var(--fs-sm); }

.page-strip { display: flex; flex-wrap: wrap; gap: 6px; }
.page-thumb {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; height: 30px; padding: 0 6px;
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--panel); color: var(--ink-2); cursor: pointer;
  font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
  transition: border-color .15s, background .15s;
}
.page-thumb:hover { border-color: var(--ink-2); background: var(--panel-3); }
.page-thumb.has-items { border-color: var(--accent); color: var(--ink); }
.page-thumb.is-active { background: var(--accent); border-color: var(--accent); color: #fff; }
.page-thumb__badge {
  position: absolute; top: -6px; right: -6px;
  min-width: 16px; height: 16px; padding: 0 4px;
  display: inline-grid; place-items: center;
  background: var(--accent); color: #fff; border-radius: var(--r-pill);
  font-size: 10px; font-weight: 700;
}
.page-thumb.is-active .page-thumb__badge { background: #fff; color: var(--accent-strong); }

/* Сетка: страница слева, карточки справа. На узком экране — стопкой. */
.pages-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(280px, 1fr); gap: var(--sp-3); align-items: start; }
.pages-grid__left, .pages-grid__right { min-width: 0; }

.pages-page { display: grid; gap: var(--sp-2); }
.pages-page__hint { font-size: var(--fs-sm); display: flex; align-items: center; gap: 6px; }
.pages-page__hint svg { flex: none; }

/* bbox-оверлей: цвет контура = статус позиции; активный/наведённый — заливка. */
.bbox-highlight { cursor: pointer; transition: background .12s, border-color .12s, box-shadow .12s; }
.bbox-highlight.bbox-tone--ok      { border-color: var(--ok); }
.bbox-highlight.bbox-tone--warn    { border-color: var(--warn); }
.bbox-highlight.bbox-tone--danger  { border-color: var(--danger); }
.bbox-highlight.bbox-tone--review  { border-color: var(--review); }
.bbox-highlight.bbox-tone--neutral { border-color: var(--muted); }
.bbox-highlight.is-hover { background: oklch(52% 0.13 155 / .22); }
.bbox-highlight.is-active {
  border-color: var(--accent); border-width: 3px;
  background: oklch(52% 0.13 155 / .28);
  box-shadow: 0 0 0 2px oklch(52% 0.13 155 / .25);
}

/* Правая панель — карточки позиций страницы. */
.pages-cards { display: grid; gap: var(--sp-2); align-content: start; }
.pages-cards__head { display: flex; align-items: center; gap: var(--sp-2); }
.pages-cards__sep {
  display: flex; align-items: center; gap: 6px;
  margin-top: var(--sp-2); padding-top: var(--sp-2);
  border-top: 1px dashed var(--line-strong);
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-2);
}

.pos-card {
  display: grid; gap: 6px;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line); border-left: 3px solid var(--line-strong);
  border-radius: var(--r-sm); background: var(--panel-2);
  cursor: pointer; transition: border-color .12s, box-shadow .12s, background .12s;
}
.pos-card:hover { border-color: var(--ink-2); background: var(--panel); }
.pos-card.is-active {
  border-color: var(--accent); border-left-color: var(--accent);
  background: var(--accent-tint); box-shadow: var(--shadow-1);
}
.pos-card.is-pending { opacity: .7; }
.pos-card__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-2); }
.pos-card__name { font-weight: 600; overflow-wrap: anywhere; }
.pos-card__agsk { font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--ink-2); }
.pos-card__agsk.is-empty { color: var(--danger); }
.pos-card__foot { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; font-size: var(--fs-sm); }
.pos-card__foot .spacer { flex: 1; }
.pos-card__price { font-variant-numeric: tabular-nums; font-weight: 600; }
.pos-card__nobox { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-xs); }
.pos-card__nobox svg { flex: none; }

.empty--sm { padding: var(--sp-4); min-height: 0; }

@media (max-width: 1080px) {
  .pages-grid { grid-template-columns: 1fr; }
}

/* ---- 12. Новый язык вёрстки — LAYOUT_SPEC v2 (волна 0) ----------------- */
/* Заготовки под перевёрстку (docs/design/2026-08-12-redesign/LAYOUT_SPEC.md,
   версия 2). Волна 0 разметку экранов НЕ трогает: здесь только добавления,
   ни один существующий класс не изменён. Префикс `ds-` — чтобы новые имена
   гарантированно не столкнулись с боевыми в app.css, который грузится ПОСЛЕ
   ds.css и иначе перекрыл бы их. Ни одного нового цвета: только переменные
   раздела 1. */

/* 12.1 Сброс. `* { box-sizing: border-box }` уже есть (раздел 2), но без
   псевдоэлементов: их паддинги и рамки считаются от content-box, из-за чего
   min-width на шапке таблицы и на обёртке тела дают разную ширину и колонки
   расходятся (LAYOUT_SPEC, преамбула). */
*::before, *::after { box-sizing: border-box; }

/* 12.2 Структурная геометрия. Отдельный блок `:root` — существующие токены
   не редактируются. Здесь только размеры, которых в спеке нет в переменных,
   и семантические псевдонимы к уже объявленным цветам. */
:root {
  /* Ширины из LAYOUT_SPEC §2.3 и §1: единая минимальная ширина таблицы и
     доки правых панелей. */
  --ds-table-min-w:    848px;
  --ds-table-cols:     minmax(190px, 1.5fr) 68px 104px 128px 52px 52px 78px 96px;
  --ds-dock-source-w:  400px;
  --ds-dock-hermes-w:  340px;

  /* Высоты, которых нет в шкале: мини-бейдж в строке. Высота полосы якорей
     групп (--ds-anchors-h) удалена волной C вместе с самой полосой (В4). */
  --ds-badge-mini-h:   18px;

  /* Псевдонимы к существующим цветам, а не новые цвета:
     внутристрочная линия спеки oklch(94% 0.004 255) — это ровно --review-tint;
     текст warn на подложке уже используется литералом в .status--warn. */
  --ds-line-inner:     var(--review-tint);
  --ds-warn-ink:       oklch(40% 0.12 58); /* AA на --warn-tint (критика 15.08) */
}

/* 12.3 Flex-строка: сжимается ТОЛЬКО текстовая колонка. Без этого при доке
   правой панели рабочая область теряет 400px и пилюли рвут текст на две
   строки (LAYOUT_SPEC §0). */
.ds-flexline { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.ds-flexline > * { flex: none; white-space: nowrap; }
.ds-flexline > .ds-flexline__text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-flexline > .ds-flexline__spacer { flex: 1 1 auto; min-width: 0; }

/* 12.4 Сегмент оси решения (LAYOUT_SPEC §2.1, строка 2). Активная кнопка —
   подложка --panel-3 и жирный --ink; это НЕ .seg из app.css, где активная
   заливается брендом. */
.ds-seg {
  display: inline-flex;
  flex: none;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--panel);
  overflow: hidden;
}
.ds-seg__btn {
  display: inline-flex; align-items: center; gap: 6px;
  height: 30px;
  padding: 0 var(--sp-3);
  border: 0;
  border-left: 1px solid var(--line);
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-size: var(--fs-sm);
  white-space: nowrap;
  cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.ds-seg__btn:first-child { border-left-color: transparent; }
.ds-seg__btn:hover { background: var(--panel-2); }
.ds-seg__btn[aria-pressed="true"] { background: var(--panel-3); color: var(--ink); font-weight: 600; }
.ds-seg__btn:disabled { opacity: .55; cursor: not-allowed; }
.ds-seg__n { font-size: var(--fs-sm); opacity: .7; font-variant-numeric: tabular-nums; }

/* 12.5 Чипы фильтров проверки. Точка-статус (.dot + .dot--*), счётчик
   (.chip__n) и подложка нулевого (.chip.is-empty) уже есть в разделе 6 —
   здесь недостающее неактивное состояние настоящей <button disabled>
   (LAYOUT_SPEC §2.2: «Нулевой чип — disabled + opacity .55»). */
.chip:disabled, .chip[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }
.chip:disabled:hover, .chip[aria-disabled="true"]:hover { background: var(--panel); }

/* 12.6 (удалено волной C, В4) Полоса якорей групп снята с экрана: вместо ряда
   чипов щитов осталась выпадашка «Все щиты · N ▾» в тулбаре. Смещение
   --ds-anchors-h упразднено вместе с лентой — шапка таблицы липнет к top: 0
   (см. комментарий у .ds-ws-table > thead). */

/* 12.7 Доки правых панелей: одна за раз, источник 400px / Гермес 340px
   (LAYOUT_SPEC §1, §2.4, §2.5). */
.ds-dock {
  flex: none;
  overflow: auto;
  background: var(--panel);
  border-left: 1px solid var(--line);
}
.ds-dock--source { width: var(--ds-dock-source-w); }
.ds-dock--hermes { width: var(--ds-dock-hermes-w); }
.ds-dock__head {
  position: sticky; top: 0; z-index: 5;
  padding: var(--sp-3) var(--sp-4);
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}
.ds-dock__body {
  display: flex; flex-direction: column; gap: var(--sp-4);
  padding: 14px var(--sp-4);
}
.ds-dock__foot {
  position: sticky; bottom: 0;
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 10px var(--sp-4);
  background: var(--panel);
  border-top: 1px solid var(--line);
}

/* 12.8 Сетка рабочей таблицы проекта (LAYOUT_SPEC §2.3).
   Минимальная ширина задаётся РОВНО ДВА раза — на шапке и на обёртке тела,
   обе в border-box. На .ds-ws__row min-width НЕ ставить: с max-content каждая
   строка возьмёт свою ширину по длине наименования и таблица поедет
   лесенкой. */
.ds-ws { overflow-x: auto; }
.ds-ws__head {
  position: sticky; top: 0; z-index: 15;
  display: grid;
  grid-template-columns: var(--ds-table-cols);
  gap: var(--sp-2);
  min-width: var(--ds-table-min-w);
  padding: 7px var(--sp-3);
  background: var(--panel-3);
  border: 1px solid var(--line);
  border-bottom: 1px solid var(--line-strong);
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.ds-ws__body {
  min-width: var(--ds-table-min-w);
  background: var(--panel);
  border: 1px solid var(--line);
  border-top: 0;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
}
.ds-ws__row {
  display: grid;
  grid-template-columns: var(--ds-table-cols);
  gap: var(--sp-2);
  align-items: center;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--ds-line-inner);
  cursor: pointer;
  transition: background .12s ease;
}
.ds-ws__row:hover { background: var(--panel-2); }
.ds-ws__row.is-selected { background: var(--accent-tint); }
.ds-ws__cell { min-width: 0; }
.ds-ws__cell.right { text-align: right; }
.ds-ws__name { font-size: var(--fs-base); font-weight: 500; overflow-wrap: anywhere; }
/* Имя строки — кнопка открытия панели позиции (волна 1 редизайна). */
.ds-ws__name--btn { display: block; width: 100%; padding: 0; margin: 0; border: 0; background: none; text-align: left; font: inherit; color: inherit; cursor: pointer; }
.ds-ws__name--btn:hover { color: var(--brand, #226f54); text-decoration: underline; }
.ds-ws__sub { font-size: var(--fs-xs); color: var(--muted); }
/* Исключённая позиция — одна строка, не скрывается (LAYOUT_SPEC §2.3). */
.ds-ws__row--excluded {
  display: block;
  padding: 6px var(--sp-3) 6px 22px;
  font-size: var(--fs-sm);
  color: var(--faint);
  cursor: default;
}
.ds-ws__row--excluded .ds-ws__name { font-weight: 400; text-decoration: line-through; }

/* Спокойная риска: место под цветную полосу занято, но не окрашено
   (LAYOUT_SPEC §2.3: «у ok — transparent»). Семейство .rowflag-* — раздел 6. */
.rowflag-none { box-shadow: inset 3px 0 0 transparent; }

/* 12.9 Заголовок группы — ДВЕ строки (LAYOUT_SPEC §2.3). Одной строкой не
   ставить: фиксированного содержимого больше 400px, и при доке правой панели
   имя группы схлопывается в ноль. */
.ds-group {
  display: flex; flex-direction: column; gap: 3px;
  padding: 9px var(--sp-3);
  background: var(--panel-2);
  border-top: 1px solid var(--line-strong);
  border-bottom: 1px solid var(--line);
}
.ds-group__line { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.ds-group__line > * { flex: none; white-space: nowrap; }
.ds-group__line > .ds-group__spacer { flex: 1 1 auto; min-width: 0; }
.ds-group__line > .ds-group__meta {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--muted);
}
.ds-group__line--meta { padding-left: 26px; }
.ds-group__name { font-size: var(--fs-base); font-weight: 700; }
.ds-group__sum {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* Единственный свободный ввод в шапке группы — сборка (работы).
   Комплектация считается сама и только показывается (LAYOUT_SPEC §5.1). */
.ds-group__assembly {
  width: 74px;
  text-align: right;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* 12.10 Мини-бейдж статуса в строке — 18px, только у проблемных
   (LAYOUT_SPEC §0, §2.3). Тона повторяют .status, но в высоте строки. */
.ds-badge-mini {
  display: inline-flex; align-items: center; gap: 4px;
  flex: none;
  height: var(--ds-badge-mini-h);
  padding: 0 6px;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}
.ds-badge-mini svg { width: 11px; height: 11px; flex: none; }
.ds-badge-mini--ok      { background: var(--ok-tint);     color: var(--ok);        border-color: var(--ok-line); }
.ds-badge-mini--warn    { background: var(--warn-tint);   color: var(--ds-warn-ink); border-color: var(--warn-line); }
.ds-badge-mini--danger  { background: var(--danger-tint); color: var(--danger);    border-color: var(--danger-line); }
.ds-badge-mini--review  { background: var(--review-tint); color: var(--review);    border-color: var(--review-line); }
.ds-badge-mini--info    { background: var(--info-tint);   color: var(--info);      border-color: var(--info-line); }
.ds-badge-mini--neutral { background: var(--panel-3);     color: var(--muted);     border-color: var(--line); }

/* ---- 13. Экраны справочников: эталон, прайсы поставщиков, база кроссов ---
   Волна 6 перевёрстки (docs/tasks/2026-08-12-redesign-w6-references.md,
   LAYOUT_SPEC §4). Только добавления и только существующие токены раздела 1:
   ни одного нового цвета, шкала кеглей не расширена (в макетах остался 14px —
   берём ближайший из шкалы, --fs-md). Размеры сеток объявлены переменными,
   а не литералами в разметке — как в разделе 12. */

:root {
  /* Ширина липкой карточки изделия (LAYOUT_SPEC §4 «Эталон»). */
  --ds-ref-card-w:  460px;

  /* Сетки таблиц справочников. Минимальная ширина задаётся один раз на
     .ds-grid__head и .ds-grid__row — обе в border-box (раздел 12.1). */
  --ds-cross-cols:  140px 100px 140px minmax(170px, 1fr) 92px 96px;
  --ds-cross-min-w: 820px;
  --ds-map-cols:    32px 116px minmax(170px, 1.5fr) minmax(150px, 1.2fr) 150px 100px 100px 108px;
  --ds-map-min-w:   970px;
  --ds-agsk-price-cols:  116px minmax(170px, 1.5fr) 92px 100px 100px 92px;
  --ds-agsk-price-min-w: 880px;

  /* Радиус паспорт-чипа в карточке результата — единственный размер, которого
     нет в шкале радиусов (LAYOUT_SPEC §4: «паспорт-чипы 11px … radius 4»). */
  --ds-r-tag:       4px;
}

/* 13.1 Экран справочника: шапка на фоне страницы (белую полосу занимает
   топбар проекта из волны 1 — второй такой же полосы над ним не ставим). */
.ds-screen {
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: 14px var(--sp-5) 30px;
  min-width: 0;
}
.ds-head { display: flex; align-items: flex-start; gap: var(--sp-3); min-width: 0; }
.ds-head__titles { display: grid; gap: 2px; min-width: 0; }
.ds-head h1 { font-size: var(--fs-md); font-weight: 600; letter-spacing: -0.01em; }
.ds-head__sub { font-size: var(--fs-sm); color: var(--muted); max-width: 78ch; text-wrap: pretty; }
.ds-head__actions { display: flex; align-items: center; gap: var(--sp-2); flex: none; margin-left: auto; }
/* Вертикальная стопка блоков экрана с тем же шагом, что и .ds-screen. */
.ds-stack { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; }

/* 13.2 Плитки счётчиков (LAYOUT_SPEC §4 «База кроссов»). Цвет значения —
   по смыслу, из семантики раздела 1. */
.ds-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
.ds-stat {
  display: grid; gap: var(--sp-1); align-content: start;
  padding: 12px 14px; min-width: 0;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
}
.ds-stat__label { font-size: var(--fs-sm); color: var(--muted); }
.ds-stat__value { font-size: var(--fs-lg); font-weight: 600; font-variant-numeric: tabular-nums; }
.ds-stat__value--ok   { color: var(--ok); }
.ds-stat__value--info { color: var(--info); }

/* 13.3 Панель справочника: шапка, полоса фильтров, подвал. */
.ds-panel {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-md); overflow: hidden; min-width: 0;
}
/* Шапка переносится: при открытой правой панели рабочая область теряет до
   400px, и кнопки действий иначе уезжают за край (LAYOUT_SPEC §5.10). */
.ds-panel__head {
  display: flex; align-items: center; gap: 10px; min-width: 0; flex-wrap: wrap;
  padding: 12px var(--sp-4); border-bottom: 1px solid var(--line);
}
.ds-panel__head > * { flex: none; white-space: nowrap; }
.ds-panel__head > .ds-panel__spacer { flex: 1 1 auto; min-width: 0; white-space: normal; }
.ds-panel__title { font-weight: 600; }
.ds-panel__bar {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 10px var(--sp-4); border-bottom: 1px solid var(--ds-line-inner);
}
.ds-panel__bar > .ds-panel__spacer { flex: 1 1 auto; min-width: 0; }
.ds-panel__body { padding: var(--sp-3) var(--sp-4); }
/* Соседние секции панели разделяются линией, а не воздухом. */
.ds-panel__body + .ds-panel__body { border-top: 1px solid var(--line); }
.ds-panel__foot {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: 10px var(--sp-4);
}
.ds-panel__foot > .ds-panel__spacer { flex: 1 1 auto; min-width: 0; }
.ds-panel__foot label { white-space: nowrap; flex: none; }
/* Счётчик-пилюля 20px (LAYOUT_SPEC §0). */
.ds-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 20px; padding: 0 6px; flex: none; white-space: nowrap;
  border-radius: var(--r-pill); background: var(--panel-3); color: var(--ink-2);
  font-size: var(--fs-xs); font-weight: 600;
}

/* 13.4 Сетчатая таблица справочника. Колонки задаёт модификатор, а не
   инлайн-стиль: набор колонок — часть спеки, а не данных строки. */
.ds-grid { overflow-x: auto; }
.ds-grid__head, .ds-grid__row {
  display: grid;
  grid-template-columns: var(--ds-grid-cols);
  gap: 10px; align-items: center;
  min-width: var(--ds-grid-min-w);
}
.ds-grid__head {
  padding: 7px var(--sp-4);
  background: var(--panel-3); border-bottom: 1px solid var(--line-strong);
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--ink-2);
}
.ds-grid__row {
  padding: 8px var(--sp-4);
  border-bottom: 1px solid var(--ds-line-inner);
  transition: background .12s ease;
}
.ds-grid__row:last-child { border-bottom: 0; }
.ds-grid__row:hover { background: var(--panel-2); }
.ds-grid__cell { min-width: 0; overflow-wrap: anywhere; }
.ds-grid__cell.right { text-align: right; }
.ds-grid__cell > .status, .ds-grid__cell > .ds-badge-mini { justify-self: start; }
.ds-grid__sub { font-size: var(--fs-xs); color: var(--muted); }
/* Внутри ячейки подпись и наименование — строками, а не в подбор. */
.ds-grid__cell > .ds-grid__sub, .ds-grid__cell > .ds-grid__line { display: block; }
.ds-grid__none { color: var(--faint); }
/* Низкая уверенность подбора — тем же warn-тоном, что и мини-бейджи. */
.ds-grid__warn { color: var(--ds-warn-ink); }
.ds-price-load-warning {
  padding: 6px 16px;
  background: var(--danger-tint);
  color: var(--danger);
  font-size: var(--fs-sm);
}
/* Пустое состояние и ошибка живут по ширине видимой области, а не таблицы:
   строк нет — незачем заставлять менеджера прокручивать пустоту вбок. */
.ds-grid__empty { padding: var(--sp-3); }
.ds-grid--cross { --ds-grid-cols: var(--ds-cross-cols); --ds-grid-min-w: var(--ds-cross-min-w); }
.ds-grid--map   { --ds-grid-cols: var(--ds-map-cols);   --ds-grid-min-w: var(--ds-map-min-w); }
.ds-grid--agsk-price { --ds-grid-cols: var(--ds-agsk-price-cols); --ds-grid-min-w: var(--ds-agsk-price-min-w); }

/* 13.5 Эталон: результаты слева, липкая карточка изделия справа. */
.ds-split {
  display: grid; grid-template-columns: minmax(0, 1fr) var(--ds-ref-card-w);
  gap: 14px; align-items: start; min-width: 0;
}
.ds-split__main { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.ds-split__side { position: sticky; top: 14px; min-width: 0; }
.ds-results { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
/* Строка поиска над двумя колонками: поле слева, итог выдачи справа. */
.ds-searchline { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 0; }
/* Подвал списка: врезка про неразмеченный хвост занимает свою строку целиком. */
.ds-listfoot { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2); min-width: 0; }

/* 13.6 Карточка найденного изделия. */
.ds-result {
  display: block; width: 100%; text-align: left; font: inherit; color: inherit;
  padding: 10px 14px; cursor: pointer;
  background: var(--panel);
  border: 1px solid var(--line); border-left: 3px solid transparent;
  border-radius: var(--r-sm);
  transition: background .12s ease, border-color .12s ease;
}
.ds-result:hover { border-color: var(--line-strong); }
.ds-result.is-active {
  border-color: var(--accent); border-left-color: var(--accent);
  box-shadow: var(--shadow-1);
}
.ds-result__line { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
.ds-result__name { font-weight: 500; min-width: 0; overflow-wrap: anywhere; }
.ds-result.is-active .ds-result__name { font-weight: 600; }
.ds-result__code {
  flex: none; margin-left: auto; white-space: nowrap;
  font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--ink-2);
}
.ds-result__code.is-empty { color: var(--faint); }
.ds-result__meta {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-top: 6px; font-size: var(--fs-xs);
}
.ds-result__offers { flex: none; margin-left: auto; color: var(--accent-strong); font-weight: 600; }
.ds-result__offers.is-empty { color: var(--danger); margin-left: auto; }
.ds-tag {
  display: inline-flex; align-items: center; flex: none; white-space: nowrap;
  padding: 1px 7px; border-radius: var(--ds-r-tag);
  background: var(--panel-3); color: var(--ink-2); font-size: var(--fs-xs);
}

/* 13.7 Липкая карточка изделия: паспорт, код АГСК, предложения. */
.ds-idcard {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-md); box-shadow: var(--shadow-1); overflow: hidden;
}
.ds-idcard__sec { padding: 12px var(--sp-4); border-bottom: 1px solid var(--line); }
.ds-idcard__sec:last-child { border-bottom: 0; }
.ds-idcard__title { font-size: var(--fs-md); font-weight: 600; margin-top: 2px; overflow-wrap: anywhere; }
.ds-idcard__sub { font-size: var(--fs-sm); color: var(--muted); margin-top: 2px; }
.ds-idcard__line { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2); min-width: 0; }
.ds-idcard__line > * { flex: none; }
.ds-idcard__line > .ds-panel__spacer { flex: 1 1 auto; min-width: 0; }
.ds-kv { display: grid; grid-template-columns: 1fr 1fr; gap: 6px var(--sp-4); }
/* В широкой панели пара «ключ — значение» на половину экрана нечитаема:
   раскладываем по колонкам постоянной ширины. */
.ds-kv--wide { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); max-width: 1040px; }
.ds-kv__row { display: flex; justify-content: space-between; gap: var(--sp-2); min-width: 0; }
.ds-kv__key { color: var(--muted); }
.ds-kv__val { font-weight: 500; text-align: right; overflow-wrap: anywhere; }
.ds-agsk {
  display: flex; align-items: center; gap: 10px; min-width: 0;
  padding: 7px 10px; background: var(--panel-2);
  border: 1px solid var(--line); border-radius: var(--r-sm);
}
.ds-agsk__code { flex: none; font-family: var(--font-mono); font-weight: 600; }
.ds-agsk__name {
  flex: 1 1 auto; min-width: 0; font-size: var(--fs-sm); color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ds-offers { display: flex; flex-direction: column; min-width: 0; }
.ds-offer {
  display: flex; align-items: flex-start; gap: 10px; min-width: 0;
  padding: 7px 0; border-bottom: 1px solid var(--ds-line-inner);
}
.ds-offer:last-child { border-bottom: 0; }
.ds-offer__sup {
  flex: none; width: 52px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ds-offer__art {
  flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere;
  font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--ink-2);
}
.ds-offer__art > .ds-grid__sub { display: block; font-family: var(--font-sans); }
.ds-offer__price { flex: none; text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }

/* 13.8 Заменено: компактный тулбар выбора источника вместо карточек прайсов. */
.ds-price-toolbar {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: 10px 14px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
  min-width: 0;
}
.ds-price-toolbar > label { display: flex; align-items: center; gap: var(--sp-2); white-space: nowrap; font-size: var(--fs-sm); font-weight: 600; color: var(--ink-2); }
.ds-price-toolbar > label > .select { width: auto; min-width: 180px; }
.ds-price-toolbar__summary { font-size: var(--fs-sm); color: var(--muted); flex: 1 1 auto; min-width: 0; }
.ds-price-toolbar__summary strong { color: var(--ink); }
.ds-price-toolbar > .ds-dropcard { flex: none; min-width: 0; }
@media (max-width: 680px) {
  .ds-price-toolbar { flex-direction: column; align-items: stretch; }
  .ds-price-toolbar > label { flex-direction: column; align-items: stretch; }
  .ds-price-toolbar > label > .select { width: 100%; }
}
.ds-dropcard {
  display: grid; place-items: center; gap: var(--sp-1); min-width: 0;
  padding: 10px 14px; text-align: center; cursor: pointer;
  background: var(--panel); border: 1px dashed var(--line-strong);
  border-radius: var(--r-sm); color: var(--muted); font-size: var(--fs-sm);
  transition: background .12s ease, border-color .12s ease;
}
.ds-dropcard:hover, .ds-dropcard.is-over {
  border-color: var(--accent); background: var(--accent-tint); color: var(--accent-strong);
}
.ds-dropcard__title { font-weight: 600; color: var(--ink); }

/* 13.9 Ручная привязка кода: точное совпадение на accent-tint, ниже похожее. */
.ds-assign {
  background: var(--panel-2); border: 1px solid var(--line-strong);
  border-radius: var(--r-sm); overflow: hidden;
}
.ds-assign__row {
  display: flex; align-items: center; gap: 10px; min-width: 0;
  padding: 7px 12px; border-top: 1px solid var(--ds-line-inner);
}
.ds-assign__row:first-child { border-top: 0; }
.ds-assign__row--best { background: var(--accent-tint); box-shadow: inset 3px 0 0 var(--accent); }
.ds-assign__text { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.ds-assign__note {
  padding: 7px 12px; border-top: 1px solid var(--line);
  font-size: var(--fs-sm); color: var(--muted);
}

/* 13.10 Превью книги в мастере импорта: строка заголовка — на accent-tint
   (была литеральная rgba в разметке экранов). */
.ds-prev__head > td { background: var(--accent-tint); font-weight: 600; }
.ds-prev__skip > td { opacity: .5; }

/* 13.11 Узкие окна: сетки схлопываются, липкая карточка перестаёт быть
   липкой — иначе на 1180px она перекрывает список (LAYOUT_SPEC §5.10). */
@media (max-width: 1180px) {
  .ds-split { grid-template-columns: minmax(0, 1fr); }
  .ds-split__side { position: static; }
}
@media (max-width: 1080px) {
  .ds-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---- 14. Экраны «КП» и «Загрузка проекта» ------------------------------
   Волна 5 перевёрстки (docs/tasks/2026-08-12-redesign-w5-offer-upload.md,
   LAYOUT_SPEC §4, абзацы «КП» и «Загрузка проекта»). Только добавления и
   только токены раздела 1; сетки объявлены переменными, как в разделах 12–13.
   Свод и стадии переиспользуют .ds-panel/.ds-grid волны 6 — второго языка
   таблиц не заводим. */

:root {
  /* Левые колонки двух экранов (LAYOUT_SPEC §4). */
  --ds-kp-side-w:     380px;
  --ds-intake-side-w: 420px;

  /* Свод КП. Колонки «Себестоимость» из макета нет: offer-state отдаёт только
     продажную сторону расчёта, себестоимость известна построчно (таблица
     «Позиции КП»), а не по разделам — выдумывать агрегат нельзя. */
  --ds-sum-cols:  minmax(190px, 1fr) 84px 84px 132px;
  --ds-sum-min-w: 508px;

  /* Кружок стадии распознавания (LAYOUT_SPEC §4 «Загрузка проекта»). */
  --ds-stage-mark: 22px;
}

/* 14.1 Двухколоночные раскладки экранов. Схлопываются по ширине РАБОЧЕЙ
   ОБЛАСТИ, а не окна: при открытой правой панели область теряет 400px, окно
   при этом остаётся 1440px и медиазапрос такого случая не видит (LAYOUT_SPEC
   §5.10 — проверять оба состояния ширины). Поэтому контейнерный запрос. */
.ds-w5-container { container-type: inline-size; }
.ds-cols { display: grid; gap: 14px; align-items: start; min-width: 0; }
.ds-cols--kp     { grid-template-columns: var(--ds-kp-side-w) minmax(0, 1fr); }
.ds-cols--intake { grid-template-columns: var(--ds-intake-side-w) minmax(0, 1fr); }
@container (max-width: 980px) {
  .ds-cols--kp, .ds-cols--intake { grid-template-columns: minmax(0, 1fr); }
}
/* Шапка экрана переносится: иначе кнопки выгрузок уезжают под правую панель,
   а заголовок схлопывается в колонку по одному слову. */
.ds-w5-container .ds-head { flex-wrap: wrap; }
.ds-w5-container .ds-head__titles { flex: 1 1 300px; }
/* flex:none у волны 6 не даёт ряду кнопок сузиться — он просто уезжает за
   край. Здесь ряд сжимаемый и переносится. */
.ds-w5-container .ds-head__actions { flex: 1 1 auto; min-width: 0; flex-wrap: wrap; justify-content: flex-end; }

/* 14.2 Параметры предложения: «подпись — поле — единица» одной строкой,
   подсказка и ошибка — под ней во всю ширину. Классы .field/.kp-form-field
   на элементе остаются: на них висит валидация экрана КП. */
/* Ограничение по ширине — для схлопнутой раскладки: без него подпись и поле
   разъезжаются на всю страницу и строку параметра не прочитать одним взглядом. */
.ds-params { display: flex; flex-direction: column; gap: 10px; min-width: 0; max-width: 560px; }
.ds-param {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 76px 14px;
  align-items: center;
  gap: var(--sp-2);
}
/* Подпись параметра — обычная строка, а не кикер поля формы (раздел 4). */
.ds-param > .label {
  grid-column: 1;
  font-size: var(--fs-base);
  font-weight: 400;
  letter-spacing: 0;
  color: var(--ink);
}
.ds-param > .input {
  grid-column: 2;
  min-height: 28px;
  padding: 3px var(--sp-2);
  text-align: right;
}
.ds-param__unit { grid-column: 3; color: var(--muted); }
.ds-param > .kp-field-hint,
.ds-param > .kp-field-error { grid-column: 1 / -1; }
/* Закрытый список (база оплаты) — полем во всю ширину под подписью. */
.ds-param--stack { grid-template-columns: minmax(0, 1fr); }
.ds-param--stack > .select { grid-column: 1; }

/* 14.3 Свод КП: та же сетчатая таблица, что у справочников. */
.ds-grid--sum { --ds-grid-cols: var(--ds-sum-cols); --ds-grid-min-w: var(--ds-sum-min-w); }
/* Свод только показывает — подсветка строки под курсором обманывала бы. */
.ds-grid--sum .ds-grid__row:hover { background: transparent; }
.ds-grid__row--nested {
  padding-top: 7px; padding-bottom: 7px; padding-left: var(--sp-7);
  font-size: var(--fs-sm); color: var(--ink-2);
}
.ds-grid__row--quiet { padding-top: 7px; padding-bottom: 7px; font-size: var(--fs-sm); color: var(--ink-2); }
.ds-grid__row--sub { font-weight: 600; border-top: 1px solid var(--line); }
/* Раздел с недоподобранным: риска по левому краю, «≥» в суммах ставит экран. */
.ds-grid__row--warn { box-shadow: inset 3px 0 0 var(--warn); }
.ds-grid__row--total {
  padding: 11px var(--sp-4);
  background: var(--accent-tint);
  font-weight: 700;
  border-bottom: 0;
}
.ds-grid--sum .ds-grid__row--total:hover { background: var(--accent-tint); }
.ds-grid__row--total .ds-grid__total { font-size: var(--fs-md); font-weight: 700; }
.ds-grid__name { font-weight: 600; }

/* 14.4 Врезка-примечание под панелью (курсы валют не показываем — всё в ₸). */
.ds-note { font-size: var(--fs-sm); color: var(--faint); text-wrap: pretty; }

/* 14.5 Стадии распознавания: готовая — ok-кружок с ✓, текущая — брендовый
   номер и полоса прогресса, будущая — приглушена. */
.ds-stages { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.ds-stage { display: flex; gap: var(--sp-3); min-width: 0; }
.ds-stage__mark {
  flex: none;
  display: grid; place-items: center;
  width: var(--ds-stage-mark); height: var(--ds-stage-mark);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  background: var(--panel-3);
  color: var(--muted);
  font-size: var(--fs-xs); font-weight: 700; line-height: 1;
}
.ds-stage__body { flex: 1 1 auto; min-width: 0; }
.ds-stage__line { display: flex; align-items: baseline; gap: var(--sp-2); min-width: 0; }
.ds-stage__name { min-width: 0; font-weight: 600; overflow-wrap: anywhere; }
.ds-stage__fact {
  flex: none; margin-left: auto; white-space: nowrap;
  font-size: var(--fs-sm); color: var(--muted); font-variant-numeric: tabular-nums;
}
.ds-stage__note { margin-top: 2px; font-size: var(--fs-sm); color: var(--muted); text-wrap: pretty; }
.ds-stage__bar { margin-top: 6px; }
.ds-stage--done .ds-stage__mark { background: var(--ok-tint); border-color: var(--ok-line); color: var(--ok); }
.ds-stage--current .ds-stage__mark { background: var(--accent); border-color: var(--accent); color: var(--panel); }
.ds-stage--failed .ds-stage__mark { background: var(--danger-tint); border-color: var(--danger-line); color: var(--danger); }
.ds-stage--future { opacity: .6; }

/* 14.6 Загрузка документов: дроп-зона и очередь ролей живут в панели, а не
   поверх страницы — форма остаётся одна (#uploadForm). */
.ds-intake-form { display: grid; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); }
.ds-intake-form .dropzone { padding: 28px var(--sp-5); }
/* Документы в узкой колонке: карточки без внешнего отступа панели. */
.ds-doclist { display: grid; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); }
.ds-doclist .docrow { background: var(--panel); }
.ds-doclist .docrow + .docrow { margin-top: 0; }

/* Подвал панели стадий: состав КП с пояснением на своей строке, состояние и
   платный CTA — справа. */
.ds-intake-foot { border-top: 1px solid var(--line); }
.ds-intake-foot .project-scope-control { flex: 0 1 auto; flex-wrap: wrap; }
.ds-intake-foot .project-scope-control > .select { width: auto; min-width: 168px; }
.ds-intake-foot .project-scope-control > .cell-sub { flex-basis: 100%; margin-top: 0; }
/* Комплектность пакета живёт прямо в панели документов: пустой блок не должен
   оставлять отступ (у нового проекта чек-листа ещё нет). */
.ds-panel > .package-checklist:not(:empty) { padding: 0 var(--sp-4) var(--sp-3); }
.ds-panel > .package-checklist:empty { margin: 0; }

/* 14.7 Узкие окна: обе раскладки схлопываются в одну колонку. */
@media (max-width: 1180px) {
  .ds-cols--kp, .ds-cols--intake { grid-template-columns: minmax(0, 1fr); }
}
/* ---- 13. Рабочая таблица проекта — сетка на табличных элементах (волна 2) --
   LAYOUT_SPEC §2.3 задаёт grid из восьми колонок. Разметка остаётся
   ТАБЛИЧНОЙ (<table>/<tr>/<td>): на ней держатся жесты и защиты боевого
   экрана — клик по строке `tr[data-pilot-line]` открывает источник,
   `data-revision` строки уезжает в команду как expected_revision, свёрнутая
   группа прячет свои штуки через `tr[hidden]`. Переписывать это на <div>
   значило бы менять способ вызова у полутора десятков действий ради
   оформления. Поэтому grid накладывается на table-элементы, а семантику
   таблицы возвращают явные role-атрибуты в разметке.

   Девятая колонка «Действия» — сознательное отступление от макета: в дизайне
   действий строки нет (они уезжают в панель источника), но терять их нельзя
   (инвентарь действий, раздел 14), а панель наполняет волна 3. */
:root {
  --ds-ws-cols:
    minmax(190px, 1.5fr)  /* наименование — единственная сжимаемая колонка */
    68px                  /* обозначение (QF1…) */
    128px                 /* цена + подстрока «закупка · поставщик · артикул» */
    52px 52px             /* количество по чертежу / по спецификации */
    78px                  /* инлайн-итог */
    96px                  /* сумма ₸ */
    160px;                /* действия строки (вне макета, см. выше) */
  /* Фактическая сумма восьми треков после удаления колонки «Код АГСК»:
     190+68+128+52+52+78+96+160 = 824, семь зазоров --sp-2 (7×8 = 56) и
     горизонтальные поля строки --sp-3 (2×12 = 24) → 904px. Прежние 1024px
     остались от девятиколоночной сетки и заставляли таблицу скроллиться
     горизонтально на 120px пустоты. */
  --ds-ws-min-w: 904px;
}

/* Минимальная ширина задаётся РОВНО ДВА раза — на шапке и на теле, обе в
   border-box. На сами grid-строки min-width НЕ ставить (LAYOUT_SPEC §2.3). */
.ds-ws-table { display: block; width: 100%; border-collapse: separate; border-spacing: 0; }
.ds-ws-table > thead, .ds-ws-table > tbody { display: block; }
/* Шапка липнет к верху СВОЕГО скроллпорта (по вертикали страница цельная,
   обёртка таблицы прокручивается только горизонтально — решение владельца
   07.08). Прежнее смещение на высоту полосы якорей снято волной C вместе
   с самой полосой (В4). */
.ds-ws-table > thead {
  position: sticky; top: 0; z-index: 15;
  min-width: var(--ds-ws-min-w);
  background: var(--panel-3);
  border: 1px solid var(--line);
  border-bottom: 1px solid var(--line-strong);
  border-radius: var(--r-sm) var(--r-sm) 0 0;
}
.ds-ws-table > tbody {
  min-width: var(--ds-ws-min-w);
  background: var(--panel);
  border: 1px solid var(--line);
  border-top: 0;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
}
.ds-ws-table > thead > tr,
.ds-ws-table > tbody > tr {
  display: grid;
  grid-template-columns: var(--ds-ws-cols);
  gap: var(--sp-2);
  align-items: center;
}
.ds-ws-table > thead > tr { padding: 7px var(--sp-3); }
.ds-ws-table > thead th {
  display: block; min-width: 0; padding: 0; border: 0;
  position: static; background: transparent;
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; text-align: left; color: var(--ink-2);
}
.ds-ws-table > thead th.right { text-align: right; }
.ds-ws-table > tbody > tr {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--ds-line-inner);
  cursor: pointer;
  transition: background .12s ease;
}
.ds-ws-table > tbody > tr:hover { background: var(--panel-2); }
.ds-ws-table > tbody > tr > td {
  display: block; min-width: 0; padding: 0; border: 0;
  /* top: плейсхолдеры «—» и многострочные ячейки не «пляшут» (Qwen 15.08) */
  vertical-align: top; color: var(--ink);
}
/* Полосы во всю ширину (щит, секция, инлайн-сверка, пустой результат) выходят
   из сетки: их содержимое само отвечает за свои отступы. */
.ds-ws-table > tbody > tr.ds-ws-band {
  display: block; padding: 0; border-bottom: 0; cursor: default; background: transparent;
}
.ds-ws-table > tbody > tr.ds-ws-band:hover { background: transparent; }

/* Ячейки строки позиции. */
.ds-ws-cell--name { display: grid; gap: 1px; min-width: 0; }
.ds-ws-cell--name .ds-ws__name { font-size: var(--fs-base); font-weight: 500; overflow-wrap: anywhere; }
/* Волна A (В7): имя + компактные иконки-статусы в одну строку, без подписей. */
.ds-ws-cell--name__line { display: flex; align-items: center; gap: 6px; min-width: 0; flex-wrap: wrap; }
.ds-ws-status-icons { display: inline-flex; align-items: center; gap: 3px; flex: none; flex-wrap: wrap; }
.ds-ws-status-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; flex: none;
  border: 1px solid transparent; border-radius: var(--r-pill);
}
.ds-ws-status-icon svg { width: 12px; height: 12px; flex: none; }
.ds-ws-status-icon--warn    { background: var(--warn-tint);   color: var(--ds-warn-ink); border-color: var(--warn-line); }
.ds-ws-status-icon--danger  { background: var(--danger-tint); color: var(--danger);    border-color: var(--danger-line); }
.ds-ws-status-icon--review  { background: var(--review-tint); color: var(--review);    border-color: var(--review-line); }
.ds-ws-status-icon--neutral { background: var(--panel-3);     color: var(--muted);     border-color: var(--line); }
.ds-ws-status-icon--info    { background: var(--info-tint);   color: var(--info);      border-color: var(--info-line); }
.ds-ws-meta {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  font-size: var(--fs-xs); color: var(--muted);
}
.ds-ws-tag .status { white-space: normal; height: auto; padding-top: 2px; padding-bottom: 2px; }
/* «Реестр: …» — одна строка с многоточием; «Источник: …» — до двух строк. */
.pilot-etim-class { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pilot-source-provenance { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.pilot-source-badge { flex: none; }
/* Стопка предупреждений АГСК — с зазором, а не внахлёст. */
[data-agsk-review-warning] + [data-agsk-review-warning] { margin-top: 3px; }
.ds-ws-tag { font-family: var(--font-mono); font-size: var(--fs-sm); font-weight: 600; }
.ds-ws-faint { color: var(--faint); }
.ds-ws-manual { display: block; font-size: 10px; font-weight: 600; color: var(--accent-strong); }
.ds-ws-price__main { font-weight: 600; font-variant-numeric: tabular-nums; }
.ds-ws-price__sub {
  font-size: var(--fs-xs); color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ds-ws-price__ai {
  color: var(--accent-strong); vertical-align: middle; margin-left: 4px;
}
.ds-ws-price__ai svg { display: inline-block; vertical-align: -2px; }
.ds-ws-qty { text-align: right; font-variant-numeric: tabular-nums; }
.ds-ws-qty--mismatch { color: var(--ds-warn-ink); font-weight: 600; }
.ds-ws-final { display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-1); }
.ds-ws-final input {
  width: 52px; text-align: right; padding: 3px 6px;
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--panel); color: var(--ink);
  font: inherit; font-variant-numeric: tabular-nums;
}
.ds-ws-final input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
.ds-ws-final input.is-warn { border-color: var(--warn-line); background: var(--warn-tint); }
.ds-ws-final__unit { width: 14px; font-size: var(--fs-xs); color: var(--faint); }
.ds-ws-sum {
  text-align: right; font-family: var(--font-mono);
  font-size: var(--fs-sm); font-weight: 600; font-variant-numeric: tabular-nums;
}

/* Исключённая позиция — одна строка, не скрывается (LAYOUT_SPEC §2.3). */
.ds-ws-excluded {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: 6px var(--sp-3) 6px 22px;
  border-bottom: 1px solid var(--ds-line-inner);
  font-size: var(--fs-sm); color: var(--faint);
}
.ds-ws-excluded__label { text-decoration: line-through; }

/* Предложенная пара «чертёж ↔ спецификация» — одна строка таблицы (волна 2).
   Строка строится штатным путём вместе со всей таблицей; разметку рисует
   модуль ui-proposed-pair-row.js, команды подтвердить/разъединить — модуль
   ui-proposed-pairs.js. Полоса во всю ширину (как секция): оба наименования,
   оба количества, бейдж причины и две кнопки решения в одной строке. */
.pilot-proposed-pair-row {
  background: var(--warn-tint);
  border-left: 3px solid var(--warn-line);
}
.pilot-proposed-pair-row:hover { background: var(--warn-tint); }
.pilot-proposed-pair__body {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: 2px 0 2px var(--sp-4);
}
.pilot-proposed-pair__copy {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  min-width: 0;
}
.pilot-proposed-pair__names {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.pilot-proposed-pair__spec { color: var(--muted); }
.pilot-proposed-pair__badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
}
.pilot-proposed-pair__qty { white-space: nowrap; }

/* Ручное связывание позиций (шаг 1 волны «ручное объединение»): окно
   подтверждения показывает обе стороны — «Чертёж» и «Спецификацию» — с
   наименованием и количеством каждой. Кнопка «Связать выбранные» (ровно при
   двух выбранных строках) живёт в ui-mass-ops.js, окно — в ui-manual-link.js. */
.manual-link-preview {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin: var(--sp-2) 0;
}
.manual-link-line {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--panel);
  min-width: 0;
}
.manual-link-line__name {
  font-weight: 600;
  color: var(--ink);
}
.manual-link-line--drawing { border-left: 3px solid var(--warn-line); }
.manual-link-line--spec { border-left: 3px solid var(--accent); }
.pilot-proposed-pair__actions { display: inline-flex; gap: var(--sp-2); }
