/*
 * Дизайн-система Bliss & Epil.
 *
 * Структура и имена токенов взяты из проекта Pradex Reports — там она
 * обкатана на живых отчётах, и совпадение имён позволяет переносить
 * готовые компоненты без правок.
 *
 * Палитра и шрифт — из панели на Apps Script (legacy/apps_script/Index.html):
 *   фон #F5F5F7 · карточка #fff · текст #1C1C1E · подпись #86868B
 *   линия #E6E6EA · зелёный #2FA96B · красный #D1495B
 *   системный шрифт (-apple-system / Segoe UI / Roboto), 400/600/700
 * Своё оставлено: акцент #AF8578 на кнопках, золото логотипа #FFBA24,
 * форма кнопок-пилюль.
 *
 * Шрифт системный: ничего не грузим, и текст рисуется гарнитурой,
 * привычной для той ОС, где панель открыли.
 */

*, *::before, *::after {
  box-sizing: border-box; margin: 0; padding: 0;
  -webkit-tap-highlight-color: transparent;
}
html, body { overflow-x: hidden; max-width: 100%; }
/* Ощущение приложения на iOS: без двойного тап-зума и авто-ресайза текста */
html { touch-action: manipulation; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

/* В режиме приложения экран не должен разъезжаться от случайного жеста.
   В браузере щипок остаётся: это средство доступности. */
@media (display-mode: standalone) {
  html, body { touch-action: pan-x pan-y; overscroll-behavior: none; }
  /* Длинное нажатие не должно выделять текст интерфейса — в приложениях
     так не бывает. Поля ввода и текст отчётов исключены: там выделять нужно. */
  body { -webkit-user-select: none; user-select: none; }
  .input, textarea, pre.tg, .tbl td { -webkit-user-select: text; user-select: text; }
}

:root, [data-theme="light"] {
  /* Палитра и шрифт — из панели на Apps Script (legacy/apps_script/Index.html):
     нейтральный серый фон, чистый белый лист карточки, системный шрифт.
     Акцент оставлен свой, пудрово-коричневый: он на кнопках. */
  --bg:        #F5F5F7;
  --bg2:       #FFFFFF;
  --bg3:       #F0F0F3;   /* наведение, «тихие» плашки */
  --txt:       #1C1C1E;
  --txt2:      #48484A;
  --muted:     #86868B;
  --title-soft:#919191;   /* крупные заголовки в макетах SMM */
  --accent:    #AF8578;   /* кнопки — как было */
  --acc-h:     #9A7266;
  --acc-s:     #F3EAE6;
  --gold:      #FFBA24;   /* логотип */
  --accent-2:  #B29A80;   /* вторая плашка, chipColor из SMM */
  --success:   #2FA96B;
  --danger:    #D1495B;
  --border:    #E6E6EA;
  --field:     #FBFBFD;   /* поля чуть темнее листа — так их видно на белой карточке */
  --shadow:    rgba(28,28,30,.10);
  --font:      -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --radius:    14px;
  --radius-s:  10px;
  --radius-pill: 40px;
  --active-bg: var(--accent);
  --active-fg: #fff;
  --active-sh: 0 4px 14px rgba(175,133,120,.30);
}

[data-theme="dark"] {
  --field:   #302C28;
  --bg:      #1C1A18;
  --bg2:     #262320;
  --bg3:     #302C28;
  --txt:     #F0EDE8;
  --txt2:    #C4BAB2;
  --muted:   #7E756C;
  --accent:  #C79A8C;
  --acc-h:   #AF8578;
  --acc-s:   #2E2320;
  --border:  #3A342F;
  --shadow:  rgba(0,0,0,.35);
  --active-sh: 0 4px 14px rgba(199,154,140,.28);
}

/* ── Стеклянные темы ────────────────────────────────────────
 * Перенесено из Pradex Reports: матовые поверхности поверх мягкого
 * градиента. Там это обкатано, поэтому взята механика — blur + saturate
 * + внутренняя световая кромка. Цвета свои: пудра, песок и тёплый белый
 * из фирменной палитры, вместо охры Прадекса.
 *
 * Полупрозрачность работает только если под ней есть что размывать,
 * поэтому фон — три мягких пятна, а не заливка.
 */
[data-theme="glass-light"] {
  --bg: radial-gradient(120% 85% at 0% 0%,   #F3E6E1 0%, rgba(243,230,225,0) 55%),
        radial-gradient(120% 90% at 100% 8%, #EFE7DE 0%, rgba(239,231,222,0) 52%),
        radial-gradient(110% 100% at 50% 120%, #F1EFE8 0%, rgba(241,239,232,0) 55%),
        #F6F6F3;
  --bg2:      rgba(255,255,255,.55);
  --field:    rgba(255,255,255,.42);
  --bg3:      rgba(255,255,255,.40);
  --txt:      #2A2320;
  --txt2:     #5C5049;
  --muted:    #8A8A8A;
  --accent:   #AF8578;
  --acc-h:    #9A7266;
  --acc-s:    rgba(175,133,120,.14);
  --border:   rgba(255,255,255,.65);
  --shadow:   rgba(90,66,58,.14);
  --blur:     22px;
  --sat:      180%;
  --s-hi:     rgba(255,255,255,.80);
  --divider:  rgba(90,66,58,.18);
  --active-bg: rgba(175,133,120,.50);
  --active-sh: 0 6px 18px rgba(175,133,120,.28);
}

[data-theme="glass-dark"] {
  --bg: radial-gradient(120% 85% at 0% 0%,   #2A211D 0%, rgba(42,33,29,0) 55%),
        radial-gradient(120% 90% at 100% 8%, #241E1B 0%, rgba(36,30,27,0) 52%),
        #171412;
  --bg2:      rgba(42,36,32,.74);
  --field:    rgba(0,0,0,.20);
  --bg3:      rgba(36,30,27,.66);
  --txt:      #F4EFEA;
  --txt2:     #D6CCC5;
  --muted:    #9A918A;
  --accent:   #C79A8C;
  --acc-h:    #AF8578;
  --acc-s:    rgba(199,154,140,.18);
  --border:   rgba(255,255,255,.14);
  --shadow:   rgba(0,0,0,.45);
  --blur:     18px;
  --sat:      150%;
  --s-hi:     rgba(255,255,255,.14);
  --divider:  rgba(255,255,255,.16);
  --active-bg: rgba(199,154,140,.42);
  --active-sh: 0 6px 18px rgba(0,0,0,.42);
}

/* Матовость — только поверхностям, не тексту и не мелким элементам:
   blur стоит дорого, а на подписях он ничего не даёт. */
[data-theme^="glass"] :is(.card, .stat, .nav, .table-wrap, .btn-quiet, .btn-ghost) {
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  backdrop-filter: blur(var(--blur)) saturate(var(--sat));
}
[data-theme^="glass"] :is(.card, .stat, .table-wrap) {
  box-shadow: 0 10px 30px var(--shadow), inset 0 1px 0 var(--s-hi);
}
[data-theme^="glass"] .nav { box-shadow: inset -1px 0 0 var(--s-hi); }
[data-theme^="glass"] :is(.tbl th, .tbl td) { border-bottom-color: var(--divider); }
[data-theme^="glass"] .nav-item.active { box-shadow: var(--active-sh); }
@media (hover: hover) { [data-theme^="glass"] .tbl tr:hover td { background: rgba(255,255,255,.28); } }

/* Устройства без backdrop-filter (старые Android) получат плотный фон,
   иначе текст ляжет на градиент и станет нечитаемым. */
@supports not (backdrop-filter: blur(1px)) {
  [data-theme="glass-light"] { --bg2: rgba(255,255,255,.92); --bg3: rgba(255,255,255,.86); }
  [data-theme="glass-dark"]  { --bg2: rgba(42,36,32,.96);   --bg3: rgba(36,30,27,.94); }
}

body {
  font-family: var(--font);
  font-weight: 400;
  background: var(--bg);
  background-attachment: fixed;
  color: var(--txt);
  min-height: 100vh;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
a.btn { text-decoration: none; }

/* ── Типографика ───────────────────────────────────────────── */
h1, h2, h3 { font-weight: 600; line-height: 1.25; }
h1 { font-size: clamp(22px, 4vw, 28px); }
h2 { font-size: 20px; }
h3 { font-size: 15px; }
.page-title { font-size: 22px; font-weight: 700; margin-bottom: 2px; }
.page-sub   { color: var(--muted); font-size: 13px; margin-bottom: 20px; max-width: 860px; }
.brand {
  font-weight: 700; font-size: 16px; padding: 6px 10px 16px;
  position: sticky; top: -18px; background: var(--bg2); z-index: 1;
}
.brand .amp { color: var(--accent); }
.eyebrow {
  font-size: 11px; font-weight: 600; letter-spacing: .34em;
  text-transform: uppercase; color: var(--accent);
}

/* ── Каркас ────────────────────────────────────────────────── */
.app { display: flex; min-height: 100vh; }
.nav {
  width: 220px; flex-shrink: 0; background: var(--bg2);
  border-right: 1px solid var(--border); padding: 18px 12px;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: #d0d0d6 transparent;
}
.nav::-webkit-scrollbar { width: 6px; }
.nav::-webkit-scrollbar-thumb { background: #d0d0d6; border-radius: 3px; }
.nav::-webkit-scrollbar-track { background: transparent; }
.main { flex: 1; min-width: 0; }
.content { max-width: 1360px; margin: 0 auto; padding: 24px 24px 120px; }

.nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: var(--radius-s);
  font-size: 14px; cursor: pointer; margin-bottom: 2px;
  user-select: none; color: var(--txt2);
  transition: background .12s ease, color .12s ease;
}
.nav-item:hover  { background: var(--bg3); color: var(--txt); }
.nav-item:active { transform: scale(.99); }
.nav-item.active {
  background: var(--acc-s); color: var(--accent); font-weight: 600;
}
.nav-item .ic   { width: 18px; text-align: center; }
.nav-item .soon {
  margin-left: auto; font-size: 10px; color: var(--muted);
  background: var(--bg3); padding: 2px 7px; border-radius: 8px;
}

/* ── Карточки и метрики ────────────────────────────────────── */
.card {
  background: var(--bg2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px; margin-bottom: 14px;
}
.card h3 { margin-bottom: 10px; }

.stats { display: flex; gap: 10px; margin-bottom: 18px; flex-wrap: wrap; }
.stat {
  flex: 1; min-width: 80px; background: var(--bg2);
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 12px 14px;
}
.stat .num { font-size: 22px; font-weight: 700; }
.stat .lbl {
  font-size: 11px; color: var(--muted);
  text-transform: uppercase; letter-spacing: .04em;
}
.stat.sel .num { color: var(--accent); }

.kv {
  display: flex; justify-content: space-between; gap: 16px;
  padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 14px;
}
.kv:last-child { border-bottom: 0; }
.kv .k { color: var(--muted); }
/* Цифры в столбик читаются, только если знаки одной ширины */
.kv .v { font-variant-numeric: tabular-nums; }

/* ── Кнопки ────────────────────────────────────────────────
 * Форма — из панели на Apps Script: прямоугольник со скруглением 10.
 * Цвет свой, пудрово-коричневый.
 */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 9px 16px; border: 1px solid transparent;
  border-radius: var(--radius-s);
  font-family: var(--font); font-size: 14px; font-weight: 600;
  cursor: pointer; background: var(--accent); color: #fff;
  transition: background .12s ease, transform .08s ease;
}
/* Отклик на нажатие, а не на отпускание — так интерфейс кажется живым */
.btn:hover  { background: var(--acc-h); }
.btn:active { transform: scale(.97); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn[disabled] { opacity: .45; cursor: not-allowed; }

.btn-ghost {
  background: transparent; color: var(--accent);
  border-color: var(--accent);
}
.btn-ghost:hover { background: var(--acc-s); }

/* Второстепенная кнопка в старой панели — белая с рамкой, не серая
   заливка: рядом с акцентной она не спорит за внимание. */
.btn-quiet {
  background: var(--bg2); color: var(--txt); border-color: var(--border);
  font-weight: 400;
}
.btn-quiet:hover { background: var(--bg3); }

.btn-mini { padding: 7px 12px; font-size: 12px; border-radius: 9px; }

/* ── Поля ──────────────────────────────────────────────────── */
.field { display: block; margin-bottom: 14px; }
.field > .lbl {
  display: block; font-size: 12px; color: var(--muted); margin-bottom: 6px;
}
.input, select.input, textarea.input {
  width: 100%; padding: 9px 12px;
  border: 1px solid var(--border); border-radius: var(--radius-s);
  background: var(--field); color: var(--txt);
  font-family: var(--font); font-size: 14px;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.input:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--acc-s);
}

/* ── Ярлыки и статусы ──────────────────────────────────────── */
.badge {
  display: inline-block; font-size: 11px; font-weight: 600;
  padding: 3px 8px; border-radius: 20px;
  background: var(--bg3); color: var(--txt2);
}
.badge.ok     { background: rgba(47,169,107,.14);  color: var(--success); }
.badge.warn   { background: rgba(255,186,36,.18);  color: #A8781A; }
.badge.err    { background: rgba(209,73,91,.12);   color: var(--danger); }
.badge.accent { background: var(--acc-s);          color: var(--accent); }
/* Синяя — про интервал клиента. Цвет закреплён за смыслом: в списке
   «Пора записаться» глаз ищет интервал и срок, и они не должны менять
   вид от того, просрочен клиент или нет. */
.badge.info   { background: rgba(56,120,255,.14);  color: #2F6BE0; }

/* ── Таблицы ───────────────────────────────────────────────── */
.table-wrap { overflow-x: auto; }
table.tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.tbl th {
  text-align: left; font-weight: 600; font-size: 11px;
  color: var(--muted); text-transform: uppercase; letter-spacing: .04em;
  padding: 8px 10px; background: var(--bg3);
  white-space: nowrap;
}
.tbl td { padding: 8px 10px; border-bottom: 1px solid var(--border); }
.tbl tr:last-child td { border-bottom: 0; }
/* Подсветка строки только там, где есть указатель: на телефоне это
   выглядит как «залипшее» серое выделение после каждого касания. */
@media (hover: hover) { .tbl tbody tr:hover td { background: var(--bg); } }
.tbl .num { text-align: right; font-variant-numeric: tabular-nums; }

/* Поля прямо в клетке. Обычные .input рассчитаны на форму: с их
   отступами строка таблицы вырастает вдвое и список перестаёт
   читаться взглядом сверху вниз. */
.tbl .input { padding: 7px 10px; font-size: 13px; }
.tbl td small { display: block; margin-top: 2px; font-size: 11px; }

/* Служебные столбцы — переключатели и кнопки — занимают ровно себя.
   Всю остальную ширину забирают поля, иначе именно они и обрезаются. */
.tbl .col-sw  { width: 1%; text-align: center; white-space: nowrap; }
.tbl .col-act { width: 1%; white-space: nowrap; }
.tbl .col-act .row { flex-wrap: nowrap; }
/* Ряд кнопок прямо в клетке остаётся клеткой: превратив td во флекс,
   мы теряли нижнюю линейку строки — список визуально распадался. */
.tbl td.row { display: table-cell; white-space: nowrap; }
.tbl td.row > .btn + .btn { margin-left: 6px; }

/* Скрытый телефон: не пустая клетка, а явный знак «нет доступа» */
.phone-hidden { color: var(--muted); }
.phone-hidden::after { content: 'нет доступа'; font-size: 12px; }

/* «Здесь пусто» — отдельное состояние, а не пустая карточка: иначе
   человек не понимает, данных нет или страница не догрузилась. */
.empty, .loading { padding: 40px; text-align: center; color: var(--muted); font-size: 14px; }

/* ── Мелочи ────────────────────────────────────────────────── */
.muted { color: var(--muted); }
.right { text-align: right; }
.row   { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.spacer{ flex: 1; }
hr.sep { border: 0; border-top: 1px solid var(--border); margin: 18px 0; }

/* ── Адаптив: до 768 меню уезжает в выдвижную панель ───────── */
.burger { display: none; }

/* Затемнение под меню: и видно, что оно поверх страницы, и закрыть
   можно тапом мимо — на телефоне это привычнее кнопки «закрыть». */
.nav-veil {
  display: none; position: fixed; inset: 0; z-index: 29;
  background: rgba(0, 0, 0, .35);
  opacity: 0; transition: opacity .22s ease;
}
.nav-veil.on { display: block; opacity: 1; }
@media (max-width: 768px) {
  .nav {
    position: fixed; left: 0; top: 0; z-index: 30;
    transform: translateX(-100%);
    transition: transform .22s cubic-bezier(.22,1,.36,1);
    box-shadow: 0 0 40px var(--shadow);
  }
  .nav.open { transform: none; }
  .nav-item { padding: 13px 14px; font-size: 15px; }
  .burger { display: inline-flex; }
  .content { padding: 16px 16px 100px; }
  .stat { min-width: calc(50% - 5px); }
}

/* Кнопка меню. Квадрат 44×44 — минимальная цель для пальца
   по рекомендациям Apple; меньше — люди промахиваются. */
.burger {
  align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: 0 0 44px;
  margin-right: 10px; border-radius: var(--radius-s);
  background: var(--bg2); border: 1px solid var(--border);
  font-size: 18px; line-height: 1; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.burger:active { transform: scale(.96); }

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

/* ── Мобильное: ведёт себя как приложение ──────────────────
 * Правила подобраны так, чтобы страницу НЕ приходилось увеличивать:
 *   • поля ввода 16px — иначе iOS сам зумит экран при фокусе
 *     и обратно не отъезжает;
 *   • touch-action: manipulation убирает зум по двойному тапу
 *     (стоит выше, в html) — щипком увеличить всё ещё можно,
 *     это нужно людям со слабым зрением;
 *   • safe-area — чтобы контент не лез под «чёлку» и полосу жестов;
 *   • меню внизу: до верха экрана большим пальцем не дотянуться.
 */
@media (max-width: 768px) {
  .input, select.input, textarea.input { font-size: 16px; }
}

.tabbar { display: none; }

@media (max-width: 768px) {
  .app { flex-direction: column; }

  /* Меню на телефоне не прячется совсем, а выезжает по кнопке.
     Раньше его тут просто выключали, и на телефоне были доступны
     только пять разделов из нижней панели — остальные найти было
     нельзя вовсе. */
  .nav {
    display: block; width: 82vw; max-width: 300px;
    padding-top: calc(18px + env(safe-area-inset-top));
    padding-bottom: calc(18px + env(safe-area-inset-bottom));
  }

  .content {
    padding: calc(12px + env(safe-area-inset-top)) 14px
             calc(84px + env(safe-area-inset-bottom));
  }

  /* Нижнее меню — как в приложении */
  .tabbar {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    background: var(--bg2); border-top: 1px solid var(--border);
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom));
    /* СВОЙ СЛОЙ — ОБЯЗАТЕЛЬНО. Без него iOS перерисовывает закреплённую
       панель ПОСЛЕ инерционной прокрутки: полоса отстаёт от экрана и
       на полсекунды зависает посреди списка — выглядит как плавающие
       кнопки. `translateZ(0)` отдаёт её композитору, и она едет
       вместе с экраном, а не догоняет его.
       Потомков с `position: fixed` внутри нет — иначе трансформация
       предка сделала бы их относительными, и это сломалось бы тихо. */
    transform: translateZ(0);
    will-change: transform;
  }
  .tabbar .tab {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
    padding: 8px 2px; border-radius: var(--radius-s);
    font-size: 11px; color: var(--muted); cursor: pointer; user-select: none;
    -webkit-tap-highlight-color: transparent;
  }
  .tabbar .tab .ic { font-size: 18px; line-height: 1; }
  .tabbar .tab.active { color: var(--accent); }
  .tabbar .tab:active { background: var(--bg3); }

  /* Пальцем: цели не меньше 44px, как в рекомендациях Apple */
  .btn { padding: 13px 22px; min-height: 44px; }
  .btn-mini { padding: 10px 16px; min-height: 40px; }
  .card { padding: 14px; border-radius: 12px; }
  .stat { min-width: calc(50% - 5px); }

  /* Таблицы на телефоне превращаются в карточки: горизонтальная
     прокрутка в списке людей — это всегда промах пальцем */
  .tbl.cards, .tbl.cards thead { display: block; }
  .tbl.cards colgroup { display: none; }
  .tbl.cards thead { display: none; }
  .tbl.cards tbody, .tbl.cards tr { display: block; }
  .tbl.cards tr {
    border: 1px solid var(--border); border-radius: 12px;
    padding: 10px 12px; margin-bottom: 10px; background: var(--bg2);
  }
  .tbl.cards td { display: flex; justify-content: space-between; gap: 12px;
                  padding: 6px 0; border: 0; }
  .tbl.cards td::before { content: attr(data-l); color: var(--muted); font-size: 12px; }
  .tbl.cards td:first-child { font-weight: 600; font-size: 16px; }
  .tbl.cards td:first-child::before { content: none; }
}

/* Список переключателей функций */
.feat { display: flex; align-items: center; gap: 12px; padding: 11px 0;
        border-bottom: 1px solid var(--border); }
.feat:last-child { border-bottom: 0; }
.feat .t { flex: 1; min-width: 0; }
.feat .t b { display: block; font-weight: 600; font-size: 14px; }
.feat .t small { color: var(--muted); font-size: 12px; }
.feat.off .t b { color: var(--muted); }

/* Переключатель.
   Выключенное состояние должно быть ВИДНО: на светлом фоне и в стеклянной
   теме полупрозрачная дорожка сливалась со страницей, и было непонятно,
   выключатель это или просто украшение. Поэтому дорожка залита плотным
   цветом, с внутренней тенью и заметной рамкой. */
.sw { display: inline-block; vertical-align: middle;
      position: relative; width: 50px; height: 30px; flex-shrink: 0; cursor: pointer; }
.sw input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.sw i {
  position: absolute; inset: 0; border-radius: 999px;
  background: #DCD6CE;
  border: 1px solid rgba(0,0,0,.16);
  box-shadow: inset 0 1px 3px rgba(0,0,0,.16);
  transition: background .15s ease, border-color .15s ease;
}
.sw i::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 22px; height: 22px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.28);
  transition: transform .18s cubic-bezier(.22,1,.36,1);
}
.sw input:checked + i {
  background: var(--accent);
  border-color: rgba(0,0,0,.12);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.12);
}
.sw input:checked + i::after { transform: translateX(20px); }
.sw input:focus-visible + i { outline: 2px solid var(--accent); outline-offset: 2px; }
.sw input:disabled + i { opacity: .45; cursor: not-allowed; }

[data-theme="dark"] .sw i, [data-theme="glass-dark"] .sw i {
  background: #4A423B; border-color: rgba(255,255,255,.18);
  box-shadow: inset 0 1px 3px rgba(0,0,0,.4);
}
[data-theme="dark"] .sw i::after, [data-theme="glass-dark"] .sw i::after { background: #EDE7E0; }

/* Полоска состояния сохранения */
.toast { position: fixed; left: 50%; transform: translateX(-50%) translateY(20px);
  bottom: calc(88px + env(safe-area-inset-bottom)); z-index: 60;
  background: var(--txt); color: var(--bg2); padding: 11px 20px;
  border-radius: 999px; font-size: 14px; opacity: 0; pointer-events: none;
  transition: opacity .18s ease, transform .18s cubic-bezier(.22,1,.36,1); }
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
@media (min-width: 769px) { .toast { bottom: 28px; } }

/* Полоса сохранения: настройки не сохраняются молча — случайный тап
   не должен менять чьи-то права. */
.savebar {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(88px + env(safe-area-inset-bottom)); z-index: 70;
  display: flex; align-items: center; gap: 10px;
  background: var(--bg2); border: 1px solid var(--border);
  border-radius: 999px; padding: 8px 8px 8px 18px;
  box-shadow: 0 10px 30px var(--shadow);
  font-size: 13px; color: var(--txt2);
  backdrop-filter: blur(14px);
  max-width: calc(100vw - 24px);
}
.savebar[hidden] { display: none; }
.savebar span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (min-width: 769px) { .savebar { bottom: 24px; } }
@media (max-width: 420px) { .savebar span { display: none; } }

/* Свёрнутые настройки в меню — как в старой панели */
.nav-sep { height: 1px; background: var(--border); margin: 12px 6px 10px; }
.nav-toggle {
  display: flex; align-items: center; gap: 7px; cursor: pointer; user-select: none;
  padding: 7px 12px; margin-bottom: 2px; border-radius: var(--radius-s);
  font-size: 11px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted);
}
.nav-toggle:hover { background: var(--bg3); color: var(--txt); }
.nav-arrow { display: inline-block; font-size: 9px; transition: transform .18s ease; }
.nav-toggle.open .nav-arrow { transform: rotate(90deg); }
.nav-fold { display: none; }
.nav-fold.open { display: block; }

/* Функция с выбором ролей: кому она доступна */
.featbox { padding: 12px 0; border-bottom: 1px solid var(--border); }
.featbox:last-child { border-bottom: 0; }
.featbox.off .t b { color: var(--muted); }

.roles { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; padding-left: 2px; }
.chip {
  display: inline-flex; align-items: center; cursor: pointer; user-select: none;
  padding: 6px 12px; border-radius: 999px; font-size: 12px;
  border: 1px solid var(--border); background: var(--bg2); color: var(--muted);
  transition: background .12s ease, color .12s ease, border-color .12s ease;
  min-height: 32px;
}
.chip input { position: absolute; opacity: 0; width: 0; height: 0; }
.chip:active { transform: scale(.97); }
.chip.on { background: var(--acc-s); border-color: var(--accent); color: var(--accent); font-weight: 600; }
.chip-note { font-size: 12px; color: var(--muted); align-self: center; }

/* Правка времени прямо в таблице прихода */
.cell-edit {
  font: inherit; color: inherit; cursor: pointer;
  background: transparent; border: 1px dashed var(--border);
  border-radius: 8px; padding: 4px 10px; min-height: 32px;
}
.cell-edit:hover { border-color: var(--accent); color: var(--accent); }
.cell-edit:active { transform: scale(.97); }
.cell-edit.manual { border-style: solid; border-color: var(--accent); color: var(--accent); }

/* Текст сообщения бота как он придёт в Telegram */
pre.tg {
  white-space: pre-wrap; word-break: break-word;
  font-family: var(--font); font-size: 13px; line-height: 1.5;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius-s); padding: 12px 14px; margin: 0;
}

/* Предложение установить приложение — снизу, не поверх работы */
.a2hs {
  position: fixed; left: 12px; right: 12px;
  bottom: calc(96px + env(safe-area-inset-bottom)); z-index: 55;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--bg2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 14px 16px;
  box-shadow: 0 10px 30px var(--shadow);
  backdrop-filter: blur(14px);
}
.a2hs[hidden] { display: none; }
.a2hs .t { flex: 1; min-width: 180px; }
.a2hs .t b { display: block; font-weight: 600; font-size: 14px; }
.a2hs .t small { color: var(--muted); font-size: 12px; }
@media (min-width: 769px) { .a2hs { left: auto; right: 24px; bottom: 24px; max-width: 420px; } }

/* Плотная таблица прихода: смысл раздела — увидеть смену целиком,
   а не любоваться воздухом. Строки ниже, шрифт мельче, лишние колонки
   свёрнуты в подписи. */
.card.compact { padding: 10px 12px; }
.tbl.dense th { padding: 6px 8px; font-size: 11px; }
.tbl.dense td { padding: 6px 8px; font-size: 13px; }
.tbl.dense td b { font-weight: 600; }
.tbl.dense .cell-edit { padding: 2px 8px; min-height: 26px; font-size: 13px; }
.tbl.dense .badge { padding: 2px 8px; font-size: 11px; }
.tbl.dense small { font-size: 11px; }

@media (max-width: 768px) {
  /* На телефоне карточка тоже плотнее: пять строк вместо восьми */
  .tbl.dense.cards tr { padding: 8px 10px; margin-bottom: 6px; border-radius: 10px; }
  .tbl.dense.cards td { padding: 3px 0; font-size: 14px; }
  .tbl.dense.cards td:first-child { font-size: 15px; }
  .tbl.dense.cards td::before { font-size: 11px; }
}

/* ── Компактный режим: больше данных на экран ──────────────
 * Панель — рабочий инструмент, а не витрина. Отступы и кегль урезаны
 * так, чтобы смена целиком помещалась без прокрутки, но текст остался
 * читаемым: ниже 13px на телефоне уже щуришься. */
.content { padding: 16px 18px 100px; }
.card { padding: 12px 14px; margin-bottom: 10px; }
.card h3 { font-size: 14px; margin-bottom: 8px; }
.page-title { font-size: 19px; }
.page-sub { font-size: 12px; margin-bottom: 12px; }
.stats { gap: 8px; margin-bottom: 12px; }
.stat { padding: 10px 12px; }
.stat .num { font-size: 20px; }
.stat .lbl { font-size: 10px; }
.kv { padding: 7px 0; }
.feat { padding: 9px 0; }
.feat .t b { font-size: 13px; }
.feat .t small { font-size: 11px; }
.nav-item { padding: 8px 12px; font-size: 13px; }
.eyebrow { font-size: 10px; }

@media (max-width: 768px) {
  .content { padding: calc(10px + env(safe-area-inset-top)) 12px
             calc(78px + env(safe-area-inset-bottom)); }
  .card { padding: 11px 12px; margin-bottom: 8px; }
  .stat { min-width: calc(33% - 6px); padding: 8px 10px; }
  .stat .num { font-size: 18px; }
  .stat .lbl { font-size: 9px; letter-spacing: .04em; }

  /* Карточка строки таблицы: подпись и значение в одну строку,
     без лишних полей. Пять человек влезают на экран целиком. */
  .tbl.dense.cards tr { padding: 7px 10px; margin-bottom: 5px; }
  .tbl.dense.cards td { padding: 2px 0; font-size: 13px; }
  .tbl.dense.cards td:first-child { font-size: 14px; padding-bottom: 4px; }
  .tbl.dense.cards td::before { font-size: 11px; }
  .tabbar { padding: 4px 4px calc(4px + env(safe-area-inset-bottom)); }
  .tabbar .tab { padding: 6px 2px; font-size: 10px; }
  .tabbar .tab .ic { font-size: 16px; }
}

/* ── Темы Apple ─────────────────────────────────────────────
 * Перенос из Pradex Reports: системные цвета iOS, материалы с размытием,
 * шрифт SF, радиус 18. Акцент — наш пудрово-коричневый вместо охры.
 *
 * Смысл материала: карточка не «белый прямоугольник», а полупрозрачный
 * слой над фоном, поэтому у неё есть светлая верхняя кромка (--s-hi)
 * и размытие. На плотном фоне это незаметно, на цветном — оживает.
 */
[data-theme="apple-light"] {
  --bg:      #F2F2F7;                    /* systemGroupedBackground */
  --bg2:     rgba(255,255,255,.72);      /* приподнятый материал карточки */
  --field:    rgba(255,255,255,.55);
  --bg3:     rgba(255,255,255,.55);
  --txt:     #1C1C1E;                    /* label */
  --txt2:    #3C3C43;                    /* secondaryLabel */
  --muted:   #8A8A8E;                    /* tertiaryLabel */
  --accent:  #AF8578;
  --acc-h:   #9A7266;
  --acc-s:   rgba(175,133,120,.12);
  --gold:    #FFBA24;
  --accent-2:#B29A80;
  --success: #34C759;                    /* systemGreen */
  --danger:  #FF3B30;                    /* systemRed */
  --border:  rgba(60,60,67,.14);         /* separator */
  --shadow:  rgba(0,0,0,.10);
  --font:    -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, 'Segoe UI', Roboto, sans-serif;
  --radius:  18px;
  --radius-s:12px;
  --radius-pill: 40px;
  --blur:    20px;
  --sat:     180%;
  --s-hi:    rgba(255,255,255,.90);
  --divider: rgba(60,60,67,.14);
  --active-bg: var(--accent);
  --active-fg: #fff;
  --active-sh: 0 4px 14px rgba(175,133,120,.26);
  color-scheme: light;
}

[data-theme="apple-dark"] {
  --bg:      #000000;                    /* истинно чёрный, экономит OLED */
  --bg2:     rgba(28,28,30,.72);         /* systemGray6, приподнятый */
  --field:    rgba(255,255,255,.06);
  --bg3:     rgba(44,44,46,.60);
  --txt:     #FFFFFF;
  --txt2:    rgba(235,235,245,.78);
  --muted:   rgba(235,235,245,.45);
  --accent:  #C79A8C;                    /* светлее: на чёрном пудра темнеет */
  --acc-h:   #AF8578;
  --acc-s:   rgba(199,154,140,.18);
  --gold:    #FFC94D;
  --accent-2:#C0A88E;
  --success: #30D158;
  --danger:  #FF453A;
  --border:  rgba(84,84,88,.50);
  --shadow:  rgba(0,0,0,.50);
  --font:    -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, 'Segoe UI', Roboto, sans-serif;
  --radius:  18px;
  --radius-s:12px;
  --radius-pill: 40px;
  --blur:    22px;
  --sat:     170%;
  --s-hi:    rgba(255,255,255,.10);
  --divider: rgba(84,84,88,.42);
  --active-bg: var(--accent);
  --active-fg: #1C1C1E;
  --active-sh: 0 6px 18px rgba(0,0,0,.50);
  color-scheme: dark;
}

/* Материалы: размытие только поверхностям, не тексту */
[data-theme^="apple"] :is(.card, .stat, .nav, .tabbar, .table-wrap, .savebar, .a2hs) {
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  backdrop-filter: blur(var(--blur)) saturate(var(--sat));
}
[data-theme^="apple"] :is(.card, .stat) {
  box-shadow: 0 1px 3px var(--shadow), inset 0 1px 0 var(--s-hi);
  border-color: var(--divider);
}
[data-theme^="apple"] .nav { border-right-color: var(--divider); }
[data-theme^="apple"] :is(.tbl th, .tbl td, .kv, .feat) { border-bottom-color: var(--divider); }

/* Типографика Apple: у крупных заголовков плотнее трекинг и леадинг */
[data-theme^="apple"] :is(h1, h2, .page-title) { letter-spacing: -.021em; line-height: 1.12; }
[data-theme^="apple"] :is(.lbl, .eyebrow, .stat .lbl) { letter-spacing: .01em; }
[data-theme^="apple"] .brand { letter-spacing: .12em; }

/* Отклик на нажатие мгновенный, как в iOS: реагируем на press, не на release */
[data-theme^="apple"] :is(.btn, .nav-item, .tab, .chip, .cell-edit) {
  transition: transform .12s ease-out, background .15s, border-color .15s, box-shadow .15s;
}
[data-theme^="apple"] :is(.btn, .nav-item, .chip, .cell-edit):active { transform: scale(.97); }

/* Пользователь просил меньше прозрачности — делаем материалы плотными */
@media (prefers-reduced-transparency: reduce) {
  [data-theme="apple-light"] { --bg2: #FFFFFF; --bg3: #F2F2F7; --blur: 0px; }
  [data-theme="apple-dark"]  { --bg2: #1C1C1E; --bg3: #2C2C2E; --blur: 0px; }
}
@media (prefers-reduced-motion: reduce) {
  [data-theme^="apple"] :is(.btn, .nav-item, .chip, .cell-edit):active { transform: none; }
}

/* Меню под именем в шапке */
.usermenu { position: relative; }
.usermenu-pop {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 80;
  min-width: 210px; padding: 6px;
  background: var(--bg2); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: 0 12px 34px var(--shadow);
  backdrop-filter: blur(16px);
}
.usermenu-pop[hidden] { display: none; }
.upop-item {
  padding: 10px 12px; border-radius: var(--radius-s);
  font-size: 14px; cursor: pointer; user-select: none;
}
.upop-item:hover { background: var(--bg3); }
.upop-item:active { transform: scale(.99); }
.upop-item.danger { color: var(--danger); }
.upop-sep { height: 1px; background: var(--border); margin: 6px 4px; }

/* ── Таблица прихода: как в старой панели ───────────────────
 * Десять колонок не помещаются на телефон, поэтому таблица прокручивается
 * вбок, а колонка с именем закреплена: без неё на четвёртой колонке уже
 * непонятно, чья это строка.
 */
.wt-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table.wt { min-width: 720px; }
table.wt .stick {
  position: sticky; left: 0; z-index: 2;
  background: var(--bg2);
  box-shadow: 1px 0 0 var(--border);
}
table.wt thead .stick { z-index: 3; }
table.wt tr:hover .stick { background: var(--bg3); }
.th-sub { font-weight: 400; text-transform: none; font-size: 10px; color: var(--muted); }
table.wt td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.dev-plus { color: var(--danger); }

/* Поля правки прямо в таблице */
.wt-edit {
  width: 66px; padding: 4px 8px; text-align: center;
  font: inherit; font-size: 13px; font-variant-numeric: tabular-nums;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--bg); color: var(--txt);
}
.wt-edit:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--acc-s); }
.wt-edit.manual { border-color: var(--accent); }
.wt-edit.dirty { border-color: var(--gold); background: rgba(255,186,36,.10); }
.wt-man { font-size: 10px; color: var(--accent); text-align: center; margin-top: 2px; }
.savebar.wt-savebar { max-width: min(560px, calc(100vw - 24px)); }
.savebar.wt-savebar .input { flex: 1; min-width: 120px; padding: 7px 12px; font-size: 13px; }

/* ── Больше стекла ──────────────────────────────────────────
 * Поверхности полупрозрачны во всех темах, а не только в «стеклянных»:
 * так интерфейс перестаёт выглядеть набором белых прямоугольников
 * и получает глубину, как в iOS и Telegram.
 *
 * Размытие вешаем только на крупные поверхности. На мелких элементах
 * оно стоит дорого и не читается.
 */
:root { --glass: rgba(255,255,255,.72); --glass-2: rgba(255,255,255,.55); }
[data-theme="dark"] { --glass: rgba(38,35,32,.72); --glass-2: rgba(48,44,40,.6); }

/* :root здесь нельзя: он совпадает с <html> при ЛЮБОЙ теме, и белое
   стекло затекало в тёмные и стеклянные темы — светлый текст ложился
   на белую карточку. Поэтому «тема по умолчанию» описана явно:
   html без атрибута. */
:is(html:not([data-theme]), [data-theme="light"], [data-theme="dark"]) :is(.card, .stat, .nav, .savebar, .a2hs, .usermenu-pop) {
  background: var(--glass);
  -webkit-backdrop-filter: blur(18px) saturate(170%);
  backdrop-filter: blur(18px) saturate(170%);
}

/* Нижнее меню — стеклянная панель, как в iOS: контент под ней
   просвечивает, сверху тонкая линия-разделитель вместо жирной рамки. */
.tabbar {
  background: color-mix(in srgb, var(--bg2) 72%, transparent);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  border-top: .5px solid var(--divider, var(--border));
  box-shadow: 0 -1px 0 rgba(255,255,255,.35) inset;
}
[data-theme$="dark"] .tabbar { box-shadow: 0 -1px 0 rgba(255,255,255,.06) inset; }

/* Активная вкладка: подложка вместо одного лишь цвета текста —
   палец закрывает подпись, и цвет не виден. */
.tabbar .tab.active {
  background: var(--acc-s);
  border-radius: 12px;
}

/* Закреплённая колонка — единственная поверхность, которой стекло
   противопоказано.
 *
 * Под остальными панелями контент просто лежит, и размытие ему к лицу.
 * Под этой он ЕДЕТ: таблицу прихода листают вбок, и уезжающие столбцы
 * проходят ровно под именем сотрудника. Восьмидесяти восьми процентов
 * непрозрачности не хватает — цифры читаются насквозь, и на телефоне
 * имя выглядит как каша из двух слоёв. Размытие тут не помогает вовсе:
 * оно смазывает фон, но текст под ним остаётся текстом.
 *
 * Поэтому фон плотный. Ровно тот же, что и в запасном варианте ниже,
 * для устройств без backdrop-filter, — то есть внешний вид у всех
 * одинаковый, и проверять его достаточно в одном месте. */
table.wt .stick {
  background: var(--bg2);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* Убираем серый след от касания: он остаётся после тапа и выглядит
   как выделенная строка, хотя ничего не выделено. */
* { -webkit-tap-highlight-color: transparent; }
:is(.card, .feat, .tbl tr, .nav-item, .tab, .upop-item) { -webkit-touch-callout: none; }

/* Устройства без color-mix и backdrop-filter получают плотный фон.
   Закреплённая колонка сюда больше не входит: она плотная всегда. */
@supports not (backdrop-filter: blur(1px)) {
  .tabbar { background: var(--bg2); }
}

/* ── Панель даты: стрелки не должны наезжать на поле ────────
 * Сетка вместо flex-обёрток: у стрелок фиксированная ширина, поле даты
 * забирает остаток. Раньше поле было внутри .field с flex:1 и на iOS
 * распухало, наезжая на соседей.
 */
.datebar { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.daynav {
  flex: 0 0 36px; width: 36px; height: 36px; padding: 0;
  display: grid; place-items: center;
  font-size: 20px; line-height: 1; color: var(--txt2);
  background: var(--bg3); border: 1px solid var(--border);
  border-radius: 50%; cursor: pointer;
}
.daynav:hover:not(:disabled) { color: var(--accent); border-color: var(--accent); }
.daynav:active:not(:disabled) { transform: scale(.94); }
.daynav:disabled { opacity: .35; cursor: not-allowed; }

.daybox { flex: 1 1 150px; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.daybox input[type="date"] {
  width: 100%; border: 0; background: transparent; padding: 0;
  font: 600 15px/1.2 var(--font); color: var(--txt);
  font-variant-numeric: tabular-nums;
}
.daybox input[type="date"]::-webkit-calendar-picker-indicator { opacity: .4; }
.daylabel { font-size: 11px; color: var(--muted); }

/* Свёрнутая подсказка вместо абзаца на треть экрана */
details.hint { margin-top: 8px; font-size: 12px; color: var(--muted); line-height: 1.5; }
details.hint summary { cursor: pointer; color: var(--accent); }
details.hint[open] summary { margin-bottom: 6px; }

/* ── Таблица прихода плотнее ────────────────────────────────
 * Было видно четыре колонки из десяти. Мельче шрифт, у́же поля,
 * имя в одну строку — теперь помещается вся смена.
 */
table.wt { min-width: 660px; font-size: 12px; }
table.wt th { padding: 5px 7px; font-size: 10px; letter-spacing: .03em; }
table.wt td { padding: 3px 7px; font-size: 12px; line-height: 1.3; height: 30px; }
table.wt td.stick { max-width: 132px; }
table.wt td.stick b { font-size: 13px; display: block;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
table.wt .wt-edit { width: 54px; padding: 2px 6px; font-size: 12px; line-height: 1.2; }
table.wt .badge { padding: 1px 7px; font-size: 10px; }
table.wt .th-sub { font-size: 9px; }
table.wt .wt-man { font-size: 9px; }

@media (max-width: 768px) {
  table.wt { min-width: 600px; }
  table.wt td.stick { max-width: 104px; }
}

/* ── Дерево выбора: категория → элементы ────────────────────
 * Плоский список из сотен строк листать невозможно, а решения
 * принимают категориями: «весь диодный лазер», «вся косметология».
 */
.tree { max-height: 420px; overflow: auto; border: 1px solid var(--border);
        border-radius: var(--radius-s); padding: 4px; }
.tree-grp { border-bottom: 1px solid var(--border); }
.tree-grp:last-child { border-bottom: 0; }
.tree-grp > summary {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 8px; cursor: pointer; list-style: none;
  font-size: 13px; font-weight: 600;
}
.tree-grp > summary::-webkit-details-marker { display: none; }
.tree-grp > summary::before { content: '▸'; font-size: 10px; color: var(--muted);
  transition: transform .15s ease; }
.tree-grp[open] > summary::before { transform: rotate(90deg); }
.tree-grp > summary:hover { background: var(--bg3); border-radius: 8px; }
.tree-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tree-count { font-size: 11px; color: var(--muted); white-space: nowrap; }
.tree-count.on { color: var(--accent); font-weight: 600; }
.tree-all { flex: 0 0 auto; font-size: 11px; padding: 4px 10px; min-height: 28px; }

.tree-item {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 8px 7px 26px; font-size: 13px; cursor: pointer;
  border-radius: 8px;
}
.tree-item:hover { background: var(--bg3); }
.tree-item input { width: 17px; height: 17px; accent-color: var(--accent); flex: 0 0 auto; }
.tree-item span { flex: 1; min-width: 0; }

/* Состояние агентов Wi-Fi: зелёная точка — снимки идут, красная — молчит */
.agents { display: grid; gap: 6px; margin-bottom: 14px; font-size: 13px; }
/* inline-block обязателен: в строке агента точка лежит во flex-контейнере
   и размеры получает сама, а в ячейке таблицы она обычный inline-span,
   которому ширина и высота не действуют — и точка пропадает */
.dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%;
       flex: 0 0 auto; background: var(--muted); }
.dot.ok  { background: #34c759; box-shadow: 0 0 0 3px rgba(52,199,89,.18); }
.dot.bad { background: #ff3b30; box-shadow: 0 0 0 3px rgba(255,59,48,.18); }

/* Персональное наблюдение: строка есть, но это не контроль дисциплины */
.tag-watch { opacity: .55; font-size: 11px; }

/* Инвентаризация.
   Расхождение — единственное, ради чего открывают таблицу, поэтому
   излишек и недостача различаются цветом, а не только знаком: глазами
   по столбцу «+3 / −2» скользишь, по красному и зелёному — нет. */
.inv-plus  { color: var(--success); font-weight: 600; }
.inv-minus { color: var(--danger);  font-weight: 600; }
.inv-unknown > td { background: rgba(231,76,60,.06); }
.inv-fact  { text-align: right; }

/* Панель сканирования липнет к верху: пересчёт — это длинный список,
   по которому крутят, и поле ввода не должно уезжать вместе с ним. */
.inv-scan {
  position: sticky; top: 0; z-index: 6; margin-top: 14px;
  padding-top: 12px; padding-bottom: 12px;
}
/* 17px — не про красоту: Safari на iPhone приближает страницу, когда
   фокус попадает в поле мельче 16px, и вернуть масштаб человек уже
   не может. Это касается всех полей, в которые тыкают на телефоне. */
.inv-scan .input, .inv-fact { font-size: 17px; }
.inv-code { flex: 1; min-width: 150px; }
.inv-scan .chip { padding: 8px 14px; }

.inv-video { position: relative; max-width: 420px; }
.inv-video video {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: 12px; background: #000; display: block;
}
/* Прицел: без него непонятно, куда подносить штрихкод, и его держат
   у края кадра, где он не читается. */
.inv-video i {
  position: absolute; inset: 22% 8%; border: 2px solid rgba(255,255,255,.85);
  border-radius: 10px; box-shadow: 0 0 0 100vmax rgba(0,0,0,.25);
  pointer-events: none;
}

/* Последний скан. Крупно и одним блоком: человек смотрит на полку,
   на экран — вполглаза, и должен считывать результат мельком. */
.inv-last {
  padding: 12px 14px; border-radius: 12px; line-height: 1.45;
  background: rgba(107,142,78,.12); border: 1px solid rgba(107,142,78,.35);
}
.inv-last.bad { background: rgba(231,76,60,.10); border-color: rgba(231,76,60,.4); }
.inv-last b { font-size: 15px; }

/* Телефон: строки-карточки и без того узкие, поэтому поле «Факт»
   разворачиваем во всю ширину карточки — попасть в него пальцем
   с первого раза важнее, чем сэкономить место. */
@media (max-width: 720px) {
  .inv-fact { width: 100% !important; min-height: 40px; }
  .inv-scan { top: -1px; }
  .inv-last b { font-size: 16px; }
}

/* ── Инвентаризация: лента сканов ────────────────────────────
   Отвечает на вопрос «я это уже сканировал?» на месте, у полки,
   не открывая журнал: номер по порядку, время, что и сколько. */
.inv-feed { margin-top: 10px; display: grid; gap: 2px; }
.inv-feed-row {
  display: grid; grid-template-columns: 28px 62px 1fr auto;
  gap: 8px; align-items: baseline;
  padding: 4px 8px; border-radius: 8px; background: var(--bg3);
  font-size: 12px; color: var(--txt2);
}
.inv-feed-row b { color: var(--muted); font-weight: 600; }
.inv-feed-row .t { color: var(--muted); font-variant-numeric: tabular-nums; }
.inv-feed-row .n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inv-feed-row .q { font-weight: 600; color: var(--accent); }
.inv-feed-row.bad { background: rgba(231,76,60,.10); }

/* ── Инвентаризация: компактная карточка позиции ─────────────
   Обычная карточка раскладывает каждый столбец в свою строку — семь
   строк на позицию, три позиции на экран. Здесь всё в две строки:
   сверху название и расхождение, снизу коды, остаток и поле факта.
   На экране телефона помещается восемь позиций вместо трёх. */
@media (max-width: 768px) {
  .tbl.cards.inv-table tr {
    display: grid;
    grid-template-columns: 1fr auto auto auto;
    grid-template-areas:
      "name name diff btns"
      "art  bc   stock fact";
    gap: 2px 8px; padding: 7px 10px; margin-bottom: 6px; align-items: center;
  }
  .tbl.cards.inv-table td { padding: 0; display: block; font-size: 12px; }
  .tbl.cards.inv-table td::before { content: none; }
  .tbl.cards.inv-table td:nth-child(1) { grid-area: art;  color: var(--muted); }
  .tbl.cards.inv-table td:nth-child(2) { grid-area: bc;   color: var(--muted); }
  .tbl.cards.inv-table td:nth-child(3) { grid-area: name; font-size: 14px; font-weight: 600;
                                         overflow: hidden; }
  .tbl.cards.inv-table td:nth-child(4) { grid-area: stock; }
  .tbl.cards.inv-table td:nth-child(5) { grid-area: fact; }
  .tbl.cards.inv-table td:nth-child(6) { grid-area: diff; font-size: 13px; text-align: right; }
  .tbl.cards.inv-table td:nth-child(7) { grid-area: btns; }
  /* Категория и склад на телефоне не нужны: они одинаковые у всей
     выборки, а место занимают у каждой позиции. */
  .tbl.cards.inv-table .where { display: none; }
  .tbl.cards.inv-table .inv-fact { width: 74px !important; min-height: 34px; padding: 4px 6px; }
  .tbl.cards.inv-table td:nth-child(4)::before { content: "ост. "; color: var(--muted); }
}

/* Крестик отмены в ленте сканов. Цель 32×32 — палец попадает, но
   случайно не заденет: отмена стоит рядом с быстрым сканированием. */
.inv-feed-row { grid-template-columns: 26px 60px 1fr auto 32px; }
.inv-undo {
  width: 32px; height: 28px; line-height: 1; padding: 0;
  border: 0; border-radius: 8px; cursor: pointer;
  background: transparent; color: var(--muted); font-size: 14px;
  -webkit-tap-highlight-color: transparent;
}
.inv-undo:active { background: var(--danger); color: #fff; }

/* Мини-редактор SMM: подписанная галочка (Ж/К) и образец цвета.
   Отдельные классы, потому что .sw — это переключатель на всю строку,
   а здесь чекбоксов по несколько в ряд. */
.chk { display: inline-flex; align-items: center; gap: 5px; font-size: 13px;
       color: var(--muted); cursor: pointer; white-space: nowrap; }
.chk input { accent-color: var(--accent); }
input[type=color] { width: 40px; height: 32px; padding: 2px; border: 1px solid var(--border);
                    border-radius: var(--radius-s); background: var(--bg2); cursor: pointer; }

/* ── Сверка препаратов ───────────────────────────────────────
   Раскладка перенесена из панели на Apps Script один в один: те же
   блоки, те же цветовые роли (разрыв — красным, ноль — приглушённо,
   «из техкарты» и «мой расходник» — разными плашками). Цвета берутся
   из переменных темы, поэтому раздел живёт и в тёмной, и в стеклянной. */
.cns-row { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; }
.cns-fld { display: flex; flex-direction: column; gap: 4px; }
.cns-fld > span { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.cns-hint { font-size: 12px; color: var(--muted); margin: 8px 0 0; }

/* Выбор услуги и расходника: список с поиском и счётчиком выбранного */
.cns-pick { border: 1px solid var(--border); border-radius: 12px; background: var(--field); margin-bottom: 10px; }
.cns-pick .hd { display: flex; gap: 8px; align-items: center; padding: 8px 10px;
                border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.cns-pick .hd input { flex: 1 1 180px; padding: 7px 10px; border: 1px solid var(--border);
                      border-radius: 8px; font-size: 13px; background: var(--bg2);
                      color: var(--txt); outline: none; font-family: inherit; }
.cns-pick .hd .cnt { font-size: 12px; color: var(--muted); white-space: nowrap; }
.cns-pick .bd { max-height: 230px; overflow: auto; padding: 4px 0; }
.cns-pick label { display: flex; gap: 8px; align-items: flex-start; padding: 5px 12px;
                  font-size: 13px; cursor: pointer; }
@media (hover: hover) { .cns-pick label:hover { background: var(--bg3); } }
.cns-pick .tag { font-size: 10px; padding: 1px 6px; border-radius: 6px;
                 background: rgba(255,186,36,.18); color: #A8781A; margin-left: 4px; white-space: nowrap; }
.cns-lnk { border: none; background: none; font: inherit; font-size: 12px;
           color: var(--accent); cursor: pointer; padding: 0 2px; }

/* Итоги прогона */
.cns-kpi { display: flex; gap: 10px; flex-wrap: wrap; }
.cns-kpi .k { flex: 1 1 120px; background: var(--field); border: 1px solid var(--border);
              border-radius: 12px; padding: 12px 14px; }
.cns-kpi .k b { display: block; font-size: 22px; font-weight: 700; line-height: 1.2;
                font-variant-numeric: tabular-nums; }
.cns-kpi .k span { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.cns-kpi .k.bad b  { color: var(--danger); }
.cns-kpi .k.good b { color: var(--success); }
.cns-kpi .k.warn b { color: #A8781A; }

table.cns-t { width: 100%; border-collapse: collapse; font-size: 13px; }
table.cns-t th { text-align: right; padding: 8px 10px; background: var(--bg3); font-size: 11px;
                 text-transform: uppercase; letter-spacing: .04em; color: var(--muted); white-space: nowrap; }
table.cns-t th:first-child { text-align: left; }
table.cns-t td { padding: 7px 10px; border-bottom: 1px solid var(--border); text-align: right;
                 font-variant-numeric: tabular-nums; white-space: nowrap; }
table.cns-t td:first-child { text-align: left; white-space: normal; }
table.cns-t tr.hasgap td { background: rgba(209,73,91,.06); }
table.cns-t tr.clickable { cursor: pointer; }
@media (hover: hover) { table.cns-t tr.clickable:hover > td { background: var(--bg3); } }
table.cns-t tr.det td { background: var(--bg3); padding: 0; text-align: left; }
.cns-det-in { padding: 8px 14px 12px; }
.cns-det-in .l { padding: 7px 0; border-bottom: 1px solid var(--border); }
.cns-det-in .l:last-child { border-bottom: none; }
.cns-det-in .l.done { opacity: .55; }
.cns-det-in .hd { font-size: 12px; color: var(--muted); }
.cns-det-in .hd b { color: var(--txt); font-weight: 600; }
.cns-det-in .w { font-size: 12px; color: var(--txt); margin-top: 3px; padding-left: 2px; }
.cns-det-in .w i { display: inline-block; font-style: normal; font-size: 10px; font-weight: 600;
                   text-transform: uppercase; letter-spacing: .03em; padding: 1px 7px;
                   border-radius: 6px; margin-right: 6px; vertical-align: 1px; }
.cns-det-in .w i.no { background: rgba(209,73,91,.14); color: var(--danger); }
.cns-det-in .w i.ok { background: rgba(47,169,107,.14); color: var(--success); }
/* Комментарий из записи: чаще всего в нём и лежит объяснение разрыва */
.cns-note { font-size: 12px; color: var(--txt2); margin-top: 3px; font-style: italic; }
.cns-gap  { color: var(--danger); font-weight: 600; }
.cns-zero { color: var(--muted); }
.cns-sub  { font-size: 11px; color: var(--muted); display: block; }
.cns-warn { background: rgba(255,186,36,.14); border: 1px solid rgba(255,186,36,.45);
            color: #A8781A; border-radius: 10px; padding: 10px 12px; font-size: 13px; margin-bottom: 10px; }
.cns-ign  { display: inline-block; font-size: 11px; padding: 3px 9px; border-radius: 20px;
            background: var(--bg3); color: var(--muted); margin: 0 6px 6px 0; }

/* Отметка «проверено»: строка приглушается, но не исчезает */
.cns-ver { display: inline-flex; align-items: center; gap: 6px; font-size: 12px;
           color: var(--muted); cursor: pointer; margin-top: 4px; }
.cns-ver input { accent-color: var(--success); }
.cns-ver .who { color: var(--success); }

/* Фильтры карты */
.cns-f { padding: 8px 13px; border: 1px solid var(--border); background: var(--field);
         color: var(--muted); border-radius: 10px; font-size: 13px; font-weight: 600;
         cursor: pointer; font-family: inherit; }
.cns-f.on { background: var(--accent); border-color: var(--accent); color: #fff; }

/* Карта услуг */
.cns-map { border: 1px solid var(--border); border-radius: 12px; max-height: 460px;
           overflow: auto; background: var(--field); }
.cns-mr { display: grid; grid-template-columns: 1fr 1fr auto; gap: 10px; align-items: start;
          padding: 9px 12px; border-bottom: 1px solid var(--border); }
.cns-mr:last-child { border-bottom: none; }
.cns-mr.off { opacity: .5; }
.cns-mr.dirty { background: rgba(255,186,36,.10); }
.cns-mr .nm { font-size: 13px; line-height: 1.35; }
.cns-mr .nm span { display: block; font-size: 11px; color: var(--muted); margin-top: 2px; }
.cns-g { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; padding: 2px 8px;
         border-radius: 20px; margin: 2px 4px 2px 0; }
.cns-g.card { background: rgba(175,133,120,.16); color: var(--accent); }
.cns-g.my   { background: rgba(47,169,107,.14);  color: var(--success); }
.cns-g.none { background: rgba(209,73,91,.12);   color: var(--danger); }
.cns-g.stub { background: rgba(255,186,36,.18);  color: #A8781A; }
.cns-g b { cursor: pointer; font-weight: 700; opacity: .55; }
.cns-add { border: 1px dashed var(--border); background: none; color: var(--muted);
           border-radius: 20px; font-size: 11px; padding: 2px 9px; cursor: pointer; font-family: inherit; }
.cns-use { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted);
           cursor: pointer; white-space: nowrap; padding-top: 2px; }

@media (max-width: 680px) {
  table.cns-t { font-size: 12px; }
  table.cns-t th, table.cns-t td { padding: 6px 5px; }
  .cns-kpi .k b { font-size: 19px; }
  .cns-mr { grid-template-columns: 1fr; gap: 5px; }
}
/* Поштучный препарат услуги: найден по факту списаний, сверяется
   по количеству единиц и не подчиняется заглушке «ввести вручную». */
.cns-g.unit { background: rgba(255,186,36,.14); color: #A8781A; }

/* Подсказка «На экран „Домой“» для iPhone.
   Системного события установки iOS не даёт, поэтому объясняем руками —
   но в родном для телефона виде: затемнение, шторка снизу, крупные
   строки-шаги и настоящая иконка «Поделиться». Диалог alert() тут
   выглядел чужим и обрывал объяснение на одной строке. */
.ios-sheet-back {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(0, 0, 0, .4);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  opacity: 0; transition: opacity .25s ease;
}
.ios-sheet-back.on { opacity: 1; }
.ios-sheet {
  position: fixed; left: 8px; right: 8px; z-index: 91;
  bottom: calc(8px + env(safe-area-inset-bottom));
  /* Шторка непрозрачная намеренно: стеклянный --bg2 сквозь затемнение
     читается как грязное пятно, а не как лист бумаги поверх экрана. */
  background: #FFF; color: #111;
  border-radius: 22px; padding: 22px 20px 16px;
  max-height: calc(100svh - 24px); overflow-y: auto;
  box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
  transform: translateY(120%); transition: transform .34s cubic-bezier(.32, .72, 0, 1);
  font-family: -apple-system, BlinkMacSystemFont, var(--font, system-ui), sans-serif;
}
.ios-sheet.on { transform: translateY(0); }
@media (min-width: 560px) { .ios-sheet { left: 50%; right: auto; width: 420px; margin-left: -210px; } }
.ios-sheet .grab {
  width: 36px; height: 5px; border-radius: 3px; background: #d8d8dc;
  margin: -10px auto 16px;
}
.ios-sheet .head {
  display: flex; align-items: center; gap: 12px; margin-bottom: 18px;
}
.ios-sheet .head img {
  width: 54px; height: 54px; border-radius: 12px; display: block; flex: none;
}
.ios-sheet .head b { display: block; font-size: 17px; letter-spacing: -.02em; }
.ios-sheet .head small { color: #8a8a8e; font-size: 13px; }
.ios-sheet ol { list-style: none; margin: 0; padding: 0; }
.ios-sheet li {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 0; font-size: 16px; letter-spacing: -.01em;
  border-top: 1px solid rgba(0, 0, 0, .08);
}
.ios-sheet li .n {
  flex: none; width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center; font-size: 13px; font-weight: 600;
  background: rgba(0, 0, 0, .07); color: #8a8a8e;
}
.ios-sheet li svg { flex: none; color: #007AFF; }
.ios-sheet .ok {
  width: 100%; margin-top: 16px; border: 0; cursor: pointer;
  background: #007AFF; color: #fff; font-size: 17px; font-weight: 600;
  padding: 14px; border-radius: 14px; font-family: inherit;
  transition: transform .12s ease-out, filter .15s;
}
.ios-sheet .ok:active { transform: scale(.97); filter: brightness(.92); }

/* Тёмная шторка — и по системной теме, и по выбранной в панели: тему
   здесь выбирают вручную, и белый лист поверх тёмного экрана слепит. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .ios-sheet { background: #1C1C1E; color: #F5F5F7; }
  :root:not([data-theme]) .ios-sheet .grab { background: #48484A; }
  :root:not([data-theme]) .ios-sheet li { border-top-color: rgba(255, 255, 255, .12); }
  :root:not([data-theme]) .ios-sheet li .n { background: rgba(255, 255, 255, .12); color: #98989E; }
}
[data-theme$="dark"] .ios-sheet { background: #1C1C1E; color: #F5F5F7; }
[data-theme$="dark"] .ios-sheet .grab { background: #48484A; }
[data-theme$="dark"] .ios-sheet li { border-top-color: rgba(255, 255, 255, .12); }
[data-theme$="dark"] .ios-sheet li .n { background: rgba(255, 255, 255, .12); color: #98989E; }

/* ── Экран ПИН-кода ─────────────────────────────────────────────────────────
   Пропорции взяты у код-пароля iPhone: кружки 72 px с шагом 24, цифра
   крупная, буквы под ней мелкие и разрежённые. Человек попадает по такой
   кнопке не глядя — этим она и отличается от поля ввода. */
/* Тряска при неверном ПИНе уводит точки на 10 px вбок — без обрезки
   от неё по всей странице появляется горизонтальная прокрутка. */
.pinpad { display: flex; flex-direction: column; align-items: center;
          max-width: 100%; overflow-x: hidden; }

.pin-dots { display: flex; gap: 20px; margin: 4px 0 2px; }
.pin-dot {
  width: 13px; height: 13px; border-radius: 50%;
  border: 1.5px solid var(--txt); opacity: .55;
  transition: background .12s ease-out, opacity .12s, transform .12s ease-out;
}
.pin-dot.on { background: var(--txt); opacity: 1; transform: scale(1.06); }
.pin-dots.shake { animation: pin-shake .42s cubic-bezier(.36, .07, .19, .97); }
@keyframes pin-shake {
  10%, 90% { transform: translateX(-5px); }
  20%, 80% { transform: translateX(8px); }
  30%, 50%, 70% { transform: translateX(-10px); }
  40%, 60% { transform: translateX(10px); }
}

.pin-hint { min-height: 20px; margin: 12px 0 6px; font-size: 13px; color: var(--muted); text-align: center; }
.pin-hint.bad { color: var(--danger); }

.pin-keys {
  display: grid; grid-template-columns: repeat(3, 72px);
  gap: 20px 24px; justify-content: center; margin-top: 8px;
}
.pin-key {
  width: 72px; height: 72px; border-radius: 50%; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  border: 0; padding: 0; color: var(--txt);
  background: color-mix(in srgb, var(--txt) 7%, transparent);
  font-family: inherit; -webkit-tap-highlight-color: transparent;
  transition: background .12s ease-out, transform .1s ease-out;
}
.pin-key:active { background: color-mix(in srgb, var(--txt) 18%, transparent); transform: scale(.94); }
.pin-key b { font-size: 30px; font-weight: 400; line-height: 1; letter-spacing: -.02em; }
.pin-key small { font-size: 10px; font-weight: 600; letter-spacing: .12em; margin-top: 3px; color: var(--muted); }
.pin-key small:empty { margin: 0; }
/* Face ID и стирание — без подложки: в iPhone это тоже не «клавиши». */
.pin-key-flat { background: none; }
.pin-key-flat:active { background: color-mix(in srgb, var(--txt) 10%, transparent); }
.pin-key-flat[hidden] { display: flex; visibility: hidden; }

/* Кто входит: кружок с инициалами и имя — как на экране блокировки. */
.pin-who { display: flex; flex-direction: column; align-items: center; margin-bottom: 18px; }
.pin-avatar {
  width: 64px; height: 64px; border-radius: 50%; display: grid; place-items: center;
  background: var(--accent); color: #fff; font-size: 24px; font-weight: 600;
  letter-spacing: .02em; margin-bottom: 12px;
}
.pin-name { font-size: 17px; font-weight: 600; letter-spacing: -.01em; }
.pin-sub { font-size: 13px; color: var(--muted); margin-top: 4px; }

@media (max-height: 700px) {
  .pin-keys { grid-template-columns: repeat(3, 64px); gap: 14px 20px; }
  .pin-key { width: 64px; height: 64px; }
  .pin-key b { font-size: 27px; }
  .pin-avatar { width: 54px; height: 54px; font-size: 21px; margin-bottom: 8px; }
}

/* Подписи колонок в списке мастеров (раздел SMM). На узком экране поля
   встают друг под друга, и шапка перестаёт им соответствовать —
   прячем её, у полей есть свои подсказки-плейсхолдеры. */
.mrhead .lbl { font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
               color: var(--muted); }
@media (max-width: 900px) { .mrhead { display: none !important; } }

/* Раздел «Функции»: кнопка «?» и раскрывающееся описание.
   Описание закрыто по умолчанию — список из трёх десятков функций
   с абзацем у каждой невозможно просмотреть глазами. */
.btn-info { display: inline-flex; align-items: center; justify-content: center;
            width: 18px; height: 18px; margin-left: 6px; padding: 0;
            border: 1px solid var(--border); border-radius: 50%; background: transparent;
            color: var(--muted); font-size: 11px; line-height: 1; cursor: pointer;
            vertical-align: middle; }
.btn-info:hover { color: var(--accent); border-color: var(--accent); }
.featbox .about { margin: 8px 0 2px; padding: 10px 12px; border-radius: var(--radius-s);
                  background: var(--bg3); color: var(--txt2); font-size: 13px; line-height: 1.5; }
.featbox .about code { font-size: 12px; }

/* Предпросмотр кадра SMM: пока сервер рисует, поверх прошлой картинки
   крутится кружок. Вуаль полупрозрачная — видно, что именно меняется. */
.shot { position: relative; min-height: 120px; }
.shot .shot-veil { position: absolute; inset: 0; display: none;
                   align-items: center; justify-content: center;
                   background: color-mix(in srgb, var(--bg2) 62%, transparent);
                   border-radius: 12px; }
.shot.loading .shot-veil,
.shot:not(.ready) .shot-veil { display: flex; }
.spinner { width: 30px; height: 30px; border-radius: 50%;
           border: 3px solid var(--border); border-top-color: var(--accent);
           animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: none; border-top-color: var(--accent); opacity: .6; }
}

/* Плотный режим для колонок с настройками: там десятки полей, и
   стандартный воздух между ними прячет половину за нижний край экрана.
   Подписи и рамки остаются — сжимаются только отступы и высота полей. */
.tight .field { margin-bottom: 8px; }
.tight .field > .lbl { font-size: 11px; margin-bottom: 3px; }
.tight .input, .tight select.input, .tight textarea.input { padding: 6px 9px; font-size: 13px; }
.tight input[type=color] { width: 34px; height: 28px; }
.tight .chk { font-size: 12px; gap: 4px; }
.tight h3 { font-size: 15px; }
.tight .page-sub { font-size: 12px; line-height: 1.45; }
.tight .feat { padding: 7px 0; gap: 8px; }
.tight .feat .t small { font-size: 11.5px; }
.tight .stats { margin-bottom: 12px; }
/* ═══════════════════════════════════════════════════════════════
   ОБЩЕЕ ОФОРМЛЕНИЕ: разделение строк + стекло
   Раздел общий для всех страниц, ниже всего остального — поэтому
   правит цвета линеек и поверхностей, не трогая раскладку выше.
   ═══════════════════════════════════════════════════════════════ */

/* ── 1. Линейка есть в каждой теме ─────────────────────────
 * Раньше внутренние разделители брали --border. В стеклянных темах
 * --border — это белая световая кромка карточки (rgba(255,255,255,.65)),
 * и на светлом фоне линия между строками просто исчезала: текст сливался
 * в сплошное полотно. Поэтому роли разведены:
 *   --border  — кромка поверхности (внешняя граница карточки),
 *   --divider — линия ВНУТРИ поверхности (между строками),
 *   --row-alt — подложка чётной строки,
 *   --row-hov — строка под курсором.
 * Разделитель везде отсчитывается от цвета текста, а не от белого:
 * только так он виден и на бежевом стекле, и на плотном листе.
 */
:root, [data-theme="light"] {
  --divider: rgba(50,40,35,.14);
  --row-alt: rgba(50,40,35,.028);
  --row-hov: rgba(175,133,120,.10);
}
[data-theme="dark"] {
  --divider: rgba(255,255,255,.13);
  --row-alt: rgba(255,255,255,.030);
  --row-hov: rgba(199,154,140,.12);
}
[data-theme="glass-light"] {
  --divider: rgba(86,62,52,.20);
  --row-alt: rgba(255,255,255,.30);
  --row-hov: rgba(255,255,255,.52);
}
[data-theme="glass-dark"] {
  --divider: rgba(255,255,255,.16);
  --row-alt: rgba(255,255,255,.035);
  --row-hov: rgba(255,255,255,.09);
}
[data-theme="apple-light"] { --row-alt: rgba(60,60,67,.030); --row-hov: rgba(175,133,120,.10); }
[data-theme="apple-dark"]  { --row-alt: rgba(255,255,255,.035); --row-hov: rgba(255,255,255,.08); }

/* Все внутренние линейки — на --divider. Перечислены поимённо, а не
   через * , чтобы не задеть рамки полей и кнопок. */
:is(.tbl th, .tbl td, .kv, .feat, .featbox, .cns-det-in .l, .cns-mr,
    table.cns-t td, .tree-grp, .upop-sep, .nav-sep, hr.sep,
    .cns-pick .hd) {
  border-bottom-color: var(--divider);
}
.upop-sep, .nav-sep { background: var(--divider); }
hr.sep { border-top-color: var(--divider); }

/* ── 2. Строки таблицы: ритм вместо полотна ────────────────
 * Три приёма разом, потому что поодиночке ни один не работает:
 *   • полосатость — глаз держит строку, ведя её слева направо;
 *   • линейка — граница видна даже там, где полоса светлая;
 *   • воздух в клетке — строки перестают слипаться по вертикали.
 * Заголовок отделён от тела жирнее остальных линий: иначе первая
 * строка данных читается как часть шапки.
 */
.tbl td { padding: 9px 10px; line-height: 1.45; border-bottom: 1px solid var(--divider); }
.tbl th { border-bottom: 1px solid var(--divider); }
.tbl thead th { box-shadow: inset 0 -1px 0 var(--divider); }
.tbl tbody tr:nth-child(even) td { background: var(--row-alt); }
.tbl tr:last-child td { border-bottom: 0; }
@media (hover: hover) and (pointer: fine) {
  .tbl tbody tr:hover td,
  [data-theme^="glass"] .tbl tbody tr:hover td { background: var(--row-hov); }
}
/* Подпись под значением — это второй уровень, а не продолжение строки */
.tbl td small { margin-top: 3px; color: var(--muted); line-height: 1.35; }
.tbl.dense td { padding: 7px 8px; }
table.cns-t td { border-bottom: 1px solid var(--divider); }
table.cns-t tbody tr:nth-child(even) > td { background: var(--row-alt); }
table.cns-t tr.hasgap td { background: rgba(209,73,91,.07); }

/* Закреплённая колонка «прихода» полосатость съедала: она матовая и
   лежит поверх строки. Возвращаем полосу и ей, иначе слева таблица
   выглядит расчёсанной, а справа — нет. */
table.wt tbody tr:nth-child(even) td.stick {
  background: color-mix(in srgb, var(--bg2) 88%, var(--row-alt));
}

/* ── 3. Телефон: карточка строки должна читаться построчно ──
 * На узком экране таблица разворачивается в карточки, и внутри каждой
 * шли подпись-значение подряд без единой линии — самое слипшееся место
 * во всей панели. Теперь: имя сверху отбито линией пожирнее, между
 * парами — тонкая линия, подпись приглушена и мельче значения.
 * inv-table исключена: там своя сетка в две строки, линии её разрежут.
 */
@media (max-width: 768px) {
  .tbl.cards tr {
    border: 1px solid var(--border);
    box-shadow: 0 1px 2px var(--shadow), inset 0 1px 0 var(--s-hi, transparent);
    padding: 4px 12px 6px;
  }
  .tbl.cards:not(.inv-table) td { padding: 8px 0; align-items: baseline; }
  .tbl.cards:not(.inv-table) td + td { border-top: 1px solid var(--divider); }
  .tbl.cards:not(.inv-table) td:first-child {
    padding: 9px 0 10px; border-bottom: 2px solid var(--divider);
    letter-spacing: -.01em;
  }
  .tbl.cards:not(.inv-table) td::before {
    flex: 0 0 auto; color: var(--muted); font-size: 11px;
    text-transform: uppercase; letter-spacing: .04em; line-height: 1.6;
  }
  /* Значение прижато вправо и весит больше подписи — взгляд идёт
     по правому краю карточки, не перечитывая подписи. */
  .tbl.cards:not(.inv-table) td { text-align: right; font-weight: 500; }
  .tbl.cards:not(.inv-table) td:first-child { text-align: left; }
  .tbl.dense.cards:not(.inv-table) td { padding: 6px 0; font-size: 13px; }
  .tbl.dense.cards:not(.inv-table) td:first-child { padding: 7px 0 8px; }
  /* Полосатость на телефоне не нужна: карточки и так отдельные */
  .tbl.cards tbody tr:nth-child(even) td { background: none; }

  /* Списки внутри карточек тоже дышат: 9px было слишком тесно для
     двухстрочных пунктов с подписью. */
  .feat, .featbox { padding: 12px 0; }
  .kv { padding: 9px 0; }
}

/* ── 4. Больше стекла, в бежево-коричневом ────────────────
 * Механика прежняя (blur + saturate + световая кромка), но:
 *   • фон глубже — пять тёплых пятен вместо трёх, есть чему просвечивать;
 *   • само стекло тонировано в тёплый белый, а не в нейтральный:
 *     на бежевом фоне серое стекло выглядит грязным;
 *   • у поверхности появилась нижняя кромка-тень — край листа виден
 *     даже там, где фон под ним светлый.
 */
[data-theme="glass-light"] {
  --bg: radial-gradient(120% 80% at 0% 0%,    #E8CFC4 0%, rgba(232,207,196,0) 60%),
        radial-gradient(110% 85% at 100% 2%,  #EADCC6 0%, rgba(234,220,198,0) 56%),
        radial-gradient(95% 75% at 84% 60%,   #DECCC0 0%, rgba(222,204,192,0) 62%),
        radial-gradient(120% 95% at 18% 110%, #E5D9C6 0%, rgba(229,217,198,0) 60%),
        #F0E8DC;
  --bg2:   rgba(255,251,246,.55);
  --bg3:   rgba(255,251,246,.38);
  --field: rgba(255,252,248,.46);
  --border: rgba(255,255,255,.70);
  --shadow: rgba(96,70,58,.16);
  --blur:  26px;
  --sat:   190%;
  --s-hi:  rgba(255,255,255,.85);
  --s-lo:  rgba(96,70,58,.10);
}
[data-theme="glass-dark"] {
  --bg: radial-gradient(120% 80% at 0% 0%,    #33251F 0%, rgba(51,37,31,0) 58%),
        radial-gradient(110% 85% at 100% 4%,  #2A2119 0%, rgba(42,33,25,0) 55%),
        radial-gradient(95% 75% at 78% 68%,   #241C18 0%, rgba(36,28,24,0) 60%),
        #15120F;
  --bg2:   rgba(52,44,38,.62);
  --bg3:   rgba(46,39,34,.54);
  --field: rgba(0,0,0,.22);
  --blur:  24px;
  --sat:   165%;
  --s-hi:  rgba(255,255,255,.13);
  --s-lo:  rgba(0,0,0,.35);
}

/* Матовыми становятся все крупные поверхности, а не только карточка:
   иначе панель — стеклянная карточка на непрозрачном меню, и обман
   заметен ровно на границе. Мелочь (значки, подписи) не размываем:
   blur стоит дорого и на них ничего не даёт. */
[data-theme^="glass"] :is(.card, .stat, .nav, .tabbar, .table-wrap, .savebar,
                          .a2hs, .usermenu-pop, .toast, .burger, .btn-quiet,
                          .btn-ghost, .tree, .cns-pick, .cns-map, .cns-kpi .k,
                          .input, select.input, textarea.input, .chip, pre.tg,
                          .daynav, table.wt .stick) {
  -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--sat));
  backdrop-filter: blur(var(--blur)) saturate(var(--sat));
}
/* Поля и чипы размываем слабее: на маленькой площади сильный blur
   превращается в мутное пятно и текст в поле теряет опору. */
[data-theme^="glass"] :is(.input, select.input, textarea.input, .chip, .daynav,
                          .btn-quiet, .btn-ghost, .burger) {
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  backdrop-filter: blur(10px) saturate(140%);
}

/* Объём: светлая кромка сверху, мягкая тень снизу. Двух линий хватает,
   чтобы лист читался как лист, а не как выцветшее пятно. */
[data-theme^="glass"] :is(.card, .stat, .table-wrap, .cns-kpi .k) {
  box-shadow: 0 8px 26px var(--shadow),
              inset 0 1px 0 var(--s-hi),
              inset 0 -1px 0 var(--s-lo);
}
[data-theme^="glass"] :is(.savebar, .usermenu-pop, .a2hs) {
  box-shadow: 0 14px 40px var(--shadow), inset 0 1px 0 var(--s-hi);
}
[data-theme^="glass"] .nav {
  border-right: 1px solid var(--divider);
  box-shadow: inset -1px 0 0 var(--s-hi);
}
[data-theme^="glass"] .brand { background: transparent; }

/* Шапка таблицы на стекле — своя полупрозрачная плашка, а не плотный
   --bg3: иначе поверх стекла лежит матовый серый прямоугольник. */
[data-theme="glass-light"] .tbl th { background: rgba(255,255,255,.42); }
[data-theme="glass-dark"]  .tbl th { background: rgba(255,255,255,.05); }
[data-theme="glass-light"] table.cns-t th { background: rgba(255,255,255,.42); }
[data-theme="glass-dark"]  table.cns-t th { background: rgba(255,255,255,.05); }

/* Активный пункт меню и вкладка: подложка плотнее фона, чтобы выбор
   читался поверх просвечивающего контента. */
[data-theme^="glass"] .nav-item.active {
  background: rgba(175,133,120,.20); color: var(--accent);
  box-shadow: var(--active-sh), inset 0 1px 0 var(--s-hi);
}
[data-theme="glass-dark"] .nav-item.active { background: rgba(199,154,140,.22); }

/* Кнопка на стекле остаётся плотной. Полупрозрачная кнопка — главная
   ошибка стеклянных тем: пропадает единственный якорь для взгляда. */
[data-theme^="glass"] .btn:not(.btn-quiet):not(.btn-ghost) {
  box-shadow: 0 4px 14px var(--shadow), inset 0 1px 0 rgba(255,255,255,.22);
}

/* Отклик на нажатие — сразу, не по отпусканию. 160ms и scale .97:
   заметно телу, незаметно глазу. */
:is(.btn, .chip, .nav-item, .tab, .cell-edit, .daynav, .burger, .upop-item) {
  transition: transform .16s cubic-bezier(.23,1,.32,1),
              background .15s ease, border-color .15s ease, box-shadow .15s ease;
}

/* Без backdrop-filter (старый Android) стекло становится плотным листом:
   размытия нет, и текст иначе ляжет прямо на градиент. */
@supports not (backdrop-filter: blur(1px)) {
  [data-theme="glass-light"] { --bg2: rgba(255,252,248,.94); --bg3: rgba(255,252,248,.88);
                               --field: rgba(255,255,255,.92); }
  [data-theme="glass-dark"]  { --bg2: rgba(52,44,38,.96);     --bg3: rgba(46,39,34,.94); }
}
/* Просили меньше прозрачности — отдаём плотные поверхности */
@media (prefers-reduced-transparency: reduce) {
  [data-theme="glass-light"] { --bg2: #FFFCF8; --bg3: #F3EEE7; --field: #FFFDFA; --blur: 0px; }
  [data-theme="glass-dark"]  { --bg2: #2B2521; --bg3: #241F1B; --blur: 0px; }
}

/* Карточка строки на телефоне — тоже стекло: она лежит поверх фона
   страницы, а не внутри карточки, и без размытия выглядит наклейкой. */
@media (max-width: 768px) {
  [data-theme^="glass"] .tbl.cards tr {
    -webkit-backdrop-filter: blur(var(--blur)) saturate(var(--sat));
    backdrop-filter: blur(var(--blur)) saturate(var(--sat));
    box-shadow: 0 6px 20px var(--shadow),
                inset 0 1px 0 var(--s-hi),
                inset 0 -1px 0 var(--s-lo);
  }
}

/* ── Главная: плитки разделов ───────────────────────────────
 * Первый экран панели — не сводка, а список входов. Плитка вместо
 * строки списка по одной причине: в неё попадают пальцем не глядя.
 * 150×74 — заметно больше 44 px, рекомендованных Apple, и рука не ищет
 * цель, когда телефон держат одной рукой.
 */
.home-grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
/* Свой display перебивает браузерное [hidden] { display: none } —
   без этой строки свёрнутая группа остаётся на экране. */
.home-grid[hidden] { display: none; }
.home-tile {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  min-height: 74px; padding: 12px 14px; cursor: pointer; text-align: left;
  font-family: inherit; color: var(--txt);
  background: var(--bg3); border: 1px solid var(--divider);
  border-radius: var(--radius);
}
.home-tile .ic { font-size: 19px; line-height: 1.1; margin-bottom: 2px; color: var(--accent); }
.home-tile b { font-size: 14px; font-weight: 600; line-height: 1.25; }
/* Подпись только у неперенесённых: «работает» под каждой плиткой —
   это двадцать одинаковых слов и ни одного полезного. */
.home-tile small { font-size: 11px; color: var(--muted); }
.home-tile:active { transform: scale(.97); }
@media (hover: hover) and (pointer: fine) {
  .home-tile:hover { border-color: var(--accent); background: var(--acc-s); }
}
[data-theme^="glass"] .home-tile {
  background: var(--bg2);
  -webkit-backdrop-filter: blur(12px) saturate(150%);
  backdrop-filter: blur(12px) saturate(150%);
  box-shadow: inset 0 1px 0 var(--s-hi);
}
@media (max-width: 380px) { .home-grid { grid-template-columns: 1fr 1fr; } }

/* Свёрнутая группа на главной. Стрелка та же, что в меню, —
   один жест должен выглядеть одинаково в обоих местах. */
.fold-h {
  display: flex; align-items: center; gap: 8px;
  cursor: pointer; user-select: none; margin: -2px 0 0;
  padding: 4px 0; min-height: 34px;
}
.fold-h h3 { margin: 0; }
.fold-h .muted { font-size: 12px; }
.fold-h .nav-arrow { color: var(--muted); }
.fold-h.open .nav-arrow { transform: rotate(90deg); }
.fold-h + .home-grid { margin-top: 10px; }
@media (hover: hover) and (pointer: fine) { .fold-h:hover h3 { color: var(--accent); } }

/* ── Стекло: воздуха больше, бежевого меньше ────────────────
 * Прошлая версия была плотной и тёплой до желтизны: пять насыщенных
 * пятен, стекло подкрашено в тёплый белый, размытие с saturate 190%.
 * Вместе это читалось как крем, а не как стекло — оттенок «старого
 * интерфейса» даёт именно пересыщенность, а не сама бежевая палитра.
 *
 * Что изменено:
 *   • основа почти белая, пятна крупнее и бледнее — фон стал светом,
 *     а не заливкой;
 *   • добавлено одно холодное пятно. Оно и делает картинку современной:
 *     тёплое рядом с прохладным читается как воздух и глубина, а один
 *     только тёплый ряд — как пожелтевшая бумага;
 *   • стекло почти нейтральное и прозрачнее, saturate снижен со 190%
 *     до 135% — цвет под стеклом больше не выкручивается;
 *   • тени крупнее и слабее, скругление больше: лист лежит НАД фоном,
 *     а не вырезан в нём.
 */
[data-theme="glass-light"] {
  --bg: radial-gradient(90% 62% at 8% -6%,   rgba(232,199,188,.55) 0%, rgba(232,199,188,0) 62%),
        radial-gradient(85% 60% at 96% 2%,   rgba(235,219,190,.50) 0%, rgba(235,219,190,0) 60%),
        radial-gradient(70% 55% at 78% 52%,  rgba(205,209,224,.42) 0%, rgba(205,209,224,0) 66%),
        radial-gradient(95% 70% at 12% 104%, rgba(226,213,199,.45) 0%, rgba(226,213,199,0) 62%),
        #FCFBF9;
  --bg2:      rgba(255,255,255,.56);
  --bg3:      rgba(255,255,255,.40);
  --field:    rgba(255,255,255,.48);
  --border:   rgba(255,255,255,.75);
  --divider:  rgba(72,58,52,.16);
  --row-alt:  rgba(255,255,255,.34);
  --row-hov:  rgba(255,255,255,.62);
  --shadow:   rgba(84,64,54,.10);
  --s-hi:     rgba(255,255,255,.90);
  --s-lo:     rgba(84,64,54,.06);
  --blur:     28px;
  --sat:      135%;
  --radius:   18px;
  --radius-s: 12px;
  --txt:      #2B2422;
  --txt2:     #5E524B;
  --muted:    #918780;
}

/* Тёмное стекло — та же правка: холодная нота, меньше сажи, больше
   прозрачности. Чёрно-коричневый монолит выглядел не ночью, а грязью. */
[data-theme="glass-dark"] {
  --bg: radial-gradient(90% 62% at 6% -6%,   rgba(86,60,50,.65) 0%, rgba(86,60,50,0) 62%),
        radial-gradient(85% 58% at 98% 4%,   rgba(70,58,44,.60) 0%, rgba(70,58,44,0) 60%),
        radial-gradient(70% 55% at 76% 56%,  rgba(52,56,74,.50) 0%, rgba(52,56,74,0) 66%),
        #131211;
  --bg2:      rgba(58,50,45,.55);
  --bg3:      rgba(52,45,40,.44);
  --field:    rgba(0,0,0,.24);
  --border:   rgba(255,255,255,.10);
  --divider:  rgba(255,255,255,.14);
  --row-alt:  rgba(255,255,255,.030);
  --row-hov:  rgba(255,255,255,.075);
  --shadow:   rgba(0,0,0,.40);
  --s-hi:     rgba(255,255,255,.10);
  --s-lo:     rgba(0,0,0,.28);
  --blur:     26px;
  --sat:      130%;
  --radius:   18px;
  --radius-s: 12px;
}

/* Тень мягче и шире, кромка тоньше. Резкая тень под каждой карточкой —
   то же самое, что рамка: она рубит страницу на прямоугольники. */
[data-theme^="glass"] :is(.card, .stat, .table-wrap, .cns-kpi .k) {
  box-shadow: 0 14px 40px var(--shadow),
              inset 0 1px 0 var(--s-hi),
              inset 0 -1px 0 var(--s-lo);
}
[data-theme^="glass"] :is(.savebar, .usermenu-pop, .a2hs) {
  box-shadow: 0 20px 50px var(--shadow), inset 0 1px 0 var(--s-hi);
}
@media (max-width: 768px) {
  [data-theme^="glass"] .tbl.cards tr {
    box-shadow: 0 8px 24px var(--shadow),
                inset 0 1px 0 var(--s-hi),
                inset 0 -1px 0 var(--s-lo);
  }
}

/* Меню — не панель, а слой: сплошная граница заменена световой кромкой */
[data-theme^="glass"] .nav {
  background: rgba(255,255,255,.34);
  border-right: 1px solid var(--divider);
}
[data-theme="glass-dark"] .nav { background: rgba(255,255,255,.035); }

/* Плитки главной легче карточек, в которых лежат: два одинаково
   плотных стекла друг на друге выглядят слипшимися. */
[data-theme^="glass"] .home-tile {
  background: rgba(255,255,255,.42);
  border-color: rgba(255,255,255,.55);
  box-shadow: 0 4px 14px var(--shadow), inset 0 1px 0 var(--s-hi);
}
[data-theme="glass-dark"] .home-tile {
  background: rgba(255,255,255,.055);
  border-color: rgba(255,255,255,.09);
}

@supports not (backdrop-filter: blur(1px)) {
  [data-theme="glass-light"] { --bg2: rgba(255,255,255,.93); --bg3: rgba(255,255,255,.86);
                               --field: rgba(255,255,255,.94); }
  [data-theme="glass-dark"]  { --bg2: rgba(58,50,45,.95);     --bg3: rgba(52,45,40,.92); }
}
@media (prefers-reduced-transparency: reduce) {
  [data-theme="glass-light"] { --bg2: #FFFFFF; --bg3: #F4F1EC; --field: #FFFFFF; --blur: 0px; }
  [data-theme="glass-dark"]  { --bg2: #2A2522; --bg3: #221E1B; --blur: 0px; }
}

/* ── Отклик на нажатие и появление ──────────────────────────
 * Меню под именем раскрывается ОТ КНОПКИ, а не из центра: всплывающее
 * окно должно расти оттуда, куда нажали, иначе взгляд теряет связь
 * между кнопкой и тем, что появилось.
 *
 * Появление анимируем, исчезновение — нет. Правило общее: медленно там,
 * где человек решает, мгновенно там, где отвечает система. Закрыл меню —
 * значит, уже смотрит в другое место, и провожать его не нужно.
 *
 * Через @starting-style, а не через классы: там, где браузер этого не
 * умеет, меню просто появится сразу — и ничего не сломается.
 */
.usermenu-pop {
  transform-origin: top right;
  transition: opacity .15s ease-out, transform .15s cubic-bezier(.23, 1, .32, 1);
  opacity: 1; transform: scale(1);
}
@starting-style {
  .usermenu-pop { opacity: 0; transform: scale(.96); }
}

/* Полоса сохранения выезжает снизу — оттуда же, где и живёт.
   Ничто в природе не появляется из ничего, поэтому не scale(0),
   а сдвиг на свою высоту и почти полный масштаб. */
.savebar, .a2hs {
  transition: opacity .2s ease-out, transform .2s cubic-bezier(.23, 1, .32, 1);
}
@starting-style {
  .savebar { opacity: 0; transform: translateX(-50%) translateY(12px); }
  .a2hs    { opacity: 0; transform: translateY(12px); }
}

/* Нажатие: цель уменьшается на 3% за 160 мс. Отвечаем на нажатие,
   а не на отпускание — так интерфейс кажется живым. */
:is(.home-tile, .fold-h):active { transform: scale(.985); }
:is(.home-tile, .fold-h) {
  transition: transform .16s cubic-bezier(.23, 1, .32, 1),
              background .15s ease, border-color .15s ease, box-shadow .15s ease;
}

/* ── Выбор оформления в меню под именем ─────────────────────
 * Строка — семейство, три кнопки — режим. Сетка, а не список из шести
 * тем: так видно, что «светлое» и «тёмное» — это одно и то же
 * оформление в двух состояниях, а не две разные темы.
 */
.upop-h {
  padding: 8px 12px 6px; font-size: 11px; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted);
}
.upop-note { padding: 8px 12px 4px; font-size: 11px; color: var(--muted); line-height: 1.4; }
.upop-more { margin-left: auto; color: var(--muted); }
.upop-item { display: flex; align-items: center; gap: 8px; }

.thr { display: flex; align-items: center; gap: 6px; padding: 4px 8px; }
.thr .t { flex: 1; font-size: 14px; }
.thb {
  min-width: 36px; height: 36px; padding: 0; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: 11px;
  background: var(--bg3); color: var(--txt2);
  font-family: inherit; font-size: 15px; line-height: 1; cursor: pointer;
  transition: transform .16s cubic-bezier(.23, 1, .32, 1),
              background .15s ease, border-color .15s ease, color .15s ease;
}
.thb.wide { padding: 0 12px; font-size: 12px; font-weight: 600; }
.thb:active { transform: scale(.94); }
.thb.on {
  background: var(--acc-s); border-color: var(--accent);
  color: var(--accent); font-weight: 600;
}
@media (hover: hover) and (pointer: fine) {
  .thb:hover { border-color: var(--accent); color: var(--accent); }
}
/* Пальцем: цель не меньше 40 px, и меню шире, чтобы строка не ломалась */
@media (max-width: 768px) {
  .thb { min-width: 40px; height: 40px; }
  .usermenu-pop { min-width: 268px; }
}

/* ── Окно поверх страницы ───────────────────────────────────
 * Затемнение с лёгким размытием: страница под ним видна, но перестаёт
 * быть тем, на что смотрят. Окно появляется от центра — оно не привязано
 * к кнопке, в отличие от всплывающих меню, и расти ему неоткуда.
 */
.modal {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center; padding: 16px;
  background: rgba(30, 22, 18, .42);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  transition: opacity .18s ease-out;
}
.modal-card {
  width: 100%; max-width: 380px;
  max-height: calc(100svh - 32px); overflow-y: auto;
  padding: 18px; border-radius: var(--radius);
  background: var(--bg2); border: 1px solid var(--border);
  box-shadow: 0 26px 70px var(--shadow), inset 0 1px 0 var(--s-hi, transparent);
  transition: opacity .2s ease-out, transform .2s cubic-bezier(.23, 1, .32, 1);
}
[data-theme^="glass"] .modal-card,
[data-theme^="apple"] .modal-card {
  -webkit-backdrop-filter: blur(var(--blur, 20px)) saturate(var(--sat, 150%));
  backdrop-filter: blur(var(--blur, 20px)) saturate(var(--sat, 150%));
}
@starting-style {
  .modal { opacity: 0; }
  .modal-card { opacity: 0; transform: scale(.96); }
}

/* ── Подгонка значка ────────────────────────────────────────
 * Скругление 22% — та же форма, что у иконки на домашнем экране iOS.
 * Показываем именно её: подгонять «в квадрат» и обнаружить потом, что
 * телефон срезал углы, — обычная и очень обидная промашка.
 */
.icon-edit {
  position: relative; width: 288px; max-width: 100%;
  aspect-ratio: 1; margin: 14px auto 0;
}
.icon-edit canvas {
  width: 100%; height: 100%; display: block;
  border-radius: 22%; background: #fff;
  /* Без этого перетаскивание пальцем прокручивает страницу, а не
     двигает картинку. */
  touch-action: none; cursor: grab;
}
.icon-edit canvas:active { cursor: grabbing; }
.icon-mask {
  position: absolute; inset: 0; pointer-events: none; border-radius: 22%;
  box-shadow: inset 0 0 0 1px var(--divider), 0 10px 30px var(--shadow);
}
.icon-range { flex: 1; min-width: 0; accent-color: var(--accent); height: 28px; }

/* Спаривание с телефоном: QR и адрес рядом. На узком экране — друг
   под другом, но там эта кнопка и не нужна: код показывают с компьютера. */
.inv-pair { display: flex; gap: 16px; align-items: flex-start; margin-top: 12px; flex-wrap: wrap; }
.inv-pair-qr { flex: 0 0 auto; background: #fff; padding: 10px; border-radius: 12px; }
.inv-pair-qr svg { width: 190px; height: 190px; display: block; }
.inv-pair-txt { flex: 1; min-width: 220px; }

/* Код инвентаризации: его называют вслух через комнату, поэтому крупно
   и с разрядкой — «четыре восемь два один», а не «четырезвосемьдесятдва». */
.inv-pin { font-size: 20px; letter-spacing: .18em; color: var(--accent); }

/* Сошлось: остаток равен факту. Подсветка нужна не для красоты —
   при пересчёте глазами ищут не цифры, а то, что уже закрыто. Зелёная
   строка отвечает на это сразу, не заставляя сравнивать два числа
   в соседних столбцах. */
.inv-ok > td { background: rgba(107, 142, 78, .10); }
@media (max-width: 768px) {
  .tbl.cards.inv-table tr.inv-ok { background: rgba(107, 142, 78, .10); }
  .tbl.cards.inv-table tr.inv-ok > td { background: transparent; }
}

/* Шапка инвентаризации на узком экране: кнопки уходят под заголовок.
   Иначе они отжимают название в колонку шириной в два слова, и дата
   переносится по слогам. */
@media (max-width: 560px) {
  .inv-head { flex-wrap: wrap; }
  .inv-head > div:first-child { flex: 1 1 100%; }
  .inv-head .row { width: 100%; }
}

/* ── Нижнее меню: стекло, как в Telegram и Instagram ────────
 * Панель не перекрывает содержимое, а размывает его: полоса сохраняет
 * ощущение, что список продолжается под ней, а не обрывается. Отсюда
 * все решения ниже.
 *
 * Сплошной рамки нет — волосяная линия в полпикселя: рамка в 1 px
 * читается как край чужого блока, приклеенного снизу.
 *
 * Выдвижного меню на телефоне больше нет, поэтому крайняя правая
 * кнопка — «Меню»: она ведёт на главную с раскрытыми настройками.
 */
@media (max-width: 768px) {
  /* НА ТЕЛЕФОНЕ ПАНЕЛЬ НЕПРОЗРАЧНАЯ, БЕЗ РАЗМЫТИЯ.
     Стекло красиво на снимке и дорого в прокрутке: размытие
     закреплённой панели пересчитывается на каждый кадр, и на iOS
     она начинает отставать от списка — та самая «плавающая» полоса.
     Поверхность под ней всё равно почти не видна, а читаемость
     подписей на непрозрачном фоне выше. На широком экране стекло
     остаётся: там прокрутка не инерционная и слой дешевле. */
  .tabbar {
    background: var(--bg2);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border-top: .5px solid var(--divider, var(--border));
    box-shadow: none;
  }
  /* Выдвижное меню убрано: открыть его больше нечем, а лежать
     невидимым слоем поверх страницы оно не должно. */
  .nav, .nav-veil { display: none !important; }

  .tabbar .tab {
    border-radius: 12px; padding: 7px 2px 6px;
    transition: color .15s ease, background .15s ease,
                transform .16s cubic-bezier(.23, 1, .32, 1);
  }
  .tabbar .tab .ic { font-size: 19px; }
  .tabbar .tab:active { transform: scale(.94); }
  /* Активная — подложкой, а не только цветом: палец закрывает подпись,
     и цвет текста под ним не виден. */
  .tabbar .tab.active { background: var(--acc-s); color: var(--accent); font-weight: 600; }
}

/* ── Шторка «Меню» ──────────────────────────────────────────
 * Список разделов ложится ПОВЕРХ страницы, не заменяя её: полупрозрачный
 * матовый слой, сквозь который видно, откуда человек пришёл. Уходит по
 * тому же нажатию, каким открылся, — поэтому полоса вкладок остаётся
 * сверху, а не прячется под шторкой.
 */
.menusheet {
  position: fixed; left: 0; right: 0; top: 0; z-index: 39;
  bottom: calc(56px + env(safe-area-inset-bottom));
  overflow-y: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: calc(12px + env(safe-area-inset-top)) 12px 14px;
  /* Шторка ПРОКРУЧИВАЕТСЯ, и размытие здесь обходится дороже всего:
     браузер пересчитывает его на каждый кадр прокрутки, а вместе
     с ним запаздывает и полоса вкладок поверх — это и выглядит как
     «кнопки плавают». Фон непрозрачный: сквозь 88% прозрачности всё
     равно ничего не разглядеть, а список читается лучше. */
  background: var(--bg2);
  transform: translateZ(0);
  transition: opacity .18s ease-out, transform .2s cubic-bezier(.23, 1, .32, 1);
}
.menusheet[hidden] { display: none; }
/* Выезжает снизу, оттуда же, где кнопка. Не из ничего: сдвиг небольшой,
   иначе на длинном списке видно, как он «догоняет» палец. */
@starting-style {
  .menusheet { opacity: 0; transform: translate3d(0, 14px, 0); }
}
@supports not (backdrop-filter: blur(1px)) {
  .menusheet { background: var(--bg2); }
}
/* На компьютере шторки нет: там слева постоянное меню, и открывать
   поверх него тот же список незачем. */
@media (min-width: 769px) { .menusheet { display: none !important; } }

/* ── Группы услуг: доска ─────────────────────────────────────
 * Слева нераспределённые категории, справа карточки групп.
 * Категорию переносят нажатием («отметил — ↙ сюда») или мышью.
 * На узком экране колонки складываются в одну: сначала список
 * «Без группы» с ограниченной высотой, под ним группы.
 */
.sg-board { display: flex; gap: 14px; align-items: flex-start; }
.sg-pool { flex: 0 0 300px; position: sticky; top: 12px; max-height: calc(100vh - 40px);
           overflow: auto; }
.sg-groups { flex: 1 1 auto; display: grid; gap: 14px;
             grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.sg-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.sg-head > b, .sg-title-ro { flex: 1 1 auto; font-size: 14px; min-width: 0;
                             overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sg-cnt { font-size: 12px; color: var(--muted); white-space: nowrap; }
.sg-title { flex: 1 1 auto; min-width: 0; border: none; background: transparent;
            font: inherit; font-size: 14px; font-weight: 600; color: var(--txt);
            padding: 2px 0; border-bottom: 1px solid transparent; }
.sg-title:hover, .sg-title:focus { border-bottom-color: var(--border); outline: none; }
.sg-del { border: none; background: transparent; color: var(--muted); cursor: pointer;
          font-size: 15px; line-height: 1; padding: 4px 6px; font-family: inherit; }
.sg-del:hover { color: var(--danger); }
.sg-take { border: 1px solid var(--border); background: var(--field); color: var(--muted);
           border-radius: 10px; font-size: 12px; font-weight: 600; padding: 5px 10px;
           cursor: pointer; white-space: nowrap; font-family: inherit; }
.sg-take.hot { background: var(--accent); border-color: var(--accent); color: #fff; }
.sg-take:disabled { opacity: .35; cursor: default; }
/* Заголовок карточки группы — в две строки: название с «↙ сюда» и ✕
   сверху, счётчик под ними. В одну строку длинный счётчик («19 кат. ·
   155 усл. (61 отдельно)») сжимал поле названия до одной буквы. */
.sg-groups .sg-head { flex-wrap: wrap; row-gap: 2px; }
.sg-groups .sg-head .sg-take { order: 1; }
.sg-groups .sg-head .sg-del { order: 2; }
.sg-groups .sg-head .sg-cnt { order: 3; flex-basis: 100%; white-space: normal; }
/* Услуги, отнесённые к группе точечно: раскрывающийся список с поиском. */
.sg-own { margin-top: 10px; padding-top: 8px; border-top: 1px dashed var(--border); }
.sg-own-t { border: 0; background: none; padding: 4px 0; font: inherit; font-size: 13px;
            color: var(--muted); cursor: pointer; }
.sg-own-t:hover, .sg-own-t[aria-expanded="true"] { color: var(--accent); }
.sg-own-q { margin: 6px 0 8px; }
.sg-own-list { display: flex; flex-direction: column; gap: 4px; max-height: 320px; overflow: auto; }
.sg-own-row { display: flex; align-items: center; gap: 8px; padding: 6px 8px;
              border: 1px solid var(--border); border-radius: 8px; font-size: 13px; }
.sg-own-row span { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sg-own-row i { flex: 0 1 40%; min-width: 0; font-style: normal; font-size: 11px; color: var(--muted);
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: right; }
.sg-own-x { border: 0; background: none; padding: 0 2px; font-size: 16px; line-height: 1;
            color: var(--muted); cursor: pointer; }
.sg-own-x:hover { color: var(--danger); }
.sg-search { margin-bottom: 10px; }
.sg-drop { min-height: 64px; border: 1px dashed var(--border); border-radius: 12px;
           padding: 8px; display: flex; flex-direction: column; gap: 6px; }
.sg-drop.over { border-color: var(--accent);
                background: color-mix(in srgb, var(--accent) 12%, transparent); }
.sg-chip { display: flex; align-items: center; gap: 8px; padding: 7px 10px;
           border: 1px solid var(--border); border-radius: 10px; background: var(--field);
           font-size: 13px; cursor: pointer; user-select: none; -webkit-user-select: none; }
.sg-chip:hover { border-color: var(--accent); }
.sg-chip.sel { border-color: var(--accent); font-weight: 600;
               background: color-mix(in srgb, var(--accent) 14%, transparent); }
.sg-chip span { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sg-chip i { font-style: normal; font-size: 11px; color: var(--muted); }
/* Категория, все услуги которой разнесены отдельно: в «Без группы» она
   ещё стоит, но разносить в ней больше нечего — гасим, чтобы глаз шёл
   к тем, где осталось. */
.sg-chip.sg-done { opacity: .5; }
.sg-chip.sg-done.sel { opacity: 1; }
.sg-none { color: var(--muted); font-size: 12px; padding: 10px 4px; text-align: center;
           line-height: 1.5; }
.sg-selinfo { font-size: 13px; font-weight: 600; color: var(--accent); margin-left: auto; }
.sg-hint { font-size: 12px; color: var(--muted); margin: 10px 0 0; line-height: 1.6; }
.sg-note { font-size: 12px; color: var(--muted); margin-top: 8px; }
.sg-note.warn { color: var(--accent); }
.sg-note.bad { color: var(--danger); }
/* Ярлык летит за курсором: без него при перетаскивании не видно, что
   именно тащишь, — особенно когда тащат пачку. */
.sg-ghost { position: fixed; z-index: 90; pointer-events: none; padding: 6px 10px;
            border-radius: 10px; background: var(--accent); color: #fff; font-size: 12px;
            font-weight: 600; box-shadow: 0 6px 18px rgba(0,0,0,.18); }
body.sg-dragging { cursor: grabbing; }
body.sg-dragging .sg-chip { cursor: grabbing; }

@media (max-width: 768px) {
  .sg-board { flex-direction: column; }
  .sg-pool { flex: 1 1 auto; width: 100%; position: static; max-height: 340px; }
  .sg-groups { width: 100%; grid-template-columns: 1fr; }
}

/* ═══════════════════════════════════════════════════════════════
   СТЕКЛО И НОЧЬ — тема по утверждённому макету
   Одно оформление в двух режимах. Светлое: почти белый лист и три
   бледных пятна — розовое, песочное и одно ХОЛОДНОЕ. Холодное здесь
   главное: тёплое рядом с прохладным читается как воздух, а один
   тёплый ряд — как пожелтевшая бумага. Ночное: тот же приём на
   чёрном, где пудра становится дороже, а экран телефона гасит
   пиксели и экономит заряд.
   ═══════════════════════════════════════════════════════════════ */
[data-theme="glass-light"] {
  --bg: radial-gradient(78% 52% at 6% -4%,   rgba(212,166,152,.55) 0%, rgba(212,166,152,0) 62%),
        radial-gradient(70% 48% at 98% 6%,   rgba(226,208,178,.50) 0%, rgba(226,208,178,0) 60%),
        radial-gradient(62% 46% at 84% 62%,  rgba(196,200,216,.42) 0%, rgba(196,200,216,0) 66%),
        #F6F6F3;
  --bg2:      rgba(255,255,255,.58);
  --bg3:      rgba(255,255,255,.42);
  --field:    rgba(255,255,255,.52);
  --border:   rgba(255,255,255,.78);
  --divider:  rgba(90,66,58,.14);
  --row-alt:  rgba(255,255,255,.32);
  --row-hov:  rgba(255,255,255,.60);
  --txt:      #221C19;
  --txt2:     #5C524C;
  --muted:    #8B8177;
  --accent:   #AF8578;
  --acc-h:    #9A7266;
  --acc-s:    rgba(175,133,120,.14);
  --shadow:   rgba(96,70,58,.10);
  --s-hi:     rgba(255,255,255,.90);
  --s-lo:     rgba(96,70,58,.05);
  --blur:     24px;
  --sat:      140%;
  --radius:   18px;
  --radius-s: 12px;
  color-scheme: light;
}

[data-theme="glass-dark"] {
  --bg: radial-gradient(80% 50% at 4% -6%,   rgba(175,133,120,.34) 0%, rgba(175,133,120,0) 62%),
        radial-gradient(66% 44% at 100% 8%,  rgba(120,96,72,.26)  0%, rgba(120,96,72,0)  60%),
        #0B0A09;
  --bg2:      rgba(255,255,255,.055);
  --bg3:      rgba(255,255,255,.04);
  --field:    rgba(0,0,0,.25);
  --border:   rgba(255,255,255,.10);
  --divider:  rgba(255,255,255,.09);
  --row-alt:  rgba(255,255,255,.025);
  --row-hov:  rgba(255,255,255,.06);
  --txt:      #F2EDE9;
  --txt2:     #C9C0B9;
  --muted:    #8E837B;
  /* Пудра на чёрном темнеет и перестаёт читаться, поэтому акцент
     поднят по светлоте. Это тот же цвет, а не другой. */
  --accent:   #C79A8C;
  --acc-h:    #D6AB9C;
  --acc-s:    rgba(175,133,120,.22);
  --success:  #47C98A;
  --danger:   #FF6B6B;
  --shadow:   rgba(0,0,0,.55);
  --s-hi:     rgba(255,255,255,.08);
  --s-lo:     rgba(0,0,0,.35);
  --blur:     22px;
  --sat:      130%;
  --radius:   18px;
  --radius-s: 12px;
  color-scheme: dark;
}

/* Ночь — не инверсия дня: жёлтые пометки, набранные дневной охрой
   #A8781A, на чёрном превращаются в грязь. Поднимаем их так же,
   как зелёный и красный. */
[data-theme="glass-dark"] :is(.badge.warn, .cns-warn, .cns-g.stub, .cns-g.unit,
                              .cns-pick .tag, .cns-kpi .k.warn b, .wt-man) {
  background-color: rgba(224,169,58,.16);
  color: #E0A93A;
  border-color: rgba(224,169,58,.34);
}
[data-theme="glass-dark"] :is(.cns-kpi .k.warn b, .wt-man) { background: none; }
[data-theme="glass-dark"] .badge.ok  { background: rgba(71,201,138,.16);  color: #47C98A; }
[data-theme="glass-dark"] .badge.err { background: rgba(255,107,107,.16); color: #FF6B6B; }
[data-theme="glass-dark"] .inv-plus  { color: #47C98A; }
[data-theme="glass-dark"] .inv-minus { color: #FF6B6B; }

/* Тень мягче и шире, кромка тоньше: резкая тень под каждым блоком
   рубит страницу на прямоугольники — ровно то, от чего уходим. */
[data-theme^="glass"] :is(.card, .stat, .table-wrap, .cns-kpi .k, .home-tile) {
  box-shadow: 0 6px 18px var(--shadow),
              inset 0 1px 0 var(--s-hi),
              inset 0 -1px 0 var(--s-lo);
}

/* Оформление нижней полосы — одно на все темы, ниже в разделе
   «НИЖНЯЯ ПАНЕЛЬ». Отдельного правила для стеклянных тем больше нет:
   полоса и так стеклянная везде, а два набора правил на один элемент
   расходились при каждой правке. */
@supports not (backdrop-filter: blur(1px)) {
  [data-theme="glass-light"] { --bg2: rgba(255,255,255,.94); --bg3: rgba(255,255,255,.88);
                               --field: rgba(255,255,255,.96); }
  [data-theme="glass-dark"]  { --bg2: #1B1917; --bg3: #171514; --field: #121110; }
}
@media (prefers-reduced-transparency: reduce) {
  [data-theme="glass-light"] { --bg2: #FFFFFF; --bg3: #F4F2EE; --field: #FFFFFF; --blur: 0px; }
  [data-theme="glass-dark"]  { --bg2: #1B1917; --bg3: #171514; --blur: 0px; }
}

/* ═══════════════════════════════════════════════════════════════
   ВЫРАВНИВАНИЯ
   Правила общие, а не для одного раздела: панель собрана из четырёх
   кирпичей — таблица, пара «ключ — значение», строка с переключателем
   и ряд кнопок. Чинить надо кирпич, иначе через месяц тот же перекос
   вылезет в новом разделе.
   ═══════════════════════════════════════════════════════════════ */

/* 1. Числа — по правому краю и одной ширины.
   Шапка числового столбца равняется по своим числам: заголовок слева
   над правым столбцом цифр — самый заметный перекос в панели.
   Класс на th проставляет сам скрипт панели, по первой строке данных. */
.tbl th.num, table.cns-t th.num { text-align: right; }
:is(.tbl, table.wt, table.cns-t) :is(td, th).num,
:is(.stat .num, .kv .v, .cns-kpi .k b, .inv-pin, .wt-edit, .inv-fact) {
  font-variant-numeric: tabular-nums;
}

/* 2. Ячейка держит содержимое по центру строки.
   По умолчанию клетки равняются по базовой линии: строка со значком
   или ярлыком приподнималась относительно соседей, и список шёл
   волной. Исключение — клетки с подписью вторым этажом: там текст
   должен начинаться сверху, иначе имя «висит» в середине. */
.tbl td, table.wt td, table.cns-t td { vertical-align: middle; }
.tbl td:has(small), .tbl td:has(br) { vertical-align: top; }
.tbl th { vertical-align: bottom; }
.badge, .dot, .cns-g { vertical-align: middle; }

/* 3. Ряд кнопок и полей: одна высота у всего, что стоит в строку.
   Кнопка 36, поле 34 и чип 32 в одном ряду дают лесенку — заметно
   даже боковым зрением. */
/* Высота задана, а не «не меньше»: у кнопки, поля и чипа разные
   внутренние отступы и разный кегль, и одного min-height мало —
   получалась лесенка в один-три пиксела. Заметно боковым зрением.
   Клетки таблицы исключены: там свой, плотный ритм.
   textarea тоже: ей высоту задаёт содержимое. */
.row:not(td) > :is(.btn, .chip, .cns-f, input.input, select.input) {
  height: 38px; min-height: 38px;
}
.row:not(td) > .btn-mini { height: 34px; min-height: 34px; }
@media (max-width: 768px) {
  .row:not(td) > :is(.btn, .chip, .cns-f, input.input, select.input) {
    height: 44px; min-height: 44px;
  }
  .row:not(td) > .btn-mini { height: 40px; min-height: 40px; }
}

/* 4. Пара «ключ — значение»: ключ слева, значение справа, обе строки
   по верхней линии. Длинный ключ переносится, значение не уезжает. */
.kv { align-items: baseline; }
.kv .k { min-width: 0; }
.kv .v { text-align: right; white-space: nowrap; flex: 0 0 auto; }

/* 5. Строка с переключателем: переключатели выстроены в один столбец
   у правого края, независимо от длины подписи. */
.feat { align-items: center; }
.feat .t { min-width: 0; }
.feat .sw { margin-left: auto; }
.feat .t small { display: block; }

/* 6. Показатели: равные плитки, без сироты во всю ширину.
   Резинка flex растягивала последнюю плитку на весь ряд, если она
   оставалась одна, — и «1 опоздание» занимало столько же места,
   сколько все остальные вместе. */
.stats {
  display: grid; gap: 8px;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.stat { min-width: 0; }
@media (max-width: 720px) { .stats { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 460px) { .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.stat .lbl {
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* 7. Поля формы: подпись, поле и подсказка одной левой линией. */
.field > .lbl, .cns-fld > span { display: block; }
.field, .cns-fld { min-width: 0; }
.input, select.input, textarea.input { max-width: 100%; }
/* Стрелка списка не должна наезжать на текст — у select своя правая
   отбивка, у обычного поля её быть не должно. */
select.input { padding-right: 30px; }

/* 8. Заголовок раздела и кнопка справа — по одной верхней линии,
   а не по середине разной высоты. */
.content > .row:first-child { align-items: flex-start; }
.usermenu { flex: 0 0 auto; }

/* 9. Служебные столбцы таблицы: переключатель по центру своей клетки,
   кнопки — плотной группой у правого края. */
.tbl :is(td, th).col-sw { text-align: center; }
.tbl td.col-act, .tbl td.row { text-align: right; }
.tbl td.col-act .row { justify-content: flex-end; }

/* 10. Плитки главной: подпись прижата к низу, поэтому нижние края
    названий совпадают в ряду независимо от длины. */
.home-tile { justify-content: flex-start; }
.home-tile b { align-self: stretch; }

/* Мелким кнопкам и полям размытие не положено.
 *
 * Радиус пробы у backdrop-filter больше самого элемента: кнопка высотой
 * 34 px с blur 22 px тянет цвет отовсюду вокруг, а у края экрана браузер
 * ещё и растягивает крайний пиксель. На чёрном из этого получалось
 * светло-серое пятно вместо кнопки — «Роман ▾» в ночной теме выглядела
 * подсвеченной, хотя стояла рядом с точно такой же тёмной «Отчёт».
 *
 * Полупрозрачность у них остаётся: она и даёт стекло. Размывать нечего —
 * на площади в два сантиметра размытие не читается, только мешает.
 */
[data-theme^="glass"] :is(.btn, .btn-quiet, .btn-ghost, .btn-mini, .chip,
                          .daynav, .cell-edit, .cns-f, .thb,
                          .input, select.input, textarea.input) {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* ═══════════════════════════════════════════════════════════════
   НИЖНЯЯ ПАНЕЛЬ — как в Instagram и Telegram

   Три вещи делают её «приложением», а не рядом ссылок:

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

   2. Подсветка активной кнопки — не цвет текста, а стеклянная пилюля,
      которая ПЕРЕЕЗЖАЕТ с кнопки на кнопку. Палец закрывает подпись
      целиком, и цвет под ним не виден; пилюля шире пальца и видна
      всегда. Переезд, а не мгновенная перестановка: глаз успевает
      проследить, куда он попал, и переход перестаёт выглядеть
      подменой экрана.

   3. Слева — «Назад». Единственная кнопка, которая ничего не открывает,
      поэтому и отделена линией: она работает с историей, а не с
      разделами. Место левое, как у системной стрелки в iOS и Telegram,
      — движение назад везде влево.
   ═══════════════════════════════════════════════════════════════ */
@media (max-width: 768px) {
  .tabbar, [data-theme^="glass"] .tabbar {
    left: 0; right: 0; bottom: 0;
    gap: 0; padding: 5px 6px calc(5px + env(safe-area-inset-bottom));
    border-radius: 0; border-top: 0;
    /* Стекло: то, что уезжает под полосу, видно размытым пятном, а не
       читается буква в букву. Плотность подобрана так, чтобы подписи
       кнопок оставались контрастнее того, что под ними. */
    background: color-mix(in srgb, var(--edge) 88%, transparent);
    -webkit-backdrop-filter: blur(26px) saturate(180%);
    backdrop-filter: blur(26px) saturate(180%);
    /* Волосяная кромка сверху вместо рамки: рамка в 1 px на телефоне
       рисуется то толще, то тоньше и выглядит грязью. */
    box-shadow: inset 0 .5px 0 var(--hairline), 0 -8px 24px var(--shadow);
    /* Пилюля лежит внутри полосы и не должна вылезать за её края,
       пока переезжает между крайними кнопками. */
    overflow: hidden;
  }

  /* ── Переезжающее стекло ──────────────────────────────────
   * Один элемент на всю полосу: положение и ширину ему ставит скрипт
   * по самой активной кнопке. Подсвечивать фоном саму кнопку нельзя —
   * это две разные коробки, и между ними ничего не «едет»: одна гаснет,
   * другая загорается. Переезжает только то, что существует всё время.
   */
  .tab-glass {
    position: absolute; left: 0; top: 5px; z-index: 0;
    height: calc(100% - 10px - env(safe-area-inset-bottom));
    width: 0; opacity: 0; pointer-events: none;
    border-radius: 17px;
    background: color-mix(in srgb, var(--accent) 17%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent),
                inset 0 1px 0 var(--hairline),
                0 2px 10px color-mix(in srgb, var(--accent) 16%, transparent);
    -webkit-backdrop-filter: blur(8px) saturate(140%);
    backdrop-filter: blur(8px) saturate(140%);
    /* Кривая с перелётом: пилюля чуть проскакивает цель и возвращается
       — так двигаются вкладки в Telegram. Ровный ease выглядит
       механическим переносом прямоугольника. */
    transition: transform .38s cubic-bezier(.34, 1.24, .42, 1),
                width     .38s cubic-bezier(.34, 1.24, .42, 1),
                opacity   .2s  ease;
    will-change: transform, width;
  }

  .tabbar .tab {
    position: relative; z-index: 1;
    flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 2px; padding: 6px 2px 5px; border-radius: 17px;
    /* .tab теперь <button>: сбрасываем всё, что браузер даёт кнопке. */
    border: 0; background: none; font-family: inherit;
    color: var(--muted); cursor: pointer; -webkit-appearance: none; appearance: none;
    -webkit-tap-highlight-color: transparent; user-select: none;
    transition: color .2s ease, transform .16s cubic-bezier(.23, 1, .32, 1),
                opacity .2s ease;
  }
  .tabbar .tab .lb { font-size: 10px; line-height: 1.15; letter-spacing: .01em;
                     max-width: 100%; overflow: hidden; text-overflow: ellipsis;
                     white-space: nowrap; }
  /* Контурный значок вместо эмодзи: эмодзи тянет за собой чужие цвета
     и рисуется по-разному на iOS и Android — полоса выглядит собранной
     из разных наборов. Линия наследует цвет вкладки и гаснет вместе
     с подписью. */
  .tabbar .tab .ic { font-size: 18px; line-height: 0; display: block;
                     transition: transform .2s cubic-bezier(.23, 1, .32, 1); }
  .tabbar .tab .ic svg { width: 23px; height: 23px; display: block; }
  .tabbar .tab:active { transform: scale(.93); }
  /* Фона у активной кнопки нет: его роль исполняет переезжающая пилюля.
     Оставить и то и другое значило бы показывать подсветку дважды —
     одну поверх другой, с разной скоростью. */
  .tabbar .tab.active { background: none; color: var(--accent); font-weight: 600; }
  /* Короткий подскок значка в момент, когда вкладка стала активной.
     Он совпадает по времени с приездом пилюли: два движения читаются
     как одно событие, а не как два подряд. */
  .tabbar .tab.active .ic { animation: tabPop .36s cubic-bezier(.24, 1.4, .35, 1); }
  @keyframes tabPop {
    0%   { transform: scale(1); }
    38%  { transform: scale(1.16) translateY(-1px); }
    100% { transform: scale(1); }
  }

  /* ── «Назад» ──────────────────────────────────────────────
   * Уже разделов: она не место, а действие, и отбирать у разделов
   * пятую часть полосы ради неё нельзя. Линия справа отделяет её от
   * кнопок-разделов — без линии она читалась как ещё один раздел.
   */
  .tabbar .tab-back { flex: 0 0 56px; }
  .tabbar .tab-back .ic svg { width: 21px; height: 21px; }
  .tabbar .tab-back::after {
    content: ''; position: absolute; right: -1px; top: 24%; bottom: 24%;
    width: 1px; background: var(--hairline-firm);
  }
  /* Стрелка отходит влево под пальцем — направление движения видно
     раньше, чем экран успеет поехать. */
  .tabbar .tab-back:active { transform: none; }
  .tabbar .tab-back:active .ic { transform: translateX(-3px); }
  /* Возвращаться некуда — кнопка гаснет, но остаётся на месте.
     Исчезающая кнопка дёргала бы всю полосу на каждом первом переходе,
     и место, где её искать, перестало бы быть постоянным. */
  .tabbar .tab-back.off { opacity: .3; pointer-events: none; }

  /* Запас снизу считается от высоты полосы: ~60 плюс безопасная зона. */
  .content { padding-bottom: calc(74px + env(safe-area-inset-bottom)); }
  .menusheet, [data-theme^="glass"] .menusheet {
    bottom: calc(60px + env(safe-area-inset-bottom));
  }
  .savebar, .toast { bottom: calc(74px + env(safe-area-inset-bottom)); }
  .a2hs { bottom: calc(82px + env(safe-area-inset-bottom)); }
}

/* Волосяные линии полосы. Отдельными переменными, потому что в светлых
   темах кромку даёт белый блик сверху, а в тёмных — наоборот, чёрная
   тень: одно и то же значение в обеих выглядит либо грязью, либо
   ничем. */
:root, [data-theme="light"] { --hairline: rgba(255,255,255,.7);  --hairline-firm: rgba(0,0,0,.10); }
[data-theme="dark"]        { --hairline: rgba(255,255,255,.10); --hairline-firm: rgba(255,255,255,.14); }
[data-theme="glass-light"] { --hairline: rgba(255,255,255,.85); --hairline-firm: rgba(90,66,58,.16); }
[data-theme="glass-dark"]  { --hairline: rgba(255,255,255,.12); --hairline-firm: rgba(255,255,255,.14); }
[data-theme="apple-light"] { --hairline: rgba(255,255,255,.8);  --hairline-firm: rgba(0,0,0,.12); }
[data-theme="apple-dark"]  { --hairline: rgba(255,255,255,.10); --hairline-firm: rgba(255,255,255,.16); }

/* ═══════════════════════════════════════════════════════════════
   ЛИСТАНИЕ РАЗДЕЛОВ
   Экран не подменяется, а уезжает: вперёд — справа, назад — слева.
   Это то же движение, что в Telegram между вкладками и в Instagram
   между разделами, и оно отвечает на вопрос, который подмена оставляет
   без ответа: куда делось предыдущее место. Расфокус в начале даёт
   «стеклянность» — содержимое как бы проявляется сквозь ту же матовую
   поверхность, из которой сделана панель.

   Смещение маленькое (20 px), а не во весь экран: полный проезд на
   длинном списке видно как рывок, потому что браузер не успевает
   отрисовать уезжающее содержимое. Глазу хватает намёка на сторону.
   ═══════════════════════════════════════════════════════════════ */
#stage.sl-fwd  { animation: slideFwd  .34s cubic-bezier(.22, 1, .36, 1) both; }
#stage.sl-back { animation: slideBack .34s cubic-bezier(.22, 1, .36, 1) both; }

@keyframes slideFwd {
  from { opacity: 0; transform: translate3d(20px, 0, 0) scale(.985); filter: blur(6px); }
  55%  { opacity: 1; filter: blur(0); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes slideBack {
  from { opacity: 0; transform: translate3d(-20px, 0, 0) scale(.985); filter: blur(6px); }
  55%  { opacity: 1; filter: blur(0); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}


/* ── Воздух в плитках ───────────────────────────────────────
 * Значок в скруглённом квадрате акцентного оттенка — приём из
 * системных «Настроек» iPhone: цветной квадрат опознаётся быстрее
 * подписи, и по списку начинают ходить по значкам, а не читать.
 */
.home-grid { gap: 12px; }
.home-tile { min-height: 86px; padding: 14px; gap: 3px; }
.home-tile .ic {
  width: 34px; height: 34px; margin-bottom: 6px;
  display: grid; place-items: center; flex: 0 0 auto;
  border-radius: 11px; font-size: 17px; line-height: 1;
  /* 15% пудры на белой плитке не видно вовсе — квадрат должен читаться
     как предмет, иначе он не работает опознавательным знаком. */
  background: color-mix(in srgb, var(--accent) 22%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
}
.home-tile b { font-size: 14.5px; }

/* Плотность шторки «Меню».
 *
 * Она брала фон у карточки (--bg2), а в ночной теме карточка — это
 * пять процентов белого: шторка получалась почти прозрачной, и список
 * разделов ложился поверх такого же списка на странице. Читалось как
 * двоение, а не как слой.
 *
 * Своя переменная, а не «сделать --bg2 плотнее»: карточка обязана
 * оставаться лёгкой, это её работа. Шторка перекрывает целый экран —
 * ей нужна плотность, иначе сквозь неё видно то, от чего она увела.
 */
:root, [data-theme="light"] { --sheet: rgba(245,245,247,.94); }
[data-theme="dark"]        { --sheet: rgba(28,26,24,.94); }
[data-theme="glass-light"] { --sheet: rgba(250,249,246,.88); }
[data-theme="glass-dark"]  { --sheet: rgba(14,13,12,.92); }
[data-theme="apple-light"] { --sheet: rgba(242,242,247,.92); }
[data-theme="apple-dark"]  { --sheet: rgba(0,0,0,.92); }

.menusheet { background: var(--sheet); }
@supports not (backdrop-filter: blur(1px)) {
  .menusheet { background: var(--sheet); }
}

/* ═══════════════════════════════════════════════════════════════
   НИЖНИЙ КРАЙ: содержимое растворяется, а не упирается в панель
   Плавающая полоса поверх крепкого текста читалась как ошибка вёрстки:
   строки списка подходили к ней вплотную и просвечивали сквозь стекло
   насквозь, буква в букву. У панели в iOS так не бывает — под ней лежит
   слой, в котором содержимое размывается и уходит в цвет страницы.
   Этот слой здесь и появляется.
   ═══════════════════════════════════════════════════════════════ */

/* Сплошной цвет страницы. У стеклянных тем --bg это набор градиентов,
   и подставить его в градиент затухания нельзя — нужен один цвет. */
:root, [data-theme="light"] { --edge: #F5F5F7; }
[data-theme="dark"]        { --edge: #1C1A18; }
[data-theme="glass-light"] { --edge: #F6F6F3; }
[data-theme="glass-dark"]  { --edge: #0B0A09; }
[data-theme="apple-light"] { --edge: #F2F2F7; }
[data-theme="apple-dark"]  { --edge: #000000; }

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

/* Стеклянная полоса требует плотного запасного цвета там, где размытия
   нет: иначе текст под ней читается насквозь. */
@supports not (backdrop-filter: blur(1px)) {
  @media (max-width: 768px) { .tabbar { background: var(--edge); } }
}

/* ── Сотрудники: сверка трёх записей ────────────────────────
 * Строка здесь плотная не ради красоты. В таблице шесть колонок, и в
 * четырёх из них — поля ввода и переключатели; при свободной раскладке
 * браузер отдаёт ширину самой болтливой колонке, роли переносятся на
 * четыре ряда, и одна строка занимает пол-экрана. Сравнить двух людей
 * взглядом становится нельзя — а раздел только для этого и нужен.
 *
 * Отсюда фиксированная сетка колонок, общая базовая линия у клеток и
 * одинаковая высота у всего, что в них лежит.
 */
.people { table-layout: fixed; }
.people td { vertical-align: top; padding: 10px; }
.people .input { width: 100%; }
.people select.input { padding-right: 26px; }

/* Один вертикальный ритм на всю строку: что бы ни лежало в клетке —
   поле, кнопка, плашка, — промежуток между ними один и тот же. */
.people .p-stack { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.people .p-stack > * { margin: 0; }

.people .p-name { font-weight: 600; line-height: 1.25; }
.people .p-sub { display: block; color: var(--muted); font-size: 11px; line-height: 1.3; }
.people .p-dash { color: var(--muted); }

/* Роли сотрудника.
 *
 * Здесь была сетка в два столбца — и она разъезжалась на узком экране.
 * `1fr` это `minmax(auto, 1fr)`, а `auto` не даёт колонке стать уже
 * своего содержимого: при ширине клетки меньше двух «Администраторов»
 * сетка не сжималась, а вылезала наружу и ложилась поверх соседней
 * колонки. Ровные ряды не стоят того, чтобы вёрстка ломалась.
 *
 * Поэтому перенос по месту и жёсткий предел ширины у самого чипа:
 * что бы ни пришло с сервера в списке ролей и как бы ни сузилась
 * колонка, за границу клетки это не выйдет. */
.people .p-roles {
  display: flex; flex-wrap: wrap; gap: 4px;
  width: 100%; min-width: 0;
}
.people .p-roles .chip {
  min-height: 24px; padding: 2px 8px; font-size: 11px;
  justify-content: center; text-align: center; line-height: 1.2;
  max-width: 100%; white-space: normal; overflow-wrap: anywhere;
}

/* Свёрнутые роли: в клетке видно только назначенное, полный набор
   открывается по «изменить».
   Семь плашек в каждой строке — это шесть рядов пустых чекбоксов
   у человека с одной ролью: строка растёт втрое, а сведений в ней
   столько же. Свёрнутая клетка возвращает таблице плотность, ради
   которой раздел и делался — сравнить людей взглядом. */
.people .p-rolebox > summary {
  list-style: none; cursor: pointer;
  display: flex; flex-wrap: wrap; gap: 4px; align-items: center;
}
.people .p-rolebox > summary::-webkit-details-marker { display: none; }
.people .p-rolebox-more {
  font-size: 11px; color: var(--muted);
  border-bottom: 1px dotted var(--muted); line-height: 1.1;
}
.people .p-rolebox[open] > summary { margin-bottom: 6px; }
.people .p-rolebox[open] .p-rolebox-more { color: var(--accent); border-bottom-color: var(--accent); }
/* Плашки в свёрнутом виде — подпись, а не переключатель: нажатие
   раскрывает клетку целиком, а не переключает роль мимо чекбокса. */
.people .p-rolebox > summary .chip { pointer-events: none; }

/* Ничто в клетке не имеет права торчать наружу: колонки заданы
   процентами, и любой неразрывный кусок — длинная роль, почта, @ник —
   иначе накрывает соседа. */
.people td > * { max-width: 100%; }
.people td { overflow-wrap: anywhere; }

/* Три записи о человеке — три группы колонок. Тонкая линейка между
   ними заменяет попытку разделить их пробелом: пробел в таблице
   съедается выравниванием, линейка держится.
   Только на широком экране: в карточном режиме колонок нет, и та же
   линейка легла бы поперёк карточки случайной чертой. */
@media (min-width: 769px) {
  .people :is(th, td):nth-child(3) { border-left: 1px solid var(--border); }
  .people.p-wide :is(th, td):nth-child(6) { border-left: 1px solid var(--border); }
  .people:not(.p-wide) :is(th, td):nth-child(5) { border-left: 1px solid var(--border); }
}

/* Служебные кнопки — сеткой, а не переносом. Перенос давал ряд
   «четыре и один»: у каждого второго человека своя ломаная, хотя
   кнопки везде одни и те же.
   `width:100%` здесь обязателен: клетка — это флекс-колонка с
   `align-items:flex-start`, а она сжимает ребёнка до его минимума.
   Сетка с `auto-fill` мерила бы себя, а не клетку, и укладывала
   кнопки в один столбик, хотя места хватает на три. */
.people .p-acts {
  display: grid; grid-template-columns: repeat(auto-fill, 26px); gap: 5px;
  justify-content: start; width: 100%;
}
.people .p-acts .btn-mini {
  width: 26px; min-height: 26px; padding: 0; font-size: 12px;
  display: inline-flex; align-items: center; justify-content: center;
}
/* Переключатели того же роста, что и кнопки под ними: разнобой в
   пол-пикселя незаметен, разнобой в четыре — это лишний ряд. */
.people .p-toggles { display: flex; flex-wrap: wrap; gap: 5px; width: 100%; }
.people .p-toggles .chip { min-height: 26px; padding: 2px 7px; font-size: 11px; }

/* Замечания: маркер вынесен в отступ, поэтому вторая строка текста
   встаёт под первой, а не под значком. */
.people .p-flag {
  font-size: 12px; line-height: 1.35; padding-left: 14px; text-indent: -14px;
}
.people .p-flag.bad { color: var(--danger); }
.people .p-flag.soft { color: var(--muted); }

/* Строку, выбранную для слияния, обводим внутренней рамкой: outline
   на <tr> в таблице рисуется поверх соседей и рвёт линейки. */
.people tr.p-merge td { background: var(--acc-s); box-shadow: inset 0 1px 0 var(--accent), inset 0 -1px 0 var(--accent); }

@media (max-width: 768px) {
  /* В карточном режиме клетка — флекс «подпись слева, значение справа»,
     и содержимое должно прижиматься к правому краю, иначе поля разной
     ширины гуляют по карточке. */
  .people { table-layout: auto; }
  .people td { padding: 4px 0; }
  .people .p-stack { align-items: flex-end; max-width: 62%; }
  /* Сетка фиксированных колонок здесь не годится: подпись слева уже
     съела половину ширины, и колонка становится уже самой длинной роли —
     «Администратор» вылезал за край карточки. Переносим по месту. */
  /* Клетка с ролями — во всю ширину карточки: подпись сверху, чипы под
     ней. Прижатые вправо, они вставали лесенкой по одному в строке —
     семь ролей давали семь ступенек. */
  .people td.p-wrap { display: block; }
  .people td.p-wrap::before { display: block; margin-bottom: 6px; text-align: left; }
  .people .p-roles {
    display: flex; flex-wrap: wrap; justify-content: flex-start;
    gap: 6px; width: auto; max-width: 100%;
  }
  .people .p-roles .chip { min-height: 30px; padding: 4px 10px; font-size: 12px; }
  /* Кнопкам доступа отдаём всю ширину карточки: зажатые в 62%, они
     ложились в три ряда там, где помещаются в один. */
  .people .p-stack-wide { max-width: 100%; flex: 1 1 auto; }
  .people .p-acts { grid-template-columns: repeat(auto-fill, 34px); justify-content: flex-end; }
  .people .p-acts .btn-mini { width: 34px; min-height: 34px; }
  .people .p-toggles { justify-content: flex-end; max-width: 62%; }
  .people .p-flag { text-align: right; }
  .people td:first-child .p-stack { align-items: flex-start; max-width: 100%; }
}

/* ── Продажи: дерево прямо в таблице ─────────────────────────
 * Уровень показываем отступом и весом строки, а не вложенными
 * таблицами: колонки «кол-во / цена / сумма» должны стоять в одном
 * столбце на всех уровнях — иначе сравнить сотрудника с сотрудником
 * и товар с товаром глазами нельзя.
 */
/* Стрелка раскрытия. Была 18×18 со значком в 9px — на телефоне в неё
   не попасть пальцем, а на экране её просто не видно среди цифр.
   Теперь 26×26 (минимальная цель для пальца) и значок 12px. Отступ
   уровня равен ширине стрелки, иначе колонки уровней разъезжаются. */
.gs-tw {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; margin-right: 4px; padding: 0;
  border: 0; border-radius: 6px; background: none; color: var(--muted);
  cursor: pointer; font-size: 12px; line-height: 1;
  transition: transform .18s ease, background .12s ease, color .12s ease;
}
.gs-tw:hover { background: var(--hover, rgba(127,127,127,.12)); color: var(--txt); }
.gs-tw.open { transform: rotate(90deg); color: var(--txt); }
.gs-tw.gs-leaf { cursor: default; }
.gs-tw.gs-leaf:hover { background: none; }
.gs-pad { display: inline-block; width: 26px; }

/* Сотрудник без продаж за период. Из списка не убираем — «ноль» это
   ответ, а пропавший человек ответом не является, — но и не выдаём
   за продавца: бледный и с нулём на чипе. */
.gs-zero { opacity: .55; }
.gs-zero.on { opacity: 1; }

/* Пересчёт идёт — таблица гаснет, но остаётся на месте. Подменять её
   надписью «загружаю» значит терять и прокрутку, и то, что человек
   сравнивал глазами секунду назад. */
#gsTable { transition: opacity .12s ease; }
#gsTable.is-busy { opacity: .45; pointer-events: none; }
.gs-tbl .gs-l0 td { font-weight: 600; }
.gs-tbl .gs-l0 td:first-child .gs-t { font-size: 14px; }
.gs-tbl .gs-l2 td { color: var(--muted); }
.gs-tbl .gs-l2 td:first-child .gs-t { color: var(--txt); }
.gs-tbl tfoot td { border-top: 1px solid var(--border); }
.gs-cat { display: flex; align-items: center; gap: 8px; padding: 5px 0; }
/* Заголовок половины списка категорий: услуги и товары нумеруются
   в YCLIENTS независимо, и без разделителя «Уход» из одной половины
   не отличить от «Ухода» из другой. */
.gs-h { margin: 12px 0 4px; font-size: 12px; text-transform: uppercase;
        letter-spacing: .04em; color: var(--muted); }
.gs-h:first-child { margin-top: 4px; }

@media (max-width: 720px) {
  /* На телефоне карточка строки уже несёт подписи колонок, и отступ
     уровня в ней теряется — оставляем его только у названия. */
  .gs-tbl.cards td:first-child { display: flex; align-items: center; }
  .gs-tbl.cards .gs-l1 td:first-child { font-size: 14px; }
  .gs-tbl.cards .gs-l2 td:first-child { font-size: 13px; font-weight: 500; }
}


/* ── Экран врача ────────────────────────────────────────────
 * Работает в двух местах: отдельной страницей `/doc.html` и вкладкой
 * «Приём» раздела «Протоколы». Стили лежат здесь, а не в странице,
 * именно поэтому: в панель они иначе не приезжают.
 */
  /* Экран узкий и вертикальный: телефон в руке, а не таблица на мониторе. */
  .doc { max-width: 720px; margin: 0 auto; padding: 12px 12px 96px; }
  .doc-top { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
  /* Заголовок экрана. На своей странице он первый на экране, во вкладке
     панели — под её заголовком и вкладками, поэтому помельче. */
  .doc-h { font-size: 18px; margin: 0; flex: 1; min-width: 0; }
  /* Во вкладке снизу места меньше: нижняя панель кнопок перекрывает
     последнее поле, если не отступить. */
  #stage .doc-top { margin-top: 4px; }
  /* ЦВЕТА — ТОЛЬКО ИЗ ТЕМЫ, БЕЗ ЗАПАСНЫХ ЗНАЧЕНИЙ.
     Здесь стояли `var(--card, #fff)` и `var(--line, #ddd)` — переменных
     с такими именами в проекте нет (в теме они зовутся `--bg2` и
     `--border`), поэтому всегда срабатывал запасной цвет. В светлой
     теме разницы не было видно, а в ночной страница превращалась в
     белые карточки со светлым текстом: на скриншоте врача читалось
     только «Записи». Правило простое: имя переменной берём из
     app.css и запасное значение не пишем — тогда опечатка видна
     сразу, а не через месяц и только в одной теме. */
  .net { font-size: 12px; padding: 4px 10px; border-radius: 999px;
         background: var(--bg3); color: var(--success); white-space: nowrap; }
  .net.off { background: var(--bg3); color: var(--danger); }
  .net.wait { background: var(--bg3); color: var(--txt2); }

  .rec { display: flex; gap: 10px; align-items: center; width: 100%;
         padding: 12px; border: 1px solid var(--border); border-radius: 14px;
         background: var(--bg2);
         box-shadow: 0 1px 2px var(--shadow); margin-bottom: 8px; text-align: left;
         font: inherit; color: var(--txt); cursor: pointer; }
  .rec .t { font-variant-numeric: tabular-nums; font-weight: 600; min-width: 48px; }
  .rec .who { flex: 1; min-width: 0; }
  .rec .who b { display: block; font-size: 15px; }
  .rec .who small { color: var(--muted); display: block;
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* Готовые формулировки — кнопки, а не выпадающий список: на телефоне
     список из пяти абзацев нечитаем, а тут видно, что выбираешь. */
  .chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; }
  .chip { border: 1px solid var(--border); background: transparent; border-radius: 999px;
          padding: 7px 12px; font: inherit; font-size: 13px; cursor: pointer;
          color: inherit; text-align: left; max-width: 100%; }
  .chip.on { background: var(--accent); color: var(--active-fg); border-color: transparent; }
  .fld { margin-bottom: 16px; }
  .fld > label { display: block; font-weight: 600; margin-bottom: 4px; }
  .fld .hint { color: var(--muted); font-size: 12px; margin: 0 0 4px; }
  .fld textarea.input { min-height: 76px; resize: vertical; }
  .req::after { content: ' •'; color: var(--danger); }

  /* КНОПКИ ЗАКРЕПЛЕНЫ У НИЗА ОКНА.
     Пробовал `sticky` — не годится: липкий элемент держится только
     пока виден его контейнер, а контейнер кончается сразу за самими
     кнопками. Стоило долистать до конца формы, и полоса уезжала
     вместе с ней — «кнопки двигаются в середину». Возвращаю `fixed`,
     но теперь он знает про свою колонку: боковое меню панели и
     нижние вкладки на телефоне обходятся отступами ниже. */
  .bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
         display: flex; gap: 8px;
         padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
         background: var(--bg2); box-shadow: 0 -1px 8px var(--shadow);
         border-top: 1px solid var(--border);
         /* Свой слой — чтобы не отставать от инерционной прокрутки,
            ровно как у нижних вкладок. */
         transform: translateZ(0); }

  /* Во вкладке панели: не залезать под боковое меню (220px) — оно
     постоянное и полосу через него тянуть незачем. */
  .main .bar { left: 220px; }

  @media (max-width: 768px) {
    /* На телефоне бокового меню нет, зато снизу свои вкладки: встаём
       НАД ними, иначе «Готово» оказывается под «Меню». */
    .main .bar { left: 0; bottom: calc(58px + env(safe-area-inset-bottom)); }
  }

  /* Место под закреплённой полосой, чтобы последнее поле формы
     не пряталось под кнопками. */
  #docRoot { padding-bottom: 84px; }
  /* Свой `display` перебивает браузерное [hidden] { display: none },
     и без этой строки нижняя панель видна ВСЕГДА: кнопки «← Записи»
     и «Готово» висели поверх списка записей, будто плавают при
     прокрутке. Та же ловушка уже описана в app.css у `.home-grid`. */
  .bar[hidden] { display: none; }
  .bar .btn { flex: 1; }
  .saved { font-size: 12px; color: var(--muted); align-self: center; }

/* Продажи: полоса загрузки. Отчёт собирается этапами (записи, оплаты,
   склад, списания), и пустая таблица на двадцать секунд выглядит как
   зависание — полоса показывает, что именно сейчас читается. */
.gs-prog { margin: 0 0 12px; }
.gs-prog-t { display: flex; justify-content: space-between; gap: 12px;
             font-size: 13px; color: var(--muted); margin-bottom: 6px; }
.gs-prog-bar { height: 6px; border-radius: 3px; background: var(--border); overflow: hidden; }
.gs-prog-bar > i { display: block; height: 100%; width: 0; background: var(--accent);
                   border-radius: inherit; transition: width .5s ease; }
/* Ход ещё не известен (запрос ушёл, сервер не ответил) — бегущий
   отрезок вместо застывшего нуля: «0 %» выглядит как зависание. */
.gs-prog-bar.indet > i { width: 35%; animation: gs-indet 1.1s ease-in-out infinite; }
@keyframes gs-indet { from { transform: translateX(-100%); } to { transform: translateX(290%); } }
@media (prefers-reduced-motion: reduce) {
  .gs-prog-bar.indet > i { animation: none; width: 100%; opacity: .5; }
}
/* Планирование дня: пока грузится другой день, старые цифры не стираем,
   а приглушаем — видно, что идёт смена, и экран не прыгает. */
#dpStats, #dpPane { transition: opacity .2s ease; }
#dpRoot.dp-busy :is(#dpStats, #dpPane) { opacity: .45; }
/* Плашка дня: название крупно, под ним «План | Факт» колонками.
   Нажимается — раскрывает список, поэтому курсор, фокус и ▾. */
.dp-tile { cursor: pointer; min-width: 190px; display: flex; flex-direction: column; gap: 6px; }
.dp-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.dp-tile-t { display: flex; justify-content: space-between; gap: 8px;
             font-size: 14px; font-weight: 650; line-height: 1.25; }
.dp-tile:hover .dp-tile-t { color: var(--accent); }
.dp-chev { color: var(--muted); transition: transform .2s ease; }
.dp-tile.sel .dp-chev { transform: rotate(180deg); color: var(--accent); }
.dp-tile.sel { box-shadow: inset 0 0 0 2px var(--accent); }
.dp-tile-h { font-size: 12px; color: var(--muted); margin-top: -4px; }
.dp-pf { display: flex; margin-top: auto; }
.dp-pf-c { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; padding-right: 10px; }
.dp-pf-c + .dp-pf-c { padding: 0 0 0 10px; border-left: 1px solid var(--border); }
.dp-k { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.dp-pf .num { font-size: 20px; font-weight: 700; white-space: nowrap; }
.dp-tile.sel .num:not(.dp-fact) { color: inherit; }
.dp-pf .num.dp-fact { color: var(--accent); }
@media (prefers-reduced-motion: reduce) { .dp-chev { transition: none; } }
/* «?» у плашки: как считается показатель. Всплывает под плашкой,
   у правого края экрана прижимается вправо (placeHelp в dayplan.js). */
.dp-tile { position: relative; }
.dp-tile-a { display: inline-flex; align-items: center; gap: 6px; flex: none; }
.dp-help {
  width: 22px; height: 22px; padding: 0; border-radius: 50%;
  border: 1px solid var(--border); background: transparent; color: var(--muted);
  font-family: inherit; font-size: 12px; font-weight: 700; line-height: 1;
  display: inline-grid; place-items: center; cursor: help;
  transition: color .15s ease, border-color .15s ease;
}
.dp-help:hover, .dp-help[aria-expanded="true"] { color: var(--accent); border-color: var(--accent); }
.dp-help:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.dp-help-pop {
  position: absolute; z-index: 30; top: calc(100% + 6px); left: 0;
  width: max(100%, 280px); max-width: calc(100vw - 32px);
  padding: 10px 12px; border-radius: var(--radius);
  background: var(--bg2); border: 1px solid var(--border);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .16);
  font-size: 13px; font-weight: 400; line-height: 1.45; color: inherit;
  text-transform: none; letter-spacing: normal; cursor: auto;
  animation: dp-pop .14s ease-out;
}
.dp-help-pop.dp-help-right { left: auto; right: 0; }
/* У плашек blur (backdrop-filter) — каждая сама себе слой, и z-index
   подсказки внутри неё не выше соседних плашек и списка под ними:
   подсказка уходила под них. Поднимаем саму плашку с открытой «?». */
.dp-tile.dp-help-on { z-index: 40; }
/* Сводная таблица план | факт в раскрытии плашки */
/* :nth-child(n) — чтобы перебить зебру `.tbl tbody tr:nth-child(even) td` */
.tbl.dp-cmp tbody tr.dp-cmp-p:nth-child(n) td { background: color-mix(in srgb, var(--danger, #d33) 9%, transparent); }
.tbl.dp-cmp tbody tr.dp-cmp-f:nth-child(n) td { background: color-mix(in srgb, var(--accent) 12%, transparent); }
@media (max-width: 768px) {
  .tbl.dp-cmp tbody tr.dp-cmp-p:nth-child(n) { background: color-mix(in srgb, var(--danger, #d33) 9%, transparent); }
  .tbl.dp-cmp tbody tr.dp-cmp-f:nth-child(n) { background: color-mix(in srgb, var(--accent) 12%, transparent); }
  .tbl.dp-cmp tbody tr[class]:nth-child(n) td { background: none; }
}
.dp-cmp .dp-fact { color: var(--accent); }
.dp-cmp-note { font-size: 12px; color: var(--muted); white-space: nowrap; }
.dp-cmp tr.dp-cmp-p .dp-cmp-note { color: var(--danger, #d33); }
@keyframes dp-pop { from { opacity: 0; transform: translateY(-4px); } }
@media (prefers-reduced-motion: reduce) { .dp-help-pop { animation: none; } .dp-help { transition: none; } }


/* Сортировка столбцов в «Марже»: заголовок — кнопка, а не надпись.
   Именно кнопка, а не div с onclick: её видно с клавиатуры и читает
   озвучка, а выглядит она всё равно как заголовок. */
.mg-sort {
  background: none; border: 0; padding: 0; font: inherit; color: inherit;
  cursor: pointer; white-space: nowrap;
}
.mg-sort:hover { text-decoration: underline; }
.mg-sort.on { color: var(--accent); }
