/* ============================================================================
   AdminWash — ДИЗАЙН-СИСТЕМА (слой поверх YetiWash style.css / Pico 2)
   ----------------------------------------------------------------------------
   style.css = бренд-база (классы cw-*, токены --cw-positive/negative/muted/
   border/bg-soft, светлая/тёмная тема). ЕЁ НЕ ТРОГАЕМ.
   Здесь — то, чего в базе нет, и единые СТРОГИЕ правила для всех страниц
   AdminWash: токены акцента + шкалы, кнопки, таблицы, карточки, бейджи,
   отступы, типографика, адаптив (мобайл/планшет/ноут/десктоп).

   ПРАВИЛА (придерживаться во всех шаблонах):
   • Отступы — только из шкалы --aw-s1..6 (4/8/12/16/24/32px). Без inline-margin.
   • Кнопки — .cw-btn-small (базовая) + модификаторы .aw-btn-danger / .aw-btn-ghost.
   • Таблицы данных — <table class="cw-tx-table"> + data-label на каждой <td>
     (даёт аккуратный стек на мобиле). Без «голых» таблиц.
   • Карточки — <article>; компактная заметка — <article class="aw-note">.
   • Сетка 2 колонки — .aw-grid-2 (сама схлопывается в 1 колонку на узком).
   • Бейджи статуса — .cw-badge + .ok/.info/.warn/.err.
   • Никаких inline style= в шаблонах — только классы/утилиты отсюда.
   ============================================================================ */

/* ============================ 1. ТОКЕНЫ ==================================== */
:root, [data-theme="light"] {
  /* Акцент (бренд YetiWash) */
  --aw-accent: #3478d1;
  --aw-accent-hover: #2a66b8;
  --aw-accent-contrast: #ffffff;
  --aw-accent-soft: color-mix(in srgb, #3478d1 12%, transparent);
  /* Опасное действие / успех — переиспользуем семантические токены базы */
  --aw-danger: var(--cw-negative);
  --aw-danger-soft: color-mix(in srgb, var(--cw-negative) 12%, transparent);
  --aw-ok-soft: color-mix(in srgb, var(--cw-positive) 14%, transparent);

  /* Шкала отступов (шаг 4px) — единственный источник отступов */
  --aw-s1: .25rem;  --aw-s2: .5rem;  --aw-s3: .75rem;
  --aw-s4: 1rem;    --aw-s5: 1.5rem; --aw-s6: 2rem;

  /* Радиусы */
  --aw-r-sm: 4px; --aw-r-md: 8px; --aw-r-lg: 12px; --aw-r-pill: 999px;

  /* Тени */
  --aw-sh-sm: 0 1px 2px rgba(0,0,0,.06);
  --aw-sh-md: 0 2px 8px rgba(0,0,0,.08);
  --aw-sh-lg: 0 6px 18px rgba(0,0,0,.12);

  /* Переход */
  --aw-dur: .15s;

  /* Типографика — размерная шкала */
  --aw-fs-h2: 1.25rem;
  --aw-fs-base: 1rem;
  --aw-fs-sm: .875rem;
  --aw-fs-xs: .78rem;
}
[data-theme="dark"] {
  --aw-accent: #4a90e2;
  --aw-accent-hover: #5ba3ff;
  --aw-accent-soft: color-mix(in srgb, #4a90e2 20%, transparent);
  --aw-sh-sm: 0 1px 2px rgba(0,0,0,.35);
  --aw-sh-md: 0 2px 8px rgba(0,0,0,.45);
  --aw-sh-lg: 0 6px 18px rgba(0,0,0,.55);
}

/* ============================ 2. ТИПОГРАФИКА ============================== */
.aw-page-head h2 { font-size: var(--aw-fs-h2); margin: 0; }
.aw-muted-sm { font-size: var(--aw-fs-sm); color: var(--cw-muted); }
.aw-xs { font-size: var(--aw-fs-xs); }

/* ============================ 3. ЗАГОЛОВОК СТРАНИЦЫ ====================== */
.aw-page-head { display: flex; align-items: center; justify-content: space-between;
                gap: var(--aw-s4); margin: var(--aw-s2) 0 var(--aw-s4); flex-wrap: wrap; }
/* вариант: строка с back-ссылкой + заголовком + статусом (карточка поста) */
.aw-page-head--row { justify-content: flex-start; }

/* шапка карточки: заголовок слева, мета/ссылка справа (вместо float) */
.aw-head { display: flex; align-items: baseline; gap: var(--aw-s3); }
/* заголовки внутри flex-шапки — без собственных margin (иначе рвут вертикаль ряда) */
.aw-head h1, .aw-head h2, .aw-head h3 { margin: 0; }
.aw-head-meta { margin-left: auto; font-size: var(--aw-fs-sm); color: var(--cw-muted); font-weight: 400; }

/* ============================ 4. КАРТОЧКИ / ЗАМЕТКИ ===================== */
/* компактная карточка-заметка (подсказки «настраивается в карточке поста» и т.п.) */
.aw-note { padding: var(--aw-s2) var(--aw-s4); }
.aw-note > :last-child { margin-bottom: 0; }

/* ряд KPI-плиток постов */
.aw-posts { display: grid; grid-template-columns: repeat(auto-fill, minmax(235px, 1fr));
            gap: var(--aw-s3); }
.aw-posts article { margin: 0; padding: var(--aw-s3) var(--aw-s4); }
.aw-post-head { display: flex; align-items: center; gap: var(--aw-s2); margin-bottom: var(--aw-s1); }
.aw-post-name { font-weight: 600; }
.aw-post-id { margin-left: auto; color: var(--cw-muted); font-size: var(--aw-fs-xs); }
.aw-dot { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto;
          display: inline-block; vertical-align: middle; }
.aw-dot-on { background: var(--cw-positive); }
.aw-dot-off { background: var(--cw-negative); }
.aw-post.is-offline { opacity: .62; }
.aw-post-meta { color: var(--cw-muted); font-size: var(--aw-fs-sm); margin-top: var(--aw-s2); }
.aw-post-meta div { margin-top: 2px; }
/* индикатор кассы на плитке поста (компактно, в 1 строку) */
.aw-post-cash { display: flex; align-items: center; gap: var(--aw-s2); margin-top: var(--aw-s2); font-size: var(--aw-fs-xs); }
.aw-post-cash-label { color: var(--cw-muted); }
.aw-post-cash-pct { color: var(--cw-muted); white-space: nowrap; }
.aw-post-cash-bar { flex: 1 1 auto; height: 6px; margin: 0; min-width: 60px; }
.aw-post-link { text-decoration: none; color: inherit; display: block; }
.aw-post-link .aw-post { transition: box-shadow var(--aw-dur), transform var(--aw-dur); }
.aw-post-link:hover .aw-post { box-shadow: var(--aw-sh-md); }

/* Сводка-обзор парка (шапка Главной) — лёгкая полоса чипов-счётчиков.
   ТОЛЬКО пересчёт сущностей доски; денег/uptime/тревог тут НЕТ (чужие меню). */
.aw-summary { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aw-s2) var(--aw-s4);
              padding: var(--aw-s2) var(--aw-s4); margin: 0 0 var(--aw-s4);
              background: var(--cw-bg-soft); border: 1px solid var(--cw-border);
              border-radius: var(--aw-r-md); font-size: var(--aw-fs-sm); }
.aw-summary-item { display: inline-flex; align-items: center; gap: var(--aw-s2); white-space: nowrap; }
.aw-summary-num { font-weight: 600; }
.aw-summary-hot { color: var(--aw-accent); }
/* тело свёрнутого тест-стенда: карточки моек со стандартным вертикальным ритмом */
.aw-testbench-body { margin-top: var(--aw-s3); display: flex; flex-direction: column; gap: var(--aw-s4); }

/* Таблица постов внутри карточки мойки (замена плиток). Вся строка кликабельна -> /post. */
.aw-posts-table { margin: 0; }
.aw-posts-table .aw-dot { margin-right: var(--aw-s2); }
.aw-post-link-inline { font-weight: 600; color: inherit; text-decoration: none; }
.aw-post-link-inline:hover { color: var(--aw-accent); text-decoration: underline; }
.aw-post-row { cursor: pointer; }
.aw-post-row:hover { background: var(--cw-bg-soft); }
.aw-post-row.is-offline { opacity: .62; }
.aw-posts-table .aw-post-cash { display: inline-flex; margin: 0; }
.aw-posts-table .aw-post-cash-bar { min-width: 70px; }

/* Страница «Программы мойки»: таблица постов с раскрытием редактора набора по строке. */
.aw-pp-row { cursor: pointer; }
.aw-pp-row:hover { background: var(--cw-bg-soft); }
.aw-pp-row .aw-pp-toggle .aw-ico { transition: transform var(--aw-dur); }
.aw-pp-row[aria-expanded="true"] .aw-pp-toggle .aw-ico { transform: rotate(180deg); }
/* Мобайл (≤768): раскрытая строка-редактор содержит вложенные cw-tx-table (программы+чеки).
   Снимаем grid/«: »-префикс с самой edit-строки; вложенные таблицы базовые правила сами
   превратят в карточки. hidden (UA display:none !important) перебивает наш display:block. */
@media (max-width: 768px) {
  .aw-pp-table tr.aw-pp-editrow { display: block; border: 0; background: none; padding: 0; margin: 0 0 var(--aw-s2); }
  .aw-pp-table tr.aw-pp-editrow > td.aw-pp-editcell { display: block; padding: 0; }
  .aw-pp-table tr.aw-pp-editrow > td.aw-pp-editcell::before { content: none; }
}

/* ============================ 5. КНОПКИ ================================== */
/* НАЙДЕНО ЖИВЬЁМ (/motors, модалка нормативов): .cw-btn-small сама пишет
   width:auto, но это голый класс (0,1,0) — Pico держит правило
   `button[type="submit"]{width:100%}` на специфичности (0,1,1) и побеждает.
   Не заметно в рядах, где кнопка соседствует с другими flex-элементами,
   которые её сжимают, — и стреляет там, где submit-кнопка в ряду одна
   («Сохранить» + «Отмена»: сохранить раздувается на всю ширину, отмена
   остаётся нормальной). Тот же приём, что уже применён для
   .aw-icon-btn -> button.aw-icon-btn: поднимаем через тег. */
button.cw-btn-small { width: auto; }
/* База — .cw-btn-small (style.css). Здесь модификаторы (равная специфичность,
   app.css грузится позже → выигрывает; !important чтобы перебить базовый фон). */
.aw-btn-danger { background: transparent !important; border: 1px solid var(--aw-danger) !important;
                 color: var(--aw-danger) !important; }
.aw-btn-danger:hover { background: var(--aw-danger-soft) !important; }
.aw-btn-ghost { background: transparent !important; border: 1px solid var(--cw-border) !important;
                color: var(--cw-muted) !important; }
.aw-btn-ghost:hover { background: var(--cw-bg-soft) !important; }
/* ряд кнопок/действий с равными промежутками (вместо inline-margin) */
.aw-btn-row { display: flex; gap: var(--aw-s2); align-items: center; flex-wrap: wrap; }
/* вертикальный стек элементов с равным промежутком (вместо inline margin-bottom) */
.aw-stack { display: flex; flex-direction: column; gap: var(--aw-s3); align-items: flex-start; }

/* ============================ 6. БЕЙДЖИ ================================= */
/* В базе есть .cw-badge .ok/.warn/.info — НО НЕТ .err. Добавляем. */
.cw-badge.err { color: var(--cw-negative);
                border-color: color-mix(in srgb, var(--cw-negative) 45%, var(--cw-border));
                background: var(--aw-danger-soft); }
/* Пометка «робот» (терминал-робот) — акцентный бейдж рядом с именем поста. */
.aw-badge-robot { color: var(--aw-accent);
                  border-color: color-mix(in srgb, var(--aw-accent) 45%, var(--cw-border));
                  background: var(--aw-accent-soft); margin-left: .4em; }

/* ============================ 7. ФОРМЫ / ИНПУТЫ ======================== */
.aw-controls { display: flex; gap: var(--aw-s4); align-items: end; flex-wrap: wrap; margin-bottom: var(--aw-s4); }
.aw-controls .dates { display: flex; gap: var(--aw-s2); align-items: end; flex-wrap: wrap; }
.aw-controls label { margin: 0; }
/* Дата-фильтр (.aw-date-row) — все контролы в одну РОВНУЮ строку по центру.
   Замером (headless-Chromium) проверено Δ=0 между кнопками и полями дат. Причины кривизны
   до фикса: (1) Pico label{display:block} → подпись «с»/«по» над полем, форма дат высокая;
   (2) Pico button[type=submit]{width:100%} раздувал кнопку «Показать по датам»;
   (3) align-items:end + margin Pico у инпутов → поля «всплывали» на ~18px выше кнопок.
   Лечение: align-items:center + inline-подписи + width:auto на кнопке + сброс margin. */
.aw-date-row { align-items: center; }
.aw-date-row .dates { align-items: center; }
.aw-date-row .dates label { display: inline-flex; align-items: center; gap: .35rem; margin: 0; }
/* «с»/«по» — разной длины подписи без общей колонки, поле начиналось в разных
   местах между строками (заметно на телефоне, где строки друг под другом:
   владелец прислал скриншот 2026-07-27). Фикс-ширина подписи уравнивает старт
   обоих полей независимо от того, сколько букв в слове. */
.aw-date-row .dates .aw-date-lbl { display: inline-block; min-width: 1.3rem; white-space: nowrap; }
.aw-date-row .dates input { margin: 0; }
.aw-date-row .dates button[type="submit"] { width: auto; margin: 0; }
.aw-date-row > button { margin: 0; }
/* Фильтр статистики (мойка/пост): подпись над select, компактные select'ы. */
.aw-stats-filter label { display: flex; flex-direction: column; gap: 2px;
  font-size: var(--yeti-fs-xs, var(--aw-fs-xs)); color: var(--yeti-ink-3, var(--cw-muted)); }
.aw-stats-filter select { margin: 0; min-width: 13rem; max-width: 20rem; }
/* инлайн-форма: поля + кнопка в строку, переносится на узком */
form.inline { display: flex; gap: var(--aw-s2); align-items: center; flex-wrap: wrap; margin: 0; }
form.inline label { margin: 0; }
/* компактные инпуты в таблицах (правка цен/привязок) */
table .aw-inp { margin: 0; padding: var(--aw-s1) var(--aw-s2); }
table .aw-inp.cw-num { text-align: right; max-width: 8rem; }
/* числовой инпут фикс-ширины → токенизированный, ужимается на мобиле.
   Высота = 2rem (совпадает с .cw-btn-small) — чтобы в рядах действий не «прыгал».
   Работает и для <select> (тот же height/padding даёт консистентный вид с кнопками).
   .is-tight — компактная версия для коротких значений («5 мин» / «30 мин»). */
.aw-inp-num { max-width: 8rem; height: 2rem; box-sizing: border-box;
              padding: 0 var(--aw-s2); margin: 0; line-height: 1;
              font-size: .875rem; }
.aw-inp-num.is-tight { max-width: 6rem; min-width: 5rem; }

/* Цены по мойкам (programs.html): карточка-форма на мойку + сетка 6 цен */
.aw-wash-prices { border: 1px solid var(--cw-border); border-radius: var(--aw-r-md);
  padding: var(--aw-s3); }
.aw-price-grid { display: grid; grid-template-columns: repeat(6, 1fr);
  gap: var(--aw-s2); margin-top: var(--aw-s2); }
.aw-price-cell { display: flex; flex-direction: column; gap: 2px; margin: 0; }
.aw-price-cell input { margin: 0; max-width: none; width: 100%; box-sizing: border-box; }
@media (max-width: 768px) { .aw-price-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 480px) { .aw-price-grid { grid-template-columns: repeat(2, 1fr); } }

/* ============================ 8. СЕТКИ ================================= */
.aw-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--aw-s4); align-items: start; }
/* В строгой 2-колоночной форме control'ы (input/select) заполняют ВСЮ ячейку —
   чтобы select «Мойка» не схлопывался до 15rem (правило §15 для inline-фильтров) и
   ряд «Мойка | Сумма» совпадал по сетке с рядами выше. .aw-card-спецификатор
   гарантированно перебивает `.aw-card select{max-width:15rem}`. label занимает ячейку. */
.aw-grid-2 > label { margin: 0; display: block; }
.aw-grid-2 input:not([type="checkbox"]):not([type="radio"]),
.aw-grid-2 select:not([multiple]),
.aw-card .aw-grid-2 select:not([multiple]) { max-width: none; width: 100%; box-sizing: border-box; }
/* Чек-лист моек профиля (один профиль → несколько моек) */
.aw-wash-checks { display: flex; flex-direction: column; gap: .25rem; max-height: 240px;
  overflow: auto; border: 1px solid var(--cw-border); border-radius: 6px; padding: .5rem .6rem; }
.aw-wash-check { display: flex; align-items: center; gap: .5rem; cursor: pointer; line-height: 1.6; }
/* Стандартный чекбокс с ГАЛОЧКОЙ (не Pico-полоска). Pico делает checkbox appearance:none
   + кастомный фон, а наш прежний width:auto схлопывал его в тонкую вертикальную полоску.
   Принудительно нативный вид + фикс. квадрат → виден стандартный квадратик с галочкой.
   Чекбоксы независимы → можно отметить НЕСКОЛЬКО моек сразу. accent-color = синяя галочка. */
.aw-wash-check input[type="checkbox"] {
  appearance: auto;
  -webkit-appearance: checkbox;
  width: 1.2rem; height: 1.2rem; min-width: 1.2rem;
  margin: 0; flex: 0 0 auto;
  accent-color: var(--aw-accent);
  cursor: pointer;
}
/* Превью СБП-QR в карточке поста (read-only) */
.aw-sbp-qr-img { width: 200px; height: 200px; background: #f5f5f5;
  border: 1px solid var(--cw-border); border-radius: 4px; display: block; }
.aw-sbp-qr-img.is-err { background: #fee; }

/* ============================ 9b. ТРЕВОГИ (баннер монитора) ========== */
.aw-alarms { background: var(--aw-danger-soft);
             border-color: color-mix(in srgb, var(--aw-danger) 30%, var(--cw-border)); }
.aw-alarms > header { color: var(--aw-danger); }
.aw-alarms .aw-feed-item { display: flex; align-items: center; gap: var(--aw-s2); }

/* ============================ 9. ЛЕНТА СОБЫТИЙ ======================== */
.aw-feed { list-style: none; padding: 0; margin: 0; font-size: var(--aw-fs-sm); }
.aw-feed-item { padding: var(--aw-s1) 0; border-bottom: 1px solid var(--cw-border); }
.aw-feed-item:last-child { border-bottom: 0; }

/* ============================ 10. УТИЛИТЫ ============================= */
.aw-nowrap { white-space: nowrap; }
.aw-center { text-align: center; }
.is-stale { opacity: .5; }
.aw-pre { white-space: pre-wrap; word-break: break-word; overflow-x: auto; }
.aw-mt0 { margin-top: 0; }
.aw-mt2 { margin-top: var(--aw-s2); }
.aw-mt3 { margin-top: var(--aw-s3); }
.aw-mt4 { margin-top: var(--aw-s4); }
.aw-mb2 { margin-bottom: var(--aw-s2); }
.aw-mb3 { margin-bottom: var(--aw-s3); }
.aw-w100 { width: 100%; box-sizing: border-box; }
.aw-flex1 { flex: 1 1 auto; min-width: 0; }
/* форма, живущая В СТРОКЕ (кнопка в тексте/ячейке) — вместо style="display:inline" */
.aw-form-inline { display: inline-flex; align-items: center; margin: 0; }
/* кнопка без рамки/фона (чип «Выйти» и т.п.) — вместо inline border:0/background.
   padding НЕ трогаем: его задаёт сам чип (.cw-chip), app.css грузится позже и
   обнуление здесь перебило бы паддинг чипа. */
.aw-btn-plain { border: 0; background: transparent; cursor: pointer; }
/* прокручиваемый бокс списка (чек-лист прав и т.п.) */
.aw-scroll-box { max-height: 20rem; overflow: auto; border: 1px solid var(--cw-border);
  border-radius: var(--aw-r-sm); padding: var(--aw-s2); margin: var(--aw-s2) 0; }
.aw-scroll-box label { display: block; margin: var(--aw-s1) 0; }
/* пустое состояние таблицы/списка */
.aw-empty { padding: var(--aw-s5); text-align: center; color: var(--cw-muted); }
/* выделяемый одноразовый секрет (пароль-фраза доступа) — кликом выделяется целиком */
.aw-pass { font-size: 1.1rem; user-select: all; overflow-wrap: anywhere; }
/* узкая колонка таблицы (th «Реле» и т.п.) */
.aw-col-5r { width: 5rem; }
/* компактная ячейка-вставка (td-подстрока на всю ширину) */
.aw-td-pad { padding: var(--aw-s2) var(--aw-s3); }

/* ============================ 11. ЭКРАН ВХОДА ========================= */
.aw-login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: var(--aw-s4); }
.aw-login-card { width: 340px; max-width: 100%; }
.aw-login-brand { font-size: 1.9rem; font-weight: 800; text-align: center; letter-spacing: -.015em; line-height: 1; }
.aw-login-sub { text-align: center; color: var(--cw-muted); margin: var(--aw-s2) 0 var(--aw-s5); }
.aw-pin { text-align: center; font-size: 1.5rem; letter-spacing: .55rem; }

/* ============================ 12. ФЛЕШ / HTMX ======================== */
.aw-flash-ok { color: var(--cw-positive); font-weight: 600; }
.aw-flash-err { color: var(--cw-negative); font-weight: 600; }
.aw-ok { color: var(--cw-positive); }
/* .aw-flash-err как блок-карточка (предупреждения) — компактный отступ */
article.aw-flash-err, p.aw-flash-err { padding: var(--aw-s2) var(--aw-s4); }
p.aw-flash-err { margin: 0; }
.htmx-indicator { opacity: 0; transition: opacity var(--aw-dur); color: var(--cw-muted); }
.htmx-request .htmx-indicator, .htmx-indicator.htmx-request { opacity: 1; }

/* ============================ 13. НАВИГАЦИЯ ========================== */
/* style.css прячет .cw-nav-track при ≤1400px в расчёте на гамбургер .cw-nav-mobile,
   которого в нашем base.html нет → на ноутах/планшетах/мобиле меню пропадало.
   У AdminWash всего 6-7 пунктов — на десктопе/планшете показываем pill-меню
   (со скроллом на узком), на телефоне ≤560px переключаемся на гамбургер. */
/* Меню всегда видимо (pill-трек). На узких экранах скроллится горизонтально
   (overflow-x:auto в style.css). Гамбургер .cw-nav-toggle/.cw-burger УДАЛЁН
   (2026-06-07): на десктопе он мешал, а на мобиле горизонтальный скролл проще
   и предсказуемее. .cw-nav-toggle на всякий случай прячем (вдруг где-то остался). */
/* Пунктов меню стало 10+ — в одну строку на ПК не влезают. Раньше был
   overflow-x:auto + justify-content:center (style.css): на десктопе мышь горизонтально
   НЕ листает (скроллбар скрыт), а центрирование ОБРЕЗАЛО крайние пункты («не листается»).
   Решение: перенос на 2-ю строку (flex-wrap) — все пункты всегда видны без скролла;
   на узких экранах правила ниже (≤768/≤560) переносят трек отдельной строкой. */
.cw-nav-track {
  display: flex !important;
  flex-wrap: wrap;
  row-gap: 0.2rem;
  justify-content: center;
}
.cw-nav-item { flex: 0 0 auto; }   /* пункт не сжимается — текст не режется */
.cw-nav-mobile, .cw-nav-toggle { display: none !important; }

/* Чип темы: иконка солнце/луна (CSS-переключение по data-theme, без JS-SVG).
   .cw-chip-icon фикс 16px — кладём ТОЛЬКО иконку (не текст), иначе текст не влезал
   и слипался с подписью («ТемаСветлая»). */
.cw-chip-icon .aw-ico { width: 16px; height: 16px; }
.theme-ico-moon { display: none; }
[data-theme="dark"] .theme-ico-sun { display: none; }
[data-theme="dark"] .theme-ico-moon { display: inline-flex; }

/* ============================ 16. ИКОНКИ / МОДАЛКИ ================== */
/* Единая иконка (inline SVG из app/icons.py). stroke=currentColor → тема/цвет
   наследуются. Выравнивание по тексту. См. правило «Иконки» в CLAUDE.md. */
.aw-ico { display: inline-block; width: 1em; height: 1em; vertical-align: -0.125em;
          flex: 0 0 auto; }
/* В кнопках с текстом ("{{ icon('plus') }} Добавить") — зазор справа от иконки. */
.cw-btn-small .aw-ico, .cw-btn-mini .aw-ico, .cw-btn-large .aw-ico,
button .aw-ico + *, a .aw-ico + * { }
.cw-btn-small > .aw-ico:first-child, .cw-btn-mini > .aw-ico:first-child {
  margin-right: .4em; }

/* Кнопка-иконка (icon-only): СТРОГО фиксированный квадрат 2rem (= высота
   .cw-btn-small), чтобы иконки не «скакали». width/height обязательны: Pico
   ставит `button{width:100%}` — без фикс-ширины иконка-кнопка растягивается на
   100% и ломает строку (корзина в <form> уезжала вниз). Специфичность .aw-icon-btn
   (0,1,0) бьёт Pico (0,0,1). flex:0 0 auto — не сжимается/не растёт в flex-ряду. */
/* button.aw-icon-btn в селекторе ОБЯЗАТЕЛЕН: Pico задаёт button[type=submit]{width:100%}
   со специфичностью (0,1,1) — голый .aw-icon-btn (0,1,0) проигрывал, и submit-иконка в
   shrink-to-fit форме схлопывалась до ширины svg (17px, архив на Главной 2026-07-23). */
.aw-icon-btn, button.aw-icon-btn {
               background: transparent; border: 0; padding: 0; margin: 0;
               width: 2rem; height: 2rem; min-height: 2rem; flex: 0 0 auto;
               box-sizing: border-box; line-height: 0; cursor: pointer;
               color: var(--cw-muted); vertical-align: middle;
               display: inline-flex; align-items: center; justify-content: center;
               border-radius: var(--aw-r-sm); transition: background var(--aw-dur), color var(--aw-dur); }
.aw-icon-btn .aw-ico { width: 17px; height: 17px; }
.aw-icon-btn:hover { background: var(--aw-accent-soft); color: var(--aw-accent); }
/* Иконка удаления — на hover краснеет. */
.aw-icon-btn.aw-icon-danger:hover { background: var(--aw-danger-soft); color: var(--aw-danger); }
/* Взведённое состояние двойного подтверждения (awArmConfirm в base.html) — заливка
   держится и БЕЗ hover, иначе после первого клика на телефоне (нет hover) кнопка
   выглядит как обычная, и непонятно, что она уже «взведена» и ждёт второго клика. */
.aw-icon-btn.is-armed { background: var(--aw-danger-soft); color: var(--aw-danger); }

/* === Строгие ряды действий (кнопки/иконки не «скачут») ===
   Действие-иконки группируем в inline-flex ряд фикс-высоты, без переноса.
   Форма-обёртка одиночной кнопки НЕ должна быть блоком (Pico делает form
   блочной с margin) — иначе кнопка/иконка уходит на новую строку. */
.aw-actions { display: inline-flex; align-items: center; gap: 2px; flex: 0 0 auto; }
.aw-actions form,
.aw-head-meta form { display: inline-flex; align-items: center; margin: 0; }
/* Шапка карточки (заголовок + мета/действия справа) — всё по центру по вертикали,
   мета — строгий inline-flex ряд без переноса. */
.aw-head { align-items: center; }
.aw-head-meta { display: inline-flex; align-items: center; gap: var(--aw-s2);
                white-space: nowrap; }

/* === Группировка по мойкам (Мониторинг и т.п.) ===
   Каждая мойка — отдельный сворачиваемый блок (горизонтальная полоса), а не
   один общий список всех постов. */
.aw-wash-cols { display: flex; flex-direction: column; gap: var(--aw-s3); }
.aw-wash-group { border: 1px solid var(--cw-border); border-radius: var(--aw-r-md);
                 background: var(--cw-bg-soft, transparent); padding: 0 var(--aw-s3); }
.aw-wash-group > summary { cursor: pointer; padding: var(--aw-s2) var(--aw-s1);
                 display: flex; align-items: center; gap: var(--aw-s2);
                 font-size: var(--aw-fs-sm); }
.aw-wash-group > summary::-webkit-details-marker { color: var(--cw-muted); }
.aw-wash-group[open] > summary { border-bottom: 1px solid var(--cw-border);
                 margin-bottom: var(--aw-s2); }
.aw-wash-group > figure { margin: 0 0 var(--aw-s2) 0; }

/* Подсветка строк состояния поста по итоговому уровню (зелёный/жёлтый/красный).
   Полупрозрачные тинты — работают и в светлой, и в тёмной теме поверх фона строки.
   Левый акцент на первой ячейке для быстрого скан-чтения. */
.aw-state-table tr.aw-row-ok   > td { background: rgba(40,170,90,.07); }
.aw-state-table tr.aw-row-warn > td { background: rgba(245,166,35,.13); }
.aw-state-table tr.aw-row-err  > td { background: rgba(211,47,47,.12); }
.aw-state-table tr.aw-row-ok   > td:first-child { box-shadow: inset 3px 0 0 var(--cw-positive, #28a85a); }
.aw-state-table tr.aw-row-warn > td:first-child { box-shadow: inset 3px 0 0 #f5a623; }
.aw-state-table tr.aw-row-err  > td:first-child { box-shadow: inset 3px 0 0 var(--cw-negative, #d32f2f); }
.aw-state-table tr.aw-row-info > td:first-child { box-shadow: inset 3px 0 0 var(--cw-border, #ccc); }
.aw-state-table tr.is-stale > td { opacity: .65; }
.aw-wash-group > figure { overflow-x: auto; }
/* Все ячейки таблицы состояния — по вертикали по центру, бейджи не «гуляют». */
.aw-state-table td, .aw-state-table th { vertical-align: middle; }
.aw-state-table .cw-badge { vertical-align: middle; margin: 0; }
/* Ячейка «Статус» — СТРОГИЙ flex-ряд: бейдж + чип всегда на месте, фикс gap,
   центр по вертикали, без переноса и без зависимости от пробелов в разметке. */
.aw-status-cell { display: inline-flex; align-items: center; gap: var(--aw-s2);
                  line-height: 1; vertical-align: middle; }
.aw-status-cell .aw-issues-btn { margin: 0; }

/* ===== Центр уведомлений /alerts + бейдж навбара ===== */
.aw-nav-badge { display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.1rem; height: 1.1rem; padding: 0 .35rem; margin-left: .35rem;
  font-size: .72rem; font-weight: 700; line-height: 1; border-radius: 999px;
  background: var(--cw-muted, #888); color: #fff; vertical-align: middle; }
.aw-nav-badge.warn { background: #f5a623; color: #1a1a1a; }
.aw-nav-badge.err  { background: var(--cw-negative, #d32f2f); color: #fff; }
.aw-alerts-summary { display: flex; flex-wrap: wrap; gap: var(--aw-s2); align-items: center; }
.aw-alert-row { display: flex; align-items: center; gap: var(--aw-s2); flex-wrap: wrap;
  padding: var(--aw-s2) var(--aw-s1); border-bottom: 1px solid var(--cw-border); }
.aw-alert-row:last-child { border-bottom: 0; }
.aw-alert-row.aw-row-err  { box-shadow: inset 3px 0 0 var(--cw-negative, #d32f2f); }
.aw-alert-row.aw-row-warn { box-shadow: inset 3px 0 0 #f5a623; }
.aw-alert-kind { flex: 1 1 16rem; min-width: 0; }
.aw-alert-label { flex: 0 0 auto; }
.aw-alert-go { margin-left: auto; flex: 0 0 auto; }
.aw-event-row { display: flex; gap: var(--aw-s2); align-items: baseline;
  padding: 2px 0; border-bottom: 1px solid var(--cw-border); }
.aw-event-row:last-child { border-bottom: 0; }
.aw-event-txt { flex: 1 1 auto; min-width: 0; }
/* ДЕСКТОП (>768px): фиксированная разметка — ширины из <colgroup>, не из контента.
   Иначе при поллинге (#mon-body перерисовывается каждые 10с) колонки пересчитывались
   по данным и таблица «скакала». nowrap — нет переноса (стабильная высота строк, нет
   «рест.131» на 2-й строке/обрезанных заголовков). min-width даёт место; уже вьюпорт →
   figure скроллится по горизонтали. На мобиле (≤768px) cw-tx-table — карточки, эти
   правила НЕ применяем. */
@media (min-width: 769px) {
  .aw-state-table { table-layout: fixed; width: 100%; min-width: 1150px; }
  .aw-state-table th, .aw-state-table td { white-space: nowrap; overflow: hidden; }
}
/* Кликабельный чип «проблемы/предупреждения» в ячейке Статус → открывает модалку. */
.aw-issues-btn { cursor: pointer; display: inline-flex; align-items: center; gap: 3px;
                 margin-left: var(--aw-s2); font: inherit; vertical-align: middle; }
.aw-issues-btn .aw-ico { width: 13px; height: 13px; flex: 0 0 auto; }
.aw-issues-btn:hover { filter: brightness(.92); }

/* Список технических оповещений в модалке. */
.aw-issues-list { list-style: none; margin: 0; padding: 0; display: flex;
                  flex-direction: column; gap: var(--aw-s2); }
.aw-issues-item { padding: var(--aw-s2) var(--aw-s3); border-radius: var(--aw-r-sm);
                  font-size: var(--aw-fs-sm); line-height: 1.35;
                  border-left: 3px solid var(--cw-border); background: var(--cw-bg-soft, transparent); }
.aw-issues-item.aw-issues-err  { border-left-color: var(--cw-negative, #d32f2f);
                  background: rgba(211,47,47,.08); }
.aw-issues-item.aw-issues-warn { border-left-color: #f5a623; background: rgba(245,166,35,.10); }
/* Шапка карточки с заголовком слева и кнопкой/иконкой справа. */
.aw-head-row { display: flex; align-items: center; justify-content: space-between; gap: var(--aw-s2); }
.aw-head-row > strong { flex: 1; }

/* Нативный <dialog> с нашими токенами.
   ВАЖНО (ревью 2026-07-23): Pico 2 задаёт dialog{display:flex;position:fixed;inset:0;
   min-width:100%;min-height:100%} — диалог у него ФУЛЛСКРИН-контейнер, а карточку
   рисует dialog>article. Из-за min-width:100% наши width/max-width были МЕРТВЫ,
   а диалоги без <article> (h3+form) раскладывались flex-СТРОКОЙ на весь экран.
   Здесь возвращаем .aw-dialog поведение «сам диалог = карточка»: block-раскладка,
   min-* сброшены, центрирование = inset:0 (Pico) + margin:auto + fit-content. */
.aw-dialog { display: block; min-width: 0; min-height: 0; height: fit-content;
             margin: auto; max-height: 85vh; overflow: auto;
             border: 1px solid var(--cw-border); border-radius: var(--aw-r-md);
             padding: var(--aw-s5); max-width: 400px; width: 90vw;
             background: var(--cw-bg-soft); color: inherit;
             box-shadow: var(--aw-sh-lg); }
/* Вложенный Pico-article внутри .aw-dialog больше НЕ вторая карточка:
   рамку/фон/паддинг даёт сам диалог, article — прозрачная обёртка контента.
   НАЙДЕНО ЖИВЬЁМ (модалка настроек /alerts): Pico сам вешает на dialog>article
   `max-height:calc(100vh - 2*spacing); overflow:auto` — вместе с нашим
   overflow:auto на .aw-dialog это ДВА независимых скролла один в другом.
   Сбрасываем article — прокрутка только одна, снаружи, у .aw-dialog. Правка
   общая для всех модалок на .aw-dialog, не только для /alerts. */
.aw-dialog > article { margin: 0; padding: 0; background: transparent;
                       border: 0; box-shadow: none; width: 100%; max-width: none;
                       max-height: none; overflow: visible; }
.aw-dialog::backdrop { background: rgba(0,0,0,.5); }
.aw-dialog h3 { margin: 0 0 var(--aw-s3); font-size: var(--aw-fs-base); }
.aw-dialog label { display: block; margin-bottom: var(--aw-s3); }

/* ============================ 15. КАРТОЧКА ПОСТА ===================== */
/* Цель: ровные секции, единые отступы/шрифты, контролы не на всю ширину. */
/* Контент карточки не растягиваем на ультра-широких мониторах. */
.aw-card { max-width: 1100px; }
/* Единый ритм заголовков секций (одинаковый отступ у всех article). */
.aw-card article > header { margin-bottom: var(--aw-s3); }
.aw-card article { margin-bottom: var(--aw-s4); }

/* key-value грид (блок «Статус»): метка слева, значение справа, ровные строки */
.aw-kv { display: grid; grid-template-columns: max-content 1fr; gap: var(--aw-s2) var(--aw-s4);
         font-size: var(--aw-fs-sm); margin: var(--aw-s3) 0 0; }
.aw-kv dt { color: var(--cw-muted); }
.aw-kv dd { margin: 0; text-align: right; word-break: break-word; }
.aw-kv dd code { font-size: var(--aw-fs-xs); }

/* список «устройство → драйвер»: ровные строки с разделителями */
.aw-dev-list { display: flex; flex-direction: column; margin-top: var(--aw-s2); }
.aw-dev-row { display: grid; grid-template-columns: 1fr auto; align-items: center;
              gap: var(--aw-s3); padding: var(--aw-s3) 0; border-bottom: 1px solid var(--cw-border); }
.aw-dev-row:first-child { padding-top: 0; }
.aw-dev-row:last-child { border-bottom: 0; padding-bottom: 0; }
.aw-dev-name { display: flex; align-items: center; gap: var(--aw-s2); flex-wrap: wrap; }
.aw-dev-sub { color: var(--cw-muted); font-size: var(--aw-fs-xs); margin-top: 3px; word-break: break-all; }
.aw-dev-ctl { display: flex; justify-content: flex-end; }
/* Контролы в карточке поста — фикс-ширина, не на всю карточку */
.aw-dev-ctl select, .aw-card select:not([multiple]) { margin: 0; max-width: 15rem; }
.aw-card form.inline { margin: 0; }

/* СТРОГАЯ сетка операционных карточек: 2 ровные колонки, align-items:stretch →
   карточки в одном ряду одной высоты (нижние края выровнены, без «дыр» между блоками).
   В отличие от masonry (CSS columns) сетка НЕ переупаковывается при HTMX-загрузке
   карточек → блоки не «скачут». На узком экране — 1 колонка. */
.aw-post-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--aw-s4);
                align-items: stretch; }
.aw-post-grid > article { margin: 0; }
/* HTMX-карточки (Кнопки K1-K6, Карт-ридер) резервируют высоту под будущий контент,
   чтобы swap «Загрузка…» -> форма меньше менял высоту ряда. */
.aw-post-grid #buttons-box { min-height: 10rem; }
.aw-post-grid #cr-box { min-height: 4rem; }
/* Ряд действий: формы-обёртки одиночных кнопок без отступов Pico и inline-flex —
   иначе margin формы сбивал вертикаль и кнопки (с Live-ссылкой) «скакали». */
.aw-btn-row form { margin: 0; display: inline-flex; }

/* «Деньги поста» — прямоугольник на всю ширину (вверху, сразу после «Статус»). */
.aw-money figure { margin: 0; }
.aw-money table.cw-tx-table { width: 100%; }

/* Submit-кнопки в inline-формах карточки поста НЕ растягиваются на всю ширину.
   Pico ставит button[type=submit]{width:100%} (специфичнее .cw-btn-small{width:auto}),
   и внутри form.inline (flex) это раздувало «Сохранить привязку»/«Добавить деньги» на
   всю оставшуюся ширину строки → кнопки «плясали». Спецификатор .aw-card form.inline …
   перебивает Pico. Только ≥561px: на ≤560 кнопки наоборот full-width (тач-таргеты). */
@media (min-width: 561px) {
  /* Выравнивание inline-форм применяем к .aw-card И к .aw-money / .aw-status —
     §33 вынесла туда форму «Начислить на пост» и ряды кнопок (label/input/кнопка
     стояли вразнобой, т.к. правила были только для .aw-card). label центрируется
     с контролами через base-правило form.inline{align-items:center}. */
  :is(.aw-card, .aw-money, .aw-status) form.inline button[type="submit"],
  :is(.aw-card, .aw-money, .aw-status) form.inline .cw-btn-small { width: auto; }
  /* Единая ВЫСОТА контролов в ряду inline-формы (select / число / кнопка) → ровно по
     одной линии. Pico-инпуты ~2.5rem, а .cw-btn-small был 2rem → «разный горизонт». */
  :is(.aw-card, .aw-money, .aw-status) form.inline select:not([multiple]),
  :is(.aw-card, .aw-money, .aw-status) form.inline input:not([type="checkbox"]):not([type="radio"]),
  :is(.aw-card, .aw-money, .aw-status) form.inline .cw-btn-small,
  :is(.aw-card, .aw-money, .aw-status) form.inline button[type="submit"] {
    height: 2.5rem; min-height: 2.5rem; box-sizing: border-box; vertical-align: middle;
    /* margin:0 ОБЯЗАТЕЛЕН: Pico ставит input/select{margin-bottom} (верт.ритм), а
       align-items:center центрирует MARGIN-box → инпут «всплывал» на ~7px выше label
       и кнопки (разнобой). Сброс margin → все элементы центрируются по одной линии. */
    margin: 0;
  }
  /* при фикс. высоте убираем большой вертикальный padding Pico у инпутов/селектов
     (горизонтальный остаётся), чтобы текст центрировался и не упирался */
  :is(.aw-card, .aw-money, .aw-status) form.inline select:not([multiple]),
  :is(.aw-card, .aw-money, .aw-status) form.inline input:not([type="checkbox"]):not([type="radio"]) {
    padding-top: var(--aw-s1); padding-bottom: var(--aw-s1);
  }
  /* Pico ставит input{width:100%} со специфичностью (0,1,1). В flex-контейнере
     flex-basis:100% расталкивает элементы (ширина «плавает» от контейнера).
     width:auto + flex:0 0 auto отменяют это: инпут берёт только свою intrinsic ширину,
     не растягивается, кнопка остаётся рядом. */
  :is(.aw-card, .aw-money, .aw-status) form.inline input:not([type="checkbox"]):not([type="radio"]) {
    width: auto;
    flex: 0 0 auto;
    min-width: 7rem;
  }
  /* «Статус» на всю ширину — kv в 2 пары (метка/значение) в ряд, чтобы не пустовало */
  .aw-status .aw-kv { grid-template-columns: max-content 1fr max-content 1fr; }
}

/* ============================ 17. МОТОРЕСУРС ========================= */
/* Один пост внутри карточки мойки: тонкий разделитель сверху между постами.
   Две таблицы (реле/программы) — в .aw-grid-2 (сама схлопывается в 1 колонку). */
.aw-motor-post { padding-top: var(--aw-s4); margin-top: var(--aw-s4); border-top: 1px solid var(--cw-border); }
.aw-motor-post:first-child { padding-top: 0; margin-top: 0; border-top: none; }
.aw-motor-post .aw-head { margin-bottom: var(--aw-s3); }
.aw-motor-sub { font-size: var(--aw-fs-xs); color: var(--cw-muted);
                margin: 0 0 var(--aw-s1); font-weight: 600; text-transform: uppercase; letter-spacing: .03em; }
/* Ресурс реле: прогресс наработка/норматив + % + бейдж (цвет по статусу ok/warn/err). */
.aw-res-cell { display: inline-flex; align-items: center; gap: var(--aw-s2); flex-wrap: wrap; }
.aw-res { width: 90px; height: 8px; vertical-align: middle; margin: 0; border: none;
          -webkit-appearance: none; appearance: none; border-radius: var(--aw-r-pill);
          overflow: hidden; background: var(--cw-bg-soft); }
/* Три уровня ресурса — не три новых цвета (было зелёный/жёлтый/красный, ни
   один не из палитры). Канон design-system.md §3: холодный = норма, тёплый =
   единственный сигнал реакции; "внимание"/"пора менять" — тот же тёплый, две
   насыщенности (глубокий цвет опаснее полупрозрачного), а не два разных цвета. */
.aw-res::-webkit-progress-bar { background: var(--yeti-cold-wash, var(--cw-bg-soft)); border-radius: var(--aw-r-pill); }
.aw-res-ok::-webkit-progress-value   { background: var(--yeti-cold-deep, var(--cw-positive)); }
.aw-res-warn::-webkit-progress-value { background: color-mix(in srgb, var(--yeti-warm, #d9a400) 55%, var(--yeti-cold-wash, #fff)); }
.aw-res-err::-webkit-progress-value  { background: var(--yeti-warm, var(--cw-negative)); }
.aw-res-ok::-moz-progress-bar   { background: var(--yeti-cold-deep, var(--cw-positive)); }
.aw-res-warn::-moz-progress-bar { background: color-mix(in srgb, var(--yeti-warm, #d9a400) 55%, var(--yeti-cold-wash, #fff)); }
.aw-res-err::-moz-progress-bar  { background: var(--yeti-warm, var(--cw-negative)); }
.aw-res-pct { font-variant-numeric: tabular-nums; white-space: nowrap; }
.aw-res-sub { display: block; margin-top: 2px; }

/* ============================ 14. АДАПТИВ ============================ */
/* Брейкпоинты: md=768 (планшет/телефон-альбом), sm=560 (телефон).
   Базовые правила (16px шрифт, 44px тач-таргеты, скролл широких таблиц,
   карточный вид .cw-tx-table) приходят из style.css. Здесь — слой AdminWash. */

@media (max-width: 768px) {
  /* навбар: бренд+чипы в строку, pill-меню — отдельной строкой под ними.
     ВНИМАНИЕ: тот же id/class-баг, что у подсветки активного пункта — у <nav>
     id="cw-nav-track", не class, правило ниже ни разу не срабатывало
     (найдено 2026-07-27 в той же проверке). */
  .cw-topbar { flex-wrap: wrap; }
  #cw-nav-track { order: 3; width: 100%; }
  .aw-page-head { gap: var(--aw-s2); }
  .aw-controls, .aw-controls .dates { width: 100%; }
  .aw-controls .dates label { flex: 1 1 auto; }
  form.inline { width: 100%; }
  form.inline > select, form.inline > input { flex: 1 1 8rem; min-width: 0; }
  /* Кнопка «Обнулить» в шапке карточки поста (.aw-head-row) — форма-обёртка
     ОДНОЙ icon-кнопки, не фильтр с select/input: общее mobile-правило
     form.inline{width:100%} раздувало её на всю строку, из-за чего вместе с
     .aw-head-row{flex-wrap:wrap} кнопка уезжала на отдельную строку под
     названием поста вместо своего места справа от него (владелец, скриншот
     /motors). */
  .aw-head-row form.inline { width: auto; }
  .aw-inp-num, table .aw-inp.cw-num { max-width: none; }
  .aw-grid-2 { grid-template-columns: 1fr; }
  .aw-post-grid { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  .aw-posts { grid-template-columns: 1fr; }
  /* «железо → драйвер»: имя сверху, контрол снизу на всю ширину */
  .aw-dev-row { grid-template-columns: 1fr; gap: var(--aw-s2); }
  .aw-dev-ctl { justify-content: stretch; }
  .aw-dev-ctl form.inline, .aw-dev-ctl select { width: 100%; }
  .aw-dev-ctl select, .aw-card select:not([multiple]) { max-width: none; }

  /* Узкий экран: бренд + чипы в строку, pill-меню — отдельной строкой ниже,
     скроллится горизонтально (без гамбургера). */
  .cw-topbar { gap: var(--aw-s2); }
  .cw-brand { order: 1; flex: 1 1 auto; }
  .cw-nav-actions { order: 2; flex: 0 0 auto; gap: var(--aw-s2); }
  .cw-nav-track { order: 3; width: 100%; justify-content: flex-start; }
  .cw-nav-actions .cw-chip, .cw-nav-actions .cw-user-chip { min-height: 40px; }

  /* Карточка поста — тач-таргеты и компактные кнопки на всю ширину. */
  :is(.aw-card, .aw-money, .aw-status) .cw-btn-small,
  :is(.aw-card, .aw-money, .aw-status) button[type="submit"],
  :is(.aw-card, .aw-money, .aw-status) .aw-btn-ghost,
  :is(.aw-card, .aw-money, .aw-status) .aw-btn-danger { min-height: 44px; padding: 10px 14px; }
  :is(.aw-card, .aw-money, .aw-status) form.inline { display: flex; flex-direction: column; gap: var(--aw-s2);
                         align-items: stretch; }
  :is(.aw-card, .aw-money, .aw-status) form.inline > * { width: 100%; }
  .aw-card .aw-stack { gap: var(--aw-s3); }
  .aw-card .aw-btn-row { flex-wrap: wrap; gap: var(--aw-s2); }
  .aw-card .aw-btn-row > * { width: 100%; }
}

/* ============================================================
 * 17. Кнопки-вкладки Админки — обычные кнопки в ряд, активная — акцент
 * ============================================================ */
.aw-tabnav { flex-wrap: wrap; gap: var(--aw-s2, .35em); }
.aw-tabnav .cw-btn-small {
  min-width: 110px;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.aw-tabnav .cw-btn-small.is-active {
  background: var(--aw-accent);
  color: var(--aw-accent-contrast, #fff);
  border-color: var(--aw-accent);
}
.aw-tabnav .cw-btn-small.is-active:hover {
  background: var(--aw-accent-hover, var(--aw-accent));
  color: var(--aw-accent-contrast, #fff);
}


/* ===== Переключатель типа пульта МСО/РОБОТ в «Экраны» (один редактор-меню, два режима) ===== */
.aw-ui-toggle { display: inline-flex; gap: 0; border: 1px solid var(--aw-accent, #3478d1);
  border-radius: 8px; overflow: hidden; flex: 0 0 auto; }
.aw-ui-pill { display: inline-flex; align-items: center; height: 2rem; padding: 0 .75rem;
  font-size: .8rem; font-weight: 700; letter-spacing: .02em; text-decoration: none;
  color: var(--aw-accent, #3478d1); background: transparent; box-sizing: border-box;
  border: 0; white-space: nowrap; }
.aw-ui-pill + .aw-ui-pill { border-left: 1px solid var(--aw-accent, #3478d1); }
.aw-ui-pill:hover { background: var(--aw-accent-soft, rgba(52,120,209,.10)); }
.aw-ui-pill.is-active { background: var(--aw-accent, #3478d1);
  color: var(--aw-accent-contrast, #fff); cursor: default; }

/* ===== §analytics — графики /analytics (server-rendered SVG, темизируемые) ===== */
.aw-chart { display: block; width: 100%; height: auto; }
.aw-chart-axis { stroke: var(--cw-border, #d8dde3); stroke-width: 1; }
.aw-chart-x, .aw-chart-y { fill: var(--cw-muted, #8a929c); font-size: 9px; }
.aw-chart-y { font-size: 10px; }
.aw-bar { fill: var(--aw-accent, #3478d1); fill-opacity: .55; transition: fill-opacity .12s; }
.aw-bar:hover { fill-opacity: .9; }
.aw-bar-max { fill-opacity: .95; }
.aw-area { fill: var(--aw-accent, #3478d1); fill-opacity: .12; stroke: none; }
.aw-line { fill: none; stroke: var(--aw-accent, #3478d1); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.aw-line-dot { fill: var(--aw-accent, #3478d1); }
.aw-heat-wrap { overflow-x: auto; }
.aw-heat { display: block; width: 100%; height: auto; min-width: 560px; max-width: 760px; }
.aw-hm-cell { fill: var(--aw-accent, #3478d1); stroke: var(--cw-border, #e3e6ea); stroke-width: .5; }
.aw-hm-cell:hover { stroke: var(--aw-accent, #3478d1); stroke-width: 1.5; }
/* каналы оплаты — stacked-доли (нал/карта/СБП/сервис) */
.aw-st { stroke: var(--cw-bg, #fff); stroke-width: .5; transition: fill-opacity .12s; }
.aw-st:hover { fill-opacity: .82; }
.aw-st-cash { fill: #9aa4b0; }
.aw-st-card { fill: var(--aw-accent, #3478d1); }
.aw-st-sbp { fill: #2e9e6b; }
.aw-st-service { fill: #d98a2b; }
.aw-st-leyka { fill: #7e57c2; }
.aw-st-legend { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: .4rem; }
.aw-st-key { display: inline-flex; align-items: center; gap: .3rem; }
.aw-st-sw { width: 11px; height: 11px; border-radius: 2px; display: inline-block; }
.aw-st-sw.aw-st-cash { background: #9aa4b0; }
.aw-st-sw.aw-st-card { background: var(--aw-accent, #3478d1); }
.aw-st-sw.aw-st-sbp { background: #2e9e6b; }
.aw-st-sw.aw-st-service { background: #d98a2b; }
.aw-st-sw.aw-st-leyka { background: #7e57c2; }
/* промо-метки (вертикали) и полосы активных окон скидки/наценки на тренде */
.aw-pmark { stroke: #d98a2b; stroke-width: 1.2; stroke-dasharray: 3 2; opacity: .85; }
.aw-pmark-discount, .aw-pmark-bonus { stroke: #2e9e6b; }
.aw-pmark-dynamic { stroke: #c0392b; }
.aw-pband { fill: #9aa4b0; fill-opacity: .10; }
.aw-pband-disc { fill: var(--aw-accent, #3478d1); fill-opacity: .08; }
.aw-pband-surge { fill: #c0392b; fill-opacity: .08; }
.aw-pleg { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: .35rem; }
.aw-an-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--aw-s3, .75rem); margin: var(--aw-s3, .75rem) 0; }
.aw-an-kpi { background: var(--cw-bg-soft, #f6f8fa); border: 1px solid var(--cw-border, #e3e6ea);
  border-radius: var(--aw-r, 8px); padding: var(--aw-s3, .75rem); margin: 0; }
/* шапка раздела с шестерёнкой + модалка настроек */
.aw-an-head { display: flex; align-items: center; justify-content: space-between;
  gap: var(--aw-s2, .5rem); }
.aw-an-head h2 { margin: 0; }
.aw-an-settings { border: 1px solid var(--cw-border, #e3e6ea); border-radius: var(--aw-r, 8px);
  padding: 0; max-width: 540px; width: calc(100% - 2rem); background: var(--cw-bg-soft, #fff);
  color: var(--cw-text, inherit);
  /* как у .aw-dialog: сброс Pico min-width/min-height:100% (иначе фуллскрин),
     центрирование inset:0 + margin:auto, собственная прокрутка */
  min-width: 0; min-height: 0; height: fit-content; margin: auto;
  max-height: 90vh; overflow: auto; }
.aw-an-settings::backdrop { background: rgba(0,0,0,.45); }
.aw-an-settings .aw-card { margin: 0; max-width: none; }
.aw-an-saved { border-left: 3px solid var(--aw-accent, #3478d1); }
.aw-an-err { border-left: 3px solid var(--cw-err, #c0392b); }
.aw-an-check { display: flex; gap: .4rem; align-items: center; }
.aw-an-check input { width: auto; }
.aw-an-settings input[type="password"], .aw-an-settings input[type="text"] { width: 100%; }
.aw-an-settings textarea { width: 100%; box-sizing: border-box; resize: vertical; min-height: 4.5rem; }
/* ИИ-инсайты (дайджест) — компактный единообразный блок */
.aw-digest-spoiler { border: 1px solid var(--cw-border, #e3e6ea); border-radius: var(--aw-r, 8px);
  padding: var(--aw-s2, .5rem) var(--aw-s3, .75rem); }
.aw-digest-sumhead { cursor: pointer; display: flex; align-items: baseline; flex-wrap: wrap;
  gap: var(--aw-s2, .5rem); list-style-position: outside; }
.aw-digest-sumhead::-webkit-details-marker { color: var(--cw-muted, #6b7280); }
.aw-digest-body { margin-top: var(--aw-s2, .5rem); }
.aw-digest-bar { display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--aw-s2, .5rem); margin: var(--aw-s2, .5rem) 0; }
.aw-digest { border: 1px solid var(--cw-border, #e3e6ea); border-radius: var(--aw-r, 8px);
  padding: var(--aw-s3, .75rem); }
.aw-digest-sum { margin: .25rem 0 .5rem; }
.aw-digest-h { font-size: .82rem; font-weight: 600; color: var(--cw-muted, #6b7280);
  margin: .55rem 0 .2rem; }
.aw-digest-list { margin: .2rem 0; padding-left: 1.1rem; }
.aw-digest-list li { margin: .28rem 0; }
.aw-digest-rec-line { margin: .05rem 0 .05rem .1rem; }
.aw-pos { color: var(--cw-ok, #2e7d32); }
.aw-neg { color: var(--cw-err, #c0392b); }

/* ===== §stats — сводка, доли каналов, строгая сетка таблиц, режим «Кратко» ===== */
.aw-share { display: block; width: 100%; height: 14px; border-radius: 3px; }
.aw-qr { display: inline-flex; align-items: center; flex-wrap: wrap; gap: .3rem; }
/* Строгая сетка: фикс. ширины колонок → поля не «прыгают» между мойками/строками
   (только на «настольном» виде; на ≤560px таблица стекается в карточки по data-label). */
@media (min-width: 561px) {
  .aw-stats-grid { table-layout: fixed; width: 100%; }
  .aw-stats-grid th:first-child, .aw-stats-grid td:first-child { width: 17%; }
  .aw-promo-grid { table-layout: fixed; width: 100%; }
  .aw-promo-grid th:first-child, .aw-promo-grid td:first-child { width: 32%; }
}
/* Режим «Кратко» — скрыть доп-колонки (Сервис, Лейка). Класс на <body> переживает HTMX-свап #stats-body.
   Второе, более специфичное правило — для .aw-dt на мобиле: там ячейка получает
   `display: grid` от карточной раскладки (brand.css, specificity 0,2,3), и
   голого `body.stats-compact .aw-col-extra` (0,2,1) не хватает, чтобы её
   перебить — колонка «Кратко» переставала прятаться именно на ≤720px. */
body.stats-compact .aw-col-extra { display: none; }
body.stats-compact .aw-dt tbody tr:not(.aw-dt-grp) td.aw-col-extra { display: none; }
/* Шапка мойки: имя слева, метрики-чипы справа; на узких экранах переносится. */
.aw-wash-group > summary { flex-wrap: wrap; }
.aw-wg-name { font-size: var(--aw-fs-md, 1rem); }
.aw-wg-meta { margin-left: auto; display: inline-flex; flex-wrap: wrap; gap: .4rem; }
.aw-chip { display: inline-flex; align-items: center; padding: .12rem .55rem; border-radius: 999px;
  background: color-mix(in srgb, #808080 14%, var(--cw-bg-soft, #f7f8f9));
  border: 1px solid var(--cw-border, #e3e6ea);
  font-size: var(--aw-fs-xs, .78rem); white-space: nowrap; }
.aw-chip b { font-weight: 600; }

/* ===== §monitor — обзор парка + детальная страница поста ===== */
/* Сводная полоса обзора /monitor */
.aw-mon-summary { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aw-s2) var(--aw-s4);
                  padding: var(--aw-s2) var(--aw-s4); margin: 0 0 var(--aw-s4);
                  background: var(--cw-bg-soft); border: 1px solid var(--cw-border);
                  border-radius: var(--aw-r-md); font-size: var(--aw-fs-sm); }
.aw-mon-kpi { display: inline-flex; align-items: center; gap: var(--aw-s2); white-space: nowrap; }
/* Табы окна аптайма (today/7д/30д/всё) */
.aw-win-tabs { display: inline-flex; gap: 2px; margin-left: auto; flex-wrap: wrap; }
.aw-win-tab { font-size: var(--aw-fs-xs); padding: 2px var(--aw-s2); border-radius: var(--aw-r-sm);
              border: 1px solid var(--cw-border); color: var(--cw-muted); text-decoration: none; }
.aw-win-tab:hover { background: var(--surface-2, #fff); }
.aw-win-tab.is-active { background: var(--aw-accent); color: var(--aw-accent-contrast);
                        border-color: var(--aw-accent); }
/* Обрезка длинной «текущей проблемы» в строке обзора */
.aw-clip { display: inline-block; max-width: 38ch; overflow: hidden; text-overflow: ellipsis;
           white-space: nowrap; vertical-align: bottom; }
/* KPI-плитки аптайма на детальной странице */
.aw-kpi-row { display: flex; flex-wrap: wrap; gap: var(--aw-s3); margin: var(--aw-s3) 0; }
.aw-kpi { flex: 1 1 120px; min-width: 110px; padding: var(--aw-s2) var(--aw-s3);
          background: var(--cw-bg-soft); border-radius: var(--aw-r-md); }
.aw-kpi-cap { font-size: var(--yeti-fs-xs, var(--aw-fs-xs)); color: var(--yeti-ink-3, var(--cw-muted)); }
.aw-kpi-value { font-size: var(--yeti-fs-xl, 1.6rem); font-weight: 600; line-height: 1.15; }
.aw-kpi-value.ok { color: var(--yeti-ink-1, var(--cw-positive)); }
.aw-kpi-value.warn { color: var(--yeti-attn-text, #b8860b); }
.aw-kpi-value.err { color: var(--yeti-state-attn, var(--cw-negative)); }
/* key-value таблицы метрик (НЕ путать с .aw-kv = grid в карточке поста) */
.aw-mon-kv { width: 100%; border-collapse: collapse; font-size: var(--aw-fs-sm); }
.aw-mon-kv th { text-align: left; font-weight: 600; padding: var(--aw-s2) var(--aw-s2) var(--aw-s1);
                border-bottom: 1px solid var(--cw-border); }
.aw-mon-kv td { padding: var(--aw-s1) var(--aw-s2); border-bottom: 1px solid var(--cw-border);
                vertical-align: top; }
.aw-mon-kv td:first-child { color: var(--cw-muted); white-space: nowrap; }
.aw-mon-kv td:last-child { text-align: right; }
/* SVG-бары аптайма по дням (цвет — здесь, тема наследуется) */
.aw-ub-bg { fill: color-mix(in srgb, #808080 12%, transparent); }
.aw-ub-ok { fill: #2e9e6b; }
.aw-ub-warn { fill: #d8a200; }
.aw-ub-err { fill: var(--cw-negative, #d32f2f); }
.aw-ub-empty { fill: var(--cw-border, #d8dde3); fill-opacity: .45; }
.aw-ub-lbl { fill: var(--cw-muted, #8a929c); font-size: 9px; }
/* прочее */
.aw-end { justify-content: flex-end; }
.aw-mon-title { display: inline; }
.aw-issues-grp { margin: .8em 0 .3em; text-transform: uppercase; letter-spacing: .04em; }
/* Обзор сгруппирован по мойкам: строка-подзаголовок (горизонтальное отбитие) + тест-стенды серым */
.aw-mon-table tr.aw-mon-grp td { font-weight: 600; background: var(--cw-bg-soft);
  border-top: 2px solid var(--cw-border); }
.aw-mon-table tr.aw-mon-grp td::before { content: none; }
.aw-mon-table tr.aw-mon-test td { color: var(--cw-muted);
  background: color-mix(in srgb, #808080 9%, transparent); }
/* шапка группы: имя слева, кнопки выше/ниже справа */
.aw-grp-head { display: flex; align-items: center; justify-content: space-between; gap: var(--aw-s2); }
@media (max-width: 768px) {
  .aw-clip { max-width: none; white-space: normal; }
  .aw-win-tabs { margin-left: 0; }
}

/* ===== §marketing — QR привлечения: фикс-размер (без layout-jump) + единая рамка как у /analytics ===== */
.aw-mk-qr { display: block; width: 160px; height: 160px; border-radius: var(--aw-r, 8px);
  border: 1px solid var(--cw-border, #e3e6ea); }

/* ===== §geo — карта-пикер координат мойки (модалки добавления/изменения мойки) ===== */
.aw-geo { margin: var(--aw-s1) 0 var(--aw-s2); }
.aw-geo-map { height: 220px; border-radius: var(--aw-r, 8px); overflow: hidden;
  border: 1px solid var(--cw-border, #e3e6ea); }
.aw-geo-row { display: flex; align-items: center; gap: var(--aw-s2); flex-wrap: wrap; margin-top: var(--aw-s2); }
.aw-geo-val { font-size: var(--aw-fs-xs, .78rem); color: var(--cw-muted, #6b7280); flex: 1 1 auto;
  min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.aw-geo-hint { display: block; margin-top: var(--aw-s2); font-size: var(--aw-fs-xs, .78rem);
  color: var(--cw-muted, #6b7280); }
/* Leaflet z-index внутри <dialog> (тайлы/маркеры не должны вылезать поверх футера модалки) */
.aw-geo-map .leaflet-pane,
.aw-geo-map .leaflet-control { z-index: 1; }

/* ===== §loyalty — редактор уровней лояльности (/marketing) ===== */
.aw-loy-toggle { display: flex; align-items: center; gap: var(--aw-s2); font-weight: 600; }
.aw-loy-toggle input { width: auto; margin: 0; }
.aw-tiers { display: flex; flex-direction: column; gap: var(--aw-s2); }
.aw-tier-row { display: grid; grid-template-columns: minmax(0,1fr) 90px 90px; gap: var(--aw-s2); align-items: center; }
.aw-tier-row input { margin: 0; }
.aw-tier-head { color: var(--cw-muted, #6b7280); font-size: var(--aw-fs-xs, .78rem); padding: 0 2px; }
.aw-tier-head span:nth-child(2), .aw-tier-head span:nth-child(3) { text-align: right; }

/* ===== §alerts — центр уведомлений (/alerts): фильтры, mute, настройки, журнал ===== */
/* Форма фильтра — самостоятельный блок перед сводкой/таблицей, а не их часть:
   margin-bottom явный, а не расчёт на margin-top соседа (тот бывает 0 у .aw-kpis
   и 4px у голого .aw-mt1 — стык слипался или скакал в зависимости от того, что
   идёт следующим). */
.aw-alerts-set-row { flex-wrap: wrap; align-items: end; gap: var(--aw-s2, 8px);
  margin-bottom: var(--aw-s4, 1rem); }
/* margin:0 обязателен: .aw-dialog label даёт ВСЕМ label внутри модалки
   margin-bottom (нужен для одноколоночных форм), а голая <button> его не
   получает — в строке с align-items:end их margin-box'ы у разных элементов
   заканчивались на разной высоте, и кнопка "Отправить сейчас" в ряду
   дайджеста вставала на 11px ниже поля/селекта рядом. */
.aw-alerts-set-row label { display: inline-flex; flex-direction: column; gap: 2px;
  font-size: var(--aw-fs-xs, .78rem); color: var(--cw-muted, #6b7280); white-space: nowrap;
  margin: 0; }
/* Чекбокс «только открытые» — исключение из «подпись сверху / контрол снизу»
   выше: для пары чекбокс+текст это переворачивало их в столбец на ЛЮБОЙ
   ширине >768px (правило было заперто внутри @media max-width:768px и не
   действовало на обычном десктопе админки). Снято из media — работает везде. */
.aw-alerts-set-row label:has(> input[type="checkbox"]) {
  flex-direction: row; align-items: center; gap: var(--aw-s2); }
/* Высота у всех контролов ряда — 2rem (как .cw-btn-small), иначе Pico задаёт
   input/select собственную формулу calc(...) и в ряду с дайджестом инпут часа
   выходил заметно ниже соседней кнопки "Отправить сейчас". Специфичность
   .aw-alerts-set-row input.aw-inp (2 класса + тег) выше, чем у Pico
   input:not(...) — тут переопределение реально работает.
   ВАЖНО: одной высоты мало — Pico даёт select/input свой вертикальный padding
   (~7px сверху и снизу) и line-height, вместе им нужно ~35px, а box-sizing:
   border-box сжимает именно ВНУТРЕННЕЕ место под текст до высоты минус
   padding — при height:2rem (29px) тексту оставалось меньше, чем его
   собственная строка, и он обрезался по факту (не просто "мельче", а
   визуально пропадал). Убираем вертикальный padding и даём line-height:1,
   как уже сделано у .aw-inp-num — тот же приём, тот же результат. */
.aw-alerts-set-row select.aw-inp, .aw-alerts-set-row input.aw-inp {
  margin: 0; height: 2rem; padding-top: 0; padding-bottom: 0; line-height: 2rem;
}
/* min-width — ТОЛЬКО для select-фильтров (Уровень/Мойка/Период): без явной
   ширины <select> сайзится нативно по САМОМУ ДЛИННОМУ <option> — «Уровень» и
   «Мойка» получали разную ширину на глаз. :not(.aw-inp-num) — иначе то же
   правило растягивало часовой инпут дайджеста (2 цифры) до нужной ширины,
   хотя у .aw-inp-num уже есть свой узкий max-width:8rem.
   16rem, а не 12rem: на реальных данных прода «критические + внимание»
   (уровень дайджеста) обрезалось — 12rem мерялся только на короткой «все»
   (значение по умолчанию в макетных тестах), самый длинный реальный вариант
   длиннее почти вдвое. */
.aw-alerts-set-row select.aw-inp:not(.aw-inp-num),
.aw-alerts-set-row input.aw-inp:not(.aw-inp-num) { min-width: 16rem; }
@media (max-width: 560px) {
  /* На узком экране ряд и так становится колонкой — каждый фильтр занимает
     всю ширину, иначе несовпадающие min-width дают ту же кривизну, что и
     нативный auto. */
  .aw-alerts-set-row label { width: 100%; }
  /* height:44px — не 2rem, как на десктопе: соседняя кнопка в этом же ряду
     (например "Отправить сейчас") на мобиле получает тач-цель 44px по общему
     правилу :is(.aw-card,...) .cw-btn-small{min-height:44px} (см. выше),
     а инпут/селект оставались на 32px — в ряду дайджеста поле и кнопка стояли
     на заметно разных высотах. Здесь все контролы ряда — одной высоты. */
  .aw-alerts-set-row select.aw-inp, .aw-alerts-set-row input.aw-inp {
    width: 100%; min-width: 0; height: 44px; line-height: 44px; padding-top: 0; padding-bottom: 0;
  }
}
/* Пороги тревог: подпись+число, а не чекбокс+текст (та же .aw-chk-grid, но
   другая внутренняя раскладка label) — точечный оверрайд через вторую
   специфичность .aw-chk-grid.aw-thresh-grid, чтобы не задеть чекбоксы событий
   выше, которые остаются на baseline .aw-chk-grid.
   Найдено при ревью 2026-07-26: подписи выросли («Reject warn, %» ->
   «Порог отказов купюр (внимание), %»), auto-fill/minmax(15rem,1fr) с
   white-space:nowrap на label не могли сжаться — грид распирало шире
   карточки, а инпуты левой/правой колонки вставали на разный X (было
   измерено: 680px доступно, ~774-790px требовалось двум самым длинным
   подписям). Фикс: ровно 2 равные колонки, внутри label — свой грид
   «текст 1fr | инпут 8rem», подпись переносится, инпут всегда на одном X. */
.aw-chk-grid.aw-thresh-grid { grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--aw-s3, .75rem) var(--aw-s4, 1rem); }
.aw-chk-grid.aw-thresh-grid label { display: grid; grid-template-columns: 1fr 8rem;
  column-gap: var(--aw-s2, .5rem); align-items: start; white-space: normal; }
.aw-chk-grid.aw-thresh-grid input[type="number"] { margin: 0; justify-self: end; align-self: center; }
@media (max-width: 560px) {
  .aw-chk-grid.aw-thresh-grid { grid-template-columns: 1fr; }
  .aw-chk-grid.aw-thresh-grid label { grid-template-columns: 1fr 6rem; }
}

/* Модалка настроек: две карточки Telegram/MAX одной высоты (сейчас
   align-items:start в .aw-grid-2 — совпадение высот у них случайное, а не
   гарантированное) + поля токена/ID чата на всю ширину карточки (уже
   написанное .aw-grid-2 input{width:100%} не срабатывает, потому что
   родительский <label> сам не растянут на всю карточку — .aw-stack даёт ему
   только ширину контента). Правки только для этой модалки: .aw-grid-2 и
   .aw-stack используются на 10+ других страниц с другой геометрией. */
#alerts-settings-modal .aw-grid-2 { align-items: stretch; }
#alerts-settings-modal .aw-stack > label { align-self: stretch; }
/* Двойная рамка: вложенные <article class="aw-card"> внутри уже оформленного
   серого диалога получают полный Pico-вид (белый фон + собственная тень) —
   пять теневых карточек внутри тени диалога читались шумно. Оставляем только
   внешнюю рамку диалога и лёгкий разделитель между блоками. */
#alerts-settings-modal .aw-card { background: transparent; box-shadow: none;
  border-top: 1px solid var(--cw-border); border-radius: 0; }
#alerts-settings-modal .aw-grid-2 .aw-card { border-top: 0; }
/* Убрать тень с .aw-card само по себе не убирает вторую плашку: Pico вешает
   на КАЖДЫЙ article>header собственный фон/паддинг/border-bottom с bleed-ом
   до края карточки (см. pico.min.css) — снятие тени у карточки этого не
   касается, и 5 заголовков внутри модалки всё равно читались отдельными
   плашками. Зануляем сам header — заголовок просто текст, без плашки. */
#alerts-settings-modal .aw-card > header {
  background: transparent; margin: 0 0 var(--aw-s3); padding: 0; border-bottom: 0;
}
/* Карточки настроек — облегчённые разделители формы, а не самостоятельные
   .aw-sheet, но стык между ними тот же смысл «граница крупного блока», что
   на самой странице оформлен через .aw-sheet.aw-mt1 (16px) — было 8px
   (aw-mt2), не совпадало с ритмом страницы. */
.aw-mt-lg { margin-top: var(--aw-s4); }

.aw-alerts-settings > summary { cursor: pointer; font-weight: 600; padding: 2px 0; }
/* тест-стенд: приглушённая группа тревог */
.aw-alerts-test { opacity: .72; }
/* «Отложить» — нативный дропдаун без JS */
.aw-mute-dd { position: relative; display: inline-block; }
.aw-mute-dd > summary { list-style: none; cursor: pointer; }
.aw-mute-dd > summary::-webkit-details-marker { display: none; }
.aw-mute-opts { position: absolute; z-index: 30; right: 0; margin-top: var(--aw-s1); display: flex;
  flex-direction: column; gap: var(--aw-s1); padding: var(--aw-s2); background: var(--cw-card, #fff);
  border: 1px solid var(--cw-border, #e5e7eb); border-radius: var(--aw-r2, 8px);
  box-shadow: var(--aw-shadow, 0 4px 14px rgba(0,0,0,.12)); min-width: 7rem; }
/* сетка чекбоксов событий / порогов в настройках */
.aw-chk-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: var(--aw-s2) var(--aw-s4); }
/* white-space:normal: подписи событий доходят до 44-52 символов ("Пост без
   автоматической защиты (не лечит себя сам)") — с унаследованным nowrap они
   распирали и десктопную, и мобильную (1-колоночную) раскладку сетки, точно
   так же, как уже нашли и починили для соседней .aw-thresh-grid. */
.aw-chk-grid label { display: inline-flex; align-items: start; gap: var(--aw-s2);
  font-size: var(--yeti-fs-xs); white-space: normal; }
.aw-chk-grid input[type="number"] { margin: 0 0 0 auto; }
.aw-inline-flash { font-size: var(--aw-fs-xs, .78rem); }
@media (max-width: 560px) {
  .aw-chk-grid { grid-template-columns: 1fr; }
  .aw-mute-opts { right: auto; left: 0; }
}

/* широкая модалка настроек уведомлений (форма каналов+порогов+дайджеста) — прокрутка при переполнении */
.aw-dialog.aw-dialog-wide { max-width: 760px; max-height: 90vh; overflow: auto; }
/* Только ШАПКА МОДАЛКИ (прямой article диалога) — вложенные карточки внутри
   модалки (alerts_settings и т.п.) sticky-шапку НЕ получают (ревью 2026-07-23). */
.aw-dialog-wide > article > header.aw-head { position: sticky; top: calc(-1 * var(--aw-s5)); z-index: 2;
  background: var(--cw-bg-soft); padding-block: var(--aw-s2); margin-bottom: var(--aw-s2); }

/* ===== §pulse — визуальный редактор импульсных каналов (карточка поста) ===== */
.aw-pulse-row { display:grid; gap: var(--aw-s2);
  grid-template-columns: minmax(8rem,1.2fr) 6.5rem 6.5rem minmax(8rem,1.4fr) auto;
  align-items:end; width:100%; box-sizing:border-box;
  padding: var(--aw-s2); border:1px solid var(--cw-border); border-radius: var(--aw-r2, 8px); }
.aw-pulse-f { display:flex; flex-direction:column; gap:2px; min-width:0;
  font-size: var(--aw-fs-xs, .78rem); color: var(--cw-muted); }
.aw-pulse-f .aw-inp { margin:0; width:100%; box-sizing:border-box; }
.aw-pulse-del { align-self:center; }
.aw-pulse-note { grid-column: 1 / -1; }
@media (max-width: 560px){
  .aw-pulse-row { grid-template-columns: 1fr 1fr auto; }
  .aw-pulse-name { grid-column: 1 / -1; }
}
.aw-pulse-prev { color: var(--aw-accent); white-space: nowrap; }

/* ===== §pinmap — схема пинов платы + инструкция (модалка в карточке поста) =====
   Цвета SVG задаём КЛАССАМИ (тема наследуется через --aw-accent/--cw-*), без inline-style.
   Геометрия/размер шрифта — презентационные атрибуты SVG (не style=). */
.aw-pinmap-figure { overflow-x: auto; margin: var(--aw-s3) 0; }
.aw-pin-svg { display: block; width: 100%; height: auto; min-width: 560px; }
.aw-pin-board { fill: var(--cw-bg-soft); stroke: var(--cw-border); stroke-width: 1.5; }
.aw-pin-conn { fill: none; stroke: var(--cw-border); stroke-width: 1.3; }
.aw-pin-key  { stroke: var(--aw-accent); stroke-width: 2; }
.aw-pin-hl   { fill: var(--aw-accent); stroke: var(--aw-accent); stroke-width: 2; }
.aw-pin-t    { fill: currentColor; }
.aw-pin-t2   { fill: var(--cw-muted); }
.aw-pin-accent-t { fill: var(--aw-accent); }
.aw-pin-hl-t { fill: var(--aw-accent-contrast); }
.aw-pinmap-table { margin-top: var(--aw-s3); }
.aw-pinmap-steps { margin: var(--aw-s2) 0 0; padding-left: 1.2rem; }
.aw-pinmap-steps li { margin-bottom: var(--aw-s2); }

/* --- §18 Embed (iframe-редактор программ/реле поста для YetiWash CRM) ------
   Standalone-страница без навбара, рендерится в iframe внутри CRM. Заполняет
   ширину фрейма с небольшим отступом; без inline-style (правило проекта). */
.aw-embed-body { margin: 0; padding: var(--aw-s3); }
.aw-embed-main { max-width: 760px; }
.aw-embed-title { margin: 0 0 var(--aw-s2); }

/* ================= §debug — дебаг-режим технаря (карточка поста) =============
   Live-хвост лога прошивки (терминал-окно) + GPIO-монитор + тест реле.
   Партиал partials/post_debug.html, поллинг HTMX every 2s. 0 inline-style. */
.aw-debug-term {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .78rem; line-height: 1.35;
  background: #10151c; color: #c8d6e5;
  border: 1px solid var(--cw-border); border-radius: var(--aw-r-md);
  padding: var(--aw-s2) var(--aw-s3);
  max-height: 320px; overflow-y: auto; overflow-x: hidden;
  white-space: pre-wrap; word-break: break-all;
  margin: 0;
}
.aw-gpio-wrap { display: flex; flex-direction: column; gap: var(--aw-s2); }
.aw-gpio-group { display: flex; flex-direction: column; gap: 2px; }
.aw-gpio-row { display: flex; flex-wrap: wrap; gap: var(--aw-s1); align-items: center; }
.aw-gpio-cell { display: inline-flex; border-radius: var(--aw-r-sm); }
.aw-gpio-changed { outline: 2px solid var(--aw-accent); outline-offset: 1px;
                   border-radius: var(--aw-r-sm); }
.aw-mt1 { margin-top: var(--aw-s1); }

/* ================= §18 — фильтр-ряды (Журнал операций /ops, Прошивки /firmware) ====
   Инлайн-ряд фильтров/полей формы без «скачков»: label'ы в ряд, контролы фикс-высоты.
   0 inline-style (правило проекта). */
.aw-flt { display: flex; flex-wrap: wrap; gap: var(--aw-s3); align-items: flex-end; }
.aw-flt > label { margin: 0; display: flex; flex-direction: column; gap: 2px;
  font-size: var(--aw-fs-sm); color: var(--cw-muted); }
.aw-flt select, .aw-flt input[type="text"], .aw-flt input[type="file"] {
  margin: 0; height: 2rem; box-sizing: border-box; min-width: 9rem; max-width: 16rem; }
.aw-flt-check { flex-direction: row !important; align-items: center; gap: .4rem !important;
  color: inherit !important; white-space: nowrap; }
.aw-flt-check input[type="checkbox"] { appearance: auto; -webkit-appearance: checkbox;
  width: 1.1rem; height: 1.1rem; min-width: 1.1rem; margin: 0; flex: 0 0 auto;
  accent-color: var(--aw-accent, #3478d1); }
.aw-flt .cw-btn-small, .aw-flt .aw-btn-ghost { align-self: flex-end; }
@media (max-width: 560px) {
  .aw-flt { flex-direction: column; align-items: stretch; }
  .aw-flt > label, .aw-flt select, .aw-flt input[type="text"], .aw-flt input[type="file"] {
    max-width: none; width: 100%; }
}

/* ============================ §19. МОБИЛЬНЫЙ СЛОЙ (строгая сетка) ==========
   Единые правила «всё влезает» для телефонов/планшетов. Секция НАМЕРЕННО в
   конце файла — при равной специфичности перебивает десктоп-правила выше.
   Причина: строгие ряды .aw-head-meta/.aw-actions (§16) построены на nowrap —
   на ≤768px мета шапок выталкивалась за вьюпорт (замерено: /home rt=496,
   /monitor rt=428, /alerts rt=425, /analytics rt=391 при вьюпорте 375px).
   Здесь nowrap ослабляется: перенос МЕЖДУ элементами ряда, каждый чип/кнопка/
   форма остаётся цельным. Отступы — только шкала --aw-s*. */
@media (max-width: 768px) {
  /* 0. Меню: одна прокручиваемая строка чипов (не рыхлый многострочный блок).
     ВНИМАНИЕ: селектор был по классу .cw-nav-track, а у <nav> это id — правило
     ни разу не срабатывало (найдено 2026-07-27 вместе со скрытым скроллбаром).
     Скролл и видимый скроллбар теперь безусловно в .aw-hd__nav (brand.css,
     грузится позже — здесь скроллбар не дублируем и не скрываем повторно). */
  #cw-nav-track { justify-content: flex-start; }
  .cw-nav-item { flex: 0 0 auto; }
  /* 1. Шапки карточек — строгие ряды: [имя+бейдж] / [адрес] / [мета+действия].
     Мета уходит ОТДЕЛЬНОЙ строкой слева (ровная панель), а не рваным
     right-align хвостом; адрес (.cw-muted) — своей строкой. */
  .aw-head { flex-wrap: wrap; row-gap: var(--aw-s2); }
  .aw-head > .cw-muted { flex: 1 0 100%; white-space: normal; }
  .aw-head-meta { white-space: normal; flex-wrap: wrap; row-gap: var(--aw-s2);
                  flex: 1 0 100%; margin-left: 0; justify-content: flex-start;
                  max-width: 100%; min-width: 0; }
  .aw-head-meta > * { white-space: nowrap; }
  .aw-actions { flex-wrap: wrap; }
  .aw-grp-head, .aw-head-row { flex-wrap: wrap; row-gap: var(--aw-s2); }
  /* 2. Длинные идентификаторы (hash/MAC/URL) не распирают контейнеры. */
  .aw-kv dd, .aw-post-id, .aw-dev-sub, .aw-pass, code { overflow-wrap: anywhere; }
  /* 3. Фикс-ширинные виджеты — не шире вьюпорта. */
  .aw-mk-qr, .aw-sbp-qr-img { max-width: 100%; }
  .aw-clip { max-width: 100%; }
  /* 4. Единый вертикальный ритм страницы: карточки друг от друга на s4.
     .p-tabpane > article — карточки внутри вкладок /programs (не прямые дети main). */
  main.container > article, .p-tabpane > article { margin-bottom: var(--aw-s4); }
}
@media (max-width: 560px) {
  /* 5. Модалки: почти во весь экран, единый внутренний отступ, прокрутка. */
  .aw-dialog, .aw-dialog.aw-dialog-wide, .aw-an-settings {
    width: calc(100vw - var(--aw-s6)); max-width: none;
    max-height: 92dvh; overflow: auto; }
  .aw-dialog { padding: var(--aw-s4); }
  .aw-dialog-wide > article > header.aw-head { top: calc(-1 * var(--aw-s4)); }
  /* 6. Тач-таргеты: icon-кнопки единого квадрата 2.5rem (все разом — ряды ровные).
     button.aw-icon-btn — против Pico button[type=submit]{width:100%} (см. §16). */
  .aw-icon-btn, button.aw-icon-btn { width: 2.5rem; height: 2.5rem; min-height: 2.5rem; }
  .aw-actions { gap: var(--aw-s1); }
  /* 7. Ряды уровней лояльности: числа компактнее, имя не схлопывается в 0. */
  .aw-tier-row { grid-template-columns: minmax(0,1fr) 74px 74px; }
  /* 8. Полосы-сводки: одинаковый ритм отступов на телефоне. */
  .aw-summary, .aw-mon-summary { gap: var(--aw-s2) var(--aw-s3); padding: var(--aw-s2) var(--aw-s3); }
}

/* ============================ §19b. ПОЛИРОВКА МОБИЛЬНОЙ ЧИСТОТЫ ============
   Свод аудита 2026-07-23 (воркфлоу 9 групп + верификация, 50 находок). Многие
   находки — ОДНОТИПНЫЕ, поэтому лечатся УНИВЕРСАЛЬНЫМИ правилами, а не правкой
   десятков шаблонов. Ключевые факты каскада:
   - `.cw-row-actions` В ШАБЛОНАХ НЕ ИСПОЛЬЗУЕТСЯ НИГДЕ (проверено grep) → резерв
     style.css `td:not(.cw-row-actions){padding-right:2.5rem}` под плавающий ✕ на
     карточках cw-tx-table ВСЕГДА пустой → снимаем везде разом.
   - style.css `td:not([data-label])::before{content:none}` НЕ гасит ПУСТОЙ
     data-label="" (атрибут присутствует) → висячее «: ». Гасим тут разом. */

/* -- Универсально для карточного вида таблиц (≤768) -- */
@media (max-width: 768px) {
  /* A. Убираем фантомный правый жёлоб 2.5rem под несуществующую ✕-кнопку на всех
     карточках-строках. Специфичность (0,2,1) = style.css, app.css позже → выигрывает. */
  .cw-tx-table td:not(.cw-row-actions) { padding-right: var(--aw-s3); }
  /* B. Гасим висячее «: » у пустого data-label и у полностью пустой ячейки
     (действие под гейтом права → td рендерится пустым, но метка остаётся). */
  .cw-tx-table td[data-label=""]::before,
  .cw-tx-table td:empty::before { content: none; }
  /* C. Ячейка с рядом действий: метка на СВОЮ строку, кнопки ровным рядом под ней. */
  .cw-tx-table td:has(> .aw-actions)::before { display: block; margin-bottom: var(--aw-s1); }
  /* D. Акцент открытого инцидента (aw-row-err) в карточном виде — на саму строку-tr,
     а не td (иначе щели между блоками ячеек). cw-tx-table — журнал /monitor/post/{hash}
     (журнал на /alerts переведён на aw-dt/aw-dt-bad, эта пара классов там больше не используется). */
  .cw-tx-table tr.aw-row-err { box-shadow: inset 3px 0 0 var(--cw-negative, #d32f2f); }
  /* E. key-value таблицы метрик (/monitor/post) — значения переносятся, не скроллятся вбок. */
  main table.aw-mon-kv td:last-child { white-space: normal; }
  /* F. «Настройки мойки» (/programs/wash) — 2-колоночная таблица «Параметр/Значение»:
     метка-параметр = заголовок карточки, префиксы «Параметр:/Значение:» не нужны. */
  .aw-settings-table td[data-label]::before { content: none; }
  .aw-settings-table td[data-label="Параметр"] { font-weight: 600; padding-top: var(--aw-s2); }
  /* G. Фильтр статистики/аналитики: селекты во всю ширину ровным стеком (не ragged). */
  .aw-stats-filter label { flex: 1 1 100%; }
  .aw-stats-filter select { min-width: 0; max-width: none; width: 100%; }
  /* H. Компактные числовые поля порогов в модалке /alerts не раздуваются на 100%. */
  .aw-chk-grid .aw-inp-num { max-width: 6rem; width: auto; }
  /* I. Таб-навбары (.aw-tabnav: /marketing, /settings, /admin/access) — прокручиваемая
     строка чипов, как #cw-nav-track, вместо рваного flex-wrap в 2-3 строки.
     Скроллбар скрыт (владелец: явные не нравятся нигде) — доступность колесом
     мыши даёт awEnableWheelScroll (base.html), без него был недостижим хвост
     строки («кнопки не листаются», владелец, скриншот /programs). */
  .aw-tabnav { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
               scrollbar-width: none; }
  .aw-tabnav::-webkit-scrollbar { display: none; }
  .aw-tabnav .cw-btn-small { min-width: auto; flex: 0 0 auto; }
  /* J. Табы окна аптайма (/monitor) — тач-цель 40px без роста шрифта. */
  .aw-win-tab { display: inline-flex; align-items: center; min-height: 2.5rem;
                padding: var(--aw-s2) var(--aw-s3); }
  /* (Модалка редактора реле rem-modal переведена на класс .aw-dialog — мобильную
     обработку получает через общий блок §19 «5. Модалки», отдельное правило не нужно.) */
  /* M. Аккаунт /admin/access = две <tr> (данные + строка «Права»). В карточном виде
     каждая tr = отдельная карточка → блок прав «отплывал». Сшиваем в один блок:
     у строки-данных гасим нижний зазор/скругления, у perm-row — верхние. */
  .cw-tx-table tr:has(+ tr.aw-perm-row), .aw-dt tr:has(+ tr.aw-perm-row) { margin-bottom: 0;
    border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
  .cw-tx-table tr.aw-perm-row, .aw-dt tr.aw-perm-row { margin-top: 0; border-top: 0;
    border-top-left-radius: 0; border-top-right-radius: 0; }
}

/* -- Не зависит от вьюпорта -- */
/* Зазор между двумя списками пилюль (проблемы+предупреждения) = внутреннему gap. */
.aw-issues-list + .aw-issues-list { margin-top: var(--aw-s2); }
/* Акцент открытого инцидента на десктопе (журнал /monitor/post/{hash}, cw-tx-table). */
.cw-tx-table tr.aw-row-err > td { background: rgba(211,47,47,.10); }
/* Ссылка-кнопка вровень с button.cw-btn-small на мобиле (Pico даёт 44px только button). */
@media (max-width: 640px) { a.cw-btn-small { min-height: 44px; } }

/* -- Телефон (≤560): тач-высоты и ровные стеки -- */
@media (max-width: 560px) {
  /* Числовые поля-инпуты подтягиваются к тач-высоте кнопок (44px), ровный ряд в формах. */
  .aw-inp-num { height: 44px; }
  /* KPI-числа аналитики/статистики не переносятся посреди разряда ('1 525 600 ₽'). */
  .aw-an-kpi .cw-kpi-value { font-size: 1.15rem; }
  /* Метрики-чипы мойки (/stats) — ровный левый ряд под именем, как .aw-head-meta. */
  .aw-wg-meta { margin-left: 0; flex: 1 0 100%; justify-content: flex-start; }
  /* Строки-чекбоксы (дни/мойки) — комфортная тач-цель. */
  .aw-wash-check { min-height: 2.25rem; }
  /* (Достижения /marketing: перекрытие 90→74px вынесено в ОТДЕЛЬНЫЙ @media ниже базового
     правила — иначе базовое, идущее позже в файле, перебивало бы мобильное.) */
  /* Формы «свет/тест реле/LED/старт дебага» в ряду действий карточки поста — ровный
     вертикальный стек full-width (select+кнопка одной ширины/высоты), как соседние кнопки. */
  .aw-card .aw-btn-row > form.aw-actions { flex-direction: column; align-items: stretch; }
  .aw-card .aw-btn-row > form.aw-actions > * {
    width: 100%; max-width: none; min-height: 44px; box-sizing: border-box; }
  /* Корзина «удалить импульсный канал» — своя строка, прижата вправо (не одиноко слева). */
  .aw-pulse-del { grid-column: 1 / -1; justify-self: end; }
}

/* -- Достижения /marketing: порядок колонок [число|ТЕКСТ|число] — широкая колонка тексту.
   Грид И строкам, И шапке (--ach), чтобы колонки заголовков и данных совпадали.
   Базовый (десктоп) → потом мобильный @media (после базового = перекрывает на телефоне). -- */
.aw-tier-row--ach, .aw-tier-head--ach { grid-template-columns: 90px minmax(0,1fr) 90px; }
.aw-tier-head--ach span:nth-child(1),
.aw-tier-head--ach span:nth-child(2) { text-align: left; }
@media (max-width: 560px) {
  .aw-tier-row--ach, .aw-tier-head--ach { grid-template-columns: 74px minmax(0,1fr) 74px; }
}

/* -- Ряды реле в модалке (перенесено из inline <style> programs.html — класс общий,
   relay_editor включается в post/wash_programs/embed, где inline-стиля не было). -- */
.aw-relay-row { display: flex; gap: var(--aw-s2); align-items: center;
                margin: var(--aw-s1) 0; flex-wrap: wrap; }
.aw-relay-row .aw-inp-num { max-width: 6.5rem; }
.aw-relay-lbl { color: var(--yeti-ink-3, var(--cw-muted)); font-size: var(--yeti-fs-sm, var(--aw-fs-xs)); min-width: 5rem; }
/* прочие мелочи, перенесённые из inline <style> programs.html */
.aw-prog-ico { width: 40px; height: 40px; object-fit: contain; vertical-align: middle;
  background: repeating-conic-gradient(#e8e8ee 0 25%, #f8f8fc 0 50%) 50%/10px 10px;
  border-radius: var(--aw-r-sm); }
.aw-block { display: block; margin-top: var(--aw-s2); }
.aw-relay-ref input { width: 100%; box-sizing: border-box; }

/* -- Вкладки /programs (.p-tabs — перенесено из inline <style> programs.html на токены) -- */
.p-tabs { display: flex; flex-wrap: wrap; gap: var(--aw-s2); margin-bottom: var(--aw-s4);
          border-bottom: 1px solid var(--cw-border); padding-bottom: var(--aw-s2); }
.p-tabs button { min-height: 2rem; padding: var(--aw-s2) var(--aw-s4); font-size: var(--aw-fs-sm);
                 border: 1px solid var(--cw-border); border-radius: var(--aw-r-md);
                 background: transparent; color: inherit; cursor: pointer; }
.p-tabs button.active { background: var(--aw-accent); color: var(--aw-accent-contrast, #fff);
                        border-color: var(--aw-accent); }
.p-tabpane { display: none; }
.p-tabpane.active { display: block; }
@media (max-width: 768px) {
  /* Скроллбар скрыт (владелец: явные не нравятся нигде в проекте) — доступность
     колесом мыши даёт awEnableWheelScroll (base.html): без неё вкладки справа
     от видимой области были недостижимы для мыши/тачпада («кнопки не
     листаются», владелец, скриншот /programs, вкладка «Бонусы» обрезана). */
  .p-tabs { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
            scrollbar-width: none; }
  .p-tabs::-webkit-scrollbar { display: none; }
  .p-tabs button { flex: 0 0 auto; min-height: 2.5rem; }
}

/* -- Форма «Зачислить» в /sbp/pending (перенесено из inline <style> шаблона) -- */
.aw-pending-attr-details { display: inline-block; vertical-align: middle; }
.aw-pending-attr-details[open] > summary { margin-bottom: var(--aw-s2); }
.aw-pending-attr-form { display: flex; flex-wrap: wrap; gap: var(--aw-s2);
                        align-items: center; margin-top: var(--aw-s2); }
/* select тянется на ширину карточки-действий (был жёсткий min-width:220px). */
.aw-pending-attr-form select { width: 100%; min-width: 0; }


/* ============================================================================
 * §vnc — живой экран поста (templates/firmware_editor/vnc.html)
 * ----------------------------------------------------------------------------
 * Перенесено из блока <style> в самом шаблоне: правило проекта запрещает
 * собственные <style> в шаблонах, а держать оформление рядом с разметкой
 * означает, что его не найдут при следующей правке стилей.
 * Классы уже названы по конвенции (aw-vnc-*), переименований не потребовалось.
 * ========================================================================== */
.aw-vnc-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: .75em;
  align-items: center;
  padding: .5em 0;
}
.aw-vnc-toolbar label { display: inline-flex; gap: .35em; align-items: center; }
.aw-spacer-l { margin-left: auto; }
.aw-vnc-frame {
  width: 100%;
  height: 70vh;
  min-height: 480px;
  background: #000;
  border-radius: 4px;
  overflow: hidden;
  position: relative;
}
.aw-vnc-frame canvas { display: block; max-width: 100%; }
.aw-vnc-log {
  max-height: 200px;
  overflow: auto;
  background: var(--card-background-color, #fafafa);
  padding: .5em;
  font-family: monospace;
  font-size: .75rem;
  margin: 0;
}
/* Тест-панель под кадром: инжект денег + симуляция кнопок K1..K6 */
.aw-vnc-testbar {
  display: flex;
  flex-wrap: wrap;
  gap: 1em 1.5em;
  align-items: center;
  padding: .75em 1em;
  margin-top: .75em;
  background: var(--card-sectioning-background-color, rgba(0,0,0,.03));
  border: 1px solid var(--muted-border-color);
  border-radius: 6px;
}
.aw-vnc-testbar-group {
  display: flex; flex-wrap: wrap; gap: .5em; align-items: center;
}
.aw-vnc-testbar-label {
  font-size: 12px; font-weight: 600;
  color: var(--muted-color); text-transform: uppercase; letter-spacing: .04em;
  margin-right: .25em;
}
.aw-vnc-money-form {
  display: inline-flex; gap: .4em; align-items: center;
}
.aw-vnc-money-form input {
  width: 80px; padding: .35em .5em; font-size: 13px;
  border: 1px solid var(--muted-border-color); border-radius: 4px;
  background: var(--card-background-color); color: var(--color);
  text-align: right;
}
.aw-vnc-money-form input:focus { outline: 2px solid var(--aw-accent); outline-offset: -1px; }
.aw-vnc-quick { display: inline-flex; gap: .25em; }
.aw-vnc-quick button { padding: .25em .55em; }
.aw-vnc-keys { display: inline-flex; gap: .3em; flex-wrap: wrap; }
.aw-vnc-keys button {
  min-width: 44px; padding: .3em .55em;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-weight: 600;
}
.aw-vnc-keys button:hover { background: var(--aw-accent); color: white; }
.aw-vnc-flash {
  margin-left: auto;
  padding: .25em .6em;
  font-size: 12px;
  border-radius: 4px;
  min-height: 1.5em;
  transition: opacity .3s;
  opacity: 0;
}
.aw-vnc-flash.show { opacity: 1; }
.aw-vnc-flash.ok { background: rgba(34, 139, 34, .15); color: #1e7e1e; border: 1px solid rgba(34, 139, 34, .35); }
.aw-vnc-flash.err { background: rgba(204, 51, 51, .15); color: #c33; border: 1px solid rgba(204, 51, 51, .35); }
/* На мобиле: подсказка-пояснение прячется (тесно), кадр чуть короче. */
@media (max-width: 560px) {
  .aw-vnc-hint { display: none; }
  .aw-vnc-frame { height: 60vh; min-height: 360px; }
  .aw-vnc-toolbar { gap: .5em; }
  .aw-vnc-testbar { gap: .75em; padding: .5em .75em; }
  .aw-vnc-testbar-group { width: 100%; }
  .aw-vnc-flash { margin-left: 0; width: 100%; }
}
