/* ============================================================
   staff-ui.css — ЕДИНАЯ дизайн-система разделов /admin/* и /staff/*,
   классы su-*. Второго CSS-слоя нет: admin.css удалён на шаге 1
   редизайна, его живые части переехали сюда.

   Тема выбирается атрибутом [data-staff-theme] на <body> (см.
   Repository::VALID_STAFF_THEMES / staffThemeContext()) и стоит на
   КАЖДОЙ странице обоих разделов — без него ни одно правило файла не
   применится.

   ДВА ПРАВИЛА, на которых всё держится:

   1. Классы ссылаются ТОЛЬКО на переменные --su-*, никогда на цвет,
      кегль, отступ или радиус напрямую. Хардкод в классе = ошибка,
      значение выносится в :root.
   2. :root — ИДЕНТИЧНОСТЬ ПРОДУКТА (типографика, шкала отступов,
      радиусы, тени, размеры тач-целей), блоки [data-staff-theme] —
      ТОЛЬКО ПАЛИТРА. Тема меняет цвет, но не геометрию: одинаковые
      элементы обязаны выглядеть одинаково на всех экранах, иначе
      человек за чужим рабочим местом теряется.
   ============================================================ */

/* ============ шрифт — самохостинг, без внешних запросов ============
   Golos Text (Paratype, SIL OFL 1.1) — спроектирован под кириллицу.
   Одна гарнитура на весь интерфейс: контраст держится ВЕСОМ, а не
   сменой семейства. Раньше здесь жили пять гарнитур (22 файла) —
   по одной на тему; теперь тема меняет только палитру, и они не нужны.
   Inter остаётся фолбэком: он уже был в проекте и покрывает кириллицу.
   Файлы собраны скриптом docs/redesign/build-fonts.py. */
@font-face { font-family: "Golos Text"; src: url("/assets/fonts/golos-text-400.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Golos Text"; src: url("/assets/fonts/golos-text-500.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "Golos Text"; src: url("/assets/fonts/golos-text-600.woff2") format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "Golos Text"; src: url("/assets/fonts/golos-text-700.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }

@font-face { font-family: "Inter"; src: url("/assets/fonts/inter-400.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Inter"; src: url("/assets/fonts/inter-500.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "Inter"; src: url("/assets/fonts/inter-600.woff2") format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "Inter"; src: url("/assets/fonts/inter-700.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }

/* ============================================================
   :root — ИДЕНТИЧНОСТЬ ПРОДУКТА. Не тема.
   Всё, что здесь, одинаково во всех шести темах.
   ============================================================ */
:root {
  --su-icon-size-lg: 25px;
  /* ── типографика ── */
  --su-font-body: "Golos Text", "Inter", system-ui, -apple-system, sans-serif;
  --su-font-heading: var(--su-font-body);
  --su-font-heading-weight: 600;
  /* Цифры той же гарнитурой: у Golos Text табличные цифры включаются
     font-variant-numeric, отдельное семейство для чисел не нужно. */
  --su-font-num: var(--su-font-body);

  --su-fs-caption: 13px;   /* минимум, ниже которого текста в системе нет */
  --su-fs-sm:      14px;
  --su-fs-base:    16px;
  --su-fs-lg:      18px;
  --su-fs-xl:      22px;
  --su-fs-2xl:     28px;

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

  /* ── отступы: 4/8/12/16/24/32/48 ──
     Прежняя шкала (5/8/13/18/25/32/50) была почти той же, но с дробными
     шагами — суммы отступов не сходились в круглые числа, и элементы
     не выравнивались друг с другом по сетке. */
  --su-space-1: 4px;  --su-space-2: 8px;  --su-space-3: 12px; --su-space-4: 16px;
  --su-space-5: 24px; --su-space-6: 32px; --su-space-8: 48px;
  /* Отступ до краёв экрана на мобильном — отдельно от --su-space-*, чтобы
     не сжимать внутренние gap карточек и композера. */
  --su-edge-pad: 12px;

  /* ── радиусы ── */
  --su-radius-sm: 8px;     /* инпуты, мелкие кнопки */
  --su-radius-md: 10px;    /* кнопки, поля */
  --su-radius-lg: 14px;    /* карточки */
  /* ── бренд ──
     ЕДИНСТВЕННЫЕ цвета, которые тема НЕ переопределяет. Логотип — константа
     компании, а не часть оформления: он обязан выглядеть одинаково на кухне,
     на кассе и на лендинге (значения взяты оттуда — --black / --green).
     Тема, перекрасившая марку, делает из одного продукта четырнадцать.
     ⚠️ Появятся тёмные темы — понадобится исключение для --su-brand-text:
     #111110 на тёмном фоне не читается. */
  --su-brand-text: #111110;
  --su-brand-accent: #16a34a;

  --su-radius-pill: 999px; /* бейджи, статусы, вкладки шапки */
  /* Круглые элементы (аватар, иконка-кнопка, точка шага) — отдельно от pill:
     у них равные ширина и высота, и 50% там читается как «окружность», а не
     как «сильно скруглённый прямоугольник». Тема, выпрямляющая углы, обязана
     уметь погасить и их — иначе шапка остаётся круглой при прямоугольном
     остальном экраном (CLAUDE.md 3.7). */
  --su-radius-round: 50%;

  /* ── тени: двухслойные, контакт + рассеивание ──
     Один слой даёт «наклейку», два — ощущение объёма: близкая жёсткая
     тень прижимает элемент к поверхности, дальняя мягкая отделяет от неё. */
  --su-shadow-sm: 0 1px 2px rgba(16,24,40,.05), 0 1px 3px rgba(16,24,40,.04);
  --su-shadow-md: 0 1px 2px rgba(16,24,40,.05), 0 4px 12px rgba(16,24,40,.07);
  --su-shadow-lg: 0 2px 4px rgba(16,24,40,.05), 0 12px 32px rgba(16,24,40,.12);
  --su-ring: 0 0 0 3px var(--su-a-200);

  /* ── тач-цели ──
     44px — минимум, ниже которого палец на планшете промахивается.
     36px — для плотных списков, где элементов много и они не основные. */
  --su-hit-min: 44px;
  --su-hit-sm:  36px;

  --su-nav-h: 56px;     /* фактическая min-height .su-nav-inner — держать в синхроне */
  --su-tabbar-h: 64px;  /* .su-tabbar берёт высоту отсюда, переменная первична */

  /* ── статусы: ОДИНАКОВЫ во всех светлых темах ──
     Цвет здесь несёт смысл, а не оформление: зелёный = свободен,
     янтарный = готовится, розовый = счёт, красный = отмена. Если тема
     будет их перекрашивать, официант на чужом планшете прочтёт статус
     неверно. Тёмная тема переопределяет только ПОДЛОЖКИ (-bg): на
     тёмном фоне светлая заливка слепит. */
  /* Значения здесь — ФОЛБЭК. Боевые приезжают из status-colors.css, который
     генерирует страница «Статусы заказа» суперадминки (см. StatusColors): файл
     подключается ПОСЛЕ этого и перекрывает :root. Без файла интерфейс
     остаётся на этих цветах, а не без цветов вовсе. */
  /* Конвейер заказа — у КАЖДОГО статуса своя пара. Группировки нет: «принят»
     и «готовится» — разные стадии, и на экране они обязаны различаться. */
  --su-new:       #c45a0a; --su-new-bg:       #fff1e6;
  --su-accepted:  #2563eb; --su-accepted-bg:  #eff6ff;
  --su-preparing: #7e22ce; --su-preparing-bg: #f3e8ff;
  --su-ready:     #15803d; --su-ready-bg:     #dcfce7;
  --su-served:    #7c8580; --su-served-bg:    #f2f3f2;
  --su-completed: #667085; --su-completed-bg: #f2f4f7;
  --su-cancelled: #b42318; --su-cancelled-bg: #fdecea;

  /* Оплата — ОТДЕЛЬНАЯ ось от конвейера (заказ бывает оплачен на любой
     стадии, см. CLAUDE.md 4.2), поэтому свои переменные, а не переиспользование
     статусных. Только цвет текста: бейдж без подложки. */
  --su-paid:   #15803d;
  --su-unpaid: #c45a0a;

  /* Состояния СТОЛА и общая семантика интерфейса — отдельно от конвейера.
     --su-free/--su-cancel используются шире статусов заказа: свободный стол,
     кнопка удаления, ошибка. Переименовывать их в статусные значило бы
     смешать две разные оси. */
  --su-free:     #1a7f43; --su-free-bg:     #e6f4ea;
  --su-cooking:  #9a6400; --su-cooking-bg:  #fdf2d9;
  --su-bill:     #b03060; --su-bill-bg:     #fdeaf1;
  --su-cleaning: #667085; --su-cleaning-bg: #f2f4f7;
  --su-cancel:   #b42318; --su-cancel-bg:   #fdecea;
}

/* ============================================================
   ТЕМЫ — только палитра. Шрифт, радиус, отступы, тени: в :root выше.

   ⚠️ САМИ БЛОКИ ПАЛИТР ПЕРЕЕХАЛИ в public/staff/assets/themes.css
   (миграция 063). Он генерируется со страницы «Темы» суперадминки и лежит
   в .gitignore: правится на проде, а этот файл приезжает туда через
   git pull — держи он блоки тем, каждый пулл ловил бы конфликт.

   Здесь остаётся ВСЁ ОСТАЛЬНОЕ: :root (идентичность продукта) и классы
   su-*. Новую переменную, общую для ВСЕХ тем, объявлять по-прежнему
   в :root здесь, а не в themes.css.

   Идентификаторы тем хранятся в БД (cafes.staff_theme, staff.theme) —
   переименование темы осиротит сохранённые значения. Удаление через
   форму это учитывает: переводит пользователей на выбранную замену.

   Скелет у всех тем одинаковый:
     --su-bg / --su-surface   подложка и карточка
     --su-text / -muted       текст
     --su-n-*                 нейтральная шкала (границы, разделители)
     --su-a-*                 акцент (ссылки, фокус, выделение)
     --su-b-*                 вторичный акцент (счёт, бейджи)
     --su-fill-primary        заливка основной кнопки
     --su-on-primary          текст на любой цветной заливке

   КАРТОЧКА СВЕТЛЕЕ ФОНА. Было наоборот (--su-bg #f3f2f2 светлее
   --su-surface #eae9e9) — серая карточка на более светлой подложке
   читается как выцветший интерфейс десятилетней давности.

   ОСНОВНАЯ КНОПКА ГРАФИТОВАЯ, не цветная: самое яркое пятно экрана
   должно быть статусом заказа, а не кнопкой «Сохранить».
   ============================================================ */

/* ============ reset / base ============ */
[data-staff-theme] * , [data-staff-theme] *::before, [data-staff-theme] *::after { box-sizing: border-box; }
[data-staff-theme] {
  background: var(--su-bg);
  color: var(--su-text);
  font-family: var(--su-font-body);
}
[data-staff-theme] h1, [data-staff-theme] h2, [data-staff-theme] h3, [data-staff-theme] h4 {
  font-family: var(--su-font-heading); font-weight: var(--su-font-heading-weight); margin: 0;
}
[data-staff-theme] a { color: var(--su-a-700); text-decoration: none; }
[data-staff-theme] a:hover { color: var(--su-a-600); }
/* Подчёркивание — только у ссылок в потоке текста (абзацы-пояснения, подписи
   под полями). Всё остальное (карточки, плитки, строки хаба, кнопки) — целые
   интерактивные блоки, у них своя реакция на hover: фон и тень. */
[data-staff-theme] .su-hint a:hover,
[data-staff-theme] .su-card-meta a:hover,
[data-staff-theme] p a:hover,
[data-staff-theme] .su-notice-text a:hover { text-decoration: underline; }
[data-staff-theme] svg { display: block; }

.su-app { display: flex; flex-direction: column; min-height: 100vh; }
.su-main { flex: 1; padding: var(--su-edge-pad); padding-bottom: calc(var(--su-tabbar-h) + var(--su-edge-pad)); max-width: 1180px; width: 100%; margin: 0 auto; }
/* Узкая колонка: экраны, где содержимое читается списком в одну колонку
   (проверка заказа перед отправкой) — на широком мониторе строка во всю
   ширину рвёт связь между блюдом и его ценой справа. */
.su-main--narrow { max-width: 520px; }
@media (min-width: 860px) { .su-main { padding: var(--su-space-6); padding-bottom: var(--su-space-6); } }

/* ============ верхняя навигация ============ */
/* .su-nav — фон/sticky на всю ширину экрана; .su-nav-inner внутри — та же
   max-width колонка, что у .su-main, чтобы на широких экранах шапка не
   визуально "отрывалась" от контента под ней разной шириной. */
.su-nav {
  background: var(--su-surface); box-shadow: var(--su-shadow-sm);
  position: sticky; top: 0; z-index: 20;
}
.su-nav-inner {
  display: flex; align-items: center; gap: var(--su-space-2);
  min-height: 52px; padding: 6px var(--su-space-2);
  flex-wrap: nowrap; max-width: 1180px; width: 100%; margin: 0 auto; box-sizing: border-box;
}
@media (min-width: 860px) { .su-nav-inner { padding: 6px var(--su-space-4); } }
/* .su-nav-brand — двухстрочный блок (бренд + опционально номер стола под ним,
   см. $contextLabel в _topbar.php), обе строки уменьшены так, чтобы суммарная
   высота укладывалась в ту же .su-nav-inner min-height, что и раньше при одной
   строке — шапка не растёт, когда появляется вторая строка. */
/* max-width фиксированный (не auto/fit-content) — иначе длинное название стола
   (вторая строка) само раздуло бы ширину .su-nav-brand и вытолкнуло вкладки/
   аватар вбок; при фиксированной ширине обе строки обрезаются НЕЗАВИСИМО
   внутри неё, а не подстраивают контейнер под самую длинную. */
.su-nav-brand { display: flex; flex-direction: column; justify-content: center; gap: 0; flex: none; max-width: 96px; line-height: 1.15; }
/* Бренд — ФИКСИРОВАННЫЕ цвета, вне палитры темы (--su-brand-* объявлены в
   :root и в блоках [data-staff-theme] не переопределяются). Марка одинакова
   на любом рабочем месте и совпадает с лендингом; красить её акцентом темы
   значило бы, что логотип компании выглядит по-разному у кухни и у кассы.
   Ссылка на главную — display:block, чтобы кликалась вся строка. */
/* Селектор с [data-staff-theme]: бренд — ссылка, а общее правило
   «[data-staff-theme] a» имеет специфичность (0,1,1) и перебивало одиночный
   класс (0,1,0) — «cafe» красился акцентом темы вместо фирменного чёрного. */
[data-staff-theme] .su-nav-brand-name {
  display: block; font-family: var(--su-font-body); font-weight: 800;
  font-size: var(--su-fs-base); letter-spacing: -.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--su-brand-text); text-decoration: none;
}
[data-staff-theme] .su-nav-brand-name span { color: var(--su-brand-accent); }
[data-staff-theme] .su-nav-brand-name:hover { color: var(--su-brand-text); text-decoration: none; opacity: .8; }
@media (min-width: 640px) { .su-nav-brand { max-width: 160px; } .su-nav-brand-name { font-size: var(--su-fs-lg); } }
/* Номер/название стола — вторая строка бренда, обрезается той же max-width
   родителя (не шире бренда над ней). */
.su-nav-context {
  font-family: var(--su-font-body); font-weight: 600; font-size: var(--su-fs-caption);
  color: var(--su-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  display: block;
}
@media (min-width: 640px) { .su-nav-context { font-size: var(--su-fs-caption); } }
.su-nav-tabs { display: flex; gap: 2px; background: var(--su-n-200); border-radius: var(--su-radius-pill); padding: 3px; min-width: 0; }
.su-nav-tab {
  padding: 6px 8px; border-radius: var(--su-radius-pill); font-size: var(--su-fs-caption); font-weight: 600;
  color: var(--su-text-muted); white-space: nowrap;
  font-family: var(--su-font-body);
}
@media (min-width: 400px) { .su-nav-tab { padding: 7px 14px; font-size: var(--su-fs-sm); } }
.su-nav-tab.is-active { background: var(--su-a-500); color: var(--su-on-primary); }
.su-nav-tab.is-active:hover { color: var(--su-on-primary); text-decoration: none; }
.su-nav-actions { display: flex; align-items: center; gap: 2px; margin-left: auto; flex: none; }

.su-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: var(--su-radius-round); border: none; background: transparent;
  color: var(--su-text); cursor: pointer; position: relative; flex: none;
}
.su-icon-btn:hover { background: var(--su-n-200); }
.su-icon-btn svg { width: 18px; height: 18px; }
.su-icon-btn--lg svg { width: var(--su-icon-size-lg); height: var(--su-icon-size-lg); }
/* Иконочным действием бывает и ссылка (нав-действия владельца в layout.php), а
   не только <button>: подчёркивание и цвет ссылки из базового правила сделали
   бы её непохожей на соседние кнопки того же ряда. */
a.su-icon-btn, a.su-icon-btn:hover { text-decoration: none; color: var(--su-text); }
a.su-icon-btn.is-active { background: var(--su-a-500); color: var(--su-on-primary); }
.su-notify-badge {
  position: absolute; top: 1px; right: 1px; min-width: 15px; height: 15px; padding: 0 3px;
  border-radius: var(--su-radius-pill); background: var(--su-b-600); color: var(--su-on-primary);
  font-size: var(--su-fs-caption); font-weight: 700; align-items: center; justify-content: center;
  display: none;
}
.su-icon-btn.has-notify .su-notify-badge { display: flex; }

/* Тот же визуал бейджа, что у колокольчика (.su-notify-badge), но inline рядом
   с текстом вкладки, а не абсолютом поверх круглой кнопки. Это "требует
   внимания" (новый заказ/стол ждёт) — отсюда тревожный --su-b-600, оставляем
   как есть для этих двух мест (шапка: Столы/Заказы, колокольчик). */
.su-tab-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; padding: 0 4px; margin-left: 5px;
  border-radius: var(--su-radius-pill); background: var(--su-b-600); color: var(--su-on-primary);
  font-size: var(--su-fs-caption); font-weight: 700; vertical-align: middle;
}
.su-nav-tab.is-active .su-tab-badge { background: var(--su-surface); color: var(--su-b-600); }
/* Нейтральный вариант: «есть активные» против «есть НОВЫЕ» у обычного
   su-tab-badge. Раньше оттенок ставился из JS (na.style.background) —
   постоянный цвет в разметке не нужен, ему место здесь.
   ⚠️ Селектор повторяет .su-nav-tab.is-active: правило активной вкладки
   выше идёт со специфичностью 0,3,0 и перебило бы одиночный класс,
   покрасив бейдж в белый (инлайновый стиль из JS этого не замечал). */
.su-tab-badge--neutral,
.su-nav-tab.is-active .su-tab-badge--neutral { background: var(--su-n-500); }

/* Бейдж-счётчик БЕЗ смысла "внимание" — просто число (позиций в корзине,
   позиций у гостя N). Нейтральная шкала --su-n-*, не пересекается с
   тревожным --su-b-600 у su-tab-badge/su-notify-badge выше. */
.su-badge-info {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: var(--su-radius-pill); background: var(--su-n-700); color: var(--su-n-100);
  font-size: var(--su-fs-caption); font-weight: 700; vertical-align: middle;
}
/* Надстрочный вариант (как степень в "м²") — абсолютом поверх правого
   верхнего угла родителя, а не inline рядом с текстом, чтобы не расширять
   саму пилюлю вкладки. Родитель обязан иметь position:relative. */
.su-badge-info--corner { position: absolute; top: -6px; right: -6px; box-shadow: 0 0 0 2px var(--su-surface); }

.su-avatar {
  width: 32px; height: 32px; border-radius: var(--su-radius-round); color: var(--su-on-primary);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--su-font-heading); font-size: var(--su-fs-caption); font-weight: 600; flex: none;
  border: none; cursor: pointer;
}
.su-avatar--sm { width: 32px; height: 32px; font-size: var(--su-fs-caption); cursor: default; }

/* Цифра персональных уведомлений на аватарке («вам передали заказ»).
   Отдельный класс, а не .su-notify-badge: тот показывается только внутри
   .su-icon-btn.has-notify, а аватарка — не icon-btn, и position: relative
   у неё своего нет (абсолютный бейдж уехал бы к краю экрана).

   Цвет — акцентный --su-b-600, как у остальных «требует внимания»: это ровно
   тот случай, уведомление адресовано лично и ждёт действия. */
.su-avatar { position: relative; }
.su-avatar-badge {
  position: absolute; top: -3px; right: -3px;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: var(--su-radius-pill);
  background: var(--su-b-600); color: var(--su-on-primary);
  font-size: var(--su-fs-caption); font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  /* Обводка цветом шапки: бейдж лежит на цветном круге аватарки, и без
     разделителя цифра сливается с ним на близких оттенках палитры. */
  box-shadow: 0 0 0 2px var(--su-surface);
}

/* Цвет аватарки — КЛАСС по индексу, а не сгенерированный style="background:...".
   Палитра фиксированная (16 цветов, H::avatarColor()), индекс = id %% 16,
   поэтому вариантов ровно столько же, сколько классов: генерировать цвет
   в атрибут на каждый рендер незачем, а инлайновый стиль ещё и режется CSP.

   ⚠️ Порядок цветов обязан совпадать с палитрой в H::avatarColor():
   класс su-avatar--cN = palette[N]. Меняешь там — правь здесь. */
.su-avatar--c0  { background: #d24141; }
.su-avatar--c1  { background: #b65f2b; }
.su-avatar--c2  { background: #8c7221; }
.su-avatar--c3  { background: #707c1d; }
.su-avatar--c4  { background: #4f801e; }
.su-avatar--c5  { background: #2d8820; }
.su-avatar--c6  { background: #20883a; }
.su-avatar--c7  { background: #1f845e; }
.su-avatar--c8  { background: #1e8080; }
.su-avatar--c9  { background: #297cae; }
.su-avatar--c10 { background: #456ee8; }
.su-avatar--c11 { background: #6a5ad8; }
.su-avatar--c12 { background: #9952e0; }
.su-avatar--c13 { background: #bc35d0; }
.su-avatar--c14 { background: #cf30a7; }
.su-avatar--c15 { background: #d13d75; }

/* ============ гамбургер-меню ============ */
.su-hamburger { position: relative; }
.su-hamburger-menu {
  position: absolute; top: calc(100% + 6px); right: 10px; min-width: 290px;
  background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-lg);
  padding: var(--su-space-2); z-index: 50;
}
.su-hamburger-whoami { display: flex; align-items: center; gap: 10px; padding: var(--su-space-2) var(--su-space-2) var(--su-space-3); border-bottom: 1px solid var(--su-n-300); margin-bottom: var(--su-space-2); }
.su-hamburger-whoami-text { display: flex; flex-direction: column; min-width: 0; }
.su-hamburger-whoami-name { font-weight: 700; font-size: var(--su-fs-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.su-hamburger-whoami-meta { font-size: var(--su-fs-caption); color: var(--su-text-muted); }
/* Тариф и режим — ссылки, но подпись мелким кеглем: подчёркивание только по
   наведению, иначе две подчёркнутые строки под email выглядят как ошибка вёрстки. */
.su-hamburger-whoami-link { text-decoration: none; white-space: nowrap; }
.su-hamburger-whoami-link:hover { color: var(--su-text); text-decoration: none; }
.su-hamburger-item {
  display: block; width: 100%; text-align: left; padding: 10px 12px; border-radius: var(--su-radius-md);
  border: none; background: none; color: var(--su-text); font-size: var(--su-fs-sm); font-weight: 500;
  font-family: var(--su-font-body); cursor: pointer; text-decoration: none;
}
.su-hamburger-item:hover { background: var(--su-n-200); text-decoration: none; }
.su-hamburger-item.is-active { color: var(--su-a-700) !important; }
.su-hamburger-item--logout { color: var(--su-cancel) !important; }
.su-hamburger-form { margin: 0; }
/* Превью заказов "требуют внимания" в гамбургере — раньше там была только
   цифра на бейдже вкладки, теперь короткий список (№/стол/статус) кликабельный
   на сам заказ, чтобы не открывать отдельную вкладку ради беглого взгляда. */
.su-hamburger-notify { padding: 0 var(--su-space-2) var(--su-space-2); border-bottom: 1px solid var(--su-n-300); margin-bottom: var(--su-space-2); }
.su-hamburger-notify-title { font-size: var(--su-fs-caption); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--su-text-muted); padding: 0 12px 4px; }
.su-hamburger-notify-item { display: flex; align-items: center; justify-content: space-between; gap: var(--su-space-2); padding: 7px 12px; border-radius: var(--su-radius-md); font-size: var(--su-fs-caption); color: var(--su-text); text-decoration: none; }
.su-hamburger-notify-item:hover { background: var(--su-n-200); text-decoration: none; }
.su-hamburger-notify-status { display: flex; align-items: center; gap: 6px; color: var(--su-text-muted); font-size: var(--su-fs-caption); flex: none; }
.su-hamburger-notify-status .su-tag { font-size: var(--su-fs-caption); padding: 2px 8px; }

/* ============ нижний tabbar ============ */
.su-tabbar { position: fixed; bottom: 0; left: 0; right: 0; height: var(--su-tabbar-h); background: var(--su-surface); box-shadow: 0 -2px 12px rgba(0,0,0,.10); display: flex; z-index: 30; }
.su-tabbar-item { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; color: var(--su-text-muted); font-size: var(--su-fs-caption); font-weight: 500; text-decoration: none; }
.su-tabbar-item:hover { text-decoration: none; }
.su-tabbar-item svg { width: 22px; height: 22px; }
.su-tabbar-item.is-active { color: var(--su-a-600); }
.su-tabbar-item--center { color: var(--su-a-600); }
.su-tabbar-item--center svg { width: 26px; height: 26px; }
body.su-has-tabbar .su-main { padding-bottom: calc(var(--su-tabbar-h) + var(--su-edge-pad)); }

/* ============ segmented control / фильтр ============ */
.su-seg { display: inline-flex; background: var(--su-n-200); border-radius: var(--su-radius-md); padding: 3px; gap: 2px; }
.su-seg-opt { padding: 7px 14px; border-radius: var(--su-radius-sm); font-size: var(--su-fs-caption); font-weight: 500; color: var(--su-text-muted); cursor: pointer; white-space: nowrap; background: none; border: none; font-family: var(--su-font-body); }
.su-seg-opt.is-active { background: var(--su-a-600); color: var(--su-on-primary); box-shadow: var(--su-shadow-sm); }

/* ============ кнопки ============ */
.su-btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--su-space-2);
  /* 44px — минимальная тач-цель: ниже палец на планшете промахивается.
     Задаётся min-height, а не height: кнопка с длинной подписью в две строки
     должна расти, а не обрезать текст. */
  min-height: var(--su-hit-min);
  font-family: var(--su-font-body); font-size: var(--su-fs-sm); font-weight: 500;
  padding: 0 var(--su-space-4); border-radius: var(--su-radius-md);
  border: none; cursor: pointer; text-decoration: none; line-height: var(--su-lh-tight);
}
.su-btn:hover { text-decoration: none; }

/* Фокус с клавиатуры. Его не было вообще: человек, идущий по форме табом,
   не видел, где находится. :focus-visible, а не :focus — по клику мышью
   кольцо не рисуется, только при навигации с клавиатуры. */
.su-btn:focus-visible,
.su-input:focus-visible, .su-textarea:focus-visible, .su-select:focus-visible,
.su-hub-item:focus-visible, .su-tabbar-item:focus-visible, .su-nav-tab:focus-visible,
[data-staff-theme] a:focus-visible, [data-staff-theme] button:focus-visible,
[data-staff-theme] input:focus-visible, [data-staff-theme] select:focus-visible,
[data-staff-theme] textarea:focus-visible {
  outline: none; box-shadow: var(--su-ring);
  /* Кольцо не должно прятаться под соседним элементом в плотном списке. */
  position: relative; z-index: 1;
}
.su-btn svg { width: 17px; height: 17px; flex: none; }
.su-btn-primary, a.su-btn-primary { background: var(--su-fill-primary); color: var(--su-on-primary); }
.su-btn-primary:hover { background: var(--su-fill-primary-hover); color: var(--su-on-primary); }
/* Вторичная кнопка — ПРОЗРАЧНАЯ с рамкой, а не серая заливка.
   Заливка бралась из --su-n-200, а в тёмной теме шкала --su-n-* инвертирована
   (100 = самый светлый), и кнопка получала светлый фон под светлый текст —
   надпись пропадала. Прозрачный фон одинаково верен в обеих. */
.su-btn-secondary { background: transparent; color: var(--su-text); border: 1px solid var(--su-n-300); }
.su-btn-secondary:hover { background: var(--su-n-200); color: var(--su-text); border-color: var(--su-n-400); }
.su-btn-danger { background: var(--su-cancel-bg); color: var(--su-cancel); }
/* Второй акцент (не primary, не серая secondary) — своя цветовая шкала темы
   --su-b-*, уже используется для сплит-чека/счёта, тут для действий-развилок
   вроде "добавить к текущему заказу" рядом с основной кнопкой отправки. */
.su-btn-accent { background: var(--su-b-400); color: var(--su-b-900); }
.su-btn-accent:hover { background: var(--su-b-500); color: var(--su-b-900); }
.su-btn-block { width: 100%; }
/* Квадратная кнопка "+" слева от кнопки смены статуса в единой карточке
   заказа (_order_card.php) — фиксированный размер, не растягивается как
   остальные flex:1 1 auto в .su-order-card-actions. */
.su-btn-square { flex: 0 0 auto !important; width: 44px; height: 44px; padding: 0; font-size: var(--su-fs-xl); }
/* Вертикальный стек из нескольких блочных кнопок-альтернатив (напр. "добавить
   к текущему заказу" / "отправить новым заказом") — отступ между ними, чтобы
   не слипались, без дублирования margin инлайном на каждой кнопке. */
.su-btn-stack > .su-btn + .su-btn { margin-top: var(--su-space-2); }
/* Тот же отступ ПЕРЕД стеком (от блока выше, напр. textarea комментария) —
   без него разрыв виден только между кнопками, а не до них. */
.su-btn-stack--spaced { margin-top: var(--su-space-2); }
.su-btn:disabled { opacity: .45; cursor: not-allowed; }

/* ============ теги / статус-плашки ============ */
.su-tag { display: inline-flex; align-items: center; gap: 5px; font-size: var(--su-fs-caption); font-weight: 600; padding: 4px 10px; border-radius: var(--su-radius-sm); white-space: nowrap; text-decoration: none; }
/* Тег как полноширинная строка статуса (плашка стола: статус слева, время
   справа) — модификатор поверх .su-tag, не inline-override display/gap. */
.su-tag--row { display: flex; width: 100%; justify-content: space-between; gap: 8px; }
.su-tag-new { background: var(--su-new-bg); color: var(--su-new); }
.su-tag-free { background: var(--su-free-bg); color: var(--su-free); }
.su-tag-occupied { background: var(--su-a-100); color: var(--su-a-700); }
.su-tag-cooking { background: var(--su-cooking-bg); color: var(--su-cooking); }
.su-tag-plan {
  border-radius: var(--su-radius-pill);
  transform: translateY(calc(var(--su-space-1) * -1));
  padding: 1px 1px;
}
.su-tag-plan--plus { background: var(--su-preparing-bg); color: var(--su-preparing); }
.su-tag-plan--team { background: var(--su-ready-bg); color: var(--su-ready); }
.su-tag-plan-icon { flex: none; }
.su-tag-bill { background: var(--su-bill-bg); color: var(--su-bill); }
.su-tag-cleaning { background: var(--su-cleaning-bg); color: var(--su-n-700); }
.su-tag-cancelled { background: var(--su-cancel-bg); color: var(--su-cancel); }
.su-tag-outline { background: transparent; border: 1px solid var(--su-n-400); color: var(--su-text-muted); }

/* ============ карточки / KPI ============ */
.su-card { background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm); padding: var(--su-space-4); display: flex; flex-direction: column; gap: var(--su-space-2); }
/* Стопка блоков-секций (страница настроек) — отступ между соседними, не после
   последнего. Смежный селектор вместо margin-bottom на каждой секции.

   .su-hub-list входит в перечисление наравне с .su-card: это тоже блок-секция,
   и без него хаб «Меню / Сотрудники / QR-коды» вплотную прилипал к соседней
   карточке — выглядело как наезд. Добавляя новый тип секции, дописать сюда. */
.su-card + .su-card,
.su-card + .su-hub-list,
.su-hub-list + .su-card,
.su-hub-list + .su-hub-list { margin-top: var(--su-space-3); }
.su-card-kicker { font-size: var(--su-fs-caption); letter-spacing: .05em; text-transform: uppercase; color: var(--su-text-muted); font-weight: 600; }
/* Разделитель между группами позиций разных гостей (split-чек) в списке. */
.su-card-kicker--group { margin-top: 10px; }
/* Иконка "добавить/изменить позиции" в строке kicker'а карточки заказа —
   владелец заказа переходит в композер. Inline рядом с текстом kicker'а
   (см. _order_card.php order_kicker_html()), не отдельный ряд кнопок внизу. */
.su-card-add-link { display: inline-flex; vertical-align: middle; margin-left: 6px; color: var(--su-text-muted); }
.su-card-add-link:hover { color: var(--su-b-600); }
.su-card-add-link svg { width: 16px; height: 16px; display: block; }
.su-card-title { font-family: var(--su-font-heading); font-size: var(--su-fs-lg); font-weight: 600; }
/* Уточнение внутри заголовка карточки — "1 заказ (2 шт)": цифра в скобках
   вторична по отношению к главной, но должна читаться. */
.su-card-title-sub { font-size: var(--su-fs-sm); font-weight: 500; opacity: .85; }
.su-card-meta { display: flex; align-items: center; gap: 6px; font-size: var(--su-fs-caption); color: var(--su-text-muted); }
.su-card-meta svg { width: 15px; height: 15px; }
.su-card-meta--right { justify-content: flex-end; }
/* Пояснительный текст сразу под .su-card-title, с кнопкой/ссылкой ниже. */
.su-card-meta--intro { margin: 6px 0 12px; }
/* Требует .su-card-row--relative у родителя. */
.su-card-meta--centered { position: absolute; left: 50%; transform: translateX(-50%); }
.su-card-row { display: flex; align-items: center; justify-content: space-between; gap: var(--su-space-2); }
/* Позиционирующий контекст для .su-card-meta--centered внутри (см. ниже) —
   плашка стола: номер слева, время строго по центру строки, кнопка + справа. */
.su-card-row--relative { position: relative; }
/* Отступ снизу минимальный: следом идёт шапка с фильтром столов, и оба
   отступа складывались в двойной зазор посреди главной. */
.su-grid-stats { display: flex; gap: var(--su-space-3); flex-wrap: wrap; margin-bottom: var(--su-space-2); }
.su-grid-stats .su-card { flex: 1 1 calc(50% - var(--su-space-3) / 2); min-width: 140px; margin-top: 0; }
.su-card-alert { background: var(--su-b-600); box-shadow: var(--su-shadow-md); text-decoration: none; }
.su-card-alert:hover { background: var(--su-b-700); text-decoration: none; }
.su-card-alert .su-card-kicker { color: rgba(255,255,255,.85); }
.su-card-alert .su-card-title { color: var(--su-on-primary); }

/* "Ожидают: 0" — карточка всегда на месте (не исчезает при 0, чтобы сетка KPI
   не прыгала), просто в спокойном свободном цвете темы вместо тревожного, без
   текста — только крупная иконка по центру (случайная из $okIcons в home.php). */
.su-card-ok { background: var(--su-free-bg); text-decoration: none; align-items: center; justify-content: center; min-height: 64px; }
.su-card-ok-icon { width: 34px; height: 34px; flex: none; color: var(--su-free); animation: su-card-ok-breathe 4.5s ease-in-out infinite; }
@keyframes su-card-ok-breathe {
  0%, 100% { opacity: .6; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.08); }
}

.su-section-head { display: flex; align-items: center; justify-content: space-between; gap: var(--su-space-3); margin: var(--su-space-5) 0 var(--su-space-3); flex-wrap: wrap; }
.su-section-head:first-child { margin-top: 0; }
/* Заголовка в шапке нет (только фильтр) и следом сразу сетка — базовый
   верхний отступ складывался бы с margin-bottom предыдущего блока в двойной
   зазор. Главная сотрудника: KPI-карточки, под ними плитки столов. */
.su-section-head--tight { margin-top: var(--su-space-2); margin-bottom: var(--su-space-2); }
/* Заголовок страницы/раздела (просмотр заказа, проверка заказа, шапка) —
   единый размер вместо повторяющегося inline font-size: var(--su-fs-base) по вьюхам. */
.su-page-title { font-size: var(--su-fs-base); }
.su-page-title--spaced { margin-bottom: var(--su-space-3); }
/* Заголовок + подпись (стол/сотрудник и т.п.) внутри su-section-head — без
   этого браузерные дефолтные margin у <h1>/<p> раздувают расстояние между
   ними до почти двух строчных высот. */
.su-title-group h1, .su-title-group p { margin: 0; }
.su-title-group .su-card-meta { margin-top: 2px; }

/* ============ столы ============ */
.su-tables-grid { display: grid; gap: var(--su-space-3); grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); }
@media (min-width: 768px) { .su-tables-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--su-space-4); } }
.su-table-card {
  background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm);
  padding: var(--su-space-3) var(--su-space-2); display: flex; flex-direction: column; gap: 8px;
  border-top: 3px solid var(--su-n-300); text-decoration: none; color: var(--su-text);
}
.su-table-card:hover { text-decoration: none; color: var(--su-text); box-shadow: var(--su-shadow-md); }
.su-table-card.is-free { border-top-color: var(--su-free); }
.su-table-card.is-occupied { border-top-color: var(--su-a-500); }
.su-table-card.is-cooking { border-top-color: var(--su-cooking); }
.su-table-card.is-bill { border-top-color: var(--su-bill); }
.su-table-card-num { font-family: var(--su-font-heading); font-size: var(--su-fs-xl); font-weight: 700; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.su-card-row > .su-tag { flex-shrink: 0; }
.su-table-card-add { margin-left: auto; width: 26px; height: 26px; border-radius: var(--su-radius-round); display: flex; align-items: center; justify-content: center; background: var(--su-n-200); color: var(--su-text); font-size: var(--su-fs-lg); font-weight: 700; text-decoration: none; }
.su-table-card-orders { display: flex; flex-direction: column; gap: 4px; }
.su-table-card-order-row { display: flex; align-items: center; justify-content: space-between; font-size: var(--su-fs-caption); color: var(--su-text); text-decoration: none; font-variant-numeric: tabular-nums; }
.su-table-card-order-row:hover { background: var(--su-n-100); }
.su-table-card-statuses { display: flex; flex-direction: column; }
.su-table-card-order { display: flex; flex-direction: column; gap: 3px; padding: 6px 0; color: inherit; text-decoration: none; }
.su-table-card-order:hover { opacity: .8; }
.su-table-card-order + .su-table-card-order { border-top: 1px solid var(--su-n-300); }
.su-table-card-order:first-child { padding-top: 0; }
.su-table-card-order:last-child { padding-bottom: 0; }
.su-table-card-order-head { display: flex; align-items: center; justify-content: space-between; font-size: var(--su-fs-caption); color: var(--su-text-muted); }
/* Имя ведущего вместо суммы — краткая подача чужого заказа (нет права
   can_view_others_table_orders, см. CLAUDE.md 2.8). Стоит там же, где сумма,
   поэтому и приглушено так же: главное на строке — номер и статус. */
.su-table-card-order-who { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Чужой заказ не ссылка (<span>) — гасим ховер-подсветку ссылки, иначе строка
   выглядит кликабельной и обещает переход, которого не будет. */
span.su-table-card-order:hover { opacity: 1; }
.su-table-card-statuses .su-tag--row { border-radius: var(--su-radius-md); }
.su-table-card-plus { font-size: var(--su-fs-2xl); font-weight: 800; color: var(--su-free); }
/* Закрепление стола на визит ("Беру стол", table_claims) — строка внизу плитки.
   Форма НЕ вкладывается в <a> самой плитки (браузер рвёт такую вложенность, см.
   CLAUDE.md 9.5) — у плитки с кнопкой ссылкой становится только номер стола. */
.su-table-claim { margin-top: auto; padding-top: 6px; border-top: 1px solid var(--su-n-300); }
.su-table-claim-btn {
  width: 100%; border: 0; border-radius: var(--su-radius-md); padding: 5px 6px;
  font: inherit; font-size: var(--su-fs-caption); font-weight: 600; cursor: pointer;
  background: var(--su-n-200); color: var(--su-text);
}
.su-table-claim-btn:hover { filter: brightness(.96); }
.su-table-claim-btn.is-take { background: var(--su-free-bg); color: var(--su-free); }
.su-table-claim-who { font-size: var(--su-fs-caption); color: var(--su-text-muted); text-align: center; display: block; }
.su-table-claim-who b { color: var(--su-text); font-weight: 600; }

/* ============ карточка заказа + степпер ============ */
/* Сетка карточек заказа (владельческая /admin/orders — много карточек разом,
   не одна колонка как у staff /staff/orders на мобильном) — своя ширина
   тайла, не .su-tables-grid (та рассчитана под квадратные плитки столов). */
.su-orders-grid { display: grid; gap: var(--su-space-3); grid-template-columns: 1fr; }
/* Планшет 768-1180 — ОСНОВНОЙ рабочий размер официанта, а тестировали всё
   вертикально. На нём карточка заказа в одну колонку растягивалась на всю
   ширину: название слева, цена у правого края в метре от него, взгляд их не
   связывает. Две-три колонки по 320px возвращают строке нормальную длину. */
@media (min-width: 768px) {
  .su-orders-grid { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: var(--su-space-4); }
}
/* ============ карточка заказа ============
   Главный компонент продукта: на нём держится всё восприятие.

   СТАТУС — ЦВЕТНОЙ РЕЛЬС СЛЕВА, а не кольцо вокруг карточки. Повар смотрит на
   планшет с полутора метров и боковым зрением: вертикальная цветная полоса
   читается с этого расстояния, тонкая обводка — нет. Плюс рельс не спорит с
   тенью: раньше st-new рисовал `box-shadow: 0 0 0 2px` поверх --su-shadow-sm,
   и на экране жили две конкурирующие механики выделения. */
.su-order-card {
  background: var(--su-surface); border-radius: var(--su-radius-lg);
  box-shadow: var(--su-shadow-sm); padding: var(--su-space-4);
  display: flex; flex-direction: column; gap: var(--su-space-3);
  border-left: 3px solid transparent;
  border-top-left-radius: 0; border-bottom-left-radius: 0;
  transition: box-shadow .15s;
}
.su-order-card:hover { box-shadow: var(--su-shadow-md); }
/* Полоса статуса — тем же цветом, что бейдж этого статуса. Раньше здесь была
   своя раскладка (accepted красился акцентом темы, served — нейтралью), и
   один статус выглядел по-разному в карточке и в бейдже позиции.
   mixed — не настраиваемый статус (его нет в конвейере, см. CLAUDE.md 2.5),
   поэтому остаётся на нейтральной шкале. */
.su-order-card.st-new       { border-left-color: var(--su-new); box-shadow: var(--su-shadow-md); }
.su-order-card.st-accepted  { border-left-color: var(--su-accepted); }
.su-order-card.st-preparing { border-left-color: var(--su-preparing); }
.su-order-card.st-ready     { border-left-color: var(--su-ready); }
.su-order-card.st-served    { border-left-color: var(--su-served); }
.su-order-card.st-completed { border-left-color: var(--su-completed); }
.su-order-card.st-cancelled { border-left-color: var(--su-cancelled); }
.su-order-card.st-mixed     { border-left-color: var(--su-n-500); }

/* Кикер карточки — две строки (см. views/staff/_order_kicker.php).
   Прежние uppercase + letter-spacing на 11.5px убраны: аптейл по-русски на
   таком кегле читается заметно хуже строчных. */
.su-order-kicker {
  /* grid, а не flex-column: кнопка передачи заказа (.su-card-add-link) —
     третий потомок кикера, и в колонке она вставала бы на свою строку под
     временем. Здесь она уходит во вторую колонку первой строки, рядом с
     номером, где ей и место. */
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  column-gap: var(--su-space-2); row-gap: 2px;
  text-transform: none; letter-spacing: normal;
}
.su-order-kicker-main {
  grid-column: 1; grid-row: 1;
  font-size: var(--su-fs-base); font-weight: 500; color: var(--su-text);
  font-variant-numeric: tabular-nums;
}
.su-order-kicker .su-card-add-link { grid-column: 2; grid-row: 1; margin-left: 0; }
/* Номер заказа — ссылка на карточку (только в списках). Выглядит как обычный
   заголовок: подчёркивание в покое превратило бы шапку каждой карточки в
   заметную синюю строку, а переход тут — не главное действие экрана. */
.su-order-kicker-link { color: inherit; text-decoration: none; }
.su-order-kicker-link:hover { text-decoration: underline; }
.su-order-kicker-meta {
  grid-column: 1; grid-row: 2;
  font-size: var(--su-fs-caption); font-weight: 400; color: var(--su-text-muted);
  font-variant-numeric: tabular-nums;
}
.su-stepper { display: flex; align-items: center; gap: 3px; flex-wrap: wrap; }
.su-step { display: flex; align-items: center; gap: 5px; }
.su-step-dot { width: 7px; height: 7px; border-radius: var(--su-radius-round); background: var(--su-n-300); flex: none; }
.su-step.is-done .su-step-dot { background: var(--su-a-500); }
.su-step-label { font-size: var(--su-fs-caption); letter-spacing: .02em; color: var(--su-n-500); white-space: nowrap; }
.su-step.is-done .su-step-label { color: var(--su-text); font-weight: 600; }
.su-step-line { width: 14px; height: 1px; background: var(--su-n-300); }
.su-order-items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
/* Шапка карточки ("стол · №" + время/официант) и первый ряд позиций — связанная
   пара: между ними уже есть padding-top самой строки позиции (8px), и общий gap
   карточки (--su-space-3) давал двойной зазор в 20px, из-за которого список
   отрывался от заголовка. Тот же приём, что .su-section-head--tight на главной:
   гасим лишний шаг у одной конкретной пары, не трогая gap остальных блоков.
   Действует и на SSR, и на JS-рендер — классы общие. */
.su-order-card > .su-card-row + .su-order-items,
.su-order-card > .su-card-row + .su-order-person-label {
  margin-top: calc(var(--su-space-3) * -1 + 2px);
}
.su-order-total { display: flex; align-items: center; justify-content: space-between; font-family: var(--su-font-heading); font-size: var(--su-fs-lg); font-weight: 700; padding-top: var(--su-space-2); border-top: 1px solid var(--su-n-300); font-variant-numeric: tabular-nums; }
/* Скидка стоит НАД "Итого" и мельче — это пояснение к итогу, а не второй итог.
   Отчёркивающую линию оставляем ей (блок начинается со скидки), а у самого
   "Итого" следом убираем, иначе линия разрежет связанную пару пополам. */
.su-order-total--discount { font-size: var(--su-fs-sm); font-weight: 600; color: var(--su-bill); }
.su-order-total--discount + .su-order-total { border-top: none; padding-top: 0; }
/* Переплата под итогом — тем же кеглем, но цветом отмены: кассир видит долг
   гостю прямо в списке заказов, не заходя в кассу. */
.su-order-total--overpaid { border-top: none; padding-top: 0; font-size: var(--su-fs-sm); font-weight: 600; color: var(--su-cancel); }

/* ============ строка позиции с per-item статусом (кухня/бар/касса/официант) ============ */
/* B2B-строка позиции, ТРИ строки внутри (редизайн 2026-08-02 — частичная оплата
   вперемешку со статусами "гуляла" на разной ширине контента): (1) название +
   кол-во крупнее + цена справа; (2) статус конвейера слева, статус оплаты
   справа (justify-content:space-between — оказывается под ценой строки 1, тот
   же правый край); (3) крестик-отмена ИЛИ бейдж "Просят отменить" слева
   (взаимоисключающие — одно вместо другого, не оба сразу), кнопка перехода
   статуса справа, оба вместе через space-between. Не "по центру" пустой
   серединой — text-align:left/min-width:0 обязательны, иначе длинное название
   при переносе строки на мобильном визуально "гуляет" по центру. */
.su-item-row { display: flex; flex-direction: column; gap: 4px; padding: 8px 0; border-bottom: 1px solid var(--su-n-200); }
.su-item-row:last-child { border-bottom: none; }
.su-item-row.su-item-foreign { /* opacity: .55; */ }
.su-item-row.su-item-cancelled { opacity: .45; text-decoration: line-through; }
.su-item-main { display: flex; align-items: center; gap: 8px; text-align: left; }
.su-item-name { flex: 1 1 auto; min-width: 0; font-size: var(--su-fs-sm); text-align: left; }
.su-item-qty { font-size: var(--su-fs-base); font-weight: 700; }
.su-item-note { font-size: var(--su-fs-caption); color: var(--su-text-muted); font-style: italic; }
.su-item-price { flex: 0 0 auto; color: var(--su-text-muted); white-space: nowrap; font-size: var(--su-fs-caption); font-variant-numeric: tabular-nums; }
/* Ряд статуса: крестик отмены (или «просят отменить») слева, следом бейдж
   статуса, признак оплаты прижат к правому краю. justify-content больше не
   space-between: с тремя элементами он развёл бы их по третям, оторвав крестик
   от статуса, к которому тот относится. */
.su-item-status-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.su-item-status-row .su-pay-badge { margin-left: auto; }
.su-item-status-badge { font-size: var(--su-fs-caption); font-weight: 700; padding: 2px 8px; border-radius: var(--su-radius-pill); background: var(--su-n-200); color: var(--su-text-muted); text-transform: uppercase; letter-spacing: .02em; white-space: nowrap; }
/* У КАЖДОГО статуса своя пара переменных. Раньше одно правило красило три
   статуса сразу (accepted/preparing/ready), и «принят» было не отличить от
   «готовится» — а это разные стадии для того, кто смотрит на экран.
   Значения приходят из status-colors.css (страница «Статусы заказа» суперадминки). */
.su-item-status-badge.st-new       { background: var(--su-new-bg);       color: var(--su-new); }
.su-item-status-badge.st-accepted  { background: var(--su-accepted-bg);  color: var(--su-accepted); }
.su-item-status-badge.st-preparing { background: var(--su-preparing-bg); color: var(--su-preparing); }
.su-item-status-badge.st-ready     { background: var(--su-ready-bg);     color: var(--su-ready); }
.su-item-status-badge.st-served    { background: var(--su-served-bg);    color: var(--su-served); }
.su-item-status-badge.st-completed { background: var(--su-completed-bg); color: var(--su-completed); }
.su-item-status-badge.st-cancelled { background: var(--su-cancelled-bg); color: var(--su-cancelled); }
.su-item-status-time { font-weight: 500; text-transform: none; letter-spacing: normal; opacity: .75; }
.su-item-cancel-requested { font-size: var(--su-fs-caption); font-weight: 700; color: var(--su-cancel); }
/* Компактная кнопка — для плотных списков, где кнопок много и они не
   основное действие. 36px, а не прежние ~26px (padding 4px 12px): для пальца
   на планшете это было мимо. */
.su-btn-small { flex: 0 0 auto; min-height: var(--su-hit-sm); padding: 0 var(--su-space-3); font-size: var(--su-fs-caption); border-radius: var(--su-radius-sm); }
/* Строка действий: кнопки решения по отмене слева, кнопка перехода справа.
   Крестик и бейдж "просят отменить" отсюда переехали в ряд статуса — отмена
   относится к состоянию позиции, а не к продвижению по конвейеру. */
.su-item-actions-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.su-item-actions-row .su-item-status-form,
.su-item-actions-row .su-btn-small:last-child { margin-left: auto; }
/* Пара "Подтвердить"/"Отклонить" одной формой. Инлайн-стилей в шаблонах нет
   (TASK-redesign.md), поэтому раскладка — здесь. */
.su-item-resolve-form { display: inline-flex; gap: 4px; }
/* Кнопка "нет в наличии" на позиции — компактная иконка-крестик. */
.su-item-out-btn {
  flex: 0 0 auto; width: 26px; height: 26px; padding: 0; border-radius: var(--su-radius-round);
  border: 1px solid var(--su-n-300); background: var(--su-surface); color: var(--su-text-muted);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.su-item-out-btn:hover { background: var(--su-cancel-bg); color: var(--su-cancel); border-color: var(--su-cancel-bg); }
.su-item-out-btn svg { width: 14px; height: 14px; }
/* Оплата — своя ось, не конвейер: заказ бывает оплачен на любой стадии.
   Цвета настраиваются там же, где статусы (--su-paid / --su-unpaid).
   ⚠️ Модификатор --pending ОБЯЗАН идти после базового правила: раньше он
   стоял на 20 строк выше, и при равной специфичности зелёный цвет базового
   затирал серый — «оплачено» и «не оплачено» выглядели одинаково. */
.su-pay-badge { font-size: var(--su-fs-caption); font-weight: 700; color: var(--su-paid); }
.su-pay-badge--pending { color: var(--su-unpaid); }
.su-pay-badge--refund { color: var(--su-cancel); }
.su-payment-badges { display: inline-flex; align-items: center; gap: var(--su-space-2); margin-left: var(--su-space-2); }

/* ---- шторка оплаты в карточке заказа (.js-pay-open -> #paySheet{id}) ----
   Раскрывается под рядом кнопок: сумма, состав (свёрнут) и ряд способов.
   Тап по способу = платёж, поэтому кнопки способов крупные и разнесены —
   промах здесь стоит отмены платежа. */
/* ============ выбор способа оплаты ============
   Живёт в МОДАЛКЕ (.su-modal--pay), не выпадающей шторкой в карточке: список
   заказов длинный, шторка раздвигала карточку и уводила способы за пределы
   экрана на телефоне. Класс .su-pay-sheet остался у скрытого div в разметке
   карточки — он больше ничего не показывает, но на нём висит id, по которому
   JS раньше искал шторку; удаляется вместе с разметкой отдельной правкой. */
.su-modal--pay { max-width: 380px; text-align: left; padding: var(--su-space-4); }
.su-modal-close {
  flex: none; margin-left: var(--su-space-2); width: 32px; height: 32px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; border-radius: var(--su-radius-sm);
  color: var(--su-text-muted); cursor: pointer;
}
.su-modal-close:hover { background: var(--su-n-200); color: var(--su-text); }
.su-pay-sheet-loading { font-size: var(--su-fs-caption); color: var(--su-text-muted); }
.su-pay-sheet-head { display: flex; align-items: center; justify-content: space-between; gap: var(--su-space-2); margin-bottom: var(--su-space-3); }
.su-pay-sheet-sum { font-family: var(--su-font-heading); font-size: var(--su-fs-xl); font-weight: 700; font-variant-numeric: tabular-nums; margin-left: auto; }
.su-pay-sheet-items { margin-bottom: var(--su-space-3); font-size: var(--su-fs-caption); color: var(--su-text-muted); }
.su-pay-sheet-items > summary { cursor: pointer; }
.su-pay-sheet-items ul { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 3px; }
.su-pay-sheet-items li { display: flex; justify-content: space-between; gap: 8px; }
.su-pay-sheet-methods { display: flex; flex-wrap: wrap; gap: var(--su-space-2); }
.su-pay-sheet-methods > .su-btn { flex: 1 1 120px; min-height: var(--su-hit-min); }
.su-pay-sheet-link { display: block; margin-top: var(--su-space-2); font-size: var(--su-fs-caption); color: var(--su-text-muted); }

/* ---- модалка результата операции (оплата прошла) ----
   Кассиру нужно подтверждение, что деньги прошли: погасшая кнопка читается
   как "ничего не произошло". Кнопка одна — куда она ведёт, решает сервер
   (order_closed/can_close_now, см. order-card-actions.js). */
.su-modal-overlay { position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center; padding: 16px; background: rgba(0,0,0,.45); }
.su-modal { width: 100%; max-width: 320px; padding: 24px 20px; border-radius: var(--su-radius-lg); background: var(--su-surface); text-align: center; box-shadow: 0 12px 40px rgba(0,0,0,.25); }
.su-modal-icon { width: 56px; height: 56px; margin: 0 auto 12px; border-radius: var(--su-radius-round); display: flex; align-items: center; justify-content: center; background: var(--su-free-bg); color: var(--su-free); }
.su-modal-icon svg { width: 30px; height: 30px; }
.su-modal-title { font-family: var(--su-font-heading); font-size: var(--su-fs-lg); font-weight: 700; margin: 0 0 4px; }
.su-modal-sub { font-size: var(--su-fs-sm); color: var(--su-text-muted); margin: 0 0 16px; }
.su-modal-hint { font-size: var(--su-fs-caption); color: var(--su-text-muted); margin: -8px 0 16px; }
/* Заголовок группы позиций конкретного гостя (split-чек) и её подытог. */
.su-order-person-label { font-size: var(--su-fs-caption); font-weight: 700; color: var(--su-text-muted); margin: 8px 0 2px; }
.su-order-person-total { text-align: right; font-size: var(--su-fs-caption); color: var(--su-text-muted); margin-bottom: 4px; }
.su-order-card-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.su-order-card-actions > * { flex: 1 1 auto; }
/* Возврат замыкает строку действий справа и остаётся там, когда кнопки оплаты
   уже нет: слева сохраняется квадратная кнопка изменения позиций. */
.su-order-refund-link { margin-left: auto; }
/* Кнопка "Продвинуть все" — двигает разом все видимые позиции своей станции
   на один шаг вперёд, поверх .su-order-items, отдельно от одиночных кнопок
   на каждой позиции (те остаются для точечного контроля). */
.su-advance-all-btn { margin-bottom: 2px; }

/* ============ композер меню ============ */
/* min-width: 0 на треках грида — без него узкая колонка растягивается по
   самому широкому непереносимому потомку (длинное название блюда/строка
   корзины) и раздвигает страницу шире экрана на мобильном. */
.su-composer { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--su-space-4); min-width: 0; margin: 0; }
@media (min-width: 900px) { .su-composer { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); align-items: start; } }

/* Панели "Гость N" / разделы меню — единый склеенный модуль, не два независимых
   элемента: .su-composer-panels оборачивает обе и целиком становится sticky
   ОДИН РАЗ, поэтому:
   - между панелями физически 0 зазора (одна над другой внутри одного блока,
     а не два разных sticky-элемента, которые могли бы разъехаться по top);
   - фон непрозрачный на всём блоке — при закреплении под ним никогда не
     "просвечивает" текст списка блюд, прокручивающийся снизу;
   - top всегда var(--su-nav-h) — сразу под шапкой, без вычисления суммарной
     высоты панелей друг под другом.
   Блок лежит СНАРУЖИ .su-main (см. waiter_composer.php) — сразу после шапки,
   без padding-предков, поэтому позиция до и после прилипания совпадает 1-в-1.
   .su-composer-panels — фон+sticky на всю ширину (как .su-nav), реальный
   горизонтальный отступ и max-width — на вложенном .su-composer-panels-inner
   (тот же паттерн, что .su-nav + .su-nav-inner), иначе на широких экранах
   панели тянулись бы во всю ширину экрана, а список блюд под ними — узкой
   колонкой по центру. */
.su-composer-panels {
  position: sticky; top: var(--su-nav-h); z-index: 15;
  background: var(--su-bg);
}
.su-composer-panels.is-static { position: static; }
.su-composer-panels-inner {
  max-width: 1180px; width: 100%; margin: 0 auto; box-sizing: border-box;
  padding: var(--su-space-2) var(--su-edge-pad);
  display: flex; flex-direction: column; gap: var(--su-space-2);
}
@media (min-width: 860px) { .su-composer-panels-inner { padding-left: var(--su-space-6); padding-right: var(--su-space-6); } }
/* overflow-x: auto нужен только чтобы вкладки прокручивались на узком экране,
   сама полоса прокрутки визуально не нужна (мелькает при первой загрузке,
   пока подменяется системный шрифт на кастомный и ширина вкладок пересчитывается —
   см. font-display: swap выше) — скрываем её кросс-браузерно, скролл жестом остаётся. */
.su-menu-tabs, .su-persons-tabs {
  display: flex; gap: var(--su-space-2); overflow-x: auto; margin: 0;
  -webkit-overflow-scrolling: touch; scrollbar-width: none; -ms-overflow-style: none;
}
.su-menu-tabs::-webkit-scrollbar, .su-persons-tabs::-webkit-scrollbar { display: none; }
/* Ряд разделов + кнопка "Назад" справа (композер). Кнопка вне прокручиваемого
   .su-menu-tabs — внутри она уезжала бы вместе с вкладками; min-width:0 нужен,
   чтобы flex дал ряду вкладок сжаться и включить свою прокрутку. */
.su-composer-tabs-row { display: flex; align-items: center; gap: var(--su-space-2); }
.su-composer-tabs-row > .su-menu-tabs { flex: 1 1 auto; min-width: 0; }
.su-composer-back { flex: 0 0 auto; }
/* overflow-x: auto на su-persons-tabs обрезает по Y тоже (браузер трактует
   overflow-x не visible как auto по обеим осям) — надстрочный бейдж su-badge-info--corner
   (см. ниже), вылезающий за верхний край вкладки, без запаса резался пополам.
   padding-top даёт место под вылет, отрицательный margin-top компенсирует
   получившийся визуальный сдвиг вкладок вниз. */
.su-persons-tabs { padding-top: 10px; margin-top: -10px; }
.su-menu-tab { flex: none; padding: 8px 16px; border-radius: var(--su-radius-pill); background: var(--su-n-200); color: var(--su-text-muted); font-size: var(--su-fs-sm); font-weight: 500; cursor: pointer; white-space: nowrap; border: none; font-family: var(--su-font-body); }
.su-menu-tab.is-active { background: var(--su-a-500); color: var(--su-on-primary); }
/* Вкладка "Гость N" с позициями — счётчик su-badge-info (нейтральный, не
   "внимание"), иначе официант должен тыкать по всем вкладкам, чтобы понять,
   у кого что есть (особенно заметно после "Назад" со страницы проверки
   заказа, где активная вкладка сбрасывается на "Гость 1"). Позиционируется
   как верхний индекс (по образцу "м²"), не расширяя саму пилюлю вкладки —
   --corner абсолютом поверх правого верхнего угла, кнопке нужен position:relative. */
.su-menu-tab--badged { position: relative; overflow: visible; }
.su-menu-tab.is-active .su-badge-info { background: var(--su-surface); color: var(--su-a-600); }
/* Кнопка "+" добавления гостя — та же пилюля, что вкладки, но не активна и
   не участвует в переключении, поэтому уже, без текста и без is-active. */
.su-persons-add { flex: none; width: 36px; padding: 8px 0; text-align: center; font-size: var(--su-fs-md); font-weight: 700; background: var(--su-n-100); color: var(--su-text-muted); }
/* scroll-margin-top — прокрутка по вкладке категории (scrollIntoView в
   waiter_composer.php) ставит верх секции ровно под верх ВЬЮПОРТА, а там висят
   шапка и панели: без запаса заголовок категории и первая позиция уезжали под
   них. Слагаемые те же, что у прилипающей корзины ниже, и --su-panels-h
   считается только для реально закреплённой панели — открепили её (is-static)
   или скрыли вкладки в настройках, и запас сам сходится к высоте одной шапки. */
.su-menu-list { display: flex; flex-direction: column; gap: var(--su-space-2); margin-top: var(--su-space-3); scroll-margin-top: calc(var(--su-nav-h) + var(--su-panels-h) + var(--su-space-2)); }
/* :first-of-type, не :first-child — рядом лежит #wHiddenInputs (не su-menu-list),
   он тоже первый ребёнок родителя, из-за чего :first-child никогда не совпал бы. */
.su-menu-list:first-of-type { margin-top: 0; }
/* Заголовок категории в композере официанта: подпись-разделитель, а не
   заголовок уровня страницы — отсюда мелкий кегль вразрядку. */
/* Селектор с [data-staff-theme] — не для красоты: базовый сброс заголовков
   выше ([data-staff-theme] h1..h4 { margin: 0 }) имеет специфичность 0,1,1,
   и голый .su-menu-cat-title (0,1,0) его не перебил бы — отступ молча
   обнулился бы. Раньше это делал инлайн-стиль. */
[data-staff-theme] .su-menu-cat-title {
  font-size: var(--su-fs-sm);
  color: var(--su-text-muted);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: var(--su-space-1);
}
.su-menu-item { display: flex; align-items: center; gap: var(--su-space-3); background: var(--su-surface); border-radius: var(--su-radius-md); padding: var(--su-space-3); box-shadow: var(--su-shadow-sm); }
.su-menu-item-body { flex: 1; min-width: 0; }
.su-menu-item-name { font-weight: 600; font-size: var(--su-fs-sm); }
.su-menu-item-desc { color: var(--su-text-muted); font-size: var(--su-fs-caption); margin: 3px 0; }
.su-menu-item-note { color: var(--su-cooking); background: var(--su-cooking-bg); border-radius: var(--su-radius-sm); padding: 4px 8px; font-size: var(--su-fs-caption); margin: 4px 0; display: inline-flex; align-items: center; gap: 4px; }
.su-menu-item-price { font-size: var(--su-fs-caption); color: var(--su-text-muted); }

.su-addbtn { padding: 8px 14px; border-radius: var(--su-radius-md); background: var(--su-a-500); color: var(--su-on-primary); border: none; font-weight: 600; font-size: var(--su-fs-sm); cursor: pointer; white-space: nowrap; font-family: var(--su-font-body); }
.su-qty { display: flex; align-items: center; gap: 10px; }
.su-qty-btn { width: 28px; height: 28px; border-radius: var(--su-radius-round); background: var(--su-n-200); border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--su-text); font-size: var(--su-fs-base); }
.su-qty-btn:hover { background: var(--su-n-300); }
.su-qty-val { min-width: 18px; text-align: center; font-weight: 600; font-variant-numeric: tabular-nums; }

/* Корзина-сайдбар — только на широких экранах (≥900px, вторая колонка грида).
   На мобильном её заменяет плавающая круглая кнопка su-cart-fab — без этого
   правила на мобильном рисовались ОБА варианта разом (сайдбар растянут на всю
   ширину под меню + fab поверх).
   top учитывает --su-panels-h — реальную высоту закреплённой панели "Гость N"/
   разделов меню (.su-composer-panels), если она есть на странице: без этого
   слагаемого корзина прилипала на той же высоте, что и шапка, и при прокрутке
   уезжала ПОД панель вместо того, чтобы остановиться под ней. Высота панели
   переменная (тема/кол-во категорий/наличие панели вообще) — сама переменная
   выставляется в waiter_composer.php через JS (getBoundingClientRect), дефолт
   0px безопасен для страниц без этой панели. */
:root { --su-panels-h: 0px; }
.su-cart { display: none; background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm); padding: var(--su-space-4); flex-direction: column; gap: var(--su-space-3); position: sticky; top: calc(var(--su-nav-h) + var(--su-panels-h) + var(--su-space-4)); min-width: 0; }
@media (min-width: 900px) { .su-cart { display: flex; } }
.su-cart-line { display: flex; align-items: center; justify-content: space-between; gap: var(--su-space-2); font-size: var(--su-fs-sm); }
.su-cart-line span:first-child { min-width: 0; overflow-wrap: break-word; }
.su-cart-total { display: flex; align-items: center; justify-content: space-between; font-family: var(--su-font-heading); font-size: var(--su-fs-lg); font-weight: 700; padding-top: var(--su-space-2); border-top: 1px solid var(--su-n-300); }

/* Строка проверки заказа со степпером +/- и удалением — места мало (узкий
   su-order-card), поэтому в один ряд через grid, не flex-wrap: имя сжимается
   первым (min-width:0), степпер/сумма/крестик держат свою ширину. */
.su-cart-line--editable { display: grid; grid-template-columns: 1fr auto auto auto; align-items: center; gap: var(--su-space-2); padding: 6px 0; }
.su-cart-line--editable + .su-cart-line--editable { border-top: 1px solid var(--su-n-200); }
.su-cart-line-name { min-width: 0; overflow-wrap: break-word; font-size: var(--su-fs-sm); }
.su-cart-line-sum { font-variant-numeric: tabular-nums; font-size: var(--su-fs-sm); min-width: 60px; text-align: right; }
.su-cart-line--editable .su-qty { gap: 3px; }
.su-cart-line--editable .su-qty-btn { width: 24px; height: 24px; font-size: var(--su-fs-sm); }
.su-cart-line--editable .su-qty-val { min-width: 12px; }
.su-qty-remove { width: 24px; height: 24px; border-radius: var(--su-radius-round); border: none; background: transparent; color: var(--su-cancel); font-size: var(--su-fs-lg); line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; }
.su-qty-remove:hover { background: var(--su-cancel-bg); }

/* Плавающая кнопка корзины — только на узких экранах (см. su-cart sidebar выше
   900px), по центру снизу экрана (композер скрывает нижний таббар — hideBottombar,
   полноэкранный ввод — поэтому отступ считаем от края экрана, не от su-tabbar-h).
   Просто круглая иконка + бейдж кол-ва позиций — без названия стола внутри:
   номер стола совпадал бы с цифрой бейджа (стол "3" + бейдж "3" читались как
   "в корзине уже что-то лежит" ещё до того, как официант успел ткнуть). */
.su-cart-fab {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%); z-index: 40;
  width: 56px; height: 56px; border-radius: var(--su-radius-round); background: var(--su-a-500); color: var(--su-on-primary);
  display: flex; align-items: center; justify-content: center; box-shadow: var(--su-shadow-lg);
  border: none; cursor: pointer; text-decoration: none;
}
.su-cart-fab:hover { text-decoration: none; color: var(--su-on-primary); background: var(--su-a-600); }
.su-cart-fab svg { width: 24px; height: 24px; }
.su-cart-fab-badge {
  /* Счётчик позиций, не "внимание" — нейтральный su-badge-info, не тревожный
     --su-b-600 (см. комментарий у .su-badge-info выше). */
  position: absolute; top: -2px; right: -2px; min-width: 20px; height: 20px; padding: 0 4px;
  border-radius: var(--su-radius-pill); background: var(--su-n-700); color: var(--su-n-100); font-size: var(--su-fs-caption); font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
@media (min-width: 900px) { .su-cart-fab { display: none; } }

/* ============ формы ============ */
.su-field { display: flex; flex-direction: column; gap: 6px; }
.su-field label { font-size: var(--su-fs-caption); font-weight: 600; color: var(--su-text-muted); }
.su-input, .su-textarea, .su-select {
  /* min-height 44px — та же тач-цель, что у кнопок. font-size 16px обязателен:
     на меньшем кегле iOS Safari зумит страницу при фокусе, и после ввода
     пользователь остаётся на увеличенном экране. */
  min-height: var(--su-hit-min);
  border: 1px solid var(--su-n-300); border-radius: var(--su-radius-md);
  padding: var(--su-space-2) var(--su-space-3);
  font-family: var(--su-font-body); font-size: var(--su-fs-base);
  background: var(--su-surface); color: var(--su-text); width: 100%;
}
.su-textarea { min-height: calc(var(--su-hit-min) * 2); }
.su-input:focus, .su-textarea:focus, .su-select:focus { border-color: var(--su-a-500); outline: none; box-shadow: var(--su-ring); }
/* Узкое числовое поле (порядок сортировки, мин/макс выбора и т.п.) — не должно
   растягиваться на всю ширину строки рядом с текстовым полем (см. .su-inline-form). */
.su-input--num { width: 76px; flex: none; }
.su-input--sm { width: 100px; flex: none; }
/* Список чекбоксов-настроек (уведомления, композер) — обёртка + строка label. */
/* Форма в столбик: поля, чекбоксы и кнопка идут друг под другом с одинаковым
   шагом. Для форм, где элементы разной высоты (селект с подписью + голый
   чекбокс + кнопка) — в строку они разъезжаются по вертикали и требуют
   подгонки отступов на каждый элемент.
   ⚠️ Ширину НЕ ограничивает: класс описывает раскладку, а не размер. Сколько
   места нужно конкретному полю — знает только это поле (селекту с длинными
   подписями нужно больше, чем полю для числа), и общий max-width здесь
   упирал бы в одну цифру любую будущую форму. */
.su-form-stack { display: flex; flex-direction: column; align-items: flex-start; gap: var(--su-space-3); }
/* --su-field-w задаётся на самой форме там, где растягивать поле на всю
   страницу незачем; без переменной поле занимает всю ширину. */
.su-form-stack > .su-input, .su-form-stack > .su-field { width: 100%; max-width: var(--su-field-w, 100%); }
/* Готовая ширина для форм с текстовыми полями/селектами — та же мера, что у
   .su-ph-wrap и .su-ticket-msg. Модификатор, а не значение в базовом классе:
   форме с таблицей или сеткой внутри эта ширина не подходит. */
.su-form-stack--md { --su-field-w: 560px; }
.su-checkbox-group { display: flex; flex-direction: column; gap: var(--su-space-1); margin: var(--su-space-3) 0; }
/* Группа настроек, недоступная на текущем тарифе: показываем как есть, но
   притушенной и некликабельной — человек должен видеть, ЧТО он получит,
   а не пустое место. */
.su-checkbox-group.is-locked { margin-top: 0; opacity: .5; }
.su-checkbox-group.is-locked .su-checkbox-row { cursor: not-allowed; }
/* Строка чекбокса — тач-цель целиком, а не только сам квадратик 13x13:
   промахнуться пальцем мимо галочки и не понять, почему настройка не
   переключилась, слишком легко. */
.su-checkbox-row { display: flex; align-items: center; gap: var(--su-space-2); cursor: pointer; min-height: var(--su-hit-min); }
.su-checkbox-row input[type="checkbox"], .su-checkbox-row input[type="radio"] {
  width: 20px; height: 20px; flex: none; accent-color: var(--su-a-600); cursor: pointer;
}
/* Отдельная строка недоступна, а не вся группа (в отличие от .is-locked):
   способ оплаты, занятый другим терминалом. Гасим строку, но оставляем
   читаемой — рядом подпись, у кого он занят, и её надо разобрать. */
.su-checkbox-row.su-is-disabled { opacity: .55; cursor: not-allowed; }
.su-checkbox-row.su-is-disabled input { cursor: not-allowed; }
/* Строка выбора С ОПИСАНИЕМ под заголовком: вариант, который нельзя назвать
   двумя словами (режимы работы кафе на онбординге и в настройках).

   Выравнивание по верху, а не по центру: у двухстрочного варианта кружок
   иначе уезжает к середине абзаца и перестаёт читаться как метка строки.

   ⚠️ Вес описания сбрасывается явно. Внутри .su-field на всё содержимое
   <label> действует font-weight:600 (см. .su-field label), а .su-card-meta
   веса не задаёт — на онбординге описание выходило таким же жирным, как
   заголовок, и вариант читался стеной текста. */
.su-checkbox-row--desc { align-items: flex-start; }
.su-checkbox-row--desc input[type="radio"], .su-checkbox-row--desc input[type="checkbox"] { margin-top: 2px; }
.su-checkbox-row--desc .su-card-meta { display: block; font-weight: 400; margin-top: 2px; }
/* Вариант, закрытый тарифом. НЕ .su-is-disabled и не атрибут disabled:
   человек должен видеть, ЧТО он получит, и — главное — в каком режиме кафе
   работает СЕЙЧАС. Браузер не показывает disabled-радио выбранным, поэтому у
   владельца на free с сохранённым 'team' все кружки выглядели пустыми, и экран
   переставал отвечать на свой главный вопрос.

   Клик снимается pointer-events (кроме ссылки на тарифы — за ней и приходят),
   гашение мягкое: подпись обязана читаться. Сервер гейт повторяет — снятый в
   девтулзах pointer-events прямой POST не пропустит. */
.su-choice-locked { cursor: default; pointer-events: none; }
.su-choice-locked > span { opacity: .72; }
.su-choice-locked input[type="radio"] { opacity: .55; }
.su-choice-locked .su-choice-locked-note { pointer-events: auto; opacity: 1; margin-top: 4px; color: var(--su-a-700); }
.su-choice-locked .su-choice-locked-note a { pointer-events: auto; }
/* Подпись со ССЫЛКОЙ внутри предложения. Базовый .su-card-meta — flex с gap,
   и он разносит текстовые узлы: точка после ссылки отъезжала от неё пробелом.
   Инлайновому тексту флекс не нужен вовсе. */
.su-note-inline { display: block; }
/* ---- тумблер ----
   Для настроек, где вопрос двоичный и решение публичное («меню видно в
   поиске»): чекбокс читается как согласие с мелким шрифтом, радио на два
   состояния — лишний вес. Состояние видно с расстояния, без чтения подписи.

   Под капотом обычный <input type="checkbox"> — форма отправляет его как
   любой другой, JS не нужен. Сам input визуально спрятан clip-path, а не
   display:none: скрытый так элемент остаётся фокусируемым с клавиатуры и
   виден скринридеру. */
.su-switch { display: flex; align-items: center; gap: var(--su-space-3); cursor: pointer; min-height: var(--su-hit-min); }
.su-switch input[type="checkbox"] {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.su-switch-track {
  flex: none; position: relative; width: 44px; height: 26px; border-radius: 999px;
  background: var(--su-n-300); transition: background .15s ease;
}
.su-switch-track::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px;
  border-radius: 50%; background: var(--su-surface); box-shadow: var(--su-shadow-sm);
  transition: transform .15s ease;
}
.su-switch input:checked + .su-switch-track { background: var(--su-a-600); }
.su-switch input:checked + .su-switch-track::after { transform: translateX(18px); }
/* Фокус виден на дорожке: сам input спрятан, и без этого клавиатурная
   навигация по форме теряет курсор. */
.su-switch input:focus-visible + .su-switch-track { box-shadow: var(--su-ring); }
.su-switch input:disabled + .su-switch-track { opacity: .55; }
.su-switch input:disabled ~ * { opacity: .55; }
.su-switch:has(input:disabled) { cursor: not-allowed; }

/* Форма "select + кнопка сохранить" в одну строку (тема оформления). */
.su-inline-form { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: var(--su-space-3); }
.su-inline-form .su-input { flex: 1 1 220px; min-width: 0; }

/* ============ таблица / история ============ */
.su-table { width: 100%; border-collapse: collapse; font-size: var(--su-fs-sm); }
.su-table th { text-align: left; font-size: var(--su-fs-caption); letter-spacing: .05em; text-transform: uppercase; color: var(--su-text-muted); font-weight: 600; padding: var(--su-space-2) var(--su-space-3); border-bottom: 2px solid var(--su-n-300); }
.su-table td { padding: var(--su-space-3); border-bottom: 1px solid var(--su-n-200); }
.su-table tr:hover td { background: var(--su-n-100); }

.su-history-date { font-family: var(--su-font-heading); font-size: var(--su-fs-sm); font-weight: 700; color: var(--su-text-muted); margin: var(--su-space-5) 0 var(--su-space-2); padding: 0 var(--su-space-2); }
.su-history-date:first-child { margin-top: 0; }
/* История — ПЛОТНЫЙ СПИСОК, а не набор карточек. У каждой строки была своя
   тень и свой margin-bottom: сорок записей превращались в сорок плашек,
   висящих в воздухе. По правилу плотных списков — общая карточка-контейнер и
   разделители между строками. */
.su-history-list {
  background: var(--su-surface); border-radius: var(--su-radius-lg);
  box-shadow: var(--su-shadow-sm); overflow: hidden;
}
.su-history-row {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--su-space-1) var(--su-space-3);
  padding: var(--su-space-2) var(--su-space-3);
  min-height: var(--su-hit-min);
  background: var(--su-surface);
  border-bottom: 1px solid var(--su-n-200);
  text-decoration: none; color: var(--su-text); cursor: pointer;
}
.su-history-row:last-child { border-bottom: none; }
.su-history-row:hover, [data-staff-theme] .su-history-row:hover { text-decoration: none; color: var(--su-text); background: var(--su-n-100); }
[data-staff-theme] .su-history-row .su-tag:hover { text-decoration: none; }
.su-history-num { font-size: var(--su-fs-caption); font-weight: 700; flex: none; }
.su-history-time { font-variant-numeric: tabular-nums; color: var(--su-text-muted); font-size: var(--su-fs-sm); width: 5ch; flex: none; }
.su-history-table { color: var(--su-text-muted); font-size: var(--su-fs-caption); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.su-history-sum { font-size: var(--su-fs-caption); font-weight: 700; flex: none; }
.su-history-payment {
  flex: 0 0 100%; justify-content: flex-end; margin-left: 0;
}

/* ============ пустые состояния ============ */
.su-empty { text-align: center; color: var(--su-text-muted); padding: var(--su-space-6) var(--su-space-3); font-size: var(--su-fs-sm); }


/* ============================================================
   Блок «СТРУКТУРНЫЕ РАЗЛИЧИЯ ПО ТЕМАМ» удалён на шаге 2 редизайна.

   В нём было 80 правил вида [data-staff-theme="x"] .su-card { … }: тема
   лезла в КОНКРЕТНЫЕ КОМПОНЕНТЫ — одна убирала тени карточке, другая
   меняла заливку кнопки на обводку, третья дорисовывала точку через
   ::before. Шесть тем оказывались шестью разными продуктами, и элемент,
   знакомый по одному рабочему месту, на соседнем выглядел иначе.

   ⚠️ Не путать с тем, как тема работает СЕЙЧАС. Она задаёт ПЕРЕМЕННЫЕ
   (--su-radius-*, --su-shadow-*, палитра), а классы их читают — один
   рычаг вместо 80 точечных переопределений. Тема не знает про .su-card
   и дорисовать ей ничего не может. Что теме можно, а что нет —
   CLAUDE.md 3.7 (граница: характер можно, раскладку нельзя).

   Отсюда требование к правилам ниже: радиус, тень и цвет писать ТОЛЬКО
   через var(--su-*). Литерал (border-radius: 999px) тема перекрыть не
   может — так шапка оставалась круглой в теме с прямыми углами.
   ============================================================ */


/* ============ экран кассы (/staff/order/{id}/pay) ============
   Только переменные --su-* — иначе экран не подхватит тему кафе. */
.su-pay-summary {
  background: var(--su-surface); border-radius: var(--su-radius-lg);
  padding: var(--su-space-3) var(--su-space-4); margin-bottom: var(--su-space-4);
  box-shadow: var(--su-shadow-sm);
}
.su-pay-sum-row {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: var(--su-space-1) 0; color: var(--su-text-muted); font-size: var(--su-fs-sm);
}
/* Остаток — главная цифра экрана: кассир смотрит "сколько взять сейчас",
   а не на общую сумму заказа. */
.su-pay-sum-row--total {
  border-top: 1px solid var(--su-n-300); margin-top: var(--su-space-2);
  padding-top: var(--su-space-2); color: var(--su-text);
  font-size: var(--su-fs-lg); font-weight: 700;
}
/* Скидка в итогах — акцентом вниз: строка со знаком минус должна читаться
   как вычитание с одного взгляда, а не как ещё одна сумма. */
.su-pay-sum-row--discount { color: var(--su-bill); font-weight: 600; }
/* Переплата встаёт на место остатка и обязана отличаться цветом: обе строки
   стоят в одном углу экрана, и кассир различает их по смыслу "взять / отдать",
   а не по подписи, которую в спешке не читают. */
.su-pay-sum-row--overpaid { color: var(--su-cancel); }

/* Форма скидки: свёрнута по умолчанию (в обычном чеке скидки нет) и не
   похожа на кнопку оплаты — её нажимают редко и осознанно. */
.su-pay-discount { margin-bottom: var(--su-space-4); }
.su-pay-discount-toggle {
  background: none; border: 1px dashed var(--su-n-300); border-radius: var(--su-radius-md);
  padding: var(--su-space-2) var(--su-space-3); width: 100%;
  color: var(--su-text-muted); font: inherit; font-size: var(--su-fs-sm); cursor: pointer;
}
.su-pay-discount-form {
  background: var(--su-surface); border-radius: var(--su-radius-md);
  padding: var(--su-space-3); margin-top: var(--su-space-2);
  display: flex; flex-direction: column; gap: var(--su-space-2);
}
.su-pay-discount-row { display: flex; align-items: center; gap: var(--su-space-2); }
/* % и ₽ — переключатель единицы, а не два разных поля: размер вводится один
   раз, меняется только его смысл. */
.su-pay-discount-kind {
  display: flex; align-items: center; gap: 4px;
  border: 2px solid var(--su-n-300); border-radius: var(--su-radius-md);
  padding: var(--su-space-2) var(--su-space-3); cursor: pointer; font-weight: 700;
}
.su-pay-discount-kind input { margin: 0; }
.su-pay-discount-kind:has(input:checked) { border-color: var(--su-b-500); background: var(--su-b-100); }
.su-pay-discount-value, .su-pay-discount-reason {
  flex: 1 1 auto; min-width: 0;
  border: 1px solid var(--su-n-300); border-radius: var(--su-radius-md);
  padding: var(--su-space-2) var(--su-space-3); font: inherit;
  background: var(--su-bg); color: var(--su-text);
}
.su-pay-discount-value { font-weight: 700; }
.su-pay-discount-actions { display: flex; align-items: center; gap: var(--su-space-3); }
.su-pay-discount-actions .su-btn { flex: 1 1 auto; }
.su-pay-discount-clear {
  background: none; border: none; padding: 0;
  color: var(--su-cancel); font: inherit; font-size: var(--su-fs-sm); cursor: pointer;
}

.su-pay-subtitle {
  font-family: var(--su-font-heading); font-weight: var(--su-font-heading-weight);
  font-size: var(--su-fs-sm); color: var(--su-text-muted);
  margin: var(--su-space-4) 0 var(--su-space-2); text-transform: uppercase; letter-spacing: .04em;
}
.su-pay-items { list-style: none; margin: 0; padding: 0; }
.su-pay-item {
  background: var(--su-surface); border-radius: var(--su-radius-md);
  margin-bottom: var(--su-space-1);
}
.su-pay-item--done { opacity: .55; }
.su-pay-item-label {
  display: flex; align-items: center; gap: var(--su-space-2);
  padding: var(--su-space-3); cursor: pointer;
}
.su-pay-item--done .su-pay-item-label { cursor: default; }
.su-pay-item-label input[type=checkbox] { width: 20px; height: 20px; flex-shrink: 0; margin: 0; }
.su-pay-item-name { flex: 1 1 auto; }
.su-pay-item-sum { flex-shrink: 0; font-weight: 600; text-align: right; }
.su-pay-item-part { display: block; font-size: var(--su-fs-caption); font-weight: 400; color: var(--su-text-muted); }

/* Способы — крупные кнопки: кассир жмёт их пальцем, часто не глядя. */
.su-pay-methods { display: flex; flex-wrap: wrap; gap: var(--su-space-2); }
.su-pay-method {
  flex: 1 1 120px; display: flex; align-items: center; justify-content: center; gap: var(--su-space-2);
  background: var(--su-surface); border: 2px solid var(--su-n-300);
  border-radius: var(--su-radius-md); padding: var(--su-space-3);
  cursor: pointer; font-weight: 600;
}
.su-pay-method input { margin: 0; }
.su-pay-method:has(input:checked) { border-color: var(--su-b-500); background: var(--su-b-100); }
.su-pay-hint { font-size: var(--su-fs-caption); color: var(--su-text-muted); margin: var(--su-space-2) 0 0; }
.su-pay-done, .su-pay-empty {
  background: var(--su-surface); border-radius: var(--su-radius-lg);
  padding: var(--su-space-4); text-align: center; color: var(--su-text-muted);
}
/* Переплата — не рядовое "всё в порядке", а долг гостю: приглушённым серым
   такое сообщение проходит мимо глаз. */
.su-pay-done--overpaid { color: var(--su-text); }
/* Разбор "и вернуть, и взять" — читается, а не проглядывается: кассир по этой
   строке решает, сколько денег реально двигать. */
.su-pay-hint--net {
  color: var(--su-text); background: var(--su-surface);
  border-radius: var(--su-radius-md); padding: var(--su-space-3);
  margin-top: var(--su-space-2); font-size: var(--su-fs-sm);
}
.su-pay-hint--net strong { color: var(--su-cancel); }
.su-pay-done--overpaid strong { color: var(--su-cancel); }
.su-pay-correction {
  margin: var(--su-space-3) 0; padding: var(--su-space-3);
  background: var(--su-surface); border-radius: var(--su-radius-lg);
}
.su-pay-correction .su-pay-subtitle { margin-top: 0; }
.su-pay-correction-note {
  display: grid; gap: var(--su-space-2); font-size: var(--su-fs-sm);
}
.su-pay-correction-note + .su-pay-correction-note { margin-top: var(--su-space-3); }
.su-pay-correction-note--external {
  border-left: 3px solid var(--su-cancel); padding-left: var(--su-space-3);
}
.su-pay-correction-note ul { margin: 0; padding-left: 1.25rem; }
/* Закрытая позиция в свёрнутом составе шторки — гасим, чтобы взгляд шёл к тем,
   за которые сейчас берут деньги. */
.su-pay-sheet-item--done { color: var(--su-text-muted); }

.su-pay-log { list-style: none; margin: 0; padding: 0; }
.su-pay-log-empty { color: var(--su-text-muted); font-size: var(--su-fs-sm); padding: var(--su-space-2) 0; }
.su-pay-log-row {
  background: var(--su-surface); border-radius: var(--su-radius-md);
  padding: var(--su-space-3); margin-bottom: var(--su-space-1);
}
.su-pay-log-row--void { opacity: .5; text-decoration: line-through; }
.su-pay-log-main { display: flex; justify-content: space-between; align-items: baseline; }
.su-pay-log-method { font-weight: 600; }
.su-pay-log-amount { font-weight: 700; }
.su-pay-log-meta { font-size: var(--su-fs-caption); color: var(--su-text-muted); margin-top: 2px; }
.su-pay-log-void { color: var(--su-cancel); }
.su-pay-log-pending { color: var(--su-cooking); }
.su-pay-log-terminal-note {
  color: var(--su-text-muted); font-size: var(--su-fs-caption); padding-top: var(--su-space-1);
}
.su-pay-void-btn {
  background: none; border: none; padding: var(--su-space-1) 0 0;
  color: var(--su-cancel); font: inherit; font-size: var(--su-fs-caption); cursor: pointer;
}

/* Фискальный чек (54-ФЗ). Пробитый — обычной служебной строкой: это норма,
   а не достижение. Непробитый — цветом тревоги: кассир обязан заметить его
   на смене, а не узнать от налоговой. */
.su-pay-log-fiscal { font-size: var(--su-fs-caption); color: var(--su-text-muted); margin-top: 2px; }
.su-pay-log-fiscal--wait { font-style: italic; }
.su-pay-log-fiscal--bad { color: var(--su-cancel); font-weight: 600; }
.su-pay-log-row--void .su-pay-void-btn { display: none; }

/* Возврат. Строка-возврат НЕ зачёркивается (в отличие от отменённого платежа):
   отмена означает "платежа не было", возврат — состоявшийся факт движения
   денег в обратную сторону. Отличается цветом суммы, а не вычёркиванием. */
.su-pay-log-row--refund { border-left: 3px solid var(--su-cancel); }
.su-pay-log-row--refund .su-pay-log-amount { color: var(--su-cancel); }
.su-pay-log-refunded { color: var(--su-cancel); }
.su-pay-log-actions { display: flex; gap: var(--su-space-3); align-items: center; }
.su-pay-refund-btn {
  background: none; border: none; padding: var(--su-space-1) 0 0;
  color: var(--su-cancel); font: inherit; font-size: var(--su-fs-caption); font-weight: 600;
  cursor: pointer;
}
.su-pay-refund-form {
  margin-top: var(--su-space-2); padding-top: var(--su-space-2);
  border-top: 1px solid var(--su-n-300);
}
.su-pay-refund-items { list-style: none; margin: var(--su-space-2) 0; padding: 0; }
.su-pay-refund-item label {
  display: flex; align-items: center; gap: var(--su-space-2);
  padding: var(--su-space-1) 0; cursor: pointer;
}
.su-pay-refund-item .su-pay-item-name { flex: 1; }
.su-pay-refund-reason {
  width: 100%; box-sizing: border-box; margin-bottom: var(--su-space-2);
  padding: var(--su-space-2); font: inherit;
  border: 1px solid var(--su-n-300); border-radius: var(--su-radius-md);
  background: var(--su-bg); color: var(--su-text);
}
/* ============================================================
   МЕНЮ ВЛАДЕЛЬЦА (/admin/dishes, /admin/dishes/{id}/edit, /admin/categories,
   /admin/modifiers, /admin/menu — редактор, /admin/menu/quick — быстрое
   скрытие). Общие для владельца и сотрудника (менеджера) компоненты —
   /staff/manager/menu переиспользует /admin/menu/quick 1-в-1, тот же
   menu-quick.js, поэтому су-классы карточки блюда живут здесь, а не в
   владельческом CSS-файле.
   ============================================================ */

/* ---- загрузчик фото блюда (/admin/dishes/{id}/edit) ---- */
.su-photo-row { display: flex; gap: var(--su-space-3); align-items: flex-start; margin: var(--su-space-3) 0; }
.su-photo-thumb { flex: none; }
.su-photo-thumb img { width: 90px; height: 90px; object-fit: cover; border-radius: var(--su-radius-md); display: block; }
.su-photo-placeholder {
  width: 90px; height: 90px; background: var(--su-n-200); border: 2px dashed var(--su-n-400);
  border-radius: var(--su-radius-md); display: flex; align-items: center; justify-content: center; font-size: var(--su-fs-2xl);
}
.su-photo-btns { display: flex; flex-direction: column; gap: 8px; }
.su-photo-btn {
  width: 40px; height: 40px; padding: 0; border-radius: var(--su-radius-md);
  border: 1px solid var(--su-n-300); background: var(--su-surface); color: var(--su-text);
  font-size: var(--su-fs-base); cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.su-photo-btn:hover { background: var(--su-n-200); }
.su-photo-btn--del { color: var(--su-cancel); border-color: var(--su-cancel-bg); }
.su-photo-btn--del:hover { background: var(--su-cancel-bg); }

/* ---- зона удаления внизу формы блюда ---- */
.su-danger-zone { margin-top: var(--su-space-5); padding-top: var(--su-space-3); border-top: 1px solid var(--su-n-300); display: flex; flex-direction: column; align-items: center; gap: 10px; }
.su-danger-zone-confirm { display: none; gap: 10px; align-items: center; flex-wrap: wrap; justify-content: center; }

/* ---- строка блюда в плоском списке (/admin/dishes) ---- */
.su-dish-row {
  display: flex; gap: var(--su-space-3); align-items: center;
  background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm);
  padding: var(--su-space-3); margin-bottom: 8px;
}
.su-dish-row.is-off { opacity: .55; }
.su-dish-photo { width: 60px; height: 60px; flex: none; border-radius: var(--su-radius-md); overflow: hidden; background: var(--su-n-200); display: flex; align-items: center; justify-content: center; }
.su-dish-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.su-dish-photo-empty { font-size: var(--su-fs-caption); color: var(--su-text-muted); text-align: center; padding: 0 4px; }
.su-dish-body { flex: 1; min-width: 0; }
.su-dish-name { font-weight: 600; font-size: var(--su-fs-sm); }
.su-dish-meta { display: flex; gap: var(--su-space-2); color: var(--su-text-muted); font-size: var(--su-fs-caption); flex-wrap: wrap; align-items: center; margin-top: 2px; }
.su-dish-price { color: var(--su-text); font-weight: 700; }
.su-dish-actions { display: flex; gap: 6px; flex-wrap: wrap; flex: none; }
.su-dish-actions form { margin: 0; }

/* ---- категории (/admin/categories) ---- */
.su-cat-row { display: flex; gap: var(--su-space-2); align-items: center; background: var(--su-surface); border-radius: var(--su-radius-md); box-shadow: var(--su-shadow-sm); padding: var(--su-space-2) var(--su-space-3); margin-bottom: 6px; flex-wrap: wrap; }
.su-cat-edit { display: flex; gap: var(--su-space-2); align-items: center; flex: 1; margin: 0; flex-wrap: wrap; min-width: 0; }
.su-cat-edit .su-input { flex: 1; min-width: 160px; }
.su-cat-row form { margin: 0; }

/* ---- редактор меню drag-drop (/admin/menu) — карточка блюда как у гостя ---- */
.su-me-toolbar { display: flex; gap: var(--su-space-2); margin-bottom: var(--su-space-4); flex-wrap: wrap; }
.su-me-toolbar > * { flex: 1 1 160px; }
.su-me-add-cat { background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm); padding: var(--su-space-4); margin-bottom: var(--su-space-4); }
.su-me-add-cat h3 { margin: 0 0 var(--su-space-2); font-size: var(--su-fs-base); }
.su-me-add-cat-row { display: flex; gap: var(--su-space-2); }
.su-me-add-cat-row .su-input { flex: 1; }

.su-me-section { margin-bottom: var(--su-space-4); }
.su-me-section-head { display: flex; align-items: center; gap: 6px; padding: var(--su-space-2) 0; }
.su-me-section-name { font-weight: 700; font-size: var(--su-fs-sm); flex: none; }
.su-me-section-name-input { flex: 1; min-width: 100px; border: 1px solid var(--su-a-500); border-radius: var(--su-radius-sm); padding: 4px 8px; font: inherit; font-weight: 700; background: var(--su-surface); color: var(--su-text); }
.su-me-section-controls { display: flex; gap: 4px; align-items: center; margin-left: auto; }
.su-me-section.is-hidden .su-me-section-head { opacity: .55; }
.su-me-section.is-hidden .su-me-section-body { opacity: .4; pointer-events: none; }
.su-me-section-body { display: flex; flex-direction: column; gap: 8px; min-height: 4px; }
.su-me-section-empty { color: var(--su-text-muted); font-size: var(--su-fs-caption); padding: var(--su-space-2) 0; }
.su-me-cat-err { color: var(--su-cancel); font-size: var(--su-fs-caption); padding: 2px 0 4px; }

.su-me-icon-btn {
  width: 30px; height: 30px; border-radius: var(--su-radius-round); border: 1px solid var(--su-n-300);
  background: var(--su-surface); color: var(--su-text); font-size: var(--su-fs-sm);
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer; flex: none;
}
.su-me-icon-btn:hover { background: var(--su-n-200); }
.su-me-icon-btn:disabled { opacity: .35; cursor: default; }
.su-me-icon-btn--save { color: var(--su-free); border-color: var(--su-free-bg); }
.su-me-icon-btn--save:hover { background: var(--su-free-bg); }
.su-me-icon-btn--del { color: var(--su-cancel); border-color: var(--su-cancel-bg); }
.su-me-icon-btn--del:hover { background: var(--su-cancel-bg); }

.su-me-dish { border-radius: var(--su-radius-lg); background: var(--su-surface); box-shadow: var(--su-shadow-sm); }
.su-me-dish.is-hidden .su-me-dish-card { opacity: .45; }
.su-me-dish.is-dragging { opacity: .3; }
.su-me-dish-card { display: flex; gap: var(--su-space-3); align-items: center; padding: var(--su-space-3); position: relative; touch-action: none; cursor: grab; }
.su-me-dish-card:active { cursor: grabbing; }
.su-me-dish-img { width: 56px; height: 56px; flex: none; border-radius: var(--su-radius-md); object-fit: cover; }
.su-me-dish-noimg { width: 56px; height: 56px; flex: none; border-radius: var(--su-radius-md); background: var(--su-n-200); display: flex; align-items: center; justify-content: center; font-size: var(--su-fs-xl); }
.su-me-dish-info { flex: 1; min-width: 0; }
.su-me-dish-name { font-weight: 600; font-size: var(--su-fs-sm); }
.su-me-dish-desc { color: var(--su-text-muted); font-size: var(--su-fs-caption); margin: 2px 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.su-me-dish-price { font-weight: 700; color: var(--su-a-700); font-size: var(--su-fs-sm); margin-top: 4px; }
.su-me-dish-edit { flex: none; color: var(--su-text-muted); padding: 6px; }
.su-me-dish-actions { display: flex; gap: 6px; padding: 0 var(--su-space-3) var(--su-space-3); }
.su-me-drag-ph { border: 2px dashed var(--su-n-400); border-radius: var(--su-radius-lg); background: var(--su-n-100); }

/* ---- расписания меню (CLAUDE.md 10.7.2): строка состояния, выбор у раздела, форма ---- */
.su-schedule-note { display: flex; align-items: flex-start; gap: var(--su-space-1); font-size: var(--su-fs-caption); font-weight: 600; color: var(--su-free); margin-top: var(--su-space-1); }
.su-schedule-note > svg { flex: none; }
.su-schedule-note-text { min-width: 0; overflow-wrap: anywhere; }
.su-schedule-note.is-off { color: var(--su-text-muted); }
.su-me-section > .su-schedule-note { margin: 0 0 var(--su-space-2); }
/* Расписание обозначает скрытие у гостя, но не блокирует работу редактора. */
.su-me-section.is-schedule-off, .su-me-dish.is-schedule-off {
  position: relative; border-inline-start: var(--su-space-5) solid var(--su-n-300);
}
.su-me-section.is-schedule-off {
  padding: var(--su-space-3); border-radius: var(--su-radius-lg); background: var(--su-n-100);
}
.su-me-section.is-schedule-off > .su-me-section-head { flex-wrap: wrap; }
.su-me-dish.is-schedule-off { background: var(--su-n-100); }
.su-me-schedule-marker {
  position: absolute; inset-inline-start: calc(-1 * var(--su-space-5)); top: var(--su-space-3);
  width: var(--su-space-5); display: flex; justify-content: center;
  color: var(--su-text-muted); pointer-events: none;
}
.su-me-section > .su-me-schedule-marker { top: var(--su-space-5); }
.is-schedule-off .su-schedule-note-text strong { color: var(--su-text); }
.su-me-sched-picker { display: flex; flex-wrap: wrap; align-items: center; gap: var(--su-space-2); padding: 0 0 var(--su-space-2); }
.su-me-sched-picker .su-input { flex: 1 1 220px; min-width: 0; }

.su-sched-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--su-space-2); margin-bottom: var(--su-space-1); }
.su-sched-name { margin: 0; font-size: var(--su-fs-base); }
.su-sched-form { margin-top: var(--su-space-3); }
.su-sched-windows { display: flex; flex-direction: column; gap: var(--su-space-2); margin-bottom: var(--su-space-2); }
.su-sched-window { display: flex; flex-wrap: wrap; align-items: center; gap: var(--su-space-2); padding: var(--su-space-2); border: 1px solid var(--su-n-300); border-radius: var(--su-radius-md); }
.su-sched-days { display: flex; flex-wrap: wrap; gap: var(--su-space-1); }
.su-sched-day { position: relative; cursor: pointer; }
/* Сам чекбокс спрятан clip-path, а не display:none — иначе пропал бы фокус с
   клавиатуры и скринридер (тот же приём, что у .su-switch). */
.su-sched-day input { position: absolute; width: 1px; height: 1px; opacity: 0; clip-path: inset(50%); }
.su-sched-day span {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: var(--su-hit-sm); min-height: var(--su-hit-sm); padding: 0 var(--su-space-2);
  border: 1px solid var(--su-n-300); border-radius: var(--su-radius-sm);
  background: var(--su-surface); color: var(--su-text-muted); font-size: var(--su-fs-caption); font-weight: 600;
}
.su-sched-day input:checked + span { background: var(--su-a-100); border-color: var(--su-a-500); color: var(--su-a-700); }
.su-sched-day input:focus-visible + span { box-shadow: var(--su-ring); }
.su-sched-times { display: flex; align-items: center; gap: var(--su-space-2); }
.su-sched-time { width: auto; flex: 0 0 auto; }
.su-sched-dash { color: var(--su-text-muted); }

/* ---- строка-форма варианта модификатора (/admin/modifiers) ----
   Раньше сидела как <td colspan> внутри <table> — заголовки th не выравнивались
   с полями (flex-форма против table-layout колонок), выглядело неряшливо.
   Явная grid-сетка с подписанными колонками читается как таблица, но остаётся
   формой без вложенной разметки table/tr/td. */
.su-mod-options { display: flex; flex-direction: column; }
.su-mod-group-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--su-space-2); }
.su-mod-group-name { flex: 1 1 160px; }
.su-mod-group-limits { display: flex; gap: var(--su-space-2); }
.su-mod-category-scope {
  margin: 0 0 var(--su-space-3); padding: var(--su-space-3);
  border: 1px solid var(--su-n-300); border-radius: var(--su-radius-md);
}
.su-mod-category-scope legend { padding: 0 4px; font-weight: 700; font-size: var(--su-fs-sm); }
.su-mod-category-list {
  display: flex; flex-direction: row; flex-wrap: wrap;
  gap: var(--su-space-2); margin: var(--su-space-2) 0;
}
.su-mod-category-chip:has(input:checked) {
  border-color: var(--su-a-500); background: var(--su-a-100); color: var(--su-a-700);
}
.su-mod-category-scope.is-saving { opacity: .65; }
.su-mod-opt-head, .su-mod-opt-row {
  display: grid; grid-template-columns: 54px minmax(0, 1fr) 112px 40px 40px 44px 44px; align-items: center;
  gap: var(--su-space-2); padding: var(--su-space-2) 0;
}
.su-mod-opt-head { font-size: var(--su-fs-caption); letter-spacing: .04em; text-transform: uppercase; color: var(--su-text-muted); font-weight: 600; border-bottom: 2px solid var(--su-n-300); }
.su-mod-opt-head > span { min-width: 0; white-space: nowrap; }
.su-mod-opt-row { border-bottom: 1px solid var(--su-n-200); }
.su-mod-opt-row:last-child { border-bottom: none; }
.su-mod-opt-row .su-input { width: 100%; }
.su-mod-sort-controls { display: inline-flex; align-items: center; gap: 2px; flex: none; }
.su-mod-sort-controls button {
  width: 25px; height: 34px; border: 1px solid var(--su-n-300); background: var(--su-surface);
  color: var(--su-text-muted); border-radius: var(--su-radius-sm); padding: 0;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
}
.su-mod-sort-controls button:hover:not(:disabled) { color: var(--su-a-600); background: var(--su-a-100); }
.su-mod-sort-controls button:disabled { opacity: .25; cursor: default; }
.su-mod-sort-up { transform: rotate(-90deg); }
.su-mod-sort-down { transform: rotate(90deg); }
.su-mod-opt-add { grid-column: 4 / 8; width: 100%; min-width: 0; align-self: stretch; }
.su-mod-default {
  border: none; background: transparent; padding: 6px; line-height: 1; cursor: pointer;
  border-radius: var(--su-radius-sm); color: var(--su-n-400); display: inline-flex;
  align-items: center; justify-content: center; justify-self: center;
}
.su-mod-default.is-on { color: var(--su-b-500); }
.su-mod-default.is-on svg { fill: currentColor; }
.su-mod-default:hover { background: var(--su-b-100); }
.su-mod-default:focus-visible { outline: 2px solid var(--su-b-500); outline-offset: 2px; }
.su-mod-visibility {
  border: none; background: transparent; padding: 6px; line-height: 1; cursor: pointer;
  border-radius: var(--su-radius-sm); color: var(--su-n-400); display: inline-flex;
  align-items: center; justify-content: center; justify-self: center; transition: transform .1s, background .1s;
}
.su-mod-visibility.is-on { color: var(--su-a-600); }
.su-mod-visibility .su-mod-visibility-on { display: none; }
.su-mod-visibility .su-mod-visibility-off { display: block; }
.su-mod-visibility.is-on .su-mod-visibility-on { display: block; }
.su-mod-visibility.is-on .su-mod-visibility-off { display: none; }
.su-mod-visibility:hover { transform: scale(1.12); background: var(--su-a-100); }
.su-mod-visibility:focus-visible { outline: 2px solid var(--su-a-500); outline-offset: 2px; }
.su-mod-visibility:disabled { cursor: wait; opacity: .55; }
.su-mod-group-visibility { width: 44px; height: 44px; }
@media (max-width: 640px) {
  .su-mod-opt-head { display: none; }
  .su-mod-group-form {
    display: grid; grid-template-columns: 54px repeat(3, minmax(0, 1fr));
    grid-template-areas: "sort name name name" "limits limits limits limits" ". eye save delete";
    align-items: end; gap: 8px;
  }
  .su-mod-group-form > .su-mod-sort-controls { grid-area: sort; }
  .su-mod-group-name { grid-area: name; min-width: 0; }
  .su-mod-group-limits { grid-area: limits; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  .su-mod-group-limits .su-input--num { width: 100%; }
  .su-mod-group-visibility { grid-area: eye; align-self: end; }
  .su-mod-group-save { grid-area: save; align-self: end; }
  .su-mod-group-delete { grid-area: delete; align-self: end; }

  .su-mod-opt-row {
    grid-template-columns: 54px repeat(3, minmax(0, 1fr));
    grid-template-areas: "sort name name name" "price price price price" "default eye save delete";
    gap: 8px; padding: var(--su-space-3) 0;
  }
  .su-mod-opt-row > .su-mod-sort-controls, .su-mod-sort-placeholder { grid-area: sort; }
  .su-mod-opt-name { grid-area: name; min-width: 0; }
  .su-mod-opt-price { grid-area: price; min-width: 0; }
  .su-mod-default { grid-area: default; }
  .su-mod-opt-visibility { grid-area: eye; }
  .su-mod-opt-save { grid-area: save; }
  .su-mod-opt-delete { grid-area: delete; }
  .su-mod-opt-row--create { grid-template-areas: "sort name name name" "price price add add"; }
  .su-mod-opt-add { grid-area: add; width: 100%; }
}

/* ---- быстрое скрытие (/admin/menu/quick, /staff/manager/menu) ---- */
.su-qm-section { border-radius: var(--su-radius-lg); overflow: hidden; box-shadow: var(--su-shadow-sm); margin-bottom: var(--su-space-3); }
.su-qm-section-head { display: flex; align-items: center; gap: var(--su-space-2); padding: var(--su-space-2) var(--su-space-3); background: var(--su-n-100); }
.su-qm-section-name { flex: 1; font-weight: 700; font-size: var(--su-fs-sm); }
.su-qm-section-body { background: var(--su-surface); }
.su-qm-section.is-hidden .su-qm-section-head .su-qm-section-name { opacity: .4; }
.su-qm-section.is-hidden .su-qm-section-body { opacity: .4; }
.su-qm-dish { display: flex; gap: var(--su-space-3); padding: var(--su-space-3); border-bottom: 1px solid var(--su-n-200); align-items: center; }
.su-qm-dish:last-child { border-bottom: none; }
.su-qm-dish.is-hidden .su-qm-dish-img, .su-qm-dish.is-hidden .su-qm-dish-noimg,
.su-qm-dish.is-hidden .su-qm-dish-name, .su-qm-dish.is-hidden .su-qm-dish-desc,
.su-qm-dish.is-hidden .su-qm-dish-price { opacity: .4; }
.su-qm-dish-img { width: 50px; height: 50px; flex: none; border-radius: var(--su-radius-md); object-fit: cover; }
.su-qm-dish-noimg { width: 50px; height: 50px; flex: none; border-radius: var(--su-radius-md); background: var(--su-n-200); }
.su-qm-dish-body { flex: 1; min-width: 0; }
.su-qm-dish-name { font-weight: 600; font-size: var(--su-fs-sm); }
.su-qm-dish-desc { color: var(--su-text-muted); font-size: var(--su-fs-caption); margin: 2px 0; }
.su-qm-price-row { display: flex; align-items: center; gap: var(--su-space-2); margin-top: 4px; flex-wrap: wrap; }
.su-qm-dish-price { font-weight: 700; font-size: var(--su-fs-sm); color: var(--su-a-700); }
.su-qm-limit-badge { font-size: var(--su-fs-caption); font-weight: 600; color: var(--su-cancel); background: var(--su-cancel-bg); border-radius: var(--su-radius-sm); padding: 2px 7px; }
.su-qm-ctrl { display: flex; gap: 6px; align-items: center; margin-left: auto; flex-shrink: 0; }
.su-qm-confirm { display: flex; gap: 6px; }

/* ============================================================
   НАСТРОЙКИ ВЛАДЕЛЬЦА (/admin/settings/*)
   Хаб-меню, карточки-секции форм, выбор шаблона, матрица маршрутизации,
   способы оплаты/провайдеры, панель сотрудника. Общий su-card/su-field/
   su-btn/su-checkbox-row переиспользуются, здесь — то, чего нет в примитивах.
   ============================================================ */

/* ---- вход/заявка на вход/онбординг (незалогинен, тема всегда broadsheet) ---- */
.su-login-box { max-width: 400px; margin: 8vh auto; background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-md); padding: var(--su-space-6) var(--su-space-5); }
@media (max-width: 480px) { .su-login-box { margin: var(--su-space-4) auto; padding: var(--su-space-5) var(--su-space-4); } }

/* ---- инструкции (push/pwa help) — карточки-платформы с нумерованными шагами ---- */
.su-ph-wrap { max-width: 560px; margin: 0 auto; }
.su-ph-intro { font-size: var(--su-fs-sm); color: var(--su-text-muted); margin-bottom: var(--su-space-4); line-height: 1.5; }
.su-ph-platform { background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm); margin-bottom: var(--su-space-3); overflow: hidden; }
.su-ph-platform-head { display: flex; align-items: center; gap: 10px; padding: var(--su-space-3) var(--su-space-4); background: var(--su-n-100); }
.su-ph-platform-icon { font-size: var(--su-fs-2xl); line-height: 1; flex: none; }
.su-ph-platform-title { font-weight: 700; font-size: var(--su-fs-base); }
.su-ph-platform-sub { font-size: var(--su-fs-caption); color: var(--su-text-muted); margin-top: 1px; }
.su-ph-steps { padding: var(--su-space-3) var(--su-space-4); display: flex; flex-direction: column; gap: 10px; }
.su-ph-step { display: flex; gap: 10px; align-items: flex-start; font-size: var(--su-fs-sm); line-height: 1.45; }
.su-ph-step-num {
  flex: none; width: 22px; height: 22px; background: var(--su-a-500); color: var(--su-on-primary);
  border-radius: var(--su-radius-round); font-size: var(--su-fs-caption); font-weight: 700;
  display: flex; align-items: center; justify-content: center; margin-top: 1px;
}
.su-ph-note { font-size: var(--su-fs-caption); color: var(--su-text-muted); padding: var(--su-space-3) var(--su-space-4) var(--su-space-3); border-top: 1px solid var(--su-n-200); line-height: 1.5; }
.su-ph-back { font-size: var(--su-fs-sm); color: var(--su-text-muted); display: block; margin-bottom: var(--su-space-4); }

/* ---- тикет-система "Идеи и поддержка" ---- */
.su-support-topic-btn { background: none; }
.su-support-topic-btn.is-active { background: var(--su-a-500); border-color: var(--su-a-500); color: var(--su-on-primary); }
.su-ticket-list { background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm); overflow: hidden; }
.su-ticket-row { display: flex; align-items: center; gap: 10px; padding: var(--su-space-3); border-bottom: 1px solid var(--su-n-200); text-decoration: none; color: var(--su-text); }
.su-ticket-row:last-child { border-bottom: none; }
.su-ticket-row:hover { background: var(--su-n-100); text-decoration: none; color: var(--su-text); }
.su-ticket-row-icon { font-size: var(--su-fs-lg); flex: none; }
.su-ticket-row-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.su-ticket-row-subject { font-weight: 600; }
.su-ticket-row-meta { font-size: var(--su-fs-caption); color: var(--su-text-muted); }
.su-ticket-status-open { color: var(--su-free); font-weight: 600; }
.su-ticket-status-closed { color: var(--su-text-muted); }
.su-ticket-thread { display: flex; flex-direction: column; gap: var(--su-space-2); margin-top: var(--su-space-2); }
.su-ticket-msg { max-width: 560px; padding: var(--su-space-2) var(--su-space-3); border-radius: var(--su-radius-lg); background: var(--su-surface); box-shadow: var(--su-shadow-sm); }
.su-ticket-msg--admin { background: var(--su-a-100); margin-right: auto; }
.su-ticket-msg--user { background: var(--su-n-100); margin-left: auto; }
.su-ticket-msg-author { font-size: var(--su-fs-caption); color: var(--su-text-muted); margin-bottom: 4px; }
.su-ticket-msg-body { white-space: pre-wrap; word-break: break-word; }

/* ---- хаб /admin/settings — список разделов ---- */
.su-hub-list { display: flex; flex-direction: column; background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm); overflow: hidden; }
/* Строка хаба — ДВЕ СТРОКИ: лейбл сверху, подпись под ним, стрелка справа по
   центру. Раньше лейбл и подпись стояли соседями в одной flex-строке, подпись
   была прижата вправо (text-align: right) — и на узком экране они тянули друг
   друга: «Столы, QR коды» ломалось на две строки, подпись наезжала.
   Двухстрочная раскладка снимает конкуренцию за ширину совсем. */
.su-hub-item {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  column-gap: var(--su-space-3); row-gap: 2px;
  min-height: 56px; padding: var(--su-space-3) var(--su-space-4);
  border-bottom: 1px solid var(--su-n-200);
  color: var(--su-text); text-decoration: none;
}
.su-hub-item:last-child { border-bottom: none; }
.su-hub-item:hover { background: var(--su-n-100); text-decoration: none; color: var(--su-text); }
.su-hub-label { font-weight: 600; font-size: var(--su-fs-base); display: flex; align-items: center; gap: 6px; min-width: 0; }
.su-hub-sub { grid-column: 1; font-size: var(--su-fs-sm); color: var(--su-text-muted); }
/* Стрелка строки хаба — SVG chevron-right (TASK-redesign.md 3.4). Символа ›
   в Golos Text нет, и он рисовался бы запасным шрифтом другого веса. */
.su-hub-arrow { grid-column: 2; grid-row: 1 / -1; color: var(--su-n-500); display: flex; align-items: center; }
.su-hub-item--locked { cursor: default; opacity: .6; }
.su-hub-item--locked:hover { background: none; }
.su-hub-section { margin-top: var(--su-space-5); }
.su-hub-section-title { font-size: var(--su-fs-sm); font-weight: 700; margin: 0 0 4px; display: flex; align-items: center; gap: 8px; }
.su-hub-section-sub { font-size: var(--su-fs-caption); color: var(--su-text-muted); margin: 0 0 var(--su-space-2); }
.su-hub-upsell { flex-direction: column; align-items: flex-start; gap: 6px; padding: var(--su-space-4); }
.su-hub-upsell .su-hub-sub { text-align: left; white-space: normal; margin: 0; }

/* ---- уведомление о push (карточка на /admin/settings) ---- */
.su-push-notice-row { display: flex; gap: var(--su-space-3); flex-wrap: wrap; justify-content: space-between; align-items: center; }

/* ---- секция формы настроек — карточка с заголовком ---- */
.su-settings-section { margin-bottom: var(--su-space-4); }
.su-settings-section h2 { font-family: var(--su-font-heading); font-weight: var(--su-font-heading-weight); font-size: var(--su-fs-base); margin: 0 0 var(--su-space-3); }
.su-settings-section--danger { border: 1px solid var(--su-cancel); }
.su-settings-section--danger h2 { color: var(--su-cancel); }
.su-account-qr-card { width: 100%; max-width: 480px; box-sizing: border-box; }
/* align-items: flex-end, а не center: в строке соседствуют голый инпут и
   поле с подписью (.su-field = колонка label + input, оно выше). При
   центрировании кнопка вставала по центру этой высоты — то есть визуально
   ВЫШЕ поля ввода, рядом с подписью. Выравнивание по низу ставит кнопку на
   одну линию с инпутом, как и ожидается. */
.su-settings-form-row { display: flex; gap: var(--su-space-2); align-items: flex-end; flex-wrap: wrap; }
.su-settings-form-row .su-input { flex: 1; min-width: 200px; }
/* Поле с подписью внутри строки формы: правило выше достаёт до голого
   .su-input, но не до инпута, обёрнутого в .su-field (там своя колонка
   label + input) — расти должна обёртка. */
.su-settings-form-row .su-field { flex: 1 1 220px; min-width: 0; }

/* ---- переключатель вкладок QR (столы / онлайн-меню) ---- */
.su-qr-tabs { display: flex; gap: var(--su-space-2); margin-bottom: var(--su-space-4); flex-wrap: wrap; }
.su-qr-tab {
  flex: 1 1 200px; display: flex; align-items: center; gap: var(--su-space-2);
  padding: var(--su-space-3); border-radius: var(--su-radius-lg); border: 2px solid var(--su-n-300);
  background: var(--su-surface); cursor: pointer; text-align: left; color: var(--su-text); font: inherit;
}
.su-qr-tab:hover { border-color: var(--su-n-400); }
/* Активная вкладка: на светлой подложке --su-a-100 цвет текста обязан быть
   задан явно. Без этого в тёмных темах он наследует светлый --su-text и
   пропадает на светлом фоне — проверено на nocturne. */
.su-qr-tab.is-active { border-color: var(--su-a-500); background: var(--su-a-100); color: var(--su-a-900); }
.su-qr-tab.is-active .su-qr-tab-sub { color: var(--su-a-700); }
.su-qr-tab-icon { font-size: var(--su-fs-xl); line-height: 1; flex: none; }
.su-qr-tab-label { font-weight: 700; font-size: var(--su-fs-sm); display: flex; flex-direction: column; gap: 2px; }
.su-qr-tab-sub { font-weight: 400; font-size: var(--su-fs-caption); color: var(--su-text-muted); }

/* ---- сетка QR-карточек столов ---- */
.su-tables-qr-grid { display: flex; flex-wrap: wrap; gap: var(--su-space-3); justify-content: center; }
.su-table-qr-card { background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm); padding: var(--su-space-3); width: 220px; display: flex; flex-direction: column; gap: var(--su-space-2); }
.su-table-qr-print { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; }
.su-table-qr-print canvas { max-width: 100%; height: auto; }
.su-table-qr-actions { display: flex; flex-direction: column; gap: 6px; }

/* Витрина: одиночный QR «меню без заказа» по центру секции. Один блок на
   /admin/settings/tables и /staff/qr-codes — раньше он был размечен инлайном
   в обеих вьюхах, и стили успели разойтись (в staff-версии был display:flex,
   в admin — нет). */
.su-qr-showcase { display: flex; flex-direction: column; align-items: center; text-align: center; }
.su-table-qr-card--showcase { width: auto; max-width: 280px; margin-left: auto; margin-right: auto; }
.su-table-copy-row { display: flex; gap: 6px; align-items: center; }
.su-table-copy-input { flex: 1; min-width: 0; font-size: var(--su-fs-caption); border: 1px solid var(--su-n-300); border-radius: var(--su-radius-sm); padding: 6px 8px; background: var(--su-bg); color: var(--su-text-muted); }
.su-table-copy-btn {
  flex: none; width: 30px; height: 30px; border-radius: var(--su-radius-sm); border: 1px solid var(--su-n-300);
  background: var(--su-surface); color: var(--su-text-muted); cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.su-table-copy-btn:hover { color: var(--su-a-600); border-color: var(--su-a-500); }
.su-table-copy-btn.is-copied { color: var(--su-free); border-color: var(--su-free); }

/* ---- выбор шаблона оформления (цвет/дизайн меню) ---- */
.su-tpl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: var(--su-space-3); margin-bottom: var(--su-space-4); }
.su-tpl-card {
  position: relative; display: flex; flex-direction: column; gap: 6px; padding: var(--su-space-2);
  border: 2px solid var(--su-n-300); border-radius: var(--su-radius-lg); cursor: pointer; background: var(--su-surface);
}
.su-tpl-card input[type=radio] { position: absolute; opacity: 0; pointer-events: none; }
.su-tpl-card:has(input:checked) { border-color: var(--su-a-500); background: var(--su-a-100); }
.su-tpl-card.is-locked { opacity: .5; cursor: default; }
.su-tpl-preview { display: block; height: 56px; border-radius: var(--su-radius-md); border: 1px solid var(--su-n-300); background: var(--su-n-200); }
.su-tpl-preview--dark { background: #0f1420; border-color: #f59e0b; }

/* ЦВЕТА ТЕМ МЕНЮ — классом по id темы, а не сгенерированным style.
   Значения продублированы из menu_templates.css_vars (--bg и --accent).

   ⚠️ Дубль осознанный: тема выбирается на /admin/settings/cafe владельцем,
   а правится на /alien8admin/templates суперадмином, и хранить её палитру
   в БД всё равно надо — превью же нужно всего два цвета из неё.
   Инлайн тут был бы честнее по «единому источнику», но под строгим CSP
   он запрещён, а <style> на каждую из 17 тем — 17 блоков на странице.

   ⚠️ НОВАЯ ТЕМА КЛАССА НЕ ПОЛУЧИТ, и её превью будет пустым.
   Добавив тему в /alien8admin/templates, допиши сюда строку с её id
   (подсказка об этом висит на самой странице шаблонов). */
.su-tpl-preview--t1  { background: #FAFAF8; border-color: #111110; } /* Material */
.su-tpl-preview--t2  { background: #ffffff; border-color: #2563eb; } /* Светлая */
.su-tpl-preview--t3  { background: #f2f9ff; border-color: #f59e0b; } /* Лето */
.su-tpl-preview--t5  { background: #0f1420; border-color: #f59e0b; } /* Тёмная */
.su-tpl-preview--t10 { background: #1b140f; border-color: #d99a4e; } /* Эспрессо */
.su-tpl-preview--t11 { background: #161217; border-color: #ec6f9b; } /* Сакура */
.su-tpl-preview--t12 { background: #0e1714; border-color: #2fd693; } /* Мята */
.su-tpl-preview--t13 { background: #faf6f1; border-color: #c0392b; } /* Марсель */
.su-tpl-preview--t14 { background: #0b0b16; border-color: #8b5cf6; } /* Неон */
.su-tpl-preview--t15 { background: #1a0f0c; border-color: #ff7a45; } /* Закат */
.su-tpl-preview--t16 { background: #f8f5f0; border-color: #c9824a; } /* Молоко */
.su-tpl-preview--t17 { background: #fffdf2; border-color: #e0a300; } /* Лимон */
.su-tpl-preview--t18 { background: #f6f3fa; border-color: #8b5cf6; } /* Лаванда */
.su-tpl-preview--t19 { background: #f1f6fa; border-color: #0d7fb8; } /* Морская */
.su-tpl-preview--t20 { background: #f4f6ef; border-color: #6b8c3a; } /* Оливка */
.su-tpl-preview--t21 { background: #14161a; border-color: #4f9dde; } /* Графит */
.su-tpl-preview--cards { background: linear-gradient(135deg, var(--su-a-100) 50%, var(--su-a-200) 50%); border-color: var(--su-a-600); }
.su-tpl-preview--page_menu_showcase { background: repeating-linear-gradient(90deg, transparent 0 28%, var(--su-surface) 28% 36%), linear-gradient(var(--su-a-100) 65%, var(--su-surface) 65%); border-color: var(--su-n-300); }
.su-tpl-preview--page_menu_editorial { background: linear-gradient(90deg, transparent 46%, var(--su-surface) 46% 54%, transparent 54%), linear-gradient(165deg, var(--su-a-200) 45%, var(--su-surface) 45% 60%, var(--su-a-100) 60%); border-color: var(--su-n-300); }
.su-tpl-preview--page_menu_list_plain { background: repeating-linear-gradient(180deg, var(--su-surface) 0 10px, var(--su-n-300) 10px 11px); border-color: var(--su-n-300); }
.su-tpl-preview--page_menu_bento { background: linear-gradient(90deg, var(--su-a-600) 0 58%, var(--su-surface) 58% 62%, transparent 62%), linear-gradient(180deg, var(--su-a-200) 0 46%, var(--su-surface) 46% 54%, var(--su-a-100) 54%); border-color: var(--su-n-300); }
.su-tpl-name { font-size: var(--su-fs-caption); font-weight: 600; color: var(--su-text); display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.su-tpl-pencil {
  position: absolute; top: 6px; right: 6px; width: 24px; height: 24px; border-radius: var(--su-radius-round);
  border: 1px solid var(--su-n-300); background: var(--su-surface); color: var(--su-text-muted);
  font-size: var(--su-fs-caption); cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.su-tpl-pencil:hover { background: var(--su-n-200); }
.su-color-picker { display: flex; flex-wrap: wrap; gap: var(--su-space-3); margin-top: var(--su-space-2); }
.su-color-picker-item { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.su-color-picker-item input[type=color] { width: 44px; height: 44px; padding: 2px; border-radius: var(--su-radius-md); border: 2px solid var(--su-n-300); cursor: pointer; background: none; }
.su-color-picker-item span { font-size: var(--su-fs-caption); color: var(--su-text-muted); text-align: center; max-width: 60px; line-height: 1.2; }

/* ---- Pro-заглушка (замочек) ---- */
.su-pro-gate-locked { position: relative; }
.su-pro-gate-locked > * { pointer-events: none; filter: blur(2px); opacity: .5; user-select: none; }
.su-pro-gate-tooltip {
  position: absolute; bottom: calc(100% + 6px); left: 0; background: var(--su-n-900); color: var(--su-on-primary);
  font-size: var(--su-fs-caption); padding: 8px 12px; border-radius: var(--su-radius-md); z-index: 200; pointer-events: auto;
  box-shadow: var(--su-shadow-lg);
}
.su-pro-gate-tooltip a { color: var(--su-a-300); }

/* ---- матрица маршрутизации (станции × статусы) ---- */
.su-routing-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm); }
.su-routing-table { border-collapse: collapse; width: 100%; font-size: var(--su-fs-caption); }
.su-routing-table th, .su-routing-table td { border: 1px solid var(--su-n-200); padding: 6px 8px; text-align: center; }
.su-routing-table thead th { background: var(--su-n-100); font-weight: 600; font-size: var(--su-fs-caption); white-space: nowrap; }
.su-routing-corner { text-align: left; vertical-align: bottom; }
.su-routing-subhead { font-weight: 500; font-size: var(--su-fs-caption); color: var(--su-text-muted); min-width: 34px; }
.su-routing-subhead svg { width: 15px; height: 15px; }
.su-routing-row-label { text-align: left; font-weight: 600; white-space: nowrap; }
.su-routing-zone-row td { background: var(--su-n-100); font-weight: 700; font-size: var(--su-fs-caption); padding: 6px 10px; }
.su-routing-zone-row--plain td { font-size: var(--su-fs-caption); color: var(--su-text-muted); font-weight: 500; text-align: left; }
.su-routing-zone-row[data-zone-toggle] { cursor: pointer; }
.su-routing-zone-row[data-zone-toggle]:hover td { background: var(--su-a-100); }
.su-routing-zone-row .su-zone-chevron { display: inline-block; transition: transform .15s; color: var(--su-text-muted); }
.su-routing-zone-row.is-open .su-zone-chevron { transform: rotate(90deg); }
.su-routing-table-row.is-collapsed { display: none; }
.su-routing-cell { width: 34px; }
.su-routing-icon-btn {
  border: none; background: none; padding: 3px; line-height: 1; cursor: pointer; border-radius: var(--su-radius-sm);
  color: var(--su-n-400); display: inline-flex; transition: transform .1s;
}
.su-routing-icon-btn svg { width: 18px; height: 18px; display: block; }
.su-routing-icon-btn .su-routing-icon-on, .su-routing-icon-btn .su-routing-icon-level-1,
.su-routing-icon-btn .su-routing-icon-level-2, .su-routing-icon-btn .su-routing-icon-level-3 { display: none; }
.su-routing-icon-btn .su-routing-icon-off, .su-routing-icon-btn .su-routing-icon-level-0 { display: block; }
.su-routing-icon-btn.is-on .su-routing-icon-on { display: block; }
.su-routing-icon-btn.is-on .su-routing-icon-off { display: none; }
.su-routing-icon-btn.is-on { color: var(--su-a-600); }
.su-routing-icon-btn.is-level-1 .su-routing-icon-level-0 { display: none; } .su-routing-icon-btn.is-level-1 .su-routing-icon-level-1 { display: block; color: var(--su-a-600); }
.su-routing-icon-btn.is-level-2 .su-routing-icon-level-0 { display: none; } .su-routing-icon-btn.is-level-2 .su-routing-icon-level-2 { display: block; color: var(--su-a-600); }
.su-routing-icon-btn.is-level-3 .su-routing-icon-level-0 { display: none; } .su-routing-icon-btn.is-level-3 .su-routing-icon-level-3 { display: block; color: var(--su-a-600); }
.su-routing-icon-btn.is-partial { color: var(--su-a-400); opacity: .6; }
.su-routing-icon-btn:hover:not(:disabled) { transform: scale(1.15); }
.su-routing-icon-btn:disabled { opacity: .3; cursor: not-allowed; }
.su-routing-table tbody tr:hover td { background: var(--su-a-100); }
.su-routing-table tbody tr:hover td.su-routing-row-label { font-weight: 700; }
.su-routing-table td.is-col-hover, .su-routing-table th.is-col-hover { background: var(--su-a-100); }

/* ---- карточка станции / зоны (список настроек маршрутизации) ---- */
.su-routing-card { border-radius: var(--su-radius-md); padding: var(--su-space-2) var(--su-space-3); margin-bottom: 8px; border: 1px solid var(--su-n-300); background: var(--su-surface); }
/* Включённая станция — ОБЫЧНАЯ карточка, без заливки: включённость здесь
   норма, а цветом метится исключение. Зелёная заливка на всех станциях разом
   делала список нечитаемым и ничего не сообщала — состояние и так видно по
   кнопке «Выключить»/«Включить». Выключенная притушена — вот она и есть
   отклонение от нормы. */
.su-routing-card.is-disabled { background: var(--su-n-100); opacity: .6; }
.su-routing-card.is-disabled .su-routing-card-title { color: var(--su-text-muted); }
.su-routing-card-head { display: flex; align-items: center; gap: var(--su-space-2); flex-wrap: wrap; }
.su-routing-card-head form { margin: 0; }
/* Форма переименования внутри карточки: занимает всю свободную ширину рядом
   с кнопками действий, инпут внутри растягивается на неё. */
.su-routing-rename-form { flex: 1; display: flex; gap: var(--su-space-2); align-items: center; min-width: 0; }
.su-routing-rename-form .su-routing-card-title { flex: 1; min-width: 0; }

/* ---- карточка станции ----
   Компактная строка: имя + иконки действий. Раньше здесь стояли три текстовые
   кнопки («Сохранить», «Выключить», «Удалить») и постоянно открытый инпут —
   на три станции это давало стену кнопок, в которой само название терялось.
   Инпут появляется только на время правки (js-station-edit). */
/* Сетка станций: на широком экране карточки идут в несколько колонок, а не
   тянутся на всю ширину. Станция — короткая строка «имя + три иконки», и
   растянутая на планшет она давала метр пустоты между названием и кнопками.
   auto-fill + minmax: число колонок считает браузер, при сужении сетка сама
   схлопывается в одну — без брейкпоинтов на каждый размер. */
#stationsList { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: var(--su-space-2); align-items: start; }
/* margin-bottom от .su-routing-card в сетке лишний — расстояние держит gap. */
#stationsList .su-routing-card { margin-bottom: 0; }
.su-station-name { font-weight: 600; color: var(--su-text); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.su-station-actions { display: flex; align-items: center; gap: var(--su-space-1); flex: none; }
.su-station-actions form { margin: 0; display: flex; }
.su-station-rename-form { display: flex; gap: var(--su-space-2); align-items: center; margin-top: var(--su-space-2); }
.su-station-rename-form .su-input { flex: 1; min-width: 0; }
.su-routing-card-title { font-weight: 600; border: 1px solid var(--su-n-300); border-radius: var(--su-radius-sm); padding: 4px 8px; background: var(--su-surface); color: var(--su-text); font: inherit; }
.su-zone-card-head { display: flex; align-items: center; gap: var(--su-space-2); }
.su-zone-chevron { display: inline-block; color: var(--su-text-muted); transition: transform .15s; flex: none; }
.su-zone-card-head.is-open .su-zone-chevron { transform: rotate(90deg); }
.su-zone-card-body { margin-top: var(--su-space-2); padding-top: var(--su-space-2); border-top: 1px solid var(--su-n-300); }
/* Заголовок зоны — СВОЙ класс, а не .su-routing-card-title: тот стилизует
   ИНПУТ переименования (рамка, паддинг, фон), и на заголовке его приходилось
   гасить инлайном (border:none;padding:0;background:none). Плюс здесь нужен
   flex-контейнер: три вложенных span (имя, счётчик, список столов) в inline-
   потоке падали в столбик, потому что flex:1 на не-флексе не работает. */
.su-zone-card-title {
  display: flex; align-items: baseline; gap: var(--su-space-2); flex-wrap: wrap;
  flex: 1; min-width: 0; font-weight: 600; color: var(--su-text); cursor: pointer;
}
/* Список столов зоны — вторичен рядом с именем и счётчиком: длинный перечень
   не должен спорить с названием за внимание. */
.su-zone-card-tables { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Форма переименования зоны — раскрывается вместо заголовка. */
.su-zone-rename-form { display: flex; gap: var(--su-space-2); }
.su-zone-table-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.su-zone-table-chip {
  border-radius: var(--su-radius-pill); padding: 4px 12px; border: 1px solid var(--su-n-300); background: var(--su-surface);
  color: var(--su-text); cursor: pointer; font-size: var(--su-fs-caption); font: inherit;
}
.su-zone-table-chip.is-on { background: var(--su-a-500); color: var(--su-on-primary); border-color: var(--su-a-500); }
.su-zone-table-chip:disabled { opacity: .5; cursor: not-allowed; }

/* ---- способы оплаты / провайдеры (/admin/settings/payments) ---- */
.su-pay-row { background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm); padding: var(--su-space-3); display: flex; flex-direction: column; gap: var(--su-space-3); margin-bottom: 8px; }
.su-pay-row-main { display: flex; flex-direction: column; gap: 8px; }
.su-pay-row-main .su-input { margin: 0; }
.su-pay-row-flags { display: flex; flex-wrap: wrap; gap: 8px 18px; font-size: var(--su-fs-sm); }
.su-pay-row-flags label { display: flex; align-items: center; gap: 6px; cursor: pointer; }
.su-pay-row-flags input[type=checkbox] { width: auto; margin: 0; }
.su-pay-row-actions { display: flex; gap: 8px; }
.su-pay-reallocation-row { flex-direction: row; align-items: center; }
.su-pay-reallocation-row .su-checkbox-row { flex: 1; min-width: 0; }
.su-pay-reallocation-feedback { flex: none; margin-left: auto; }
.su-pay-reallocation-feedback[data-state="saved"] { color: var(--su-free); }
.su-pay-reallocation-feedback[data-state="error"] { color: var(--su-cancel); }
.su-pay-row-del { text-align: right; margin: -4px 0 8px; }
.su-pay-row-del button { background: none; border: none; color: var(--su-cancel); font: inherit; font-size: var(--su-fs-caption); cursor: pointer; padding: 4px; }
.su-pay-row-del button:hover { color: var(--su-cancel); }
.su-pay-row--provider .su-pay-row-main { gap: 2px; flex-direction: row; align-items: center; flex-wrap: wrap; }
.su-prov-name { font-weight: 700; }
.su-prov-kind { font-size: var(--su-fs-caption); color: var(--su-text-muted); }
.su-prov-badge { display: inline-flex; align-items: center; font-size: var(--su-fs-caption); padding: 2px 8px; border-radius: var(--su-radius-sm); border: 1px solid var(--su-n-300); color: var(--su-text-muted); }
.su-prov-badge--on { color: var(--su-free); border-color: var(--su-free); }
.su-prov-badge--fiscal { color: var(--su-a-600); border-color: var(--su-a-600); }
.su-pay-add summary { cursor: pointer; font-weight: 600; color: var(--su-a-700); padding: var(--su-space-2) 0; }

/* Сворачиваемый блок формы: поле нужно не всем и не всегда, но убрать его
   совсем нельзя — значения внутри <details> браузер отправляет независимо от
   того, раскрыт он или нет, поэтому свернуть безопасно, а скрыть — уже нет
   (пустой POST стёр бы сохранённое). Сейчас так живут станции в форме блюда:
   вне режима «Команда» они не работают. */
.su-fold > summary {
  cursor: pointer; font-weight: 600; color: var(--su-text);
  padding: var(--su-space-2) 0; list-style: none;
}
.su-fold > summary::-webkit-details-marker { display: none; }
/* Треугольник рисуем сами: нативный маркер по-разному выглядит в браузерах и
   не поддаётся окраске темой. */
.su-fold > summary::before {
  content: '▸'; display: inline-block; width: 1em;
  color: var(--su-text-muted); transition: transform .15s ease;
}
.su-fold[open] > summary::before { transform: rotate(90deg); }
.su-fold > summary .su-fold-note { font-weight: 500; color: var(--su-text-muted); }

/* ---- диагностика провайдера (АТОЛ) ---- */
.su-prov-testbar { background: var(--su-cooking-bg); color: var(--su-cooking); border-radius: var(--su-radius-md); padding: var(--su-space-3); font-weight: 600; margin-bottom: var(--su-space-4); }
.su-prov-subhead { margin: var(--su-space-5) 0 var(--su-space-2); font-size: var(--su-fs-sm); font-weight: 700; }
.su-prov-check { border: 1px solid var(--su-n-300); border-radius: var(--su-radius-md); padding: var(--su-space-3); margin-top: var(--su-space-3); }
.su-prov-check--ok { border-color: var(--su-free); }
.su-prov-check--err { border-color: var(--su-cancel); }
.su-prov-check-err { margin-top: 4px; color: var(--su-cancel); font-size: var(--su-fs-caption); }
.su-prov-check-meta { margin-top: 6px; font-size: var(--su-fs-caption); color: var(--su-text-muted); word-break: break-all; }
.su-prov-queue { list-style: none; padding: 0; margin: 0; font-size: var(--su-fs-sm); }
.su-prov-queue li { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid var(--su-n-200); }
.su-prov-queue li:last-child { border-bottom: none; }
.su-prov-queue--bad b { color: var(--su-cancel); }
.su-prov-problems { list-style: none; padding: 0; margin: 0; }
.su-prov-problem { background: var(--su-cancel-bg); border-radius: var(--su-radius-md); padding: var(--su-space-3); margin-bottom: 8px; }
.su-prov-problem-head { display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap; font-size: var(--su-fs-sm); }
.su-prov-problem-status { color: var(--su-cancel); font-size: var(--su-fs-caption); font-weight: 600; }
.su-prov-problem-err { margin-top: 6px; color: var(--su-cancel); font-size: var(--su-fs-caption); word-break: break-word; }
.su-prov-problem-meta { margin-top: 6px; font-size: var(--su-fs-caption); color: var(--su-text-muted); word-break: break-all; }
.su-prov-problem-retry { margin-top: 8px; }
.su-prov-exch { list-style: none; padding: 0; margin: 0; }
.su-prov-exch-row { border-bottom: 1px solid var(--su-n-200); }
.su-prov-exch-row summary { display: flex; gap: var(--su-space-2); flex-wrap: wrap; align-items: center; padding: var(--su-space-2) 0; cursor: pointer; }
.su-prov-exch-op { font-weight: 600; font-size: var(--su-fs-sm); }
.su-prov-exch-time, .su-prov-exch-code { color: var(--su-text-muted); font-size: var(--su-fs-caption); }
.su-prov-exch-row--bad .su-prov-exch-op, .su-prov-exch-row--bad .su-prov-exch-code { color: var(--su-cancel); }
.su-prov-exch-body { padding: 4px 0 var(--su-space-3); }
.su-prov-exch-url { font-size: var(--su-fs-caption); color: var(--su-text-muted); word-break: break-all; }
.su-prov-exch-err { margin-top: 6px; color: var(--su-cancel); font-size: var(--su-fs-caption); }
.su-prov-exch-label { margin-top: 10px; font-size: var(--su-fs-caption); color: var(--su-text-muted); }
.su-prov-exch-pre { background: var(--su-n-100); border-radius: var(--su-radius-sm); padding: var(--su-space-2); font-size: var(--su-fs-caption); overflow-x: auto; white-space: pre-wrap; word-break: break-all; color: var(--su-text); }

/* ---- панель сотрудника (slide-over, /admin/settings/staff-access) ---- */
.su-staff-panel-backdrop { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.3); z-index: 40; }
.su-staff-panel-backdrop.open { display: block; }
.su-staff-panel {
  position: fixed; top: 0; right: 0; height: 100%; width: min(480px, 100%);
  background: var(--su-surface); box-shadow: var(--su-shadow-lg);
  transform: translateX(100%); transition: transform .2s ease;
  z-index: 41; overflow-y: auto; padding: var(--su-space-4);
}
.su-staff-panel.open { transform: translateX(0); }
body.su-staff-panel-open { overflow: hidden; }
@media (max-width: 640px) { .su-staff-panel { width: 100%; } }
.su-staff-panel-header { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.su-staff-panel-header h2 { margin: 0; font-size: var(--su-fs-lg); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.su-staff-panel-close { width: 32px; height: 32px; flex: none; border: none; background: none; cursor: pointer; color: var(--su-text-muted); font-size: var(--su-fs-lg); display: flex; align-items: center; justify-content: center; border-radius: var(--su-radius-round); }
.su-staff-panel-close:hover { background: var(--su-n-200); color: var(--su-text); }
.su-staff-name-row { display: flex; align-items: center; gap: 8px; margin-bottom: var(--su-space-4); flex-wrap: wrap; }
.su-staff-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--su-n-300); margin-bottom: var(--su-space-4); }
.su-staff-tab-btn { padding: 8px 14px; font-size: var(--su-fs-caption); font-weight: 600; color: var(--su-text-muted); background: none; border: none; border-bottom: 2px solid transparent; cursor: pointer; font-family: inherit; }
.su-staff-tab-btn.is-active { color: var(--su-a-600); border-bottom-color: var(--su-a-500); }
.su-staff-tabpanel { display: none; }
.su-staff-tabpanel.is-active { display: block; }
.su-staff-stations-row { display: flex; flex-wrap: wrap; gap: 8px; }
.su-staff-station-chip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; border-radius: var(--su-radius-pill); font-size: var(--su-fs-caption); cursor: pointer; border: 1px solid var(--su-n-300); background: var(--su-surface); color: var(--su-text); }
.su-staff-station-chip input { margin: 0; }
.su-staff-station-chip.is-saving { opacity: .6; }
.staff-tables-block { display: flex; flex-direction: column; }
.su-staff-tables-zone-row { display: flex; align-items: center; gap: 8px; cursor: pointer; margin-bottom: 6px; font-size: var(--su-fs-caption); font-weight: 600; }
.su-staff-tables-zone-label { color: var(--su-text-muted); }
.su-staff-pencil { width: 28px; height: 28px; border-radius: var(--su-radius-sm); flex: none; border: 1px solid var(--su-n-300); background: var(--su-surface); cursor: pointer; font-size: var(--su-fs-sm); display: flex; align-items: center; justify-content: center; color: var(--su-text-muted); }
.su-staff-pencil:hover { background: var(--su-n-200); }
.su-staff-name-input { flex: 1; min-width: 120px; max-width: 260px; }
.su-staff-col-qr { display: flex; flex-direction: column; align-items: flex-start; }

/* ---- список сотрудников (компактные строки со slide-over) ---- */
.su-staff-list-toolbar { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: var(--su-space-3); }
.su-staff-list { background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm); overflow: hidden; margin-bottom: var(--su-space-4); }
.su-staff-list-head, .su-staff-list-row { display: grid; grid-template-columns: 1fr 1.2fr 1.2fr auto; align-items: center; gap: var(--su-space-2); padding: var(--su-space-2) var(--su-space-3); }
.su-staff-list-head { border-bottom: 1px solid var(--su-n-300); }
.su-staff-list-sort-btn { background: none; border: none; text-align: left; font-size: var(--su-fs-caption); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--su-text-muted); cursor: pointer; font-family: inherit; padding: 0; }
.su-staff-list-row { width: 100%; border: none; border-bottom: 1px solid var(--su-n-200); background: none; cursor: pointer; text-align: left; font: inherit; color: var(--su-text); }
.su-staff-list-row:last-child { border-bottom: none; }
.su-staff-list-row:hover { background: var(--su-n-100); }
.su-staff-list-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.su-staff-list-stations, .su-staff-list-zones { font-size: var(--su-fs-caption); color: var(--su-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.su-staff-list-arrow { color: var(--su-text-muted); font-size: var(--su-fs-lg); justify-self: end; }

/* ---- группы прав сотрудника (Заказы/Деньги/Меню/Управление/История) ---- */
.su-perm-group { margin-bottom: var(--su-space-4); }
.su-perm-group-title { font-size: var(--su-fs-caption); font-weight: 700; color: var(--su-text-muted); text-transform: uppercase; letter-spacing: .04em; margin-bottom: 8px; }
.su-perm-group-items { display: flex; flex-direction: column; gap: 8px; }

/* ============================================================
   ОТЧЁТЫ ВЛАДЕЛЬЦУ (/admin/reports/*)
   Единственный владельческий раздел на этой дизайн-системе — layout.php
   подключает staff-ui.css по флагу $useStaffUi, тема берётся кафейная.
   Всё ниже — только то, чего НЕТ в общих su-* примитивах: KPI-плитки,
   CSS-бары графика (в проекте нет JS-библиотек графиков и не заводим),
   суб-навигация раздела. Карточки/таблицы/кнопки/теги переиспользуются.
   ============================================================ */

/* ---- суб-навигация раздела (Выручка / Блюда / Сотрудники / ...) ---- */
.su-rep-nav {
  display: flex; gap: var(--su-space-1); overflow-x: auto; margin-bottom: var(--su-space-4);
  padding-bottom: 2px; -webkit-overflow-scrolling: touch;
}
.su-rep-nav::-webkit-scrollbar { display: none; }
.su-rep-nav-item {
  flex: none; padding: 7px 14px; border-radius: var(--su-radius-pill); font-size: var(--su-fs-sm); font-weight: 500;
  background: var(--su-n-200); color: var(--su-text-muted); text-decoration: none; white-space: nowrap;
}
.su-rep-nav-item .su-tag-plan { vertical-align: middle; }
.su-rep-nav-item:hover { text-decoration: none; color: var(--su-text); }
.su-rep-nav-item.is-active { background: var(--su-a-600); color: var(--su-on-primary); }
.su-rep-nav-item.is-active:hover { color: var(--su-on-primary); }

/* ---- выбор периода: пресеты + свои даты ----
   Все контролы строки (поля дат, кнопка, пилюли-пресеты) держатся на ОДНОЙ
   высоте --su-rep-ctl-h.

   ⚠️ Поле даты НЕ описывать через flex — .su-rep-period-field это
   flex-direction: column, у него главная ось ВЕРТИКАЛЬНАЯ, и flex-basis
   на вложенном .su-input задаёт не ширину, а высоту (поле вытягивается
   в столбик выше кнопок). Ширина — только width, высота — только height. */
.su-rep-period { --su-rep-ctl-h: 38px; display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--su-space-2); margin-bottom: var(--su-space-4); }
.su-rep-period-presets { display: flex; gap: var(--su-space-1); flex-wrap: wrap; align-items: flex-end; }
.su-rep-period .su-input {
  flex: none; width: 150px; max-width: 100%; font-size: var(--su-fs-sm);
  height: var(--su-rep-ctl-h); padding: 0 10px; line-height: normal;
}
.su-rep-period .su-btn { flex: none; height: var(--su-rep-ctl-h); padding: 0 18px; }
.su-rep-period .su-rep-nav-item { display: inline-flex; align-items: center; height: var(--su-rep-ctl-h); padding: 0 14px; }
.su-rep-period-field { display: flex; flex-direction: column; gap: 3px; }
.su-rep-period-field label { font-size: var(--su-fs-caption); text-transform: uppercase; letter-spacing: .04em; color: var(--su-text-muted); font-weight: 600; }

/* ---- KPI-плитки: сетка, а не flex — цифры разной длины не должны прыгать ---- */
.su-rep-kpis {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--su-space-3); margin-bottom: var(--su-space-5);
}
.su-rep-kpi {
  background: var(--su-surface); border-radius: var(--su-radius-lg); box-shadow: var(--su-shadow-sm);
  padding: var(--su-space-3) var(--su-space-4); display: flex; flex-direction: column; gap: 4px;
}
.su-rep-kpi-label { font-size: var(--su-fs-caption); letter-spacing: .05em; text-transform: uppercase; color: var(--su-text-muted); font-weight: 600; }
.su-rep-kpi-value {
  font-family: var(--su-font-heading); font-size: var(--su-fs-xl); font-weight: 700;
  font-variant-numeric: tabular-nums; line-height: 1.15;
}
.su-rep-kpi-sub { font-size: var(--su-fs-caption); color: var(--su-text-muted); }
/* Чистая выручка — главная цифра раздела, выделяется акцентом темы. */
.su-rep-kpi--accent .su-rep-kpi-value { color: var(--su-a-700); }
.su-rep-kpi--muted .su-rep-kpi-value { color: var(--su-text-muted); font-size: var(--su-fs-lg); }

/* ---- график по дням: горизонтальные бары на чистом CSS ---- */
.su-rep-chart { display: flex; flex-direction: column; gap: var(--su-space-2); }
.su-rep-bar-row { display: grid; grid-template-columns: 78px 1fr auto; align-items: center; gap: var(--su-space-2); font-size: var(--su-fs-caption); }
.su-rep-bar-day { color: var(--su-text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Полоса дня — инлайновый SVG (App\Chart::barRow), а не <span> с width в %:
   ширина полосы вычисляется из данных, и в HTML это был бы style="width:42%",
   то есть инлайн-стиль, который режет CSP. Атрибут width у SVG-элемента
   к style-src не относится.

   Внутри две полосы друг на друге: оборот (бледная) и чистая выручка (акцент) —
   видно, какую долю дня съела скидка. */
.su-chart-bar { display: block; height: 22px; }
.su-chart-track    { fill: var(--su-n-200); }
.su-chart-bar-main { fill: var(--su-a-200); }
.su-chart-bar-sub  { fill: var(--su-a-500); }
.su-rep-bar-sum { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; min-width: 90px;}
.su-rep-legend { display: flex; flex-wrap: wrap; gap: var(--su-space-3); font-size: var(--su-fs-caption); color: var(--su-text-muted); margin-top: var(--su-space-3); }
.su-rep-legend-item { display: flex; align-items: center; gap: 6px; }
.su-rep-legend-swatch { width: 12px; height: 12px; border-radius: 2px; flex: none; }
.su-rep-legend-swatch--turnover { background: var(--su-a-200); }
.su-rep-legend-swatch--revenue { background: var(--su-a-500); }

/* ---- таблицы отчётов: числовые колонки вправо, моноширинные цифры ---- */
.su-rep-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.su-rep-table-wrap .su-table { min-width: 460px; }
.su-table td.su-num, .su-table th.su-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.su-table td.su-num-strong { font-weight: 700; }
.su-rep-muted-cell { color: var(--su-text-muted); }

/* ---- полоска доли внутри таблицы (топ блюд, способы оплаты) ----
   Тоже SVG (App\Chart::share): ширина считается из данных. */
.su-chart-share { display: block; height: 4px; margin-top: 4px; }
.su-chart-share-fill { fill: var(--su-a-400); }

/* ---- тайминги: цепочка этапов ---- */
.su-rep-stage-chain { display: flex; flex-wrap: wrap; gap: var(--su-space-2); }
.su-rep-stage {
  flex: 1 1 110px; background: var(--su-n-100); border-radius: var(--su-radius-md);
  padding: var(--su-space-2) var(--su-space-3); display: flex; flex-direction: column; gap: 2px;
}
.su-rep-stage-name { font-size: var(--su-fs-caption); text-transform: uppercase; letter-spacing: .04em; color: var(--su-text-muted); font-weight: 600; }
.su-rep-stage-value { font-family: var(--su-font-heading); font-size: var(--su-fs-lg); font-weight: 700; font-variant-numeric: tabular-nums; }
/* Этап, который автопропуск прошёл мимо: данных нет, и это не ноль. */
.su-rep-stage--empty .su-rep-stage-value { color: var(--su-n-400); font-weight: 500; }
.su-rep-stage-count { font-size: var(--su-fs-caption); color: var(--su-text-muted); }
/* Самый долгий этап станции — тот самый "затык". */
.su-rep-stage--slow { background: var(--su-cooking-bg); }
.su-rep-stage--slow .su-rep-stage-value { color: var(--su-cooking); }

/* ---- пояснение под блоком (почему цифры могут расходиться) ---- */
.su-rep-note { font-size: var(--su-fs-caption); color: var(--su-text-muted); margin-top: var(--su-space-3); line-height: 1.5; }

/* ---- журнал действий ---- */
.su-rep-log-time { font-variant-numeric: tabular-nums; color: var(--su-text-muted); white-space: nowrap; }
.su-rep-pager { display: flex; justify-content: center; gap: var(--su-space-2); margin-top: var(--su-space-4); }

/* ── лист выбора модификаторов (композер официанта) ─────────────────────────
   Шторка снизу — тот же паттерн, что у гостя (menu.css): официант оформляет
   заказ ЗА гостя и должен видеть ровно тот же выбор, чтобы называть цену
   вслух до отправки. */
.mod-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 60;
  display: flex; align-items: flex-end; justify-content: center;
}
body.mod-open { overflow: hidden; }
.mod-sheet {
  width: 100%; max-width: 520px; background: var(--su-bg); color: var(--su-text);
  border-radius: 16px 16px 0 0; max-height: 88vh; display: flex; flex-direction: column;
  padding-bottom: env(safe-area-inset-bottom);
}
.mod-head {
  display: flex; align-items: center; gap: var(--su-space-2);
  padding: var(--su-space-3) var(--su-space-4) var(--su-space-2);
  border-bottom: 1px solid var(--su-n-300);
}
.mod-title { flex: 1; font-family: var(--su-font-heading); font-weight: 700; font-size: var(--su-fs-lg); }
.mod-close {
  flex: none; width: 32px; height: 32px; border-radius: 8px; border: none;
  background: var(--su-n-200); color: var(--su-text); font-size: var(--su-fs-base); line-height: 1; cursor: pointer;
}
.mod-body { overflow-y: auto; padding: 0 var(--su-space-4) var(--su-space-3); -webkit-overflow-scrolling: touch; }
.mod-group { padding: var(--su-space-3) 0; border-bottom: 1px solid var(--su-n-200); }
.mod-group:last-child { border-bottom: none; }
.mod-group-head { display: flex; align-items: baseline; gap: var(--su-space-2); margin-bottom: 4px; }
.mod-group-name { font-weight: 700; font-size: var(--su-fs-sm); }
.mod-group-rule { color: var(--su-text-muted); font-size: var(--su-fs-caption); }
.mod-opt { display: flex; align-items: center; gap: var(--su-space-2); padding: 10px 2px; font-size: var(--su-fs-sm); }
.mod-opt input { width: 18px; height: 18px; flex: none; }
.mod-opt-name { flex: 1; min-width: 0; }
.mod-opt-price { color: var(--su-text-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.mod-foot { padding: var(--su-space-3) var(--su-space-4); border-top: 1px solid var(--su-n-300); }

/* Комментарий к позиции (композер официанта) ────────────────────────────────
   Карандаш стоит ПОД счётчиком, а не отдельной кнопкой в ряду: он относится к
   уже набранной позиции, и до первого «В заказ» его нет вовсе. Текст самого
   комментария живёт в плитке блюда (под ценой) и в строке корзины — набравший
   его официант должен видеть результат там же, где смотрит состав заказа. */
.su-ctrl-stack { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.su-note-btn {
  width: 28px; height: 28px; flex: none; padding: 0;
  border: none; border-radius: var(--su-radius-round);
  background: var(--su-n-200); color: var(--su-text-muted);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.su-note-btn:hover { background: var(--su-n-300); }
.su-note-btn.is-set { background: var(--su-a-100); color: var(--su-a-600); }
.su-menu-item-comment {
  display: flex; align-items: flex-start; gap: 4px; margin-top: 4px;
  font-size: var(--su-fs-caption); color: var(--su-a-600);
}
.su-menu-item-comment svg { flex: none; margin-top: 1px; }
/* Строка комментария в корзине — кнопка, а не поле ввода: правится тем же
   окном, что и с плитки, иначе одно и то же действие выглядело бы в двух
   местах по-разному. Прежний <input class="su-input--sm"> к тому же был шириной
   в 100px (утилита под числовое поле) и на мобильном не показывался вовсе —
   корзина-сайдбар скрыта до 900px. */
.su-cart-line-note { padding: 2px 0 0; }
.su-note-line {
  display: flex; align-items: flex-start; gap: 4px; width: 100%;
  padding: 2px 0; border: none; background: none; cursor: pointer;
  font-family: var(--su-font-body); font-size: var(--su-fs-caption);
  color: var(--su-text-muted); text-align: left;
}
.su-note-line svg { flex: none; margin-top: 1px; }
.su-note-line.is-set { color: var(--su-a-600); }
.su-note-field {
  width: 100%; min-height: 90px; resize: vertical;
  padding: var(--su-space-2); border: 1px solid var(--su-n-300);
  border-radius: var(--su-radius-md); background: var(--su-surface);
  color: var(--su-text); font-family: var(--su-font-body); font-size: var(--su-fs-sm);
}
.su-note-field:focus { outline: none; border-color: var(--su-a-500); box-shadow: var(--su-ring); }
.su-note-foot { display: flex; gap: var(--su-space-2); }
.su-note-foot .su-btn { flex: 1; }

/* состав и степпер строки в корзине композера */
.su-cart-line-mods { font-size: var(--su-fs-caption); color: var(--su-text-muted); padding: 2px 0 0; }
.su-cart-line-qty { display: flex; align-items: center; gap: 6px; padding: 4px 0; }
.su-cart-line-qty .su-qty-btn { width: 24px; height: 24px; font-size: var(--su-fs-sm); }

/* состав позиции в карточке заказа и на кассе */
.su-item-mods { font-size: var(--su-fs-caption); color: var(--su-text-muted); margin-top: 2px; }

/* ============================================================
   РЕДИЗАЙН, шаг 1 — то, что переехало из admin.css, плюс классы
   вместо инлайн-стилей и эмодзи. Переменные не заводить нигде,
   кроме :root и блоков тем (TASK-redesign.md, «Чего не делать»).
   ============================================================ */

/* Кружок статуса вместо цветных эмодзи. Цвет НЕ зашит в элемент: он
   приходит от класса статуса рядом, как у всех статусных элементов. */
.su-status-dot { display: inline-flex; vertical-align: middle; color: var(--su-n-400); }
.su-status-dot.st-new       { color: var(--su-a-400); }
.su-status-dot.st-accepted  { color: var(--su-a-600); }
.su-status-dot.st-preparing { color: var(--su-cooking); }
.su-status-dot.st-ready     { color: var(--su-free); }
.su-status-dot.st-served    { color: var(--su-n-500); }
.su-status-dot.st-cancelled { color: var(--su-cancel); }

/* Состояние «пусто» карточкой — приглашение, не извинение (3.8). */
.su-empty-card {
  text-align: center; align-items: center;
  padding: var(--su-space-6) var(--su-space-4);
  margin-bottom: var(--su-space-4);
}
.su-empty-icon { display: inline-flex; color: var(--su-n-400); margin-bottom: var(--su-space-2); }

/* Иконка внутри строки текста (например «нажмите на замок [icon]»):
   выравнивается по базовой линии соседних букв, а не по низу строки. */
/* Иконка ВНУТРИ строки текста («нажмите на замок [icon]», легенда матрицы).
   Селектор с [data-staff-theme] намеренно: базовое правило
   `[data-staff-theme] svg { display: block }` имеет специфичность (0,1,1) и
   одним классом не перебивается — иконка встаёт блоком и разрывает строку. */
[data-staff-theme] .su-inline-icon { display: inline-block; vertical-align: -.18em; }

/* Служебные экраны (подтверждение действия, «проверьте почту», вне рабочего
   времени) — вместо инлайн-стилей в шаблонах. */
.su-text-center { text-align: center; }
.su-login-box--wide { max-width: 480px; }
.su-page-title--md { font-size: var(--su-fs-xl, 22px); margin-bottom: var(--su-space-2); }
.su-card-meta--spaced { margin-bottom: var(--su-space-5); }
.su-card-meta--sm { font-size: var(--su-fs-caption, 13px); }
.su-result-icon {
  display: flex; justify-content: center;
  color: var(--su-n-400); margin-bottom: var(--su-space-3);
}
.su-result-icon--ok  { color: var(--su-free); }
.su-result-icon--err { color: var(--su-cancel); }
.su-fullscreen-notice {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 60vh; text-align: center; padding: var(--su-space-5);
}

/* Тег-точка: «есть новое», когда цифры нет и текст не нужен. Раньше здесь
   стоял колокольчик-эмодзи на su-tag-cooking — семантика «готовится» к
   непрочитанному ответу отношения не имеет (TASK-redesign.md 1.5). */
.su-tag-dot { width: 8px; height: 8px; min-height: 0; padding: 0; border-radius: var(--su-radius-pill, 999px); }

/* ============================================================
   ПЕРЕЕХАЛО ИЗ admin.css (шаг 1). Файл удалён — здесь всё, что
   в нём было живым по результатам полного grep-аудита
   (69 живых классов из 313, см. docs/redesign/visual-log.md).
   ============================================================ */

/* ── reset и базовые стили документа ──
   Раньше их держал admin.css на голом html/body. Теперь они внутри
   [data-staff-theme], как остальной su-* CSS: атрибут стоит на <body>
   на КАЖДОЙ странице /admin/* и /staff/*, поэтому охват тот же, а фон
   берётся из темы. Именно из-за прежнего разделения в тёмной теме под
   контентом оставалась светлая полоса — body красил admin.css. */
html, body { margin: 0; }
[data-staff-theme] {
  -webkit-tap-highlight-color: transparent;
  -webkit-overflow-scrolling: touch;
  /* Нижний таббар у сотрудника перекрывается системной панелью жестов —
     отступ был на body в admin.css, не потерять при удалении файла. */
  padding-bottom: env(safe-area-inset-bottom);
}

/* ── обёртки страниц ──
   .wrap / .wrap-flush / .wrap-no-topbar ставятся из PHP через $wrapClass
   (20 роутов в public/index.php) — в разметке их нет, grep по class= не
   находит. Имена сохранены: переименование в .su-page потребовало бы
   править те же 20 роутов ради косметики, а гаттеры выравниваются и так.
   Гаттер теперь общий с .su-main — раньше /admin давал 14px, /staff 10px,
   и разница была заметна при переходе между разделами. */
/* ВСЕ ТРИ обёртки ограничены одной шириной и имеют одинаковый гаттер.
   Раньше .wrap держал 1180px, а .wrap-flush и .wrap-no-topbar не держали
   ничего: /admin/orders, /admin/orders/history и /admin/menu растекались
   на весь монитор, остальные страницы — нет, и админка выглядела собранной
   из двух разных продуктов. Ширина совпадает с .su-main, поэтому переход
   между разделами не двигает контент.

   Разница между вариантами осталась только в вертикальных отступах:
   -flush прижат к шапке (свой заголовок внутри страницы),
   -no-topbar для экранов без навигации вообще. */
.wrap, .wrap-flush, .wrap-no-topbar {
  max-width: 1180px; width: 100%; margin: 0 auto;
  /* padding: var(--su-edge-pad); */
  padding-bottom: var(--su-space-6);
}
.wrap-flush { padding-top: 0; }
.wrap-no-topbar { margin-top: 0; padding-top: 0; }
@media (min-width: 860px) {
  .wrap, .wrap-flush, .wrap-no-topbar { padding-left: var(--su-space-6); padding-right: var(--su-space-6); }
  .wrap { padding-top: var(--su-space-6); }
}
@media (min-width: 860px) {
  .wrap { padding: var(--su-space-6); padding-bottom: var(--su-space-6); }
}

/* ── flash-сообщения ──
   Показываются только после POST-редиректа, поэтому в сохранённых
   страницах не встречались — но живые (10 файлов + layout.php). */
.flash {
  padding: var(--su-space-3) var(--su-space-4);
  font-size: var(--su-fs-sm, 14px);
  max-width: 960px; margin: 0 auto;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--su-radius-md);
}
.flash-ok  { background: var(--su-free-bg);   color: var(--su-free); }
.flash-err { background: var(--su-cancel-bg); color: var(--su-cancel); margin-bottom: 3px; }

/* У staff flash ведёт себя как уведомление поверх экрана. Ошибки остаются до
   явного закрытия; таймер успешных сообщений задаёт разметка layout.php. */
.flash-stack {
  position: fixed; z-index: 60;
  top: max(var(--su-space-3), env(safe-area-inset-top)); left: 50%;
  width: calc(100% - var(--su-space-6)); max-width: 960px;
  display: grid; gap: var(--su-space-2);
  transform: translateX(-50%); pointer-events: none;
}
.flash-stack .flash {
  position: relative; width: 100%; margin: 0;
  padding-right: var(--su-space-8);
  border: 0; box-shadow: var(--su-shadow-lg);
  cursor: pointer; pointer-events: auto; touch-action: pan-y;
  opacity: 1; transform: translateY(0);
  transition: opacity .18s ease, transform .18s ease;
}
.flash-stack .flash::after {
  content: "\00d7"; position: absolute; right: var(--su-space-4);
  font-size: var(--su-fs-lg); line-height: 1; opacity: .7;
}
.flash-stack .flash:focus-visible { outline: none; box-shadow: var(--su-shadow-lg), var(--su-ring); }

/* Плашка с действиями («Сменить тариф», «Написать в поддержку»). Колонкой, а
   не в строку: текст отказа бывает длинным, и ссылки, прижатые к нему сбоку,
   на телефоне уехали бы за край. Курсор обычный — закрывает такую плашку
   крестик, а не клик по всей площади: под ним живут ссылки. */
.flash--actions {
  flex-direction: column; align-items: flex-start; gap: var(--su-space-2);
  text-align: left; cursor: default;
}
.flash-actions { display: flex; flex-wrap: wrap; gap: var(--su-space-4); }
.flash-action {
  color: inherit; font-weight: 600; text-decoration: underline;
  text-underline-offset: 3px; cursor: pointer;
}
.flash-action:hover { text-decoration: none; }
.flash-stack .flash.is-dismissed {
  opacity: 0; transform: translateY(calc(var(--su-space-2) * -1)); pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .flash-stack .flash { transition: none; }
}

/* Панели вкладок истории заказов — показ/скрытие, класс ставится из JS. */
.orders-panel { display: none; }
.orders-panel.active { display: block; }

/* Сентинелы бесконечной прокрутки истории (пустые div-триггеры). */
#completedSentinel, #cancelledSentinel { height: 40px; }

/* ── печатный макет QR ──
   Точная копия стилей страницы печати для превью в списке столов.
   Имена не переименованы намеренно: это макет БУМАЖНОЙ карточки, а не
   UI-компонент — он обязан выглядеть одинаково на экране и в печати,
   поэтому цвета здесь абсолютные и темой не управляются. */
.qr-print-wrap {
  width: 240px; margin: 0 auto var(--su-space-2); text-align: center;
  border: 1.5px solid #222; border-radius: 10px; padding: 12px 10px 8px;
  background: #fff; color: #111;
}
.qr-print-cafe  { font-size: var(--su-fs-caption); font-weight: 700; line-height: 1.2; margin-bottom: 3px; }
.qr-print-table { font-size: var(--su-fs-xl); font-weight: 800; margin-bottom: 6px; }
.qr-print-hint  { font-size: var(--su-fs-caption); color: #555; margin-top: 5px; line-height: 1.3; font-weight: 600; }
.qr-canvas { display: block; max-width: 100%; margin: 0 auto; }

/* Стрелка направления сортировки в списке сотрудников (ставится из JS). */
.staff-sort-arrow { font-size: var(--su-fs-caption, 12px); }

/* Код сверки заявки на вход — крупно и с разрядкой, чтобы читалось вслух через
   зал. ⚠️ Это НЕ секрет: он не даёт входа, а только отвечает подтверждающему на
   вопрос «то ли это устройство». Поэтому его показывают до всякой авторизации. */
.su-code-display {
  font-size: var(--su-fs-2xl, 28px); font-weight: 700; letter-spacing: .12em;
  font-variant-numeric: tabular-nums;
}
.su-table-copy-row--spaced { margin-top: var(--su-space-2); }

/* Абзац-пояснение под заголовком раздела.
   Отдельно от .su-card-meta намеренно: та — flex-СТРОКА (иконка + подпись в
   одну линию), и многострочный текст в ней разваливается — каждый <b> и <br>
   становится отдельным flex-элементом. Здесь обычный поток текста. */
.su-hint {
  font-size: var(--su-fs-caption, 13px);
  line-height: 1.5;
  color: var(--su-text-muted);
  margin: 0 0 var(--su-space-3);
}
.su-hint b, .su-hint strong { color: var(--su-text); font-weight: 600; }

/* ============ утилиты отступов ============
   Узкий набор ровно под то, что раньше писалось инлайном в шаблонах
   (margin-top/bottom одного из шагов шкалы + сброс margin). Инлайн-стиль —
   дыра в системе токенов: тема поменяется, а он останется; плюс его нельзя
   переопределить из CSS без !important.

   Набор намеренно НЕ полный (нет mt-1..8 x mb-1..8 x padding): утилита на
   каждый случай превращается в второй язык поверх CSS. Здесь только те,
   что реально встречались в разметке. */
/* ⚠️ Порядок внутри блока значим: .su-m-0 сбрасывает ВСЕ поля и поэтому
   объявлен ПЕРВЫМ — иначе он перебивал бы .su-mt-2 в наборе вроде
   class="su-mt-2 su-m-0", и отступ молча пропадал бы (при равной
   специфичности выигрывает то правило, что ниже в файле).
   Направленные классы идут после и уточняют сброс. */
.su-m-0  { margin: 0; }
.su-mt-0 { margin-top: 0; }
.su-mt-1 { margin-top: var(--su-space-1); }
.su-mt-2 { margin-top: var(--su-space-2); }
.su-mt-3 { margin-top: var(--su-space-3); }
.su-mt-4 { margin-top: var(--su-space-4); }
.su-mt-5 { margin-top: var(--su-space-5); }
.su-mt-6 { margin-top: var(--su-space-6); }
.su-mb-0 { margin-bottom: 0; }
.su-mb-2 { margin-bottom: var(--su-space-2); }
.su-mb-3 { margin-bottom: var(--su-space-3); }
.su-mb-4 { margin-bottom: var(--su-space-4); }
.su-mb-5 { margin-bottom: var(--su-space-5); }
.su-ml-1 { margin-left: var(--su-space-1); }
/* Вертикальный отступ сверху и снизу одним шагом — разделители внутри форм. */
.su-my-3 { margin-top: var(--su-space-3); margin-bottom: var(--su-space-3); }
/* Вертикальный отступ сверху и снизу одним шагом — разделители внутри форм. */

/* Раскладка. Узкий набор: только то, что реально повторялось инлайном
   в шаблонах — ряд с переносом, растяжимое поле, центрирование текста. */
.su-row       { display: flex; align-items: center; gap: var(--su-space-2); flex-wrap: wrap; }
.su-row--end  { align-items: flex-end; }
.su-row--between { justify-content: space-between; }
.su-grow      { flex: 1 1 200px; min-width: 0; }
.su-grow--sm  { flex: 1 1 160px; min-width: 0; }
.su-grow--lg  { flex: 1 1 220px; min-width: 0; }
.su-shrink    { flex: 0 0 auto; width: auto; }

/* Ссылка, которая не должна выглядеть ссылкой: строка таблицы или карточка
   целиком кликабельна, а подчёркнутый синий текст внутри неё сбивает. */
.su-link-plain { text-decoration: none; color: inherit; }

/* Выключенный на вид блок: настройка, недоступная на текущем тарифе.
   Не disabled — сервер всё равно откажет, а показать её надо (CLAUDE.md 7.2). */
.su-dimmed { opacity: .55; }
.su-dimmed--locked { opacity: .5; pointer-events: none; }
/* ⚠️ Атрибут hidden сам по себе даёт display:none, но ЛЮБОЙ класс с
   display:flex/grid его перебивает — специфичность у класса выше, чем
   у браузерного правила для hidden. Раз раскладку задают классы (.su-row
   и подобные), правило нужно явно, иначе «скрытый» блок остаётся на экране.
   [hidden] здесь важнее всех: скрыт — значит скрыт. */
[hidden] { display: none !important; }

.su-not-allowed { cursor: not-allowed; }
.su-row--pointer { cursor: pointer; gap: 10px; }
.su-gap-2 { gap: var(--su-space-2); }
.su-gap-3 { gap: var(--su-space-3); }

/* Подстрока настройки: уточнение под галочкой, со сдвигом под её текст. */
.su-subrow {
  display: flex; align-items: center; gap: var(--su-space-2);
  margin: var(--su-space-1) 0 0 26px;
  font-size: var(--su-fs-caption);
}

/* fieldset без собственной рамки — он тут только чтобы разом отключить
   вложенные поля через disabled, а не ради визуального блока. */
.su-fieldset-plain { border: 0; padding: 0; margin: 0; }

/* Ширины полей ввода. Три ступени вместо россыпи 34/60/90/110/120px —
   разница в пару пикселей ничего не выражала, а классов плодила. */
.su-w-xs   { width: 60px; }
.su-w-sm   { width: 90px; }
.su-w-md   { width: 120px; }
.su-w-full { width: 100%; }
.su-w-fit  { width: fit-content; }
/* Колонка формы: дальше строка не тянется, читать длинные поля неудобно. */
.su-w-form { max-width: 560px; }

/* Поле многострочного ввода: обращение в поддержку, ответ в тикете. */
.su-textarea-lg { min-height: 120px; }

/* Подзаголовок внутри карточки — не h2 страницы, а подпись группы полей. */
.su-subhead { font-weight: 600; margin: 0 0 var(--su-space-2); }

/* Слово-разделитель поверх линии («или»). */
.su-divider-word { font-weight: 700; padding: 0 var(--su-space-1); }

/* Итоговая сумма в печатном счёте. */
.su-total-line { font-size: 16px; font-weight: 700; }

/* Длинная ссылка или токен: рвём по символам, иначе распирает колонку. */
.su-break-all { word-break: break-all; }

/* Шапка списка-таблицы: подпись колонок над строками. */
.su-list-head {
  padding: var(--su-space-2) 0;
  border-bottom: 2px solid var(--su-n-300);
  margin-bottom: var(--su-space-2);
}

/* Блок в рамке — группа настроек внутри карточки. */
.su-bordered-box { border: 1px solid var(--su-n-300); border-radius: var(--su-radius-md); }

/* Превью QR в настройках аккаунта. */
/* Размер QR под печать. Пять ступеней вместо девяти: 30/35 и 40/45/50/55
   на бумаге неразличимы, а выбор из девяти пунктов заставляет владельца
   гадать. Значение хранится в cafes.qr_size_mm (мм), класс ставится по нему.

   ⚠️ Список обязан совпадать с Repository::QR_SIZES — оттуда же строится
   <select> в настройках. */
.su-qr-mm-30  { width: 30mm;  height: 30mm; }
.su-qr-mm-40  { width: 40mm;  height: 40mm; }
.su-qr-mm-60  { width: 60mm;  height: 60mm; }
.su-qr-mm-100 { width: 100mm; height: 100mm; }
.su-qr-mm-150 { width: 150mm; height: 150mm; }

.su-qr-preview {
  display: block;
  margin: var(--su-space-3) 0;
  border: 1px solid var(--su-n-300);
  border-radius: var(--su-radius-md);
}

/* ============ плашка-уведомление ============
   «Включите уведомления», «Уведомления заблокированы» и т.п. Классы
   push-notice* жили в admin.css и после его удаления остались без стилей —
   переехали сюда под именем su-notice. Это su-карточка с двумя колонками:
   текст слева, действия справа; на узком экране — в столбик. */
.su-notice-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--su-space-3); flex-wrap: wrap;
}
.su-notice-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.su-notice-text strong { font-size: var(--su-fs-base); font-weight: 600; }
.su-notice-text span { font-size: var(--su-fs-sm); color: var(--su-text-muted); }
.su-notice-actions { display: flex; align-items: center; gap: var(--su-space-2); flex-wrap: wrap; }
@media (max-width: 560px) {
  .su-notice-actions { width: 100%; }
  .su-notice-actions .su-btn { flex: 1 1 auto; }
}

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

/* Полоса при потере связи. Ставится под навбар из sse-client.js, когда молчит
   не только SSE, но и polling. Position: sticky, а не fixed — не перекрывает
   нижний таббар на телефоне. */
.su-offline-bar {
  position: sticky; top: var(--su-nav-h); z-index: 30;
  padding: var(--su-space-2) var(--su-space-4);
  background: var(--su-cancel-bg); color: var(--su-cancel);
  font-size: var(--su-fs-sm); font-weight: 500; text-align: center;
}

/* Скелетон вместо спиннера при первой загрузке списка: он показывает БУДУЩУЮ
   форму содержимого, поэтому переход к данным не выглядит скачком. */
.su-skeleton {
  background: var(--su-n-200); border-radius: var(--su-radius-sm);
  animation: su-skeleton-pulse 1.4s ease-in-out infinite;
}
.su-skeleton-row { height: 16px; margin-bottom: var(--su-space-2); }
.su-skeleton-row:nth-child(2n) { width: 70%; }
.su-skeleton-card { height: 92px; border-radius: var(--su-radius-lg); margin-bottom: var(--su-space-3); }
/* Заглушка строки истории — ровно та же высота, что у настоящей строки
   (--su-hit-min), поэтому при появлении данных список не подпрыгивает. */
.su-skeleton-history-row {
  height: var(--su-hit-min); border-radius: 0; margin: 0;
  border-bottom: 1px solid var(--su-n-200);
}
@keyframes su-skeleton-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
/* Движение в рабочем инструменте мешает — у кого выключены анимации,
   скелетон остаётся статичной заглушкой. */
@media (prefers-reduced-motion: reduce) { .su-skeleton { animation: none; } }

/* Состояние «пусто» — приглашение, не извинение: «Заказов пока нет.
   Отсканируйте QR стола, чтобы начать» вместо «Нет данных». */
.su-empty-state {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--su-space-2); padding: var(--su-space-8) var(--su-space-4);
  color: var(--su-text-muted);
}
.su-empty-state svg { width: 32px; height: 32px; color: var(--su-n-400); }
.su-empty-state-title { font-size: var(--su-fs-base); font-weight: 600; color: var(--su-text); }
.su-empty-state-sub { font-size: var(--su-fs-sm); max-width: 34ch; }

/* Утилиты кегля — для мест, где размер задавался инлайном мимо шкалы
   (заголовки экранов входа, разовые коды, подписи секций). Инлайновый
   font-size переживает смену шкалы и остаётся на старом значении, поэтому
   выносится в класс. Прочий инлайн (flex-basis, width, выравнивание) — это
   раскладка конкретного места, а не токен, и классом не заменяется. */
.su-fs-caption { font-size: var(--su-fs-caption); }
.su-fs-sm      { font-size: var(--su-fs-sm); }
.su-fs-base    { font-size: var(--su-fs-base); }
.su-fs-xl      { font-size: var(--su-fs-xl); }
.su-fs-2xl     { font-size: var(--su-fs-2xl); }

/* ── Оплата тарифа (/admin/billing) ─────────────────────────────────────
   Сетка тарифных карточек: два тарифа × несколько сроков. Колонок ровно
   столько, сколько влезает — при одном активном тарифе в прайсе карточка не
   должна растягиваться на всю ширину. */
.su-plan-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: var(--su-space-3); margin: var(--su-space-3) 0;
}
.su-plan-card {
  display: flex; flex-direction: column; gap: var(--su-space-1);
  padding: var(--su-space-3); border: 1px solid var(--su-n-300);
  border-radius: var(--su-radius-lg); background: var(--su-surface);
}
/* Текущий тариф подсвечен рамкой, а не заливкой: заливка спорила бы с
   выделением выгодного предложения. */
.su-plan-card--current { border-color: var(--su-fill-primary); }
.su-plan-card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--su-space-2); }
.su-plan-card-term { font-size: var(--su-fs-sm); color: var(--su-text-muted); }
.su-plan-card-price { font-size: var(--su-fs-xl); font-weight: 700; }
.su-plan-card-permonth { font-size: var(--su-fs-caption); color: var(--su-text-muted); }
.su-plan-limits {
  display: grid; grid-template-columns: 1fr auto; gap: var(--su-space-1) var(--su-space-2);
  margin: auto 0 0; padding-top: var(--su-space-3);
  border-top: 1px solid var(--su-n-200);
}
.su-plan-limit { display: contents; }
.su-plan-limit dt { color: var(--su-text-muted); font-size: var(--su-fs-caption); }
.su-plan-limit dd { margin: 0; font-size: var(--su-fs-sm); font-weight: 600; text-align: right; }
.su-plan-card form { padding-top: var(--su-space-2); }
.su-plan-card .su-btn { width: 100%; }

/* Экономия за длинный срок — единственный аргумент за годовую оплату,
   поэтому цифрой, а не мелким текстом. */
.su-plan-save {
  align-self: flex-start; font-size: var(--su-fs-caption); font-weight: 600;
  padding: 2px 8px; border-radius: var(--su-radius-sm);
  background: var(--su-ready-bg); color: var(--su-ready);
}

/* Строка счёта в истории. */
.su-invoice-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--su-space-3); padding: var(--su-space-3) 0;
  border-bottom: 1px solid var(--su-n-200);
}
.su-invoice-row:last-child { border-bottom: 0; }
.su-invoice-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.su-invoice-actions { display: flex; align-items: center; gap: var(--su-space-2); flex-shrink: 0; }
.su-invoice-row-cancelled { opacity: .55; }
.su-invoice-cancelled-label {
  font-size: var(--su-fs-sm); color: var(--su-text-muted);
}

/* Баннер «тариф истекает» — на всех страницах владельца, не только здесь:
   узнать о даунгрейде постфактум хуже, чем увидеть предупреждение заранее. */
.su-plan-warning {
  display: flex; align-items: center; justify-content: space-between; gap: var(--su-space-3);
  flex-wrap: wrap;
  padding: var(--su-space-3) var(--su-space-4); margin-bottom: var(--su-space-3);
  border: 1px solid var(--su-cooking); border-radius: var(--su-radius-lg);
  background: var(--su-cooking-bg); color: var(--su-text);
  font-size: var(--su-fs-sm);
}

/* Лицевой счёт на странице оплаты: моноширинный, потому что его переписывают
   в платёжку цифра в цифру. */
.su-account-code { margin: var(--su-space-2) 0 0; font-size: var(--su-fs-sm); }
.su-account-code b { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: var(--su-fs-base); letter-spacing: .04em; }
.su-account-code .su-card-meta { display: block; }

/* Пиксель Яндекс.Метрики для <noscript>: убран за край экрана, а не спрятан
   через [hidden] или display:none — счётчик без загрузки картинки не сработает
   вовсе, а ради него всё и стоит. Зеркало .m-metrika-px в menu.css. */
.su-metrika-px { position: absolute; left: -9999px; }

/* Заявка на вход: карточка «кто просит + код сверки + решение».
   Стоит в разделе «Сотрудники» у того, кто может пустить в смену. Раньше на
   этом месте была кнопка «Показать код» — механизм заменён заявкой (097). */
.su-approval {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--su-space-3); flex-wrap: wrap;
  padding: var(--su-space-3) 0;
  border-top: 1px solid var(--su-n-300);
}
.su-approval:first-child { border-top: 0; }
.su-approval-who { min-width: 0; }
/* Код сверки читают вслух через зал, поэтому он крупнее подписи, но мельче
   того же кода на экране просящего: там он главный, здесь — одна из колонок. */
.su-approval-who .su-code-display { margin-top: var(--su-space-1); font-size: var(--su-fs-xl); }
