/* Оформление модуля «Инвентаризация».
 *
 * Стиль подобран скиллом ui-ux-pro-max под тип продукта «инструмент склада»:
 * минимализм швейцарской школы, промышленный сланец плюс складской зелёный.
 * Украшательств нет намеренно — человек стоит в подсобке с телефоном в одной
 * руке и коробкой в другой, ему нужны крупные цифры и попадание пальцем.
 *
 * Ограничения, заложенные в разметку:
 *   • цель нажатия не меньше 48 px, зазор между целями не меньше 8 px;
 *   • главные кнопки внизу экрана — там, где достаёт большой палец;
 *   • тёмная тема равноправна: в подсобках свет бывает любой;
 *   • безопасные зоны телефона учтены через env(safe-area-inset-*).
 */

@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&family=Poppins:wght@500;600;700&display=swap');

:root {
  --primary: #334155;
  --on-primary: #ffffff;
  --accent: #059669;
  --on-accent: #ffffff;
  --bg: #f8fafc;
  --fg: #0f172a;
  --card: #ffffff;
  --card-fg: #0f172a;
  --muted: #f2f3f4;
  --muted-fg: #475569;
  --border: #e6e8ea;
  --danger: #dc2626;
  --on-danger: #ffffff;
  --warn: #b45309;

  /* Фирменные переменные страницы входа. Эталон единого входа настраивается
     только ими — см. секцию «вход: эталон единой страницы входа» ниже.
     --brand обязан давать с текстом кнопки контраст не ниже 4,5:1: складской
     --accent #059669 даёт 3,77 и на кнопку не годится, затемнённый #047857 —
     5,48. Проверено расчётом, а не на глаз.
     --mark не равен --brand намеренно: знак повторяет значок установленного
     приложения (icon-192.png), а по значку человек ищет приложение. */
  --brand: #047857;
  --brand-soft: #e3f1ea;
  --mark: #334155;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 16px;
  --space-4: 24px;
  --space-5: 32px;
  --radius: 12px;
  --tap: 52px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --primary: #cbd5e1;
    --on-primary: #0f172a;
    --accent: #10b981;
    --on-accent: #05241a;
    --bg: #0b1120;
    --fg: #e2e8f0;
    --card: #16203a;
    --card-fg: #e2e8f0;
    --muted: #1e293b;
    --muted-fg: #94a3b8;
    --border: #263453;
    --danger: #f87171;
    --on-danger: #2b0a0a;
    --warn: #fbbf24;

    /* В тёмной теме текст кнопки тёмный (--on-accent), поэтому фирменный тон
       возвращается к светлому: #10b981 под почти чёрным текстом даёт 7,7:1.
       Плашка знака остаётся сланцевой — значок приложения не перекрашивается
       вместе с темой. */
    --brand: #10b981;
    --brand-soft: color-mix(in srgb, var(--brand) 22%, var(--card));
    --mark: #334155;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: 'Open Sans', system-ui, -apple-system, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  color: var(--fg);
  background: var(--bg);
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           env(safe-area-inset-bottom) env(safe-area-inset-left);
  -webkit-text-size-adjust: 100%;
}

h1, h2, h3 { font-family: 'Poppins', system-ui, sans-serif; margin: 0; }
h1 { font-size: 22px; font-weight: 600; }
h2 { font-size: 18px; font-weight: 600; }

.wrap {
  max-width: 560px;
  margin: 0 auto;
  padding: var(--space-3);
  padding-bottom: calc(var(--space-5) + env(safe-area-inset-bottom));
}

/* ─── шапка с ходом работы ─── */

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--bg);
  padding: var(--space-3) var(--space-3) var(--space-2);
  border-bottom: 1px solid var(--border);
}

.topbar__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-2);
}

.topbar__count { font-family: 'Poppins', sans-serif; font-weight: 600; font-size: 15px; }
.topbar__left { color: var(--muted-fg); font-size: 14px; }

.bar {
  height: 6px;
  background: var(--muted);
  border-radius: 3px;
  margin-top: var(--space-2);
  overflow: hidden;
}
.bar__fill {
  height: 100%;
  background: var(--accent);
  border-radius: 3px;
  transition: width 250ms ease;
}

/* ─── карточка позиции ─── */

.card {
  background: var(--card);
  color: var(--card-fg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-4);
  margin-bottom: var(--space-3);
}

.card--tight { padding: var(--space-3); margin-bottom: var(--space-2); }

/* Карточка-предупреждение. Не красная: это не авария и не обвинение, а
   наблюдение — «учёта нет», а не «украли». Цвет тот же, которым помечается
   расхождение на экране ответа, чтобы человек читал их одинаково. */
.card--warn {
  border-color: var(--warn);
  border-left-width: 4px;
}
.card--warn h2 { color: var(--warn); }
/* Правая подпись в строке списка не переносится: «молчит 96 дн.» или
   артикул «PN-50», разорванные пополам, читаются как ошибка вёрстки, а не
   как значение. Название слева при нехватке места перенесётся само. */
.list__item span + span { white-space: nowrap; }
#stale-list .list__item:last-child { border-bottom: none; padding-bottom: 0; }

.good__title {
  font-family: 'Poppins', sans-serif;
  font-size: 21px;
  font-weight: 600;
  line-height: 1.3;
  margin-bottom: var(--space-2);
}
.good__meta { color: var(--muted-fg); font-size: 14px; }

/* ─── ввод количества ─── */

.counter {
  display: grid;
  grid-template-columns: var(--tap) 1fr var(--tap);
  gap: var(--space-2);
  align-items: center;
  margin: var(--space-4) 0 var(--space-3);
}

.counter__btn {
  height: 68px;
  min-width: 52px;
  font-size: 30px;
  font-weight: 700;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--muted);
  color: var(--fg);
  cursor: pointer;
  transition: background 180ms ease, transform 120ms ease;
}
.counter__btn:active { transform: scale(0.96); background: var(--border); }

/* Табло вместо поля ввода. Курсор сюда не ставится намеренно: со сканером
   в руках экранной клавиатуры нет, а мигающий курсор обещает ввод, которого
   не будет. */
.counter__display {
  display: block;
  height: 68px;
  width: 100%;
  line-height: 64px;
  text-align: center;
  font-family: 'Poppins', sans-serif;
  font-size: 40px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--fg);
  background: var(--card);
  border: 2px solid var(--primary);
  border-radius: var(--radius);
  overflow: hidden;
}
.counter__display--fresh { color: var(--muted-fg); }

/* Приставка и единица на табло: «53 уп + 50 мл».
 *
 * Обе мельче и тише самого числа намеренно. Набираемое число — то, на что
 * человек смотрит; приставка отвечает на другой вопрос — «а сколько я уже
 * набрал», — и спорить с числом за внимание не должна.
 *
 * Единица здесь несёт правило работы, а не подпись: «уп» против «мл» —
 * единственное, что при поднятой панели браузера отличает первый шаг от
 * второго. Прятать её нельзя ни на какой высоте. */
.counter__prefix,
.counter__unit {
  font-size: 0.45em;
  font-weight: 600;
  color: var(--muted-fg);
}
.counter__prefix { margin-right: 0.25em; }
.counter__unit { margin-left: 0.15em; }
/* Пустые части не занимают ничего: у обычной позиции табло выглядит
   ровно так же, как выглядело до двух шагов. */
.counter__prefix:empty,
.counter__unit:empty { display: none; }

/* ВТОРОЙ ШАГ ОБЪЁМНОЙ ПОЗИЦИИ.
 *
 * Вопрос «сколько в початой» виден при любой высоте экрана, а платят за
 * него кнопки, которых на этом шаге нет: «В руках другая позиция» и
 * «Сканировать». Обе про выбор позиции, а позиция здесь уже выбрана и
 * наполовину посчитана.
 *
 * Подсказка про повторный скан уходит по той же причине: сканировать
 * миллилитры нечем. */
#screen-count.rest #scan-hint,
#screen-count.rest .good__find,
#screen-count.rest #scan,
#screen-count.rest #absent { display: none; }

/* ПЕРВЫЙ ШАГ ОБЪЁМНОЙ ПОЗИЦИИ: подсказок две, а места на одну.
 *
 * «Скан добавляет единицу» и «только целые упаковки» — обе про правила
 * работы, и обе серые. Рядом они не помещаются: на 375×667 карточка
 * ужалась и отрезала вторую строку названия, а в ней у объёмной позиции
 * как раз стоит объём — «750 мл».
 *
 * Уступает подсказка про скан: правило про целые действует прямо сейчас
 * и меняет то, что человек наберёт, а про скан он узнаёт один раз на
 * штучных позициях, которых в разы больше. */
#screen-count.tselye #scan-hint { display: none; }
#screen-count.rest .row2 { grid-template-columns: 1fr; }
/* Собственные отступы у этой строки обнулены: она стоит между табло и
   набором, где своего воздуха и так хватает, а на 360×520 её отступы —
   это разница между «блок кнопок на месте» и «уехал за край». Замер:
   с отступами страница 521 при видимой области 520. */
#screen-count.rest #step-hint {
  display: block;
  margin: var(--space-1) 0 0;
}

/* Записать нечего — сказать об этом негде: подписи под табло нет, места
   на экране тоже. Мигаем самим табло. */
.counter__display--nudge {
  animation: nudge 320ms ease;
  border-color: var(--warn);
}
@keyframes nudge {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-6px); }
  75% { transform: translateX(6px); }
}

/* Экранный набор. Четыре ряда по три клавиши: большой палец достаёт весь
   блок, не перехватывая телефон. Клавиша 56 px при минимуме 44 pt по iOS,
   зазор 8 px при минимуме 8 px. */
.keypad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
  margin: var(--space-3) 0;
}

.keypad__key {
  height: 56px;
  font-family: 'Poppins', sans-serif;
  font-size: 26px;
  font-weight: 600;
  color: var(--fg);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background 140ms ease, transform 100ms ease;
}
.keypad__key:active { transform: scale(0.95); background: var(--muted); }
.keypad__key--soft { background: var(--muted); color: var(--muted-fg); }

.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
.row2 .btn + .btn { margin-top: 0; }

.hint--center { text-align: center; margin-top: 0; }

.label {
  display: block;
  font-size: 14px;
  font-weight: 600;
  color: var(--muted-fg);
  margin-bottom: var(--space-2);
}

/* Значение, которое человек не выбирает, а просто видит: точка, если она
   у него одна, или единственный склад. Выглядит как поле, чтобы строка
   не выпадала из ряда подписей, но не притворяется органом управления —
   ни рамки-кнопки, ни стрелки. */
.field--kak-est {
  display: block;
  margin: 0 0 var(--space-3);
  border-color: transparent;
  background: var(--muted);
  color: var(--fg);
}

.field {
  width: 100%;
  min-height: var(--tap);
  padding: 0 var(--space-3);
  font-size: 17px;
  color: var(--fg);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: var(--space-3);
}

/* ─── кнопки ─── */

.btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 56px;
  padding: 0 var(--space-3);
  font-family: 'Poppins', sans-serif;
  font-size: 17px;
  font-weight: 600;
  border: 1px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  transition: background 200ms ease, transform 120ms ease;
}
.btn:active { transform: scale(0.985); }
.btn + .btn { margin-top: var(--space-2); }

.btn--primary { background: var(--accent); color: var(--on-accent); }
.btn--ghost { background: transparent; color: var(--muted-fg); border-color: var(--border); }
.btn--quiet { background: var(--muted); color: var(--fg); }
.btn--danger { background: transparent; color: var(--danger); border-color: var(--border); }

.btn:focus-visible,
.keypad__key:focus-visible,
.counter__btn:focus-visible,
.field:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

/* ─── ответ после ввода ─── */

.verdict { text-align: center; padding: var(--space-4) var(--space-3); }
.verdict__mark {
  width: 64px; height: 64px;
  margin: 0 auto var(--space-3);
  display: grid; place-items: center;
  border-radius: 50%;
}
.verdict--ok .verdict__mark { background: color-mix(in srgb, var(--accent) 16%, transparent); }
.verdict--diff .verdict__mark { background: color-mix(in srgb, var(--warn) 18%, transparent); }
.verdict__title { font-family: 'Poppins', sans-serif; font-size: 20px; font-weight: 600; }
.verdict__body { color: var(--muted-fg); margin-top: var(--space-2); }

.numbers {
  display: flex;
  justify-content: center;
  gap: var(--space-5);
  margin: var(--space-4) 0;
}
.numbers__cell { text-align: center; }
.numbers__value { font-family: 'Poppins', sans-serif; font-size: 32px; font-weight: 700; }
.numbers__caption { font-size: 13px; color: var(--muted-fg); }

/* ─── итог ─── */

.stat {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}
.stat__cell {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-3);
}
.stat__value { font-family: 'Poppins', sans-serif; font-size: 26px; font-weight: 700; }
.stat__caption { font-size: 13px; color: var(--muted-fg); }
.stat__value--short { color: var(--danger); }
.stat__value--over { color: var(--accent); }

table { width: 100%; border-collapse: collapse; font-size: 15px; }
th, td { padding: var(--space-2) var(--space-1); text-align: left; border-bottom: 1px solid var(--border); }
th { font-size: 13px; color: var(--muted-fg); font-weight: 600; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
.scroll-x { overflow-x: auto; }

.list { list-style: none; margin: 0; padding: 0; }
.list__item {
  display: flex; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-3) 0; border-bottom: 1px solid var(--border);
}

.hint { color: var(--muted-fg); font-size: 14px; margin-top: var(--space-2); }
.hidden { display: none !important; }

.sticky-actions {
  position: sticky;
  bottom: 0;
  background: linear-gradient(to top, var(--bg) 72%, transparent);
  padding: var(--space-3) 0 calc(var(--space-2) + env(safe-area-inset-bottom));
}

/* Низкие экраны (iPhone SE и подобные). Без этого нижний ряд клавиш
   уезжает под липкую панель кнопок, и до него нужно доскроллить —
   а человек в подсобке жмёт вслепую, одной рукой. Клавиша 48 px
   остаётся выше минимума iOS в 44 pt. */
.good__find { margin-top: var(--space-3); }

@media (max-height: 720px) {
  /* Отступы карточки и табло схлопываются между собой — уменьшать надо
     оба сразу, иначе больший съедает меньший и правка не даёт ничего. */
  .card--tight { padding: var(--space-2) var(--space-3); margin-bottom: var(--space-1); }
  .counter { margin: var(--space-1) 0 0; }
  .counter__display { height: 52px; line-height: 48px; font-size: 32px; }
  .counter__btn { height: 52px; font-size: 26px; }
  .keypad { margin: var(--space-1) 0; }
  /* 46 px при минимуме iOS в 44 pt. Ниже не опускаем даже ради места:
     подсказку «скан добавляет единицу» убрать было бы дешевле, но она
     несёт правило работы, а не украшение. */
  .keypad__key { height: 45px; font-size: 22px; }
  .hint--center { font-size: 12px; }
  .btn { min-height: 48px; }

  /* iPhone SE, 375x667. Замерено рамкой 28.08.2026: без этих строк нижний
     ряд набора уходит под кнопку «Записать» на 63 px — целый ряд с нулём,
     запятой и стиранием. Человек не может ввести ни ноль, ни дробь, и
     не догадывается, что там что-то есть: под липкой кнопкой не видно.
     Прежние снимки этого не показывали, потому что снимались на вьюпорте
     496 — headless на Windows не умеет окно уже пятисот пикселей. */
  .topbar { padding: var(--space-2) var(--space-3) var(--space-1); }
  .signed { padding-bottom: var(--space-1); margin-bottom: var(--space-1); font-size: 14px; }
  .signed .btn--inline { min-height: 36px; }
  /* Полоса хода тоньше, но не убрана: цифры «позиция 28 из 101» говорят
     то же самое, а полоса показывает это, не читая. */
  .bar { height: 3px; margin-top: var(--space-1); }
  .good__title { font-size: 18px; margin-bottom: var(--space-1); }
  .good__meta { font-size: 13px; }
  .good__find { margin-top: var(--space-2); min-height: 38px; }
  .sticky-actions { padding-top: var(--space-1); }
  .row2 .btn { min-height: 46px; }
}

/* Телефон повернули боком. В манифесте стоит orientation: portrait, но он
   действует только у установленного приложения — в обычном Safari экран
   поворачивается всё равно, и клавиатура целиком уезжает под панель кнопок.
   Поэтому боком раскладываем в две колонки: слева позиция и табло, справа
   набор. Клавиша 46 px — выше минимума iOS в 44 pt. */
@media (orientation: landscape) and (max-height: 520px) {
  #screen-count {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
    align-items: start;
  }
  #screen-count > .card--tight,
  #screen-count > .counter,
  #screen-count > .hint--center,
  #screen-count > .sticky-actions { grid-column: 1; }
  #screen-count > .counter { margin: 0; }
  #screen-count > .sticky-actions { position: static; background: none; padding: 0; }
  #screen-count > .keypad { grid-column: 2; grid-row: 1 / span 4; margin: 0; }
  #screen-count > .keypad .keypad__key { height: 46px; }
  .topbar { padding: var(--space-2) var(--space-3); }
  .wrap { padding-top: var(--space-2); }
}

/* ─── вход ─── */

/* Кто вошёл. Строка нужна не для красоты: под одним телефоном за смену
   работают разные люди, и подпись под пересчётом должна быть видна до
   того, как человек начал считать, а не после. */
/* Кто подписывает пересчёт. Стоит в липкой шапке и видно всегда: телефон
   общий, лежит в подсобке и переходит из рук в руки. Следующий человек
   должен увидеть чужое имя сразу, а не искать его в меню — иначе подпись
   «кто считал» станет враньём, а на ней держится весь смысл модуля. */
.signed {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding-bottom: var(--space-2);
  margin-bottom: var(--space-2);
  border-bottom: 1px solid var(--border);
  font-size: 15px;
  color: var(--muted-fg);
}
.signed__name b { color: var(--fg); font-weight: 700; }

/* Липкая шапка стала выше — якорь прокрутки сдвигаем, иначе она закрывает
   то, к чему только что перешли. */
html { scroll-padding-top: 96px; }

.whobar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-2) 0 var(--space-3);
  font-size: 14px;
  color: var(--muted-fg);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-3);
}

.btn--inline {
  width: auto;
  min-height: 40px;
  padding: 0 var(--space-3);
  font-size: 14px;
}

/* Выбор себя из списка. Строка целиком — цель нажатия, а не имя внутри неё:
   попасть пальцем в текст на ходу тяжело. */
.list__item--tap {
  min-height: var(--tap);
  align-items: center;
  cursor: pointer;
  padding: var(--space-3) var(--space-2);
  border-radius: var(--radius);
}
.list__item--tap:active { background: var(--muted); }
.list__item--tap:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

/* Галочка в списке выбора. Крупнее системной: попасть пальцем в квадрат
   13 px, стоя у полки с коробкой в другой руке, нельзя. Нажатие ловит
   вся строка, галочка — только показывает состояние. */
/* Имя в списке «кто считает». Крупнее обычной строки: имён три-четыре,
   выбирают их стоя, одной рукой, и промах здесь подписывает пересчёт
   чужим именем. */
.list__item--big {
  min-height: 64px;
  font-family: 'Poppins', sans-serif;
  font-size: 19px;
  font-weight: 600;
  border: 1px solid var(--border);
  margin-bottom: var(--space-2);
  background: var(--card);
}
.list__item--big:last-child { border-bottom: 1px solid var(--border); }

.pick__box {
  width: 24px;
  height: 24px;
  margin-right: var(--space-3);
  accent-color: var(--accent);
  pointer-events: none;
  flex: none;
}

/* Набранный PIN точками, а не цифрами: экран телефона в зале видно со
   стороны. Точки крупные — иначе не понять, сколько уже набрал. */
.pin {
  font-family: 'Poppins', sans-serif;
  font-size: 40px;
  font-weight: 700;
  letter-spacing: 10px;
  line-height: 1.2;
  min-height: 48px;
  color: var(--fg);
  margin-top: var(--space-2);
}

/* Пустая клетка на месте запятой: без неё ноль и «стереть» съезжают
   под единицу, и палец бьёт мимо по памяти. */
.keypad__gap { display: block; }

/* ─── вход: эталон единой страницы входа ─── */

/* Стили скопированы из канонического шаблона
   D:\Project_AI\Штаб\reference\design\etalon-vhod-shablon.html
   (он, в свою очередь, дословно повторяет вход Компаса —
   salon-academy/salon_academy/static/styles.css, классы login-*).
   Перерисовывать эталон по описанию запрещено: 26.08.2026 трое
   исполнителей собрали «по чек-листу» три разных экрана.

   Правка ровно одна и она обязательная: жёстко зашитые цвета шаблона
   заменены на переменные модуля, иначе тёмная тема на этом экране
   пропала бы. Эталон требует обе темы. Структура и размеры — как в
   шаблоне.

   ФИРМЕННЫЕ ПЕРЕМЕННЫЕ ПРОДУКТА — единственное, что здесь настраивается.
   --brand      кнопка «Войти» и текст вторичных кнопок. Контраст с белым
                текстом обязан быть не ниже 4,5:1. Складской зелёный
                --accent (#059669) даёт 3,77:1 и на кнопку не годится:
                затемнён до #047857 — 5,48:1. Проверено расчётом, а не
                на глаз.
   --brand-soft светлая фирменная подложка кнопки «Вставить».
   --mark       цвет плашки знака. Здесь он НЕ равен --brand намеренно:
                знак повторяет значок установленного приложения
                (icon-192.png) — сланец с зелёной галочкой. Разойтись им
                нельзя, человек ищет приложение по значку.
   Сами значения стоят выше, в общей палитре: блок тёмной темы в этом файле
   обязан быть ОДИН. Снимок тёмной темы собирается подстановкой переменных
   из первого такого блока (tools/preview.py, dark_tokens), и второй блок
   он бы молча не увидел — на снимке тёмная кнопка входа осталась бы
   светлой, а дефект нашёлся бы у человека, а не у меня. */

.login-card {
  max-width: 430px;
  margin: 0 auto;
  padding: var(--space-3);
}

/* Знак и название рядом в строку — дополнение эталона 26.08.2026:
   «по одному знаку не понять, куда входишь». */
.login-brand { display: flex; align-items: center; gap: .95rem; margin-bottom: 1.1rem; }
.login-mark { display: block; width: 64px; height: 64px; border-radius: 16px; flex: 0 0 auto; }
.login-brand-text { min-width: 0; }
.login-brand-text strong {
  display: block;
  font-family: 'Poppins', system-ui, sans-serif;
  font-size: 1.6rem;
  line-height: 1.1;
  letter-spacing: -.01em;
}
.login-brand-text span {
  display: block;
  margin-top: .3rem;
  color: var(--muted-fg);
  font-size: .92rem;
  line-height: 1.35;
}

.login-card h1 { margin: 0 0 1rem; font-size: 1.45rem; }

/* Подпись поля убрана с экрана решением Сергея 26.08.2026 и оставлена
   скринридерам. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* Поле кода ШИРОКОЕ, кнопка «Вставить» компактная. Не наоборот. */
.code-row { display: flex; gap: .5rem; align-items: stretch; }

/* Код диктуют и вставляют из буфера: он должен читаться знак за знаком,
   поэтому крупно, вразрядку и по центру — как код, а не как обычное поле.
   Заглавные — начертанием, а не переделкой значения: код регистронезависим,
   но набранный вразнобой выглядит как ошибка. */
.code-input {
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
  font: inherit;
  text-transform: uppercase;
  letter-spacing: .3em;
  text-align: center;
  font-size: 1.5rem;
  font-weight: 600;
  padding: .7rem .5rem;
  color: var(--fg);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.code-input::placeholder {
  /* Плейсхолдер — обычный текст «Введите код»: пример кода вида AC7F34
     сбивал с толку и запрещён решением Сергея 26.08.2026. */
  letter-spacing: normal;
  text-transform: none;
  font-weight: 400;
  font-size: 1.05rem;
  color: var(--muted-fg);
}
.code--bad { border-color: var(--danger); }

.paste-btn {
  flex: 0 0 auto;
  padding: .7rem .9rem;
  font-size: .9rem;
  font-family: 'Poppins', sans-serif;
  font-weight: 700;
  border: 0;
  border-radius: 12px;
  background: var(--brand-soft);
  color: var(--brand);
  cursor: pointer;
}

/* Главная кнопка эталона — во всю ширину, фирменным цветом. */
.login-pane > button[type="button"]#enter {
  display: block;
  width: 100%;
  min-height: 56px;
  margin-top: var(--space-3);
  padding: .8rem 1rem;
  font-family: 'Poppins', sans-serif;
  font-size: 17px;
  font-weight: 700;
  color: var(--on-accent);
  background: var(--brand);
  border: 0;
  border-radius: 12px;
  cursor: pointer;
}
#enter:active { transform: scale(0.985); }

.login-hint {
  margin-top: .75rem;
  margin-bottom: 0;
  color: var(--muted-fg);
  font-size: .92rem;
  line-height: 1.45;
}

/* Вторичное действие: обводка, без заливки. background: transparent
   обязателен — иначе класс садится на кнопку с фирменным фоном
   по умолчанию (живой дефект Компаса 24.08.2026). */
.bot-link {
  display: inline-block;
  margin-top: .55rem;
  padding: .7rem .95rem;
  border: 1px solid color-mix(in srgb, var(--brand) 35%, transparent);
  border-radius: 10px;
  background: transparent;
  color: var(--brand);
  font-weight: 600;
  text-decoration: none;
}

/* Место под ошибку держится пустым всегда: без этого появление строки
   сдвигает вниз весь набор, и палец, уже занесённый над клавишей,
   попадает не туда. Две строки — столько занимает самое длинное
   сообщение входа.
   Стоит под полем, а не внизу карточки, как в шаблоне: между полем и
   низом у нас четыре ряда клавиш, и ошибка про код уехала бы на триста
   пикселей от самого кода. Отличие согласовано архитектором 28.08.2026,
   правило — сообщение живёт там, где вызвавшее его действие. */
.error {
  color: var(--danger);
  font-size: 14px;
  min-height: 42px;
  margin: var(--space-1) 0 0;
}

.code-input:focus-visible,
.paste-btn:focus-visible,
#enter:focus-visible,
.bot-link:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }

/* Экранный набор кода. Знаков в алфавите ОКО двадцать два, поэтому шесть
   колонок, а не три: при трёх блок уходит на восемь рядов и не помещается
   на экран целиком. Клавиша выходит 53x48 px при минимуме iOS в 44 pt.
   Похожих знаков в алфавите нет по построению — 0, O, 1, I и L из него
   выброшены, — поэтому мелкий шрифт клавиши здесь не опасен. */
.keypad--code { grid-template-columns: repeat(6, 1fr); margin-top: var(--space-1); }
.keypad--code .keypad__key { height: 48px; font-size: 20px; }

/* Низкие экраны (iPhone SE и подобные). Алфавит на двадцать два знака
   должен помещаться ЦЕЛИКОМ: нижний ряд, уехавший под край экрана,
   человек не найдёт — он не знает, что там есть ещё знаки, и будет
   искать свою букву среди видимых. Поэтому ужимается всё, кроме самих
   клавиш. */
@media (max-height: 720px) {
  .login-brand { margin-bottom: .7rem; gap: .75rem; }
  .login-mark { width: 52px; height: 52px; border-radius: 13px; }
  .login-brand-text strong { font-size: 1.35rem; }
  .login-card h1 { margin-bottom: .6rem; font-size: 1.3rem; }
  .code-input { font-size: 1.35rem; padding: .55rem .5rem; }
  .keypad--code .keypad__key { height: 44px; font-size: 18px; }
  .error { min-height: 21px; font-size: 13px; }
  .login-pane > button[type="button"]#enter { min-height: 50px; margin-top: var(--space-2); }
  .login-hint { margin-top: .5rem; font-size: .88rem; }
}

/* Совсем низкая видимая область: узкий андроид с панелью адреса и
   системными кнопками — около 520 px. Здесь уступает подпись под
   названием: куда человек входит, говорит само название рядом со
   знаком, а ряд клавиш заменить нечем. */
@media (max-height: 620px) {
  .login-brand { margin-bottom: .5rem; }
  .login-mark { width: 44px; height: 44px; border-radius: 11px; }
  .login-brand-text strong { font-size: 1.2rem; }
  .login-brand-text span { display: none; }
  .login-card h1 { margin-bottom: .45rem; font-size: 1.15rem; }
  .code-input { font-size: 1.2rem; padding: .45rem .5rem; }
  .keypad--code .keypad__key { height: 40px; font-size: 17px; }
  .keypad { gap: var(--space-1); }
  .login-pane > button[type="button"]#enter { min-height: 46px; }
  .login-hint { margin-top: .4rem; font-size: .84rem; }
  .bot-link { margin-top: .35rem; padding: .5rem .9rem; }
}


/* ─── экран пересчёта: ряд клавиш не может спрятаться ─── */

/* 28.08.2026. Сергей открыл образец на живом андроиде: нижний ряд набора
   всё равно обрезан, «всё равно ноль прячется». Замер в рамке 375x667 при
   этом проходил с запасом 11 px.
 *
 * Причина: 667 — высота СТРАНИЦЫ, а на телефоне видимая область меньше на
 * панель адреса сверху и системные кнопки снизу. Запас в одиннадцать
 * пикселей их не переживает, и никакой запас не пережил бы: панель адреса
 * то появляется, то прячется прямо во время работы.
 *
 * Поэтому уплотнять дальше бессмысленно — меняем саму раскладку. Экран
 * пересчёта становится колонкой во всю ВИДИМУЮ высоту: набор и кнопки
 * прибиты к низу и не сжимаются, а уступает место карточка товара —
 * единственное, что можно прокрутить без вреда.
 *
 * Так ряд клавиш не может уехать под кнопку ни при какой высоте экрана:
 * не «помещается с запасом», а «не может не поместиться».
 *
 * `dvh` — высота видимой области, которая меняется вместе с панелью
 * браузера. `vh` оставлен запасным для старых телефонов: он считает по
 * максимальной высоте и ошибается в ту же сторону, что и раньше, но
 * это всё же лучше, чем ничего. */
body.schet {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}
body.schet .topbar { flex: none; position: static; }
body.schet .wrap {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  width: 100%;
  padding-bottom: calc(var(--space-2) + env(safe-area-inset-bottom));
}
body.schet #screen-count {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* Уступает только карточка товара: название длинное, но прочесть его
   можно и прокрутив, а до клавиши надо ДОТЯНУТЬСЯ. */
body.schet #screen-count > .card--tight {
  flex: 0 1 auto;
  /* Одна строка названия видна ВСЕГДА. Без этого минимума карточка
     сжималась до двадцати двух пикселей: свободную высоту забирал
     автоотступ над кнопками, а не она. Освобождаешь место — оно уходит
     в пустоту над кнопкой, а название остаётся обрезанным. */
  min-height: 40px;
  overflow-y: auto;
}
body.schet #screen-count > .counter,
body.schet #screen-count > .hint--center,
body.schet #screen-count > .keypad,
body.schet #screen-count > .good__find,
body.schet #screen-count > .sticky-actions { flex: none; }
/* Липкость больше не нужна: кнопки и так стоят внизу колонки, а липкая
   кнопка поверх потока — это ровно тот механизм, который накрывал ряд. */
body.schet .sticky-actions {
  position: static;
  background: none;
  margin-top: auto;
}
/* Экран ответа живёт в том же потоке и прокручивается целиком: там нет
   клавиш, до которых надо дотянуться. */
body.schet #screen-verdict { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

/* Экран входа — та же колонка по видимой высоте. Алфавит ОКО из двадцати
   двух знаков занимает четыре ряда, и спрятать из них хоть один нельзя:
   человек не найдёт свою букву и решит, что кода не набрать вовсе.
   Уступает инструкция «где взять код» — её можно прокрутить. */
body.vhod {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}
body.vhod .wrap {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  width: 100%;
  padding-bottom: calc(var(--space-2) + env(safe-area-inset-bottom));
}
/* Карточка эталона занимает колонку целиком. Уступает место только строка
   знака: название и подпись можно ужать или подрезать, а поле, набор,
   «Войти» и «Открыть бота ОКО» — нельзя, ими работают. */
body.vhod .login-card {
  /* Карточка ровно по содержимому — как в эталоне. Растянуть её на всю
     высоту значило бы нарисовать рамку вокруг пустоты. Сжаться она может:
     на низкой видимой области уступает строка знака, ниже по файлу. */
  flex: 0 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
body.vhod .login-brand { flex: 0 1 auto; min-height: 0; overflow: hidden; }
body.vhod .login-card h1,
body.vhod .login-pane { flex: none; }

/* ─── совсем низкая видимая область ─── */

/* Узкий андроид с панелью адреса и системными кнопками: видимой высоты
   остаётся около 520 px. Здесь уже нечего ужимать отступами — приходится
   выбирать, что важнее. Выбор такой: ряд клавиш остаётся, подсказка про
   повторный скан уходит.
 *
 * Раньше я эту подсказку отстояла — она несёт правило работы, а не
 * украшение. Но правило можно узнать один раз, а до клавиши надо
 * дотягиваться каждый раз, и невидимый ряд читается как «в приложении
 * этого нет». На экранах повыше подсказка на месте. */
/* Подсказка про повторный скан уходит уже здесь: на 600 пикселях видимой
   области её восемнадцать пикселей — это разница между «видно название
   товара» и «не видно». Правило узнают один раз, название читают каждый. */
@media (max-height: 620px) {
  #scan-hint { display: none; }
  /* Подсказка первого шага уступает так же: единица «уп» на самом табло
     и подпись кнопки «Теперь початая» говорят то же самое и видны всегда.
     На ВТОРОМ шаге эта же строка остаётся — правило выше сильнее, и там
     ей уступают кнопки, которых на нём нет. */
  #step-hint { display: none; }
}

@media (max-height: 560px) {
  .counter__display { height: 46px; line-height: 42px; font-size: 28px; }
  .counter__btn { height: 46px; font-size: 24px; }
  .btn { min-height: 46px; }
  .row2 .btn { min-height: 44px; }
  h1 { font-size: 19px; }
  /* Полоса хода уходит: «позиция 3 из 12» рядом говорит то же самое. */
  .bar { display: none; }
  /* Двойной класс намеренно: ниже в этом же блоке стоит .btn с высотой
     44 px, и одноклассовое правило он бы переспорил — кнопка осталась бы
     прежней, а места не хватило бы ровно на неё. */
  .btn.good__find { min-height: 30px; margin-top: var(--space-1); font-size: 14px; }
  /* Артикул уступает место кнопке «В руках другая позиция». Название
     товара человек читает, артикул — почти никогда: он нужен глазам,
     когда ищут позицию, а не когда её уже держат в руках. */
  .good__meta { display: none; }
  .signed { font-size: 13px; }
  .signed .btn--inline { min-height: 32px; }
  /* Само слово «Считает» уходит, имя остаётся. На 360 px строка целиком
     переносилась на две и съедала высоту, которой не хватало названию
     товара. Чьё имя стоит в шапке — видно по-прежнему всегда. */
  .signed__label { display: none; }
  .signed__name b { font-size: 15px; }
  /* 42 px против рекомендованных iOS 44 pt. Отступаем сознательно и
     только здесь: невидимый ряд клавиш читается как «в приложении этого
     нет», а два лишних пикселя — как чуть более тесная клавиша. Из двух
     зол это меньшее, и оно живёт только на самой низкой видимой области. */
  .keypad__key { height: 42px; }
  /* Набор кода задан отдельным, более сильным правилом — без этой строки
     он не услышал бы предыдущую и остался бы прежней высоты. */
  .keypad--code .keypad__key { height: 42px; }
  /* Место под ошибку больше не резервируем: в колонке по высоте появление
     строки не двигает набор — его впитывает карточка сверху. Резерв тут
     отнимал бы у названия товара восемнадцать пикселей просто так. */
  .error { min-height: 0; font-size: 12px; }
  .code-input { font-size: 1.1rem; padding: .4rem .5rem; }
  .label { font-size: 13px; }
  body.schet .wrap, body.vhod .wrap { padding-top: var(--space-2); }
  .card--tight { padding: var(--space-1) var(--space-3); }
  .counter__display { height: 44px; line-height: 40px; }
  .counter__btn { height: 44px; }
  .btn { min-height: 44px; }
  .row2 .btn { min-height: 42px; }
}

/* ─── пересчёт потоком: ноутбук и проводной сканер ─── */

/* Экран для другого рабочего места, а не другая тема того же экрана.
   Обе управляющие 28.08.2026: сканер и ноутбук стоят на столе админа,
   товары подносят к ним по одному.

   НА ЭТОТ ЭКРАН НЕ СМОТРЯТ, НА НЕГО ПОГЛЯДЫВАЮТ. Человек стоит, руки
   заняты, взгляд возвращается на долю секунды — убедиться, что скан
   прошёл. Отсюда размеры: число крупнее всего, состояние «ждёт скан»
   читается через стол, список сделанного занимает высоту, а не ютится.

   Телефонный экран (`body.schet`) при этом не тронут и остаётся: он для
   «одной полки» и для того, кто считает стоя у стеллажа. */

body.potok {
  background: var(--bg);
  /* Экран занимает высоту целиком: список посчитанного растягивается на
     всё свободное место, а не оставляет треть страницы пустой. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* ВЫСОТА ЗАКРЕПЛЯЕТСЯ, А НЕ ПРОСТО НЕ МЕНЬШЕ ЭКРАНА — иначе внутренняя
   прокрутка ленты не работает вовсе: страница растёт по содержимому, и
   «Завершить пересчёт» уезжает вниз, куда надо ещё доскроллить.
   Незаметно, пока строк пять. У Кварты в день выкладки их было 546.
   Только на широком экране: на узком сетка перестраивается в одну
   колонку, и там прокручивается страница целиком, как и должна. */
@media (min-width: 901px) {
  body.potok:not(.potok--stranica) { height: 100vh; overflow: hidden; }
}

/* Экраны, которые прокручиваются страницей целиком, а не внутренней
   лентой: ведомость расхождений и всё, что похоже на длинный список
   вопросов. Закреплять им высоту нельзя — содержимое просто обрежется
   снизу, и человек не доберётся до нижних строк. */
.potok--stranica { height: auto; overflow: visible; }

/* «Отменить пересчёт» на экране начала. Тише строки, к которой относится:
   продолжают пересчёт каждый день, отменяют раз в месяц. */
.otmenit { color: var(--muted-fg); }
.otmenit:hover { color: var(--danger); border-color: var(--danger); }

.potok__top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
  background: var(--card);
}
.potok__where { font-family: 'Poppins', sans-serif; font-size: 17px; color: var(--muted-fg); }
.potok__where b { color: var(--fg); }

/* Ход работы — то, ради чего поднимают глаза. Поэтому он крупный и стоит
   рядом с названием точки, а не мелким серым в углу. Ширина держится
   постоянной: строка меняется на каждый скан, и «прыгающая» шапка под
   рукой человека читается как сбой. */
.potok__progress {
  font-family: 'Poppins', sans-serif;
  font-size: 22px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  min-width: 11em;
}

/* Имя и «Выйти» держатся в одну строку: `.btn` — блочный flex во всю
   ширину, и без inline-flex кнопка уезжает под имя отдельной строкой.
   Стоят они справа, отдельно от завершения пересчёта: два действия,
   обрывающие работу, в одном углу — верный способ нажать не то. */
.potok__who {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
  color: var(--muted-fg);
  font-size: 15px;
}
.potok__who b { color: var(--fg); }
.potok__who .btn {
  display: inline-flex;
  width: auto;
  min-height: 36px;
  padding: 0 var(--space-3);
  font-size: 14px;
}

.potok__grid {
  flex: 1 1 auto;
  /* Без этого сетка не сжимается ниже своего содержимого: flex-элемент по
     умолчанию не меньше своего контента, и внутренняя прокрутка ленты не
     включается вовсе — страница просто растёт, а кнопка завершения уезжает
     за нижний край. */
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  grid-template-areas: "now done" "find done";
  align-items: start;
  gap: var(--space-3);
  max-width: 1280px;
  width: 100%;
  margin: 0 auto;
  padding: var(--space-3) var(--space-4) var(--space-4);
}
.potok__now { grid-area: now; }
.potok__find { grid-area: find; }
.potok__done {
  grid-area: done;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.potok__now,
.potok__find,
.potok__done {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-4);
}

.potok__label {
  font-family: 'Poppins', sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted-fg);
  margin-bottom: var(--space-2);
}

/* СОСТОЯНИЕ, ЧИТАЕМОЕ ЧЕРЕЗ СТОЛ.
 *
 * У проводного сканера нет своего экрана: единственный способ понять,
 * дойдёт ли следующий скан, — посмотреть сюда. Поэтому это полоса, а не
 * значок: значок в углу человек с занятыми руками не заметит.
 *
 * Второе состояние — не украшение. Щелчок мимо окна уводит нажатия
 * клавиатуры мимо страницы, и молчащий экран человек обнаружил бы на
 * пятой пачке, а не на первой. */
.potok__ready {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: calc(-1 * var(--space-4)) calc(-1 * var(--space-4)) var(--space-3);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius) var(--radius) 0 0;
  font-weight: 600;
  font-size: 15px;
  background: color-mix(in srgb, var(--accent) 14%, var(--card));
  color: var(--fg);
}
.potok__dot {
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}
/* Поломка заметнее нормы. Полоса становится толще и жирнее, а не просто
   меняет оттенок: человек, у которого всё хорошо, её не читает вовсе,
   и различать два спокойных состояния по цвету — работа, которой быть
   не должно. Тем более что у части читающих слабое зрение. */
.potok__ready--lost {
  background: color-mix(in srgb, var(--warn) 30%, var(--card));
  padding-top: var(--space-3);
  padding-bottom: var(--space-3);
  font-size: 17px;
  font-weight: 700;
  border-bottom: 3px solid var(--warn);
}
.potok__ready--lost .potok__dot { background: var(--warn); width: 14px; height: 14px; }

/* Сама карточка при этом гаснет: пока скан не дойдёт, всё, что на ней
   написано, — вчерашняя правда. */
.potok__now--lost .potok__title,
.potok__now--lost .potok__row,
.potok__now--lost .potok__from,
.potok__now--lost #undo { opacity: .45; }

/* Название последней позиции — ответ сканеру: пискнул, и человек видит,
   ЧТО именно принято, не переводя взгляд. Две строки места держатся
   всегда: иначе первый же длинный заголовок сдвинул бы поле под рукой. */
.potok__title {
  font-family: 'Poppins', sans-serif;
  font-size: 24px;
  font-weight: 600;
  line-height: 1.25;
  min-height: 2.5em;
  margin-bottom: var(--space-3);
}

.potok__row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.potok__row .counter__btn { width: 64px; height: 84px; flex: none; font-size: 34px; }

/* ИТОГ — САМОЕ КРУПНОЕ НА ЭКРАНЕ. Его ловят боковым зрением за долю
   секунды, чтобы убедиться, что скан прошёл; название позиции при этом
   читают глазами и осознанно.
   Табло, а не поле: курсор в него не ставится, и прибавить его к самому
   себе случайным Enter нельзя. */
.potok__itog {
  display: block;
  min-width: 160px;
  font-family: 'Poppins', sans-serif;
  font-size: 52px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  color: var(--fg);
}

/* Поле прибавки — вдвое мельче итога: оно спрашивает «сколько ещё», а не
   показывает результат. Разный размер здесь и есть ответ на вопрос, куда
   смотреть, а куда печатать. */
.potok__row--vvod { margin-top: var(--space-2); }
/* Подсказка в поле мельче самого набора: она отвечает на вопрос «что сюда
   вводить», а не показывает число. В размер набора она не влезала и
   обрывалась посреди буквы. */
.potok__fact::placeholder {
  font-family: 'Open Sans', system-ui, sans-serif;
  font-size: 15px;
  font-weight: 400;
}
.potok__fact {
  flex: 0 1 180px;
  min-width: 0;
  height: 56px;
  padding: 0 var(--space-3);
  font-family: 'Poppins', sans-serif;
  font-size: 28px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: center;
  color: var(--fg);
  background: var(--bg);
  border: 2px solid var(--primary);
  border-radius: var(--radius);
}
.potok__fact:disabled { color: var(--muted-fg); border-color: var(--border); }
.potok__unit { color: var(--muted-fg); font-size: 18px; min-width: 3em; }

/* Подсказка про Enter стоит там, где раньше был «+»: мышь на этом экране
   не нужна ни разу, и сказать об этом надо один раз в нужном месте.
   На телефоне вместо неё кнопка: клавиши Enter на цифровой клавиатуре
   телефона нет, и подсказка обещала бы то, чего не существует. */
.potok__enter { color: var(--muted-fg); font-size: 14px; }
.potok__pribavit { display: none; }

/* Откуда взялось число. «3 сканами» и «3 набрано» одинаковы только в базе:
   человеку разница нужна, чтобы знать, что случится дальше — прибавит
   следующее действие или заменит. Строка держит место всегда. */
.potok__from {
  margin-top: var(--space-2);
  min-height: 1.4em;
  color: var(--muted-fg);
  font-size: 15px;
}

#undo { width: auto; min-height: 40px; padding: 0 var(--space-3); font-size: 14px; }

.potok__find .field { margin-bottom: var(--space-2); }

/* Список сделанного — доказательство работы, поэтому занимает всю высоту
   колонки и прокручивается сам, а не обрезается пятью строками. */
/* Прокручивается ЛЕНТА целиком — журнал и посчитанное раньше вместе.
   Прокрутка на одном только журнале выталкивала «Завершить пересчёт» за
   край: у Кварты в день выкладки было 546 строк, посчитанных до журнала. */
.potok__lenta {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
.list__fact { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }

/* ЖУРНАЛ ОПЕРАЦИЙ. Три уровня, а не один список одинаковых строк:
   первое — что принялось только что, второе — сколько стало по позиции,
   третье — способ и снятие. Человек смотрит сюда после каждого подхода
   к сканеру, и главное должно ловиться взглядом, а не чтением. */
.zhurnal__item {
  display: block;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border);
}
.zhurnal__glavnoe {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}
.zhurnal__title {
  /* Названия товаров длинные: «Davines базовая крем краска без аммиака».
     Перенос в три строки ломает ритм списка, обрезка — нет. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.zhurnal__delta {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: 18px;
  white-space: nowrap;
}
.zhurnal__vtoroe {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: 2px;
  font-size: 13px;
  color: var(--muted-fg);
}
.zhurnal__stalo { font-variant-numeric: tabular-nums; white-space: nowrap; }
.zhurnal__sposob {
  padding: 1px 6px;
  border-radius: 6px;
  background: var(--muted);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
/* «Убрать» — словом, а не иконкой: значок корзины без подписи читается
   как «удалить товар», а снимается операция.

   БЕЗ РАМКИ, и это не экономия. Рамка у каждой строки давала лестницу
   из шести одинаковых кнопок, и глаз цеплялся за них раньше, чем за
   прибавку, — то есть третий уровень спорил с первым. Снятие операции
   случается раз в смену, прибавка — сотни раз. */
.zhurnal__snyat {
  margin-left: auto;
  min-height: 32px;
  padding: 0 var(--space-1);
  border: none;
  border-radius: 8px;
  background: none;
  color: var(--muted-fg);
  font: inherit;
  font-size: 13px;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--border);
  cursor: pointer;
}
.zhurnal__snyat:hover { color: var(--fg); text-decoration-color: currentColor; }
.zhurnal__snyat:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
/* Пока сервер не ответил, снимать нечего: номера операции ещё нет.
   Строка при этом видна сразу — человек уже потянулся за следующей
   коробкой и ждать ответа сети не будет. */
.zhurnal__item--zhdyot { opacity: .6; }

/* Признак происхождения у КАЖДОЙ строки: через час человек не вспомнит,
   какие позиции набирал руками, а разница между «сканами» и «руками» —
   это разница между «пересчитал» и «переписал». */
.list__ruka {
  margin-left: var(--space-2);
  padding: 1px 6px;
  border-radius: 6px;
  background: var(--muted);
  color: var(--muted-fg);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

/* Посчитанное до журнала. Тише журнала намеренно: это уже сделанная
   работа, а не то, что происходит сейчас. Но и не спрятано — человек
   должен видеть, что она цела. */
.potok__ranee {
  flex: none;
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border);
}
.potok__ranee .list__item { padding: var(--space-2) 0; color: var(--muted-fg); }
.potok__ranee .list__fact { color: var(--fg); }

.potok__finish { margin-top: var(--space-3); flex: none; }

/* ─── выбор одного из: причина списания, склад-получатель ─── */

/* Кнопки равного веса, ни одна не предвыбрана: пустота значит
   «не знаем», и угадывать ответ за человека нельзя. Выбранная кнопка
   красится акцентом целиком — состояние должно читаться через стол,
   как и полоса готовности. Нативные кнопки с aria-pressed, а не div:
   выбор работает и с клавиатуры, и читалкой. */
.prichina,
.kuda {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}
.prichina .btn,
.kuda .btn {
  width: auto;
  flex: 1 1 0;
  min-height: 48px;
  white-space: nowrap;
}
.prichina .btn + .btn,
.kuda .btn + .btn { margin-top: 0; }
.prichina .btn[aria-pressed="true"],
.kuda .btn[aria-pressed="true"] {
  background: var(--accent);
  color: var(--on-accent);
  border-color: var(--accent);
}
/* Складов-получателей у управляющей до десятка: колонки по содержимому,
   а не три равных, иначе длинное «Товары · Точка Красоты» сожмёт соседей
   в нечитаемое. */
.kuda .btn { flex: 1 1 auto; }

/* Комментарий к «иному». Появляется только при этой причине: постоянное
   пустое поле читалось бы как обязательное для всех. */
.prichina__komm { margin: calc(-1 * var(--space-2)) 0 var(--space-3); }
.prichina__komm .field { margin: 0; }

/* ─── экран «не встретились» ─── */

/* Тот же каркас, но в одну колонку: здесь не работают потоком, здесь
   отвечают на один вопрос. Две колонки заставили бы искать глазами, куда
   смотреть первым. */
/* Заголовок здесь не держит двух строк: на экране потока место резервируют
   под меняющееся название товара, а тут текст один и навсегда. */
.potok__grid--one .potok__title { min-height: 0; margin-bottom: var(--space-2); }

.potok__grid--one {
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  grid-template-areas: "now" "done";
  max-width: 860px;
}

/* Два ответа стоят рядом и равного веса: мы не подталкиваем ни к одному.
   «Их нет на полке» оформлен как опасное действие не для строгости —
   он записывает ноль по десяткам позиций, и выглядеть так же, как
   «вернуться», не должен. */
.potok__vybor {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-3);
}
.potok__vybor .btn { width: auto; flex: 1 1 240px; }

/* Отвеченная строка гаснет и остаётся на месте: исчезающая строка
   заставляет человека вспоминать, была ли она вообще, — а он в этот
   момент считает совсем другое. */
.list__item--done { opacity: .55; }
.list__otvety { display: flex; gap: var(--space-2); white-space: nowrap; }

/* ─── строка ведомости расхождений ─── */

/* Два числа рядом и подписанные словами. «2 / 3» человек читает как дробь
   и понимает наоборот; «посчитано 2, числится 3» прочитать неверно
   нельзя. Ответы справа, одинаковой ширины: рука идёт по столбцу, а не
   ищет кнопку в каждой строке заново. */
.vedomost__stroka {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.vedomost__tovar { flex: 1 1 320px; min-width: 0; }
.vedomost__title { font-weight: 600; line-height: 1.35; }
.vedomost__chisla {
  display: flex;
  gap: var(--space-3);
  margin-top: 2px;
  color: var(--muted-fg);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.vedomost__chisla b { color: var(--fg); }
/* Невстреченная позиция не притворяется нулём: она отдельным словом. */
.vedomost__net { color: var(--warn); font-weight: 600; }

.vedomost__otvety {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
}
.vedomost__pole {
  width: 96px;
  margin: 0;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.vedomost__otvety .btn { width: auto; min-height: 40px; padding: 0 var(--space-3);
                         font-size: 14px; }
.list__item .btn { width: auto; min-height: 36px; padding: 0 var(--space-3);
                   font-size: 14px; }

/* Узкий экран: ноутбук бывает и маленьким, а ещё сюда попадает планшет,
   поставленный на стол рядом со сканером. Колонки складываются в одну,
   и первым остаётся то, ради чего пришли, — последняя позиция. */
@media (max-width: 900px) {
  .potok__grid {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto;
    grid-template-areas: "now" "find" "done";
  }
  .potok__who { margin-left: 0; }
  .potok__fact { font-size: 40px; height: 68px; }
  .potok__row .counter__btn { height: 68px; }

  /* КАРТОЧКА ДЕРЖИТСЯ ВВЕРХУ. На телефоне экран вытянут в столбик и
     втрое выше видимой области: журнал длинный, и человек, пролиставший
     его вниз, после скана смотрел бы на чужие строки вместо своего
     итога.

     Со сканером в руке это хуже, чем неудобство: ответ на скан — то
     единственное, ради чего сюда смотрят. Липкая карточка отвечает
     всегда, на какой бы высоте человек ни был. */
  .potok__now {
    position: sticky;
    top: 0;
    z-index: 5;
  }

  /* Кнопка вместо подсказки: Enter на телефоне нажать нечем. */
  .potok__enter { display: none; }
  .potok__pribavit {
    display: block;
    width: auto;
    min-height: 56px;
    padding: 0 var(--space-4);
    flex: none;
  }
}

/* ─── накладка образца ─── */

/* Показывается только на странице-образце и только до первого нажатия.
   Накладкой, а не строкой в потоке: строка сверху сдвинула бы весь экран
   вниз и сломала ровно то, что человек пришёл проверить — помещается ли
   нижний ряд клавиш. После нажатия экран пиксель в пиксель боевой. */
.obrazec {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  padding: var(--space-3);
  background: var(--bg);
}
.obrazec__box { max-width: 420px; }
.obrazec__box h2 { margin-bottom: var(--space-3); }
.obrazec__box p { margin: 0 0 var(--space-3); }

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ─────────────────────────── ЭКРАН «СКЛАД» ───────────────────────────
 *
 * Главный экран модуля. Вид согласован с Сергеем мокапом 28.08.2026,
 * палитра взята у «Смены» по его прямой просьбе: соседние модули сети
 * должны выглядеть одним продуктом, а не тремя разными.
 *
 * Плотность дашбордная (скилл ui-ux-pro-max, density 8): сюда смотрят
 * не любуясь, а ища строку.
 */

body.sklad { background: var(--bg); }

.sklad__top {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  max-width: 1280px;
  margin: 0 auto;
  padding: var(--space-3) var(--space-4) 0;
}
.sklad__gde { font-family: 'Poppins', sans-serif; font-size: 22px; font-weight: 700; }
.sklad__gde span { color: var(--muted-fg); font-weight: 500; }

/* Переключатель складов, а не выпадающий список: их два-три у человека,
   и лишнее нажатие здесь дороже места на экране. */
.sklad__pereklyuch {
  display: flex;
  gap: 2px;
  background: var(--muted);
  border-radius: 9px;
  padding: 2px;
}
.sklad__vkladka {
  padding: 6px 14px;
  border-radius: 7px;
  color: var(--muted-fg);
  text-decoration: none;
  font-size: 14px;
  white-space: nowrap;
}
.sklad__vkladka--tut { background: var(--card); color: var(--fg); font-weight: 600; }
/* Шапка в одну строку: имя и «К началу» прижаты вправо и не переносятся
   — на снимке они уезжали на вторую строку и сдвигали весь экран. */
.sklad__kto {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--muted-fg);
  font-size: 14px;
  white-space: nowrap;
}
.sklad__kto b { color: var(--fg); }

.sklad__grid {
  max-width: 1280px;
  margin: 0 auto;
  padding: var(--space-3) var(--space-4) var(--space-5);
}

/* Склад без номера YCLIENTS. Показать пустой экран и промолчать нельзя:
   человек решит, что склад пуст, а он просто не связан с единой базой. */
.sklad__beda {
  border: 1px solid var(--warn);
  border-left-width: 4px;
  border-radius: var(--radius);
  background: var(--card);
  color: var(--warn);
  padding: var(--space-3);
  margin-bottom: var(--space-3);
}

/* ЧЕТЫРЕ ОПЕРАЦИИ ПЕРВЫМИ. Сюда приходят что-то сделать со складом, а не
   посмотреть на него. Приход выделен: без него остаток ползёт в минус. */
.sklad__operacii {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}
.sklad__op {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px var(--space-3);
  font: inherit;
  font-size: 16px;
  font-weight: 600;
  color: var(--fg);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 150ms ease;
}
.sklad__op:hover { border-color: var(--accent); }
.sklad__op:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.sklad__op svg { flex: none; }
.sklad__op small { display: block; font-weight: 400; font-size: 12px; color: var(--muted-fg); }
/* ЯНТАРЬ, А НЕ СКЛАДСКОЙ ЗЕЛЁНЫЙ. Просьба Сергея: соседние модули сети
   («Смена», «Фокус») должны выглядеть одним продуктом, а не тремя
   разными. Оттенок затемнён против исходного #b8862e — тот с белым
   текстом даёт 3,9:1, а на кнопке нужно не меньше 4,5. */
.sklad__op--glavnaya {
  background: #9a6f22;
  border-color: #9a6f22;
  color: #fff;
}
.sklad__op--glavnaya small { color: #fff; opacity: .85; }
.sklad__op--glavnaya:hover { border-color: #7d5a1b; background: #7d5a1b; }

.sklad__plitki {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}
.sklad__plitka {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px var(--space-3);
  min-width: 0;
}
.sklad__podpis { color: var(--muted-fg); font-size: 13px; margin-bottom: 6px; }
.sklad__chislo {
  font-family: 'Poppins', sans-serif;
  font-size: 24px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sklad__hvost { color: var(--muted-fg); font-size: 12px; margin-top: 4px; }

/* Минусы — тревогой, а не строчкой в отчёте: это не «немного неточно»,
   а учёт, которого нет. */
.sklad__plitka--trevoga { border-color: var(--danger); }
.sklad__plitka--trevoga .sklad__chislo,
.sklad__plitka--trevoga .sklad__podpis { color: var(--danger); }

.sklad__blok {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.sklad__blok-verh {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3);
  border-bottom: 1px solid var(--border);
}
.sklad__blok-ime { font-size: 15px; font-weight: 700; }
.sklad__blok-hvost { margin-left: auto; color: var(--muted-fg); font-size: 13px; }
.sklad__poisk-ryad { padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--border); }
.sklad__poisk-ryad .field { margin: 0; }

.sklad__tablica { width: 100%; border-collapse: collapse; }
.sklad__tablica th {
  text-align: left;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted-fg);
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.sklad__tablica td {
  padding: 9px var(--space-3);
  border-bottom: 1px solid var(--border);
  font-size: 14px;
}
.sklad__tablica tr:last-child td { border-bottom: 0; }
.sklad__tovar { max-width: 1px; width: 55%; }
.sklad__tovar-ime {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sklad__tablica .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.sklad__tablica .num--minus { color: var(--danger); font-weight: 700; }
.sklad__metka {
  display: inline-block;
  margin-left: var(--space-2);
  padding: 1px 7px;
  border-radius: 6px;
  background: var(--muted);
  color: var(--danger);
  font-size: 11px;
  font-weight: 600;
}

/* Пустой склад — не белый лист, а первый шаг. */
.sklad__pusto { padding: var(--space-5) var(--space-3); text-align: center; color: var(--muted-fg); }
.sklad__pusto b { display: block; color: var(--fg); font-size: 16px; margin-bottom: 4px; }

@media (max-width: 900px) {
  .sklad__top, .sklad__grid { padding-left: var(--space-3); padding-right: var(--space-3); }
  .sklad__gde { font-size: 19px; }
  .sklad__kto { margin-left: 0; width: 100%; }
  /* Операции в колонку: в две «Инвентаризация» распирает кнопку и экран
     уезжает вбок — то же, что было на экране потока. */
  .sklad__operacii { grid-template-columns: minmax(0, 1fr); }
  .sklad__plitki { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* Таблица становится карточками, а не едет вбок: четыре столбца в 375
     точек не помещаются никак, а в горизонтальной прокрутке человек
     теряет название товара. */
  .sklad__tablica thead { display: none; }
  .sklad__tablica tr { display: block; padding: var(--space-3); border-bottom: 1px solid var(--border); }
  .sklad__tablica td { display: block; padding: 0; border: 0; }
  .sklad__tovar { max-width: none; width: auto; margin-bottom: 4px; }
  .sklad__tovar-ime { white-space: normal; }
  /* Карточный вид: три числа идут в строку и ПЕРЕНОСЯТСЯ.
     Без снятия nowrap строка «остаток · себестоимость · сумма» шире
     экрана, и весь склад уезжает вбок — замер на 390 показал обрезку
     правого края. */
  .sklad__tablica, .sklad__tablica tbody, .sklad__tablica tr { width: 100%; }
  .sklad__tablica .num {
    display: inline-block;
    text-align: left;
    margin-right: var(--space-3);
    font-size: 13px;
    color: var(--muted-fg);
    white-space: normal;
  }
  /* И шапка тоже: имя с кнопкой не должны распирать страницу. */
  .sklad__kto { white-space: normal; flex-wrap: wrap; }
  .sklad__tablica .num::before { content: attr(data-podpis) " "; font-size: 11px; opacity: .7; }
}
