/* admin.ihelp.az — рабочие места. Режим Operate: интерфейс обслуживает задачу.
   Структура «следующее действие»: экран показывает не данные, а то, что нужно сделать сейчас,
   и кнопка стоит в самой строке задачи. Искать по экрану нечего. */

/* Гарнитура рабочего места лежит рядом, а не на чужом домене.

   Здесь стоял @import с fonts.googleapis.com — и не работал ни разу: CSP рабочих мест
   (web/nginx.conf) разрешает стили только со своего домена, браузер молча блокировал
   запрос, и весь интерфейс всё это время рисовался системным шрифтом. Заметить это
   по виду было нельзя — ровно потому, что fallback был выбран удачно.

   Теперь Inter лежит в public/fonts и подключается <link>-ом из самой страницы, до
   этого файла. Через @import было бы честно, но медленно: он не может начать
   загрузку, пока не разобран style.css, а сами woff2 — пока не разобран inter.css,
   то есть три круга подряд, и первый экран всё равно успевал нарисоваться системным.
   Рабочие места на прежних скинах (bubble) до переезда остаются на системной
   гарнитуре — то есть ровно в том виде, в каком были всегда. */

:root {
  /* Хром — фирменные чернила сайта; полотно работы — светлое, под восемь часов смены. */
  --chrome: #0b241d;
  --chrome-2: #103029;
  --canvas: #f5f4ef;
  --surface: #ffffff;
  --surface-2: #faf9f5;

  --ink: #14181b;
  --ink-2: #4d5754;
  --ink-3: #6b7570;
  --line: #dfded6;
  --line-strong: #c7c6bc;

  /* ─────────── четыре цвета, и у каждого одно значение ───────────
     Смена длится восемь часов, людей за экраном учить некому, поэтому цвет
     обязан отвечать на один вопрос — «мне тут что-то делать?» — раньше, чем
     человек прочитает надпись. Значения не пересекаются и не меняются от экрана
     к экрану: увидел цвет один раз — знаешь его везде.

     ЗЕЛЁНЫЙ  — твой ход и сделанное. Главные кнопки, выбранное, закрытые работы.
     СИНИЙ    — система подсказывает или дело у кого-то другого. Рекомендации,
                пояснения, «у мастера», «у кассы».
     ЖЁЛТЫЙ   — ждём и не можем ускорить: деталь, ответ, срок на исходе.
     КРАСНЫЙ  — нельзя, необратимо или уже плохо: отмена, отказ, просрочка.

     Цвет никогда не единственный признак: рядом всегда слово. */
  --go: #186b46;              /* твой ход, подтверждение, готово */
  --go-ink: #ffffff;
  --go-bg: #e6f3ec;
  --go-line: #a9d4bd;
  --go-hover: #12583a;

  --info: #1d5fa4;            /* подсказка системы, ход не твой */
  --info-ink: #ffffff;
  --info-bg: #e7f0fa;
  --info-line: #b2d0ee;

  --wait: #8a5b06;            /* ждём внешнего: деталь, оплату, время */
  --wait-bg: #fbf2df;
  --wait-line: #e8d3a4;

  --stop: #b32d1d;            /* нельзя, необратимо, просрочено */
  --stop-bg: #fceae7;
  --stop-line: #f0bcb3;

  /* Старые имена остаются как псевдонимы: значение задаётся выше, в одном месте. */
  --accent: var(--go);
  --accent-ink: var(--go-ink);
  --ok: var(--go);
  --ok-bg: var(--go-bg);
  --warn: var(--wait);
  --warn-bg: var(--wait-bg);
  --danger: var(--stop);
  --danger-bg: var(--stop-bg);
  --brass: var(--wait);

  /* Скругления лесенкой: мелкие элементы мягче крупных, иначе карточка выглядит
     подушкой, а кнопка внутри неё — таблеткой. Одно значение на всё не работает.
     Шаг взят строже прежнего (13/9/20 → 10/6/14): у денежного интерфейса скругление
     работает как интонация, и чем оно мягче, тем менее серьёзно читается таблица сумм. */
  --r: 10px;              /* карточки, плитки, поля */
  --r-sm: 6px;            /* кнопки и мелкие элементы */
  --r-lg: 14px;           /* крупные секции */
  --r-pill: 999px;        /* метки и счётчики */

  /* Тень со смещением и мягким размытием, а не цветной ореол вокруг элемента. */
  --shadow-1: 0 1px 2px rgba(20, 24, 27, .04), 0 6px 16px -10px rgba(20, 24, 27, .1);
  --shadow-2: 0 10px 28px -14px rgba(20, 24, 27, .3), 0 2px 6px -2px rgba(20, 24, 27, .08);
  --shadow-go: 0 2px 8px -2px rgba(24, 107, 70, .35);

  /* Шкала отступов под плотный рабочий экран: восемь часов и много строк. */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px;

  --fast: 160ms cubic-bezier(.2, .6, .3, 1);
  --smooth: 220ms cubic-bezier(.2, .7, .3, 1);

  --sans: "Instrument Sans", ui-sans-serif, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: "Martian Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

  /* ─────────── типографическая шкала ───────────
     Тело задано в body — 14 точек полужирным начертанием, а не 15 обычным: у гротеска
     с высоким ростом строчных 500-й вес на 14 читается плотнее и деловитее, чем 400 на 15,
     и на строке заявки это выигрывает вертикаль под лишнюю строку очереди.
     Отклонения от тела вверх — здесь, чтобы заголовок секции нельзя было задать
     «на глаз» в трёх местах по-разному. */
  --fs-display: 1.286rem;   /* 18px — заголовок экрана */
  --fs-heading: 1.143rem;   /* 16px — заголовок секции */
  --fs-small: .929rem;      /* 13px — подпись рядом с числом */

  /* Пол читаемости. Метка, хинт и подпись под числом читаются за стойкой под углом
     и с метра, поэтому их размер задан в точках и не съезжает вслед за телом. */
  --fs-floor: 13px;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font: 500 14px/1.5 var(--sans);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Выделение, каретка и полоса прокрутки — тоже часть интерфейса: браузерные
   умолчания здесь единственное, что не принадлежит ни одной системе. */
::selection { background: #cfe6db; color: var(--ink); }
html { caret-color: var(--go); accent-color: var(--go); }
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--canvas); }
::-webkit-scrollbar-thumb { background: var(--line-strong); border: 3px solid var(--canvas); border-radius: 8px; }
::-webkit-scrollbar-thumb:hover { background: var(--ink-3); }

:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; border-radius: 3px; }

/* Заголовки — 700 и 600: у Instrument Sans средние веса близки, и на 16 точках
   разница между 500 и 600 не видна вовсе. Отрицательный трекинг обязателен:
   гротеск такого роста без него на крупных кеглях выглядит разреженным. */
h2 { font-size: var(--fs-display); font-weight: 700; line-height: 1.2; margin: 0 0 .6rem; letter-spacing: -.02em; }
h3 { font-size: var(--fs-heading); font-weight: 600; line-height: 1.25; margin: 1.6rem 0 .6rem; letter-spacing: -.015em; }
h3:first-child { margin-top: 0; }
p { margin: 0 0 .7rem; }

/* ─────────── шапка ─────────── */
header {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  gap: 14px;
  align-items: center;
  padding: 10px 20px;
  background: var(--chrome);
  color: #eef1ee;
  box-shadow: var(--shadow-1);
}
header b { font-size: .95rem; font-weight: 600; letter-spacing: .01em; }
header .brand { height: 28px; width: auto; display: block; }
header span { margin-left: auto; font-size: .85rem; color: #b6c3bc; }
/* «Выйти» не главное действие ни на одном экране — на тёмной шапке оно живёт
   контуром, а не заливкой: зелёная кнопка здесь и читалась бы плохо, и звала бы зря. */
header button {
  flex: 0 0 auto;
  background: transparent;
  color: #cfdcd5;
  border-color: rgba(207, 220, 213, .35);
  min-height: 34px;
  padding: 6px 14px;
  font-size: .85rem;
}
header button:hover { background: rgba(255, 255, 255, .1); color: #fff; border-color: rgba(255, 255, 255, .5); }

/* ─────────── основа ─────────── */
main {
  max-width: 1180px;
  margin: 22px auto 80px;
  padding: 0 20px;
}
/* Рабочий кабинет — не текст, а плотная таблица: 1180px здесь не читаемая мера,
   а стена, в которую упирается справочник цен на любом мониторе шире ноутбука.
   #app снимает потолок текстовых страниц (двери, гарантия) и берёт всю ширину
   окна — как в обычных панелях администратора, а не в статье. */
#app { max-width: none; padding: 0 32px; }
@media (max-width: 480px) { #app { padding: 0 var(--s4); } }
/* ─────────── дверь: единственный вход в систему ───────────
   Рабочие экраны светлые — на них смотрят восемь часов. Дверь тёмная:
   это единственный экран, где не работают, и граница «снаружи / внутри» должна читаться сразу.
   Тот же приём уже держит табло в зале, так что мир системы остаётся один. */
body.door {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--chrome);
  color: #eef1ee;
  overflow: hidden;
}

.door__mark {
  position: fixed;
  right: -6vw;
  bottom: -14vh;
  height: 128vh;
  width: auto;
  color: #eef1ee;
  opacity: .05;
  pointer-events: none;
}

.door__panel {
  position: relative;
  width: 100%;
  max-width: 380px;
  text-align: center;
  animation: door-in 620ms cubic-bezier(.16, 1, .3, 1) both;
}
@keyframes door-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .door__panel { animation: none; }
}

.door__logo { display: block; margin: 0 auto 22px; height: 34px; width: auto; }

.door__card {
  background: var(--surface);
  color: var(--ink);
  border-radius: 10px;
  padding: 26px 24px 24px;
  text-align: left;
  box-shadow: 0 18px 44px -20px rgba(0, 0, 0, .55), 0 2px 6px rgba(0, 0, 0, .18);
}
.door__card h1 { font-size: 1.3rem; line-height: 1.25; margin: 0 0 6px; letter-spacing: -.015em; }
.door__lede { color: var(--ink-2); font-size: .88rem; margin: 0 0 20px; }
.door__card .field { margin-bottom: 14px; }
.door__card .field__label { font-size: .82rem; }
.door__card input { width: 100%; min-height: 46px; }
.door__card button { width: 100%; min-height: 48px; margin-top: 4px; font-size: .98rem; }

.door__err {
  margin: 0 0 14px;
  padding: 10px 12px;
  background: var(--stop-bg);
  border: 1px solid var(--stop-line);
  border-radius: var(--r);
  color: #7f2415;
  font-size: .88rem;
}

.door__foot { margin: 18px 0 0; font-size: .82rem; color: #a9bdb0; }
/* Ссылка на тёмной двери — светлая, а не браузерная синяя: та на чёрном почти не читалась. */
.door__foot a { color: #e7efe9; text-decoration: underline; text-underline-offset: 3px; }
.door__foot a:hover { color: #fff; }

/* Имя-ссылка: строка таблицы ведёт на свою страницу. Это кнопка, а не ссылка,
   потому что переход внутренний, но выглядеть должна как то, на что жмут. */
.linkish {
  background: none; border: 0; padding: 0; min-height: 0;
  font: inherit; font-weight: 500; color: var(--ink);
  text-decoration: underline; text-decoration-color: var(--line-strong);
  text-underline-offset: 3px; cursor: pointer;
}
.linkish:hover { background: none; color: var(--info); text-decoration-color: currentColor; }

/* Остаток гарантии полосой: цифру читают, а полоса отвечает «много ещё или на исходе»
   без чтения. Используется и на клиентской странице, и за стойкой. */
.wbar { height: 4px; margin-top: 8px; max-width: 320px; border-radius: 2px;
  background: var(--line); overflow: hidden; }
.wbar i { display: block; height: 100%; background: var(--ok); border-radius: 2px; }

/* Клетка варианта в справочнике: цена и срок гарантии стоят рядом,
   потому что это одно решение — какую деталь ставим и что обещаем клиенту. */
.vcell { display: flex; gap: 4px; align-items: center; }
.vcell input { width: 74px; min-height: 34px; padding: 5px 7px; font-size: .86rem; }
.vcell input[data-wdays], .vcell input[data-nwdays] { width: 62px; color: var(--ink-2); }
.vcell--new { flex-wrap: wrap; width: 160px; }
.vcell--new .field__label { flex: 1 0 100%; }
th .hint { display: block; font-weight: 400; font-size: .72rem; }

/* ─────────── карта сотрудника ───────────
   Печатается на бумаге и носится в кармане, поэтому карточка белая и без лишнего:
   код, имя, роль. Всё остальное на бейдже только мешает сканеру. */
.qrwrap { max-width: 340px; margin: 0; }
.qrcard {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 18px 18px 16px;
  text-align: center;
}
.qrcard__top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.qrcard__logo { height: 20px; width: auto; }
.qrcard__role { font-size: .74rem; color: var(--ink-2); text-transform: lowercase; }
.qrcard__code svg { width: 200px; height: 200px; display: block; margin: 0 auto; }
.qrcard__name { font-size: 1.05rem; font-weight: 600; margin-top: 12px; letter-spacing: -.01em; }
.qrcard__note { font-size: .76rem; color: var(--ink-2); margin: 8px 0 0; }

/* Проверка гарантии: клиент читает ответ с телефона, поэтому строки крупнее рабочих экранов. */
.door__panel--wide { max-width: 460px; }
.door__result { margin-top: 14px; }
.door__result h2 { font-size: 1.15rem; margin: 0 0 2px; letter-spacing: -.01em; }
.door__result .hint { display: block; margin-bottom: 14px; }

.wrow { padding: 12px 0; border-top: 1px solid var(--line); }
.wrow:first-of-type { border-top: 0; padding-top: 4px; }
.wrow__what { font-weight: 500; margin-bottom: 3px; }
.wrow__state { font-size: .9rem; }
.wrow__state .hint { display: inline; margin: 0 0 0 6px; font-size: .84rem; }
.wrow__state--ok { color: var(--ok); }
.wrow__state--off { color: var(--danger); }
.wrow__state--none { color: var(--ink-2); }

@media (max-width: 420px) {
  /* На телефоне дверь раньше гасла до обычной формы — водяной знак снимали
     целиком, и единственный тёмный экран системы становился белой карточкой
     на тёмном фоне без единого своего жеста. Мотив не убираем, а подгоняем
     под портрет: тот же знак, ближе и чуть настойчивее — здесь его видят чаще,
     чем на широком экране кассы. */
  .door__mark { right: -30vw; bottom: -8vh; height: 78vh; opacity: .07; }
  .door__card { padding: 22px 18px 20px; }
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 16px;
  margin-bottom: 14px;
  box-shadow: var(--shadow-1);
}
a.card { display: block; text-decoration: none; color: inherit;
  transition: border-color var(--smooth), transform var(--smooth), box-shadow var(--smooth); }
a.card:hover { border-color: var(--ink-3); transform: translateY(-1px); box-shadow: var(--shadow-2); }

.row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 12px; }
.row:last-child { margin-bottom: 0; }
.spacer { margin-left: auto; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 10px; }

/* Строка справочника: имя слева, действия справа единой группой — правка и клон рядом,
   выключить/удалить отделены зазором, чтобы рука не путала «спрятать» с «стереть». */
.mnode { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px;
  padding: 6px 0; border-bottom: 1px solid var(--line); }
.mnode__label { flex: 1 1 160px; display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.mnode__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-left: auto; }
.mnode__danger { display: flex; gap: 6px; margin-left: 8px; padding-left: 8px; border-left: 1px solid var(--line); }

/* Подпись задана в точках, а не долей от тела: тело ужалось до 14, и всё, что от него
   считается, уехало под 12. Двенадцать точек за стойкой читают наклонившись — то есть
   не читают. Пол в 13 стоит здесь, а не в каждом правиле по отдельности. */
.hint { color: var(--ink-2); font-size: var(--fs-floor); }

/* Про этого человека что-то записано. Именно точка, а не текст: в таблице из трёхсот
   строк заметка каждого — это простыня, а знак «загляни в карточку» занимает 6 точек.
   Смысл продублирован в title и aria-label: одним цветом состояний мы не показываем. */
.dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--wait); vertical-align: middle; margin-inline-start: 2px;
}
.err { color: var(--stop); font-size: .9rem; }

/* ─────────── три голоса системы ───────────
   Пояснение (синее) — система рассказывает, как это работает и что предлагает.
   Ожидание (жёлтое) — не от нас зависит, но знать надо.
   Запрет (красное) — так нельзя или уже случилось плохое.
   Все три — плашки одной формы: человек различает их цветом, а читает словами. */
.note {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 11px 14px; margin: 0 0 12px;
  border: 1px solid var(--info-line);
  background: var(--info-bg);
  border-radius: var(--r);
  font-size: .86rem; line-height: 1.5; color: #17416f;
}
.note .ic { flex: 0 0 auto; width: 18px; height: 18px; margin-top: 1px; color: var(--info); }
.note b { color: #12325a; }
.note--wait { border-color: var(--wait-line); background: var(--wait-bg); color: #6b4705; }
.note--wait .ic { color: var(--wait); }
.note--wait b { color: #57390a; }
.note--stop { border-color: var(--stop-line); background: var(--stop-bg); color: #8c2216; }
.note--stop .ic { color: var(--stop); }
.note--stop b { color: #6f1b12; }
.note--go { border-color: var(--go-line); background: var(--go-bg); color: #12583a; }
.note--go .ic { color: var(--go); }
.note--go b { color: #0f4a31; }
/* Плашка «ваш ход» кликабельна — она уводит к списку деталей, и это должно быть видно
   пальцу, а не только курсору: подчёркивания на планшете никто не увидит. */
.note--go[data-goto-parts] { cursor: pointer; }
.note--go[data-goto-parts]:hover { border-color: var(--go); }
.note--go[data-goto-parts]:active { transform: translateY(1px); }
.note button { margin-left: 2px; }
code { font-family: var(--mono); font-size: .78em; letter-spacing: -.03em; word-break: break-all; color: var(--ink-2); }

/* ─────────── элементы управления ─────────── */
input, select, textarea {
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  padding: 9px 12px;
  min-height: 40px;
  transition: border-color var(--fast), box-shadow var(--fast);
}
input::placeholder, textarea::placeholder { color: var(--ink-3); }
input:hover, select:hover, textarea:hover { border-color: var(--ink-3); }
/* Фокус — синий: это система показывает, где вы находитесь, а не действие. */
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--info);
  box-shadow: 0 0 0 3px rgba(29, 95, 164, .16);
}
input:disabled, select:disabled, button:disabled { opacity: .5; cursor: not-allowed; }
input[type=file] { padding: 6px; border-style: dashed; }
select { appearance: none; padding-right: 30px;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-2) 50%), linear-gradient(135deg, var(--ink-2) 50%, transparent 50%);
  background-position: right 14px center, right 9px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

/* Кнопка отвечает цветом на вопрос «что будет, если нажать».
   Зелёная двигает дело вперёд, серая — сопутствующее, красная останавливает
   или уничтожает. Красной заливки нет ни одной: необратимое не должно быть
   самым ярким пятном на экране, иначе на него жмут не глядя. */
button {
  font: 500 inherit;
  font-size: .92rem;
  min-height: 40px;
  padding: 9px 16px;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: var(--go);
  color: var(--go-ink);
  cursor: pointer;
  box-shadow: var(--shadow-go);
  transition: background var(--smooth), border-color var(--smooth), color var(--smooth),
              transform var(--fast), box-shadow var(--smooth);
}
button.ghost, button.quiet, button.danger, button.info { box-shadow: none; }
button:hover { background: var(--go-hover); }
button:active { transform: translateY(1px); }
button.ghost { background: var(--surface); color: var(--ink); border-color: var(--line-strong); }
button.ghost:hover { background: var(--surface-2); border-color: var(--ink-3); }
button.ghost:disabled:hover { background: var(--surface); border-color: var(--line-strong); }
button.quiet { background: transparent; color: var(--ink-2); border-color: transparent; padding-inline: 8px; }
button.quiet:hover { background: var(--surface-2); color: var(--ink); }
/* Телефон клиента — ссылка «позвонить»: со стойки набирают прямо отсюда,
   поэтому она выглядит нажимаемой, но браузерным синим не светит. */
a.quiet {
  color: var(--info); text-decoration: underline; text-decoration-color: var(--info-line);
  text-underline-offset: 3px; font-weight: 500;
}
a.quiet:hover { text-decoration-color: currentColor; }
a.quiet { display: inline-block; padding: 11px 4px; margin: -11px -4px; }
/* Останавливающее действие: видно, но не зовёт. Цвет проступает под курсором,
   когда человек уже целится, а не пока он просматривает экран. */
button.danger { background: var(--surface); color: var(--stop); border-color: var(--stop-line); }
button.danger:hover { background: var(--stop-bg); border-color: var(--stop); }
button.quiet.danger { background: transparent; border-color: transparent; }
button.quiet.danger:hover { background: var(--stop-bg); color: var(--stop); }
/* Действие-подсказка: система предлагает, решает человек. */
button.info { background: var(--surface); color: var(--info); border-color: var(--info-line); }
button.info:hover { background: var(--info-bg); border-color: var(--info); }

label.chk {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  padding: 8px 12px;
  min-height: 40px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  cursor: pointer;
  font-size: .9rem;
  transition: border-color var(--fast), background var(--fast);
}
label.chk:hover { border-color: var(--ink-3); }
label.chk:has(input:checked) { border-color: var(--accent); background: #fdf3f1; }
label.chk input { min-height: 0; accent-color: var(--accent); width: 17px; height: 17px; }

/* ─────────── строка задачи: сердце экрана ─────────── */
.tasks { display: grid; gap: 8px; }

.task {
  display: grid;
  grid-template-columns: 3.4rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-1);
  transition: border-color var(--fast), box-shadow var(--fast);
}
.task:hover { border-color: var(--line-strong); box-shadow: var(--shadow-2); }
.task.is-open { border-color: var(--ink-3); }

/* Состояние несёт блок с номером — он и так есть в строке.
   Декоративная полоса сбоку тут ничего не сообщает, только шумит. */
.task__no {
  align-self: stretch;
  display: grid;
  place-content: center;
  padding: 6px 4px;
  border-radius: 4px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--ink);
  text-align: center;
}
.task__no small { display: block; font-size: .56rem; letter-spacing: .06em; color: var(--ink-3); font-weight: 400; }

/* Код заявки с ярлыка («32K-C5S») в колонке номера — одной строкой. */
.task__no--code { white-space: nowrap; font-size: .8rem; }
.task--urgent .task__no { background: var(--stop-bg); border-color: var(--stop-line); color: var(--stop); }
.task--urgent .task__no small { color: var(--danger); opacity: .75; }
.task--wait .task__no { background: var(--wait-bg); border-color: var(--wait-line); color: var(--wait); }
.task--wait .task__no small { color: var(--warn); opacity: .75; }
.task--ready .task__no { background: var(--go-bg); border-color: var(--go-line); color: var(--go); }
.task--ready .task__no small { color: var(--ok); opacity: .75; }
/* Закрытая работа в очереди работ: видно с одного взгляда, докуда дошли. */
.task__no.done { background: var(--go-bg); border-color: var(--go-line); color: var(--go); }
.task__no.done small { color: var(--ok); opacity: .75; }

.task__main { min-width: 0; }
.task__title { font-weight: 600; font-size: .98rem; }
.task__title span { font-weight: 400; color: var(--ink-2); }
.task__meta { font-size: .82rem; color: var(--ink-2); display: flex; gap: 10px; flex-wrap: wrap; margin-top: 2px; }
.task__meta b { color: var(--ink); font-weight: 500; }

.task__act { display: flex; gap: 8px; align-items: center; }
.task__act .sum { font-family: var(--mono); font-size: 1rem; font-weight: 600; margin-right: 4px; }

/* Раскрытая карточка живёт в потоке — сотрудник не теряет очередь из виду. */
.task__panel {
  grid-column: 1 / -1;
  margin-top: 10px;
  padding-top: 14px;
  border-top: 1px dashed var(--line-strong);
}

/* ─────────── статусы ─────────── */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-floor);   /* ниже этого чип на пастельном фоне под углом не читается */
  font-weight: 500;
  letter-spacing: .01em;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: #eceae2;
  color: var(--ink-2);
  white-space: nowrap;
}
.tag::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* Метка красится не по названию статуса, а по ответу на вопрос «чей сейчас ход».
   Сотрудник не обязан помнить, что «diagnosed» — это его дело, а «in_progress» —
   уже нет: он видит зелёное и знает, что это к нему. */
.tag.new,                                    /* ждёт разбора — ваш ход */
.tag.diagnosed,                              /* назначить мастера — ваш ход */
.tag.done,                                   /* передать кассиру — ваш ход */
.tag.open { background: var(--go-bg); color: var(--go); }

.tag.in_progress,                            /* у мастера */
.tag.awaiting_payment { background: var(--info-bg); color: var(--info); }   /* у кассы */

.tag.waiting_part,                           /* ждём деталь */
.tag.paused { background: var(--wait-bg); color: var(--wait); }

/* Ваш ход не по статусу заявки, а по событию: мастер поднял руку и ждёт ответа. */
.tag.mine { background: var(--go-bg); color: var(--go); }
/* Человек сидит в зале: не ждём мы, а ждут нас — поэтому жёлтый, а не синий. */
.tag.hot { background: var(--wait-bg); color: var(--wait); }
.tag.cancelled { background: var(--stop-bg); color: var(--stop); }
.tag.paid, .tag.closed { background: #eceae2; color: var(--ink-2); }        /* дело закрыто */

/* То же правило четырёх цветов, но для состояний, у которых нет статуса заявки:
   сверка ящика, остаток, долг. Красить их через .tag.cancelled значило бы называть
   недостачу отменённым заказом. */
.tag--go { background: var(--go-bg); color: var(--go); }
.tag--wait { background: var(--wait-bg); color: var(--wait); }
.tag--stop { background: var(--stop-bg); color: var(--stop); }

/* ─────────── таблицы ─────────── */
table { width: 100%; border-collapse: collapse; background: var(--surface); font-size: .9rem; }
/* Шапка колонки — прописные, 12 точек, 600. Прописные читаются медленнее строчных,
   поэтому им нужен и вес, и разрядка, и размер не по остаточному принципу:
   заголовок «ОСТАЛОСЬ» над колонкой сумм — половина смысла таблицы. */
th {
  text-align: left;
  font-weight: 600;
  font-size: 12px;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 9px 10px;
  border-bottom: 1px solid var(--line-strong);
  white-space: nowrap;
}
td { padding: 9px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
tbody tr:hover td, tr:hover td { background: var(--surface-2); }
table .row { margin: 0; gap: 6px; }
table button { min-height: 32px; padding: 5px 10px; font-size: .84rem; }

/* ─────────── экран хостес и крупные подтверждения ─────────── */
.big {
  font-size: clamp(1.6rem, 4vw, 2.4rem);
  font-weight: 600;
  line-height: 1.2;
  padding: 28px 24px;
  text-align: center;
  background: var(--ok-bg);
  color: #14432c;
  border: 1px solid #bfe0cd;
  border-radius: var(--r);
}
.big small { display: block; margin-top: 8px; font-size: 1rem; font-weight: 400; color: #2f6b4c; }
/* Галочка приёма: одна деталь, которая говорит «готово» раньше, чем текст
   прочитан — на приёме клиентов много, и глаз должен ловить итог, не фразу. */
.big__check { display: block; width: 40px; height: 40px; margin: 0 auto 10px; color: var(--go); }

/* ─────────── пустые состояния и загрузка ─────────── */
.empty {
  padding: 32px 20px;
  text-align: center;
  color: var(--ink-2);
  background: var(--surface);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r);
}
.empty b { display: block; color: var(--ink); font-weight: 600; margin-bottom: 4px; }

.skeleton {
  height: 62px;
  border-radius: var(--r);
  background: linear-gradient(90deg, #eeece5 25%, #f6f5f0 37%, #eeece5 63%);
  background-size: 400% 100%;
  animation: shimmer 1.4s ease infinite;
}
@keyframes shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }

/* ─────────── подтверждение QR-кодом ─────────── */
.modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(11, 36, 29, .55);
  backdrop-filter: blur(2px);
  display: grid;
  place-items: start center;
  padding: 12vh 16px;
  animation: fade 140ms ease-out;
}
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
.modal .card { max-width: 520px; width: 100%; margin: 0; box-shadow: var(--shadow-2); }
.modal input, .modal select, .modal textarea { width: 100%; }
/* Поле сканера — моноширинное: код читается посимвольно. */
.modal #qrInput { font-family: var(--mono); }

/* Окно подтверждения. Камера — главное, что здесь происходит, поэтому она занимает
   почти всю карточку: человек держит QR-код в одной руке и планшет в другой, и попасть
   кодом в маленькое окошко предпросмотра одной рукой невозможно. Рамка показывает, куда
   попасть; по прочтении она зеленеет — это единственная обратная связь до того, как
   окно закроется. */
.qrask { max-width: 460px; }
.qrask__cam {
  position: relative;
  margin: 4px 0 10px;
  border-radius: var(--r);
  overflow: hidden;
  background: #0b1512;
}
.qrask__cam video {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  max-height: 46vh;
  object-fit: cover;
}
.qrask__frame {
  position: absolute;
  inset: 14% 22%;
  border: 2px solid rgba(255, 255, 255, .82);
  border-radius: 12px;
  box-shadow: 0 0 0 100vmax rgba(11, 21, 18, .38);
  transition: border-color var(--fast), background var(--fast);
}
.qrask__cam.is-read .qrask__frame { border-color: var(--go); background: rgba(24, 107, 70, .28); }
.qrask__lead { margin: 0 0 12px; text-align: center; font-size: .9rem; color: var(--ink-2); }
.qrask__code { margin-bottom: 4px; }
.qrask__code input { min-height: 46px; }
.qrask__act { margin-top: 14px; }
@media (prefers-reduced-motion: reduce) {
  .qrask__frame { transition: none; }
}

/* Форма в диалоге: все поля разом, а не вопрос за вопросом. */
.formgrid { display: grid; gap: 12px; }
.field { display: grid; gap: 5px; align-content: start; }
.field__label { font-size: .78rem; font-weight: 500; color: var(--ink-2); }
.field textarea { resize: vertical; font: inherit; }
@media (min-width: 560px) {
  .formgrid { grid-template-columns: 1fr 1fr; }
  .formgrid .field:only-child, .field--wide { grid-column: 1 / -1; }
}

/* ─────────── уведомление ─────────── */
#toast {
  position: fixed;
  left: 50%;
  bottom: 20px;
  transform: translate(-50%, 160%);
  z-index: 70;
  max-width: min(560px, calc(100vw - 32px));
  padding: 11px 16px;
  border-radius: var(--r);
  background: var(--chrome);
  color: #eef1ee;
  font-size: .9rem;
  box-shadow: var(--shadow-2);
  opacity: 0;
  visibility: hidden;
  transition: transform 260ms cubic-bezier(.2, .6, .3, 1), opacity 200ms, visibility 260ms;
}
#toast.is-on { transform: translate(-50%, 0); opacity: 1; visibility: visible; }
#toast.err { background: var(--danger); }

/* ─────────── вкладки ─────────── */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line-strong); margin-bottom: 18px; }
.tabs button {
  background: transparent;
  color: var(--ink-2);
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  padding: 10px 14px;
  min-height: 42px;
}
.tabs button:hover { color: var(--ink); background: transparent; }
.tabs button[aria-current="true"] { color: var(--ink); border-bottom-color: var(--go); font-weight: 600; }
.tabs .count {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 20px;
  background: var(--line);
  color: var(--ink-2);
  font-size: .74rem;
  font-weight: 500;
}
.tabs button[aria-current="true"] .count { background: var(--go); color: #fff; }

/* ─────────── рабочее место мастера ───────────
   Мастер работает стоя, телефон или планшет лежит на столе среди инструмента, и
   смотрит он на экран секунду между двумя движениями. Отсюда всё остальное: цели
   нажатия крупнее обычных, название аппарата — самое большое на экране, главное
   действие одно и живёт внизу, под большим пальцем, а код разблокировки читается
   с расстояния вытянутой руки.

   Три состояния — три вида. Очередь и «перед началом» светлые, как весь цех. Работа
   тёмная: экран меняется целиком, и это видно боковым зрением, с другого конца стола. */
.mw { max-width: 760px; margin: 0 auto; padding-bottom: var(--s5); }
.mw .ic { width: 18px; height: 18px; flex: 0 0 auto; }
.mono { font-family: var(--mono); letter-spacing: .04em; }

/* Точка «идёт» — дышит, пока идут часы. Единственное движение на экране, которое
   повторяется: всё остальное двигается один раз, в момент перемены. */
.mwdot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: var(--go); box-shadow: 0 0 0 0 rgba(22, 163, 74, .5);
  animation: mwbreathe 2.4s ease-in-out infinite;
}
@keyframes mwbreathe {
  0%, 100% { box-shadow: 0 0 0 0 rgba(22, 163, 74, .45); }
  50% { box-shadow: 0 0 0 5px rgba(22, 163, 74, 0); }
}

/* Метка: состояние заявки одним словом и цветом. Четыре смысла системы — и только они. */
.mwpill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: var(--r-pill);
  font-size: .78rem; font-weight: 600; line-height: 1.4; white-space: nowrap;
  background: var(--surface-2); color: var(--ink-2);
}
.mwpill .ic { width: 13px; height: 13px; }
.mwpill--go { background: var(--go-bg); color: var(--go-hover); }
.mwpill--wait { background: var(--wait-bg); color: #9a5405; }
.mwpill--info { background: var(--info-bg); color: var(--info); }
.mwpill--stop { background: var(--stop-bg); color: var(--stop); }

/* Большая кнопка — одна на экран. Высота под палец в перчатке, а не под курсор. */
.mwbig {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; min-height: 60px; padding: 14px 22px;
  font-size: 1.1rem; font-weight: 700; letter-spacing: -.01em;
  border-radius: var(--r);
}
.mwbig .ic { width: 22px; height: 22px; stroke-width: 2; }
.mwbig small { font-size: .85rem; font-weight: 500; opacity: .85; }
.mwbig:disabled { background: var(--surface-2); color: var(--ink-3); box-shadow: none; cursor: default; transform: none; }
button.mwsm { min-height: 34px; padding: 6px 12px; font-size: .84rem; display: inline-flex; gap: 6px; align-items: center; }

/* ── очередь ── */
.mwshift {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 14px; margin-bottom: var(--s4);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
}
.mwshift__txt { display: grid; line-height: 1.2; }
.mwshift__txt b { font-size: .95rem; }
.mwshift__txt span { font-family: var(--mono); font-size: .82rem; color: var(--ink-2); }
.mwshift .spacer { margin-left: auto; }
.mwbye { display: flex; justify-content: center; margin-top: var(--s5); }
.mwshift button { display: inline-flex; gap: 6px; align-items: center; }

.mwgate {
  display: grid; gap: 14px; grid-template-columns: auto 1fr; align-items: center;
  padding: 20px; margin-bottom: var(--s4);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}
.mwgate h2 { margin: 0 0 2px; }
.mwgate p { margin: 0; color: var(--ink-2); }
.mwgate .mwbig { grid-column: 1 / -1; }
.mwgate__ic { display: grid; place-items: center; width: 48px; height: 48px; border-radius: 50%;
  background: var(--info-bg); color: var(--info); }
.mwgate__ic .ic { width: 24px; height: 24px; }

/* «Сейчас в руках» — одна тёмная плашка над очередью: вышел посмотреть список,
   а работа идёт, и вернуться к ней — одно касание. */
.mwnow {
  display: grid; grid-template-columns: 1fr auto; gap: 4px 12px; align-items: center;
  width: 100%; margin-bottom: var(--s4); padding: 16px 18px;
  background: var(--ink); color: #fff; border: 0; border-radius: var(--r-lg);
  text-align: left; box-shadow: var(--shadow-2);
}
.mwnow:hover { background: #2b2550; }
.mwnow__k { display: inline-flex; align-items: center; gap: 8px; font-size: .78rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .08em; color: #a7f3c4; }
.mwnow__dev { grid-column: 1; font-size: 1.15rem; }
.mwnow__t { grid-column: 2; grid-row: 1 / 3; font-family: var(--mono); font-size: 1.6rem; font-weight: 600; }
.mwnow__go { grid-column: 1 / -1; font-size: .84rem; color: #cfc8f5; }

.mwhead { display: flex; align-items: center; gap: 8px; margin: var(--s5) 0 10px; }
.mwhead h3 { margin: 0; font-size: 1rem; }
.mwcount { min-width: 24px; padding: 1px 8px; border-radius: var(--r-pill); background: var(--surface-2);
  color: var(--ink-2); font-size: .8rem; font-weight: 600; text-align: center; }
.mq__find { width: 100%; margin-bottom: 10px; }

.mwqueue { display: grid; gap: 10px; }
/* Заявки, где шаг у другого мастера: свёрнуты под лентой своих (разбор 2026-09-30). */
.mwothers { margin-top: 14px; }
.mwothers > summary { cursor: pointer; padding: 10px 2px; color: var(--ink-2); font-weight: 600; }
.mwothers[open] > summary { margin-bottom: 8px; }
.loadfail { display: grid; gap: 12px; justify-items: start; padding: 20px; }
.mwq {
  display: flex; gap: 12px; align-items: flex-start; justify-content: space-between;
  width: 100%; min-height: 76px; padding: 14px 16px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r);
  text-align: left; box-shadow: var(--shadow-1);
  transition: border-color var(--fast), box-shadow var(--fast), transform var(--fast);
}
.mwq:hover { background: var(--surface); border-color: var(--line-strong); box-shadow: var(--shadow-2); }
.mwq:active { transform: scale(.995); }
.mwq[hidden] { display: none; }
.mwq__main { display: grid; gap: 3px; min-width: 0; }
.mwq__dev { font-size: 1.05rem; letter-spacing: -.01em; }
.mwq__sym { color: var(--ink-2); font-size: .9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mwq__who { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; font-size: .8rem; color: var(--ink-3); }
.mwq__who code, .mwcard__code code { font-family: var(--mono); font-size: .8rem; color: var(--ink); letter-spacing: .04em; }
.mwq__side { display: grid; gap: 6px; justify-items: end; flex: 0 0 auto; }

/* ── заявка до начала ── */
.mwbar { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; }
.mwback { display: inline-flex; gap: 4px; align-items: center; padding-left: 4px; font-weight: 600; }
.mwcard {
  padding: 20px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-1);
  animation: mwrise 260ms var(--smooth);
}
@keyframes mwrise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.mwcard__head { margin-bottom: 14px; }
.mwcard__code { margin: 0 0 6px; font-size: .8rem; color: var(--ink-3); }
.mwcard__dev { margin: 0; font-size: 1.6rem; line-height: 1.15; letter-spacing: -.025em; }
.mwcard__sym { margin: 4px 0 0; font-size: 1rem; color: var(--ink-2); }
.mwcard__tags { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; }
.mwcard__tags:empty { display: none; }
.mwh { margin: var(--s5) 0 10px; font-size: .78rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em; color: var(--ink-3); }
.mwh4 { margin: 14px 0 8px; font-size: .85rem; }

/* «Перед началом» — не форма, а осмотр: три вопроса, у каждого значок-ответ слева.
   Зелёный — готово, жёлтый — надо сделать, прежде чем вскрывать. */
.mwcheck { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.mwcheck > li {
  display: grid; grid-template-columns: 36px 1fr; gap: 12px; align-items: start;
  padding: 12px 14px; border-radius: var(--r); background: var(--surface-2);
}
.mwcheck > li > div { min-width: 0; }
.mwcheck > li > div > b { display: block; font-size: .95rem; margin-bottom: 2px; }
.mwcheck > li > div > span { display: block; color: var(--ink-2); font-size: .9rem; }
.mwcheck__ic { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 50%;
  background: var(--surface); color: var(--ink-2); }
.mwcheck .is-ok .mwcheck__ic { background: var(--go-bg); color: var(--go); }
.mwcheck .is-wait .mwcheck__ic, .mwcheck .is-warn .mwcheck__ic { background: var(--wait-bg); color: var(--wait); }
.mwcheck .is-warn, .mwcheck .is-wait { background: #fff8ec; }
.mwcheck .is-info .mwcheck__ic { background: var(--info-bg); color: var(--info); }
/* Код набирают глазами с экрана — крупно и с разрядкой, цифры не склеиваются. */
.mwcheck__big { font-family: var(--mono); font-size: 1.5rem !important; font-weight: 600; letter-spacing: .12em;
  color: var(--ink) !important; white-space: pre-line; }

.mwintake { display: grid; gap: 8px; margin-top: 6px; justify-items: start; }
.mwintake .hint { margin: 0; }
.mwintake__tags { display: flex; flex-wrap: wrap; gap: 6px; }
.mwintake__none { margin: 0; color: var(--ink-2); font-size: .9rem; }
.mwdefect { padding: 4px 10px; border-radius: var(--r-pill); background: var(--wait-bg);
  color: #8a4b04; font-size: .84rem; font-weight: 600; }

/* Снимки лентой: палец листает вбок, подпись под кадром, а не в отдельном окне. */
.mwshots { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px; max-width: 100%;
  scrollbar-width: none; }
.mwshots::-webkit-scrollbar { display: none; }
.mwshots__it {
  flex: 0 0 auto; display: grid; gap: 4px; width: 112px; padding: 0;
  background: none; border: 0; box-shadow: none; color: var(--ink-2); text-align: left;
  font-size: .75rem; line-height: 1.3; font-weight: 500;
}
.mwshots__it:hover { background: none; }
.mwshots__it img { width: 112px; height: 112px; object-fit: cover; border-radius: var(--r-sm);
  border: 1px solid var(--line); background: var(--surface-2); }
.mwshots__it span { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
.mwshots__it i { color: var(--ink-3); }

.mwsteps { display: grid; gap: 8px; }
.mwstep {
  display: grid; grid-template-columns: 34px 1fr auto; gap: 12px; align-items: start;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface);
}
.mwstep__n { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%;
  background: var(--surface-2); color: var(--ink-2); font-weight: 700; }
.mwstep__main { min-width: 0; }
.mwstep__main b { display: block; }
.mwstep__main > span { font-size: .84rem; color: var(--ink-2); }
.mwstep__main .note { margin: 8px 0 0; }
.mwstep--now { border-color: var(--go-line); box-shadow: 0 0 0 3px var(--go-bg); }
.mwstep--now .mwstep__n { background: var(--go); color: #fff; }
.mwstep--done { background: var(--surface-2); border-color: transparent; }
.mwstep--done .mwstep__n { background: var(--go-bg); color: var(--go); }
.mwstep--done b { color: var(--ink-2); }

/* Нижняя панель: главное действие всегда под большим пальцем, сколько бы ни было
   над ним. Стоит в потоке и прилипает к низу — не закрывает последнюю строку. */
.mwdock {
  position: sticky; bottom: 0; z-index: 20;
  display: grid; gap: 8px;
  margin: var(--s4) calc(-1 * var(--s2)) 0; padding: 12px var(--s2) calc(12px + env(safe-area-inset-bottom));
  background: linear-gradient(to top, var(--canvas) 78%, transparent);
}
.mwdock__row { display: grid; grid-template-columns: 1fr 1fr auto; gap: 8px; }
.mwdock__row button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 46px; }

/* ── работа: экран темнеет ── */
.mwlive {
  position: relative; overflow: hidden;
  margin: 0 0 var(--s4); padding: 14px 18px 20px;
  background: radial-gradient(120% 90% at 100% 0%, #3a2f7a 0%, transparent 60%), var(--ink);
  color: #fff; border-radius: var(--r-lg); box-shadow: var(--shadow-2);
  animation: mwrise 320ms var(--smooth);
}
.mwlive__top { display: flex; align-items: center; gap: 10px; }
.mwlive__back { display: grid; place-items: center; width: 40px; height: 40px; min-height: 0; padding: 0;
  border-radius: 50%; background: rgba(255, 255, 255, .1); color: #fff; box-shadow: none; }
.mwlive__back:hover { background: rgba(255, 255, 255, .18); }
.mwlive__state { display: inline-flex; align-items: center; gap: 8px; font-size: .78rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .1em; color: #a7f3c4; }
.mwlive__code { margin-left: auto; font-family: var(--mono); font-size: .82rem; color: #cfc8f5; letter-spacing: .06em; }
/* Часы — самое крупное на экране: «сколько я уже на нём» читается с другого конца стола. */
.mwlive__clock { margin: 18px 0 6px; font-family: var(--mono); font-size: clamp(3rem, 14vw, 4.4rem);
  font-weight: 600; line-height: 1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.mwlive__dev { margin: 0; color: #fff; font-size: 1.35rem; }
.mwlive__step { margin: 4px 0 0; color: #d9d4f7; font-size: 1rem; }
.mwlive__prog { height: 6px; margin-top: 12px; border-radius: var(--r-pill); background: rgba(255, 255, 255, .14); overflow: hidden; }
.mwlive__prog i { display: block; height: 100%; background: #4ade80; border-radius: inherit; transition: width var(--smooth); }
.mwlive__facts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.mwlive__facts > span {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px;
  border-radius: var(--r-pill); background: rgba(255, 255, 255, .1); font-size: .86rem; color: #ece9fb;
}
.mwlive__facts b { font-family: var(--mono); font-size: 1rem; letter-spacing: .1em; color: #fff; }
.mwlive__facts .ic { width: 15px; height: 15px; }
.mwlive__facts .is-warn { background: rgba(251, 191, 36, .18); color: #fde68a; }

/* Три дела под рукой во время работы — плитками, а не строкой кнопок: попасть в
   плитку можно не глядя, в кнопку «Спросить администратора» — нет. */
.mwtools { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: var(--s4); }
.mwtool {
  display: grid; justify-items: center; gap: 4px; min-height: 104px; padding: 14px 8px;
  background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: var(--shadow-1); text-align: center;
}
.mwtool:hover { background: var(--surface); border-color: var(--info-line); box-shadow: var(--shadow-2); }
.mwtool .ic { width: 28px; height: 28px; color: var(--info); stroke-width: 1.8; }
.mwtool b { font-size: .98rem; }
.mwtool span { font-size: .76rem; color: var(--ink-3); font-weight: 500; }

.mwmore { margin-top: var(--s4); border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.mwmore > summary { cursor: pointer; padding: 14px 16px; font-weight: 600; list-style: none; }
.mwmore > summary::-webkit-details-marker { display: none; }
.mwmore > summary::after { content: '＋'; float: right; color: var(--ink-3); }
.mwmore[open] > summary::after { content: '−'; }
.mwmore > :not(summary) { margin-inline: 16px; }
.mwmore > :last-child { margin-bottom: 16px; }
.mwfacts { display: grid; gap: 8px; }
.mwfacts > div { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.mwfacts span { min-width: 130px; font-size: .84rem; color: var(--ink-2); }
.mwfacts b i { font-family: var(--sans); font-weight: 500; color: var(--ink-3); }
.mwmore__act { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }

.mwdock--live { grid-template-columns: auto 1fr; align-items: stretch; }
.mwpause {
  display: grid; justify-items: center; align-content: center; gap: 2px;
  min-width: 92px; min-height: 60px; padding: 8px 14px;
  background: var(--surface); color: var(--ink); border: 1px solid var(--line-strong); border-radius: var(--r);
  box-shadow: none; font-size: .8rem; font-weight: 600;
}
.mwpause:hover { background: var(--wait-bg); border-color: var(--wait-line); }
.mwpause .ic { width: 22px; height: 22px; color: var(--wait); stroke-width: 2.2; }

/* ── перерыв: весь экран ── */
.mwbreak {
  position: fixed; inset: 0; z-index: 40;
  display: grid; place-items: center; padding: 24px;
  background: radial-gradient(90% 70% at 50% 0%, #3a2f7a 0%, transparent 70%), var(--ink);
  color: #fff; animation: fade 200ms ease-out;
}
.mwbreak__in { display: grid; justify-items: center; gap: 10px; width: 100%; max-width: 420px; text-align: center; }
.mwbreak__ic { display: grid; place-items: center; width: 64px; height: 64px; border-radius: 50%;
  background: rgba(251, 191, 36, .16); color: #fbbf24; }
.mwbreak__ic .ic { width: 30px; height: 30px; stroke-width: 2.2; }
.mwbreak__k { margin: 6px 0 0; font-size: .82rem; font-weight: 700; text-transform: uppercase; letter-spacing: .12em; color: #cfc8f5; }
.mwbreak__t { font-family: var(--mono); font-size: clamp(3.2rem, 16vw, 5rem); font-weight: 600; line-height: 1.05; }
.mwbreak__p { margin: 0 0 14px; color: #d9d4f7; }
.mwbreak__end { color: #cfc8f5; }
.mwbreak__end:hover { background: rgba(255, 255, 255, .08); color: #fff; }

/* ── листы снизу ── */
/* .modal.mwsheet, а не .mwsheet: общие правила окон (прокрутка, телефон) стоят в файле
   ниже и прижимали лист к верху экрана. */
.modal.mwsheet { place-items: end center; padding: 16px; }
.mwsheet__card { max-width: 480px; width: 100%; padding: 20px; border-radius: var(--r-lg);
  animation: mwup 240ms var(--smooth); max-height: 88vh; overflow: auto; }
.mwsheet__card--wide { max-width: 640px; }
@keyframes mwup { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
.mwsheet__card h3 { margin: 0 0 10px; font-size: 1.2rem; }
.mwsheet__k { margin: 0 0 4px; font-size: .75rem; font-weight: 700; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3); }
.mwsheet__act { display: grid; gap: 8px; margin-top: 14px; }
.mwsheet__act button { min-height: 50px; display: inline-flex; gap: 8px; align-items: center; justify-content: center; font-size: 1rem; }
.mwsheet__list { display: grid; gap: 8px; }
.mwsheet__list button { min-height: 50px; justify-content: flex-start; display: flex; gap: 10px; align-items: center; }
.mwsum { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 4px 0 12px; }
.mwsum > div { padding: 12px 14px; border-radius: var(--r); background: var(--surface-2); }
.mwsum span { display: block; font-size: .78rem; color: var(--ink-2); }
.mwsum b { font-size: 1.3rem; }
.mwshot__img { display: block; width: 100%; max-height: 42vh; object-fit: contain; margin-bottom: 12px;
  border-radius: var(--r-sm); background: var(--ink); }
.mwshot__img--big { max-height: 64vh; }
.mwshot__cap { margin: 0; font-weight: 600; }
.mwshot .field { margin-bottom: 8px; }
.mwshot input { width: 100%; }

/* ── возвраты по гарантии ── */
.mwret__score { display: flex; align-items: center; gap: 12px; padding: 14px 16px; margin-bottom: 8px;
  border-radius: var(--r); }
.mwret__score b { font-size: 2rem; line-height: 1; }
.mwret__score.is-good { background: var(--go-bg); color: var(--go-hover); }
.mwret__score.is-bad { background: var(--wait-bg); color: #8a4b04; }
.mwret__it { display: grid; grid-template-columns: 1fr auto; gap: 2px 12px; padding: 12px 14px; margin-bottom: 8px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); }
.mwret__it.is-off { opacity: .7; }
.mwret__what b { display: block; }
.mwret__what span, .mwret__why { font-size: .86rem; color: var(--ink-2); }
.mwret__when { text-align: right; font-size: .84rem; font-weight: 600; color: #9a5405; }
.mwret__when em { display: block; font-style: normal; font-weight: 500; color: var(--ink-3); }
.mwret__it.is-off .mwret__when { color: var(--ink-3); }
.mwret__why { grid-column: 1 / -1; margin: 4px 0 0; }

@media (max-width: 560px) {
  .mwcard { padding: 16px; border-radius: var(--r); }
  .mwcard__dev { font-size: 1.35rem; }
  .mwq { flex-direction: column; gap: 8px; }
  .mwq__side { grid-auto-flow: column; justify-content: start; }
  .mwgate { grid-template-columns: 1fr; }
  .mwtools { gap: 8px; }
  .mwtool { min-height: 92px; }
  .mwstep { grid-template-columns: 30px 1fr; }
  .mwstep > button { grid-column: 2; justify-self: start; }
  .modal.mwsheet { padding: 0; place-items: end stretch; }
  .mwsheet__card { border-radius: var(--r-lg) var(--r-lg) 0 0; padding-bottom: calc(20px + env(safe-area-inset-bottom)); }
}
@media (prefers-reduced-motion: reduce) {
  .mwdot, .mwcard, .mwlive, .mwsheet__card { animation: none; }
}

/* «Деталь на складе» — факт, который стоит заметить один раз, когда он появился
   (JS ставит класс только на первый рендер с новым фактом, см. partsReadyAnnounced
   в master()), а не мигать на нём весь опрос цеха. */
@keyframes notepulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(22, 163, 74, 0); } 30% { box-shadow: 0 0 0 4px var(--go-bg); } }
.note--pulse { animation: notepulse 900ms ease-out; }
@media (prefers-reduced-motion: reduce) { .note--pulse { animation: none; } }

/* Секция «мои детали»: заголовок с пояснением отдельно от списка — как в кабинете
   супер-админа, чтобы вокабуляр экранов не расходился. */
.msec { margin-top: var(--s5); }
.msec__head { margin-bottom: 10px; }
.msec__head h3 { margin: 0 0 2px; font-size: 1rem; }
.msec__head p { margin: 0; }

.mparts { display: grid; gap: 8px; }
.mpart {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  padding: 11px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
/* Деталь, за которой можно идти прямо сейчас, отличается от «ещё ищут» цветом рамки,
   а не только словом в метке: строк бывает шесть, и читать их все незачем. */
.mpart.is-ready { border-color: var(--go-line); background: var(--go-bg); }
.mpart__what { min-width: 0; flex: 1 1 220px; }
.mpart__what b { display: block; font-weight: 600; font-size: .95rem; }
.mpart__what span { font-size: .82rem; color: var(--ink-2); }
.mpart__todo { font-size: .84rem; color: var(--ink-2); text-align: right; }
.mpart__todo em { display: block; font-style: normal; font-size: .78rem; color: var(--ink-3); }
@media (max-width: 560px) { .mpart__todo { text-align: left; flex-basis: 100%; } }

/* ─────────── цепочка передач у супер-админа ─────────── */
/* Путь предмета читается по строке слева направо: просил → купил → принял → забрал.
   Имя и время под ним — одно звено; прочерк значит «этого движения ещё не было», и он
   должен быть виден как пропуск, а не как пустая клетка вёрстки. */
.cust td { vertical-align: top; }
.cust .hint { display: block; font-size: .78rem; }
.cust__who { white-space: nowrap; }
.cust__who b { font-weight: 500; }
.cust__who em {
  display: block;
  font-style: normal;
  font-size: .75rem;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* Резервный код: его переписывают на бумагу, поэтому разрядка и никаких переносов. */
.bkcode {
  font-family: var(--mono);
  font-size: .95rem;
  letter-spacing: .1em;
  color: inherit;
  word-break: normal;
}
.bkoff { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin: 8px 0 0; }

/* ─────────── показатели ─────────── */
.stats { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.stat {
  flex: 1 1 130px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.stat b { display: block; font-size: 1.5rem; line-height: 1.1; font-family: var(--mono); letter-spacing: -.04em; }
.stat span { font-size: .78rem; color: var(--ink-2); }
.stat.alert { border-color: var(--stop-line); background: var(--stop-bg); }
.stat.alert b { color: var(--stop); }
.stat.go { border-color: var(--go-line); background: var(--go-bg); }
.stat.go b { color: var(--go); }
.stat.wait { border-color: var(--wait-line); background: var(--wait-bg); }
.stat.wait b { color: var(--wait); }

/* ─────────── шаги приёма ─────────── */
.steps { counter-reset: s; display: grid; gap: 10px; position: relative; }
.step { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 12px; align-items: start; position: relative; }
/* Соединительная линия между кружками — то, чего не хватало мастеру шагов, чтобы
   читаться как визард, а не просто нумерованный список. Растёт от кружка к кружку,
   зелёная там, где шаг уже пройден. */
.step:not(:last-child)::after {
  content: ''; position: absolute; left: 13px; top: 26px; bottom: -10px; width: 2px;
  background: var(--line-strong);
}
.step.is-done:not(:last-child)::after { background: var(--go-line); }
.step::before {
  counter-increment: s;
  content: counter(s);
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--line-strong);
  color: var(--ink-2);
  font-size: .78rem;
  font-weight: 600;
  position: relative; z-index: 1;
  transition: background var(--fast), color var(--fast);
}
.step.is-done::before { background: var(--go); color: #fff; }
.step.is-todo::before { background: var(--line-strong); color: var(--ink-2); }
/* Шаг «Принять аппарат» готов к нажатию — тот самый момент, когда кружок раньше
   становился глухим чёрным (--chrome, цвет, зарезервированный только под экран
   входа): последний шаг ничего не «завершал», просто терял оба класса-модификатора.
   Теперь у готового шага свой цвет — тот же зелёный, что и «ваш ход» везде в системе. */
.step.is-ready::before { background: var(--go); color: #fff; }
.step__title { font-weight: 500; margin-bottom: 6px; }

/* ─────────── адаптация ─────────── */
@media (max-width: 760px) {
  main { padding: 0 12px; margin-top: 14px; }
  header { padding: 8px 12px; gap: 10px; flex-wrap: wrap; }
  header span { width: 100%; order: 5; margin-left: 0; }
  /* Имя ушло на свою строку (order:5), значит «Выйти» на первой строке осталась
     без распорки — прижимаем её к правому краю, иначе висит вплотную к заголовку. */
  header button { margin-left: auto; }
  .task { grid-template-columns: 2.6rem minmax(0, 1fr); row-gap: 10px; }
  .task__act { grid-column: 1 / -1; justify-content: flex-end; }
  .tabs { overflow-x: auto; }
  table { font-size: .84rem; }
  th, td { padding: 7px 8px; }
  /* Счётчики в две колонки: шесть штук в ряд на телефоне превращаются в ленту
     из обрезков, по которой ничего не прочитать. */
  .stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .stat { min-width: 0; }
  /* Путь заявки прокручивается, а не рвётся на строки: это одна дорога. */
  .flow { flex-wrap: nowrap; overflow-x: auto; padding-bottom: 4px; scrollbar-width: none; }
  .flow::-webkit-scrollbar { display: none; }
  .note { padding: 10px 12px; font-size: .84rem; }
  /* В зале жмут пальцем, а иногда в перчатке: цель не меньше сорока точек. */
  header button { min-height: 40px; padding: 8px 14px; }
  /* Кнопка стадии — главное действие экрана, на телефоне она во всю ширину. */
  .adm__sum button, #take { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ─────────── разбор заявки у администратора ───────────
   Работа слева, смета справа и всегда на виду: её администратор произносит клиенту вслух,
   поэтому она не должна уезжать при прокрутке. */
.adm { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 20px; align-items: start; }
/* Отступ от реальной высоты шапки, а не от числа: на узком экране шапка переносит
   строку и становится выше, и смета уезжала под неё. */
.adm__sum { position: sticky; top: calc(var(--head-h, 66px) + 10px); }
.adm__sum .card { margin: 0; }
@media (max-width: 900px) {
  .adm { grid-template-columns: 1fr; }
  .adm__sum { position: static; }
}

/* Код заявки в шапке карточки. Это то единственное, что клиент называет по телефону
   и читает с квитанции, — поэтому он набран моноширинным и стоит отдельной строкой,
   а не теряется в ряду служебных номеров. Кнопка, а не подпись: нажатие копирует. */
.ocode {
  display: inline-flex; align-items: baseline; gap: 8px;
  margin: 2px 0 12px; padding: 4px 10px;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-sm);
  color: var(--ink); cursor: pointer; font: inherit;
}
.ocode span { font-size: .72rem; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); }
.ocode b { font-family: var(--mono); font-size: 1.02rem; letter-spacing: .04em; }
.ocode:hover { border-color: var(--line-strong); background: var(--surface); }

.admsay { margin: 10px 0 0; font-size: .92rem; }
.admsay .quiet { margin-left: 6px; }

/* Что написал мастер. Полоса слева, а не рамка: это чужая речь внутри карточки,
   и её надо отличать от полей, которые администратор правит сам. */
.admsaid { margin: 10px 0 0; border-left: 2px solid var(--line-strong); padding-left: 10px; }
.admsaid__l { margin: 4px 0; font-size: .92rem; }
.admsaid__l .hint { display: block; }

/* Плитки поломок: администратор думает узлами аппарата, а не строками справочника. */
.tiles { display: grid; gap: 14px; }
.tiles__group { display: grid; gap: 6px; }
.tiles__head {
  font-size: .74rem; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
}
.tiles__group { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
.tiles__head { grid-column: 1 / -1; }

.tile {
  display: grid; gap: 2px; justify-items: start; text-align: left;
  padding: 10px 12px; min-height: 56px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--r);
  font: inherit; cursor: pointer;
  transition: border-color var(--fast), background var(--fast);
}
.tile:hover { background: var(--surface-2); border-color: var(--ink-3); }
.tile__name { font-weight: 500; font-size: .92rem; }
.tile__price { font-size: .8rem; color: var(--ink-2); }
.tile.is-on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.tile.is-on:hover { background: #b03a22; }
.tile.is-on .tile__price { color: #fbded7; }
/* Названо клиентом, но ещё не подтверждено диагностом — версия, а не выбор. */
.tile--said { border-style: dashed; border-color: var(--info-line); background: var(--info-bg); }
.tile--said::after { content: 'со слов клиента'; font-size: .68rem; color: var(--info); }
[data-lang="az"] .tile--said::after { content: 'müştərinin sözlərinə görə'; }
.tile--said:hover { background: var(--info-bg); border-color: var(--info); }

/* Кандидаты в мастера: подсказка обязана объяснять себя, иначе её обходят. */
.cands { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.cand {
  display: grid; gap: 1px; justify-items: start; text-align: left;
  padding: 8px 12px; min-width: 170px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--r);
  font: inherit; cursor: pointer;
  transition: border-color var(--fast), background var(--fast);
}
.cand:hover { background: var(--surface-2); border-color: var(--ink-3); }
.cand__flag {
  font-size: .66rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--info);
}
.cand--best { border-color: var(--info-line); background: var(--info-bg); }
.cand--best:hover { border-color: var(--info); background: var(--info-bg); }
.cand__name { font-weight: 500; font-size: .92rem; }
.cand__why { font-size: .78rem; color: var(--ink-2); }
.cand.is-on { background: var(--chrome); border-color: var(--chrome); color: #eef1ee; }
.cand.is-on .cand__why { color: #a9bdb0; }
.cand.is-on .cand__flag { color: #8ec1f0; }
/* «Не берёт эту работу» и «предел загрузки» — предупреждение, а не запрет: красный
   пунктир, но кнопка живая. Спрятать нельзя — администратор будет искать человека
   и не поймёт, куда тот делся. */
.cand--off { border-style: dashed; border-color: var(--stop-line); background: var(--surface); }
.cand--off .cand__name { color: var(--ink-2); }
.cand--off .cand__why { color: var(--stop); }
.cand--off:hover { background: var(--stop-bg); border-color: var(--stop); }

/* ─────────── путь заявки ───────────
   Администратор должен видеть не статус в базе, а место заявки в дороге:
   где она сейчас и чей следующий ход. */
.flow { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 0 0 8px; padding: 0; }
.flow__i {
  padding: 5px 12px; border-radius: 999px;
  background: var(--surface-2); color: var(--ink-3);
  border: 1px solid var(--line); font-size: .8rem; white-space: nowrap;
}
/* Пройденное — зелёное и приглушённое, текущее — зелёное и полное.
   Будущее остаётся серым: цветом отмечено только то, что уже случилось. */
.flow__i.is-past { background: var(--go-bg); border-color: var(--go-line); color: var(--go); }
.flow__i.is-now {
  background: var(--go); border-color: var(--go); color: var(--go-ink); font-weight: 600;
  box-shadow: 0 1px 2px rgba(24, 107, 70, .3);
}
.flow__next { margin: 0 0 14px; font-size: .92rem; color: var(--ink-2); }
.flow__next b { color: var(--ink); }

/* Предупреждение, которое администратор обязан увидеть до разговора о цене:
   гарантия ещё жива, у клиента здесь второй аппарат. */
/* Предупреждение над заявкой: жёлтое, потому что это не запрет, а «прочти,
   прежде чем говорить с клиентом о цене» — живая гарантия, второй аппарат. */
.card--warn { border-color: var(--wait-line); background: var(--wait-bg); }
.card--warn .estim li { border-bottom-color: var(--wait-line); }
.card--warn > b { color: #57390a; }

/* Справка, меняющая разговор с клиентом: действующая гарантия на этот аппарат,
   второй его телефон у нас. Ждать тут нечего — это факт, а не ожидание, поэтому
   синий: жёлтым он забирал внимание у строк, где человек правда ждёт. */
.card--info { border-color: var(--info-line); background: var(--info-bg); }
.card--info .estim li { border-bottom-color: var(--info-line); }
.card--info > b { color: #12325a; }
.card--info .quiet { color: var(--info); text-decoration: underline;
  text-decoration-color: var(--info-line); text-underline-offset: 3px; }
.card--info .quiet:hover { background: rgba(255, 255, 255, .6); }

/* Снимки приёмки: доказательство, а не украшение — поэтому мелко и в ряд. */
.shots { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.shots img {
  width: 96px; height: 96px; object-fit: cover;
  border-radius: var(--r); border: 1px solid var(--line-strong);
}
/* Кадр с подписью: «трещина справа сверху» объясняет, на что смотреть, а две кнопки
   под ним дают переподписать и убрать не тот снимок. Ширина — по миниатюре, иначе
   длинная подпись растягивает плитку и ряд перестаёт быть рядом. */
.shot { margin: 0; width: 96px; }
.shot figcaption {
  margin-top: 4px; font-size: .75rem; line-height: 1.3; color: var(--ink-2); word-break: break-word;
}
.shot figcaption button { display: inline; padding: 0; font-size: .75rem; }

/* От чего клиент отказался: остаётся видно, но в сумму не идёт. */
.task--off { opacity: .6; }
.estim li.is-off { opacity: .6; text-decoration: line-through; }
.estim li.is-off .hint { text-decoration: none; }

/* Смета */
.estim { list-style: none; margin: 0 0 10px; padding: 0; }
.estim li { display: flex; justify-content: space-between; gap: 10px; padding: 6px 0;
  border-bottom: 1px solid var(--line); font-size: .9rem; }
.estim__total { display: flex; justify-content: space-between; align-items: baseline;
  margin: 0 0 12px; font-size: 1.05rem; }
.estim__total b { font-size: 1.3rem; letter-spacing: -.02em; }
.adm__sum button { width: 100%; margin-top: 6px; }

/* Скидка в смете. Уступают с конкретной работы, поэтому строка скидки стоит под своей
   работой и сдвинута вправо — видно, к чему она относится, без объяснений.
   Кнопки внутри сметы обязаны быть текстом: правило выше растягивает любую кнопку
   в этой колонке на всю ширину, и «%» рядом с ценой превратилось бы в полосу. */
.estim .pricebtn { width: auto; margin: 0; flex: none; color: var(--ink-3); }
.estim .pricebtn:hover { color: var(--ink); }
.estim li.estim__off { color: var(--go); border-bottom-style: dashed; }
.estim li.estim__off span { padding-left: 10px; }

.quiet.is-on { background: var(--chrome); color: #eef1ee; }

/* ─────────── выбор устройства плитками ───────────
   За стойкой не читают выпадающий список из двухсот строк: узнают модель в лицо
   и попадают пальцем. Цель нажатия крупная — работают в перчатках и в спешке. */
.pickpath { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; margin-bottom: 8px; }
.pickpath__sep { color: var(--ink-3); font-size: .8rem; }
.pickpath .quiet { font-size: .84rem; padding: 4px 8px; min-height: 30px; }

/* Быстрый путь к модели: восемь самых частых плюс поиск по листьям. Дерево остаётся
   ниже — оно нужно для редкого аппарата, а не для каждого приёма. */
.pickquick { margin-bottom: 10px; }
.pickquick .pickgrid { margin-bottom: 8px; }
.pickfind { width: 100%; max-width: 320px; }

.pickgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 8px; }
.pick {
  min-height: 54px; padding: 10px 12px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--r);
  font: 500 .95rem/1.25 var(--sans); text-align: left; cursor: pointer;
  transition: border-color var(--fast), background var(--fast);
}
.pick:hover { background: var(--surface-2); border-color: var(--ink-3); }
/* Конечная модель — на неё уже можно оформлять, поэтому она читается иначе, чем раздел. */
.pick--leaf { border-color: var(--ink-3); }
/* «Добавить» стоит в одной сетке с плитками аппаратов, но не притворяется одной из них:
   пунктир и приглушённый текст — это действие, а не пункт справочника. */
.pick--add { border-style: dashed; color: var(--ink-2); }
.pick--add:hover { color: var(--ink); }
.pick--leaf::after { content: '→'; float: right; color: var(--ink-3); }

/* ─────────── силуэты ───────────
   Свои SVG в одном весе линии. Хостес тратит на приём десять секунд:
   за это время читается силуэт, а не подпись. Подпись — подтверждение, а не опознание. */
.ic { flex: 0 0 auto; display: block; }
.ic--brand { width: 30px; height: 30px; color: var(--ink-2); }

/* Плитка симптома: крупная цель, силуэт сверху, слово под ним. */
.symp {
  display: grid; justify-items: center; gap: 7px;
  min-height: 92px; padding: 14px 10px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--r);
  font: 500 .9rem/1.2 var(--sans); text-align: center; cursor: pointer;
  transition: border-color var(--fast), background var(--fast), color var(--fast);
}
.symp .ic { width: 30px; height: 30px; color: var(--ink-2); }
.symp:hover { background: var(--surface-2); border-color: var(--ink-3); }
.symp:hover .ic { color: var(--ink); }
.symp.is-on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.symp.is-on .ic { color: var(--accent-ink); }

/* Подтверждение приёма. Самое необратимое действие экрана: отдельная крупная кнопка,
   а не касание симптома — промах пальцем не должен стоить вызова супер-админа. */
#take { min-width: 260px; padding: 14px 22px; font-size: 1.05rem; }
#sumUp.ready, #willBe { font-size: 1rem; color: var(--ink); margin-bottom: .5rem; }

/* Плитка устройства: на первом уровне силуэт слева от имени бренда. */
.pick { display: flex; align-items: center; gap: 10px; }
.pick > span { min-width: 0; }
.pick:hover .ic--brand { color: var(--ink); }

/* ═══════════════════ деньги и себестоимость ═══════════════════ */

/* Первый экран супер-админа отвечает на первый вопрос супер-админа.
   Не таблица, не график — одна цифра, крупно, и под ней честная арифметика,
   из которой она получилась. Спорить с такой цифрой можно построчно. */
.daymoney {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: var(--s5);
  align-items: center;
  padding: var(--s5);
  margin-bottom: var(--s4);
  border-radius: var(--r-lg);
  background: linear-gradient(158deg, var(--chrome) 0%, #0e2f26 62%, #123a2c 100%);
  color: #eef1ee;
  box-shadow: var(--shadow-2);
}
.daymoney__label {
  display: block; font-size: .78rem; letter-spacing: .06em; text-transform: uppercase;
  color: #8fae9d;
}
.daymoney__sum {
  display: block; margin: 2px 0 4px;
  font-family: var(--mono); font-size: clamp(2rem, 5vw, 2.9rem); font-weight: 600;
  letter-spacing: -.04em; line-height: 1;
}
.daymoney__sub { font-size: .85rem; color: #a9bdb0; }

/* Арифметика дня: принято → минус детали → минус траты → осталось.
   Каждая строка на своём месте, итог отделён линией, а не цветом. */
.daymoney__flow { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.daymoney__flow li {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--s3);
  padding: 7px 0; font-size: .88rem; color: #cfdcd5;
}
.daymoney__flow b { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.daymoney__flow .is-minus { color: #a9bdb0; }
.daymoney__flow .is-sub {
  margin: var(--s1) 0; padding: 7px 0;
  border-top: 1px solid rgba(207, 220, 213, .14);
  border-bottom: 1px solid rgba(207, 220, 213, .14);
  color: #eef1ee; font-weight: 500;
}
.daymoney__flow .is-total {
  margin-top: var(--s1); padding-top: var(--s3);
  border-top: 1px solid rgba(207, 220, 213, .22);
  color: #fff; font-weight: 600; font-size: 1rem;
}
/* Минус виден цветом, но и знаком: на тёмном фоне один цвет читается хуже. */
.daymoney__sum.is-neg, .daymoney__flow .is-total.is-neg b { color: #f0a99e; }
@media (max-width: 760px) {
  .daymoney { grid-template-columns: 1fr; gap: var(--s4); padding: var(--s4); }
}

/* Себестоимость в смете администратора: цену он называет клиенту вслух, а прибыль
   читает глазами — поэтому мельче итога и приглушённее, но на том же месте. */
.estim__margin {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--s2);
  margin: 0 0 2px; font-size: .84rem; color: var(--ink-2);
}
.estim__margin--net {
  margin-top: var(--s1); padding-top: var(--s2);
  border-top: 1px solid var(--line); color: var(--ink); font-size: .92rem;
}
.estim__margin--net b { font-family: var(--mono); color: var(--go); font-size: 1.05rem; }

/* Прибыль по заявке в отчёте: минус читается сразу, а не вычисляется взглядом. */
b.pos { color: var(--go); }
b.neg { color: var(--stop); }

/* Закупочная цена в справочнике отличается от цены клиенту: её видит только супер-админ. */
.vcell input.cost { background: var(--surface-2); color: var(--ink-2); }
.vcell input.cost:focus { background: var(--surface); color: var(--ink); }

/* Код разблокировки: его диктуют вслух и набирают на чужом аппарате,
   поэтому моноширинный и с разрядкой — «0» и «O» не должны спорить. */
.pass {
  font-family: var(--mono); font-size: .95em; letter-spacing: .06em;
  padding: 1px 6px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--line);
  white-space: pre-line;
}
.miss { color: var(--stop); }

/* ═══════════════════ журнал действий ═══════════════════ */

/* Лента длинная, читают её по диагонали в поисках одного человека или одного дня.
   Поэтому действие подсвечено видом, а не строка целиком: цветные полосы во всю
   ширину превращают таблицу в ковёр, по которому взгляду не за что зацепиться. */
.jrn td { vertical-align: top; }
.jrn__act {
  display: inline-block; padding: 1px 8px; border-radius: var(--r-pill);
  font-size: .8rem; font-weight: 500; white-space: nowrap;
  background: var(--surface-2); color: var(--ink-2);
}
.jrn__act--money { background: var(--go-bg); color: var(--go); }        /* деньги */
.jrn__act--order { background: var(--info-bg); color: var(--info); }    /* заявки */
.jrn__act--shift { background: var(--wait-bg); color: var(--wait); }    /* приход-уход */
.jrn__act--catalog, .jrn__act--staff { background: #eceae2; color: var(--ink-2); }

/* Плитка сотрудника в сводке кликается: это фильтр, а не украшение. */
.stat[data-jwho] { transition: border-color var(--fast), background var(--fast); }
.stat[data-jwho]:hover { border-color: var(--info); background: var(--info-bg); }

/* ═══════════════════ касса ═══════════════════

   У кассира одна работа и очередь живых людей перед ним. Всё, что он делает, — это
   назвать сумму, взять деньги и отдать аппарат, и на экране должно быть ровно это.

   Второй проход (текущий). Первый уже увёл кассу от списка-подписи к крупной сумме
   и кнопкам под палец, но остался в том же визуальном языке, что и очередь
   администратора — карточка на карточке, квадратный номер. Кассе выделен свой
   характер: круглый жетон очереди вместо квадрата (касса выдаёт номерок, а не
   заводит дело), способ оплаты — плитка со своим силуэтом, а не кнопка с подписью,
   и чек оплаты выглядит чеком — с сеченой кромкой над позициями, а не карточкой
   с заголовком. Экономика экрана та же: одна задача на экране, сумма крупнее
   всего остального, сдача считается сама. */

.till { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s4); }

/* Шапка: остаток наличных и поиск. Остаток виден весь день, а не в момент сдачи —
   расхождение ищут по свежим следам. Жетон, а не подпись: это первое число,
   которое кассир называет, если спросят «сколько у тебя». */
.till-bar {
  display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
  padding: var(--s3) var(--s4); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow-1);
}
.till-hero {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 14px 7px 10px; border-radius: var(--r-pill);
  background: var(--go-bg); border: 1px solid var(--go-line); color: var(--go);
}
.till-hero .ic { width: 18px; height: 18px; flex: 0 0 auto; }
.till-hero b { font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 1.1rem; letter-spacing: -.03em; color: var(--ink); }
.till-hero span { font-size: .78rem; color: var(--ink-2); }
.till-hero--wait { background: var(--wait-bg); border-color: var(--wait-line); }
.till-bar input { flex: 1; min-width: 180px; max-width: 320px; }

/* Строка очереди. Кликается целиком и крупно: кассир попадает в неё, не глядя. */
.till-row {
  display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap;
  width: 100%; min-height: 76px; padding: 14px var(--s4); text-align: left;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r); box-shadow: none;
  font: 400 1rem/1.3 var(--sans);
  transition: border-color var(--fast), box-shadow var(--fast);
}
.till-row:hover { background: var(--surface); border-color: var(--go); box-shadow: var(--shadow-1); }
/* Круглый жетон очереди — не квадратная карточка заявки: касса выдаёт номерок,
   не заводит дело. Тот же силуэт, что у настоящего бумажного номерка из аппарата. */
.till-no {
  flex: 0 0 auto; width: 52px; height: 52px; display: grid; place-items: center;
  border-radius: 50%;
  background: var(--go-bg); border: 1.5px solid var(--go-line); color: var(--go);
  font: 700 1.15rem/1 var(--mono); text-align: center; letter-spacing: -.03em;
}
.till-no small { display: none; }
/* У поставщика в жетоне код заявки с ярлыка («GDK-UQU»), а не номер: в одну строку. */
.till-who { min-width: 0; flex: 1 1 200px; }
.till-who b { display: block; font-weight: 600; }
.till-who span { font-size: .85rem; color: var(--ink-2); }
.till-due { margin-left: auto; font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 1.4rem; font-weight: 700; letter-spacing: -.03em; white-space: nowrap; }
.till-row--issue .till-no { background: var(--info-bg); border-color: var(--info-line); color: var(--info); }

/* ─── чек оплаты ───
   Одна оплата — один экран, и сумма на нём одна крупная. Карточка читается как
   лента чека: клиент и аппарат сверху, сумма посередине, сеченая кромка, дальше
   позиции моноширинным столбцом, как в самом чеке, который кассир распечатает
   через минуту. */
.receipt { max-width: 560px; margin: 0 auto; }
.receipt__ticket {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-1); padding: var(--s5) var(--s4) 0; text-align: center;
  overflow: hidden;
}
.receipt__who { font-size: 1.05rem; font-weight: 600; }
.receipt__dev { font-size: .9rem; color: var(--ink-2); margin-top: 2px; }
.receipt__sum {
  display: block; margin: var(--s4) 0 2px; font-family: var(--mono);
  font-size: clamp(2.6rem, 11vw, 3.6rem); font-weight: 700; letter-spacing: -.05em; line-height: 1;
}
.receipt__sub { font-size: .85rem; color: var(--ink-2); }
/* Сеченая кромка чека: пунктир, а не сплошная линия-разделитель — единственная
   деталь, которая говорит «это чек», без рисования зубчиков по краю карточки. */
.receipt__tear {
  margin: var(--s4) 0 0; border-top: 2px dashed var(--line-strong);
}
.receipt__lines { list-style: none; margin: 0; padding: 10px 0 6px; text-align: left; }
.receipt__lines li {
  display: flex; justify-content: space-between; gap: var(--s3);
  padding: 8px var(--s2); font: 400 .92rem/1.3 var(--mono);
}
.receipt__lines b { font-family: var(--mono); font-variant-numeric: tabular-nums; font-weight: 600; }
.receipt__lines .is-off { color: var(--ink-2); }
/* У окна кассы строка чека — ещё и место скидки: «%» у работы, «✕» у скидки.
   Кнопки узкие и стоят после суммы, чтобы суммы оставались одной колонкой. */
.receipt__lines li > span { flex: 1; }
.receipt__lines .pricebtn { min-width: 28px; min-height: 28px; text-align: center;
  color: var(--ink-3); border-bottom: 0; }
.receipt__lines .pricebtn:hover { color: var(--ink); }

/* Способ оплаты — плитка со своим силуэтом, а не кнопка с подписью: кассир бьёт
   по ней взглядом, а не читает. Нажимает сотню раз за смену, глядя на клиента. */
.till-ways { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 8px; }
.till-way {
  min-height: 84px; padding: 12px 8px 10px; border-radius: var(--r);
  background: var(--surface); color: var(--ink); border: 1.5px solid var(--line-strong);
  box-shadow: none; font: 500 .92rem/1.2 var(--sans);
  display: grid; gap: 4px; justify-items: center; align-content: center;
}
.till-way .ic { width: 22px; height: 22px; color: var(--ink-3); }
.till-way small { font-size: .7rem; color: var(--ink-3); font-weight: 400; }
.till-way:hover { background: var(--surface-2); border-color: var(--ink-3); }
.till-way[aria-pressed="true"] {
  background: var(--go-bg); border-color: var(--go); color: var(--go); font-weight: 600;
}
.till-way[aria-pressed="true"] .ic { color: var(--go); }
.till-way[aria-pressed="true"] small { color: var(--go); opacity: .8; }

/* Поле суммы на кассе крупнее обычного поля формы — его читают на бегу и часто
   пальцем, не мышью. */
.till-field input { font-size: 1.3rem; min-height: 56px; }

/* Сдача. Единственная арифметика, которую кассир делает в уме сто раз за смену. */
.change {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3);
  padding: 14px var(--s4); border-radius: var(--r);
  background: var(--wait-bg); border: 1px solid var(--wait-line); color: #6b4705;
}
.change b { font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 1.8rem; font-weight: 600; letter-spacing: -.04em; color: #57390a; }
.change--short { background: var(--stop-bg); border-color: var(--stop-line); color: #8c2216; }
.change--short b { color: var(--stop); }
.change--exact { background: var(--go-bg); border-color: var(--go-line); color: #14503a; }
.change--exact b { color: var(--go); font-size: 1.15rem; }

/* Главное действие экрана: во всю ширину, с суммой прямо на кнопке. */
.till-go { width: 100%; min-height: 60px; border-radius: var(--r); font-size: 1.1rem; font-weight: 600; }
.till-go .num { font-size: 1.2rem; }

/* Второстепенное действие внутри строки кассы (пригласить, квитанция, возврат).
   Отдельная цель под палец, а не подпись: промахнуться отсюда в «отдал телефон»
   стоит дороже, чем лишние восемь пикселей. Базовый вид — нейтральный: красный в
   этой системе значит «необратимо», а приглашение и квитанция таковы не являются.
   Возврат денег помечается модификатором .till-back--danger. */

/* ponytail: правило ниже дублируется в конце файла — там, где оно наконец
   выигрывает у базового .bseg. Здесь оставлено, чтобы не потерять объяснение.
   Пальцем попадают хуже, чем курсором: сегменты подрастают до сорока четырёх точек
   там, где вероятен палец, — на узком экране и на грубом указателе. Это не про
   красоту, это про промахи в чужие деньги. Проверяем оба условия: кассовый терминал
   с тачскрином на широком мониторе прикидывается мышью, а телефон в альбомной
   ориентации — широким экраном. */
@media (pointer: coarse), (max-width: 900px) {
  .bseg button { min-height: 44px; padding-inline: 16px; }
}
/* Касса — рабочее место с очередью людей: здесь палец всегда, на любой ширине. */
.till .bseg button { min-height: 44px; padding-inline: 16px; }

/* ═══════════════════ кабинет супер-админа ═══════════════════

   Супер-админ заходит на минуту и с вопросом, а не на смену и с задачей. Поэтому здесь
   другая плотность, чем у мастера: воздуха больше, крупных чисел ровно по одному на
   экран, а всё, что можно свернуть, свёрнуто до клика. Токены и четыре цвета — общие
   с остальными рабочими местами: цвет не должен менять значение при переходе между
   экранами одной системы.

   Меню было колонкой слева в 208px. Колонка честно решала свою задачу — девять разделов
   разной важности в ряд не помещались, — но платила за это двумя вещами. Во-первых,
   208px ширины на экране, где считают деньги в таблицах на восемь колонок. Во-вторых,
   она врала о глубине: полки раздела («Смены», «Гарантия», «Ведомость») в колонке не
   показывались вовсе, и человек узнавал об их существовании, только зайдя внутрь.

   Стало две строки сверху. Первая — четыре комнаты и шестерёнка, всегда одинаковые.
   Вторая — полки открытой комнаты, всегда видны все пять. Глубина в двух строках
   ровно та, что есть на самом деле, и ни один экран больше не прячется. */

/* Каркас кабинета: меню слева, справа — заголовок экрана с поиском и сам экран.
   Меню показывает всё дерево: семь комнат и полки открытой комнаты прямо под ней.
   Две ленты пилюль сверху прятали вторую ступень — полки появлялись и исчезали, и
   человек не видел, где он и куда ещё можно пойти, не нажав наугад. */
.sadesk {
  display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: 28px; align-items: start;
}
.saroom {
  position: sticky; top: calc(var(--head-h, 66px) + 14px);
  display: flex; flex-direction: column; gap: 2px;
  max-height: calc(100vh - var(--head-h, 66px) - 28px); overflow-y: auto; scrollbar-width: thin;
  padding: 6px 4px 12px 0;
}
.saroom__b {
  display: flex; align-items: center; gap: 11px;
  min-height: 40px; padding: 0 12px;
  border: 0; border-radius: 10px; background: transparent; box-shadow: none;
  color: var(--ink-2); text-decoration: none; white-space: nowrap; text-align: left;
  font: 500 .93rem/1.2 var(--sans); cursor: pointer;
  transition: background var(--fast), color var(--fast);
}
.saroom__b .ic { width: 19px; height: 19px; color: var(--ink-3); flex: none; }
.saroom__b:hover { background: color-mix(in srgb, var(--ink) 5%, transparent); color: var(--ink); }
.saroom__b[aria-current="true"] {
  background: var(--surface); color: var(--ink); font-weight: 600;
  box-shadow: var(--shadow-1), inset 0 0 0 1px var(--line);
}
.saroom__b[aria-current="true"] .ic { color: var(--go); }
.saroom__b:focus-visible, .saroom__segs a:focus-visible { outline: 2px solid var(--go); outline-offset: 1px; }
/* Счётчик — только когда там ждут человека: «0 решений» приучает не читать. */
.saroom__b .count {
  margin-left: auto; min-width: 22px; padding: 1px 7px; border-radius: var(--r-pill);
  background: var(--stop); color: #fff; font: 600 .72rem/1.5 var(--mono); text-align: center;
}
/* Полки открытой комнаты — веткой под ней. Тише комнат: это второй уровень. */
.saroom__segs {
  display: grid; gap: 1px; margin: 4px 0 10px 21px; padding-left: 10px;
  border-left: 1px solid var(--line);
}
.saroom__segs a {
  display: block; padding: 7px 10px; border-radius: 8px;
  color: var(--ink-3); text-decoration: none; font: 500 .88rem/1.25 var(--sans);
  transition: background var(--fast), color var(--fast);
}
.saroom__segs a:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 5%, transparent); }
.saroom__segs a[aria-current="true"] {
  color: var(--go); font-weight: 600; background: color-mix(in srgb, var(--go) 10%, transparent);
}
/* Редкие комнаты — отдельной группой под чертой: «Логи», «Справочник», «Настройки». */
.saroom__extra {
  display: flex; flex-direction: column; gap: 2px;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line);
}
.saroom__more { display: none; }

/* Шапка экрана: где я (раздел и полка крупно) и поиск. Липкая: поиск нужен из
   любой точки длинной таблицы, а не только с её начала. */
.satop {
  position: sticky; top: var(--head-h, 66px); z-index: 6;
  display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap;
  padding: 16px 0 14px; background: var(--canvas); box-shadow: 0 1px 0 var(--line);
}
.satitle { min-width: 0; }
.satitle small {
  display: block; margin-bottom: 2px; color: var(--ink-3);
  font: 500 .8rem/1.2 var(--sans);
}
.satitle small::first-letter { text-transform: uppercase; }
.satitle h1 { margin: 0; font: 650 1.5rem/1.15 var(--sans); letter-spacing: -.025em; color: var(--ink); }
.sasegs { display: none; }
#sa { padding-top: 18px; min-width: 0; }

.safind { position: relative; flex: 0 1 440px; min-width: 220px; margin-left: auto; }
.safind__ic {
  position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
  width: 17px; height: 17px; color: var(--ink-3); pointer-events: none;
}
.safind input {
  width: 100%; min-height: 42px; padding: 0 42px 0 40px;
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--surface); font-size: .93rem; box-shadow: var(--shadow-1);
}
.safind input:focus { border-color: var(--go); outline: 3px solid color-mix(in srgb, var(--go) 18%, transparent); }
.safind input::-webkit-search-cancel-button { display: none; }
.safind__key {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  padding: 1px 6px; border: 1px solid var(--line); border-radius: 5px;
  background: var(--surface-2); color: var(--ink-3);
  font: 500 .72rem/1.5 var(--mono); pointer-events: none;
}
.safind input:focus + .safind__key { display: none; }
.safind__out {
  position: absolute; z-index: 20; top: calc(100% + 6px); left: 0; right: 0;
  max-height: 60vh; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--shadow-2);
}
.safind__r {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; color: var(--ink); text-decoration: none;
  border-bottom: 1px solid var(--line);
}
.safind__r:last-child { border-bottom: 0; }
.safind__r .ic { width: 18px; height: 18px; color: var(--ink-3); flex: none; }
.safind__r b { display: block; font-size: .93rem; font-weight: 600; }
.safind__r em { display: block; font-style: normal; font-size: .8rem; color: var(--ink-3); }
.safind__r:hover, .safind__r[aria-selected="true"] { background: var(--surface-2); }
.safind__none { margin: 0; padding: 14px 12px; color: var(--ink-3); font-size: .88rem; }

@media (max-width: 1100px) {
  .sadesk { grid-template-columns: 200px minmax(0, 1fr); gap: 20px; }
}

/* Колонка-меню. Кабинет супер-админа с неё ушёл (см. .sash выше), но у бухгалтерии
   кассира разделов всего два, и колонка им подходит: ей нечего прятать. */
.bwrap { display: grid; grid-template-columns: 208px minmax(0, 1fr); gap: var(--s5); align-items: start; }
.bnav {
  position: sticky; top: calc(var(--head-h, 66px) + var(--s3));
  display: grid; gap: 2px; align-content: start;
}
.bnav button {
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: 44px; padding: 9px 12px;
  background: transparent; color: var(--ink-2); border: 1px solid transparent;
  border-radius: var(--r); box-shadow: none;
  font: 500 .93rem/1.2 var(--sans); text-align: left;
  transition: background var(--fast), color var(--fast);
}
.bnav button .ic { width: 18px; height: 18px; color: var(--ink-3); }
.bnav button:hover { background: var(--surface); color: var(--ink); }
.bnav button:hover .ic { color: var(--ink-2); }
.bnav button[aria-current="true"] {
  background: var(--surface); color: var(--ink); font-weight: 600;
  border-color: var(--line); box-shadow: var(--shadow-1);
}
.bnav button[aria-current="true"] .ic { color: var(--go); }

@media (max-width: 900px) {
  /* minmax(0, 1fr), не голый 1fr: у голого нет верхней защиты от содержимого —
     широкая таблица раздувает саму колонку сетки шире экрана. */
  .bwrap { grid-template-columns: minmax(0, 1fr); gap: var(--s4); }
  .bnav {
    position: sticky; top: var(--head-h, 66px); z-index: 5;
    grid-auto-flow: column; grid-auto-columns: max-content;
    gap: 4px; overflow-x: auto; scrollbar-width: none;
    margin: 0 calc(var(--s4) * -1); padding: var(--s2) var(--s4);
    background: var(--canvas); box-shadow: 0 1px 0 var(--line);
  }
  .bnav::-webkit-scrollbar { display: none; }
  .bnav button { min-height: 44px; white-space: nowrap; }
}

/* Секция — карточка с заголовком. Раньше это был h3 и таблица встык под ним:
   на экране из семи таблиц подряд глазу не за что зацепиться, где кончается одно
   и начинается следующее. */
.bsec { margin-bottom: var(--s4); }
.bsec__head {
  display: flex; align-items: baseline; gap: var(--s3); flex-wrap: wrap;
  margin: 0 0 var(--s3);
}
.bsec__head h3 { margin: 0; font-size: 1rem; }
.bsec__head p { margin: 0; }
.bsec__head .spacer { margin-left: auto; }
/* Свёрнутый раздел: заголовок читается так же, как у обычного, но содержимое ждёт
   нажатия. Полок в кабинете стало меньше, а разделов внутри полки — по шесть-семь
   в одну колонку; всё, что отвечает на второй вопрос полки, уходит под заголовок. */
.bsec--fold > summary {
  list-style: none; cursor: pointer; display: flex; align-items: baseline;
  gap: var(--s3); flex-wrap: wrap; margin: 0 0 var(--s3);
}
.bsec--fold > summary::-webkit-details-marker { display: none; }
.bsec--fold > summary h3 { margin: 0; font-size: 1rem; }
.bsec--fold > summary h3::before { content: '\25B8  '; color: var(--ink-3); font-weight: 400; }
.bsec--fold[open] > summary h3::before { content: '\25BE  '; }
.bsec--fold > summary .hint { margin: 0; }

.bsec__body {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-1); overflow: hidden;
}
.bsec__body > p, .bsec__body > .bpad { padding: var(--s4); margin: 0; }
.bsec__body > table th:first-child, .bsec__body > table td:first-child { padding-left: var(--s4); }
.bsec__body > table th:last-child, .bsec__body > table td:last-child { padding-right: var(--s4); }
.bsec__body > table tr:last-child td { border-bottom: 0; }
.bsec__body .empty { border: 0; margin: 0; background: transparent; }

/* Разворачивается по клику: подробности существуют, но не занимают экран, пока их
   не спросили. Супер-админ сначала смотрит итог и лезет внутрь, только если он странный. */
.bmore > summary {
  list-style: none; cursor: pointer; padding: var(--s3) var(--s4);
  font-size: .88rem; color: var(--ink-2); border-top: 1px solid var(--line);
  transition: background var(--fast), color var(--fast);
}
.bmore > summary::-webkit-details-marker { display: none; }
.bmore > summary::before { content: '\25B8  '; color: var(--ink-3); }
.bmore[open] > summary::before { content: '\25BE  '; }
.bmore > summary:hover { background: var(--surface-2); color: var(--ink); }
.bmore > summary:focus-visible { outline: 2px solid var(--go); outline-offset: -2px; }

/* Числа моноширинные и по правому краю. Иначе колонка сумм пляшет по ширине,
   и «1 200» с «980» нельзя сравнить взглядом — только вычитанием. */
.num { font-family: var(--mono); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
td.num, th.num { text-align: right; white-space: nowrap; }
td.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* Полоса «требует вас». Пустого состояния у неё нет: вместо «0 решений»
   её просто нет на экране. */
.balert { display: grid; gap: 8px; margin-bottom: var(--s4); }
.balert__i {
  display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
  padding: 12px var(--s4); border-radius: var(--r);
  border: 1px solid var(--wait-line); background: var(--wait-bg); color: #6b4705;
  font-size: .92rem;
}
.balert__i b { color: #57390a; }
.balert__i .spacer { margin-left: auto; }
.balert__i .ic { width: 18px; height: 18px; color: var(--wait); }
/* Текст рядом со значком, а не строкой ниже; ссылки-фильтры внутри — строкой текста,
   без телефонной высоты кнопки (она растягивала полосу на пол-экрана). */
.balert__i > .ic { flex: none; }
.balert__i > .ic + span { flex: 1 1 0; min-width: 0; }
.balert__i .linkish { min-height: 0; }
.balert__i--stop { border-color: var(--stop-line); background: var(--stop-bg); color: #8c2216; }
.balert__i--stop b { color: #6f1b12; }
.balert__i--stop .ic { color: var(--stop); }
.balert__i--go { border-color: var(--go-line); background: var(--go-bg); color: #14503a; }
.balert__i--go b { color: #0f3d2c; }
.balert__i--go .ic { color: var(--go); }

/* Воронка дня. Шесть одинаковых плиток со счётчиками не показывали главного —
   где встало. Здесь этапы стоят по порядку движения заявки, и затор виден местом. */
.bfunnel { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: var(--s4); }
.bfunnel__i {
  flex: 1 1 108px; padding: 12px 14px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
}
.bfunnel__i b { display: block; font: 600 1.5rem/1.1 var(--mono); letter-spacing: -.04em; }
.bfunnel__i span { font-size: .78rem; color: var(--ink-2); }
.bfunnel__i.is-hot { border-color: var(--wait-line); background: var(--wait-bg); }
.bfunnel__i.is-hot b { color: var(--wait); }

/* Отчёт о прибыли читается фразой сверху вниз, а не набором плиток.
   Строка расхода разворачивается в то, из чего сложилась. */
.bpl { list-style: none; margin: 0; padding: 0; }
.bpl li {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3);
  padding: 9px var(--s4); border-bottom: 1px solid var(--line);
}
.bpl li:last-child { border-bottom: 0; }
.bpl b { font-family: var(--mono); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.bpl .is-sub { padding-left: calc(var(--s4) + 18px); font-size: .88rem; color: var(--ink-2); }
.bpl .is-sub b { font-weight: 400; }
.bpl .is-head { font-weight: 600; }
.bpl .is-out b { color: var(--stop); }
.bpl .is-total {
  padding-top: var(--s3); padding-bottom: var(--s3);
  border-top: 2px solid var(--line-strong); font-weight: 600; font-size: 1.05rem;
}
.bpl .is-total b { font-size: 1.3rem; color: var(--go); }
.bpl .is-total.is-neg b { color: var(--stop); }
/* «Есть сейчас» читается наоборот, чем отчёт о прибыли: сначала ответ, под ним —
   где он лежит. Поэтому итог стоит первой строкой и отделён снизу, а не сверху. */
.bpl .is-sum { border-bottom: 2px solid var(--line-strong); font-weight: 600; font-size: 1.05rem; }
.bpl .is-sum b { font-size: 1.5rem; }

/* ─────────── графики ───────────
   Стоят над таблицей, а не вместо неё: форма отвечает «нормально ли это»,
   цифры под ней — «сколько именно». Цветом ничего не кодируется: в системе он занят
   четырьмя значениями, и пятое — «просто столбик» — сломало бы остальные четыре.
   Величину несёт длина, и только она. */
.chart { padding: var(--s4); border-bottom: 1px solid var(--line); }
.bsec__body > .chart:last-child { border-bottom: 0; }

/* Столбики. Сетка в четыре колонки: имя, полоса, число, доля — числа выстраиваются
   в столбец и сравниваются взглядом, как в таблице, потому что это и есть таблица. */
.chart--bars { display: grid; gap: 9px; }
.chart__row {
  display: grid;
  grid-template-columns: minmax(80px, 150px) minmax(60px, 1fr) auto 40px;
  gap: var(--s3);
  align-items: center;
}
/* Доля от суммы имеет смысл только там, где сумма что-то значит: у расходов имеет,
   у среднего времени ремонта — нет, «эта работа занимает 14% всего времени» не вопрос. */
.chart--noshare .chart__row { grid-template-columns: minmax(80px, 150px) minmax(60px, 1fr) auto; }
.chart__name {
  font-size: var(--fs-floor);
  color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chart__track { height: 22px; border-radius: var(--r-sm); background: var(--surface-2); overflow: hidden; }
/* Полоса не анимируется. Рост от нуля через scaleX выглядит нарядно ровно до первого
   случая, когда кадры не пошли — свёрнутая вкладка, второй монитор, слабый планшет за
   стойкой: fill-mode оставляет её в начальном состоянии, и супер-админ видит отчёт,
   где все расходы равны нулю. Раздел и так въезжает целиком (.bfade); платить за второе
   движение риском показать пустой график там, где считают деньги, нечем. */
.chart__track i {
  display: block; height: 100%;
  border-radius: inherit;
  background: var(--info);
}
.chart__track i.is-neg { background: var(--stop); }
.chart__val { font-size: var(--fs-small); font-weight: 600; text-align: right; white-space: nowrap; }
.chart__val span { color: var(--ink-3); font-weight: 400; }
.chart__share { font-size: var(--fs-floor); color: var(--ink-3); text-align: right; }

/* Линия по дням. Область под ней бледная: она показывает объём, но спорить с линией
   за внимание не должна — читают всё-таки линию. */
.chart--trend svg { display: block; width: 100%; height: 150px; }
.chart__area { fill: var(--info-bg); stroke: none; }
.chart__line {
  fill: none; stroke: var(--info); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round;
  /* preserveAspectRatio="none" растягивает и обводку тоже — здесь она задана
     в пользовательских единицах, поэтому по горизонтали её тянет. Это осознанно:
     вариант с честной геометрией требует пересчёта на resize, то есть JS на каждый кадр. */
  vector-effect: non-scaling-stroke;
}
.chart__zero { stroke: var(--line-strong); stroke-width: 1; stroke-dasharray: 3 3; vector-effect: non-scaling-stroke; }
.chart__axis {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--s3);
  margin-top: 8px; font-size: var(--fs-floor); color: var(--ink-3);
}
.chart__axis b { color: var(--ink-2); font-weight: 600; }

@media (max-width: 640px) {
  /* На телефоне подпись встаёт над полосой, а не рядом. В строку из четырёх колонок
     полосе оставалось сто двадцать точек из трёхсот семидесяти — сравнивать длины на
     таком отрезке нельзя, то есть график переставал быть графиком. Доля уходит совсем:
     она и так читается по самой полосе. */
  .chart--bars { gap: var(--s3); }
  .chart__row {
    grid-template-columns: 1fr auto;
    grid-template-areas: 'name val' 'track track';
    gap: 4px var(--s2);
  }
  .chart__name { grid-area: name; }
  .chart__val { grid-area: val; }
  .chart__track { grid-area: track; height: 16px; }
  .chart__share { display: none; }
}

/* Широкая таблица прокручивается внутри своей карточки, а не тянет за собой страницу.
   Отчёты супер-админа доходят до восьми числовых колонок, и на планшете мастера
   такая таблица раньше выдавливала горизонтальную прокрутку всему экрану. */
.bsec__body { overflow-x: auto; }
.bsec__body > table { min-width: max-content; }

/* Таблица вариантов детали в справочнике — фиксированные пять колонок,
   не растёт вширь ни при каком числе вариантов, но подстрахована тем же приёмом. */
.tbl-wrap { overflow-x: auto; }
.tbl-wrap > table { min-width: max-content; }

/* Подстраховка по умолчанию: голая <table> без .tbl-wrap/.bsec__body раньше
   так же выдавливала горизонтальную прокрутку всего экрана — таких в отчётах
   супер-админа десятки. Скроллится сама, колонки внутри не ломаются: table
   остаётся table для дочерних tr/td, наружу отдаёт себя как block. */
table { display: block; overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }
.tbl-wrap > table, .bsec__body > table { display: table; overflow-x: visible; max-width: none; }

/* ─────────── таблица цен справочника ───────────
   Вариант детали здесь — строка внутри работы, не колонка: раньше три поля на каждый
   вариант растили таблицу вширь, и с тремя вариантами она уже не помещалась в рабочую
   колонку. Ширина больше не зависит от того, сколько вариантов заведено — растёт
   высота, а с высотой справляется обычная прокрутка страницы. rowspan держит общие
   для работы поля в одной ячейке на группу, чтобы их не повторять на каждый вариант.

   Зебра — по группе, а не по строке: с общей ячейкой слева ряды одной работы и так
   стоят вместе, но глазу нужна метка, где заканчивается одна работа и начинается
   следующая, особенно когда группы соседствуют без явной границы между вариантами. */
/* Ширина — по классу, не по nth-child: у rowspan-ячейки нет пары в строках
   второго и третьего варианта детали внутри той же работы, и без неё счёт
   позиции в строке съезжает на одну ячейку. Классу всё равно, какая по счёту
   ячейка перед ним — он привязан к роли колонки, а не к её месту в разметке.
   table-layout: fixed здесь не подходит по той же причине: он тоже считает
   позиции, а не роли, и наравне с nth-child путает вариант со следующей
   колонкой в строках без общей ячейки слева. */
/* У заголовков в остальной системе — nowrap: там подпись короче поля под ней.
   Здесь наоборот: «Гарантия, дней» и подсказка в «Плитке» длиннее заданной ширины
   колонки, и без переноса ячейка требует место под одну строку целиком, игнорируя
   width — в auto-layout ширина только подсказка, содержимое может её раздвинуть. */
.catbl th { white-space: normal; }
/* width один не держит потолок: авторазметка таблицы всё равно раздаёт свободное
   место туда, где у содержимого большой запас между «переносится» и «в одну строку»
   — а у «Плитки» с длинной подсказкой в заголовке этот запас самый большой на всей
   таблице. max-width делает то же число потолком, а не пожеланием. */
.catbl__work { width: 200px; max-width: 200px; }
/* Узел и название — разные строки, не соседи в один ряд: .vcell — общий строчный
   флекс, а здесь при 200px он сминал название рядом со значком и селектом узла. */
.catbl__work .vcell { flex-direction: column; align-items: flex-start; gap: 4px; }
.catbl__variant { width: 88px; max-width: 88px; }
.catbl__num { width: 80px; max-width: 80px; }
.catbl__onsite, .catbl__active { width: 68px; max-width: 68px; }
.catbl__plitka { width: 165px; max-width: 165px; }
.catbl__save { width: 96px; max-width: 96px; }
.catbl input[type="number"] { width: 100%; min-width: 0; }
.catbl .vcell input:not([type]) { width: 130px; }
.catbl__work .vcell input[data-name] { width: 100%; }
/* Каждая колонка — фиксированная роль что в шапке, что в теле: класс одинаковый
   у th и у td, поэтому ширина не гуляет от того, сколько случайно осталось
   после соседей, и не раздувается на широком мониторе без причины. */
.catbl__grp:nth-of-type(even) { background: var(--surface-2); }
.catbl__grp:nth-of-type(even) tr:hover td { background: var(--surface); }

/* Колонка выделения — самая узкая в таблице: в ней один квадрат, и отдавать ей
   место наравне с ценой незачем. */
.catbl__pick { width: 34px; max-width: 34px; text-align: center; }

/* Выключенная работа теперь видна в списке — иначе включить её было бы негде.
   Видна приглушённой: в справочнике она есть, в работе её нет, и путать эти
   два состояния нельзя. Поля при этом остаются рабочими — правят как раз перед
   тем, как включить обратно. */
.catbl__grp--off .catbl__work { opacity: .55; }

/* ── Прайс: матрица модели × работы ──────────────────────────────────────────
   Та же раскладка, что в книге Excel, и закреплено то же самое: шапка и первая
   колонка. Без этого при прокрутке вправо непонятно, чья это строка, а вниз —
   что за колонка. Прокрутка живёт внутри .tbl-wrap, страница вбок не едет. */
.mxbar { gap: 8px; margin-bottom: 10px; }
.mx-wrap { max-height: 70vh; }
.mx { border-collapse: separate; border-spacing: 0; font-variant-numeric: tabular-nums; }
.mx th, .mx td { border-bottom: 1px solid var(--line); border-right: 1px solid var(--line);
  padding: 4px 8px; white-space: nowrap; }
.mx thead th { position: sticky; top: 0; z-index: 2; background: var(--surface-2);
  font-size: .8rem; font-weight: 600; }
.mx thead tr:nth-child(2) th { top: 28px; }
.mx__w { text-align: center; }
.mx__v { font-weight: 400; color: var(--ink-2); }
/* Первая колонка закреплена и шире прочих: в ней имя модели, галочка и счётчик. */
.mx__row { position: sticky; left: 0; z-index: 3; background: var(--surface);
  text-align: left; font-weight: 500; min-width: 180px; }
.mx thead .mx__row { z-index: 4; background: var(--surface-2); }
.mx__row .chk { gap: 6px; margin: 0; align-items: baseline; }
.mx__row .hint { display: block; font-size: .75rem; }
.mx__c { min-width: 74px; text-align: right; }
.mx__c[contenteditable] { cursor: cell; }
.mx__c[contenteditable]:focus { outline: 2px solid var(--go); outline-offset: -2px; background: var(--surface); }
/* Базовая строка — первая в сетке: «базовые цены» перестали быть отдельным экраном. */
/* Своей цены нет — клетка приглушена: видно, где линейка живёт на базовой. */
/* Клетка без цены: работа по этому аппарату не предлагается. Фон, а не цвет текста —
   текста в ней теперь нет вовсе, красить было бы нечего. */
.mx__c.is-noprice { background: repeating-linear-gradient(135deg,
  transparent 0 6px, var(--surface-2) 6px 12px); }
/* «Не ставим» — не пустая цена, и путать их нельзя. */
.mx__c.is-no { color: var(--ink-3); font-style: italic; }
/* Изменено, но не сохранено. Жёлтым, пока не уедет одним сохранением. */
.mx__c.is-dirty { background: #fff4cc; }
.mx__off .mx__row { opacity: .55; }

/* Цена на плитке разбора — отдельная цель внутри плитки: по ней правят справочник,
   не выбирая саму работу. Пунктир говорит «это можно менять», не крича об этом. */
.tile__price[data-tileprice] { cursor: pointer;
  border-bottom: 1px dashed var(--line-strong); }
.tile__price[data-tileprice]:hover { border-bottom-style: solid; }

/* Цена записанной работы — кнопка, но в строке она должна читаться как цена, а не как
   ещё одна кнопка среди прочих: подчёркивание пунктиром говорит «это можно менять»,
   не крича об этом. Строку работы читают в первую очередь глазами клиента напротив. */
.pricebtn { font: inherit; color: inherit; background: none; border: 0; padding: 0;
  border-bottom: 1px dashed var(--line-strong, var(--ink-3)); border-radius: 0;
  cursor: pointer; box-shadow: none; }
.pricebtn:hover { border-bottom-style: solid; }

/* Окно цены. Узкое: в нём одно поле ввода и один выбор, а всё остальное — то,
   что человек читает, прежде чем назвать число.

   Селектор с .modal нарочно: у «.modal .card» ширина задана двумя классами, и одиночный
   класс окна её не перебивает (ровно поэтому «.qrask { max-width: 460px }» выше ничего
   не делает). Высота ограничена и содержимое прокручивается внутри: на телефоне это
   окно с тремя вариантами, фактом закупки и двумя полями выше экрана, а модалка
   прижата к верху и низ просто уезжал бы за край. */
.modal .askprice { max-width: 460px; max-height: 76vh; overflow: auto; }
.askprice__vars { display: grid; gap: 4px; margin-bottom: 12px; }
.askprice__vars .chk { align-items: flex-start; }
.askprice__sum { max-width: 200px; }
.askprice__fact { margin: 10px 0 14px; padding: 10px 12px;
  background: var(--surface-2); border-radius: var(--r-sm, 8px); }
.askprice__fact:empty { display: none; }
.askprice__head { margin: 0 0 2px; font-size: .85rem; color: var(--ink-2); }
.askprice__avg { margin: 0 0 4px; }
.askprice__fact .hint { margin: 2px 0 0; }
.askprice__keep { margin-bottom: 12px; align-items: flex-start; }
.askprice__act { margin-top: 4px; }

/* Окно скидки. Строится на окне цены: те же поля и ритм, плюс выбор строки и быстрые
   проценты. Строка под ценой окрашивается заранее: зелёная — хватит своего QR-кода,
   жёлтая — понадобится супер-админ. Человек знает это до нажатия, а не по окну
   сканирования. */
.disc__targets { border: 0; padding: 0; margin: 0 0 12px; }
.disc__target { display: grid; grid-template-columns: auto 1fr auto; gap: 8px;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--r-sm); }
.disc__target:has(input:checked) { border-color: var(--go-line); background: var(--go-bg); }
.disc__tsum { font-family: var(--mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
.disc__quick { display: flex; flex-wrap: wrap; gap: 6px; margin: -4px 0 10px; }
.disc__chip { font: inherit; font-size: .82rem; font-weight: 500; line-height: 1; padding: 7px 10px; min-height: 32px;
  background: var(--surface-2); color: var(--ink-2); border: 1px solid var(--line);
  border-radius: var(--r-pill); box-shadow: none; cursor: pointer; }
.disc__chip:hover { color: var(--ink); border-color: var(--line-strong); }
.disc__live { margin: 0 0 12px; padding: 8px 10px; border-radius: var(--r-sm);
  font-size: .9rem; background: var(--surface-2); color: var(--ink-2); }
.disc__live:empty { display: none; }
.disc__live--own { background: var(--go-bg); color: var(--go); }
.disc__live--boss { background: var(--wait-bg); color: var(--wait); }

/* Полоса массового действия. Липкая к низу: строки выделяют, прокручивая список,
   и кнопка должна оказаться там же, где палец, а не там, где список кончился. */
.bulkbar { position: sticky; bottom: 0; z-index: 3;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin-top: 12px; padding: 10px 12px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--shadow-2); }
.bulkbar b { white-space: nowrap; }

/* Скрытый пункт дерева: зачёркнут, но читаем — по нему ещё нужно попасть пальцем,
   чтобы вернуть. */
.mnode--off .mnode__label b { opacity: .55; text-decoration: line-through; }

/* Переключатель периода: один на весь раздел «Деньги». Раньше период жил только
   в «Финансах» и сбрасывался при уходе на соседнюю вкладку. */
.bseg { display: flex; gap: 2px; padding: 3px; border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--line); min-width: 0;
  overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
.bseg::-webkit-scrollbar { display: none; }
.bseg button {
  background: transparent; color: var(--ink-2); border: 0; box-shadow: none;
  min-height: 34px; padding: 5px 13px; border-radius: var(--r-pill);
  font: 500 .85rem/1.2 var(--sans); flex-shrink: 0; white-space: nowrap;
}
.bseg button:hover { background: var(--surface); color: var(--ink); }
.bseg button[aria-current="true"] {
  background: var(--surface); color: var(--ink); font-weight: 600; box-shadow: var(--shadow-1);
}

/* Строка человека кликается целиком: имя, деньги и состояние — один объект,
   и попадать надо в него, а не в шестипиксельную ссылку внутри. */
.bpeople { display: grid; gap: 6px; }
.bperson {
  display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
  width: 100%; min-height: 60px; padding: 11px var(--s4); text-align: left;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r); box-shadow: none;
  font: 400 .95rem/1.3 var(--sans);
  transition: border-color var(--fast), box-shadow var(--fast);
}
.bperson:hover { background: var(--surface); border-color: var(--ink-3); box-shadow: var(--shadow-1); }
.bperson__name { font-weight: 600; }
.bperson__meta { font-size: .82rem; color: var(--ink-2); }
.bperson__sum { margin-left: auto; text-align: right; }
.bperson__sum b { display: block; font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 1.05rem; letter-spacing: -.02em; }
.bperson__sum span { font-size: .74rem; color: var(--ink-2); }
.bperson--off { opacity: .55; }
.bperson__sum.is-debt b { color: var(--stop); }
.bperson__sum.is-clear b { color: var(--ink-3); font-weight: 400; }

/* Карточка человека: деньги сверху и крупно — это первое, зачем сюда заходят. */
.bmoney {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--s5);
  padding: var(--s5); margin-bottom: var(--s4);
  border-radius: var(--r-lg); background: var(--surface);
  border: 1px solid var(--line); box-shadow: var(--shadow-1);
}
.bmoney__main { min-width: 180px; }
.bmoney__label { display: block; font-size: .78rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3); }
.bmoney__sum { display: block; margin-top: 4px; font-family: var(--mono);
  font-size: clamp(1.8rem, 4vw, 2.4rem); font-weight: 600; letter-spacing: -.04em; line-height: 1; }
.bmoney__sum.is-debt { color: var(--stop); }
.bmoney__sum.is-clear { color: var(--ink-3); }
.bmoney__note { display: block; margin-top: 6px; font-size: .85rem; color: var(--ink-2); }
.bmoney__side { display: flex; gap: var(--s5); flex-wrap: wrap; }
.bmoney__side div { min-width: 90px; }
.bmoney__side b { display: block; font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 1.15rem; letter-spacing: -.03em; }
.bmoney__side span { font-size: .76rem; color: var(--ink-2); }
.bmoney__act { display: flex; gap: 8px; flex-wrap: wrap; margin-left: auto; align-self: center; }

/* Появление раздела: движение объясняет смену содержимого, поэтому оно есть,
   и оно короткое, поэтому не мешает. */
/* backwards, а не both: застывший после анимации transform делает раздел опорой для
   position:fixed, и выпадающее меню («⋯» в заявке) считало координаты от раздела,
   а не от окна — панель уезжала за правый край экрана, и меню «не открывалось». */
.bfade { animation: bfade 200ms cubic-bezier(.2, .7, .3, 1) backwards; }
@keyframes bfade { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .bfade { animation: none; } }

/* ═══════════════ рабочее место администратора: очередь и поиск ═══════════════

   Экран отвечает на два разных вопроса, и раньше они были свалены в одну строку.
   Первый — «что горит прямо сейчас»: на него отвечают счётчики и ленты. Второй —
   «что с телефоном вот этого человека»: на него отвечает поиск, и он не должен
   выглядеть как ещё одно поле в ряду кнопок, потому что за ним стоит живой клиент. */

.admbar {
  display: grid;
  grid-template-columns: minmax(260px, 460px) 1fr;
  gap: var(--s4) var(--s5);
  align-items: end;
  margin-bottom: var(--s5);
  padding-bottom: var(--s4);
  border-bottom: 1px solid var(--line);
}
.admbar h1 { font-size: 1.5rem; line-height: 1.15; margin: 0 0 2px; letter-spacing: -.02em; }
.admbar__find { min-width: 0; }
.admbar__find input { width: 100%; }
/* Подсказка под полем, а не плейсхолдером внутри: плейсхолдер исчезает ровно тогда,
   когда человек начал печатать, то есть когда подсказка и нужна.
   Ниже 13 точек текст за стойкой читают под углом и с метра — то есть не читают. */
.admbar__find .hint { margin: 4px 0 0; font-size: var(--fs-floor); }
.admbar__act { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; align-self: end; }

/* Счётчик — кнопка к своей ленте, а не табло. Выглядит как раньше, но нажимается,
   и это видно до нажатия: курсор, подсветка и рамка выбранного. */
/* Только button.stat: те же счётчики стоят табло у кассира и у супер-админа, и курсор-палец
   над тем, что не нажимается, — обещание, которого экран не выполнит. */
button.stat {
  display: block;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  min-height: 0;
  box-shadow: none;
  transition: border-color var(--fast), box-shadow var(--fast), transform var(--fast);
}
button.stat:hover { background: var(--surface); border-color: var(--line-strong); box-shadow: var(--shadow-1); }
button.stat.alert:hover { background: var(--stop-bg); }
button.stat.go:hover { background: var(--go-bg); }
button.stat.wait:hover { background: var(--wait-bg); }
button.stat:active { transform: translateY(1px); }
button.stat.is-on { border-color: var(--ink-3); box-shadow: inset 0 -3px 0 var(--go); }

/* ─────────── результат поиска ───────────
   Не строка очереди, а ответ вслух: где аппарат, что сделано, когда будет.
   Порядок сверху вниз — порядок, в котором это произносят клиенту. */
.founds { display: grid; gap: var(--s4); margin-bottom: var(--s4); }
.found {
  padding: var(--s4) var(--s5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-1);
  cursor: pointer;
  transition: border-color var(--fast), box-shadow var(--fast);
}
.found:hover { border-color: var(--line-strong); box-shadow: var(--shadow-2); }
.found__top { display: flex; gap: var(--s4); align-items: flex-start; flex-wrap: wrap; }
.found__code { flex: 0 0 auto; }
.found__code b {
  display: block; font-family: var(--mono); font-size: 1.35rem;
  letter-spacing: .06em; line-height: 1.1;
}
.found__code small { display: block; font-size: .72rem; color: var(--ink-3); margin-top: 2px; }
.found__who { min-width: 0; flex: 1 1 220px; }
.found__who h3 { margin: 0; font-size: 1.05rem; }
.found__who p { margin: 2px 0 0; font-size: .85rem; color: var(--ink-2); }
.found__who a { color: inherit; }
.found__flags { display: flex; gap: 6px; flex-wrap: wrap; margin-left: auto; }
.found .flow { margin: var(--s4) 0 var(--s3); }
.found__did { margin: 0 0 6px; font-size: .88rem; }
.found__act { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: var(--s3); }
.found__act .sum { font-family: var(--mono); font-size: 1.05rem; font-weight: 600; }

/* Факты парами «вопрос — ответ». Таблица здесь была бы честнее по разметке, но
   четыре строки по два слова читаются хуже, чем четыре колонки. */
.facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--s3) var(--s4); margin: 0 0 var(--s3);
  padding: var(--s3) 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.facts div { min-width: 0; }
.facts dt { font-size: .72rem; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); }
.facts dd { margin: 2px 0 0; font-size: .92rem; font-weight: 500; }

@media (max-width: 900px) {
  .admbar { grid-template-columns: 1fr; align-items: stretch; }
  .admbar__act { justify-content: flex-start; }
  .found { padding: var(--s4); }
  .found__flags { margin-left: 0; }
}

/* Длинный чекбокс: право с объяснением, зачем оно и чем платится. Обычный .chk —
   строка в одну фразу, и переносить в нём абзац некуда. */
label.chk--long { display: flex; width: 100%; align-items: flex-start; margin-bottom: 8px; }
label.chk--long input { margin-top: 3px; flex: 0 0 auto; }
label.chk--long span { line-height: 1.45; color: var(--ink-2); }
label.chk--long span b { color: var(--ink); }

/* Выбор файла выглядит кнопкой: настоящий input[type=file] показывает «Файл не выбран»
   и подпись на языке системы, а не на языке экрана. */
.filebtn {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 40px; padding: 9px 16px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  font-size: .92rem; font-weight: 500; cursor: pointer;
  transition: background var(--fast), border-color var(--fast);
}
.filebtn:hover { background: var(--surface-2); border-color: var(--ink-3); }
.filebtn:focus-within { outline: 2px solid var(--info); outline-offset: 2px; }

/* ═══════════════ очередь администратора: пять зон и один механизм ═══════════════

   Между шапкой и первой рабочей строкой было семь элементов: шесть счётчиков,
   строка смены карточкой, две красные полосы и ряд вкладок — три механизма
   навигации по одним и тем же лентам. Осталось три: поиск, строка смены,
   сегменты. Дальше сразу работа. */

/* Строка смены — статус, а не предупреждение: она меняется дважды в день, и рамка
   с фоном ради этого факта кричала громче просроченных заявок. */
.shiftline { margin: 0 0 var(--s4); font-size: .88rem; color: var(--ink-2); }
.shiftline > summary {
  display: flex; align-items: center; gap: 8px;
  min-height: 32px; padding: 4px 2px;
  cursor: pointer; list-style: none;
}
.shiftline > summary::-webkit-details-marker { display: none; }
/* Точка слева несёт состояние, слово рядом несёт смысл — цвет никогда не один. */
.shiftline > summary::before {
  content: ''; flex: 0 0 auto; width: 8px; height: 8px;
  border-radius: 50%; background: var(--line-strong);
}
.shiftline--wait > summary::before { background: var(--wait); }
.shiftline > summary::after {
  content: '▾'; color: var(--ink-3); font-size: .8rem;
  transition: transform var(--fast);
}
.shiftline[open] > summary::after { transform: rotate(180deg); }
.shiftline > summary:hover { color: var(--ink); }
.shiftline > summary:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; border-radius: var(--r-sm); }
.shiftline ul { margin: 4px 0 0; padding: 0 0 0 16px; list-style: none; display: grid; gap: 2px; }
.shiftline__act { display: inline-flex; flex-wrap: wrap; gap: 4px; margin-left: 8px; vertical-align: middle; }
.shiftline__act button { min-height: 32px; padding: 2px 10px; font-size: .82rem; }
.shiftline li { font-size: .85rem; }
.shiftline b { color: var(--ink); font-weight: 600; }

/* Сегменты — единственная навигация экрана. Подчёркивание, а не таблетка: шесть
   таблеток в ряд читаются как шесть кнопок, а это одна кнопка с шестью положениями. */
.segs {
  display: flex; gap: 2px; margin: 0 0 var(--s4);
  border-bottom: 1px solid var(--line-strong);
  overflow-x: auto; scrollbar-width: none;
}
.segs::-webkit-scrollbar { display: none; }
.segs button {
  display: flex; align-items: center; gap: 7px; white-space: nowrap;
  background: transparent; color: var(--ink-2); box-shadow: none;
  border: 0; border-bottom: 2px solid transparent; border-radius: 0;
  min-height: 44px; padding: 8px 14px;
  font: 500 .93rem/1.2 var(--sans);
}
.segs button:hover { background: transparent; color: var(--ink); }
.segs button[aria-selected="true"] {
  color: var(--ink); font-weight: 600; border-bottom-color: var(--go);
}
.segs button:focus-visible { outline: 2px solid var(--info); outline-offset: -2px; }
.segs .count {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: .78rem; font-weight: 600; line-height: 1;
  padding: 3px 7px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink-2); border: 1px solid var(--line);
}
.segs button[aria-selected="true"] .count { background: var(--go); border-color: var(--go); color: #fff; }
/* Полка — единственный счётчик, который значит «что-то пошло не так», но не «человек
   ждёт прямо сейчас»: забытый аппарат это тишина, а не срочность. Поэтому жёлтый. */
.segs button[data-seg="shelf"] .count:not(:empty) {
  background: var(--wait-bg); border-color: var(--wait-line); color: var(--wait);
}
.segs button[data-seg="shelf"][aria-selected="true"] .count {
  background: var(--wait); border-color: var(--wait); color: #fff;
}

.shelfbar { align-items: center; margin-bottom: var(--s3); }

/* ─────────── строка заявки: пять зон, фиксированных ───────────
   Номер · аппарат с клиентом · почему она здесь · одно число времени · один шаг.
   Раньше в этой строке помещалось до девяти меток, и читать её было нечем. */
.task--q {
  grid-template-columns: 3.4rem minmax(0, 1fr) minmax(0, 21ch) 6.5rem auto;
  gap: var(--s3);
}
/* Одна строка с обрезкой: описание со слов клиента бывает в три предложения,
   и тогда оно раздвигало строку вдвое, а читали всё равно первые пять слов. */
.task__said {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Причина: одна фраза, объясняющая, почему строка здесь и что с ней делать.
   Она заменила россыпь чипов и поэтому читается как текст, а не как метка. */
.task__why {
  min-width: 0; font-size: .86rem; line-height: 1.35; color: var(--ink-2);
}
.task--urgent .task__why { color: var(--stop); font-weight: 500; }
/* Время: одно число и слово под ним. Двух чисел в этой зоне не бывает. */
.task__ago { text-align: right; font-size: .82rem; color: var(--ink-3); }
.task__ago b {
  display: block; font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: .95rem; font-weight: 600; color: var(--ink-2); letter-spacing: -.02em;
}
.task--urgent .task__ago b { color: var(--stop); }
.task__ago .sum {
  display: block; margin-top: 2px; font-family: var(--mono);
  font-size: .92rem; font-weight: 600; color: var(--ink);
}

/* ─────────── цвет номера: четыре состояния, не восемь ───────────
   Номер заявки отвечает на тот же вопрос, что и метка статуса: чей сейчас ход.
   Восемь статусов дают четыре ответа, и цветов ровно четыре. */
.task--q .task__no.new,
.task--q .task__no.diagnosed,
.task--q .task__no.done {                    /* ваш ход */
  background: var(--go-bg); border-color: var(--go-line); color: var(--go);
}
.task--q .task__no.new small,
.task--q .task__no.diagnosed small,
.task--q .task__no.done small { color: var(--ok); opacity: .75; }

.task--q .task__no.in_progress,
.task--q .task__no.awaiting_payment {        /* ход не ваш */
  background: var(--info-bg); border-color: var(--info-line); color: var(--info);
}
.task--q .task__no.in_progress small,
.task--q .task__no.awaiting_payment small { color: var(--info); opacity: .75; }

.task--q .task__no.waiting_part {            /* ждём извне */
  background: var(--wait-bg); border-color: var(--wait-line); color: var(--wait);
}
.task--q .task__no.waiting_part small { color: var(--wait); opacity: .75; }
/* paid и cancelled остаются серыми по умолчанию: дело закрыто. */

/* Срочность старше статуса: если человек ждёт прямо сейчас, чей формально ход —
   уже неважно. Красное в строке одно и то же: номер и причина, а не пять мест. */
.task--q.task--urgent .task__no {
  background: var(--stop-bg); border-color: var(--stop-line); color: var(--stop);
}
.task--q.task--urgent .task__no small { color: var(--stop); opacity: .75; }

/* Имя клиента внутри строки — своя цель: ведёт к человеку, а не к заявке.
   Внутрь кнопки кнопку вкладывать нельзя, поэтому строка снаружи — article role=button. */
.who {
  background: none; border: 0; box-shadow: none; padding: 0;
  min-height: 0; font: inherit; font-weight: 400; color: var(--ink-2);
  text-decoration: underline; text-decoration-color: var(--line-strong);
  text-underline-offset: 3px;
}
/* Цель нажатия растёт отступом, а не высотой строки: пальцем в двадцать четыре
   точки не попадают, а раздвинуть строку ради этого нельзя — их в ленте тридцать. */
.who { padding: 11px 4px; margin: -11px -4px; }
.who:hover { background: none; color: var(--info); text-decoration-color: currentColor; }
.who:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; border-radius: 3px; }

/* Полка приглушена: её строки пересекаются с другими сегментами, и это единственное
   допустимое пересечение — фон говорит «ты уже видел это в другом месте». */
.tasks--quiet .task { background: var(--surface-2); }

/* ─────────── меню редких входов ───────────
   Раскрытие держит браузер: <details> сам умеет клавиатуру, Escape и фокус. */
.menu { position: relative; }
.menu > summary {
  display: grid; place-content: center;
  width: 44px; height: 44px; border-radius: var(--r-sm);
  color: var(--ink-2); cursor: pointer; list-style: none;
  border: 1px solid transparent;
  transition: background var(--fast), border-color var(--fast), color var(--fast);
}
.menu > summary::-webkit-details-marker { display: none; }
.menu > summary .ic { width: 20px; height: 20px; }
.menu > summary:hover { background: var(--surface-2); border-color: var(--line-strong); color: var(--ink); }
.menu > summary:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; }
.menu[open] > summary { background: var(--surface-2); border-color: var(--line-strong); color: var(--ink); }
/* fixed, а не absolute: меню живёт и внутри таблиц с собственной прокруткой (прайс,
   дерево моделей), а absolute внутри overflow-контейнера этим контейнером обрезается.
   Координаты ставит placeMenu() при открытии — см. app.js. */
.menu__body {
  position: fixed; z-index: 60; left: 0; top: 0;
  min-width: 244px; padding: var(--s2);
  display: grid; gap: 1px;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--r); box-shadow: var(--shadow-2);
}
.menu__body button {
  width: 100%; text-align: left; min-height: 40px;
  padding-inline: 10px; border-radius: var(--r-sm);
}
.menu__body hr { margin: var(--s2) 0; border: 0; border-top: 1px solid var(--line); }

/* Ссылка, которая работает как кнопка: «Позвонить» и WhatsApp обязаны быть
   настоящими ссылками, иначе планшет не отдаст их набирателю номера. */
.btnish {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 40px; padding: 9px 16px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  font: 500 .92rem/1.2 var(--sans); text-decoration: none;
  transition: background var(--fast), border-color var(--fast);
}
.btnish:hover { background: var(--surface-2); border-color: var(--ink-3); color: var(--ink); }

/* ─────────── панель клиента ───────────
   Панель, а не экран: администратор смотрит человека, не бросая заявку. Диалог
   браузера сам держит фокус внутри, закрывается по Escape и возвращает фокус туда,
   откуда его открыли, — своего кода на это писать нечего. */
dialog.side {
  margin: 0 0 0 auto; height: 100dvh; max-height: 100dvh;
  width: min(380px, 100vw); max-width: 100vw;
  padding: 0; border: 0; border-left: 1px solid var(--line-strong);
  background: var(--surface); color: var(--ink);
  box-shadow: var(--shadow-2);
  animation: sidein var(--smooth) both;
}
dialog.side::backdrop { background: rgba(11, 36, 29, .38); }
@keyframes sidein { from { transform: translateX(16px); opacity: 0 } to { transform: none; opacity: 1 } }
@media (prefers-reduced-motion: reduce) { dialog.side { animation: none } }
@media (max-width: 560px) { dialog.side { width: 100vw; border-left: 0 } }

.side__body { height: 100%; overflow-y: auto; padding: var(--s4) var(--s5) var(--s6); }
.side__head { display: flex; gap: var(--s3); align-items: flex-start; margin-bottom: var(--s4); }
.side__head h2 { margin: 0; font-size: 1.2rem; letter-spacing: -.015em; }
.side__head p { margin: 2px 0 0; }
.side__head button { margin-left: auto; min-width: 40px; }
.side__body h3 {
  margin: var(--s5) 0 var(--s2); font-size: .78rem; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3);
  display: flex; align-items: center; gap: 8px;
}
.side__body h3 .count {
  font-family: var(--mono); font-size: .74rem; padding: 1px 7px;
  border-radius: var(--r-pill); background: var(--surface-2);
  border: 1px solid var(--line); color: var(--ink-2); letter-spacing: 0;
}
/* Строка в панели кликается целиком: заявка открывается, панель закрывается. */
.side__row {
  display: flex; align-items: center; gap: var(--s3); width: 100%;
  min-height: 44px; padding: 8px 10px; margin-bottom: 2px; text-align: left;
  background: transparent; color: var(--ink); border: 1px solid transparent;
  border-radius: var(--r-sm); box-shadow: none; font: 400 .92rem/1.3 var(--sans);
}
.side__row:hover { background: var(--surface-2); border-color: var(--line); }
.side__row .hint { margin-left: auto; white-space: nowrap; }

/* ─────────── карточка заявки ─────────── */

/* Шаг разбора, который уже сделан: одна строка вместо сетки из двадцати семи плиток.
   Плитки нужны тридцать секунд, а занимали середину экрана всё время разбора. */
.stepdone {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 0 0 var(--s4); padding: 10px var(--s3);
  background: var(--go-bg); border: 1px solid var(--go-line); border-radius: var(--r);
  font-size: .92rem; color: #14503a;
}
.stepdone b { color: var(--go); }
.stepdone button { margin-left: auto; }

/* Себестоимость и маржа: экран стойки виден клиенту, который стоит напротив. */
.forus { margin: 0 0 var(--s3); border-top: 1px solid var(--line); padding-top: 6px; }
.forus > summary {
  min-height: 32px; display: flex; align-items: center; gap: 6px;
  font-size: .8rem; color: var(--ink-3); cursor: pointer; list-style: none;
}
.forus > summary::-webkit-details-marker { display: none; }
.forus > summary::before { content: '▸'; transition: transform var(--fast); }
.forus[open] > summary::before { transform: rotate(90deg); }
.forus > summary:hover { color: var(--ink-2); }
.forus > summary:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; border-radius: var(--r-sm); }

@media (max-width: 900px) {
  /* Планшет за стойкой: причина и время встают под аппарат, но рядом друг с другом —
     в четыре яруса строка вырастала до 184 точек, и на экран влезало пять заявок. */
  .task--q { grid-template-columns: 3.4rem minmax(0, 1fr) auto; row-gap: var(--s2); }
  .task--q .task__main { grid-column: 2 / -1; }
  .task--q .task__why { grid-column: 2; align-self: center; }
  /* Время в одну строку: число над словом крало ещё двадцать точек с каждой заявки. */
  .task--q .task__ago { grid-column: 3; display: flex; gap: 6px; align-items: baseline; }
  .task--q .task__ago b { display: inline; }
  .task--q .task__ago .sum { display: inline; margin: 0; }
  .task--q .task__act { grid-column: 1 / -1; }
  .task--q .task__act button, .task--q .task__act .btnish { width: 100%; }
  /* Пальцем попадают хуже, чем курсором: сорок четыре точки — нижняя граница. */
  .task--q, .side__row, .btnish, .menu__body button,
  .task--q .task__act button, .segs button, .menu > summary { min-height: 44px; }
  /* Базовое правило .bseg стоит в файле ниже той медиазапроса, где палец учтён,
     и выигрывало у него по порядку. Здесь оно наконец в конце. */
  .bseg button { min-height: 44px; padding-inline: 16px; }
  /* Сорок точек — это курсор. За стойкой всё нажимают пальцем, и половина кнопок
     карточки заявки («править», «записать», «+ Заметка мастеру») стояла вплотную
     друг к другу ровно на этой границе. */
  button, .btnish, label.chk { min-height: 44px; }
  .shiftline > summary, .forus > summary { min-height: 44px; }
}

/* ═══════════════════ «Воздух» — вид стойки ═══════════════════

   Включается атрибутом `data-skin="air"` на <html> и пока стоит на двух страницах:
   диагност и администратор. Снять атрибут — вернуться к прежнему виду; поставить
   на кассе или у мастера — перенести туда. Ни одного правила вне этой области:
   старые экраны не должны меняться, пока их не переделали.

   Что меняется: полотно, воздух, скругления, тени, движение.
   Что НЕ меняется: четыре смысловых цвета. Зелёный — твой ход, синий — ход не твой,
   жёлтый — ждём извне, красный — поздно. Люди выучили их за смену, и переучивать
   ради моды дороже, чем всё остальное вместе взятое. Синий стал заметнее — он теперь
   держит фокус, выбранный сегмент и выделение текста, — но значения не поменял. */

:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) {
  /* Полотно нейтрально-холодное, почти без оттенка: тёплый бежевый читается как
     бумага, синеватый — как «корпоративный портал». Современный рабочий SaaS 2020-х
     (Linear, Stripe Dashboard, Vercel) держит серый строго нейтральным. */
  --canvas: #f7f8fa;
  --surface: #ffffff;
  --surface-2: #f2f3f6;

  --ink: #14161b;
  --ink-2: #5a5f6a;
  --ink-3: #8b8f99;   /* 4.6:1 на белом: подпись под числом читают под углом и с метра */
  --line: #e8e9ed;
  --line-strong: #d4d6dc;

  /* Хром — только дверь входа (см. body.door ниже), в интерфейсе больше не используется:
     рабочая шапка светлая, как в любом современном инструменте, а не панель 2008 года
     с тёмной плашкой сверху. */
  --chrome: #0a0b0d;
  --chrome-2: #16181c;

  /* Один акцент интерфейса — синий, тот же смысл («ход не ваш»), но чище и холоднее. */
  --info: #2f5fe0;
  --info-bg: #eef2fe;
  --info-line: #c2d1fb;

  /* Скругления современной панели: крупнее прежних десяти точек — на экране,
     где карточка занимает всю ширину, десять точек читаются как «почти прямой угол».
     Но и подушкой карточка быть не должна — двадцать была именно ею. */
  --r: 12px;
  --r-sm: 8px;
  --r-lg: 16px;

  /* Тени тихие и короткие: современная плоская панель держится хайрлайном,
     тень — только лёгкий намёк на приподнятость при наведении, не свечение по контуру. */
  --shadow-1: 0 1px 2px rgba(20, 22, 27, .05);
  --shadow-2: 0 8px 24px -12px rgba(20, 22, 27, .22), 0 2px 6px -2px rgba(20, 22, 27, .08);
  --shadow-go: 0 2px 10px -3px rgba(24, 107, 70, .28);

  --fast: 140ms cubic-bezier(.2, .8, .2, 1);
  --smooth: 220ms cubic-bezier(.16, 1, .3, 1);   /* экспоненциальное затухание */
}

/* ═══════════════════ «Пузырь» — пробный заход ═══════════════════

   Включается атрибутом `data-skin="bubble"` на <html> — стоит на всех рабочих
   местах (rm/*/index.html). Наследует всю структуру
   «Воздуха» (те же правила, см. :is() выше) — меняются только значения переменных:
   светлее полотно, крупнее скругления, ярче те же четыре смысловых цвета, тени
   мягче и с оттенком акцента вместо серого. Смысл цветов не меняется, только громкость. */
[data-skin="bubble"] {
  --canvas: #f4f1ff;
  --surface: #ffffff;
  --surface-2: #ede7ff;

  --ink: #211c3d;
  --ink-2: #5f5580;
  --ink-3: #9089ac;
  --line: #e5deff;
  --line-strong: #cdc0ff;

  /* Акцент — фиолетовый вместо синего, чище, чем формальный «синий SaaS»,
     но роль та же: подсказка системы, «ход не твой». */
  --info: #6d4aff;
  --info-bg: #efe9ff;
  --info-line: #d7c9ff;

  /* Те же четыре смысла, что и везде в системе (см. :root выше), только звонче:
     это ровно то, что «ярко и игриво» и значит — не новый язык, а громкость старого. */
  --go: #16a34a;
  --go-bg: #e3f9ea;
  --go-line: #a7ebc0;
  --go-hover: #0f7c38;
  --wait: #d97706;
  --wait-bg: #fff2dc;
  --wait-line: #f7d99a;
  --stop: #e0294b;
  --stop-bg: #ffe6ec;
  --stop-line: #f8b8c8;

  /* Скругления крупнее «Воздуха» — карточка мягкая, кнопка близка к таблетке. */
  --r: 20px;
  --r-sm: 14px;
  --r-lg: 28px;

  /* Тень с лёгким фиолетовым оттенком вместо нейтрально-серой — как будто у света
     в комнате тот же акцентный цвет, а не голая физика тени. */
  --shadow-1: 0 2px 8px -3px rgba(109, 74, 255, .16);
  --shadow-2: 0 20px 44px -20px rgba(109, 74, 255, .32), 0 4px 14px -6px rgba(33, 28, 61, .12);
  --shadow-go: 0 4px 14px -3px rgba(22, 163, 74, .38);
}

/* .note--wait/--stop/--go красят текст под свой же фон и остаются в тон и здесь.
   Плашка-пояснение (по умолчанию) — исключение: текст у нее зашит тёмно-синим
   при любом скине, а на фиолетовом фоне «пузыря» это читается чужеродно. */
[data-skin="bubble"] .note { color: #382a6e; }
[data-skin="bubble"] .note b { color: #241a52; }

/* ─────────── плотность ───────────
   За стойкой стоят двое разных людей: диагност сидит с аппаратом минуты, ему нужен
   воздух; администратор смотрит урывками по две секунды и хочет видеть всю очередь
   сразу. Одна настройка на человека, помнится в браузере. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"])[data-density="air"] {
  --s1: 6px; --s2: 10px; --s3: 16px; --s4: 22px; --s5: 32px; --s6: 44px;
  --row-pad: 16px 18px;
  --row-gap: 10px;
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"])[data-density="dense"] {
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px;
  --row-pad: 10px 14px;
  --row-gap: 6px;
}

/* Рабочая шапка светлая — рабочий экран открыт восемь часов, и тёмная плашка
   сверху весь день не средство фирменности, а лишний контраст, с которым устают
   глаза. Гейт (дверь входа) остаётся тёмным намеренно — см. правило ниже, — это
   единственное место, где граница «снаружи / внутри» всё ещё должна читаться цветом. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) header {
  background: var(--surface);
  color: var(--ink);
  border-bottom: 1px solid var(--line);
  box-shadow: none;
  padding: 14px 24px;
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) header b { color: var(--ink); font-weight: 600; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) header span { color: var(--ink-3); }
/* Знак — светлые линии на прозрачном, рисовался для тёмной плашки. На белой
   шапке те же линии инвертируются в тёмные тем же файлом, без второго актива. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) header .brand { filter: invert(1); opacity: .88; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) header button {
  color: var(--ink-2);
  border-color: var(--line-strong);
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) header button:hover {
  background: var(--surface-2); color: var(--ink); border-color: var(--ink-3);
}

/* Дверь исключена намеренно. Она красится в тёмный хром — это единственный экран,
   где не работают, и граница «снаружи / внутри» держится именно цветом. Правило ниже
   имеет ту же силу, что и `body.door`, и стоит в файле позже, то есть без :not() оно
   молча перекрашивает дверь в полотно — светлый текст на светлом фоне. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) body:not(.door) { background: var(--canvas); }
/* Числа в колонку: сумма под суммой, срок под сроком. Иначе взгляд ищет разряд. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) { font-variant-numeric: tabular-nums; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) h1, :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) h2, :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) h3 { letter-spacing: -.022em; }

/* Поверхности: белое на холодном полотне плюс мягкая тень. Рамка остаётся —
   на светлом фоне одна тень границу не держит. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .card {
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  padding: var(--s4) var(--s5);
}

:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) input,
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) select,
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) textarea {
  border-radius: var(--r-sm);
  background: var(--surface);
  min-height: 44px;
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) input:focus,
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) select:focus,
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) textarea:focus { box-shadow: 0 0 0 4px rgba(31, 95, 208, .14); }

:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) button { border-radius: var(--r-sm); min-height: 42px; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) button:active { transform: translateY(1px) scale(.995); }

/* Поиск — самая нажимаемая цель экрана после строки заявки. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .admbar {
  border-bottom: 0;
  padding-bottom: 0;
  margin-bottom: var(--s4);
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .admbar__find input {
  min-height: 52px;
  font-size: 1rem;
  padding-inline: 18px;
  background: var(--surface);
  box-shadow: var(--shadow-1);
  border-color: transparent;
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .admbar__find input:hover { border-color: var(--line-strong); }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .admbar__find .field__label { display: none; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .admbar__act #admNew { min-height: 52px; padding-inline: 22px; font-size: .96rem; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .menu > summary { width: 52px; height: 52px; border-radius: var(--r-sm); }

/* Сегменты: подчёркивание уезжает, остаётся мягкая подложка. Полоса под шестью
   пунктами делила экран пополам и читалась как край страницы. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .segs {
  border-bottom: 0;
  gap: var(--s1);
  padding: 5px;
  background: rgba(255, 255, 255, .7);
  border-radius: var(--r-pill);
  box-shadow: inset 0 0 0 1px var(--line);
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .segs button {
  border-bottom: 0;
  border-radius: var(--r-pill);
  transition: background var(--fast), color var(--fast), box-shadow var(--smooth);
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .segs button:hover { background: var(--surface-2); }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .segs button[aria-selected="true"] {
  background: var(--surface);
  box-shadow: var(--shadow-1);
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .segs .count { border-color: transparent; background: var(--canvas); }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .segs button[aria-selected="true"] .count { background: var(--go); color: #fff; }

/* Строка заявки. Отдельная плавающая карточка на строку — это язык дашборда
   из плиток, а не список дел: одна тень на весь список, внутри — плоские
   строки с хайрлайном, как современный список задач, а не стопка визиток. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks {
  gap: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task {
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
  padding: var(--row-pad, 14px 18px);
  transition: background var(--fast);
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks > .task:last-child { border-bottom: 0; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task--q:hover {
  background: var(--surface-2);
  box-shadow: none;
  transform: none;
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task--q:focus-visible {
  outline: 2px solid var(--info);
  outline-offset: -2px;
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task__no { border-radius: 8px; background: transparent; border-color: transparent; }

/* Строка кассы — тот же список дел, что и везде, только с денежной зоной вместо
   времени и круглым жетоном вместо квадратного номера заявки (см. .till-no
   в основном блоке кассы). Плоская строка внутри одного контейнера — тот же
   приём, что `.task` получил выше, под именем `.till-row`. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks > .till-row {
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
  transition: background var(--fast);
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks > .till-row:last-child { border-bottom: 0; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks > .till-row:hover {
  background: var(--surface-2);
  border-color: transparent;
  box-shadow: none;
}

/* Способ оплаты — та же логика выбора, что у сегментов очереди (.segs), но
   раньше переключался без единого перехода: цвет и рамка просто скакали. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .till-way {
  transition: background var(--fast), border-color var(--fast), color var(--fast);
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .till-way .ic {
  transition: color var(--fast);
}


/* Плашка сдачи/остатка на карту всплывает один раз, когда появляется на экране
   (её className переустанавливается на каждую цифру суммы, но сам DOM-узел не
   пересоздаётся — animation-name не меняется, поэтому повторного проигрывания
   на каждый ввод не будет). */
@keyframes changein { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .change {
  animation: changein var(--smooth) both;
}
@media (prefers-reduced-motion: reduce) {
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .change { animation: none; }
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task--urgent .task__no,
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task--wait .task__no,
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task--ready .task__no,
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task__no.done { border-color: transparent; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task__title { font-size: .98rem; }

/* Единственная авторская сцена экрана: дела не появляются разом, а раскладываются
   сверху вниз. Это ровно тот порядок, в котором их надо делать, — движение говорит
   то же, что и сортировка. Больше нигде на экране ничего не «въезжает».
   Проигрывается только когда список правда изменился (класс ставит JS): очередь
   перерисовывается раз в полторы секунды, и без этого экран бы мигал всю смену. */
@keyframes rowin {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks.is-fresh > .task {
  animation: rowin var(--smooth) both;
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks.is-fresh > .task:nth-child(1) { animation-delay: 0ms; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks.is-fresh > .task:nth-child(2) { animation-delay: 24ms; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks.is-fresh > .task:nth-child(3) { animation-delay: 48ms; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks.is-fresh > .task:nth-child(4) { animation-delay: 72ms; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks.is-fresh > .task:nth-child(5) { animation-delay: 96ms; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks.is-fresh > .task:nth-child(6) { animation-delay: 120ms; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks.is-fresh > .task:nth-child(7) { animation-delay: 144ms; }
/* Дальше седьмой задержку не наращиваем: восьмая строка ниже сгиба, и ждать её
   появления никто не будет. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks.is-fresh > .task:nth-child(n+8) { animation-delay: 160ms; }

@media (prefers-reduced-motion: reduce) {
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tasks.is-fresh > .task { animation: none; }
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task--q:hover { transform: none; }
}

/* Кто на месте. Строка статуса, а не карточка: рамка ради факта, который меняется
   дважды в день, забирала внимание у просроченных заявок. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .shiftline {
  padding: 2px var(--s3);
  background: rgba(255, 255, 255, .6);
  border-radius: var(--r-pill);
  box-shadow: inset 0 0 0 1px var(--line);
  margin-bottom: var(--s3);
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .shiftline[open] { border-radius: var(--r); padding-bottom: var(--s2); }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .shiftline--wait {
  background: var(--wait-bg);
  box-shadow: inset 0 0 0 1px var(--wait-line);
  color: #6b4705;
}

/* Кого подменяем — тихая пометка у причины, а не ещё один чип в строке.
   Она отвечает на «почему это у меня», и ответ нужен один раз, а не каждый раз. */
.task__stand {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 8px;
  border-radius: var(--r-pill);
  background: var(--info-bg);
  color: var(--info);
  font-size: .76rem;
  font-weight: 500;
  white-space: nowrap;
  vertical-align: 1px;
}

/* Смета и панель клиента — те же поверхности, что и лента. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .adm__sum .card { border-radius: var(--r-lg); }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) dialog.side { border-left: 0; box-shadow: -24px 0 60px -30px rgba(13, 22, 38, .45); }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .side__row { border-radius: var(--r-sm); }

/* Итого в смете шевелится, только когда сумма правда изменилась (класс ставит
   draw() в admOrder — сравнивает с прошлым значением, не перерисовкой ради
   другого повода). Короткий всплеск веса и цвета: подтверждение, что цифра
   услышана, а не мигание на каждый клик по карточке. */
@keyframes sumpop {
  0%   { color: var(--go); transform: scale(1.08); }
  100% { color: var(--ink); transform: scale(1); }
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .estim__total b.sumpop {
  display: inline-block;
  animation: sumpop 420ms cubic-bezier(.2, .8, .2, 1) both;
}
@media (prefers-reduced-motion: reduce) {
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .estim__total b.sumpop { animation: none; }
}

/* Заявка только что подняла руку (needs_admin) — рамка толкается один раз при
   появлении в сегменте «Сейчас» (класс ставит row(), see admJustRaised в app.js).
   Не постоянное мигание — оно раздражает за смену, — а один заметный толчок в
   момент, когда администратор мог это увидеть. */
@keyframes raisedpulse {
  0%   { box-shadow: inset 0 0 0 2px var(--info); }
  70%  { box-shadow: inset 0 0 0 2px var(--info); }
  100% { box-shadow: inset 0 0 0 0 transparent; }
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task--raised {
  animation: raisedpulse 1400ms cubic-bezier(.2, .8, .2, 1) both;
}
@media (prefers-reduced-motion: reduce) {
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task--raised { animation: none; }
}

/* Плитки работ и кандидаты в мастера. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tile,
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .cand { border-radius: var(--r-sm); transition: all var(--fast); }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .tile:hover,
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .cand:hover { transform: translateY(-1px); box-shadow: var(--shadow-1); }

/* Поверхности браузера, которые никто не рисовал: выделение, каретка, полоса
   прокрутки. По умолчанию они принадлежат не этой системе, а операционной. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) ::selection { background: rgba(31, 95, 208, .18); color: var(--ink); }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) { caret-color: var(--info); scrollbar-color: var(--line-strong) transparent; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) ::-webkit-scrollbar { width: 11px; height: 11px; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) ::-webkit-scrollbar-thumb {
  background: var(--line-strong); border-radius: 999px;
  border: 3px solid transparent; background-clip: content-box;
}
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) ::-webkit-scrollbar-thumb:hover { background-clip: content-box; background-color: var(--ink-3); }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) ::-webkit-scrollbar-track { background: transparent; }

/* Переключатель плотности в меню: две подписи, выбранная отмечена. */
.menu__body .dens { display: flex; gap: 4px; padding: 4px 6px 2px; }
.menu__body .dens button { min-height: 36px; flex: 1; text-align: center; padding-inline: 8px; }
.menu__body .dens button[aria-pressed="true"] { background: var(--go-bg); color: var(--go); font-weight: 600; }
.menu__body .dens__label {
  padding: 6px 10px 2px; font-size: .74rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
}

/* Палец на планшете. Правило про сорок четыре точки стоит в файле выше скина
   и проигрывало ему по порядку — здесь оно наконец последнее.
   Считать 42 достаточным нельзя: цели стоят вплотную рядами по шесть. */
@media (max-width: 900px), (pointer: coarse) {
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) button,
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .btnish,
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) label.chk,
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .segs button,
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .menu__body button,
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .menu__body .dens button,
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .shiftline > summary,
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .forus > summary { min-height: 44px; }
}

/* Строка работы в ведении сворачивается: кнопки живут у раскрытой.
   До этого на заявке из четырёх работ экран был стеной из двадцати кнопок,
   из которых за смену нажимают одну. */
.task--fold { cursor: pointer; }
.task--fold:hover { border-color: var(--line-strong); }
.task--fold.is-open { box-shadow: var(--shadow-2); }
.task--fold:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; }
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) .task--fold.is-open { box-shadow: var(--shadow-2); }

/* ─────────────── дверь кассира: касса или бухгалтерия ───────────────

   Две панели во весь экран, а не пункты меню: выбор делается один раз за смену,
   и человек должен видеть, что его ждёт за каждой дверью, до того как войдёт. */
.hub { max-width: 900px; margin: 0 auto; padding: var(--s4) 0; }
.hub__lede { color: var(--ink-2); text-align: center; margin: 0 0 var(--s4); }
.hub__doors { display: grid; gap: var(--s4); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.hub__door {
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  padding: 22px; min-height: 200px; text-align: left; cursor: pointer;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r);
  color: inherit; font: inherit; box-shadow: var(--shadow-1);
  transition: border-color var(--fast), box-shadow var(--fast), transform var(--fast);
}
.hub__door:hover { border-color: var(--go); box-shadow: var(--shadow-2); transform: translateY(-1px); }
.hub__door:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; }
.hub__door .ic { width: 26px; height: 26px; color: var(--ink-3); }
.hub__name { font-size: 1.35rem; font-weight: 600; }
.hub__sub { font-size: .88rem; color: var(--ink-2); }
.hub__nums { display: flex; flex-wrap: wrap; gap: 14px; margin-top: auto; padding-top: 12px; }
.hubnum b {
  display: block; font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 1.15rem; letter-spacing: -.03em;
}
.hubnum span { font-size: .72rem; color: var(--ink-2); }
.hubnum.is-hot b { color: var(--wait); }
.hub__hero {
  margin-top: 10px; font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 1.3rem; font-weight: 600; color: var(--go);
}
.hub__hero small { font-family: inherit; font-size: .72rem; font-weight: 400; color: var(--ink-2); }

/* Переключатель стола: тот же сегментный контрол, что и вкладки, но отдельной строкой —
   стол меняют раз в час, а вкладку раз в минуту, и путать их пальцем не нужно. */
.deskswitch { margin-bottom: 4px; }
.bnav__back { margin-top: auto; }

/* Сверка смены: сколько должно лежать в ящике прямо сейчас. Одно крупное число,
   всё остальное — чтобы его объяснить. */
.shift { display: grid; gap: var(--s3); }
.shift__hero {
  padding: 18px 20px; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r); text-align: center;
}
.shift__label { display: block; font-size: .8rem; color: var(--ink-2); }
.shift__sum {
  display: block; font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 2.2rem; letter-spacing: -.04em; line-height: 1.1; margin: 4px 0;
}
.shift__note { display: block; font-size: .78rem; color: var(--ink-3); max-width: 60ch; margin: 0 auto; }

/* Точка безубыточности дня: одна строка под потоком денег. Не карточка и не блок —
   это вывод из чисел выше, а не отдельная цифра, и читаться должна как фраза. */
.daymoney__even {
  margin: 12px 0 0; padding: 10px 12px;
  border-radius: var(--r);
  border: 1px solid var(--wait-line); background: var(--wait-bg);
  font-size: .86rem; line-height: 1.5; color: #6b4705;
}
.daymoney__even b { color: #57390a; }
.daymoney__even.is-ok { border-color: var(--go-line); background: var(--go-bg); color: #12583a; }
.daymoney__even.is-ok b { color: #0f4a31; }

/* ─── Зарплата: карточка человека ───
   Экран зарплаты — про людей, а не про период, поэтому строка таблицы заменена
   карточкой: у человека есть имя, одна главная цифра и действия рядом с ней.
   В таблице на семь колонок главное число терялось среди служебных. */
.paylist { display: grid; gap: 10px; }
.payc {
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); padding: 14px 16px;
}
.payc__h { display: flex; align-items: flex-start; gap: 12px; }
.payc__name { font-size: 1.02rem; font-weight: 600; }
.payc__sum { margin-left: auto; text-align: right; }
.payc__sum b { display: block; font-size: 1.35rem; font-variant-numeric: tabular-nums; }
.payc__sum b.neg { color: var(--stop); }
.payc__sum b.is-clear { font-size: 1rem; color: var(--go); }
.payc__sum span { font-size: .78rem; color: var(--ink-3); }
.payc__line {
  display: flex; flex-wrap: wrap; gap: 4px 16px;
  margin: 10px 0 0; font-size: .86rem; color: var(--ink-2);
}
.payc__line b { font-variant-numeric: tabular-nums; color: var(--ink); }
.payc__line b.neg { color: var(--stop); }
/* Действия в одну строку и переносятся на узком экране: на планшете у стойки
   четыре кнопки в ряд не помещаются, а прятать их за «ещё» — добавить лишний шаг
   ровно там, ради чего на экран и зашли. */
.payc__act { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.payc details { margin-top: 10px; }
.payc details table { width: 100%; font-size: .84rem; }
/* Человек без правила оплаты: ведомость выглядит посчитанной, а он в ней забыт. */
.payc__warn {
  margin: 10px 0 0; font-size: .82rem; color: #6b4705;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}

/* Имя модели в прайсе — ссылка в справочник. Кнопкой, а не <a>: переход внутренний,
   а в строке оно должно читаться как имя, а не как ещё один элемент управления. */
.mx__name {
  font: inherit; font-weight: 600; color: inherit;
  background: none; border: 0; padding: 0; border-radius: 0;
  box-shadow: none; cursor: pointer; text-align: left;
  border-bottom: 1px dashed var(--line-strong);
}
.mx__name:hover { border-bottom-style: solid; }

/* Разделитель в полосе массовых действий: слева правки цен, которые ещё можно
   отменить, справа — то, что случится немедленно. Без него они читаются одним рядом. */
.bulkbar__sep {
  width: 1px; align-self: stretch; margin-inline: 4px;
  background: var(--line); flex: 0 0 auto;
}

/* ═══════════════════ Приложение (PWA) ═══════════════════
   viewport-fit=cover отдаёт странице весь экран, включая вырез и полосу жестов.
   Отступы ниже возвращают содержимое из-под них; в обычной вкладке env() = 0,
   и ничего не меняется. Всё поведение — в pwa.js. */
:is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) body > header {
  padding-top: calc(14px + env(safe-area-inset-top));
  padding-left: max(24px, env(safe-area-inset-left));
  padding-right: max(24px, env(safe-area-inset-right));
}
@media (max-width: 760px) {
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) body > header {
    padding: calc(10px + env(safe-area-inset-top)) max(14px, env(safe-area-inset-right)) 10px max(14px, env(safe-area-inset-left));
  }
}
main { padding-bottom: env(safe-area-inset-bottom); }
#toast { bottom: calc(20px + env(safe-area-inset-bottom)); }
.bulkbar { padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
body.door {
  padding: max(24px, env(safe-area-inset-top)) max(24px, env(safe-area-inset-right))
           max(24px, env(safe-area-inset-bottom)) max(24px, env(safe-area-inset-left));
}

/* Установленное приложение не должно вести себя как страница: без резинового
   оттягивания всего экрана, без синей вспышки на тапе, без выделения шапки. */
html { -webkit-tap-highlight-color: transparent; }
.is-app body { overscroll-behavior-y: none; }
.is-app body > header { -webkit-user-select: none; user-select: none; }
.is-app :is(button, .btnish, nav) { -webkit-touch-callout: none; }

/* Кнопка «установить» в шапке: иконка и слово, на телефоне — только иконка. */
body > header #install { display: inline-flex; align-items: center; gap: 6px; }
body > header #install[hidden] { display: none; }
@media (max-width: 560px) {
  body > header #install span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  body > header #install { padding-inline: 10px; }
}

/* Та же кнопка на двери: тихая, под карточкой — главное на двери всё равно «Войти». */
.door__install {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; min-height: 48px; margin-top: 12px;
  background: rgba(255, 255, 255, .06); color: #eef1ee;
  border: 1px solid rgba(238, 241, 238, .22); border-radius: 10px;
  font: inherit; font-size: .92rem; box-shadow: none; cursor: pointer;
  transition: background var(--fast), border-color var(--fast);
}
.door__install:hover { background: rgba(255, 255, 255, .12); border-color: rgba(238, 241, 238, .4); }
.door__install[hidden] { display: none; }

/* Инструкция для iPhone: лист снизу, как системный. */
.pwa-sheet {
  position: fixed; inset: 0; z-index: 90;
  display: grid; align-items: end; justify-items: center;
  background: rgba(10, 11, 13, .45);
  padding: 16px max(16px, env(safe-area-inset-right)) calc(16px + env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
  animation: pwa-fade 180ms ease both;
}
.pwa-sheet__card {
  width: 100%; max-width: 420px;
  background: var(--surface); color: var(--ink);
  border-radius: var(--r-lg, 16px); padding: 20px 20px 16px;
  box-shadow: var(--shadow-2);
  animation: pwa-up 320ms cubic-bezier(.16, 1, .3, 1) both;
}
.pwa-sheet__card b { display: block; font-size: 1.05rem; margin-bottom: 10px; }
.pwa-sheet__card ol { margin: 0 0 16px; padding-left: 20px; line-height: 1.9; color: var(--ink-2); }
.pwa-sheet__card svg { vertical-align: -4px; color: var(--info); }
.pwa-sheet__card button { width: 100%; min-height: 48px; }
@keyframes pwa-fade { from { opacity: 0; } }
@keyframes pwa-up { from { transform: translateY(24px); opacity: 0; } }

/* Полоса связи: под шапкой, во всю ширину. Жёлтый — «ждём и не можем ускорить». */
.netbar {
  position: fixed; z-index: 29; left: 0; right: 0;
  top: var(--head-h, 60px);
  padding: 8px max(16px, env(safe-area-inset-right)) 8px max(16px, env(safe-area-inset-left));
  background: var(--wait-bg); color: #6b4705;
  border-bottom: 1px solid var(--wait-line);
  font-size: .86rem; font-weight: 600; text-align: center;
  animation: pwa-down 240ms cubic-bezier(.16, 1, .3, 1) both;
}
.netbar.is-ok { background: var(--go-bg); color: var(--go-hover, #0f7c38); border-color: var(--go-line); }
.netbar[hidden] { display: none; }
@keyframes pwa-down { from { transform: translateY(-100%); opacity: 0; } }

/* Старт без сети: вход сохранён, ждём. */
.offline-start { max-width: 420px; margin: 12vh auto 0; text-align: center; }
.offline-start button { margin-top: 14px; min-height: 48px; min-width: 200px; }
.offline { text-align: center; }
.offline__icon { color: var(--wait); margin: 4px auto 10px; display: block; }

@media (prefers-reduced-motion: reduce) {
  .pwa-sheet, .pwa-sheet__card, .netbar { animation: none; }
}

/* ─────────── окна поверх экрана: прокрутка и выход ───────────
   Окно выше экрана телефона раньше обрезалось вместе с кнопками. Теперь прокручивается
   само затемнение, а крестик в углу карточки есть у каждого окна. */
.modal {
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: max(12vh, calc(16px + env(safe-area-inset-top))) max(16px, env(safe-area-inset-right))
           calc(24px + env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
}
.modal > .card, .modal > form.card { position: relative; }
.modal__x {
  position: absolute; top: 8px; right: 8px; z-index: 2;
  width: 40px; height: 40px; min-height: 40px; padding: 0;
  display: grid; place-items: center;
  border-radius: 999px; color: var(--ink-3); background: transparent; border: 0; box-shadow: none;
}
.modal__x:hover { background: var(--surface-2); color: var(--ink); }
.modal__x .ic { width: 20px; height: 20px; }
.modal > .card > h3:first-of-type { padding-right: 40px; }
@media (max-width: 560px) {
  .modal { padding-top: calc(12px + env(safe-area-inset-top)); place-items: start stretch; }
  .modal .card { max-width: none; }
  .modal .askprice { max-height: none; }
  /* Кнопки окна на телефоне — во всю ширину, главное сверху. */
  .modal .row:last-child:not(.qrask__act) { flex-direction: column; align-items: stretch; }
  .modal .row:last-child > button { width: 100%; min-height: 48px; }
  .modal .row:last-child > .spacer { display: none; }
}

/* ─────────── окно печати ─────────── */
.printsheet {
  position: fixed; inset: 0; z-index: 80;
  display: grid; place-items: center;
  background: rgba(10, 11, 13, .55);
  padding: calc(16px + env(safe-area-inset-top)) max(16px, env(safe-area-inset-right))
           calc(16px + env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
  animation: fade 140ms ease-out;
}
.printsheet__card {
  width: min(560px, 100%); height: min(860px, 100%);
  display: flex; flex-direction: column;
  background: var(--surface); border-radius: var(--r-lg, 16px); overflow: hidden;
  box-shadow: var(--shadow-2);
}
.printsheet__bar {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 10px 10px 18px; border-bottom: 1px solid var(--line);
}
.printsheet__bar b { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.printsheet__bar button { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; }
.printsheet__bar .ic { width: 18px; height: 18px; }
.printsheet__doc { flex: 1; width: 100%; border: 0; background: #fff; }
@media (max-width: 560px) {
  .printsheet { padding: 0; }
  .printsheet__card { width: 100%; height: 100%; border-radius: 0; }
  .printsheet__bar { padding-top: calc(10px + env(safe-area-inset-top)); }
  .printsheet__bar [data-close] span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
}
@media print { .printsheet { display: none; } }

/* ─────────── телефон: шапка в одну полосу ───────────
   Было: логотип, роль и две кнопки в первой строке, имя — второй строкой на всю ширину,
   95px шапки на экране в 812. Стало: роль и имя столбиком рядом со знаком, кнопки
   справа во всю высоту — 56px. */
body > header #install span { margin: 0; color: inherit; }
@media (max-width: 760px) {
  :is([data-skin="air"], [data-skin="bubble"], [data-skin="console"]) body > header {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto auto auto;
    column-gap: 8px; row-gap: 0; align-items: center;
    padding-top: calc(8px + env(safe-area-inset-top)); padding-bottom: 8px;
  }
  body > header .brand { grid-row: 1 / 3; height: 26px; }
  body > header b {
    grid-column: 2; grid-row: 1; align-self: end; line-height: 1.25;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  body > header #who {
    grid-column: 2; grid-row: 2; align-self: start; margin: 0;
    font-size: .74rem; line-height: 1.3;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  body > header button { grid-row: 1 / 3; min-height: 40px; padding: 0 12px; }

  /* У консоли в шапке на два элемента больше — поиск и приём аппарата, — и в сетку
     выше они не заложены: колонок пять, детей семь, и лишние молча ложились в чужие
     ячейки поверх кнопок. Своя раскладка на две строки: сверху кто и действия,
     снизу поиск во всю ширину — на телефоне он нужнее имени.
     Имя не теряется: на «Сегодня» первой же строкой написано, кто на стойке. */
  [data-skin="console"] body > header {
    grid-template-columns: auto minmax(0, 1fr) auto auto auto;
    row-gap: 8px;
  }
  [data-skin="console"] body > header .brand { grid-row: 1; }
  [data-skin="console"] body > header > b { grid-column: 2; grid-row: 1; align-self: center; }
  [data-skin="console"] body > header #who { display: none; }
  [data-skin="console"] body > header button { grid-row: 1; }
  [data-skin="console"] .deskfind {
    grid-column: 1 / -1; grid-row: 2; margin-left: 0; max-width: none;
  }
}

/* ─────────── телефон: кабинет супер-админа как приложение ───────────
   Было: шапка с «Выйти», заголовок, поле поиска и лента полок — сорок процентов экрана
   до первой строки данных, и всё это уезжало при прокрутке: на середине длинной таблицы
   не оставалось ни поиска, ни полок, ни «назад».
   Стало, как в приложениях телефона:
   - сверху тонкая липкая панель: «назад» (или знак), короткий заголовок, лупа;
   - крупный заголовок уезжает вместе со страницей, его копия проявляется в панели;
   - полки прилипают под панелью и не теряются никогда;
   - поиск — во весь экран; внизу — плавающая панель комнат; «Ещё» — лист снизу
     с редкими комнатами, кто вошёл и «Выйти».
   Высота липких частей не меняется при прокрутке — ничего не прыгает. */
.sabar, .safind__x, .sasheet { display: none; }

@media (max-width: 760px) {
  body:has(.sadesk) > header { display: none; }
  body:has(.sadesk) .netbar { top: 0; padding-top: calc(8px + env(safe-area-inset-top)); }
  html.sa-lock body { overflow: hidden; }

  .sadesk { display: block; }

  /* Верхняя панель */
  .sabar {
    position: sticky; top: 0; z-index: 30;
    display: grid; grid-template-columns: 44px minmax(0, 1fr) 44px; align-items: center;
    height: calc(52px + env(safe-area-inset-top));
    margin-inline: calc(50% - 50vw);
    padding: env(safe-area-inset-top) max(6px, env(safe-area-inset-right)) 0 max(6px, env(safe-area-inset-left));
    background: color-mix(in srgb, var(--canvas) 92%, transparent);
    -webkit-backdrop-filter: saturate(1.8) blur(18px); backdrop-filter: saturate(1.8) blur(18px);
    transition: box-shadow .2s ease;
  }
  .samain:has(.sasegs[hidden]) .sabar.is-small { box-shadow: 0 1px 0 var(--line); }
  .sabar .sabar__b {
    grid-row: 1; display: grid; place-items: center;
    width: 44px; height: 44px; min-height: 44px; padding: 0;
    border: 0; border-radius: 14px; background: transparent; box-shadow: none; color: var(--ink);
    transition: background var(--fast), transform var(--fast);
  }
  .sabar__b .ic { width: 22px; height: 22px; }
  .sabar__b:active { background: color-mix(in srgb, var(--ink) 8%, transparent); transform: scale(.92); }
  .sabar__b[hidden] { display: none; }
  .sabar__back { grid-column: 1; }
  .sabar__find { grid-column: 3; }
  .sabar__logo { grid-column: 1; grid-row: 1; justify-self: center; height: 22px; width: auto; filter: invert(1); opacity: .85; }
  .sabar__back:not([hidden]) ~ .sabar__logo { display: none; }
  .sabar__title {
    grid-column: 2; grid-row: 1; text-align: center;
    font: 600 1rem/1.2 var(--sans); letter-spacing: -.015em; color: var(--ink);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    opacity: 0; transform: translateY(8px);
    transition: opacity .2s ease, transform .3s cubic-bezier(.2, .8, .2, 1);
  }
  .sabar.is-small .sabar__title { opacity: 1; transform: none; }

  /* Крупный заголовок — уезжает со страницей */
  .satop { position: static; display: block; padding: 2px 0 14px; background: transparent; box-shadow: none; }
  .satitle small { margin-bottom: 4px; font-size: .8rem; font-weight: 600; color: var(--ink-3); }
  .satitle h1 { font-size: 2rem; font-weight: 700; letter-spacing: -.035em; line-height: 1.1; }

  /* Поиск во весь экран */
  .samain:not(.is-finding) .safind { display: none; }
  .samain.is-finding .safind {
    position: fixed; inset: 0; z-index: 60; display: block; margin: 0; min-width: 0;
    padding: calc(8px + env(safe-area-inset-top)) 16px 0;
    background: var(--canvas);
    animation: sa-find .22s cubic-bezier(.2, .8, .2, 1) both;
  }
  .samain.is-finding .safind__ic { left: 29px; top: calc(29px + env(safe-area-inset-top)); }
  .samain.is-finding .safind input { width: calc(100% - 78px); min-height: 42px; font-size: 1rem; box-shadow: none; }
  .safind__key { display: none; }
  .samain.is-finding .safind .safind__x {
    display: block; position: absolute; right: 8px; top: calc(8px + env(safe-area-inset-top));
    min-height: 42px; padding: 0 10px; border: 0; background: transparent; box-shadow: none;
    color: var(--info); font: 600 .95rem/1 var(--sans);
  }
  .samain.is-finding .safind__out {
    position: static; margin-top: 12px;
    max-height: calc(100dvh - 84px - env(safe-area-inset-top)); border-radius: 16px; box-shadow: none;
  }
  .safind__r { min-height: 56px; }

  /* Полки — прилипают под панелью */
  .sasegs {
    position: sticky; top: calc(52px + env(safe-area-inset-top)); z-index: 29;
    display: flex; gap: 6px; overflow-x: auto; flex-wrap: nowrap; scrollbar-width: none;
    scroll-snap-type: x proximity; scroll-padding-inline: 16px;
    margin-inline: calc(50% - 50vw); padding: 4px 16px 10px;
    background: color-mix(in srgb, var(--canvas) 92%, transparent);
    -webkit-backdrop-filter: saturate(1.8) blur(18px); backdrop-filter: saturate(1.8) blur(18px);
    box-shadow: 0 1px 0 var(--line); border: 0;
  }
  .sasegs[hidden] { display: none; }
  .sasegs::-webkit-scrollbar { display: none; }
  .sasegs a {
    flex: none; scroll-snap-align: start;
    display: inline-flex; align-items: center; min-height: 36px; padding: 0 15px;
    border-radius: var(--r-pill); color: var(--ink-2); text-decoration: none; white-space: nowrap;
    font: 500 .88rem/1.2 var(--sans); background: var(--surface); box-shadow: inset 0 0 0 1px var(--line);
    transition: background .2s ease, color .2s ease, transform var(--fast);
  }
  .sasegs a:active { transform: scale(.95); }
  .sasegs a[aria-current="true"] { background: var(--ink); color: var(--surface); box-shadow: none; font-weight: 600; }
  #sa { padding-top: 16px; }

  /* Нижняя панель — плавающая, с подсветкой-пилюлей под иконкой */
  .saroom {
    position: fixed; z-index: 40; top: auto;
    left: max(10px, env(safe-area-inset-left)); right: max(10px, env(safe-area-inset-right));
    bottom: max(10px, env(safe-area-inset-bottom));
    display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0;
    max-height: none; overflow: visible; padding: 5px;
    border-radius: 24px; border: 0;
    background: color-mix(in srgb, var(--surface) 84%, transparent);
    -webkit-backdrop-filter: saturate(1.8) blur(20px); backdrop-filter: saturate(1.8) blur(20px);
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--ink) 7%, transparent), 0 14px 34px -12px rgba(27, 31, 36, .32);
  }
  .saroom__segs, .saroom__extra { display: none; }
  .saroom > .saroom__b, .saroom__more {
    position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
    min-height: 54px; padding: 6px 2px 4px; border-radius: 18px;
    background: transparent !important; box-shadow: none !important;
    color: var(--ink-3); font: 600 .66rem/1.1 var(--sans); letter-spacing: -.005em;
    transition: color .2s ease, transform var(--fast);
  }
  .saroom > .saroom__b::before, .saroom__more::before {
    content: ''; position: absolute; top: 4px; left: 50%; width: 54px; height: 30px;
    border-radius: 999px; background: var(--info-bg);
    transform: translateX(-50%) scaleX(.4); opacity: 0;
    transition: transform .32s cubic-bezier(.2, .9, .25, 1.2), opacity .2s ease;
  }
  .saroom > .saroom__b .ic, .saroom__more .ic { position: relative; width: 22px; height: 22px; color: inherit; }
  .saroom > .saroom__b span:not(.count), .saroom__more span { position: relative; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
  .saroom > .saroom__b[aria-current="true"], .saroom__more[aria-current="true"] { color: var(--ink); }
  .saroom > .saroom__b[aria-current="true"] .ic, .saroom__more[aria-current="true"] .ic { color: var(--info); }
  .saroom > .saroom__b[aria-current="true"]::before, .saroom__more[aria-current="true"]::before { transform: translateX(-50%); opacity: 1; }
  .saroom > .saroom__b:active, .saroom__more:active { transform: scale(.92); }
  .saroom > .saroom__b .count {
    position: absolute; z-index: 1; top: 1px; left: calc(50% + 7px); margin: 0;
    min-width: 18px; padding: 0 5px; font-size: .62rem; line-height: 18px;
    box-shadow: 0 0 0 2px var(--surface);
  }
  body:has(.saroom) main { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
  body:has(.saroom) #toast { bottom: calc(96px + env(safe-area-inset-bottom)); }

  /* Лист «Ещё» */
  .sasheet {
    display: block; position: fixed; inset: 0; z-index: 70;
    background: rgba(10, 11, 13, 0); transition: background .26s ease;
  }
  .sasheet[hidden] { display: none; }
  .sasheet.is-open { background: rgba(10, 11, 13, .42); }
  .sasheet__card {
    position: absolute; left: max(8px, env(safe-area-inset-left)); right: max(8px, env(safe-area-inset-right));
    bottom: max(8px, env(safe-area-inset-bottom));
    padding: 8px 12px 10px; border-radius: 26px; background: var(--surface);
    box-shadow: 0 -10px 40px -12px rgba(10, 11, 13, .35);
    transform: translateY(calc(100% + 24px));
    transition: transform .34s cubic-bezier(.2, .9, .25, 1);
  }
  .sasheet.is-open .sasheet__card { transform: none; }
  .sasheet__grip { display: block; width: 38px; height: 5px; margin: 2px auto 14px; border-radius: 9px; background: var(--line-strong); }
  .sasheet__tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
  .satile {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
    min-height: 90px; padding: 10px 6px; border-radius: 18px;
    background: var(--surface-2); color: var(--ink); text-decoration: none;
    font: 600 .8rem/1.15 var(--sans); text-align: center;
    transition: transform var(--fast), background var(--fast);
  }
  .satile .ic { width: 24px; height: 24px; color: var(--ink-2); }
  .satile .count { display: none; }
  .satile:active { transform: scale(.95); }
  .satile[aria-current="true"] { background: var(--info-bg); color: var(--info); }
  .satile[aria-current="true"] .ic { color: var(--info); }
  .sasheet__me {
    display: flex; align-items: center; gap: 12px;
    margin-top: 12px; padding: 14px 6px 8px; border-top: 1px solid var(--line);
  }
  .sasheet__ava {
    display: grid; place-items: center; flex: none; width: 42px; height: 42px; border-radius: 50%;
    background: linear-gradient(135deg, var(--info), color-mix(in srgb, var(--info) 60%, #000));
    color: #fff; font: 700 1.05rem/1 var(--sans); text-transform: uppercase;
  }
  .sasheet__me b { display: block; font-size: .98rem; }
  .sasheet__me em { display: block; font-style: normal; font-size: .8rem; color: var(--ink-3); }
  .sasheet .sasheet__row {
    display: flex; align-items: center; gap: 12px; width: 100%; min-height: 50px; padding: 0 12px;
    border: 0; border-radius: 14px; background: transparent; box-shadow: none;
    color: var(--ink); font: 500 .95rem/1.2 var(--sans); text-align: left;
  }
  .sasheet__row[hidden] { display: none; }
  .sasheet__row .ic { width: 20px; height: 20px; color: var(--ink-3); }
  .sasheet__row:active { background: var(--surface-2); }
  .sasheet .sasheet__row--out, .sasheet__row--out .ic { color: var(--stop); }

  /* Своё «← Назад» одолженных экранов — в панели сверху */
  /* Широкая таблица не обрезается краем карточки — листается вбок. */
  .sadesk .bsec__body { overflow-x: auto; overscroll-behavior-x: contain; }

  .sadesk #admBack, .sadesk #backPeople { display: none; }
  .sadesk .row:has(> #cBack:only-child) { display: none; }
}
@keyframes sa-find { from { opacity: 0; transform: translateY(-8px); } }
@media (prefers-reduced-motion: reduce) {
  .sabar__title, .saroom > .saroom__b::before, .saroom__more::before, .sasheet, .sasheet__card { transition: none; }
  .samain.is-finding .safind { animation: none; }
}


/* ─────────── телефон: строки очереди и вкладки ───────────
   На 375px третья колонка «время + сумма» забирала всю ширину, причина сжималась
   в ноль и налезала на дату. На телефоне причина и время — каждая своей строкой. */
@media (max-width: 560px) {
  .task--q .task__why { grid-column: 2 / -1; }
  .task--q .task__ago {
    grid-column: 2 / -1; justify-content: flex-start; flex-wrap: wrap;
    column-gap: 6px; row-gap: 0; text-align: left;
  }
  .task--q .task__ago .sum { margin-left: auto; }
  /* Вкладки лентой, а не столбиком слов: «Alınıb və yoldadır» переносилось в три строки. */
  .tabs { scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs button { flex: none; white-space: nowrap; }
}

/* ─── касса: смена ───
   Экран кассы перестал быть списком с вкладками. Три зоны: плитки дня, окно (одно дело —
   одна строка, откуда бы оно ни пришло) и лента движений. Лента стоит справа и не
   листается вместе со списком: это то, что кассир проверяет глазами, не отрываясь
   от клиента. На узком экране она уходит вниз — у окна сначала люди, потом история. */

.tillmain { display: grid; gap: var(--s4); grid-template-columns: minmax(0, 1fr) 320px; align-items: start; }
.tillwork { display: grid; gap: var(--s3); min-width: 0; }
@media (max-width: 900px) { .tillmain { grid-template-columns: minmax(0, 1fr); } }

.tape {
  padding: var(--s3) var(--s4); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow-1);
  max-height: 70vh; overflow: auto;
}
.tape h3 { margin: 0 0 2px; font-size: 1rem; }
.tape .hint { margin: 0 0 10px; }
.tape__row { display: flex; align-items: baseline; gap: 8px; padding: 6px 0; border-top: 1px solid var(--line); }
.tape__t { font: .72rem/1 var(--mono); color: var(--ink-3); flex: 0 0 auto; }
.tape__what { flex: 1; min-width: 0; font-size: .85rem; }
.tape__what small { display: block; color: var(--ink-3); font-size: .72rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tape__row b { font-family: var(--mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
.tape__row.is-in b { color: var(--go); }
.tape__row.is-out b { color: var(--ink-2); }

/* Касса закрыта. Дверь, а не заглушка: единственная кнопка — первый пересчёт дня. */
.gate {
  max-width: 560px; margin: 8vh auto 0; display: grid; gap: var(--s3); justify-items: center;
  text-align: center; padding: var(--s5) var(--s4);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}
.gate .ic { width: 34px; height: 34px; color: var(--ink-3); }
.gate__name { font-size: 1.5rem; font-weight: 600; }
.gate__sub { color: var(--ink-2); margin: 0; max-width: 46ch; }
.gate .stats { margin: 4px 0; }

/* Акт смены: столбец «строка — сумма», как в бумаге, которая из него печатается. */
.act { display: grid; gap: 2px; margin: 12px 0; }
.actrow { display: flex; justify-content: space-between; gap: 14px; padding: 5px 0;
  border-bottom: 1px solid var(--line); font-size: .9rem; }
.actrow b { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.actrow--tot { border-bottom: none; border-top: 2px solid var(--ink); font-size: 1.05rem; font-weight: 600; }
.actrow--diff b { color: var(--stop); }

.buylist > summary { cursor: pointer; padding: 8px 0; color: var(--ink-2); font-size: .9rem; }

/* ═══════════════════ «Консоль» — рабочее место стойки ═══════════════════

   Третий набор значений поверх той же структуры, что «воздух» и «пузырь»
   (см. :is(...) выше — селекторы перечисляют все три скина). Меняются только
   значения переменных и добавляются части, которых раньше не было вовсе:
   боковая колонка, поиск в шапке и палитра команд.

   Почему не «пузырь». Сиреневое полотно и фиолетовый акцент — это громкость,
   выкрученная ради бодрости; на экране, который открыт восемь часов и в котором
   считают чужие деньги, бодрость через неделю читается как несерьёзность.
   Стандарт выбран владельцем и уже стоит на приёмке магазина (site/receiver):
   светлая рабочая консоль уровня Linear и Notion — нейтральное полотно, индиго
   как единственный акцент интерфейса, тонкие разделители, скругления строже.

   Смысл четырёх цветов не тронут: зелёный — твой ход, индиго — система и выбор,
   жёлтый — ждём, красный — нельзя. Меняются оттенки, не значения. */
[data-skin="console"] {
  --canvas: #f6f7f9;
  --surface: #ffffff;
  --surface-2: #f1f3f6;
  /* Вторая нейтральная плоскость: боковая колонка чуть холоднее полотна, иначе
     колонка и содержимое сливаются в одно поле без края. */
  --rail: #f2f4f7;

  --ink: #1b1f24;
  --ink-2: #565b66;   /* 7.0:1 на белом */
  --ink-3: #6b7079;   /* 5.4:1 — подпись под числом читают под углом и с метра */
  --line: #e9ebef;
  --line-strong: #dbdee4;

  /* Индиго — акцент интерфейса: фокус, выбор, текущая комната, выделение текста.
     Ровно та же роль, что была у синего и у фиолетового: «система, а не ваш ход». */
  --info: #4c5fd5;
  --info-bg: #eef0fc;
  --info-line: #ccd3f6;

  --go: #1a9d63;
  --go-bg: #e7f6ef;
  --go-line: #b8e4cd;
  --go-hover: #157f50;

  --wait: #b3760f;
  --wait-bg: #fbf1de;
  --wait-line: #f0d7a8;

  --stop: #d3453b;
  --stop-bg: #fdece9;
  --stop-line: #f4c4bd;

  /* Скругления строже «воздуха» (16/12/8 → 12/8/6): у таблицы сумм скругление
     работает интонацией, и чем оно мягче, тем менее серьёзно читается число. */
  --r-lg: 12px;
  --r: 8px;
  --r-sm: 6px;

  --shadow-1: 0 1px 2px rgba(27, 31, 36, .05);
  --shadow-2: 0 12px 28px -14px rgba(27, 31, 36, .28), 0 2px 6px -2px rgba(27, 31, 36, .07);
  --shadow-go: 0 1px 2px rgba(27, 31, 36, .08);

  --sans: Inter, ui-sans-serif, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;

  --head-h: 52px;
  --rail-w: 224px;
}

/* Поверхности, которые рисует браузер, а не мы: выделение, каретка, полоса прокрутки,
   кольцо фокуса. По умолчанию они принадлежат операционной системе, а не этой. */
[data-skin="console"] ::selection { background: var(--info-bg); color: var(--ink); }
[data-skin="console"] { accent-color: var(--info); caret-color: var(--info); }
[data-skin="console"] * { scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; }
[data-skin="console"] *::-webkit-scrollbar { width: 10px; height: 10px; }
[data-skin="console"] *::-webkit-scrollbar-thumb {
  background: var(--line-strong); border-radius: 999px;
  border: 3px solid transparent; background-clip: content-box;
}
[data-skin="console"] *::-webkit-scrollbar-thumb:hover { background: var(--ink-3); background-clip: content-box; }
[data-skin="console"] *:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; }
[data-skin="console"] input:focus,
[data-skin="console"] select:focus,
[data-skin="console"] textarea:focus {
  border-color: var(--info);
  box-shadow: 0 0 0 3px var(--info-bg);
}

/* ─────────── шапка: узкая полоса приложения, а не вывеска ─────────── */
[data-skin="console"] header {
  min-height: var(--head-h);
  padding: 0 var(--s3) 0 var(--s4);
  gap: var(--s3);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  box-shadow: none;
}
[data-skin="console"] header .brand { height: 20px; }
[data-skin="console"] header > b { font-size: .875rem; font-weight: 600; letter-spacing: -.01em; }
[data-skin="console"] header #who {
  margin-left: 0; font-size: .8125rem; color: var(--ink-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 22ch;
}
[data-skin="console"] header button { min-height: 32px; padding: 5px 12px; font-size: .8125rem; }

/* ─────────── поиск в шапке: один на всё приложение ───────────
   Раньше поле жило на экране очереди: открыл карточку заявки — искать стало нечем,
   и чтобы найти второй талон, надо было выйти назад. Теперь оно в шапке и видно
   отовсюду, включая приём аппарата и справочник. */
.deskfind { position: relative; flex: 1 1 auto; min-width: 0; max-width: 520px; margin-left: var(--s2); }
.deskfind__ic {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--ink-3); pointer-events: none;
}
.deskfind input {
  width: 100%; min-height: 34px; padding: 6px 64px 6px 32px;
  border-radius: var(--r-sm); background: var(--surface-2);
  border: 1px solid transparent; font-size: .875rem;
}
.deskfind input:hover { border-color: var(--line-strong); }
.deskfind input:focus { background: var(--surface); }
.deskfind__key {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  display: inline-flex; gap: 2px; align-items: center;
  font: 500 11px/1 var(--sans); color: var(--ink-3);
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--r-sm); padding: 3px 5px; pointer-events: none;
  transition: opacity var(--fast);
}
.deskfind input:focus ~ .deskfind__key { opacity: 0; }
.deskfind__out {
  position: absolute; z-index: 40; top: calc(100% + 6px); left: 0; right: 0;
  max-height: min(62vh, 460px); overflow: auto;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--shadow-2); padding: 4px;
}
.deskfind__r {
  display: flex; gap: 10px; align-items: center; width: 100%;
  padding: 8px 10px; border-radius: var(--r-sm); text-decoration: none; color: var(--ink);
  background: none; border: 0; text-align: left; cursor: pointer;
}
.deskfind__r .ic { width: 16px; height: 16px; color: var(--ink-3); flex: 0 0 auto; }
.deskfind__r span { min-width: 0; }
.deskfind__r b { display: block; font-weight: 600; font-size: .875rem; }
.deskfind__r em {
  display: block; font-style: normal; font-size: var(--fs-floor); color: var(--ink-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.deskfind__r:hover,
.deskfind__r[aria-selected="true"] { background: var(--info-bg); }
.deskfind__r[aria-selected="true"] .ic { color: var(--info); }
.deskfind__none { margin: 0; padding: 14px 12px; color: var(--ink-3); font-size: .875rem; }

/* Кнопка приёма — стоячее действие рабочего места, а не «ваш ход» по конкретной
   заявке, поэтому она не зелёная: зелёный в этой системе занят смыслом. */
.btn-strong {
  background: var(--ink); color: var(--surface); border: 1px solid var(--ink);
  font-weight: 600; white-space: nowrap;
  /* Иконка рядом с текстом, а не над ним: блочная кнопка ставила значок отдельной
     строкой, и в шапке он обрезался по высоте. */
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
}
.btn-strong:hover { background: #0f1216; border-color: #0f1216; }
.btn-strong .ic { width: 16px; height: 16px; }

/* ─────────── боковая колонка: где я, и что там ждёт ─────────── */
[data-skin="console"] .deskwrap{ display: grid; grid-template-columns: var(--rail-w) minmax(0, 1fr); align-items: start; }
[data-skin="console"] .rail{
  position: sticky; top: var(--head-h);
  height: calc(100dvh - var(--head-h));
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--s3) var(--s2);
  background: var(--rail); border-right: 1px solid var(--line);
  overflow-y: auto;
}
[data-skin="console"] .rail__nav{ display: flex; flex-direction: column; gap: 1px; }
[data-skin="console"] .rail__sep{ margin: var(--s2) 8px; border: 0; border-top: 1px solid var(--line-strong); opacity: .7; }
[data-skin="console"] .rail__foot{ margin-top: auto; padding-top: var(--s3); }
[data-skin="console"] .rail__cap{
  margin: 0 0 4px; padding: 0 10px;
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink-3);
}
[data-skin="console"] .rail a, [data-skin="console"] .rail button.rail__b{
  display: flex; align-items: center; gap: 10px;
  min-height: 34px; padding: 6px 10px;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: none; color: var(--ink-2); font: 500 .875rem/1.3 var(--sans);
  text-decoration: none; text-align: left; cursor: pointer;
  transition: background var(--fast), color var(--fast);
}
[data-skin="console"] .rail a .ic, [data-skin="console"] .rail button.rail__b .ic{ width: 17px; height: 17px; color: var(--ink-3); flex: 0 0 auto; }
[data-skin="console"] .rail a > span, [data-skin="console"] .rail button.rail__b > span{ min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
[data-skin="console"] .rail a:hover, [data-skin="console"] .rail button.rail__b:hover{ background: rgba(27, 31, 36, .05); color: var(--ink); }
[data-skin="console"] .rail a:hover .ic, [data-skin="console"] .rail button.rail__b:hover .ic{ color: var(--ink-2); }
[data-skin="console"] .rail a[aria-current="true"]{
  background: var(--surface); color: var(--ink); font-weight: 600;
  border-color: var(--line); box-shadow: var(--shadow-1);
}
[data-skin="console"] .rail a[aria-current="true"] .ic{ color: var(--info); }
[data-skin="console"] .rail .badge{
  margin-left: auto; flex: 0 0 auto;
  min-width: 20px; padding: 1px 6px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink-2);
  font: 600 11px/1.6 var(--sans); text-align: center;
  font-variant-numeric: tabular-nums;
}
[data-skin="console"] .rail a[aria-current="true"] .badge{ background: var(--canvas); }
[data-skin="console"] .rail .badge--hot{ background: var(--stop-bg); color: var(--stop); }
[data-skin="console"] .rail .badge:empty{ display: none; }

/* Плотность экрана — настройка вида, и живёт она среди настроек, а не среди разделов.
   Раньше она лежала последним пунктом того же списка, что и «Гарантия». */
[data-skin="console"] .rail__dens{ display: flex; gap: 4px; padding: 0 6px; }
[data-skin="console"] .rail__dens button{
  flex: 1; min-height: 28px; padding: 4px 6px;
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink-2); font: 500 12px/1 var(--sans);
}
[data-skin="console"] .rail__dens button[aria-pressed="true"]{
  background: var(--info-bg); border-color: var(--info-line); color: var(--info); font-weight: 600;
}

/* ─────────── содержимое комнаты ─────────── */
[data-skin="console"] .deskmain{ min-width: 0; padding: 0 var(--s5) var(--s6); }
[data-skin="console"] .deskmain > #work{ padding-top: var(--s4); }
/* Полки комнаты: то же, что вкладки, но они принадлежат комнате, а не экрану. */
[data-skin="console"] .shelfs{
  display: flex; gap: 2px; align-items: center;
  margin: 0 calc(var(--s5) * -1); padding: 0 var(--s5);
  border-bottom: 1px solid var(--line);
  overflow-x: auto; scrollbar-width: none;
}
[data-skin="console"] .shelfs::-webkit-scrollbar{ display: none; }
[data-skin="console"] .shelfs button{
  position: relative; flex: 0 0 auto;
  min-height: 40px; padding: 10px 12px;
  background: none; border: 0; border-radius: 0;
  color: var(--ink-2); font: 500 .875rem/1.2 var(--sans); white-space: nowrap;
}
[data-skin="console"] .shelfs button:hover{ background: transparent; color: var(--ink); }
[data-skin="console"] .shelfs button[aria-selected="true"]{ color: var(--ink); font-weight: 600; }
[data-skin="console"] .shelfs button[aria-selected="true"]::after{
  content: ''; position: absolute; left: 10px; right: 10px; bottom: -1px;
  height: 2px; background: var(--info); border-radius: 2px 2px 0 0;
}
[data-skin="console"] .shelfs .count{
  margin-left: 6px; padding: 1px 6px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink-2); font: 600 11px/1.6 var(--sans);
}
[data-skin="console"] .shelfs button[aria-selected="true"] .count{ background: var(--info-bg); color: var(--info); }

/* ─────────── палитра команд ───────────
   Одной рукой: вторая держит телефон клиента. Ctrl+K открывает список того, что
   вообще можно сделать, — и там же ищутся заявки и люди. Человек не обязан
   помнить, где лежит кнопка, если может назвать действие словом. */
[data-skin="console"] dialog.pal{
  width: min(620px, calc(100vw - 32px)); max-height: 70vh;
  margin: 12vh auto auto; padding: 0;
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--surface); box-shadow: var(--shadow-2);
  overflow: hidden;
}
[data-skin="console"] dialog.pal::backdrop{ background: rgba(27, 31, 36, .28); }
[data-skin="console"] .pal__in{ display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-bottom: 1px solid var(--line); }
[data-skin="console"] .pal__in .ic{ width: 18px; height: 18px; color: var(--ink-3); flex: 0 0 auto; }
[data-skin="console"] .pal__in input{
  flex: 1; min-height: 28px; padding: 2px 0;
  border: 0; background: none; font-size: 1rem; color: var(--ink);
}
[data-skin="console"] .pal__in input:focus{ box-shadow: none; border: 0; }
[data-skin="console"] .pal__out{ max-height: calc(70vh - 58px); overflow: auto; padding: 6px; }
[data-skin="console"] .pal__cap{
  margin: 8px 8px 2px; font-size: 11px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
}
[data-skin="console"] .pal__r{
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 10px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--ink); text-align: left; cursor: pointer;
}
[data-skin="console"] .pal__r .ic{ width: 16px; height: 16px; color: var(--ink-3); flex: 0 0 auto; }
[data-skin="console"] .pal__r span{ min-width: 0; }
[data-skin="console"] .pal__r b{ display: block; font-weight: 600; font-size: .9rem; }
[data-skin="console"] .pal__r em{
  display: block; font-style: normal; font-size: var(--fs-floor); color: var(--ink-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
[data-skin="console"] .pal__r[aria-selected="true"]{ background: var(--info-bg); }
[data-skin="console"] .pal__r[aria-selected="true"] .ic{ color: var(--info); }
[data-skin="console"] .pal__r kbd{
  margin-left: auto; font: 500 11px/1 var(--sans); color: var(--ink-3);
  background: var(--surface-2); border: 1px solid var(--line-strong);
  border-radius: var(--r-sm); padding: 3px 5px;
}
[data-skin="console"] .pal__none{ margin: 0; padding: 18px 14px; color: var(--ink-3); font-size: .875rem; }

/* ─────────── комната «Сегодня» ───────────
   Не витрина с числами: число стоит в строке, к которой относится, и строка ведёт
   в список. Сводка, в которой нечего нажать, за неделю перестаёт открываться. */
[data-skin="console"] .today{ display: grid; gap: var(--s5); max-width: 1100px; }
[data-skin="console"] .today__head{ display: flex; flex-wrap: wrap; gap: var(--s3); align-items: baseline; }
[data-skin="console"] .today__head h2{ margin: 0; font-size: 1.5rem; letter-spacing: -.025em; }
[data-skin="console"] .today__date{ color: var(--ink-3); font-size: .875rem; }
[data-skin="console"] .today__shift{
  display: flex; flex-wrap: wrap; gap: var(--s2) var(--s4); align-items: center;
  padding: 10px var(--s4); border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); font-size: .875rem; color: var(--ink-2);
}
[data-skin="console"] .today__shift b{ color: var(--ink); font-weight: 600; }
[data-skin="console"] .today__shift .dot{
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--go); margin-right: 6px; vertical-align: 1px;
}
[data-skin="console"] .today__shift .dot--off{ background: var(--ink-3); }
[data-skin="console"] .today__sec > h3{
  display: flex; align-items: baseline; gap: 8px;
  margin: 0 0 var(--s3); font-size: var(--fs-heading); font-weight: 600;
}
[data-skin="console"] .today__sec > h3 small{ font-weight: 500; font-size: var(--fs-floor); color: var(--ink-3); }
[data-skin="console"] .today__grid{ display: grid; gap: var(--s4); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
[data-skin="console"] .tally{ display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
[data-skin="console"] .tally a{
  display: flex; align-items: baseline; gap: 10px;
  padding: 11px var(--s4); background: var(--surface);
  color: var(--ink); text-decoration: none; font-size: .875rem;
  transition: background var(--fast);
}
[data-skin="console"] .tally a:hover{ background: var(--surface-2); }
[data-skin="console"] .tally b{ font-size: 1.125rem; font-weight: 700; letter-spacing: -.02em; min-width: 2.5ch; }
[data-skin="console"] .tally span{ color: var(--ink-2); }
[data-skin="console"] .tally .arrow{ margin-left: auto; color: var(--ink-3); opacity: 0; transition: opacity var(--fast); }
[data-skin="console"] .tally a:hover .arrow,
[data-skin="console"] .tally a:focus-visible .arrow { opacity: 1; }
[data-skin="console"] .tally a.is-hot b{ color: var(--stop); }
[data-skin="console"] .tally a.is-wait b{ color: var(--wait); }

/* ─────────── карточка клиента: одна на все входы ─────────── */
[data-skin="console"] .cli{ display: grid; gap: var(--s5); max-width: 1100px; }
[data-skin="console"] .cli__head{ display: flex; flex-wrap: wrap; gap: var(--s3); align-items: flex-start; }
[data-skin="console"] .cli__head h2{ margin: 0 0 2px; font-size: 1.5rem; letter-spacing: -.025em; }
[data-skin="console"] .cli__head p{ margin: 0; color: var(--ink-2); font-size: .875rem; }
[data-skin="console"] .cli__acts{ display: flex; flex-wrap: wrap; gap: var(--s2); margin-left: auto; }
[data-skin="console"] .cli__cols{ display: grid; gap: var(--s5); grid-template-columns: minmax(0, 1fr) 300px; align-items: start; }
[data-skin="console"] .cli__note{
  margin: 0; padding: var(--s3) var(--s4); white-space: pre-wrap;
  border: 1px solid var(--line); border-radius: var(--r); background: var(--surface);
  font-size: .875rem;
}
[data-skin="console"] .cli__note .hint{ margin: 0; }

@media (max-width: 1060px) { [data-skin="console"] .cli__cols { grid-template-columns: minmax(0, 1fr); } }

/* ─────────── узкий экран: колонка ложится сверху лентой ─────────── */
@media (max-width: 900px) {
  [data-skin="console"] .deskwrap { grid-template-columns: minmax(0, 1fr); }
  [data-skin="console"] .rail {
    position: sticky; top: var(--head-h); z-index: 20;
    flex-direction: row; align-items: center; gap: 4px;
    height: auto; overflow-x: auto; overflow-y: hidden;
    padding: 6px var(--s3); border-right: 0; border-bottom: 1px solid var(--line);
    scrollbar-width: none;
  }
  [data-skin="console"] .rail::-webkit-scrollbar { display: none; }
  [data-skin="console"] .rail__nav { flex-direction: row; gap: 2px; }
  [data-skin="console"] .rail a { white-space: nowrap; }
  [data-skin="console"] .rail__sep, [data-skin="console"] .rail__cap { display: none; }
  [data-skin="console"] .rail__foot { margin: 0 0 0 auto; padding: 0; display: flex; gap: 4px; }
  [data-skin="console"] .rail__dens { display: none; }
  [data-skin="console"] .deskmain { padding: 0 var(--s4) var(--s6); }
  [data-skin="console"] .shelfs { margin: 0 calc(var(--s4) * -1); padding: 0 var(--s4); }
  [data-skin="console"] .deskfind { max-width: none; }
  [data-skin="console"] .deskfind__key { display: none; }
}
@media (max-width: 560px) {
  [data-skin="console"] header > b { display: none; }
  [data-skin="console"] header #who { display: none; }
  [data-skin="console"] .btn-strong span.lbl { display: none; }
}
/* ─────────── одно движение и одна кривая ───────────

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

   Играет только на переходе (класс ставит admin(), см. app.js): лента заявок
   перерисовывает себя каждые полторы секунды, и движение на каждой перерисовке
   было бы не смыслом, а миганием. */
@keyframes deskSwap {
  from { opacity: .45; transform: translateY(5px); }
  to   { opacity: 1; transform: none; }
}
[data-skin="console"] #work.is-swap { animation: deskSwap 220ms cubic-bezier(.16, 1, .3, 1); }

@keyframes palIn {
  from { opacity: 0; transform: translateY(-6px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
[data-skin="console"] dialog.pal { animation: palIn 160ms cubic-bezier(.16, 1, .3, 1); }
[data-skin="console"] dialog.pal::backdrop { animation: palIn 160ms ease-out; }

@media (prefers-reduced-motion: reduce) {
  [data-skin="console"] .rail a, [data-skin="console"] .tally a, [data-skin="console"] .deskfind__key { transition: none; }
  [data-skin="console"] #work.is-swap,
  [data-skin="console"] dialog.pal,
  [data-skin="console"] dialog.pal::backdrop { animation: none; }
}

/* Разбивка по дням: колонка цифр не показывает разницу между «двести» и «две тысячи»,
   пока не прочитаешь их все. Полоска под числом прибыли даёт эту разницу глазом за
   мгновение. Она под числом, а не вместо него: считают всё-таки по числу. */
.byday__bar {
  display: block; height: 3px; margin-top: 3px; margin-left: auto;
  border-radius: 2px; background: var(--info); min-width: 2px;
}
.byday__bar.is-neg { background: var(--stop); }
.byday b.is-neg { color: var(--stop); }

/* ─────────── кошелёк: карты, итог, выписка ───────────
   Карта — плитка своего цвета (--wc), чтобы две карты одного банка различались глазом,
   а не только подписью. Число — моноширинным, как все деньги в системе. */
.whero { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: var(--s4) var(--s5);
  padding: var(--s5); border-radius: var(--r-lg); background: var(--chrome); color: #fff; margin-bottom: var(--s4); }
.whero .hint { color: rgba(255, 255, 255, .7); }
.whero__label { display: block; font-size: .8rem; letter-spacing: .06em; text-transform: uppercase; opacity: .7; }
.whero__sum { display: block; font-family: var(--mono); font-size: clamp(2rem, 6vw, 3.2rem); letter-spacing: -.05em;
  line-height: 1.05; margin: 6px 0 8px; }
.whero__sum small { font-size: .5em; opacity: .7; }
.whero__flow { display: grid; gap: 10px; align-content: center; }
.whero__flow > div { display: grid; grid-template-columns: repeat(3, auto); justify-content: start; gap: 2px 14px;
  align-items: baseline; padding: 10px 14px; border-radius: var(--r); background: rgba(255, 255, 255, .07); }
.whero__flow span { grid-column: 1 / -1; font-size: .78rem; opacity: .75; }
.whero__flow b, .whero__flow em { font-family: var(--mono); font-style: normal; font-size: .9rem; }
.whero__flow .pos { color: #8fe0b5; } .whero__flow .neg { color: #ffb3a8; }
.whero__trend { grid-column: 1 / -1; }
.whero__trend .chart__line { stroke: #8fe0b5; } .whero__trend .chart__area { fill: rgba(143, 224, 181, .14); }
.whero__trend .chart__axis { color: rgba(255, 255, 255, .6); }
.pos { color: var(--go); } .neg { color: var(--stop); }

.wpos { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s3); }
.wpos__i { padding: var(--s4); border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); display: grid; gap: 4px; }
.wpos__i span { font-size: .82rem; color: var(--ink-2); }
.wpos__i b { font-family: var(--mono); font-size: 1.35rem; letter-spacing: -.04em; }
.wpos__i small { color: var(--ink-3); font-size: .76rem; }
.wpos__i--net { background: var(--surface-2); border-color: var(--line-strong); }

.wgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: var(--s3); }
.wcard { --wc: #186b46; all: unset; box-sizing: border-box; cursor: pointer; display: grid; gap: 6px;
  min-height: 150px; padding: 16px 18px; border-radius: 16px; color: #fff; position: relative; overflow: hidden;
  background: linear-gradient(135deg, var(--wc), color-mix(in srgb, var(--wc) 62%, #000));
  box-shadow: var(--shadow-2); transition: transform .15s ease, box-shadow .15s ease; }
.wcard::after { content: ''; position: absolute; right: -40px; top: -40px; width: 140px; height: 140px;
  border-radius: 50%; background: rgba(255, 255, 255, .08); pointer-events: none; }
.wcard:hover { transform: translateY(-2px); }
.wcard:focus-visible { outline: 3px solid var(--info); outline-offset: 2px; }
.wcard--off { filter: grayscale(.8); opacity: .7; }
.wcard__top { display: flex; justify-content: space-between; font-size: .78rem; opacity: .85; }
.wcard__kind { text-transform: uppercase; letter-spacing: .08em; font-size: .68rem; }
.wcard__name { font-weight: 600; font-size: 1rem; }
.wcard__bal { font-family: var(--mono); font-size: 1.6rem; letter-spacing: -.05em; }
.wcard__bal small { font-size: .6em; opacity: .75; }
.wcard__foot { display: flex; justify-content: space-between; gap: 8px; font-family: var(--mono); font-size: .8rem; opacity: .85; }
.wcard__today { font-size: .74rem; opacity: .8; }
.wcard__today b { font-family: var(--mono); font-weight: 500; }

.wsub { margin: 22px 0 10px; font-size: 1rem; }
.wgrid--hands { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }
.whand { padding: 14px 16px; border: 1px dashed var(--line-strong); border-radius: var(--r); display: grid; gap: 2px; background: var(--surface); }
.whand span { color: var(--ink-2); font-size: .85rem; }
.whand b { font-family: var(--mono); font-size: 1.25rem; letter-spacing: -.04em; }
.whand small { color: var(--ink-3); font-size: .74rem; }

.wmonth { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s5); }
.wbars { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.wbars li { display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; font-size: .88rem; }
.wbars i { grid-column: 1 / -1; height: 6px; border-radius: 3px; background: var(--go); }
.wbars i.is-out { background: var(--stop); opacity: .75; }

.wtag { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: .74rem;
  background: var(--surface-2); border: 1px solid var(--line); color: var(--ink-2); }
.wtag--go { background: var(--go-bg); border-color: var(--go-line); color: var(--go); }
.wtag--wait { background: var(--wait-bg); border-color: var(--wait-line); color: var(--wait); }

.wstmt { display: grid; grid-template-columns: 280px minmax(0, 1fr); gap: var(--s5); margin-bottom: var(--s4); }
.wstmt .wcard { cursor: default; width: 100%; }
.wstmt .wcard:hover { transform: none; }
.wtable td.pos { color: var(--go); }

/* касса: выбор карты плитками */
.till-cards { display: grid; gap: 6px; margin: 4px 0 10px; }
.till-cards__row { display: flex; flex-wrap: wrap; gap: 8px; }
.till-card { --wc: #186b46; display: grid; gap: 2px; text-align: left; min-width: 150px; padding: 10px 14px;
  border-radius: var(--r); border: 2px solid var(--line); background: var(--surface); color: var(--ink); cursor: pointer;
  border-left: 6px solid var(--wc); }
.till-card small { color: var(--ink-3); font-family: var(--mono); font-size: .74rem; }
.till-card[aria-pressed="true"] { border-color: var(--wc); background: color-mix(in srgb, var(--wc) 10%, var(--surface));
  box-shadow: 0 0 0 1px var(--wc); }

@media (max-width: 760px) {
  .whero { grid-template-columns: 1fr; padding: var(--s4); }
  .wpos, .wmonth, .wstmt { grid-template-columns: 1fr; }
  .wtable td:first-child { white-space: nowrap; }
}

/* Второстепенные действия карточки заявки — одним блоком под главной кнопкой. */
.estim__more { margin-top: 10px; border-top: 1px solid var(--line); padding-top: 8px; }
.estim__more summary { cursor: pointer; font-size: .86rem; color: var(--ink-2); padding: 6px 0; }
.estim__more summary:hover { color: var(--ink); }
.estim__more-body { display: grid; gap: 8px; margin-top: 8px; }
.estim__more-body > button { width: 100%; }

/* Очередь стойки считает ширину своей колонки, а не окна: на ноутбуке 1280 с боковой
   панелью колонке остаётся ~700 точек, а правило «@media 900px» ещё не срабатывало —
   модель и клиент ломались по слову в строке. Та же компактная раскладка, что у
   планшета, включается по ширине самого списка. */
.tasks { container-type: inline-size; }
@container (max-width: 820px) {
  .task--q { grid-template-columns: 3.4rem minmax(0, 1fr) auto; row-gap: var(--s2); }
  .task--q .task__main { grid-column: 2 / -1; }
  .task--q .task__why { grid-column: 2; align-self: center; }
  .task--q .task__ago { grid-column: 3; display: flex; gap: 6px; align-items: baseline; }
  .task--q .task__ago b { display: inline; }
  .task--q .task__ago .sum { display: inline; margin: 0; }
  .task--q .task__act { grid-column: 1 / -1; justify-self: end; }
}
/* Карточка заявки тоже меряет свою колонку, а не окно: рядом с боковой панелью на
   ноутбуке левой половине оставалось меньше 300 точек, и работы с ценами ломались по
   слову. Уже 720 точек — смета встаёт под карточку, как на планшете. */
*:has(> .adm) { container-type: inline-size; }
@container (max-width: 720px) {
  .adm { grid-template-columns: 1fr; }
  .adm__sum { position: static; }
}
/* Кнопка, чьё действие ещё идёт: видно, что нажатие принято, и второй раз жать незачем. */
[aria-busy="true"] { cursor: progress; opacity: .6; pointer-events: none; }

/* ═══════════ Логи владельца ═══════════ */
.jf { display: grid; gap: 8px; padding: 12px; margin-bottom: 14px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r); position: sticky; top: calc(var(--head-h, 66px) + 4px); z-index: 3; }
.jf__row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.jf__row select, .jf__row input { min-height: 36px; }
.jf__f { display: inline-flex; align-items: center; gap: 6px; font-size: .82rem; color: var(--ink-3); }
.jf__f input[type="time"] { width: 104px; }
.jf__q { flex: 1 1 220px; min-width: 180px; max-width: 420px; }
.jf__presets button { min-height: 34px; padding: 6px 12px; }
.jsum { display: grid; grid-template-columns: repeat(4, minmax(110px, 1fr)) minmax(240px, 2fr);
  gap: 10px; margin-bottom: 16px; align-items: stretch; }
.jsum .stat { margin: 0; }
.jsum__hours { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); padding: 10px 12px 6px; }
@media (max-width: 900px) { .jsum { grid-template-columns: repeat(2, 1fr); } .jsum__hours { grid-column: 1 / -1; } }
.jhours { display: grid; grid-template-columns: repeat(24, 1fr); gap: 3px; height: 72px; align-items: end; }
.jhours__c { height: 100%; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 3px; }
.jhours__c i { display: block; width: 100%; border-radius: 3px 3px 1px 1px; background: var(--info); opacity: .78; min-height: 0; }
.jhours__c.is-night i { background: var(--ink-3); }
.jhours__c span { font-size: .62rem; color: var(--ink-3); height: 10px; line-height: 10px; }

.jfeed { display: grid; gap: 14px; }
.jday { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.jday__head { display: flex; align-items: baseline; gap: 10px; padding: 10px 14px; background: var(--surface-2);
  border-bottom: 1px solid var(--line); position: sticky; top: calc(var(--head-h, 66px) + 4px); }
.jday__head b { font-size: .92rem; text-transform: capitalize; }
.jrow { display: grid; grid-template-columns: 3.2rem 12px minmax(0, 1fr) auto; gap: 10px; align-items: start;
  padding: 9px 14px; border-top: 1px solid var(--line); }
.jrow:first-of-type { border-top: 0; }
.jrow:hover { background: var(--surface-2); }
.jrow__t { font-family: var(--mono); font-size: .84rem; color: var(--ink-3); padding-top: 2px; }
.jrow__dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 7px; background: var(--ink-3); }
.jrow--money .jrow__dot { background: var(--go); }
.jrow--salary .jrow__dot { background: #8b5cf6; }
.jrow--spend .jrow__dot { background: var(--wait); }
.jrow--supply .jrow__dot { background: #0ea5a4; }
.jrow--order .jrow__dot { background: var(--info); }
.jrow--staff .jrow__dot { background: var(--stop); }
.jrow__line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 8px; }
.jrow__who { all: unset; cursor: pointer; font-weight: 600; color: var(--ink); }
.jrow__who:hover { text-decoration: underline; text-underline-offset: 3px; }
.jrow__act { color: var(--ink-2); }
.jrow__sum { margin-left: auto; font-family: var(--mono); }
.jrow__note { font-size: .84rem; color: var(--ink-2); margin-top: 2px; overflow-wrap: anywhere; }
.jrow__ord { font-size: .8rem; color: var(--ink-3); margin-top: 2px; }
.jrow__ord button { padding: 0; min-height: 0; font-size: .8rem; }
.jrow__kind { font-size: .72rem; color: var(--ink-3); border: 1px solid var(--line); border-radius: 999px; padding: 2px 8px; white-space: nowrap; }
@media (max-width: 640px) { .jrow { grid-template-columns: 3rem minmax(0, 1fr); } .jrow__dot, .jrow__kind { display: none; } }

.jtable { width: 100%; }
.jtable tr.is-link { cursor: pointer; }
.jtable tr.is-link:hover td { background: var(--surface-2); }
.jtable .is-warn, .jtable tr.is-warn td { color: var(--stop); }
.jevents { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 8px; }
.jevent { all: unset; cursor: pointer; display: flex; justify-content: space-between; gap: 10px; align-items: center;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); }
.jevent:hover { border-color: var(--line-strong); background: var(--surface-2); }
.jevent b { font-family: var(--mono); }

/* ═══════════ Дверь входа, 2026-09-23 ═══════════
   Прежняя дверь — чёрный фон, обрезанный по краю контур телефона и белая карточка —
   выглядела заготовкой. Теперь: глубокий фон с двумя мягкими свечениями (фирменный
   зелёный сверху слева, холодный снизу справа) и тонкой сеткой точек, которая гаснет
   к краям; карточка — тёмное стекло, поля и кнопка в том же мире. Разметка та же. */
body.door {
  background:
    radial-gradient(900px 620px at 12% -12%, rgba(34, 160, 107, .30), transparent 62%),
    radial-gradient(760px 540px at 112% 112%, rgba(70, 120, 255, .16), transparent 60%),
    linear-gradient(180deg, #0c0f12 0%, #07090b 100%);
  color: #eef2ef;
}
body.door::before {
  content: ''; position: fixed; inset: 0; pointer-events: none;
  background-image: radial-gradient(rgba(255, 255, 255, .07) 1px, transparent 1px);
  background-size: 22px 22px;
  -webkit-mask-image: radial-gradient(ellipse 70% 60% at 50% 45%, #000 20%, transparent 75%);
          mask-image: radial-gradient(ellipse 70% 60% at 50% 45%, #000 20%, transparent 75%);
}
body.door .door__mark { display: none; }
body.door .door__panel { max-width: 404px; z-index: 1; }
body.door .door__logo { height: 36px; margin-bottom: 26px; filter: drop-shadow(0 6px 18px rgba(0, 0, 0, .5)); }
body.door .door__card {
  background: linear-gradient(180deg, rgba(26, 30, 35, .82), rgba(15, 18, 21, .86));
  color: #eef2ef;
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 18px;
  padding: 30px 28px 26px;
  box-shadow: 0 30px 80px -24px rgba(0, 0, 0, .75), 0 0 0 1px rgba(0, 0, 0, .35),
              inset 0 1px 0 rgba(255, 255, 255, .06);
  -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px);
}
body.door .door__card h1 { color: #fff; font-size: 1.4rem; font-weight: 650; letter-spacing: -.02em; }
body.door .door__lede { color: #9ba7a1; }
body.door .door__card .field__label { color: #b3bdb8; font-weight: 500; letter-spacing: .01em; }
body.door .door__card input {
  background: rgba(255, 255, 255, .045); color: #f3f6f4;
  border: 1px solid rgba(255, 255, 255, .12); border-radius: 12px; min-height: 48px;
  padding: 11px 14px; font-size: .98rem;
  transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
}
body.door .door__card input:hover { border-color: rgba(255, 255, 255, .2); }
body.door .door__card input:focus {
  outline: none; background: rgba(255, 255, 255, .07); border-color: #2bb57a;
  box-shadow: 0 0 0 4px rgba(43, 181, 122, .18);
}
body.door .door__card input:-webkit-autofill {
  -webkit-text-fill-color: #f3f6f4; caret-color: #f3f6f4;
  -webkit-box-shadow: 0 0 0 1000px #1a1f23 inset; border-color: rgba(255, 255, 255, .16);
}
body.door .door__card button {
  margin-top: 10px; min-height: 50px; border: 0; border-radius: 12px;
  background: linear-gradient(180deg, #25a871, #178457); color: #fff;
  font-weight: 600; font-size: 1rem; letter-spacing: .01em;
  box-shadow: 0 10px 26px -10px rgba(37, 168, 113, .7), inset 0 1px 0 rgba(255, 255, 255, .18);
  transition: transform .12s ease, box-shadow .18s ease, filter .18s ease;
}
body.door .door__card button:hover { filter: brightness(1.07); box-shadow: 0 14px 30px -10px rgba(37, 168, 113, .8), inset 0 1px 0 rgba(255, 255, 255, .2); }
body.door .door__card button:active { transform: translateY(1px); }
body.door .door__card button:disabled { filter: saturate(.6) brightness(.9); cursor: progress; }
body.door .door__err {
  background: rgba(220, 70, 50, .12); border: 1px solid rgba(240, 110, 90, .35);
  color: #ffb4a6; border-radius: 12px;
}
body.door .door__foot { color: #8e9a94; line-height: 1.55; }
body.door .door__foot a { color: #d9e6df; }
body.door .door__way {
  border-color: rgba(255, 255, 255, .1); border-radius: 12px; background: rgba(255, 255, 255, .03);
}
body.door .door__way:hover { background: rgba(255, 255, 255, .07); border-color: rgba(43, 181, 122, .55); }
body.door .door__way span { color: #9ba7a1; }
body.door .door__install { border-radius: 12px; }
@media (max-width: 420px) {
  body.door .door__card { padding: 24px 20px 22px; border-radius: 16px; }
}
/* Поправки комнаты «Логи»: фильтр и заголовок дня не липнут одновременно — они наезжали
   друг на друга; кнопки с иконкой — в строку. */
.jf { position: static; }
.jf button { display: inline-flex; align-items: center; gap: 6px; }
.jday__head { position: static; }
.jday__head b { text-transform: none; }

/* ─────────── Кабинет: «Сегодня» ─────────── */
.sahead {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: 0 0 12px; font: 650 1rem/1.3 var(--sans); letter-spacing: -.01em; color: var(--ink);
}
.sahead > span { font: 500 .85rem/1 var(--sans); color: var(--ink-3); }

/* Требует решения: одна карточка, строки внутри. Цвет — у значка и полоски слева,
   а не заливкой всей строки: пять разноцветных плашек подряд читались как светофор. */
.sadec {
  margin-bottom: 22px; padding: 16px 16px 8px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-1);
}
.sadec .sahead > span {
  min-width: 22px; padding: 2px 7px; border-radius: var(--r-pill);
  background: var(--ink); color: var(--surface); font: 600 .72rem/1.3 var(--mono); text-align: center;
}
.sadec__i {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 0 12px 12px; border-top: 1px solid var(--line);
  box-shadow: inset 3px 0 0 var(--line);
}
.sadec__i > .ic { width: 20px; height: 20px; flex: none; color: var(--ink-3); }
.sadec__i--ask { box-shadow: inset 3px 0 0 var(--stop); }
.sadec__i--ask > .ic, .sadec__i--stop > .ic { color: var(--stop); }
.sadec__i--stop { box-shadow: inset 3px 0 0 var(--stop); }
.sadec__i--wait { box-shadow: inset 3px 0 0 var(--wait); }
.sadec__i--wait > .ic { color: var(--wait); }
.sadec__i--go { box-shadow: inset 3px 0 0 var(--go); }
.sadec__i--go > .ic { color: var(--go); }
.sadec__t { flex: 1 1 260px; min-width: 0; font-size: .93rem; color: var(--ink-2); }
.sadec__t b { color: var(--ink); font-weight: 600; }
.sadec__t small { display: block; margin-top: 2px; font-size: .84rem; color: var(--ink-3); }
.sadec__act { display: flex; gap: 8px; flex-wrap: wrap; margin-left: auto; }

/* Деньги дня и этапы — рядом на широком экране: оба отвечают на «как идёт день». */
.satoday {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: 18px;
  margin-bottom: 22px; align-items: stretch;
}
.satoday .daymoney { margin: 0; }
.daymoney__be { margin-top: 18px; display: grid; gap: 8px; font-size: .84rem; color: #a9bdb0; }
.daymoney__be b { color: #f4d79a; }
.daymoney__bar { height: 6px; border-radius: 99px; background: rgba(255, 255, 255, .12); overflow: hidden; }
.daymoney__bar i { display: block; height: 100%; border-radius: inherit; background: #e7b75a; }
.daymoney__be.is-ok .daymoney__bar i { background: #5fd29a; }
.daymoney__be.is-ok { color: #bfe8cf; }

.sastage {
  padding: 18px; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-1);
  display: flex; flex-direction: column;
}
.sastage__late {
  margin-left: auto; display: inline-flex; align-items: center; gap: 6px;
  min-height: 30px; padding: 0 10px; border-radius: var(--r-pill);
  background: var(--stop-bg); color: var(--stop); border: 1px solid var(--stop-line); box-shadow: none;
  font: 500 .82rem/1 var(--sans);
}
.sastage__late .ic { width: 15px; height: 15px; }
.sastage__row {
  flex: 1; display: grid; grid-template-columns: repeat(auto-fit, minmax(84px, 1fr)); gap: 8px;
}
.sastage__i {
  display: flex; flex-direction: column; align-items: flex-start; justify-content: space-between; gap: 10px;
  min-height: 92px; padding: 12px 14px; text-align: left;
  background: var(--surface-2); color: var(--ink); border: 1px solid transparent;
  border-radius: 12px; box-shadow: none; cursor: pointer;
  transition: border-color var(--fast), background var(--fast), transform var(--fast);
}
.sastage__i:hover { border-color: var(--line); background: var(--surface); transform: translateY(-1px); }
.sastage__i b { font: 650 1.75rem/1 var(--mono); letter-spacing: -.04em; }
.sastage__i span { font: 500 .8rem/1.25 var(--sans); color: var(--ink-2); }
.sastage__i.is-zero b { color: var(--ink-3); }
.sastage__i.is-hot { background: var(--wait-bg); border-color: var(--wait-line); }
.sastage__i.is-hot b { color: var(--wait); }

/* Мастера и зависшие — две колонки: обе про людей и заявки, обе короткие. */
.sagrid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; align-items: start; }
.sagrid > .bsec { margin: 0; }
.satable tr[data-person] { cursor: pointer; }
.satable tr[data-person]:hover td { background: var(--surface-2); }
.sastale { display: grid; }
.sastale__i {
  display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; gap: 12px; align-items: center;
  padding: 10px var(--s4); border-bottom: 1px solid var(--line);
  color: var(--ink); text-decoration: none; transition: background var(--fast);
}
.sastale__i:last-child { border-bottom: 0; }
.sastale__i:hover { background: var(--surface-2); }
.sastale__d { font: 650 1.15rem/1 var(--mono); color: var(--wait); text-align: center; }
.sastale__d small { display: block; margin-top: 2px; font: 500 .66rem/1 var(--sans); color: var(--ink-3); }
.sastale__t, .sastale__s { min-width: 0; }
.sastale__t b { display: block; font-size: .92rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sastale__t small, .sastale__s small { display: block; font-size: .8rem; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sastale__s { text-align: right; }
.sastale__all { display: block; padding: 10px var(--s4); border-top: 1px solid var(--line); }

@media (max-width: 1280px) {
  .satoday, .sagrid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 560px) {
  .sadec { padding: 14px 12px 6px; }
  .sadec__act { margin-left: 0; width: 100%; }
  .sastage__row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sastage__i { min-height: 78px; }
  .sastale__i { grid-template-columns: 38px minmax(0, 1fr); }
  .sastale__s { grid-column: 2; text-align: left; display: flex; gap: 8px; align-items: center; }
}

/* Значок внутри кнопки или ссылки не должен забирать нажатие: обработчики смотрят на
   e.target.id и data-*, а при попадании в <svg> они молчали — кнопка «не нажималась». */
:is(button, a, [role="button"]) :is(svg, .ic) { pointer-events: none; }

.linkish { box-shadow: none; }
.linkish[aria-current="true"] { font-weight: 700; text-decoration-color: currentColor; }
/* Полоса «экран сотрудника» в кабинете: одна тихая строка, а не жёлтая плашка на каждом
   одолженном экране — её читали один раз, а место она занимала всегда. */
.ownerbar {
  display: flex; align-items: center; gap: 8px; margin: 0 0 14px;
  color: var(--ink-3); font-size: .82rem;
}
.ownerbar .ic { width: 15px; height: 15px; flex: none; }
.payidle {
  display: flex; gap: 10px; align-items: flex-start; margin: 0 0 16px; padding: 12px 14px;
  border: 1px dashed var(--line); border-radius: var(--r); color: var(--ink-2); font-size: .88rem;
}
.payidle .ic { width: 17px; height: 17px; flex: none; margin-top: 2px; color: var(--ink-3); }

/* Настройки: пояснения — две строки, остальное по нажатию. Над каждой галочкой стояло
   по шесть-восемь строк объяснений, и сами галочки терялись между абзацами. */
.is-setup .bpad > p.hint, .is-setup .bpad > .note > span {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
  overflow: hidden;
}
.is-setup .bpad > p.hint, .is-setup .bpad > .note { cursor: pointer; }
.is-setup .bpad > p.hint.is-open, .is-setup .bpad > .note.is-open > span { display: block; -webkit-line-clamp: unset; }

/* Логи на телефоне: фильтры в колонку, пресеты — лентой, ничего не шире экрана. */
@media (max-width: 560px) {
  .jf { min-width: 0; grid-template-columns: minmax(0, 1fr); }
  .jf .jf__presets { max-width: 100%; overflow-x: auto; scrollbar-width: none; flex-wrap: nowrap; }
  .jf .bseg { max-width: 100%; overflow-x: auto; scrollbar-width: none; flex-wrap: nowrap; }
  .jf .bseg::-webkit-scrollbar { display: none; }
  .jf__row > select, .jf__row > input, .jf__q { flex: 1 1 100%; min-width: 0; max-width: none; width: 100%; }
  .jf__f { flex-wrap: wrap; }
  .jf__f input[type="date"] { width: 140px; }
}

/* ── Журнал закупок (partsJournal): одна деталь — когда, зачем, для чего, у кого ── */
.pj-bar { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-bottom: 10px; }
.pj-bar input[type="search"] { flex: 1 1 280px; min-width: 0; }
.pj-bar select { flex: 0 1 220px; min-width: 0; }
.pj-day { display: flex; gap: 10px; align-items: baseline; margin: 18px 0 8px;
  font-size: .9rem; color: var(--ink); }
.pj { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  padding: 12px 14px; margin-bottom: 8px; }
.pj--off { opacity: .6; }
.pj__top { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.pj__name { font-size: 1rem; }
.pj__sum { font-family: var(--mono); font-size: 1.05rem; margin-left: auto; }
.pj__dl { display: grid; grid-template-columns: max-content 1fr; gap: 3px 12px;
  margin: 8px 0 0; font-size: .85rem; }
.pj__dl dt { color: var(--ink-2); }
.pj__dl dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
@media (max-width: 520px) {
  .pj__dl { grid-template-columns: 1fr; gap: 0; }
  .pj__dl dt { margin-top: 6px; font-size: .75rem; }
}
.modal .card.pj-sheet { max-width: 760px; max-height: 88vh; overflow: auto; }
button.stat { text-align: left; font: inherit; color: inherit; cursor: pointer; box-shadow: none; min-height: 0; }
button.stat:hover { border-color: var(--line-strong); }
tr.is-link { cursor: pointer; }

/* Движение кассы: лента по дням — открыли → за смену → закрыли → после закрытия. */
.tflow { margin: var(--s5) 0; }
.tflow__day { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin: 0 0 8px; font-size: 1rem; }
.tflow__day small { font-weight: 400; color: var(--ink-2); font-size: .82rem; }
.tflow__list { list-style: none; margin: 0; padding: 0 0 0 14px; border-left: 2px solid var(--line); }
.tflow__i { position: relative; display: grid; grid-template-columns: 96px minmax(0, 1fr) auto;
  gap: 2px 12px; align-items: baseline; padding: 8px 10px; border-radius: 8px; }
.tflow__i::before { content: ''; position: absolute; left: -21px; top: 14px; width: 10px; height: 10px;
  border-radius: 50%; background: var(--surface); border: 2px solid var(--line); }
.tflow__i--open::before, .tflow__i--close::before { background: var(--ink-2); border-color: var(--ink-2); }
.tflow__i[data-shift] { cursor: pointer; }
.tflow__i[data-shift]:hover { background: var(--surface-2); }
.tflow__i--gap { background: var(--surface-2); }
.tflow__t { font-variant-numeric: tabular-nums; color: var(--ink-2); font-size: .8rem; line-height: 1.25; }
.tflow__what small { display: block; color: var(--ink-2); font-size: .8rem; margin-top: 2px; }
.tflow__who { color: var(--ink-2); }
.tflow__sum { font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 560px) {
  .tflow__i { grid-template-columns: 72px minmax(0, 1fr); }
  .tflow__sum { grid-column: 2; }
}

/* ═══════════════════ касса, редакция 2026-09-27 ═══════════════════
   Кассир жаловался не на цвета, а на то, что экран врёт: вкладка «Поставщик» без
   денежных просьб отвечала «у окна никого», хотя ниже, свёрнутыми, лежали купленные
   детали. Отсюда три правила:
     1. вкладка — вопрос, у неё счётчик и сумма, и пусто она говорит своими словами;
     2. у строки одна крупная кнопка-глагол справа, мелочь — ссылками под именем;
     3. инструменты — две подписанные группы сбоку, а не восемь одинаковых кнопок в ряд. */
.till-top { gap: var(--s3); }
.till-search { flex: 1 1 280px; display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 0 12px; border: 1px solid var(--line-strong); border-radius: var(--r-pill);
  background: var(--surface); }
.till-search:focus-within { border-color: var(--go); box-shadow: 0 0 0 3px var(--go-bg); }
.till-search .ic { width: 18px; height: 18px; color: var(--ink-3); flex: 0 0 auto; }
.till-bar .till-search input { flex: 1; min-width: 0; max-width: none; border: 0; box-shadow: none;
  background: transparent; min-height: 44px; padding: 0; font-size: 1rem; outline: none; }

/* Раздел во вкладке. */
.tgroup { display: grid; gap: 8px; }
.tgroup + .tgroup { margin-top: var(--s3); }
.tgroup__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
.tgroup__head h3 { margin: 0; font-size: 1.02rem; }
.tgroup__head .hint { flex-basis: 100%; margin: 0; }
.tgroup__n { font: 600 .8rem/1 var(--mono); padding: 3px 8px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--ink-2); }
.tgroup__empty { margin: 0; padding: 14px 16px; border: 1px dashed var(--line-strong); border-radius: var(--r);
  color: var(--ink-2); font-size: .9rem; background: var(--surface); }

/* Строка: слева жетон и кто, под именем — мелкие действия, справа — сумма и глагол. */
.till .till-row { cursor: pointer; align-items: center; }
.till-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.till-end { margin-left: auto; display: grid; justify-items: end; gap: 8px; }
.till-end .till-due { margin-left: 0; }
.till-go-btn { min-height: 44px; padding: 8px 18px; font-weight: 600; white-space: nowrap; }
@media (max-width: 640px) {
  .till-end { margin-left: 0; width: 100%; grid-template-columns: 1fr auto; align-items: center; }
  .till-end .till-due { justify-self: start; }
}

/* Инструменты сбоку: две подписанные группы, у каждой кнопки — зачем она. */
.till-side { display: grid; gap: var(--s4); align-content: start; min-width: 0; }
.tools { padding: var(--s3) var(--s4); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow-1); }
.tools h3 { margin: 4px 0 8px; font-size: .78rem; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3); }
.tools h3 + .tools__grid + h3 { margin-top: 14px; }
.tools__grid { display: grid; gap: 6px; }
.tool { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 52px; padding: 8px 12px;
  text-align: left; background: var(--surface-2); color: var(--ink); border: 1px solid transparent;
  border-radius: var(--r); box-shadow: none; font: 500 .92rem/1.2 var(--sans); cursor: pointer; }
.tool:hover { border-color: var(--line-strong); background: var(--surface); }
.tool .ic { width: 20px; height: 20px; color: var(--ink-2); flex: 0 0 auto; }
.tool span { display: grid; gap: 2px; }
.tool small { font-size: .75rem; font-weight: 400; color: var(--ink-3); }
@media (max-width: 900px) {
  .tools__grid { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
}

/* ═══════════════ бухгалтерия, редакция 2026-09-27 (books.js) ═══════════════
   Рабочее место бухгалтера и кассира за вторым столом. Слева — вкладки группами
   (Дела / Деньги / Отчёты) со счётчиком дел; справа — шапка вкладки с периодом и
   Excel, под ней содержимое. На телефоне вкладки встают лентой сверху, а числа —
   в две колонки. Цвета графиков — отдельные от статусных (зелёный/жёлтый/красный
   заняты под «твой ход / ждём / плохо» и в графики не отдаются). */
.bk { display: grid; grid-template-columns: 216px minmax(0, 1fr); gap: var(--s5); align-items: start; }
.bk-nav { position: sticky; top: calc(var(--head-h, 66px) + var(--s3)); display: grid; gap: var(--s3); }
.bk-nav__group { display: grid; gap: 2px; }
.bk-nav__g { padding: 0 12px 2px; font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.bk-nav button {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 42px; padding: 8px 12px;
  background: transparent; color: var(--ink-2); border: 1px solid transparent; border-radius: var(--r);
  box-shadow: none; font: 500 .93rem/1.2 var(--sans); text-align: left;
  transition: background var(--fast), color var(--fast);
}
.bk-nav button .ic { width: 18px; height: 18px; color: var(--ink-3); flex: 0 0 auto; }
.bk-nav button:hover { background: var(--surface); color: var(--ink); }
.bk-nav button[aria-current="true"] { background: var(--surface); color: var(--ink); font-weight: 600; border-color: var(--line); box-shadow: var(--shadow-1); }
.bk-nav button[aria-current="true"] .ic { color: var(--go); }
.bk-nav__n { margin-left: auto; min-width: 22px; padding: 1px 7px; border-radius: var(--r-pill); background: var(--wait-bg); color: var(--wait); font-size: 12px; text-align: center; }
.bk-nav__foot { border-top: 1px solid var(--line); padding-top: var(--s3); }
.bk-bar { display: none; }
.bk-nav .bk-nav__till, .bk-nav .bk-nav__till .ic { color: var(--go); }

.bk-main { min-width: 0; }
.bk-head { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s3); margin-bottom: var(--s4); }
.bk-head__t h2 { margin: 0; font-size: var(--fs-display); letter-spacing: -.01em; }
.bk-head__t .hint { margin: 0; }
.bk-head .ic { width: 16px; height: 16px; margin-right: 6px; vertical-align: -3px; }
.bk-range { max-width: 100%; overflow-x: auto; }
.bk-cmp { margin: -6px 0 var(--s3); }
.bk-sub { margin: var(--s5) 0 var(--s3); font-size: var(--fs-heading); }

/* Плитки показателей: число крупно, под ним сравнение словами и стрелкой. */
.bk-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--s3); margin-bottom: var(--s4); }
.bk-kpi { position: relative; display: grid; gap: 4px; align-content: start; padding: var(--s4); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow-1); overflow: hidden; }
.bk-kpi__label { font-size: var(--fs-floor); color: var(--ink-3); }
.bk-kpi__value { font-size: 1.55rem; line-height: 1.15; font-weight: 650; letter-spacing: -.01em; }
.bk-kpi__delta { font-size: var(--fs-floor); color: var(--ink-2); display: grid; }
.bk-kpi__delta small { color: var(--ink-3); font-size: 12px; }
.bk-kpi__delta.is-better { color: var(--go); }
.bk-kpi__delta.is-worse { color: var(--stop); }
.bk-kpi__note { font-size: 12px; color: var(--ink-3); }
.bk-spark { width: 100%; height: 30px; margin-top: 4px; }
.bk-spark polyline { fill: none; stroke: #2a78d6; stroke-width: 1.6; vector-effect: non-scaling-stroke; stroke-linejoin: round; }

.bk-cols { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: var(--s4); align-items: start; margin-bottom: var(--s4); }
.bk-cols--even { grid-template-columns: 1fr 1fr; }
.bk-cols > .bsec { margin-bottom: 0; }
.bk-side { display: grid; gap: var(--s4); }
.bk-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-1); padding: var(--s4); }
.bk-card__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s2); margin-bottom: var(--s3); }
.bk-card__head h3 { margin: 0; font-size: var(--fs-heading); }
.bk-big { margin: 0; font-size: 1.9rem; font-weight: 650; letter-spacing: -.02em; }
.bk-big small { font-size: 1rem; color: var(--ink-3); }

/* Дело: значок уровня, что и почему, сумма и кнопка туда, где это делается. */
.bk-todo { display: grid; grid-template-columns: 36px minmax(0, 1fr) auto; gap: var(--s3); align-items: start;
  padding: var(--s3) 0; border-top: 1px solid var(--line); }
.bk-card__head + .bk-todo { border-top: 0; }
.bk-todo__ic { display: grid; place-items: center; width: 36px; height: 36px; border-radius: var(--r); background: var(--info-bg); color: var(--info); }
.bk-todo__ic .ic { width: 18px; height: 18px; }
.bk-todo--stop .bk-todo__ic { background: var(--stop-bg); color: var(--stop); }
.bk-todo--wait .bk-todo__ic { background: var(--wait-bg); color: var(--wait); }
.bk-todo__body { display: grid; gap: 2px; min-width: 0; }
.bk-todo__body .hint { margin: 0; }
.bk-todo__n { display: inline-block; min-width: 22px; padding: 0 7px; border-radius: var(--r-pill); background: var(--canvas); border: 1px solid var(--line); font-size: 12px; text-align: center; }
.bk-todo__rows { display: grid; gap: 4px; margin-top: 6px; font-size: var(--fs-small); }
.bk-todo__rows span { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.bk-todo__end { display: grid; justify-items: end; gap: 6px; }
.bk-todo__end b { font-size: 1.05rem; }

.bk-held { background: var(--info-bg); color: var(--info); gap: 4px; }
.bk-held .ic { width: 12px; height: 12px; }
.bk-held::before { display: none; }
.bk-held-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); }
.bk-held-list li { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.bk-held-list .ic { width: 16px; height: 16px; color: var(--info); }
.bk-held-list small { color: var(--ink-3); }

/* Графики. */
.bk-chart { padding: var(--s4); }
.bk-chart svg { display: block; width: 100%; height: 190px; overflow: visible; }
.bk-legend { display: flex; flex-wrap: wrap; gap: var(--s2) var(--s4); margin-bottom: var(--s2); font-size: var(--fs-floor); color: var(--ink-2); }
.bk-legend span { display: inline-flex; align-items: center; gap: 6px; }
.bk-legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.bk-legend .bk-legend__line { width: 16px; height: 2px; border-radius: 1px; background: var(--ink); }
.bk-grid { stroke: #e1e0d9; stroke-width: 1; vector-effect: non-scaling-stroke; }
.bk-base { stroke: #c3c2b7; stroke-width: 1; vector-effect: non-scaling-stroke; }
.bk-netline { fill: none; stroke: var(--ink); stroke-width: 2; vector-effect: non-scaling-stroke; stroke-linejoin: round; pointer-events: none; }
.bk-hit { fill: transparent; }
.bk-hit:hover { fill: rgba(20, 24, 27, .05); }
.bk-stack { padding: var(--s4); display: grid; gap: var(--s3); }
.bk-stack__bar { display: flex; gap: 2px; height: 22px; border-radius: 6px; overflow: hidden; }
.bk-stack__bar i { min-width: 3px; }
.bk-stack__legend { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.bk-stack__legend li { display: grid; grid-template-columns: 12px minmax(0, 1fr) auto 44px; gap: var(--s2); align-items: center; font-size: var(--fs-small); }
.bk-stack__legend i { width: 10px; height: 10px; border-radius: 3px; }
.bk-stack__legend span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bk-stack__legend small { color: var(--ink-3); text-align: right; }
.bk-tip { position: fixed; z-index: 90; pointer-events: none; opacity: 0; transform: translateY(4px);
  transition: opacity var(--fast), transform var(--fast); min-width: 170px; max-width: 280px;
  padding: 8px 10px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: var(--shadow-2); font-size: var(--fs-floor); display: grid; gap: 3px; }
.bk-tip.is-on { opacity: 1; transform: none; }
.bk-tip__row { display: grid; grid-template-columns: 10px 1fr auto; gap: 6px; align-items: center; color: var(--ink-2); }
.bk-tip__row i { width: 10px; height: 10px; border-radius: 3px; }
.bk-tip__row b { color: var(--ink); }

/* Долги: поставщик — заголовок, строки деталей — под ним, «оплатить всё» справа. */
.bk-line { display: flex; align-items: center; gap: var(--s3); padding: var(--s2) var(--s4); flex-wrap: wrap; }
.bk-line + .bk-line { border-top: 1px dashed var(--line); }
.bk-line__main { flex: 1 1 240px; display: grid; min-width: 0; }
.bk-line__main .hint { margin: 0; }
.bk-line.is-held { opacity: .75; }
.bk-asks .bsec__body { padding: 0; }

/* Касса: сколько должно лежать, кто открыл, действия одной строкой. */

/* Журнал: фильтры в одну строку, дни заголовками, строка — время, что, сумма, отмена. */
.bk-filter { display: flex; flex-wrap: wrap; gap: var(--s2); margin-bottom: var(--s4); }
.bk-filter select { width: auto; min-width: 180px; }
.bk-filter .till-search { flex: 1 1 220px; }
.bk-kpis--3 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.bk-day { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); margin-bottom: var(--s3); overflow: hidden; }
.bk-day__h { display: flex; justify-content: space-between; align-items: baseline; margin: 0; padding: var(--s3) var(--s4); font-size: var(--fs-heading); background: var(--surface-2); border-bottom: 1px solid var(--line); }
.bk-day__h small { font-size: var(--fs-small); color: var(--ink-3); font-weight: 500; }
.bk-act { display: grid; grid-template-columns: 52px minmax(0, 1fr) auto auto; gap: var(--s3); align-items: center; padding: 10px var(--s4); }
.bk-act + .bk-act { border-top: 1px solid var(--line); }
.bk-act__t { color: var(--ink-3); font-size: var(--fs-small); }
.bk-act__what { display: grid; min-width: 0; }
.bk-act__what b { font-weight: 600; overflow-wrap: anywhere; }
.bk-act__what small { color: var(--ink-3); font-size: 12px; overflow-wrap: anywhere; }
.bk-act__sum { font-size: 1rem; }
.bk-act__end { justify-self: end; }
.bk-act__end .ic { width: 14px; height: 14px; margin-right: 4px; vertical-align: -2px; }
.bk-act.is-undone .bk-act__what b, .bk-act.is-undone .bk-act__sum { text-decoration: line-through; color: var(--ink-3); }

@media (max-width: 1100px) {
  .bk-cols { grid-template-columns: 1fr; }
}
@media (max-width: 900px) {
  .bk { grid-template-columns: minmax(0, 1fr); gap: var(--s3); }
  /* Меню — нижней панелью (bkBar в books.js), боковые группы на телефоне не нужны. */
  .bk-nav { position: static; display: block; }
  .bk-nav__group, .bk-nav__foot { display: none; }
  .bk-bar {
    position: fixed; z-index: 40; left: 0; right: 0; bottom: 0;
    display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
    padding: 4px max(4px, env(safe-area-inset-right)) calc(4px + env(safe-area-inset-bottom)) max(4px, env(safe-area-inset-left));
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    -webkit-backdrop-filter: saturate(1.4) blur(14px); backdrop-filter: saturate(1.4) blur(14px);
    border-top: 1px solid var(--line);
  }
  .bk-bar > button, .bk-bar__more > summary {
    position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    min-height: 54px; padding: 4px 2px; border: 0; border-radius: 12px; background: transparent; box-shadow: none;
    font-size: .68rem; font-weight: 500; color: var(--ink-2); cursor: pointer; list-style: none;
  }
  .bk-bar__more > summary::-webkit-details-marker { display: none; }
  .bk-bar > button span, .bk-bar__more > summary span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .bk-bar .ic { width: 22px; height: 22px; margin: 0; color: var(--ink-3); }
  .bk-bar > button[aria-current="true"], .bk-bar__more > summary[aria-current="true"],
  .bk-bar > button[aria-current="true"] .ic, .bk-bar__more > summary[aria-current="true"] .ic { color: var(--go); }
  .bk-nav .bk-bar > button[aria-current="true"] { background: transparent; border-color: transparent; box-shadow: none; }
  .bk-bar > button .bk-nav__n {
    position: absolute; top: 2px; left: calc(50% + 6px); margin: 0;
    min-width: 18px; padding: 0 5px; font-size: .64rem; line-height: 18px;
  }
  .bk-bar__extra {
    position: absolute; right: 8px; bottom: calc(100% + 8px); min-width: 220px;
    display: grid; gap: 2px; padding: 6px;
    background: var(--surface); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow-2);
  }
  .bk-bar__extra button {
    display: flex; align-items: center; gap: 10px; width: 100%; min-height: 46px; padding: 0 12px;
    border: 0; border-radius: 10px; background: transparent; box-shadow: none; color: var(--ink); text-align: left;
  }
  .bk-bar__extra button[aria-current="true"] { background: var(--go-bg); color: var(--go); font-weight: 600; }
  .bk-bar__extra .bk-nav__n { margin-left: auto; }
  /* Низ страницы не прячется под панелью. */
  .bk { padding-bottom: calc(72px + env(safe-area-inset-bottom)); }
  .bk-cols--even { grid-template-columns: 1fr; }
  .bk-kpis { grid-template-columns: 1fr 1fr; }
  .bk-kpi__value { font-size: 1.25rem; }
  .bk-head { gap: var(--s2); }
}
@media (max-width: 520px) {
  .bk-act { grid-template-columns: 44px minmax(0, 1fr) auto; }
  .bk-act__end { grid-column: 2 / -1; justify-self: start; }
  .bk-todo { grid-template-columns: 32px minmax(0, 1fr); }
  .bk-todo__end { grid-column: 2; justify-items: start; grid-auto-flow: column; align-items: center; }
  .bk-stack__legend li { grid-template-columns: 12px minmax(0, 1fr) auto; }
  .bk-stack__legend small { display: none; }
  .bk-filter select { flex: 1 1 100%; }
}

/* ═══════════════ бухгалтер на консоли, 2026-09-27 ═══════════════
   Бухгалтер переехал со «пузыря» на ту же светлую консоль, что у стойки: два рабочих
   места одной фирмы не должны выглядеть двумя разными программами. */

/* Шапка без поиска (бухгалтер, касса): имя и кнопки прижаты вправо, как у стойки,
   а не липнут к названию рабочего места. */
[data-skin="console"] header:not(:has(.deskfind)) #who { margin-left: auto; }

/* Деньги на консоли — тем же Inter с цифрами одинаковой ширины: столбцы сумм ровные,
   а моноширинный шрифт рядом с Inter читался как вставка из другой программы.
   Коды и IMEI остаются моноширинными — там важна каждая литера. */
[data-skin="console"] :is(.num, td.num, .bpl b, .bk-big, .stat b, .task__act .sum,
  .daymoney__flow b, .daymoney__sum, .estim__margin--net b) {
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}

.bk-head button { display: inline-flex; align-items: center; gap: 6px; }
.bk-head button .ic { margin-right: 0; }

/* Шапка вкладки бухгалтерии прилипает под шапкой приложения: название, период и Excel
   остаются под рукой, пока читаешь длинный отчёт. Раньше это был тег <header>, и на
   него действовали правила главной шапки — он прилипал к самому верху поверх неё. */
.bk-head {
  position: sticky; top: var(--head-h, 52px); z-index: 6;
  margin: calc(var(--s3) * -1) 0 var(--s4); padding: var(--s3) 0 var(--s2);
  background: var(--canvas);
}
@media (max-width: 900px) {
  /* На телефоне сверху уже прилипла лента вкладок — вторая липкая полоса съела бы экран. */
  .bk-head { position: static; margin: 0 0 var(--s3); padding: 0; background: none; }
}

/* ═══════════════ итог дня и «где деньги», 2026-09-28 ═══════════════ */
.bk-daybar { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s2); margin-bottom: var(--s4); }
.bk-daybar > button.ghost { min-width: 40px; justify-content: center; }
.bk-daybar__d { display: grid; font-size: 1.05rem; line-height: 1.2; padding: 0 var(--s2); }
.bk-daybar__d small { font-size: 12px; font-weight: 400; color: var(--ink-3); }

.bk-places { width: 100%; }
.bk-places td, .bk-places th { padding: 10px 14px; }
.bk-places tr.is-cash td { background: var(--surface-2); }
.bk-places tr.is-total td { border-top: 2px solid var(--line-strong); font-weight: 600; }
.bk-places .pos, .bk-wherebar .pos { color: var(--go); }
.bk-places .neg { color: var(--stop); }

.bk-close {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s4);
  margin: var(--s4) 0; padding: var(--s4) var(--s5);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow-1);
}
.bk-close h3 { margin: 0 0 4px; }
.bk-close .hint { margin: 0; max-width: 62ch; }
.bk-close__acts { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center; }
.bk-close__acts button { display: inline-flex; align-items: center; gap: 6px; }
.bk-close__acts .ic { width: 16px; height: 16px; }

/* Полоса «где деньги» над оплатами: место — сумма, в конце — всего у фирмы. */

.bk-where li { font-size: .92rem; }
@media (max-width: 640px) {
  .bk-places td, .bk-places th { padding: 8px 8px; font-size: .88rem; }
  .bk-close { padding: var(--s4); }
}
.bk-where .is-sum b { font-size: 1.1rem; }
[data-skin="console"] :is(.till-due, .till-hero b, .tape b) {
  font-family: var(--sans); font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}

/* Смета: сумма строки не рвётся на «320.00» и «₼» в две строки — на узкой колонке
   это читалось как две разные цифры. На широком экране колонка сметы шире. */
.estim li b { white-space: nowrap; flex: 0 0 auto; }
@media (min-width: 1200px) { .adm { grid-template-columns: minmax(0, 1fr) 340px; } }
.bk-places__m { display: none; }
@media (max-width: 640px) {
  .bk-places th:nth-child(2), .bk-places td:nth-child(2),
  .bk-places th:nth-child(3), .bk-places td:nth-child(3),
  .bk-places th:nth-child(4), .bk-places td:nth-child(4) { display: none; }
  .bk-places__m { display: block; margin-top: 2px; }
  .bk-places tr.is-cash td { background: var(--surface-2); }
}

/* ── Время мастеров (кабинет супер-админа) ── */
.tmf { margin-bottom: 12px; gap: 6px; }
.tmf button { min-height: 36px; padding: 4px 12px; }
.tmcols { margin-bottom: 12px; }
.tmcols .row { gap: 4px 14px; padding: 8px 0; }
.tmgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 12px; }
.tmcard {
  display: grid; gap: 8px; padding: 14px 16px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
}
.tmcard--closed { opacity: .75; }
.tmcard__head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tmcard__line { margin: 0; font-size: .9rem; }
.tmcard__nums { margin: 0; display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: .86rem; color: var(--ink-2); }
.tmcard .note { margin: 0; }
.tmhands {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border-radius: 10px; background: var(--go-bg); color: var(--ink); text-decoration: none;
}
.tmhands small { display: block; color: var(--ink-2); }
.tmhands__t { margin-left: auto; font-variant-numeric: tabular-nums; font-size: 1.1rem; color: var(--go); }
.tmheat td[style] { background: color-mix(in srgb, var(--info) calc(var(--v) * 28%), transparent); }
.tmheat th.is-off { color: var(--ink-2); background: var(--surface-2); }
.tmheat th small { font-weight: 400; color: var(--ink-2); }
@media (max-width: 640px) {
  .tmgrid { grid-template-columns: 1fr; }
}

/* ─────────── очередь: полоса под шапкой (queue.js) ───────────
   Талоны с входа и вызов на табло. Липнет под шапкой: номер «кого звать» должен быть
   виден с любого экрана, а список на 10+ человек раскрывается вниз и листается сам. */
.qbar {
  position: sticky; top: var(--head-h, 52px); z-index: 25;
  background: var(--surface); border-bottom: 1px solid var(--line);
  padding: 6px 20px; font-size: .875rem;
}
.qbar__row { display: flex; align-items: center; gap: 8px 12px; flex-wrap: wrap; }
.qbar button { min-height: 32px; padding: 4px 12px; font-size: .8125rem; }
.qbar__title {
  display: inline-flex; align-items: center; gap: 8px; background: transparent; color: var(--ink);
  border: 0; padding: 4px 6px !important; cursor: pointer;
}
.qbar__title:hover { background: var(--surface-2, #f2f4f7); }
.qbar__n {
  min-width: 26px; padding: 1px 8px; border-radius: var(--r-pill); background: var(--line);
  font-weight: 700; text-align: center; font-variant-numeric: tabular-nums;
}
.qbar__n.is-on { background: var(--info); color: var(--info-ink); }
.qbar__sub { color: var(--ink-2, #5b6570); }
.qbar__chev { color: var(--ink-3, #8a939c); }
.qbar__no { font-size: 1.05rem; font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.qbar__mine {
  display: inline-flex; align-items: center; gap: 8px; padding: 3px 4px 3px 12px;
  border-radius: var(--r); border: 1px solid var(--go-line); background: var(--go-bg);
}
.qbar__mine.is-called { border-color: var(--info-line); background: var(--info-bg); }
.qbar__next { background: var(--go); color: var(--go-ink); border-color: var(--go); font-weight: 600; }
.qbar__give { background: var(--info); color: var(--info-ink); border-color: var(--info); font-weight: 600; }
.qbar__issue { display: inline-flex; gap: 6px; flex-wrap: wrap; margin-left: auto; }
.qbar__list {
  display: grid; gap: 4px; margin: 8px 0 4px; max-height: min(50vh, 420px); overflow-y: auto;
  overscroll-behavior: contain;
}
.qbar__item {
  display: grid; grid-template-columns: 56px minmax(0, 1fr) auto 72px auto; align-items: center; gap: 10px;
  padding: 4px 8px; border-radius: var(--r-sm); background: var(--canvas);
}
.qbar__item.is-other { opacity: .7; }
.qbar__what { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.qbar__st { font-size: .75rem; padding: 1px 8px; border-radius: var(--r-pill); background: var(--line); white-space: nowrap; }
.qbar__st--called { background: var(--info-bg); color: var(--info); }
.qbar__st--serving { background: var(--go-bg); color: var(--go); }
.qbar__min { text-align: right; font-variant-numeric: tabular-nums; color: var(--ink-2, #5b6570); }
.qbar__act { display: inline-flex; gap: 4px; }
.qbar__act button { min-height: 28px; padding: 2px 8px; }
.qticket { text-align: center; max-width: 360px; }
.qticket__no { font-size: 5.5rem; font-weight: 800; line-height: 1; letter-spacing: -.04em; margin: 6px 0 10px; font-variant-numeric: tabular-nums; }
@media (max-width: 720px) {
  .qbar { padding: 6px 12px; }
  .qbar__issue { margin-left: 0; width: 100%; }
  .qbar__item { grid-template-columns: 48px minmax(0, 1fr) 60px; }
  .qbar__item .qbar__st { display: none; }
  .qbar__act { grid-column: 1 / -1; justify-content: flex-end; }
}

/* ─────────── владелец: сотрудники (saPeople, saPerson) ───────────
   Строка — человек: где он сейчас, чем занят сегодня, сколько ему должны.
   Карточка — вкладки «Деньги / Доступ / Действия / Работа» вместо одной ленты. */
.pfilter { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; }
.pfilter__b {
  min-height: 32px; padding: 4px 12px; border-radius: var(--r-pill); font-size: .8125rem;
  background: var(--surface); color: var(--ink-2); border: 1px solid var(--line);
}
.pfilter__b b { margin-left: 4px; color: var(--ink); font-variant-numeric: tabular-nums; }
.pfilter__b[aria-selected="true"] { background: var(--ink); color: var(--surface); border-color: var(--ink); }
.pfilter__b[aria-selected="true"] b { color: var(--surface); }
.plist { display: grid; gap: 6px; padding: 8px; }
.prow {
  display: grid; grid-template-columns: 12px minmax(0, 1.4fr) minmax(0, 1.2fr) auto 120px;
  align-items: center; gap: 14px; width: 100%; text-align: left; padding: 10px 14px;
  background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: var(--r);
  min-height: 0; font-weight: 400;
}
.prow:hover { border-color: var(--ink-3); box-shadow: var(--shadow-1); background: var(--surface); }
.prow--off { opacity: .55; }
.prow__who, .prow__state, .prow__sum { display: flex; flex-direction: column; min-width: 0; }
.prow__who b { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.prow small { color: var(--ink-3, #8a939c); font-size: .75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.prow__state > span { font-size: .8125rem; }
.prow__sum { text-align: right; align-items: flex-end; }
.prow__sum.is-debt b { color: var(--stop); }
.prow__sum.is-clear b { color: var(--ink-3, #8a939c); }
.prow__dot { width: 10px; height: 10px; border-radius: 50%; background: var(--line-strong); }
.prow__dot--on { background: var(--go); box-shadow: 0 0 0 3px var(--go-bg); }
.prow__dot--away { background: var(--wait-line); }
.prow__dot--off { background: var(--stop-line); }
.phead { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.phead h2 { margin: 0; }
.phead .prow__dot { width: 12px; height: 12px; flex: none; }
.ptabs { display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin-bottom: 16px; overflow-x: auto; }
.ptabs__b {
  background: transparent; color: var(--ink-2); border: 0; border-bottom: 2px solid transparent;
  border-radius: 0; padding: 8px 16px; min-height: 40px; font-weight: 500;
}
.ptabs__b[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--accent); font-weight: 600; }
.ptabs__b:hover { background: transparent; color: var(--ink); }
.pgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
.pgrid > div { display: flex; flex-direction: column; gap: 2px; }
.pacts { margin-bottom: 12px; gap: 6px; }
tr.is-warn td { background: var(--wait-bg); }
@media (max-width: 760px) {
  .prow { grid-template-columns: 12px minmax(0, 1fr) auto; }
  .prow__state, .prow > .tag, .prow > span:empty { display: none; }
}

/* ═══════════════════ аналитика услуг ═══════════════════

   У каждой цифры — её пара из прошлого. Рост и падение несут стрелка и знак, а цвет
   лишь повторяет их: зелёный — лучше, красный — хуже, серый — так же. */
.svc__top { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s3); margin-bottom: var(--s4); }
.svc__top .bseg { max-width: 100%; }

.svd {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 2px 8px; border-radius: var(--r-pill);
  font: 600 .78rem/1.4 var(--sans); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.svd.is-up { color: var(--go); background: var(--go-bg); }
.svd.is-down { color: var(--stop); background: var(--stop-bg); }
.svd.is-flat { color: var(--ink-3); background: var(--surface-2); }
.svd + small { display: block; margin-top: 3px; font-size: .74rem; color: var(--ink-3); white-space: nowrap; }

/* Главная цифра: сколько работ, крупно, и рядом — деньги за них. */
.svhero {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--s5); align-items: center;
  padding: var(--s5); margin-bottom: var(--s3);
  border-radius: var(--r-lg);
  background: linear-gradient(158deg, var(--chrome) 0%, #14171d 60%, #1b2030 100%);
  color: #eef0f4; box-shadow: var(--shadow-2);
}
.svhero__l { display: block; font-size: .76rem; letter-spacing: .06em; text-transform: uppercase; color: #9aa1b2; }
.svhero__v {
  display: block; margin: 4px 0 8px;
  font-size: clamp(2.6rem, 7vw, 3.6rem); font-weight: 650; letter-spacing: -.04em; line-height: 1;
}
.svhero__d { display: flex; align-items: center; gap: var(--s2); }
.svhero__d .svd + small { display: inline; margin: 0; color: #9aa1b2; }
.svhero__vs { display: block; margin-top: var(--s3); font-size: .8rem; color: #8a91a2; }
.svhero .svd.is-up { color: #7fe0ae; background: rgba(127, 224, 174, .12); }
.svhero .svd.is-down { color: #ffad9f; background: rgba(255, 173, 159, .12); }
.svhero .svd.is-flat { color: #b7bdca; background: rgba(255, 255, 255, .08); }
.svhero__side { display: grid; gap: var(--s2); }
.svhero__side > div {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto auto;
  column-gap: var(--s3); align-items: center;
  padding: var(--s3) var(--s4); border-radius: var(--r);
  background: rgba(255, 255, 255, .05); border: 1px solid rgba(255, 255, 255, .07);
}
.svhero__side span { grid-column: 1; font-size: .8rem; color: #9aa1b2; }
.svhero__side b { grid-column: 1; font-size: 1.35rem; font-weight: 600; letter-spacing: -.02em; }
.svhero__side .svd { grid-column: 2; grid-row: 1 / span 2; }

.svks { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s3); margin-bottom: var(--s3); }
.svk {
  padding: var(--s3) var(--s4); border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow-1);
}
.svk__l { display: block; font-size: .78rem; color: var(--ink-3); }
.svk__v { display: block; margin: 2px 0 6px; font-size: 1.5rem; font-weight: 650; letter-spacing: -.03em; }
.svk__v span { font-size: .9rem; font-weight: 500; color: var(--ink-3); }

.svfacts {
  list-style: none; margin: 0 0 var(--s4); padding: var(--s2) var(--s4);
  border-radius: var(--r); background: var(--surface); border: 1px solid var(--line);
}
.svfacts li { display: flex; align-items: center; gap: var(--s3); padding: 7px 0; font-size: .9rem; color: var(--ink-2); }
.svfacts li + li { border-top: 1px solid var(--line); }
.svfacts .ic { flex-shrink: 0; width: 18px; height: 18px; color: var(--ink-3); }
.svfacts b { color: var(--ink); }

/* График: сплошная — сейчас, пунктир — тогда. Точка на конце — «мы здесь». */
.svc__chart { position: relative; padding: var(--s4); }
.svc__chart svg { display: block; width: 100%; height: 210px; overflow: visible; }
.svc__legend { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s4);
  margin-bottom: var(--s2); font-size: var(--fs-floor); color: var(--ink-2); }
.svc__legend b { margin-left: auto; color: var(--ink-3); font-weight: 500; }
.svc__key { display: inline-block; width: 18px; height: 0; margin-right: 6px; vertical-align: middle;
  border-top: 2.5px solid var(--info); }
.svc__key--prev { border-top: 2px dashed var(--ink-3); }
.svc__grid { stroke: var(--line); stroke-width: 1; vector-effect: non-scaling-stroke; }
.svc__area { fill: var(--info-bg); opacity: .8; }
.svc__line { fill: none; stroke: var(--info); stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.svc__prev { fill: none; stroke: var(--ink-3); stroke-width: 1.5; stroke-dasharray: 5 5; vector-effect: non-scaling-stroke; }
.svc__hit { fill: transparent; }
.svc__hit:hover { fill: rgba(127, 127, 127, .06); }
.svc__dot {
  position: absolute; width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px; pointer-events: none;
  border-radius: 50%; background: var(--info); box-shadow: 0 0 0 4px var(--info-bg);
}
.svc__plot { position: relative; }
.svc__axis { position: relative; height: 18px; margin-top: 8px; font-size: var(--fs-floor); color: var(--ink-3); }
.svc__axis span { position: absolute; top: 0; transform: translateX(-50%); white-space: nowrap; }
.svc__axis span:first-child { transform: none; }
.svc__axis span:last-child:not(:first-child) { transform: translateX(-100%); }
.bseg--sm button { min-height: 30px; padding: 3px 11px; font-size: .8rem; }

/* Строки «что и сколько»: имя с полоской доли, число, рост, деньги. */
.svrows { list-style: none; margin: 0; padding: 0; }
.svr {
  display: grid; grid-template-columns: minmax(0, 1fr) 56px 120px 150px;
  gap: var(--s3); align-items: center;
  padding: 10px var(--s4); border-bottom: 1px solid var(--line);
}
.svrows:last-child .svr:last-child { border-bottom: 0; }
.svr--head { padding-block: 8px; font-size: .74rem; letter-spacing: .04em; text-transform: uppercase; color: var(--ink-3); }
.svr__name b { display: block; font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svr__bar { display: block; height: 4px; margin-top: 6px; border-radius: 2px; background: var(--surface-2); overflow: hidden; }
.svr__bar i { display: block; height: 100%; border-radius: inherit; background: var(--info); }
.svr__n { font-size: 1.15rem; font-weight: 650; text-align: right; }
.svr__sum { text-align: right; font-weight: 600; white-space: nowrap; }
.svr__sum small { display: block; font-size: .74rem; font-weight: 400; color: var(--ink-3); }
.svr.is-gone .svr__name b, .svr.is-gone .svr__n { color: var(--ink-3); }

@media (max-width: 760px) {
  .svhero { grid-template-columns: 1fr; gap: var(--s4); padding: var(--s4); }
  .svks { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .svc__chart svg { height: 170px; }
  .svc__legend b { margin-left: 0; width: 100%; }
  .svr { grid-template-columns: minmax(0, 1fr) 40px auto; grid-template-areas: 'name n d' 'sum sum sum'; row-gap: 4px; }
  .svr__name { grid-area: name; } .svr__n { grid-area: n; } .svr__d { grid-area: d; text-align: right; }
  .svr__sum { grid-area: sum; text-align: left; font-weight: 500; font-size: .86rem; color: var(--ink-2); }
  .svr__sum small { display: inline; margin-left: 6px; }
  .svr--head { display: none; }
}

/* Строка аналитики раскрывается: модели и заявки под ней. Уголок перед именем
   поворачивается — видно, что строка нажимается и что она открыта. */
.svr.is-open-able { cursor: pointer; transition: background var(--fast); }
.svr.is-open-able:hover { background: var(--surface-2); }
.svr.is-open-able:focus-visible { outline: 2px solid var(--info); outline-offset: -2px; }
.svr.is-open-able .svr__name b::before {
  content: ''; display: inline-block; width: 6px; height: 6px; margin: 0 10px 2px 1px;
  border-right: 1.6px solid var(--ink-3); border-bottom: 1.6px solid var(--ink-3);
  transform: rotate(-45deg); transition: transform var(--fast);
}
.svr[aria-expanded="true"] { background: var(--surface-2); }
.svr[aria-expanded="true"] .svr__name b::before { transform: rotate(45deg); margin-bottom: 4px; }

.svx { padding: var(--s3) var(--s4) var(--s4); background: var(--surface-2); border-bottom: 1px solid var(--line); }
.svx h4 { margin: var(--s2) 0; font-size: .78rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--ink-3); }
.svx h4 .hint { margin-left: 4px; text-transform: none; }
.svx__cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--s4); }
.svx .chart { padding: var(--s2) 0; border: 0; }
.svx__list { list-style: none; margin: 0; padding: 0; border-radius: var(--r); background: var(--surface); border: 1px solid var(--line); overflow: hidden; }
.svx__list li + li { border-top: 1px solid var(--line); }
.svx__list a {
  display: grid; grid-template-columns: 120px minmax(0, 1.2fr) minmax(0, 1fr) auto 90px;
  gap: var(--s3); align-items: center; padding: 9px var(--s3);
  color: inherit; text-decoration: none; font-size: .88rem;
}
.svx__list a:hover { background: var(--info-bg); }
.svx__list b { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svx__when, .svx__code { color: var(--ink-3); font-size: .8rem; white-space: nowrap; }
.svx__code { font-family: var(--mono); }
.svx__what { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svx__what em { font-style: normal; color: var(--wait); }
.svx__sum { text-align: right; font-weight: 600; }
@media (max-width: 760px) {
  .svx { padding-inline: var(--s3); }
  .svx__list a { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: 'model sum' 'what code' 'when when'; row-gap: 2px; }
  .svx__list b { grid-area: model; } .svx__sum { grid-area: sum; } .svx__what { grid-area: what; }
  .svx__code { grid-area: code; text-align: right; } .svx__when { grid-area: when; }
}

/* ═══════════ деньги с работ: «Прибыль», «Мастера», «Модели» ═══════════
   Три цвета вычетов одни на весь раздел: серый — деталь, жёлтый — мастер,
   зелёный — то, что осталось точке. Маржа — цветной ярлык с порогами 15 и 35%. */
.svsplit__p { background: #9aa0ab; }
.svsplit__m { background: #e0a43a; }
.svsplit__n { background: var(--go); }

.svm { display: inline-block; min-width: 54px; padding: 2px 8px; border-radius: var(--r-pill); text-align: center;
  font: 650 .8rem/1.4 var(--sans); font-variant-numeric: tabular-nums; }
.svm.is-good { color: var(--go); background: var(--go-bg); }
.svm.is-mid { color: var(--wait); background: var(--wait-bg); }
.svm.is-low { color: var(--stop); background: var(--stop-bg); }
.svm.is-flat { color: var(--ink-3); background: var(--surface-2); }

.svsplit { display: flex; height: 6px; margin-top: 7px; border-radius: 3px; overflow: hidden; background: var(--surface-2); min-width: 4px; }
.svsplit i { display: block; height: 100%; }

/* Денежная таблица: имя с полосой состава, четыре числа, чистыми, маржа, рост. */
.svqrows { list-style: none; margin: 0; padding: 0; }
.svq {
  display: grid;
  grid-template-columns: minmax(150px, 1.6fr) 44px repeat(3, minmax(64px, .8fr)) minmax(96px, 1fr) 66px 104px;
  gap: var(--s3); align-items: center; padding: 10px var(--s4); border-bottom: 1px solid var(--line);
}
.svq__nums { display: contents; }
.svqrows:last-child .svq:last-child { border-bottom: 0; }
.svq--head { padding-block: 8px; font-size: .72rem; letter-spacing: .04em; text-transform: uppercase; color: var(--ink-3); }
.svq--head .num { text-align: right; }
.svq__name { min-width: 0; }
.svq__name b { display: block; font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svq__c { text-align: right; font-size: .9rem; }
.svq__c--minus { color: var(--ink-3); }
.svq__net { text-align: right; white-space: nowrap; }
.svq__net b { font-weight: 650; }
.svq__net small { display: block; font-size: .72rem; color: var(--ink-3); }
.svq.is-loss .svq__net b { color: var(--stop); }
.svq.is-gone .svq__name b, .svq.is-gone .svq__net b { color: var(--ink-3); }
.svq.is-open-able { cursor: pointer; transition: background var(--fast); }
.svq.is-open-able:hover { background: var(--surface-2); }
.svq.is-open-able:focus-visible { outline: 2px solid var(--info); outline-offset: -2px; }
.svq.is-open-able .svq__name b::before {
  content: ""; display: inline-block; width: 6px; height: 6px; margin: 0 10px 2px 1px;
  border-right: 1.6px solid var(--ink-3); border-bottom: 1.6px solid var(--ink-3);
  transform: rotate(-45deg); transition: transform var(--fast);
}
.svq[aria-expanded="true"] { background: var(--surface-2); }
.svq[aria-expanded="true"] .svq__name b::before { transform: rotate(45deg); margin-bottom: 4px; }

/* «Куда уходит оборот»: одна толстая полоса и легенда с суммами. */
.svflow { padding: var(--s4); display: grid; gap: var(--s3); }
.svflow__bar { display: flex; height: 22px; border-radius: var(--r-sm); overflow: hidden; background: var(--surface-2); }
.svflow__bar i { display: block; min-width: 0; }
.svflow__legend { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s3); }
.svflow__legend li {
  display: grid; grid-template-columns: 12px minmax(0, 1fr) auto; column-gap: var(--s2); row-gap: 2px; align-items: center;
  padding: var(--s3); border-radius: var(--r); border: 1px solid var(--line);
}
.svflow__legend li > i { width: 10px; height: 10px; border-radius: 3px; }
.svflow__legend span { font-size: .82rem; color: var(--ink-2); }
.svflow__legend b { grid-column: 2; font-size: 1.15rem; font-weight: 650; }
.svflow__legend em { grid-column: 3; grid-row: 1; font-style: normal; font-weight: 600; color: var(--ink-2); }
.svflow__legend .svd { grid-column: 2 / span 2; justify-self: start; margin-top: 4px; }
.svflow__legend .svd + small { grid-column: 2 / span 2; }
.svflow__prev { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--s3); align-items: center; font-size: .8rem; color: var(--ink-3); }
.svflow__prev .svflow__bar { height: 8px; opacity: .7; }

.svpct { display: flex; flex-wrap: wrap; align-items: center; gap: 6px var(--s2); font-size: .86rem; color: var(--ink-2); }
.svpct input { width: 76px; text-align: right; font-variant-numeric: tabular-nums; }
.svpct small { color: var(--ink-3); }
.svbar { margin-bottom: var(--s3); padding: var(--s3) var(--s4); border-radius: var(--r); background: var(--surface); border: 1px solid var(--line); }

.svks--6 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.svfacts li.is-go .ic { color: var(--go); }
.svfacts li.is-wait .ic { color: var(--wait); }
.svfacts li.is-stop .ic { color: var(--stop); }
.svfacts small { color: var(--ink-3); }
.svhero__v span { font-size: .45em; font-weight: 500; color: #9aa1b2; }
.svhero__v.is-neg { color: #ffad9f; }

/* Карточки мастеров: одна цифра — что принёс точке, под ней — из чего. */
.svmcs { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--s3); margin-bottom: var(--s4); }
.svmc { padding: var(--s4); border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow-1); }
.svmc__h { display: flex; justify-content: space-between; align-items: center; gap: var(--s2); }
.svmc__h b { font-size: 1rem; }
.svmc__v { margin: var(--s2) 0 4px; font-size: 1.6rem; font-weight: 650; letter-spacing: -.02em; }
.svmc__v small { display: block; font-size: .74rem; font-weight: 400; color: var(--ink-3); letter-spacing: 0; }
.svmc .svsplit { height: 8px; margin: var(--s3) 0; }
.svmc__dl { margin: 0; display: grid; grid-template-columns: 1fr 1fr; gap: var(--s2) var(--s3); }
.svmc__dl div { min-width: 0; }
.svmc__dl dt { font-size: .74rem; color: var(--ink-3); }
.svmc__dl dd { margin: 0; font-weight: 600; font-size: .92rem; }
.svmc__dl .svd { padding: 0 5px; font-size: .7rem; }
.svmc__dl .svd + small { display: none; }

/* Раскрытая строка: сводки и заявки с деньгами. */
.svmini { list-style: none; margin: 0; padding: 0; border-radius: var(--r); background: var(--surface); border: 1px solid var(--line); }
.svmini li { display: grid; grid-template-columns: minmax(0, 1fr) 32px 96px 62px; gap: var(--s2); align-items: center; padding: 7px var(--s3); font-size: .86rem; }
.svmini li + li { border-top: 1px solid var(--line); }
.svmini li > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svmini .num { text-align: right; }
.svmini li.hint { display: block; }
.svx__list a { grid-template-columns: 130px minmax(0, 1fr) minmax(0, 1.4fr) 62px; }
.svx__when { display: grid; gap: 2px; }
.svx__main { min-width: 0; display: grid; }
.svx__money { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) minmax(70px, auto); gap: var(--s2); text-align: right; white-space: nowrap; font-size: .84rem; }
.svx__money .is-minus { color: var(--ink-3); }
.svx__money b { font-weight: 650; }
.svx__money sup { color: var(--wait); font-weight: 700; }
.svx__list a.is-loss .svx__money b { color: var(--stop); }

@media (max-width: 760px) {
  .svq { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "name net" "nums m" "d d"; row-gap: 6px; padding-inline: var(--s3); }
  .svq--head { display: none; }
  .svq__name { grid-area: name; } .svq__net { grid-area: net; } .svq__m { grid-area: m; justify-self: end; } .svq__d { grid-area: d; }
  .svq__nums { grid-area: nums; display: flex; flex-wrap: wrap; gap: 2px 10px; min-width: 0; }
  .svq__c { font-size: .78rem; color: var(--ink-2); text-align: left; }
  .svq__c::before { content: attr(data-l) " "; color: var(--ink-3); }
  .svq__d { display: flex; align-items: center; gap: var(--s2); }
  .svq__d .svd + small { display: inline; margin: 0; }
  .svflow__legend { grid-template-columns: 1fr; }
  .svks--6 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .svmini li { grid-template-columns: minmax(0, 1fr) 26px 82px 56px; }
  .svx__list a { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "main m" "money money" "when when"; }
  .svx__main { grid-area: main; } .svx__money { grid-area: money; text-align: left; }
  .svx__list a > .svm { grid-area: m; } .svx__when { grid-area: when; display: flex; gap: var(--s2); }
}

/* Предоплата у владельца — прямо в смете, во всю ширину колонки. */
.estim__prepay { width: 100%; margin: var(--s2) 0; justify-content: center; gap: 6px; }

/* Фильтр купленных деталей: касса и «Должны поставщикам». */
.bf { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px 10px; margin: 10px 0 6px; }
.bf__f { display: flex; flex-direction: column; gap: 3px; min-width: 150px; flex: 0 1 200px; }
.bf__f span { font-size: .75rem; color: var(--ink-3); }
.bf__f select, .bf__f input { width: 100%; min-height: 38px; }
.bf__sum { margin: 2px 0 8px; font-size: .9rem; color: var(--ink-3); }
.bf__sum b { color: var(--ink); }
@media (max-width: 560px) { .bf__f { flex: 1 1 calc(50% - 10px); min-width: 0; } }

/* ═══════════════ касса и книги, переделка 2026-10-13 (books.js) ═══════════════
   Окно — две колонки людей у окна («Платят», «Забирают») и ящик сбоку. Карточка заявки —
   одна на все состояния, главное действие крупно. Списки истории — страницами. */
.wincols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s4); align-items: start; }
@media (max-width: 1180px) { .wincols { grid-template-columns: minmax(0, 1fr); } }
.wincol .tgroup + .tgroup { margin-top: 0; }
.wincol__more { justify-self: start; margin-top: 4px; }
.wincol__more b { font-family: var(--mono); margin-left: 4px; }

.ocard { gap: var(--s3); }
.ocard__head { display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap;
  padding: var(--s4); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-1); }
.ocard__who { flex: 1 1 260px; min-width: 0; }
.ocard__who h2 { margin: 0; font-size: 1.3rem; }
.ocard__who p { margin: 2px 0 0; color: var(--ink-2); }
.ocard__sum { display: grid; justify-items: end; gap: 2px; margin-left: auto; }
.ocard__sum span { font-size: .8rem; color: var(--ink-3); }
.ocard__sum b { font: 700 clamp(1.8rem, 6vw, 2.4rem)/1 var(--mono); letter-spacing: -.04em; }
.ocard__sum small { font-size: .78rem; color: var(--ink-3); font-family: var(--mono); }
.ocard__main { display: flex; flex-wrap: wrap; gap: var(--s2); }
.ocard__main .till-go { flex: 1 1 280px; margin: 0; }
.ocard__main .ghost { min-height: 56px; }
.ocard__acts { display: flex; flex-wrap: wrap; gap: 4px; }
.ocard__acts .ic { width: 15px; height: 15px; margin-right: 6px; vertical-align: -2px; }
.ocard .bk-cols { margin-bottom: 0; }

.pager { display: flex; align-items: center; justify-content: center; gap: var(--s3); margin: var(--s4) 0; flex-wrap: wrap; }
.pager__n { font: .9rem var(--mono); color: var(--ink-2); }

.bk-trust { display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 6px 12px;
  border-radius: var(--r-pill); background: var(--go-bg); color: var(--go); border: 1px solid var(--go-line);
  box-shadow: none; font: 500 .85rem/1 var(--sans); }
.bk-trust .ic { width: 16px; height: 16px; margin: 0; }
.bk-trust.is-bad { background: var(--stop-bg); color: var(--stop); border-color: var(--stop); }

.bk-inline { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; padding: 4px 0; }
.bk-inline > span:first-child { flex: 1 1 200px; min-width: 0; }
.bk-inline b { font-family: var(--mono); }

.bk-days { display: grid; grid-template-columns: repeat(14, minmax(36px, 1fr)); gap: 4px; margin-bottom: var(--s3); overflow-x: auto; }
.bk-days button { display: grid; justify-items: center; gap: 2px; min-height: 52px; padding: 4px 2px;
  background: var(--surface); color: var(--ink-2); border: 1px solid var(--line); border-radius: var(--r); box-shadow: none; font-size: .78rem; }
.bk-days i { font-style: normal; font-weight: 700; }
.bk-days .is-closed i { color: var(--go); }
.bk-days button[aria-current="true"] { border-color: var(--go); box-shadow: 0 0 0 1px var(--go) inset; color: var(--ink); }

.sup__title { margin: var(--s2) 0; font-size: 1.3rem; }
.sup__row { color: inherit; text-decoration: none; }
.sup__row:hover { background: var(--surface-2); }
.sup__bar { display: flex; flex-wrap: wrap; align-items: end; gap: var(--s2); padding: var(--s3) var(--s4) 0; }
.sup__table, .sup__pays { display: block; overflow-x: auto; }
.sup__table td:first-child { width: 32px; }
.sup__table input[type="checkbox"] { width: 20px; height: 20px; }
button.whand { text-align: left; cursor: pointer; box-shadow: none; color: var(--ink); font: inherit; }
button.whand:hover { border-color: var(--go); }


/* ═══════════════ касса и книга, редакция 2026-10-14 ═══════════════
   Очереди окна — переключателем с числами, инструменты — по риску, книга дня —
   с остатком места после каждой строки, «Где деньги» — одно окно со всеми местами. */
@media (min-width: 901px) { .tillmain { grid-template-columns: minmax(0, 1fr) 360px; } }
.till-top > button { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
@media (min-width: 1500px) { .tillmain { grid-template-columns: minmax(0, 1fr) 420px; } }
.winq { display: flex; gap: 8px; flex-wrap: wrap; }
.winq button { color: var(--ink); flex: 1 1 150px; display: grid; grid-template-columns: 1fr auto; align-items: baseline; gap: 2px 10px;
  min-height: 64px; padding: 10px 14px; text-align: left; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--shadow-1); }
.winq button span { font-weight: 600; }
.winq button b { font: 600 1.4rem/1 var(--mono); font-variant-numeric: tabular-nums; }
.winq button small { grid-column: 1 / -1; font-size: var(--fs-floor); color: var(--ink-3); font-family: var(--mono); }
.winq button:hover { border-color: var(--line-strong); }
.winq button[aria-current="true"] { border-color: var(--go); background: var(--go-bg); color: var(--ink); box-shadow: 0 0 0 1px var(--go) inset; }
.winq button[aria-current="true"] b { color: var(--go); }
.winq button.is-empty:not([aria-current="true"]) { color: var(--ink-3); box-shadow: none; }
.winq + .tgroup { margin-top: var(--s3); }
.tools__grid { grid-template-columns: 1fr 1fr; }
.tools__links { display: flex; gap: 6px; flex-wrap: wrap; }
.tools__links button { flex: 1 1 140px; }
.tool-danger { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%;
  margin-top: 14px; min-height: 46px; padding: 8px 12px; background: var(--surface); color: var(--stop);
  border: 1px solid var(--stop-line); border-radius: var(--r); font-weight: 600; cursor: pointer; }
.tool-danger span { flex: 1; text-align: left; }
.tool-danger small { font-weight: 400; font-size: var(--fs-floor); }
.tool-danger:hover { background: var(--stop-bg); }
.tape__row b { margin-left: auto; }
.tape__bal { font: 500 var(--fs-floor) var(--mono); font-variant-numeric: tabular-nums; color: var(--ink-3);
  min-width: 70px; text-align: right; white-space: nowrap; }
.wm { max-width: 520px; display: grid; gap: var(--s3); }
.wm__head { display: flex; align-items: center; justify-content: space-between; }
.wm__head h3 { margin: 0; }
.wm__list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: var(--r); }
.wm__list li + li { border-top: 1px solid var(--line); }
.wm__list a { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 14px;
  color: var(--ink); text-decoration: none; }
.wm__list a:hover { background: var(--surface-2); }
.wm__name { display: flex; align-items: center; gap: 10px; }
.wm__list .num { font: 600 1.05rem var(--mono); }
.wm__total { display: flex; justify-content: space-between; align-items: baseline; padding: 0 14px; }
.wm__total b { font: 700 1.4rem var(--mono); }
.bk-carry { display: flex; flex-wrap: wrap; gap: 6px 18px; padding: 10px 16px; background: var(--surface-2);
  color: var(--ink-2); font-size: var(--fs-floor); }
.bk-carry b { color: var(--ink); }
.bk-book { width: 100%; border-collapse: collapse; }
.bk-book th { text-align: left; font-size: var(--fs-floor); font-weight: 600; color: var(--ink-3); padding: 8px 10px;
  border-bottom: 1px solid var(--line); white-space: nowrap; }
.bk-book td { padding: 8px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
.bk-book td small { display: block; color: var(--ink-3); }
.bk-book .num { text-align: right; white-space: nowrap; font-family: var(--mono); }
.bk-book .pos { color: var(--go); }
.bk-book tr.is-flag td { background: var(--stop-bg); }
.bk-book tr.is-inner td { color: var(--ink-3); }
.bk-book__m { width: 30px; padding-right: 0 !important; }
.bk-mark { display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 6px;
  background: var(--stop); color: #fff; }
.bk-mark .ic { width: 14px; height: 14px; }
/* Экран оплаты: чек и способ оплаты рядом на широком экране, а не узкая колонка по центру. */
@media (min-width: 1100px) {
  .receipt { max-width: 1320px; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--s3) var(--s5); align-items: start; }
  .receipt > .row:first-child { grid-column: 1 / -1; }
  .receipt > .receipt__ticket { grid-row: span 6; }
}
[data-skin="console"] .today, [data-skin="console"] .cli { max-width: 1440px; }
@media (max-width: 720px) {
  .winq button { min-height: 56px; }
  .bk-book th:nth-child(4), .bk-book td:nth-child(4), .bk-book th:nth-child(5), .bk-book td:nth-child(5) { display: none; }
}
.solo-nolimit { margin-left: 8px; color: var(--stop); font-size: var(--fs-floor); font-weight: 600; }

/* Снабжение одним экраном (2026-10-15): поиск сверху, карточки поставщиков, история оплат. */
.sup__q { display: flex; margin-bottom: var(--s4); background: var(--surface); }
.sup__q input { flex: 1; min-width: 0; max-width: none; border: 0; box-shadow: none; background: transparent; min-height: 44px; padding: 0; font-size: 1rem; outline: none; }
.supcards { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--s3); margin-bottom: var(--s4); }
.supc { display: grid; gap: 6px; padding: var(--s4); color: inherit; text-decoration: none;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-1);
  transition: border-color var(--fast); }
.supc:hover { border-color: var(--go); }
.supc.is-late { border-left: 3px solid var(--stop); }
.supc__name { font-weight: 650; font-size: 1.05rem; overflow-wrap: anywhere; }
.supc__debt { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.supc__debt b { font: 700 1.5rem/1.1 var(--mono); letter-spacing: -.03em; }
.supc__debt small, .supc__row small, .supc__last { color: var(--ink-3); font-size: .78rem; }
.supc__row { display: grid; grid-template-columns: 1fr auto 2.2em; gap: 8px; font-size: .9rem; border-top: 1px dashed var(--line); padding-top: 4px; }
.supc__row b { font-family: var(--mono); }
.supc__row small { text-align: right; }
.sup__views { margin: var(--s2) 0 var(--s3); }
.sup__pays { width: 100%; }
.sup__pays td, .sup__pays th { padding: 8px 10px; vertical-align: top; }
/* Объединение поставщиков: карточка отмечается, а не открывается. */
.sup__top { display: flex; gap: var(--s2); align-items: center; flex-wrap: wrap; margin-bottom: var(--s4); }
.sup__top .sup__q { flex: 1 1 320px; margin: 0; }
.sup__merge { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; margin-bottom: var(--s3); }
button.supc { text-align: left; font: inherit; cursor: pointer; }
.supc--pick[aria-pressed="true"] { border-color: var(--go); box-shadow: 0 0 0 2px var(--go) inset; background: var(--go-bg); }

/* ═══ дизайн-ревью кассы и книг, 2026-10-15 ═══ */
/* Кнопка со значком: значок и подпись в одну строку (у блочных кнопок значок вставал над текстом). */
.tools__links button, .ocard__acts button, .sup__top > button, .bk-close__acts button, .till-top > button {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.tools__links button .ic, .ocard__acts button .ic, .sup__top > button .ic { margin: 0; flex: 0 0 auto; }
/* Боковая панель кассы узкая: инструменты одним столбцом, подпись — одной строкой рядом с названием. */
.till-side .tools__grid { grid-template-columns: minmax(0, 1fr); }
.till-side .tool small { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.till-side .tool span { min-width: 0; }
/* Кнопка «Назад» в шапке кассы — без отступа-призрака слева. */
.till-back-btn { padding-left: 4px; padding-right: 8px; }
/* Подпись поля под плитками способа оплаты не прилипает к ним. */
.till-ways + .till-field, .till-ways ~ .till-field { margin-top: var(--s3); }

@media (max-width: 720px) {
  /* Телефон: в шапке кассы — остаток и значки в одну строку, поиск — второй строкой.
     Было четыре строки шапки, и первый клиент начинался ниже середины экрана. */
  .till-top { gap: 4px; padding: 8px 10px; }
  .till-top .till-hero { padding: 6px 10px; }
  .till-top .till-hero .ic { display: none; }
  .till-top > button .lbl { display: none; }
  .till-top > button { min-width: 42px; min-height: 44px; padding: 8px; }
  .till-top > button .ic { margin: 0; }
  .till-top .till-hero { flex: 1 1 0; min-width: 0; justify-content: flex-start; white-space: nowrap; overflow: hidden; }
  .till-top .till-hero > span { display: none; }
  .till-top .till-search { order: 9; flex: 1 1 100%; }
  .till-top .spacer { display: none; }
  /* Очереди — одна строка, листается пальцем, а не три строки плиток. */
  .winq { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; margin: 0 -4px; padding: 0 4px 2px; }
  .winq::-webkit-scrollbar { display: none; }
  .winq button { flex: 0 0 auto; min-width: 128px; }
}

/* Подсказка под полем (askForm: pick/combo) — в потоке, чтобы прокрутка окна её не обрезала */
.sugg { display: flex; flex-direction: column; max-height: 220px; overflow-y: auto; margin-top: 4px;
  border: 1px solid var(--line-strong); border-radius: 8px; background: var(--surface); }
.sugg[hidden] { display: none; }
.sugg button { all: unset; box-sizing: border-box; padding: 10px 12px; cursor: pointer; border-bottom: 1px solid var(--line); }
.sugg button:last-child { border-bottom: 0; }
.sugg button:hover, .sugg button.on { background: var(--surface-2); }

/* ─── телефон: проверка 2026-10-17 ─── */

/* Закрытое меню «⋯» не должно занимать место. Панель у меню position: fixed и display: grid,
   и у закрытого <details> она оставалась в раскладке невидимой — в «Справочник → Техника»
   растягивала страницу на 34px вправо, а вслед за страницей уезжала нижняя панель. */
.menu:not([open]) > .menu__body { display: none; }

/* Фильтры списка заявок на телефоне: поиск во всю ширину, марка и «по какой дате» рядом,
   «с — по» одной строкой. Раньше пять строк фильтров закрывали весь первый экран, а
   поля дат разъезжались на две строки с одиноким «—» посередине. */
.ofbar__dates { display: inline-flex; align-items: center; gap: 6px; }
@media (max-width: 600px) {
  .ofbar { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .ofbar > #ofQ, .ofbar__dates, .ofbar [data-ofreset] { grid-column: 1 / -1; }
  .ofbar > select { min-width: 0; width: 100%; }
  .ofbar__dates { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
  .ofbar__dates input { min-width: 0; width: 100%; }
}

/* «срок прошёл», «молчат дольше трёх дней» — ссылки-фильтры высотой 22px: по ним промахивается палец. */
.balert .linkish { display: inline-block; min-height: 36px; padding: 7px 0; }

/* Подписи 9px («№ заявки», «дней») и часы на ленте журнала — на грани читаемого. */
.task__no small { font-size: .7rem; }
.jhours__c span { font-size: .7rem; }

/* Дерево техники: метки «только магазин — и всё внутри», «не на сайте — и всё внутри»
   не переносились и вылезали за экран на 34px. Переносятся, когда места не хватает. */
.mnode__label { flex-wrap: wrap; }
.mnode__label .tag { white-space: normal; }
