/* Риск-лист по макету «Риск-лист механика» и карточка позиции (пакет 1, задача 9).
   Только раскладка: компоненты — из Operate UI (op-norm, op-tabs, op-kpis--links, op-timeline,
   op-meta, op-split), цвета — токены --op-*. Подключается после zip-app.css. */

/* —— Риск-лист —— */
.risk-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--op-space-3) var(--op-space-4);
}
.risk-toolbar .op-tabs { flex: 1 1 auto; min-width: 0; }
.risk-toolbar__search {
  display: flex;
  align-items: center;
  gap: var(--op-space-2);
  flex: 0 1 20rem;
  min-width: 0;
}
.risk-toolbar__search .op-field { flex: 1 1 auto; min-width: 0; margin: 0; }
.risk-th-note {
  display: block;
  font-weight: var(--op-fw-regular);
  color: var(--op-text-3);
}
.risk-pos__sku { align-self: flex-start; font-size: var(--op-fs-sm); }
.risk-pos__place { color: var(--op-text-3); }
.risk-supply {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  min-width: 0;
}
/* Длинная пометка («поставки не хватит…») переносится, а не растягивает столбец. */
.risk-supply .op-tag {
  height: auto;
  min-height: 20px;
  padding-block: 2px;
  white-space: normal;
  line-height: var(--op-lh-sm);
}
.risk-actions .op-turn { align-self: flex-end; }
/* Правка владельца 3 (задача 9б): кнопки строки и «Пересчитал — верно» — без переноса. */
.risk-actions .op-btn,
.recount-form .op-btn { white-space: nowrap; }
.risk-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--op-space-2) var(--op-space-4);
  font-size: var(--op-fs-sm);
}
.risk-legend .op-norm { white-space: normal; }
.risk-legend .op-norm__text { color: var(--op-text-2); }

@media (max-width: 640px) {
  .risk-toolbar__search { flex: 1 1 100%; }
}

/* —— Карточка позиции —— */
.part-head .op-cluster { margin-top: var(--op-space-2); }
/* С «Ваш ход» действий в шапке четыре: им не хватает места — переносятся под заголовок,
   а не сжимают его (задача 9б). На телефоне — общее правило шапки (operate.css, на всю ширину),
   M069: «not all and (max-width: …)» — без зазора на дробной ширине при масштабе браузера. */
@media not all and (max-width: 640px) {
  .op-page-head__text.part-head { flex-basis: 30rem; }
}
.part-badge {
  height: auto;
  min-height: 24px;
  padding: 2px var(--op-space-2);
  font-size: var(--op-fs-sm);
  white-space: normal;
}
.part-reserve {
  display: flex;
  flex-direction: row; /* op-panel__body — колонка */
  flex-wrap: wrap;
  align-items: center;
  gap: var(--op-space-4) var(--op-space-6);
}
.part-reserve__text { margin: 0; max-width: 46ch; }
/* Поле и «Сохранить» — в строку, «Записано сейчас» — сразу под полем, до кнопки (M112). */
.part-stock-form {
  display: grid;
  grid-template-columns: minmax(0, 16rem) auto;
  justify-content: start;
  align-items: end;
  gap: var(--op-space-2);
}
.part-stock-form .op-field { min-width: 0; }
.part-stock-form .part-stock-now { grid-column: 1; grid-row: 2; margin: 0; }
.recount-form--button,
.part-turn-form { margin: 0; display: flex; }
@media (max-width: 640px) {
  .recount-form--button,
  .part-turn-form { flex: 1 1 auto; }
  .recount-form--button .op-btn,
  .part-turn-form .op-btn { flex: 1 1 auto; }
}

/* —— Срок годности (Т-7, ADR 0005, макет «Srok») ——
   Клетка шкалы «срок истёк» (макрос `_zip_reserve.html`): лежит, но не считается — тёмная заливка,
   красный контур, косая черта; только токены --op-*. Общий набор Operate UI не меняется до пилота. */
.op-norm__cells i.zip-expired {
  background:
    linear-gradient(to top right, transparent calc(50% - 1px), var(--op-critical-fg) calc(50% - 1px),
      var(--op-critical-fg) calc(50% + 1px), transparent calc(50% + 1px)),
    var(--op-border-strong);
  box-shadow: inset 0 0 0 1.5px var(--op-critical-fg);
}
.op-norm__fill.zip-expired {
  background: repeating-linear-gradient(-45deg, var(--op-critical-fg) 0 1.5px, var(--op-border-strong) 1.5px 6px);
  box-shadow: inset 0 0 0 1.5px var(--op-critical-fg);
}
.risk-signals { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.risk-signals .op-status { white-space: normal; }
.risk-expiry-kpi__value { display: block; font-size: var(--op-fs-xl); line-height: var(--op-lh-xl); }
.risk-expiry-kpi__value a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 3px; }
.risk-expiry-kpi__value a[aria-current] { color: var(--op-accent-text); }
.part-lots__foot { display: flex; flex-direction: column; gap: var(--op-space-3); }
.part-lots__foot p { margin: 0; }
.part-lots__sum .op-status { white-space: normal; }
.part-lot-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--op-space-2) var(--op-space-3);
}
.part-lot-form .op-field { flex: 0 1 12rem; min-width: 0; }
.part-steps { margin: 0 0 var(--op-space-4); padding-left: var(--op-space-5); display: grid; gap: var(--op-space-2); }
.import-row-note { display: block; margin-top: var(--op-space-1); color: var(--op-warning-fg); }
.delivered-form__expiry { max-width: 12rem; }

/* —— Справочник позиций: «Где лежит» (до 120 символов) — не узкое поле —— */
.zip-catalog-table--parts .zip-location-input { min-width: 14rem; }
.zip-catalog-table--parts .zip-shelf-life-input { min-width: 5rem; max-width: 7rem; }

/* —— Списание: «Что изменится» (пакет 1, задача 10; макет «Списание») ——
   Сетка op-split — сама форма: поля, «Что изменится», кнопка (порядок DOM). В одну колонку
   (≤ 1024 px, как у op-split) — в этом порядке: блок перед кнопкой (правка владельца 1, задача 10б).
   Шире — блок справа на обе строки, кнопка под полями и вместе с ними — одна панель. Шкалы — op-norm. */
.consume-fields,
.consume-actions { min-width: 0; max-width: var(--op-form-max); }
@media (max-width: 1024px) {
  .consume-actions .op-form-actions { padding-top: 0; border-top: 0; }
}
@media not all and (max-width: 1024px) {  /* без зазора на дробной ширине, M093 */
  .consume-split { grid-template-rows: auto 1fr; row-gap: 0; }
  .consume-change { grid-column: 2; grid-row: 1 / span 2; }
  .consume-fields {
    grid-column: 1;
    grid-row: 1;
    border-bottom: 0;
    border-radius: var(--op-radius-md) var(--op-radius-md) 0 0;
  }
  .consume-actions {
    grid-column: 1;
    grid-row: 2;
    padding: 0 var(--op-panel-p) var(--op-panel-p);
    background: var(--op-surface);
    border: 1px solid var(--op-border);
    border-top: 0;
    border-radius: 0 0 var(--op-radius-md) var(--op-radius-md);
  }
}
.consume-qty-hint { display: flex; flex-direction: column; gap: 2px; }
/* Кнопки «только со скриптом» («Сейчас», «0 — уже пришло из 1С», «Не отмечать»): атрибут hidden
   сильнее display у .op-btn — без скрипта их не видно (задача 11б). */
[data-js-only][hidden] { display: none; }
/* display:flex у .op-error-text (operate.css) перебивал [hidden]: подсказка «Впишите время
   вручную…» у «Сейчас» была видна всегда (повторное ревью волны, M107). Как .op-tag[hidden]. */
.op-error-text[hidden] { display: none; }
/* «Когда списали» и «Сейчас» в одну строку (задача 11б): поле сжимается, кнопка — нет. */
.consume-when { display: flex; align-items: stretch; gap: var(--op-space-2); min-width: 0; }
.consume-when .op-input { flex: 1 1 auto; min-width: 0; }
.consume-when .op-btn { flex: none; }
.consume-change__cmp {
  display: flex;
  flex-direction: column;
  gap: var(--op-space-2);
}
.consume-change__state {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--op-space-1) var(--op-space-2);
  min-width: 0;
}
.consume-change .op-norm { white-space: normal; flex-wrap: wrap; }

/* —— Черновик в «Снабжении»: «Сколько заказать» и «В тот же день» (макет «Черновик задачи») —— */
.draft-blocks {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
  gap: var(--op-space-3);
  align-items: start;
}
/* Без промежутка между колонками: черта над «Заказать» — сплошная через обе. */
.draft-calc { column-gap: 0; }
.draft-calc dd.op-num { text-align: right; padding-left: var(--op-space-4); }
.draft-calc .draft-calc__note { grid-column: 1 / -1; margin-top: -4px; }
.draft-calc .draft-calc__total {
  padding-top: var(--op-space-2);
  border-top: 1px solid var(--op-border);
  color: var(--op-text);
  font-weight: var(--op-fw-semibold);
}

/* —— Снабжение и «Поставки»: «Заказать», «Ход поставки», «Срок» (пакет 1, задача 11) —— */
.supply-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--op-space-3) var(--op-space-8);
  margin: 0;
}
.supply-row__cell { display: flex; flex-direction: column; gap: var(--op-space-1); min-width: 0; }
.supply-row__cell > dt { font-size: var(--op-fs-sm); line-height: var(--op-lh-sm); color: var(--op-text-2); }
.supply-row__cell > dd,
.supply-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--op-space-1);
  margin: 0;
}
.supply-cell.op-num { align-items: flex-end; }
.supply-row__note {
  display: block;
  font-size: var(--op-fs-sm);
  line-height: var(--op-lh-sm);
  color: var(--op-text-2);
  white-space: normal;
}
@media (max-width: 640px) {
  .op-table--stack .supply-cell.op-num { align-items: flex-start; }
}

/* Окно «Поставлено»: со скриптом — op-dialog; без скрипта — раскрывающийся блок под кнопкой. */
.delivered-confirm > .op-dialog__form {
  max-width: 34rem;
  border: 1px solid var(--op-border);
  border-radius: var(--op-radius-sm);
  background: var(--op-surface);
}
.delivered-form [hidden] { display: none; }
.delivered-form__qty {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: var(--op-space-2);
}
.delivered-form__qty .op-input-group { flex: 0 1 11rem; min-width: 0; }
.delivered-form__qty .op-input { min-width: 0; }

/* Мастер загрузки остатков из 1С (Т-5, И1, макет «Import»): шаги, колонки, предпросмотр. */
.import-steps { margin-block: var(--op-space-2) var(--op-space-4); }
.import-split [hidden] { display: none; }
.import-split .op-select { min-width: 15rem; }
.import-hint { margin: var(--op-space-1) 0 0; }
.import-hint--auto { color: var(--op-success-fg); }
.import-skipped { margin: var(--op-space-2) 0 0; padding-left: var(--op-space-5); }
.import-summary strong { font-variant-numeric: tabular-nums; }

/* —— Аналитика, обзор (Т-11, макет «Аналитика руководителя») ——
   Столбцы и шкалы — HTML и CSS, без библиотек и CDN; цвет серии — --op-chart-1, остальные
   строки и разброс — она же с прозрачностью (color-mix), справочный срок — --op-text. */
.analytics-pair {
  display: grid;
  gap: var(--op-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(30rem, 100%), 1fr));
  align-items: start;
}
.analytics-pair > .op-panel { margin: 0; min-width: 0; }
.pareto-lead { margin: 0 0 var(--op-space-2); }
.op-pareto { list-style: none; margin: 0; padding: 0; }
.op-pareto__row {
  display: grid;
  grid-template-columns: minmax(8rem, 13rem) minmax(0, 1fr) 3rem 3.5rem;
  gap: var(--op-space-3);
  align-items: center;
  padding: var(--op-space-1) 0;
}
.op-pareto__name { min-width: 0; overflow-wrap: anywhere; color: inherit; text-decoration: none; }
a.op-pareto__name:hover { color: var(--op-link); }
.op-pareto__track { display: block; min-width: 0; }
.op-pareto__bar {
  display: block;
  height: 14px;
  min-width: 2px;
  border-radius: var(--op-radius-xs);
  background: var(--op-chart-1);
}
.op-pareto__row.is-rest .op-pareto__bar { background: color-mix(in srgb, var(--op-chart-1) 40%, transparent); }
.op-pareto__row.is-rest .op-pareto__name { color: var(--op-text-2); }
.op-pareto__n,
.op-pareto__cum { text-align: right; white-space: nowrap; }
.op-pareto__cum { color: var(--op-text-2); }
.op-pareto__cut {
  display: flex;
  align-items: center;
  gap: var(--op-space-2);
  padding: var(--op-space-2) 0;
  font-size: var(--op-fs-sm);
  font-weight: var(--op-fw-semibold);
}
.op-pareto__cut i { flex: 1; border-top: 1px dashed var(--op-text-2); }
.op-pareto + .op-legend { margin-top: var(--op-space-3); }
@media (max-width: 640px) {
  .op-pareto__row { grid-template-columns: minmax(0, 1fr) 2.5rem 3.5rem; row-gap: var(--op-space-1); }
  .op-pareto__name { grid-column: 1 / -1; }
}

.lead-table__range { width: 40%; }
.lead-range {
  position: relative;
  height: 22px;
  min-width: 8rem;
  background: linear-gradient(90deg, var(--op-chart-grid) 1px, transparent 1px) 0 0 / 25% 100%;
  border-right: 1px solid var(--op-chart-grid);
}
.lead-range__span {
  position: absolute;
  top: 7px;
  height: 8px;
  min-width: 2px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--op-chart-1) 55%, transparent);
}
.lead-range__avg {
  position: absolute;
  top: 5px;
  width: 12px;
  height: 12px;
  margin-left: -6px;
  border-radius: 50%;
  background: var(--op-chart-1);
  border: 2px solid var(--op-surface);
}
.lead-range__avg.is-single { opacity: 0.6; }
.lead-range__plan {
  position: absolute;
  top: 0;
  width: 2px;
  height: 22px;
  margin-left: -1px;
  background: var(--op-text);
}
.lead-up { color: var(--op-warning-fg); font-weight: var(--op-fw-semibold); }
.op-legend i.lead-legend__plan { width: 2px; height: 12px; border-radius: 0; background: var(--op-text); }
.op-legend i.lead-legend__span { width: 22px; height: 8px; border-radius: 4px; background: color-mix(in srgb, var(--op-chart-1) 55%, transparent); }
.op-legend i.lead-legend__avg { border-radius: 50%; }

/* Карточка позиции: «По факту N дн в среднем» под справочным сроком. */
.part-lead-fact { margin-top: var(--op-space-1); font-size: var(--op-fs-sm); line-height: var(--op-lh-sm); color: var(--op-text-2); }
.part-lead-fact.is-up { color: var(--op-warning-fg); }

/* А2 «Хватает ли нормы»: восемь колонок не помещаются на планшете — вывод переезжает под название. */
.op-table.norm-table thead th { white-space: normal; }
.norm-table__inline { display: none; }
@media (max-width: 1100px) {
  .norm-table .norm-table__verdict { display: none; }
  .norm-table__inline { display: block; margin-top: var(--op-space-1); }
}

/* Свой период исправлен (неверная дата, перевёрнут, длиннее года) — пояснение под полями. */
.op-filterbar .period-notice { flex-basis: 100%; margin: 0; color: var(--op-warning-fg); }

/* —— Аналоги позиции (Т-10, Б1, макет «Analogi») ——
   «Аналоги на полке: …» в риск-листе и карточке, подсказка «Списать аналог» в списании,
   страница аналогов в справочнике. Компоненты — op-alert, op-segmented, op-table--stack. */
.zip-analogs { display: inline-flex; align-items: flex-start; gap: var(--op-space-2); min-width: 0; overflow-wrap: anywhere; }
.zip-analogs > .op-icon { flex: none; margin-top: 2px; color: var(--op-text-2); }
.risk-pos__analogs { color: var(--op-text-2); }
.part-analogs {
  margin: 0;
  padding: var(--op-space-2) var(--op-space-3);
  border-radius: var(--op-radius-sm);
  background: var(--op-surface-2);
  font-size: var(--op-fs-sm);
}
.zip-analog-hint { margin-top: var(--op-space-2); }
/* Место подсказки в списании: у позиции без аналогов на полке фрагмент пустой — без лишнего отступа. */
.zip-analog-slot:empty { display: none; }
/* display:grid у .op-alert перебивал [hidden]: пометка «вместо какой позиции» снимается при смене позиции. */
.zip-analog-note[hidden],
.zip-analog-hint-text[hidden] { display: none; }
.zip-analog-dir { display: inline-flex; align-items: center; gap: var(--op-space-2); white-space: nowrap; }
.zip-analog-form { flex-direction: row; flex-wrap: wrap; align-items: flex-end; gap: var(--op-space-3) var(--op-space-4); max-width: none; }
.zip-analog-form__part { flex: 1 1 16rem; }
.zip-analog-form .op-form-actions { padding-top: 0; border-top: 0; }

/* —— Телефон (Т-8, макет «Telefon») ——
   Цели касания не меньше 44 px (WCAG 2.5.5), риск-лист карточками, шапка телефона. Только раскладка:
   компоненты Operate UI и токены --op-*, общий набор не меняется. Границы: 960 px — шапка-«гамбургер»
   (как в operate.css), 640 px — одна колонка карточек. «Заявки» эти правила не затрагивают. */

/* «Перейти к содержимому» (WCAG 2.4.1): на экране только в фокусе, цель — не меньше 44 px. */
.op-skip { display: inline-flex; align-items: center; min-height: 44px; }

/* Область состояния «Найдено N» у поиска: всегда в дереве, плашка внутри появляется и меняется. */
.risk-filter-live { display: flex; flex: none; }
.risk-filter-live .op-tag { margin-left: var(--op-space-2); }
.risk-toolbar__search { gap: 0; }

/* Строка про неверную норму — только на телефоне (на десктопе её роль у подписи плитки «В риске»). */
.risk-norm-note { display: none; }

/* Значок склада у места в карточке — на широком экране строка таблицы без него. */
.risk-pos__place .op-icon { display: none; }

/* Цели касания. operate.css даёт 44 px только указателю coarse, а zip-app.css задаёт полям 40 px:
   на узком окне и в браузере без «грубого» указателя цели мельче. До 960 px и для касания — 44. */
@media (max-width: 960px), (pointer: coarse) {
  .op-input, .op-select select, .combo-trigger, .combo-option, .op-btn, .op-icon-btn, .op-tab { min-height: 44px; }
  .op-icon-btn { min-width: 44px; }
  .op-breadcrumbs a { display: inline-flex; align-items: center; min-height: 44px; }
  /* Меню: пункты, марка, «Компактно»; переключатели (тема в меню, «Взаимно / Только в одну сторону»). */
  .op-nav__item, .op-sidebar .op-brand, .op-sidebar .op-switch { min-height: 44px; }
  .op-segmented span { height: auto; min-height: 44px; }
  /* Строки списков-ссылок: артикул в ячейке таблицы, полоса «отказы по ОС» в аналитике, «Что сделать сейчас». */
  .op-cell > a.op-mono, .home-links a { display: inline-flex; align-items: center; min-height: 44px; }
  .op-cell > a.op-mono { align-self: flex-start; }
  .op-bar-select { display: flex; flex-direction: column; justify-content: center; min-height: 44px; }
  /* Таблица основных средств в аналитике: в строке пять ссылок на одно и то же — каждая не меньше 44×44. */
  .zip-asset-table td > a { display: inline-flex; align-items: center; min-height: 44px; min-width: 44px; }
  /* Итоговая проверка 1.3.0 (Minor-2, -3). Список выбора без обёртки .op-select («Справочники»): WebKit не
     даёт нативному списку высоту из min-height — вид снят, стрелка нарисована токеном, как у .op-select. */
  select.op-input {
    -webkit-appearance: none;
    appearance: none;
    padding-right: 36px;
    background-image:
      linear-gradient(45deg, transparent 50%, var(--op-text-2) 50%),
      linear-gradient(135deg, var(--op-text-2) 50%, transparent 50%);
    background-position: right 19px center, right 14px center;
    background-size: 5px 5px;
    background-repeat: no-repeat;
  }
  /* «Показать таблицей» у графиков аналитики: блок с треугольником раскрытия, высота — отступами. */
  .op-chart-table > summary { min-height: 44px; padding-block: 12px; box-sizing: border-box; }
  /* Названия позиций в таблицах и «Парето» аналитики, номер задачи на «Поставках» и в «Ходе поставок». */
  .op-cell > a.op-cell__primary, a.op-pareto__name { display: flex; align-items: center; min-height: 44px; }
  a.op-id { display: inline-flex; align-items: center; min-height: 44px; min-width: 44px; }
  /* «Срок, дн.» у снабжения: высота поля — токен --op-control-h, 44 px он даёт только касанию. */
  .eta-field .op-input, .eta-field input { min-height: 44px; }
}

/* Шапка телефона: меню слева, название, число «В риске» справа (ссылка на риск-лист). */
@media (max-width: 960px) {
  .op-topbar__title {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--op-font-brand);
    font-size: 15px;
    line-height: 20px;
    font-weight: 600;
  }
  .op-topbar__risk {
    display: grid;
    place-items: center;
    flex: none;
    min-width: 44px;
    min-height: 44px;
    text-decoration: none;
  }
}

/* Риск-лист. Заголовок — без пояснения; сводка — «пилюли» вместо шести плиток (три из них
   повторяют очереди ниже); очереди — «пилюли» по 44 px; строки таблицы — карточки. */
@media (max-width: 960px) {
  .risk-page-sub { display: none; }

  .risk-kpi--dup, .risk-kpi--zero { display: none; }
  .op-kpis--links:not(:has(.risk-kpi:not(.risk-kpi--dup, .risk-kpi--zero))) { display: none; }
  .op-kpis--links {
    gap: var(--op-space-2);
    background: transparent;
    border: 0;
    border-radius: 0;
    overflow: visible;
  }
  .op-kpis--links > .risk-kpi {
    flex: 1 1 auto;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    min-height: 44px;
    padding: 0 10px;
    background: var(--op-surface);
    border: 1px solid var(--op-border-strong);
    border-radius: var(--op-radius-pill);
  }
  .op-kpis--links > .risk-kpi.is-active { border-color: var(--op-accent); }
  .op-kpis--links > .risk-kpi.is-active::after { display: none; }
  .op-kpis--links > .risk-kpi .op-kpi__value {
    font-size: var(--op-fs-lg);
    line-height: var(--op-lh-lg);
    font-weight: var(--op-fw-bold);
  }
  /* Пояснение под числом — для чтения с экрана, не на глаз. */
  .op-kpis--links > .risk-kpi .op-kpi__note {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .risk-expiry-kpi__value { display: flex; align-items: center; font-size: var(--op-fs-md); line-height: var(--op-lh-md); }
  .risk-expiry-kpi__value a { display: inline-flex; align-items: center; min-height: 44px; padding-inline: var(--op-space-1); }

  .risk-toolbar { gap: var(--op-space-2); }
  .risk-toolbar .op-tabs { flex-wrap: wrap; gap: var(--op-space-2); padding: 2px; border-bottom: 0; overflow: visible; }
  .risk-toolbar .op-tab {
    padding: 0 var(--op-space-3);
    background: var(--op-surface);
    border: 1px solid var(--op-border-strong);
    border-radius: var(--op-radius-pill);
  }
  .risk-toolbar .op-tab[aria-current="page"] {
    color: var(--op-text);
    background: var(--op-accent-soft);
    border-color: var(--op-accent-soft-border);
  }
  .risk-toolbar .op-tab[aria-current="page"]::after { display: none; }
}

/* Строка таблицы — карточка (макет «Telefon»): артикул и «Ваш ход» в одной строке, название, тип
   и место, шкала, сигналы, поставка, одна главная кнопка во всю ширину. На телефоне — столбиком,
   на планшете (641–960 px) — в две колонки. Заменяет блок «Risk-list cards» из zip-app.css. */
@media (max-width: 960px) {
  .op-app .op-table-wrap:has(#risk-table) { border: 0; background: transparent; overflow: visible; }
  .op-app #risk-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .op-app #risk-table { display: block; }
  .op-app #risk-table tbody { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--op-space-3); }
  .op-app #risk-table tbody tr {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--op-space-2);
    margin: 0;
    padding: var(--op-space-1) var(--op-space-4) var(--op-space-4);
    background: var(--op-surface);
    border: 1px solid var(--op-border);
    border-radius: var(--op-radius-md);
  }
  .op-app #risk-table tbody tr:not([data-search]) { grid-column: 1 / -1; padding-block: var(--op-space-4); }
  .op-app #risk-table tbody tr:hover { background: var(--op-surface); }
  .op-app #risk-table tbody tr.is-risk { box-shadow: inset 3px 0 0 var(--op-critical-fg); }
  .op-app #risk-table tbody tr > :first-child { box-shadow: none !important; }
  .op-app #risk-table td {
    display: block;
    width: auto;
    min-width: 0;
    padding: 0;
    border: 0;
    text-align: left;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  /* Подпись ячейки («Резерв», «Риск», …) — для чтения с экрана, на карточке её не видно. */
  .op-app #risk-table td[data-label]::before {
    content: attr(data-label);
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  .op-app #risk-table .risk-pos { gap: 0; }
  .op-app #risk-table .risk-pos__sku {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding-right: var(--op-space-3);
    font-size: var(--op-fs-sm);
  }
  .op-app #risk-table td[data-primary] .op-cell__primary {
    font-size: var(--op-fs-lg);
    line-height: var(--op-lh-lg);
    font-weight: var(--op-fw-bold);
    letter-spacing: -0.01em;
  }
  .op-app #risk-table td[data-primary] .op-cell__secondary {
    margin: 0;
    font-size: var(--op-fs-sm);
    line-height: var(--op-lh-sm);
    font-weight: var(--op-fw-medium);
    color: var(--op-text-2);
  }
  .op-app #risk-table .risk-pos__place { display: flex; align-items: flex-start; gap: var(--op-space-1); margin-top: var(--op-space-1); }
  .op-app #risk-table .risk-pos__place .op-icon { display: block; flex: none; width: 16px; height: 16px; margin-top: 1px; }

  .op-app #risk-table .risk-cell--fresh { display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--op-space-2); }
  .op-app #risk-table .risk-cell--fresh .recount-form { flex: 1 1 100%; margin: 0; }
  .op-app #risk-table .risk-signals { flex-direction: row; flex-wrap: wrap; }
  .op-app #risk-table .risk-signals .op-status { height: auto; min-height: 22px; padding-block: 2px; line-height: var(--op-lh-xs); }
  .op-app #risk-table .risk-supply a { display: inline-flex; align-items: center; min-height: 44px; }

  /* Главная кнопка — во всю ширину, прижата к низу карточки (в паре карточек — на одном уровне); у «Ваш ход» она
     цветная (`op-btn--primary` в разметке), «Ваш ход» — вверху справа, в строке артикула. */
  .op-app #risk-table tbody tr[data-search] { align-content: start; }
  .op-app #risk-table tbody tr[data-search]:has(.risk-actions) { grid-template-rows: repeat(5, auto) 1fr; }
  .op-app #risk-table td.op-actions { align-self: end; padding-top: var(--op-space-1); }
  .op-app #risk-table td.op-actions:not(:has(.risk-actions)) { display: none; }
  .op-app #risk-table .risk-actions .op-turn {
    position: absolute;
    top: calc(var(--op-space-1) + 11px);
    right: var(--op-space-4);
    align-self: auto;
  }
  /* «Ваш ход» занимает правый край строки артикула: ссылке остаётся остальное, длинный артикул переносится. */
  .op-app #risk-table tbody tr:has(.risk-actions.is-turn) .risk-pos__sku { max-width: max(40%, calc(100% - 6rem)); }

  /* Строка про неверную норму — вместо подписи скрытой плитки (руководителю и администратору). */
  .risk-norm-note { display: block; margin: 0; font-size: var(--op-fs-sm); line-height: var(--op-lh-sm); color: var(--op-text-2); }
}
@media not all and (max-width: 960px) {
  /* Десктоп, макет «Main»: у «Ваш ход» кнопка в строке — обычная (op-btn--primary ей нужен на телефоне). Токены --op-*. */
  .risk-actions .op-btn--primary { background: var(--op-surface); border-color: var(--op-border-input); color: var(--op-text); }
  .risk-actions .op-btn--primary:hover { background: var(--op-surface-hover); }
}
@media (max-width: 640px) {
  .op-app #risk-table tbody { grid-template-columns: minmax(0, 1fr); }
}

/* Карточка позиции на телефоне: главное действие шапки — отдельной строкой во всю ширину. */
@media (max-width: 640px) {
  .op-page-head__actions > .op-btn--primary,
  .op-page-head__actions > .part-turn-form { flex: 1 1 100%; }
}

/* —— QR-этикетки (Т-9, макет Etiketki) ——
   Слева — отбор и параметры листа, справа — предпросмотр. Лист — бумага: системные цвета светлой
   схемы (Canvas / CanvasText) вместо токенов темы — этикетка всегда чёрная на белом, и на экране
   в тёмной теме, и на бумаге. Размеры этикетки — в миллиметрах листа: --mm — 1 мм на бумаге,
   на экране — 1/210 ширины листа (контейнер .zip-sheet). */
.zip-labels { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--op-space-6); }
.zip-labels [hidden] { display: none; }
.zip-labels__controls { flex: 1 1 22rem; max-width: 30rem; min-width: 0; display: flex; flex-direction: column; gap: var(--op-space-4); }
.zip-labels__preview { flex: 999 1 24rem; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: var(--op-space-3); }
.zip-labels-filter { flex-wrap: wrap; overflow: visible; padding: 0 var(--op-space-2); }
.zip-labels-pick { gap: var(--op-space-2); }
.zip-labels-list { list-style: none; margin: 0; padding: 0; max-height: 22rem; overflow: auto; }
.zip-labels-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--op-space-2);
  min-height: 44px;
  padding: var(--op-space-1) 0;
  border-bottom: 1px solid var(--op-border);
}
.zip-labels-row:last-child { border-bottom: 0; }
.zip-labels-row .op-check { flex: 1 1 auto; min-width: 0; align-items: center; }
.zip-labels-row .op-check__text { min-width: 0; overflow-wrap: anywhere; }
.zip-labels-row .op-btn { flex: none; }
.zip-labels-foot { justify-content: space-between; }
.zip-labels-url { overflow-wrap: anywhere; }
.zip-labels-url__id { font-style: italic; color: var(--op-text-2); }

.zip-sheets { width: 100%; max-width: 37.5rem; display: flex; flex-direction: column; gap: var(--op-space-4); }
.zip-sheet {
  color-scheme: light;
  background: Canvas;
  color: CanvasText;
  container-type: inline-size;
  width: 100%;
  aspect-ratio: 210 / 297;
  padding: calc(1.5 / 210 * 100%) 0; /* 7 × 42 = 294 мм: по 1,5 мм сверху и снизу */
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: repeat(7, minmax(0, 1fr));
  border-radius: var(--op-radius-xs);
  box-shadow: var(--op-shadow-overlay);
}
.zip-label {
  --mm: calc(100cqw / 210);
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  padding: calc(3 * var(--mm));
  display: grid;
  grid-template-columns: minmax(0, 1fr) calc(24 * var(--mm));
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: "sku sku" "text qr";
  gap: calc(1 * var(--mm)) calc(2 * var(--mm));
  outline: 1px dashed color-mix(in srgb, CanvasText 30%, Canvas);
  outline-offset: -1px;
}
.zip-label--blank {
  background: repeating-linear-gradient(135deg, transparent 0 4px, color-mix(in srgb, CanvasText 10%, Canvas) 4px 6px);
}
.zip-label__sku {
  grid-area: sku;
  font-family: var(--op-font-mono);
  font-size: calc(6 * var(--mm));
  line-height: 1.1;
  font-weight: var(--op-fw-bold);
  white-space: nowrap;
  overflow: hidden;
}
.zip-label__sku--long { font-size: calc(4.4 * var(--mm)); }
.zip-label__sku--xlong { font-size: calc(3.4 * var(--mm)); white-space: normal; overflow-wrap: anywhere; }
.zip-label__text { grid-area: text; min-width: 0; display: flex; flex-direction: column; gap: calc(1 * var(--mm)); }
.zip-label__name,
.zip-label__place {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}
.zip-label__name { font-size: calc(3.3 * var(--mm)); line-height: 1.2; font-weight: var(--op-fw-semibold); -webkit-line-clamp: 3; line-clamp: 3; }
.zip-label__place { font-size: calc(2.9 * var(--mm)); line-height: 1.2; -webkit-line-clamp: 2; line-clamp: 2; }
.zip-qr { grid-area: qr; width: 100%; height: 100%; align-self: end; shape-rendering: crispEdges; }

@page zip-labels { size: A4 portrait; margin: 0; }
@media print {
  body:has(.zip-sheets) .op-shell,
  body:has(.zip-sheets) .op-main-wrap,
  body:has(.zip-sheets) .op-main,
  body:has(.zip-sheets) .op-main__inner { display: block; padding: 0; margin: 0; max-width: none; min-height: 0; }
  body:has(.zip-sheets) .op-main__inner > :not(.zip-labels),
  .zip-labels > :not(.zip-labels__preview),
  .zip-labels__preview > :not(.zip-sheets),
  .zip-noprint { display: none !important; }
  .zip-labels, .zip-labels__preview { display: block; }
  .zip-sheets { display: block; width: auto; max-width: none; }
  .zip-sheet {
    page: zip-labels;
    width: 210mm;
    height: 297mm;
    aspect-ratio: auto;
    padding: 1.5mm 0;
    grid-template-columns: repeat(3, 70mm);
    grid-template-rows: repeat(7, 42mm);
    border-radius: 0;
    box-shadow: none;
    break-after: page;
    overflow: hidden;
  }
  .zip-sheet:last-child { break-after: auto; }
  .zip-label { outline: 0; }
  .zip-label--blank { background: none; }
}

/* —— Списание по QR (Т-9, макет QrSpisanie) —— */
.zip-qr-form,
.zip-qr-error { max-width: 32rem; width: 100%; }
.zip-qr-form { display: flex; flex-direction: column; gap: var(--op-space-4); }
.zip-qr-from { display: flex; align-items: center; gap: var(--op-space-2); margin: 0; font-size: var(--op-fs-sm); line-height: var(--op-lh-sm); color: var(--op-text-2); }
.zip-qr-card { padding: var(--op-space-4); display: flex; flex-direction: column; gap: var(--op-space-2); }
.zip-qr-card__row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--op-space-2); }
.zip-qr-card__name { margin: 0; font-size: var(--op-fs-lg); line-height: var(--op-lh-lg); font-weight: var(--op-fw-bold); overflow-wrap: anywhere; }
.zip-qr-card__place { margin: 0; }
.zip-qr-card__other { align-self: flex-start; display: inline-flex; align-items: center; min-height: 44px; font-weight: var(--op-fw-semibold); }
.zip-qr-qty { display: flex; align-items: stretch; max-width: 14rem; }
.zip-qr-qty .op-input { flex: 1 1 auto; min-width: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; }
.zip-qr-qty__unit {
  display: grid;
  place-items: center;
  padding: 0 var(--op-space-3);
  border: 1px solid var(--op-border-input);
  border-left: 0;
  border-radius: 0 var(--op-radius-sm) var(--op-radius-sm) 0;
  background: var(--op-surface-2);
  color: var(--op-text-2);
}
.zip-qr-foot {
  position: sticky;
  bottom: 0;
  z-index: var(--op-z-sticky);
  display: flex;
  flex-direction: column;
  gap: var(--op-space-2);
  padding: var(--op-space-3) 0 calc(var(--op-space-3) + env(safe-area-inset-bottom, 0px));
  background: var(--op-canvas);
  border-top: 1px solid var(--op-border);
}
.zip-qr-foot .op-btn { width: 100%; }
.zip-qr-foot__hint { margin: 0; text-align: center; }
.zip-qr-foot__hint[hidden] { display: none; }

/* —— Сканер QR-этикеток (Т-9б, макет Skaner) ——
   Весь экран — видоискатель камеры: чернильная зона (.op-ink) в обеих темах, как шапка телефона.
   Видео под шапкой и рамкой; шапка полупрозрачная, лист снизу — непрозрачный. */
.zip-scan-page { background: var(--op-sidebar-bg); }
.zip-scan {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  overflow: hidden;
  background: var(--op-canvas);
  color: var(--op-text);
}
.zip-scan__video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.zip-scan__video[hidden] { display: none; }
.zip-scan__top {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: calc(56px + env(safe-area-inset-top, 0px));
  padding: env(safe-area-inset-top, 0px) var(--op-space-2) 0 var(--op-space-1);
  background: color-mix(in srgb, var(--op-sidebar-bg) 72%, transparent);
}
.zip-scan__icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: var(--op-radius-pill);
  background: transparent;
  color: var(--op-text);
  cursor: pointer;
}
.zip-scan__icon[hidden] { display: none; }
.zip-scan__icon[aria-pressed="true"] { background: color-mix(in srgb, var(--op-text) 16%, transparent); }
.zip-scan__icon .op-icon { width: 22px; height: 22px; }
.zip-scan__title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 16px;
  line-height: 22px;
  font-weight: var(--op-fw-bold);
  overflow-wrap: anywhere;
}

/* Рамка по центру свободного места; что прочитано — под ней, рамка от этого не сдвигается. */
.zip-scan__view {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto minmax(0, 1fr);
  justify-items: center;
  padding: var(--op-space-6) var(--op-space-4);
}
.zip-scan__view > * { grid-row: 2; width: 100%; max-width: 30rem; }
.zip-scan__frame { position: relative; width: min(240px, 62vw); max-width: none; aspect-ratio: 1; }
.zip-scan__frame[hidden], .zip-scan__msg[hidden], .zip-scan__starting[hidden] { display: none; }
.zip-scan__frame span { position: absolute; width: 34px; height: 34px; border: 0 solid var(--op-focus); }
.zip-scan__frame span:nth-child(1) { left: 0; top: 0; border-width: 4px 0 0 4px; border-top-left-radius: 10px; }
.zip-scan__frame span:nth-child(2) { right: 0; top: 0; border-width: 4px 4px 0 0; border-top-right-radius: 10px; }
.zip-scan__frame span:nth-child(3) { left: 0; bottom: 0; border-width: 0 0 4px 4px; border-bottom-left-radius: 10px; }
.zip-scan__frame span:nth-child(4) { right: 0; bottom: 0; border-width: 0 4px 4px 0; border-bottom-right-radius: 10px; }
.zip-scan__starting { text-align: center; color: var(--op-text-2); }
.zip-scan__live { grid-row: 3; align-self: start; margin-top: 22px; }
.zip-scan__msg,
.zip-scan__result {
  display: flex;
  flex-direction: column;
  gap: var(--op-space-1);
  padding: 12px 14px;
  border: 1px solid var(--op-border-strong);
  border-radius: 10px;
  background: var(--op-surface);
  overflow-wrap: anywhere;
}
.zip-scan__result[hidden] { display: none; }
.zip-scan__result strong, .zip-scan__msg strong { font-weight: var(--op-fw-bold); }
.zip-scan__result--ok {
  flex-direction: row;
  align-items: center;
  gap: 10px;
  background: var(--op-success-bg);
  border-color: var(--op-success-border);
}
.zip-scan__result--ok > .op-icon { flex: none; width: 20px; height: 20px; color: var(--op-success-fg); }
.zip-scan__result-note { font-size: 13px; line-height: 18px; color: var(--op-success-fg); }
.zip-scan__result--warning { background: var(--op-warning-bg); border-color: var(--op-warning-border); }
.zip-scan__result--warning strong { color: var(--op-warning-fg); }
.zip-scan__result--critical { background: var(--op-critical-bg); border-color: var(--op-critical-border); }
.zip-scan__result--critical strong { color: var(--op-critical-fg); }

.zip-scan__sheet {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: var(--op-space-4) var(--op-space-4) calc(22px + env(safe-area-inset-bottom, 0px));
  background: var(--op-sidebar-bg);
  border-top: 1px solid var(--op-border);
  border-radius: 14px 14px 0 0;
}
.zip-scan__manual { width: 100%; height: 48px; font-size: 16px; }
.zip-scan__hint { font-size: 13px; line-height: 18px; color: var(--op-text-2); }
@media not all and (max-width: 960px) {
  .zip-scan__sheet > * { width: 100%; max-width: 30rem; margin-inline: auto; }
}

/* Кнопка сканера в шапке телефона (макет Telefon): справа от числа «В риске». Видна только при
   защищённом адресе — скрипт снимает hidden; без него места не занимает. */
.zip-scan-btn {
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: var(--op-radius-sm);
  background: var(--op-accent-soft);
  color: var(--op-accent-text);
}
.zip-scan-btn .op-icon { width: 22px; height: 22px; }
.zip-scan-btn[hidden], .zip-scan-entry[hidden] { display: none; }

/* «Ввести артикул вручную». */
.zip-sku-panel { max-width: 40rem; width: 100%; }
.zip-sku-form__row { display: flex; flex-wrap: wrap; gap: var(--op-space-2); }
.zip-sku-form__row .op-input { flex: 1 1 12rem; min-width: 0; }
.zip-sku-result { display: flex; flex-direction: column; gap: var(--op-space-3); overflow-wrap: anywhere; }
.zip-sku-list { display: flex; flex-direction: column; gap: var(--op-space-2); margin: 0; padding: 0; list-style: none; }
.zip-sku-list__item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 44px;
  padding: var(--op-space-2) var(--op-space-3);
  border: 1px solid var(--op-border);
  border-radius: var(--op-radius-sm);
  color: var(--op-text);
  text-decoration: none;
}
.zip-sku-list__item:hover { background: var(--op-surface-hover); }
.zip-sku-list__item .op-mono { color: var(--op-link); }
.zip-sku-list__name { font-weight: var(--op-fw-semibold); }
