/* ============================================================================
   brand.css — фирменный слой «След Йети» для админки AdminWash.

   Источник правды: notes/brandbook-sledyeti.md (брендбук бюро Weiss, 2025).
   Подключается ПОСЛЕ app.css, поэтому переопределяет его токены — откат
   делается удалением одной строки <link> в base.html, без правок в app.css.

   Почему отдельным файлом: app.css — 1170 строк накопленных правил, и мешать
   в него бренд значит терять возможность откатиться и сравнить «до/после».

   ЗАГОЛОВОЧНЫЙ ШРИФТ. По брендбуку это TT Runs DemiBold капсом, но лицензии
   на веб пока нет (триальная версия запрещает встраивание в публичные
   страницы). До покупки заголовки набираются Montserrat 800 капсом — он
   тоже брендовый и ближе всего по характеру. Замена, когда лицензия появится:
   положить montserrat-подобный ttruns-600.woff2 рядом и поменять ОДНУ
   переменную --yeti-font-display, макеты трогать не придётся.
   ========================================================================== */

/* ---- Montserrat: наборный шрифт бренда. Файлы уже есть в проекте (сабсет
        кириллица + латиница + знак рубля), те же, что у клиентского приложения. */
@font-face { font-family: 'Montserrat'; font-weight: 400; font-style: normal; font-display: swap;
             src: url('/static/fonts/montserrat-400.woff2') format('woff2'); }
@font-face { font-family: 'Montserrat'; font-weight: 500; font-style: normal; font-display: swap;
             src: url('/static/fonts/montserrat-500.woff2') format('woff2'); }
@font-face { font-family: 'Montserrat'; font-weight: 600; font-style: normal; font-display: swap;
             src: url('/static/fonts/montserrat-600.woff2') format('woff2'); }
@font-face { font-family: 'Montserrat'; font-weight: 700; font-style: normal; font-display: swap;
             src: url('/static/fonts/montserrat-700.woff2') format('woff2'); }
@font-face { font-family: 'Montserrat'; font-weight: 800; font-style: normal; font-display: swap;
             src: url('/static/fonts/montserrat-800.woff2') format('woff2'); }

:root, [data-theme="light"], [data-theme="dark"] {
  /* ---- Палитра брендбука. Ровно четыре цвета, пятого не существует. ---- */
  --yeti-cold:  #88B9C9;   /* холодный, Pantone 550 C — основной цвет бренда   */
  --yeti-dark:  #2A3237;   /* тёмный,   Pantone 432 C — фон, текст, кнопки     */
  --yeti-warm:  #E65D08;   /* тёплый,   Pantone 1595 C — ТОЛЬКО акцент         */
  --yeti-light: #E2EFF9;   /* светлый,  Pantone 642 C — фоны блоков            */

  /* Производные. Не новые цвета, а затемнения/осветления четырёх основных:
     холодный в чистом виде слишком светлый для текста и ссылок (контраст
     на белом около 2:1), поэтому для интерактива берём его тёмную версию. */
  --yeti-cold-deep: #4F7E8E;   /* ссылки и активные состояния, контраст ~4.7:1 */
  --yeti-dark-soft: #3D474E;   /* ховер тёмных кнопок                          */
  --yeti-cold-wash: #F2F8FB;   /* очень светлый фон полос и зебры таблиц       */

  /* ---- Шрифты ---- */
  --yeti-font-text:    'Montserrat', -apple-system, system-ui, 'Segoe UI', Roboto, sans-serif;
  --yeti-font-display: 'Montserrat', -apple-system, system-ui, 'Segoe UI', Roboto, sans-serif;
  --yeti-display-weight: 800;      /* у TT Runs это будет 600 (DemiBold)       */
  --yeti-display-spacing: .01em;   /* у TT Runs трекинг не нужен, поставить 0  */

  /* ---- Перевод существующих токенов админки на бренд ----
     Один этот блок перекрашивает весь интерфейс, потому что весь app.css
     уже написан через --aw-*. Главное действие делаем тёмным, а не оранжевым:
     оранжевый по брендбуку — акцент, и на кнопках он даёт контраст всего
     3.4:1 с белым текстом, чего мало для мелкого шрифта. */
  --aw-accent: var(--yeti-dark);
  --aw-accent-hover: var(--yeti-dark-soft);
  --aw-accent-contrast: #ffffff;
  --aw-accent-soft: color-mix(in srgb, var(--yeti-cold) 26%, transparent);

  /* ---- ШКАЛА КЕГЛЕЙ. Пять ступеней, между соседними заметный шаг ----
     Аудит показал, что в style.css и app.css фактически используется больше
     тридцати разных значений font-size. Когда размеры близки, но не равны,
     глаз читает это как сбой, а не как иерархию, — отсюда ощущение «грубого»
     текста при любом хорошем шрифте. Новые экраны берут размеры только
     отсюда. Имена намеренно с префиксом yeti-, чтобы не столкнуться с
     существующими --aw-fs-* из app.css (у них другие значения). */
  --yeti-fs-xs: .75rem;      /* 12 — счётчики, время, служебные подписи        */
  --yeti-fs-sm: .8125rem;    /* 13 — шапка таблицы, сноски, вторичный текст    */
  --yeti-fs-md: .875rem;     /* 14 — основной текст данных                     */
  --yeti-fs-lg: 1rem;        /* 16 — заголовок группы, подзаголовок блока      */
  --yeti-fs-xl: 1.375rem;    /* 22 — заголовок страницы                        */

  /* ---- ЧЕТЫРЕ УРОВНЯ ТЕКСТА вместо семи прозрачностей ----
     У каждого своя роль, и это единственный способ отличить «важное» от
     «служебного» без цвета: цвет в этом интерфейсе занят под состояния.

     Доли подобраны РАСЧЁТОМ контраста, а не на глаз. Первая редакция была
     набрана на глаз и провалила собственное правило: ink-3 при 46 % давал
     на светлых фонах 2,5-2,7 : 1 при норме 4,5, а им набран почти весь
     служебный текст — крошки, адреса моек, время в ленте, проценты в
     таблицах. Пересчитано на четырёх фактических фонах (белый лист, фон
     страницы, шапка таблицы, полоса группы); доля 70 % — минимальная, при
     которой порог держится на всех четырёх. */
  --yeti-ink-1: var(--yeti-dark);                                     /* 13,0 : 1  главное   */
  --yeti-ink-2: color-mix(in srgb, var(--yeti-dark) 82%, transparent); /*  6,6 : 1  обычное   */
  --yeti-ink-3: color-mix(in srgb, var(--yeti-dark) 70%, transparent); /*  4,7 : 1  служебное */
  /* ink-4 — единственный, кто ниже порога (4,0 : 1 на белом). Он и не для
     текста: им набирается прочерк «нет данных», то есть отсутствие значения.
     Информативный текст этим уровнем набирать нельзя. */
  --yeti-ink-4: color-mix(in srgb, var(--yeti-dark) 62%, transparent); /*  4,0 : 1  прочерки  */

  /* ---- ЛИНИИ. Три толщины смысла, а не три случайных цвета ---- */
  --yeti-line:        color-mix(in srgb, var(--yeti-dark) 8%, transparent);  /* между строк */
  --yeti-line-strong: color-mix(in srgb, var(--yeti-dark) 14%, transparent); /* под шапкой  */
  --yeti-grid:        color-mix(in srgb, var(--yeti-cold) 34%, transparent); /* сетка таблиц*/

  /* ---- СЕМАНТИКА СОСТОЯНИЙ. Один смысл — один цвет ----
     Аудит нашёл в проекте четыре разных «зелёных», семь «жёлто-оранжевых» и
     четыре «красных» для одних и тех же смыслов. Здесь их ровно три, и все
     из палитры брендбука:
       норма      — холодный: живо и внимания не требует;
       внимание   — тёплый контуром: заметно, но не авария;
       требует    — тёплый заливкой: единственный сигнал «иди чини»;
       нет связи  — тёмный: не тревога, а отсутствие. */
  --yeti-state-ok:   var(--yeti-cold);
  --yeti-state-attn: var(--yeti-warm);
  --yeti-state-dead: var(--yeti-dark);
  /* Тёплый текст (счётчики «N офлайн» и т.п.): чистый --yeti-warm на белом
     мелким шрифтом даёт недостаточный контраст, поэтому для ТЕКСТА берём
     затемнённый вариант. Раньше было 3 разных места с литералом #9c4206 —
     свели в один токен. */
  --yeti-attn-text: #9c4206;

  /* ---- Поверхность листа (.aw-sheet, шапка таблицы, рама приложения) ----
     Раньше это было буквальным #fff по всему файлу — в тёмной теме карточки
     оставались белыми пятнами на тёмном фоне, а текст поверх них (набранный
     через --yeti-ink-*, см. ниже) становился тёмным на тёмном и пропадал.
     Заводим переменную один раз, дальше меняется только она. */
  --yeti-surface: #fff;
}

/* ---- ТЁМНАЯ ТЕМА ----------------------------------------------------------
   brand.css целиком проектировался на светлом фоне: --yeti-ink-* всегда были
   производными от --yeti-dark (тёмный текст), а --yeti-surface — литерал
   #fff. В [data-theme="dark"] это даёт тёмный текст на тёмном фоне почти
   везде. --yeti-dark САМ не трогаем — он ещё нужен как фон светлых плашек
   (аватар, активный пункт меню) и в этой роли на тёмном фоне работает.
   Цвета взяты из уже проверенной тёмной темы Pico (pico.min.css
   [data-theme=dark]), чтобб не изобретать новую палитру: --pico-card-
   background-color:#181c25, --pico-color:#c2c7d0, --pico-muted-border-
   color:#202632. */
[data-theme="dark"] {
  --yeti-surface: #181c25;
  --yeti-ink-1: #eef0f2;
  --yeti-ink-2: color-mix(in srgb, #eef0f2 82%, transparent);
  --yeti-ink-3: color-mix(in srgb, #eef0f2 70%, transparent);
  --yeti-ink-4: color-mix(in srgb, #eef0f2 55%, transparent);
  --yeti-line:        color-mix(in srgb, #eef0f2 12%, transparent);
  --yeti-line-strong: color-mix(in srgb, #eef0f2 20%, transparent);
  --yeti-grid:        color-mix(in srgb, var(--yeti-cold) 30%, transparent);
  --yeti-cold-wash: color-mix(in srgb, var(--yeti-cold) 12%, #181c25);
  /* нет связи/офлайн: --yeti-dark на тёмном фоне сливается в невидимую точку,
     нужен нейтральный серый вместо тёмного. */
  --yeti-state-dead: #7b8495;
  /* На тёмном фоне сам --yeti-warm уже достаточно контрастен для текста —
     затемнённый вариант, наоборот, слился бы с фоном. */
  --yeti-attn-text: var(--yeti-warm);
}

/* ---- Базовая типографика админки ---- */
body {
  font-family: var(--yeti-font-text);
  font-feature-settings: 'tnum' 1;   /* цифры одной ширины: суммы и температуры
                                        выравниваются в колонку, а не пляшут   */
}

h1, h2, h3, .yeti-display {
  font-family: var(--yeti-font-display);
  font-weight: var(--yeti-display-weight);
  letter-spacing: var(--yeti-display-spacing);
}

/* Заголовки первого уровня — капсом, как требует брендбук.
   На h2/h3 капс не распространяем: в админке они несут длинные названия
   моек и постов, и капс их удлиняет и мешает читать. */
h1, .yeti-display--caps { text-transform: uppercase; }

/* Ссылки: чистый холодный на белом не читается, берём его тёмную версию. */
a:not([role="button"]):not(.cw-btn-small) { color: var(--yeti-cold-deep); }
a:not([role="button"]):not(.cw-btn-small):hover { color: var(--yeti-dark); }

/* Горный мотив живёт ровно в одном месте — сцене экрана входа (ниже). Общей
   утилиты `.yeti-ridge` больше нет: в админке приоритет у плотности данных,
   и переносить рекламный приём на рабочие экраны брендбук сам не советует. */

/* ---- КАНОН НАБОРА: старые кегли app.css переведены на шкалу --yeti-fs-* ----
   Найдено при ревью /alerts 2026-07-26: заголовок страницы (.aw-page-head h2)
   сидел на старом --aw-fs-h2=20px (на мобиле — вообще отдельное 18.4px), а
   канонический --yeti-fs-xl=22px, заведённый именно под роль «заголовок
   страницы», не использовался НИГДЕ. Тот же разнобой у мелкого текста:
   .aw-xs/.aw-chk-grid/.aw-inline-flash сидели на --aw-fs-xs=.78rem вместо
   канонического --yeti-fs-xs=.75rem — тот самый случай «близко, но не
   равно», о котором предупреждает шкала кеглей выше. */
.aw-page-head h2 { font-size: var(--yeti-fs-xl); }
.aw-xs, .aw-chk-grid label, .aw-inline-flash { font-size: var(--yeti-fs-xs); }

/* ============================================================================
   ЭКРАН ВХОДА
   Собран по правилам композиции из брендбука (стр. 32): заголовок капсом,
   текст с левой выключкой, рамка со скруглением 20-30 px, логотип сверху,
   одна гора (лимит брендбука — не более трёх).
   ========================================================================== */

.yeti-login {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--aw-s4, 1rem);
  background: var(--yeti-dark);
}

.yeti-login__card {
  width: 100%;
  max-width: 380px;
  background: #fff;
  border-radius: 24px;          /* брендбук: рамка макета 20-30 px */
  overflow: hidden;             /* чтобы горная кромка обрезалась по радиусу */
  box-shadow: 0 18px 48px rgb(0 0 0 / .28);
}

/* Шапка карточки: холодный блок с логотипом и горной сценой снизу. */
.yeti-login__head {
  background: var(--yeti-cold);
  padding: var(--aw-s5, 1.5rem) var(--aw-s5, 1.5rem) 0;
  text-align: left;             /* левая выключка — правило брендбука */
  /* Pico вешает на header внутри article разделительную черту. Здесь границу
     рисуют сами горы, а линия поверх них читается как шов. */
  border-bottom: 0;
}

.yeti-login__brand {
  font-family: var(--yeti-font-display);
  font-weight: var(--yeti-display-weight);
  font-size: 1.6rem;
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: .02em;
  color: var(--yeti-dark);
  margin: 0;
}

/* Акцентный хвост логотипа из макроса brand(): на холодной шапке даём ему
   выворотку, иначе он сливается с основным начертанием (акцент теперь тёмный). */
.yeti-login__brand .cw-brand-accent { color: #fff; }

.yeti-login__descriptor {
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: lowercase;
  color: color-mix(in srgb, var(--yeti-dark) 72%, transparent);
  margin: .25rem 0 var(--aw-s4, 1rem);
}

/* ---- Сцена восхода: две горы, из-за дальней встаёт солнце ----
   Бренд-мотив брендбука в единственном на весь интерфейс экземпляре: две горы
   (лимит — три), обе холодные, а тёплый цвет появляется ровно один раз — как
   диск солнца. Везде остальное действие в админке намеренно тёмное, потому
   что оранжевый на мелком тексте даёт контраст 3.4:1; здесь он крупным пятном
   и ничего не подписывает, так что работает как акцент, а не как текст.

   Слои снизу вверх: солнце -> дальняя гора -> ближняя гора. Порядок в разметке
   и есть то, что заставляет солнце вставать ИЗ-ЗА хребта. */
.yeti-login__scene {
  position: relative;
  height: 126px;
  margin: 10px calc(-1 * var(--aw-s5, 1.5rem)) 0;
  overflow: hidden;             /* прячет солнце в нижнем положении */
}

.yeti-login__mount {
  position: absolute;
  /* Не «bottom: 0», а на 2 px ниже: высота шапки дробная (её задаёт line-height
     логотипа), и на последний ряд пикселей белая гора попадает лишь частично —
     остаток проступает цветом дальней горы, и по стыку с телом карточки идёт
     серая нить. Лишние 2 px срезает overflow сцены, край получается чистым. */
  inset: auto 0 -2px 0;
}
.yeti-login__mount--far {
  height: 96px;
  background: color-mix(in srgb, var(--yeti-cold) 55%, #fff);
  clip-path: polygon(0 60%, 13% 30%, 25% 52%, 38% 22%, 52% 46%, 66% 24%,
                     79% 50%, 90% 32%, 100% 54%, 100% 100%, 0 100%);
}
.yeti-login__mount--near {
  height: 52px;
  background: #fff;             /* сливается с телом карточки — это «земля» */
  clip-path: polygon(0 74%, 12% 56%, 24% 70%, 37% 50%, 50% 68%, 63% 48%,
                     76% 66%, 88% 54%, 100% 72%, 100% 100%, 0 100%);
}

.yeti-login__sun {
  position: absolute;
  left: 50%;
  bottom: 18px;
  width: 68px;
  height: 68px;
  margin-left: -34px;
  border-radius: 50%;
  background: var(--yeti-warm);
  box-shadow: 0 0 40px 14px color-mix(in srgb, var(--yeti-warm) 45%, transparent);
  transform: translateY(92px);  /* в покое диск целиком ниже линии гор */
  transition: transform .85s cubic-bezier(.22, .7, .3, 1);
}

/* Триггер — работа с полем фразы, а не случайный проезд мышью по карточке.
   :has() читает состояние поля из тела карточки, поэтому JS не нужен: на
   странице входа, которая отдаётся до авторизации, чем меньше исполняемого
   кода, тем лучше. Фокус в списке обязателен — на телефоне ховера нет. */
.yeti-login__card:has(.yeti-login__field:hover) .yeti-login__sun,
.yeti-login__card:has(.yeti-login__input:focus) .yeti-login__sun {
  transform: translateY(0);
}

/* При запрете анимаций солнце просто стоит над горами: лучше статичная
   картинка, чем скачок диска на 92 px без перехода. */
@media (prefers-reduced-motion: reduce) {
  .yeti-login__sun { transform: translateY(0); transition: none; }
}

.yeti-login__body { padding: var(--aw-s5, 1.5rem); }

/* Обёртка поля — зона, которая поднимает солнце. Своей геометрии не несёт. */
.yeti-login__field { display: block; }

.yeti-login__title {
  font-size: .95rem;
  font-weight: 700;
  color: var(--yeti-dark);
  margin: 0 0 var(--aw-s4, 1rem);
}

.yeti-login__label {
  display: block;
  font-size: .8rem;
  font-weight: 600;
  color: color-mix(in srgb, var(--yeti-dark) 78%, transparent);
  margin-bottom: .35rem;
}

.yeti-login__input {
  width: 100%;
  height: 2.75rem;
  box-sizing: border-box;
  padding: 0 .85rem;
  font-family: var(--yeti-font-text);
  font-size: 1rem;
  color: var(--yeti-dark);
  background: var(--yeti-cold-wash);
  border: 1px solid color-mix(in srgb, var(--yeti-cold) 55%, transparent);
  border-radius: var(--aw-r-md, 8px);
  margin-bottom: var(--aw-s4, 1rem);
}
.yeti-login__input:focus {
  outline: 2px solid var(--yeti-cold-deep);
  outline-offset: 1px;
  border-color: transparent;
  background: #fff;
}

/* Кнопка задаёт ширину явно: Pico по умолчанию растягивает button на 100%,
   и на этом проект уже обжигался — полагаться на дефолт нельзя. */
.yeti-login__submit {
  width: 100%;
  height: 2.75rem;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--yeti-font-text);
  font-size: .95rem;
  font-weight: 700;
  color: #fff;
  background: var(--yeti-dark);
  border: 0;
  border-radius: var(--aw-r-md, 8px);
  cursor: pointer;
  margin: 0;
}
.yeti-login__submit:hover  { background: var(--yeti-dark-soft); }
.yeti-login__submit:focus-visible { outline: 2px solid var(--yeti-cold-deep); outline-offset: 2px; }


.yeti-login__error {
  font-size: .85rem;
  font-weight: 600;
  color: var(--yeti-warm);
  background: color-mix(in srgb, var(--yeti-warm) 10%, transparent);
  border-radius: var(--aw-r-sm, 4px);
  padding: .5rem .65rem;
  margin: 0 0 var(--aw-s3, .75rem);
}

@media (max-width: 560px) {
  .yeti-login { padding: 0; place-items: stretch; }
  .yeti-login__card { max-width: none; border-radius: 0; min-height: 100dvh; box-shadow: none; }
}

/* ============================================================================
   ЛОГОТИП
   ----------------------------------------------------------------------------
   Небрендовый #3478d1 задан в style.css литералом мимо токена, поэтому перевод
   --aw-accent на тёмный его не достал. Правим здесь, в последнем слое:
   style.css общий с YetiWash CRM, и правка в нём разъедет две системы.
   ========================================================================== */
   Правила для .cw-nav-item, .cw-user-avatar и .cw-chip отсюда убраны: шапка
   переписана на собственные классы (.aw-hd__*), и перекрашивать чужие больше
   незачем. Осталось только это — акцентный хвост логотипа из макроса brand(),
   он используется и в шапке, и на экране входа. */
.cw-brand-accent { color: var(--yeti-cold-deep); }

/* ============================================================================
   РАМА ПРИЛОЖЕНИЯ: ШАПКА, КРОШКИ, ПОДВАЛ
   ----------------------------------------------------------------------------
   Шапка в два ряда: сверху логотип и действия пользователя, снизу меню.
   Раньше всё шло одной flex-строкой с переносом и на любой реальной ширине
   разваливалось на три ряда, съедая треть первого экрана.

   Логотип взят с экрана входа — тот же набор и тот же дескриптор, поэтому
   вход и рабочие экраны читаются как один продукт. Знака нет: на входе его
   тоже нет, а в размере строки меню он превращался в пятно.
   ========================================================================== */
/* Ширина рамы и контента должна совпадать, иначе логотип выглядит съехавшим
   к центру: Pico-контейнер шире нашей шапки, и левые края не сходятся.
   Приводим main к той же мере. */
main.container { max-width: 1120px; }

.aw-hd { background: var(--yeti-surface); }
.aw-hd__in { max-width: 1120px; margin: 0 auto; padding: 0 var(--aw-s5, 1.5rem); }
.aw-hd__row { display: flex; align-items: center; justify-content: space-between;
              gap: var(--aw-s4, 1rem); height: 52px; }

.aw-hd__brand { display: inline-flex; flex-direction: column; gap: 2px;
                text-decoration: none; flex: 0 0 auto; }
.aw-hd__brand:hover { text-decoration: none; }
/* Логотип — единственное исключение из шкалы кеглей: он бренд-элемент,
   а не текст интерфейса, и его размер больше нигде не повторяется. */
.aw-hd__name { font-family: var(--yeti-font-display); font-weight: 800; font-size: 1.15rem;
               line-height: 1; letter-spacing: .02em; text-transform: uppercase;
               color: var(--yeti-ink-1); }
.aw-hd__name .cw-brand-accent { color: var(--yeti-cold-deep); }
.aw-hd__sub { font-size: var(--yeti-fs-xs); font-weight: 500; letter-spacing: .04em;
              text-transform: lowercase; color: var(--yeti-ink-3); }

/* Меню не переносится никогда: при нехватке ширины прокручивается вбок.
   Перенос давал третий ряд и прыгающую высоту шапки. */
.aw-hd__strip { background: color-mix(in srgb, var(--yeti-cold) 26%, var(--yeti-surface)); }
/* Скроллбар скрыт (владелец: явные скроллбары не нравятся нигде в проекте) —
   доступность колесом мыши даёт awEnableWheelScroll (base.html), не CSS. */
.aw-hd__nav { display: flex; gap: 2px; flex-wrap: nowrap; overflow-x: auto;
              height: 40px; align-items: center; scrollbar-width: none; }
.aw-hd__nav::-webkit-scrollbar { display: none; }
.aw-hd__nav a { display: inline-flex; align-items: center; font-size: var(--yeti-fs-sm);
                font-weight: 500; line-height: 1; padding: 7px 10px;
                border-radius: var(--aw-r-md, 8px); text-decoration: none;
                white-space: nowrap; flex: 0 0 auto; color: var(--yeti-ink-2); }
.aw-hd__nav a:hover { background: var(--yeti-surface); color: var(--yeti-ink-1); text-decoration: none; }
.aw-hd__nav a.is-active { background: var(--yeti-dark); color: #fff; font-weight: 600; }
/* --yeti-dark на тёмной поверхности хедера почти не отличим от фона — активный
   пункт меню и аватар "пропадают" в тёмной теме. Берём холодный-глубокий:
   он и на белом, и на тёмном фоне остаётся собой. */
[data-theme="dark"] .aw-hd__nav a.is-active { background: var(--yeti-cold-deep); }
[data-theme="dark"] .aw-hd__ava { background: var(--yeti-cold-deep); }

/* Индикатор тревог — точка без числа. Число ушло в подсказку: в меню важен
   один бит «есть непрочитанное», а сколько именно — вопрос уже на странице.
   Сдвиг на полпикселя ставит её по центру ВЫСОТЫ СЛОВА, а не кнопки: у
   Montserrat 13/500 подъём прописной 9 px и нижний вынос 2, значит центр
   глифов на 3,5 px выше базовой линии, а центр кнопки — на 3. */
.aw-hd__dot { width: 6px; height: 6px; border-radius: 50%; flex: 0 0 auto;
              margin-left: var(--aw-s2, .5rem); align-self: center;
              background: var(--yeti-state-attn); transform: translateY(-.5px); }

/* Правая группа: тема и выход иконками, у пользователя аватар и логин.
   Роль («админ») в подсказке — она не меняется от сессии к сессии и места
   в постоянно видимой строке не стоит. */
.aw-hd__tools { display: inline-flex; align-items: center; gap: var(--aw-s2, .5rem);
                flex: 0 0 auto; }
.aw-hd__user { display: inline-flex; align-items: center; gap: 7px; height: 32px;
               padding: 0 10px 0 3px; border-radius: var(--aw-r-pill, 999px);
               text-decoration: none;
               background: color-mix(in srgb, var(--yeti-cold) 18%, transparent); }
.aw-hd__user:hover { background: color-mix(in srgb, var(--yeti-cold) 30%, transparent);
                     text-decoration: none; }
.aw-hd__ava { width: 28px; height: 28px; border-radius: 50%; flex: 0 0 auto;
              background: var(--yeti-dark); color: #fff; display: inline-flex;
              align-items: center; justify-content: center;
              font-size: var(--yeti-fs-xs); font-weight: 700; }
.aw-hd__login { font-size: var(--yeti-fs-xs); font-weight: 500; color: var(--yeti-ink-2);
                white-space: nowrap; }

/* Круглая кнопка рамы. Селектор намеренно с типом (`button.`), а не просто
   классом: Pico объявляет `button[type=submit]{width:100%}` со специфичностью
   (0,1,1), и голый класс (0,1,0) ей проигрывает — кнопка выхода схлопывалась
   до ширины иконки. Проверено замером: было 16 px вместо 32. */
button.aw-hd__btn,
.aw-hd__btn { width: 32px; height: 32px; flex: 0 0 auto; display: inline-flex;
              align-items: center; justify-content: center; padding: 0; margin: 0;
              color: var(--yeti-ink-2); background: transparent; border: 0;
              border-radius: var(--aw-r-pill, 999px); cursor: pointer;
              box-sizing: border-box; }
.aw-hd__btn:hover { background: color-mix(in srgb, var(--yeti-cold) 24%, transparent);
                    color: var(--yeti-dark); }
.aw-hd__btn .aw-ico { width: 16px; height: 16px; }
/* Выход теплеет на наведении: это единственное действие в шапке, которое
   обрывает работу, и промахиваться по нему не должно быть безболезненно. */
.aw-hd__btn--exit:hover { background: color-mix(in srgb, var(--yeti-warm) 14%, transparent);
                          color: var(--yeti-attn-text); }
.aw-hd__tools form { display: inline-flex; margin: 0; }

.aw-hd__btn:focus-visible, .aw-hd__user:focus-visible, .aw-hd__brand:focus-visible,
.aw-hd__nav a:focus-visible, .aw-crumbs a:focus-visible {
  outline: 2px solid var(--yeti-cold-deep); outline-offset: 2px;
  border-radius: var(--aw-r-md, 8px);
}

/* ---- Хлебные крошки ------------------------------------------------------
   Нужны там, где есть вложенность: мойка -> пост. Без них с карточки поста
   непонятно, к какой мойке он относится и куда возвращаться. */
.aw-crumbs { max-width: 1120px; margin: 0 auto; width: 100%;
             padding: var(--aw-s4, 1rem) var(--aw-s5, 1.5rem) 0;
             font-size: var(--yeti-fs-sm); color: var(--yeti-ink-3); }
.aw-crumbs a { color: var(--yeti-ink-3); text-decoration: none; }
.aw-crumbs a:hover { color: var(--yeti-cold-deep); }
.aw-crumbs .aw-crumbs__sep { margin: 0 7px; color: var(--yeti-ink-4); }
.aw-crumbs .aw-crumbs__cur { color: var(--yeti-ink-2); }

/* ---- Подвал: две горы ----------------------------------------------------
   Единственное место, где остался горный мотив. В шапке он не живёт: там
   полоса высотой в два десятка пикселей, и рваный силуэт читается орнаментом,
   а не образом. */
.aw-foot { position: relative; height: 140px; margin-top: var(--aw-s6, 2rem);
           flex: 0 0 auto; overflow: hidden; }
.aw-foot__m { position: absolute; inset: auto 0 -2px 0; }
.aw-foot__m--far { height: 110px;
  background: color-mix(in srgb, var(--yeti-cold) 34%, var(--yeti-cold-wash));
  clip-path: polygon(0 62%, 12% 30%, 24% 54%, 37% 22%, 50% 48%, 63% 24%, 76% 52%,
                     88% 30%, 100% 56%, 100% 100%, 0 100%); }
.aw-foot__m--near { height: 60px;
  background: color-mix(in srgb, var(--yeti-cold) 62%, var(--yeti-cold-wash));
  clip-path: polygon(0 72%, 11% 50%, 23% 68%, 36% 44%, 49% 66%, 62% 42%, 75% 64%,
                     87% 48%, 100% 70%, 100% 100%, 0 100%); }
/* В светлой теме горы — почти белый силуэт, едва темнее фона: узнаётся как
   текстура, не как яркая картинка. В тёмной те же 34%/62% холодного дают
   светлый силуэт на угольном фоне — то, что было тихим орнаментом, становится
   самым ярким пятном экрана. Снижаем долю холодного, чтобы сохранить ту же
   тихую роль. */
[data-theme="dark"] .aw-foot__m--far { background: color-mix(in srgb, var(--yeti-cold) 12%, var(--yeti-cold-wash)); }
[data-theme="dark"] .aw-foot__m--near { background: color-mix(in srgb, var(--yeti-cold) 26%, var(--yeti-cold-wash)); }

@media (max-width: 720px) {
  .aw-hd__in, .aw-crumbs { padding-left: var(--aw-s4, 1rem); padding-right: var(--aw-s4, 1rem); }
  /* Круглые кнопки на телефоне — 44x44 (тач-цель, правило проекта). Ширину
     нужно задавать явно: глобальное `button{min-height:44px}` тянуло только
     высоту, и кнопка превращалась в овал 32x44. */
  button.aw-hd__btn, .aw-hd__btn { width: 44px; height: 44px; }
  .aw-hd__tools { gap: var(--aw-s1, .25rem); }
  /* На телефоне логин прячем: аватар опознаёт пользователя, а место дорого. */
  .aw-hd__user { padding: 0; background: transparent; }
  .aw-hd__login { display: none; }
  .aw-foot { height: 90px; }
}

/* ============================================================================
   ДИЗАЙН-СИСТЕМА: ЛИСТ, ТАБЛИЦА ДАННЫХ, СОСТОЯНИЯ
   ----------------------------------------------------------------------------
   Компоненты для страниц, приведённых к единому виду. Правила и обоснования —
   notes/design-system.md. Существующие экраны продолжают жить на старых
   классах: слой ничего не переопределяет глобально, только добавляет новые
   имена. Страница переезжает целиком и осознанно, а не «наполовину».
   ========================================================================== */

/* ---- Лист: белая плоскость с данными на светлом фоне страницы ------------ */
.aw-sheet {
  background: var(--yeti-surface);
  border-radius: var(--aw-s4, 1rem);
  padding: var(--aw-s4, 1rem);
  box-shadow: 0 1px 2px rgb(42 50 55 / .05), 0 10px 30px rgb(42 50 55 / .06);
}
.aw-sheet + .aw-sheet { margin-top: var(--aw-s4, 1rem); }
/* Модификатор .aw-mt1 (app.css, margin-top: 4px) на листе даёт РАЗНЫЙ отступ в
   зависимости от соседа: 8px после .aw-fold > summary (правило ниже, 0,1,1),
   16px после другого .aw-sheet (правило выше, 0,2,0 побеждает по specificity),
   4px после голого div/тега — на /alerts один и тот же стык «конец блока тревог
   -> Недавние события» скакал между 16 и 4px в зависимости от того, есть ли
   заглушённые. Явный .aw-sheet.aw-mt1 той же specificity (0,2,0), но позже в
   файле — снимает случайность, отступ всегда 16px. */
.aw-sheet.aw-mt1 { margin-top: var(--aw-s4, 1rem); }

/* ---- Таблица данных с сеткой --------------------------------------------
   Сетка выбрана не для украшения: когда у колонки есть границы, взгляд идёт
   вниз по столбцу и не соскальзывает на соседний — это главный сценарий на
   экранах со списком постов. Плата — много линий, поэтому линии самые
   светлые, какие ещё различимы. */
.aw-dt { width: 100%; border-collapse: collapse;
         border: 1px solid var(--yeti-grid); border-radius: var(--aw-s2, .5rem);
         overflow: hidden; }

.aw-dt th {
  font-size: var(--yeti-fs-sm);
  /* 500, а не 600: по шкале весов это «подпись колонки», а 600 отведён под
     акценты и цифры. С 600 шапка соревновалась с данными за внимание. */
  font-weight: 500;
  line-height: 1.3;
  text-align: left;
  color: var(--yeti-ink-2);
  background: color-mix(in srgb, var(--yeti-cold) 16%, var(--yeti-surface));
  padding: var(--aw-s3, .75rem);       /* 12: подпись не липнет к первой строке */
  border-bottom: 1px solid var(--yeti-grid);
  border-right: 1px solid var(--yeti-grid);
  white-space: nowrap;
}
.aw-dt th:last-child { border-right: 0; }

.aw-dt td {
  font-size: var(--yeti-fs-md);
  line-height: 1.45;
  padding: var(--aw-s2, .5rem) var(--aw-s3, .75rem);
  vertical-align: baseline;
  border-right: 1px solid var(--yeti-grid);
  border-bottom: 1px solid var(--yeti-grid);
}
.aw-dt td:last-child { border-right: 0; }
.aw-dt tbody tr:hover td { background: color-mix(in srgb, var(--yeti-cold) 8%, transparent); }

.aw-dt .aw-dt-num { text-align: right; font-variant-numeric: tabular-nums; }
.aw-dt .aw-dt-mid { text-align: center; }

/* ---- Длинный текст в ячейке ----------------------------------------------
   Описание проблемы бывает в полтора десятка слов и переносится на второй
   ряд: строка становится вдвое выше соседних, и ровный ритм таблицы — то,
   ради чего она затевалась, — рассыпается. Обрезаем многоточием; полный
   текст остаётся в подсказке при наведении, а разбор проблемы и без того
   открывается по счётчику рядом со статусом.
   `max-width: 0` — приём для таблиц: без него ячейка растёт по содержимому,
   и обрезка не срабатывает вовсе. Ширину задаёт `width` в процентах. */
.aw-dt td.aw-dt-clip {
  max-width: 0;
  width: 34%;
  cursor: pointer;
}
/* На /alerts тот же приём даёт слишком широкую колонку: причина тревоги обычно
   короткое словосочетание («Просадка питания»), не абзац, как на /monitor —
   34% читались как пустая колонка между «Тревога» и «Где». Сужаем через ID
   контейнера поллинга, а не переопределяя общий класс: на /monitor описание
   бывает предложением целиком и там 34% уместны.
   ТОЛЬКО десктоп (>720px): ID-селектор специфичнее любого класса и на мобиле
   перебивал бы сброс `width: auto` из мобильной раскладки ниже (та держится на
   голых классах) — колонка встала бы в 22% уже внутри грида «подпись—значение»
   и обрезала само значение до пустоты. Баг найден и исправлен в этой же сессии. */
@media (min-width: 721px) {
  #alerts-body .aw-dt-clip { width: 22%; }
}
/* Обрезаем внутренний span, а не ячейку: на телефоне ячейка становится сеткой
   «подпись — значение», и многоточие должно жить на значении. На десктопе
   span тянется на всю ячейку, поведение то же. */
.aw-dt td.aw-dt-clip .aw-clip-in {
  display: block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Раскрытие по нажатию — без единой строки JS. Ячейке в разметке дан
   tabindex, поэтому тап и клавиша Tab дают ей фокус, а по фокусу снимаем
   обрезку. ВНИМАНИЕ: на страницах с 10с-поллингом (hx-swap="innerHTML")
   раскрытие переживает только до ближайшей перерисовки — innerHTML пересоздаёт
   узел и вместе с ним фокус. Это осознанный компромисс (полный текст всегда
   доступен через title), а не гарантия сохранности состояния. */
.aw-dt td.aw-dt-clip:focus,
.aw-dt td.aw-dt-clip:focus-within {
  max-width: none;
  outline: 2px solid var(--yeti-cold-deep);
  outline-offset: -2px;
  border-radius: var(--aw-r-sm, 4px);
}
.aw-dt td.aw-dt-clip:focus .aw-clip-in,
.aw-dt td.aw-dt-clip:focus-within .aw-clip-in {
  white-space: normal;
  overflow: visible;
}

/* Первая колонка держит уступ: в него уходит маркер проблемной строки. */
.aw-dt tbody td:first-child { position: relative; white-space: nowrap;
                              padding-left: var(--aw-s5, 1.5rem); }

/* ---- Группа строк (мойка, категория) -------------------------------------
   Единственная толстая линия во всей таблице — граница сверху у группы.
   Без неё конец одной группы отделяется от начала следующей той же волосяной
   линией, что и обычные строки, и разделы сливаются. */
.aw-dt .aw-dt-grp td {
  background: color-mix(in srgb, var(--yeti-cold) 22%, var(--yeti-surface));
  padding: var(--aw-s3, .75rem);
  border-top: 2px solid var(--yeti-grid);
  border-bottom: 1px solid var(--yeti-grid);
  border-right: 0;
  position: sticky; top: 0; z-index: 2;   /* видно, чья строка, при прокрутке */
}
.aw-dt tbody .aw-dt-grp:first-child td { border-top: 0; }
.aw-dt .aw-dt-grp:hover td { background: color-mix(in srgb, var(--yeti-cold) 22%, var(--yeti-surface)); }
/* Воздух внутри группы: первая и последняя строка отходят от полос. */
.aw-dt .aw-dt-grp + tr td { padding-top: var(--aw-s3, .75rem); }
.aw-dt .aw-dt-last td { padding-bottom: var(--aw-s3, .75rem); }

.aw-dt-grp__in { display: flex; align-items: center; gap: var(--aw-s3, .75rem);
                 flex-wrap: wrap; width: 100%; }
/* white-space:normal: без явного сброса имя мойки наследует nowrap от
   .aw-dt tbody td:first-child (нужен там для десктопной уступ-колонки под
   маркер), а мобильный сброс на normal намеренно исключает строку-группу
   через :not(.aw-dt-grp) — длинное название/адрес на узком экране вылезло бы
   за карточку группы, а не перенеслось. */
.aw-dt-grp__name { font-size: var(--yeti-fs-md); font-weight: 700; line-height: 1.25;
                    white-space: normal; }
.aw-dt-grp__meta { font-size: var(--yeti-fs-xs); font-weight: 400; color: var(--yeti-ink-3);
                   white-space: nowrap; }
/* Счётчики проблем в шапке группы — тем же тёплым, что маркер строки: одно
   сообщение должно опознаваться одним цветом. */
.aw-attn-txt { color: var(--yeti-attn-text); font-weight: 600; }

/* Кнопки перестановки моек уезжают к правому краю и уменьшаются: это редкое
   служебное действие, ему незачем стоять вплотную к названию и держать
   высоту строки заголовка. */
.aw-dt-grp .aw-actions { margin-left: auto; gap: 2px; }
.aw-dt-grp .aw-actions .aw-icon-btn,
.aw-dt-grp .aw-actions button.aw-icon-btn { width: 24px; height: 24px; }
.aw-dt-grp .aw-actions .aw-ico { width: 14px; height: 14px; }

/* ---- Маркер строки, требующей внимания -----------------------------------
   Статус стоит во второй колонке, а взгляд идёт по левому краю — слово
   «проблема» там просто не встречается первым. Полоска стоит там, куда
   взгляд попадает раньше всего. */
/* Маркер рисуем через ::after, а не ::before. На телефоне ::before первой
   ячейки занят подписью колонки (content: attr(data-label)), и полоска с
   текстом наложились друг на друга — в карточке было видно два «Пост 2». */
.aw-dt .aw-dt-bad td:first-child::after {
  content: ''; position: absolute; left: var(--aw-s2, .5rem); top: 0; bottom: 0;
  width: 3px; background: var(--yeti-state-attn);
}
.aw-dt .aw-dt-dead td:first-child::after { background: var(--yeti-state-dead); }

/* ---- Состояние: точка плюс слово -----------------------------------------
   Заливные пилюли на каждой строке давали два десятка цветных плашек, и глаз
   цеплялся за здоровую строку так же, как за сломанную, — сигнал переставал
   работать. Здоровое уходит в фон, тревожное набирается в полную силу.
   Два уровня тревоги различаются формой (заливка против контура), а не
   оттенком: на точке в 7 px оттенок неразличим. */
.aw-state { display: inline-flex; align-items: baseline; gap: var(--aw-s2, .5rem);
            white-space: nowrap; }
/* Кружки состояния и признака прошивки — одного размера: рядом в строке
   разница в два пикселя читалась как разные по важности значки. */
.aw-state__dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto;
                 transform: translateY(-1px); }

.aw-state--ok   { color: var(--yeti-ink-3); }
.aw-state--ok   .aw-state__dot { background: var(--yeti-state-ok); }
.aw-state--warn { color: var(--yeti-ink-1); }
.aw-state--warn .aw-state__dot { background: transparent;
                                 box-shadow: inset 0 0 0 2px var(--yeti-state-attn); }
.aw-state--err  { color: var(--yeti-state-attn); font-weight: 600; }
.aw-state--err  .aw-state__dot { background: var(--yeti-state-attn); }
.aw-state--dead { color: var(--yeti-ink-1); font-weight: 600; }
.aw-state--dead .aw-state__dot { background: var(--yeti-state-dead); }

/* ---- Признак «совпадает с эталоном» --------------------------------------
   Для колонок, где значение почти всегда одно и то же (версия прошивки).
   Повторённое двадцать раз, оно не сообщает ничего — важен один бит. Само
   значение живёт в title, поэтому информация не теряется. */
.aw-flag { display: inline-block; width: 8px; height: 8px; border-radius: 50%;
           background: var(--yeti-state-ok); cursor: help; }
.aw-flag--off { background: transparent;
                box-shadow: inset 0 0 0 1.5px var(--yeti-state-dead); }

/* ---- Числовые значения в таблице ----------------------------------------- */
.aw-val { font-variant-numeric: tabular-nums; color: var(--yeti-ink-2); }
.aw-val--low { color: var(--yeti-ink-1); font-weight: 600; }
.aw-txt { color: var(--yeti-ink-2); }
.aw-txt--none { color: var(--yeti-ink-4); }
.aw-sub { font-size: var(--yeti-fs-sm); color: var(--yeti-ink-3); }

/* ---- Переключатель окна аптайма ------------------------------------------
   Был тёмной плашкой и весил на экране больше заголовка страницы. Приводим
   к языку системы: холодная заливка активного, тонкая обводка у остальных. */
.aw-win-tabs { display: flex; gap: var(--aw-s1, .25rem); flex-wrap: nowrap;
               overflow-x: auto; scrollbar-width: none; margin: 0 0 var(--aw-s4, 1rem); }
.aw-win-tabs::-webkit-scrollbar { display: none; }
.aw-win-tabs .aw-win-tab {
  flex: 0 0 auto;
  font-size: var(--yeti-fs-xs);
  font-weight: 500;
  line-height: 1;
  padding: 7px 11px;
  border: 0;
  border-radius: var(--aw-r-pill, 999px);
  text-decoration: none;
  color: var(--yeti-ink-3);
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--yeti-grid);
}
.aw-win-tabs .aw-win-tab:hover { color: var(--yeti-cold-deep);
                                 box-shadow: inset 0 0 0 1px var(--yeti-cold-deep); }
.aw-win-tabs .aw-win-tab.is-active {
  background: color-mix(in srgb, var(--yeti-cold) 30%, transparent);
  box-shadow: none;
  color: var(--yeti-dark);
  font-weight: 600;
}

/* ---- Кнопка «показать детали» ---------------------------------------------
   Маленькая иконка без рамки и без числа. Раньше это была пилюля с цифрой:
   она весила больше самого статуса, повторяла его смысл и в узкой ячейке
   вытягивалась в овал. Сколько именно проблем — видно в разборе, который она
   и открывает; число осталось в подсказке и для скринридера.
   Ширина задана явно: Pico растягивает button на 100 %. */
button.aw-attn-btn,
.aw-attn-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  padding: 0;
  margin: 0 0 0 var(--aw-s2, .5rem);
  color: var(--yeti-state-attn);
  background: transparent;
  border: 0;
  border-radius: var(--aw-r-pill, 999px);
  cursor: pointer;
  box-sizing: border-box;
}
/* Состояние и кнопка деталей стоят в одном контейнере, выровненные по центру.
   Подбирать вертикальное смещение кнопке не нужно вовсе: выравнивание задаёт
   flex, а не магическое число, и оно не поедет при смене кегля. */
.aw-status-cell { display: inline-flex; align-items: center; gap: var(--aw-s1, .25rem); }
.aw-attn-btn:hover { background: color-mix(in srgb, var(--yeti-state-attn) 14%, transparent); }
.aw-attn-btn:focus-visible { outline: 2px solid var(--yeti-cold-deep); outline-offset: 1px; }
.aw-attn-btn .aw-ico { width: 13px; height: 13px; flex: 0 0 auto; }

/* ============================================================================
   КАРТОЧКА МОЙКИ НА ГЛАВНОЙ
   ========================================================================== */
.aw-wash-head {
  display: flex;
  align-items: center;
  gap: var(--aw-s3, .75rem);
  flex-wrap: wrap;
  margin: 0 0 var(--aw-s3, .75rem);
  padding: 0;
  background: none;
  border: 0;
}
.aw-wash-name { font-size: var(--yeti-fs-lg); font-weight: 700; line-height: 1.25;
                letter-spacing: -.005em; }
.aw-wash-addr { font-size: var(--yeti-fs-sm); color: var(--yeti-ink-3); }
/* Метка среды: холодная плашка, а не цветной бейдж. «Рабочая» и «тест» —
   не состояния, а свойства мойки, и кричать им незачем. */
.aw-tag {
  font-size: var(--yeti-fs-xs); font-weight: 500; line-height: 1;
  padding: 4px 8px; border-radius: var(--aw-r-pill, 999px);
  color: var(--yeti-ink-2);
  background: color-mix(in srgb, var(--yeti-cold) 26%, transparent);
  white-space: nowrap;
}
/* --wrap: для плашки с целым предложением-статистикой ("тип: Nx · время"), а
   не с коротким словом ("тест"). nowrap там держит каждую плашку одним куском
   — при 10+ плашках в ряд ("Чаще всего") они переносятся ЦЕЛИКОМ (обычное
   инлайновое поведение), а самая длинная не вылезает за экран сама по себе. */
.aw-tag--wrap { white-space: normal; display: inline-block; margin: 2px 0; }
/* Действия мойки уходят к правому краю: это редкие служебные кнопки. */
.aw-wash-head .aw-head-meta { margin-left: auto; display: inline-flex;
                              align-items: center; gap: var(--aw-s2, .5rem); }
.aw-wash-head .aw-actions { gap: 2px; }
.aw-wash-head .aw-icon-btn,
.aw-wash-head button.aw-icon-btn { width: 28px; height: 28px; }
.aw-wash-head .aw-ico { width: 15px; height: 15px; }
/* Метка внутри строки таблицы («робот») — мельче, чем метка среды у мойки. */
.aw-tag--sm { font-size: var(--yeti-fs-xs); padding: 2px 6px; }

/* Наполнение кассы полоской. Нативный progress: значение приходит атрибутом,
   без inline-стилей, и элемент доступен для скринридера. */
.aw-bar { display: inline-flex; align-items: center; gap: var(--aw-s2, .5rem); }
.aw-bar__el {
  appearance: none; -webkit-appearance: none;
  width: 54px; height: 5px; border: 0; border-radius: 3px;
  background: color-mix(in srgb, var(--yeti-cold) 28%, transparent);
  color: var(--yeti-cold-deep);           /* Firefox берёт заливку отсюда */
  /* Заливку прогресса Pico красит собственной переменной — перекрываем её,
     а не воюем с вендорными псевдоэлементами. Иначе полоска остаётся синей,
     то есть цветом, которого в брендбуке нет. */
  --pico-progress-color: var(--yeti-cold-deep);
}
.aw-bar__el::-webkit-progress-bar { background: transparent; border-radius: 3px; }
.aw-bar__el::-webkit-progress-value { background: var(--yeti-cold-deep); border-radius: 3px; }
.aw-bar__el::-moz-progress-bar { background: var(--yeti-cold-deep); border-radius: 3px; }
/* Ближе к полной кассе полоска теплеет: это уже повод планировать инкассацию. */
.aw-bar__el--hot { color: var(--yeti-state-attn); --pico-progress-color: var(--yeti-state-attn); }
.aw-bar__el--hot::-webkit-progress-value { background: var(--yeti-state-attn); }
.aw-bar__el--hot::-moz-progress-bar { background: var(--yeti-state-attn); }

/* ---- Раскрываемый раздел (тестовый стенд, архив) --------------------------
   Именно разделитель, а не карточка: раньше стенд лежал в собственном
   контейнере, внутри которого были карточки моек — выходила таблица в таблице,
   особенно заметно на телефоне. Здесь у раздела есть только заголовок, а
   содержимое — те же листы, что у боевых моек. */
/* Сброс собственных полей details: Pico даёт ему рамку, фон и внутренние
   отступы, из-за чего карточка внутри становилась уже соседних и сдвигалась
   вправо — именно это и выглядело «выбивается из всех блоков». Замер до
   правки: 317 px против 351 у боевых, сдвиг 17 px. */
.aw-fold {
  margin: var(--aw-s4, 1rem) 0 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}
.aw-fold > summary + * { margin-top: var(--aw-s2, .5rem); }
/* Заголовок раздела намеренно тихий: мелкий, служебного цвета, без линии.
   Крупный заголовок с чертой превращал стенд в самостоятельный блок, и он
   выбивался из ряда карточек моек, хотя внутри лежат такие же карточки.
   Здесь это просто подпись «что дальше», а не отдельная сущность. */
.aw-fold > summary.aw-fold__head {
  display: flex;
  align-items: center;
  gap: var(--aw-s2, .5rem);
  padding: var(--aw-s1, .25rem) 0;
  list-style: none;
  cursor: pointer;
  color: var(--yeti-ink-3);
}
.aw-fold > summary.aw-fold__head::-webkit-details-marker { display: none; }
.aw-fold__name { font-size: var(--yeti-fs-sm); font-weight: 600; line-height: 1.3;
                 color: var(--yeti-ink-2); }
/* Стрелка своя: нативный маркер details выглядит по-разному в браузерах.
   Стоит сразу за подписью, а не у правого края — тогда заголовок читается
   как одна короткая строка, а не как полоса во всю ширину. */
.aw-fold > summary.aw-fold__head::after {
  content: '';
  width: 7px; height: 7px;
  margin-left: var(--aw-s1, .25rem);
  border-right: 1.5px solid var(--yeti-ink-3);
  border-bottom: 1.5px solid var(--yeti-ink-3);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .15s ease;
}
.aw-fold[open] > summary.aw-fold__head::after {
  transform: rotate(-135deg) translate(-2px, -2px);
}
.aw-fold > summary.aw-fold__head:focus-visible {
  outline: 2px solid var(--yeti-cold-deep); outline-offset: 2px;
  border-radius: var(--aw-r-sm, 4px);
}
@media (prefers-reduced-motion: reduce) {
  .aw-fold > summary.aw-fold__head::after { transition: none; }
}
@media (max-width: 560px) {
  /* Заголовку раздела и так тесно в один ряд с числом и стрелкой; описание —
     самый необязательный из трёх элементов, и при переносе на вторую строку
     съезжало относительно них. Смысл понятен по названию раздела и таблице
     внутри, поэтому на узком экране просто убираем текст, а не переносим. */
  .aw-fold__desc { display: none; }
}

/* Строка поста кликабельна целиком (обработчик в home.html). */
.aw-dt tbody tr.aw-post-row { cursor: pointer; }

/* ---- Итоговая строка таблицы (tfoot) — /stats, деньги по мойке/парку ------
   Три уровня итога (пост -> подытог мойки -> итог по парку) различаются
   весом и цветом, не новым пятым уровнем серого: подытог мойки — ink-1/600
   (как акцентная цифра), итог по парку — та же ступень, но с верхней чертой
   потолще и светлой подложкой, чтобы визуально стоять «over» подытогов. */
.aw-dt tfoot td {
  font-weight: 600;
  color: var(--yeti-ink-1);
  border-top: 2px solid var(--yeti-grid);
}
.aw-dt tfoot.aw-dt-grand td {
  background: var(--yeti-cold-wash);
  border-top: 2px solid var(--yeti-line-strong);
}

/* .aw-fold--wide: та же секция-разделитель, что «Скрытые» на /alerts, но в
   заголовке кроме имени и счётчика ещё блок метрик (выручка/машины/чек на
   /stats) — без wrap они не помещались бы в один ряд на среднем экране. */
.aw-fold--wide > summary.aw-fold__head { flex-wrap: wrap; row-gap: var(--aw-s1, .25rem); }
.aw-fold__meta { margin-left: auto; display: inline-flex; flex-wrap: wrap; gap: var(--aw-s3, .75rem); }
.aw-fold__meta b { color: var(--yeti-ink-1); font-weight: 600; }

/* ---- Техническое пояснение под кнопкой «?» --------------------------------
   Разбор механики страницы (как считаем метрику, что делает кнопка) раньше
   висел абзацем прямо под каждым заголовком постоянно и спорил за внимание
   с самими данными — 11+ страниц, у каждой свой абзац. Прячем под компактный
   icon-only триггер (тот же .aw-icon-btn, что и везде): читает тот, кому
   сейчас нужно, остальным не мешает.

   ПРАВИЛО РАЗМЕТКИ (обязательно для каждой страницы): триггер стоит рядом со
   словом заголовка, а не отдельной строкой ниже — отдельная строка «разбивает»
   макет (живая правка владельца 2026-07-27, скриншот /motors). Панель —
   ПРОСТОЙ toggle через hidden (функция awToggleHelp в base.html), НЕ нативный
   <details>: пробовали — <details>/<summary> внутри flex-шапки с кнопкой
   действия справа ломали раскладку (кнопка действия уезжала на отдельную
   строку вместо верхнего правого угла; воспроизводилось двумя разными
   вариантами display:contents/order/flex-basis). Разметка:
     <div class="aw-page-head">
       <span class="aw-title-help">
         <h2>Название</h2>
         <button type="button" class="aw-icon-btn" title="Пояснение" aria-label="Пояснение"
                 aria-expanded="false" aria-controls="aw-help-<уникальный-id>"
                 onclick="awToggleHelp(this)">{{ icon('help') }}</button>
       </span>
       <button ...>Кнопка действия справа, как раньше — .aw-page-head не трогаем</button>
     </div>
     <div class="aw-help-body" id="aw-help-<тот-же-id>" hidden>
       ...исходный текст, переписанный проще (не термины реализации)...
     </div>
   .aw-help-body — ОБЫЧНЫЙ блок ПОСЛЕ .aw-page-head (не внутри), поэтому в
   закрытом состоянии раскладка шапки идентична странице без пояснения
   (.aw-title-help — просто ещё один узкий flex-элемент рядом с h2), а в
   открытом — обычный блок на всю ширину контента, без правок каскада
   flex/grid у .aw-page-head. */
.aw-title-help { display: inline-flex; align-items: center; gap: var(--aw-s2, .5rem); }
.aw-title-help .aw-icon-btn[aria-expanded="true"] {
  background: var(--aw-accent-soft); color: var(--aw-accent);
}
.aw-help-body {
  margin: var(--aw-s2, .5rem) 0 var(--aw-s3, .75rem);
  padding: var(--aw-s3, .75rem);
  background: var(--yeti-cold-wash);
  border-radius: var(--aw-r-md, 8px);
  color: var(--yeti-ink-2);
  font-size: var(--yeti-fs-sm);
  line-height: 1.5;
}
.aw-help-body > :first-child { margin-top: 0; }
.aw-help-body > :last-child { margin-bottom: 0; }

/* Класс .aw-btn-primary (тёмная заливка) не используется: на главной кнопка
   добавления мойки лёгкая. Действие редкое — новая точка открывается раз в
   полгода, — и тёмный круг делал его самым весомым пятном экрана. */

/* ---- Лёгкое окно деталей --------------------------------------------------
   Диалог по умолчанию раздувается: Pico задаёт dialog{min-width:100%}, а
   .aw-dialog снимает это лишь частично. Здесь окно ровно под содержимое —
   список из двух-трёх строк не должен разворачиваться во весь экран. */
.aw-dialog--slim > article {
  max-width: 460px;
  width: 100%;
  padding: var(--aw-s4, 1rem) var(--aw-s5, 1.5rem) var(--aw-s5, 1.5rem);
}
/* Заголовок слева, кнопки прижаты к правому краю. Раньше они стояли сразу за
   текстом, и крестик болтался в середине шапки. */
.aw-dialog--slim > article > header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--aw-s3, .75rem);
  margin: 0 0 var(--aw-s3, .75rem);
  padding: 0 0 var(--aw-s3, .75rem);
  background: none;
  border-bottom: 1px solid var(--yeti-line);
}
.aw-dialog--slim > article > header strong {
  font-size: var(--yeti-fs-lg); font-weight: 700; line-height: 1.25;
}
.aw-dialog--slim > article > header .aw-actions { margin-left: auto; gap: var(--aw-s1, .25rem); }

/* Список проблем: подпись группы обычным регистром служебным цветом, сами
   строки — тёплая черта слева и текст. Прежний вид (капс, маркеры списка и
   заливка плашкой) для двух строк выглядел тяжелее самой информации.
   :is(.aw-dialog--slim, .aw-sheet) — тот же список проблем используется и в
   слим-модалке, и прямо в листе карточки поста (partials/monitor_post_live.html,
   не в диалоге вообще) — без второй ветки там оставался старый вид (плашка,
   cw-negative). */
:is(.aw-dialog--slim, .aw-sheet) .aw-issues-grp {
  font-size: var(--yeti-fs-xs);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--yeti-ink-3);
  margin: var(--aw-s3, .75rem) 0 var(--aw-s2, .5rem);
}
:is(.aw-dialog--slim, .aw-sheet) .aw-issues-grp:first-child { margin-top: 0; }
:is(.aw-dialog--slim, .aw-sheet) .aw-issues-list { list-style: none; margin: 0; padding: 0; }
:is(.aw-dialog--slim, .aw-sheet) .aw-issues-item {
  position: relative;
  margin: 0 0 var(--aw-s2, .5rem);
  padding: 0 0 0 var(--aw-s3, .75rem);
  font-size: var(--yeti-fs-md);
  line-height: 1.45;
  color: var(--yeti-ink-1);
  background: none;
  border: 0;
  border-radius: 0;
}
:is(.aw-dialog--slim, .aw-sheet) .aw-issues-item::marker { content: none; }
:is(.aw-dialog--slim, .aw-sheet) .aw-issues-item::before {
  content: '';
  position: absolute; left: 0; top: 3px; bottom: 3px;
  width: 3px; border-radius: 2px;
  background: var(--yeti-state-attn);
}
/* Предупреждение отличается от проблемы формой, как и в таблице: контур
   вместо заливки. */
:is(.aw-dialog--slim, .aw-sheet) .aw-issues-warn::before {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--yeti-state-attn);
}
:is(.aw-dialog--slim, .aw-sheet) .aw-issues-item:last-child { margin-bottom: 0; }

/* ---- Лента событий -------------------------------------------------------
   Время слева колонкой, состояние тем же языком, что в таблице. Хеш поста
   моноширинным и приглушённым: это опознавательный знак, а не содержание. */
.aw-ev { list-style: none; margin: 0; padding: 0; }
.aw-ev__row {
  display: flex;
  gap: var(--aw-s4, 1rem);
  align-items: baseline;
  padding: var(--aw-s2, .5rem) 0;
  border-bottom: 1px solid var(--yeti-line);
  font-size: var(--yeti-fs-md);
  line-height: 1.45;
}
.aw-ev__row:last-child { border-bottom: 0; padding-bottom: 0; }
.aw-ev__ts {
  flex: 0 0 auto;
  min-width: 8.5rem;
  font-size: var(--yeti-fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--yeti-ink-3);
}
.aw-ev__what { display: flex; align-items: baseline; gap: var(--aw-s2, .5rem); flex-wrap: wrap; }
.aw-ev__hash { font-size: var(--yeti-fs-sm); color: var(--yeti-ink-3);
               background: none; padding: 0; }

@media (max-width: 720px) {
  .aw-ev__row { flex-direction: column; gap: var(--aw-s1, .25rem); }
  .aw-ev__ts { min-width: 0; }
}

/* ---- Заголовок листа и строка сводки под заголовком страницы ------------- */
.aw-sheet-title {
  font-size: var(--yeti-fs-lg);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -.005em;
  margin: 0 0 var(--aw-s3, .75rem);
}
.aw-sheet-title .aw-sub { font-weight: 400; }

/* ---- Сводка страницы -----------------------------------------------------
   Ряд пар «число — подпись». Разделяет не точка в потоке текста, а волосяная
   линия между парами: сплошная фраза через точки читалась одним потоком, и
   выхватить из неё нужный показатель глазом было нельзя. Числа держит вес,
   а не размер — крупные цифры превратили бы строку в табло. */
.aw-kpis {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--aw-s2, .5rem) 0;
  margin: 0 0 var(--aw-s4, 1rem);
  font-size: var(--yeti-fs-sm);
  line-height: 1.4;
  color: var(--yeti-ink-3);
}
.aw-kpi { padding: 0 var(--aw-s4, 1rem); white-space: nowrap; }
.aw-kpi:first-child { padding-left: 0; }
.aw-kpi + .aw-kpi { border-left: 1px solid var(--yeti-line-strong); }
.aw-kpi b { font-weight: 600; color: var(--yeti-ink-1); font-variant-numeric: tabular-nums; }
/* Тёплым — только то, что требует реакции: офлайн, инциденты, новые посты. */
.aw-kpi--hot b { color: var(--yeti-attn-text); }

@media (max-width: 560px) {
  /* На узком экране линии-разделители рвут ряд по переносам — оставляем воздух. */
  .aw-kpi { padding: 0 var(--aw-s3, .75rem) 0 0; }
  .aw-kpi + .aw-kpi { border-left: 0; }
}


/* ---- Фон страницы -------------------------------------------------------
   Белый лист данных на белом фоне листом не читается — нужна подложка.
   Только светлая тема: в тёмной фон уже даёт Pico, и подмена его холодным
   сломала бы контраст текста, который под неё не считался. */
[data-theme="light"] body { background: var(--yeti-cold-wash); }

/* ============================================================================
   МОБИЛЬНАЯ РАСКЛАДКА ТАБЛИЦЫ ДАННЫХ
   Колонок больше четырёх в 375 px не помещается, а горизонтальная прокрутка
   страницы — правило, которое в проекте нарушать нельзя. Прятать колонки
   тоже плохо: на телефоне смотрят в дороге, и второстепенное там как раз
   нужнее. Поэтому строка перестаёт быть строкой и становится карточкой,
   а подписи колонок переезжают к значениям через data-label.
   ========================================================================== */
@media (max-width: 720px) {
  .aw-dt { border: 0; }
  .aw-dt thead { position: absolute; width: 1px; height: 1px;
                 overflow: hidden; clip: rect(0 0 0 0); }

  /* Карточка строится как строгий список «подпись — значение»: подписи стоят
     в одной колонке фиксированной ширины, значения в другой. Прежняя схема
     (первые две ячейки в ряд, остальные во всю ширину) давала разнобой —
     каждая строка выравнивалась по-своему, и блок читался хаотично. */
  /* :is(tbody,tfoot) — таблицы с денежным итогом (/stats) кладут подытог в
     <tfoot>: без него строка итога осталась бы обычной широкой строкой таблицы
     рядом с уже превращёнными в карточки строками tbody. */
  .aw-dt :is(tbody, tfoot) tr:not(.aw-dt-grp) {
    display: block;
    /* Правый паддинг был 0 (только левый ради полоски aw-dt-bad) — значения
       садились впритык к правому краю листа на телефоне (прогресс-бар/проценты
       у /motors, но правило общее для всех .aw-dt). Отступ нужен с обеих сторон. */
    padding: var(--aw-s3, .75rem) var(--aw-s4, 1rem);
    border-bottom: 1px solid var(--yeti-line);
    position: relative;
  }
  .aw-dt :is(tbody, tfoot) tr:not(.aw-dt-grp) td {
    display: grid;
    grid-template-columns: 5.25rem 1fr;   /* подпись | значение */
    column-gap: var(--aw-s2, .5rem);
    align-items: baseline;
    border: 0;
    padding: 1px 0;
    text-align: left;
    min-width: 0;
    /* НАЙДЕНО ЖИВЬЁМ: style.css (общий с YetiWash CRM, не трогаем) держит
       общее правило `main table:not(.cw-tx-table):not(.cw-schedule) td {
       white-space: nowrap }` для узких таблиц — .aw-dt в список исключений
       не попал. Подпись из ::before наследует nowrap ОТ ЭТОЙ ячейки и не
       переносится: «Мойка · пост»/«Длительность» рядом с длинным значением
       съезжались в одну строку без видимого пробела. Тот же specificity
       (0,2,3), но правило позже в каскаде (brand.css грузится последним) —
       возвращаем перенос словами тем, кому нужна подпись/заголовок карточки
       шире одного слова. */
    white-space: normal;
  }
  /* Ячейка «Действия»/«Действие» — во второй колонке лежит .aw-actions без
     единого текстового узла (только SVG-иконки); у flex-блока без текста нет
     собственной базовой линии, браузер синтезирует её по нижнему краю — из-за
     этого иконки прижимались к верху ячейки, а подпись колонки съезжала вниз
     относительно них. По центру ячейки, а не по псевдо-baseline. */
  .aw-dt :is(tbody, tfoot) tr:not(.aw-dt-grp) td:has(.aw-actions) { align-items: center; }
  /* Имя поста — заголовок карточки: во всю ширину, без подписи, с отбивкой. */
  .aw-dt :is(tbody, tfoot) tr:not(.aw-dt-grp) td:first-child {
    display: block; padding: 0 0 var(--aw-s1, .25rem);
    font-weight: 600; font-size: var(--yeti-fs-md);
  }
  .aw-dt :is(tbody, tfoot) td:first-child { padding-left: 0; font-weight: 600; }
  .aw-dt .aw-dt-bad td:first-child::after { left: calc(-1 * var(--aw-s4, 1rem) + var(--aw-s1, .25rem)); }
  /* Имя поста — заголовок карточки, подпись «Пост» перед ним избыточна.
     В селектор добавлен [data-label]: без него специфичность совпадает с
     правилом подписи ниже, и побеждает оно, а не это. */
  .aw-dt :is(tbody, tfoot) tr:not(.aw-dt-grp) td:first-child[data-label]::before { content: none; }

  .aw-dt tbody .aw-dt-grp td {
    padding: var(--aw-s3, .75rem);
    position: static;            /* прилипание на телефоне только мешает */
  }
  /* Перестановка моек — действие с рабочего места, а не из дороги. На телефоне
     эти стрелки занимают целую строку в каждом заголовке и ничего не дают. */
  .aw-dt .aw-dt-grp .aw-actions { display: none; }

  /* Подпись колонки рядом со значением. Пустой data-label дал бы висячее
     «: », поэтому у ячеек без подписи атрибут не ставим вовсе. */
  .aw-dt :is(tbody, tfoot) tr:not(.aw-dt-grp) td[data-label]::before {
    content: attr(data-label) ' ';
    color: var(--yeti-ink-3);
    font-weight: 400;
    /* Длинная однословная подпись («Длительность») шире 5.25rem-колонки и не
       может перенестись по пробелу — без этого она наезжала на значение
       соседней колонки без видимого зазора. */
    overflow-wrap: break-word;
  }
  /* Прочерк вместо значения на телефоне только занимает строку. Селектор с
     тем же префиксом, что у правила display:block выше, иначе оно победит. */
  .aw-dt :is(tbody, tfoot) tr:not(.aw-dt-grp) td.aw-txt--none { display: none; }

  /* На телефоне обрезка нужна тем более: длинное описание занимало три строки
     и растягивало карточку так, что соседние посты уходили за экран. Ширину
     задаём авто (в гриде колонка и так ограничена), обрезку оставляем,
     раскрытие — по тапу, правило :focus выше. */
  /* Обрезка живёт на внутреннем span: в сетке «подпись — значение» многоточие
     на самой ячейке не работает — обрезать нужно тот элемент, который лежит
     во второй колонке. */
  .aw-dt tbody tr:not(.aw-dt-grp) td.aw-dt-clip { max-width: none; width: auto; }

  /* Кнопка деталей на телефоне обязана быть тач-целью 44x44 (правило проекта,
     глобальное `button{min-height:44px}` — WCAG 2.5.5). Но 44 px распирали
     строку статуса вдвое: под ней зияла пустота. Реальный размер оставляем,
     а лишнюю высоту выносим за поток отрицательными полями — палец получает
     свои 44 px, строка остаётся высотой в текст. */
  /* Тач-цель 44x44 (правило проекта, WCAG 2.5.5), но лишняя высота и ширина
     вынесены за поток отрицательными полями: палец получает свои 44 px, а в
     строке значок занимает столько же места, сколько текст рядом. */
  .aw-dt tbody tr:not(.aw-dt-grp) .aw-attn-btn {
    width: 44px;
    height: 44px;
    margin: -12px -12px -12px -12px;
  }
  /* Подсветка наведения на телефоне не нужна и вредна: указателя нет, а после
     тапа фон «залипает» — вокруг значка оставалось круглое пятно во всю
     тач-цель. Отклик даёт сама открывшаяся карточка. */
  .aw-dt tbody tr:not(.aw-dt-grp) .aw-attn-btn:hover { background: transparent; }
}

/* ============================================================================
   ОБЩИЙ КОМПОНЕНТ: ПЛИТКИ KPI (.aw-an-kpis / .aw-an-kpi)
   ----------------------------------------------------------------------------
   Один и тот же паттерн «карточка: подпись сверху, крупное число, подпись
   снизу» используется на /stats, /analytics, /marketing и вкладке «Обратная
   связь» — это не дубли, а один переиспользуемый компонент (app.css §analytics,
   структуру не меняем). Здесь только переводим токены на канон: было
   --cw-bg-soft/--cw-border (style.css, серые дефолты YetiWash) и число из
   style.css .cw-kpi-value (1.4rem/600, вне нашей шкалы) — становится холодная
   подложка бренда и число по канону (22px = та же ступень, что у заголовка
   страницы: это самая важная цифра на листе, ей положен тот же вес).
   ========================================================================== */
.aw-an-kpis { gap: var(--aw-s3, .75rem); margin: 0 0 var(--aw-s4, 1rem); }
.aw-an-kpi {
  background: var(--yeti-cold-wash);
  border: 1px solid var(--yeti-line-strong);
  border-radius: var(--aw-r, 8px);
}
.aw-an-kpi .cw-kpi-value {
  font-size: var(--yeti-fs-xl);
  font-weight: 600;
  color: var(--yeti-ink-1);
  margin-top: var(--aw-s1, .25rem);
}
/* Подписи внутри плитки — служебный текст (роль --yeti-fs-xs уже верна после
   общего перевода .aw-xs выше; здесь только цвет: cw-muted даёт серый
   YetiWash, а не наш ink-3). */
.aw-an-kpi .cw-muted { color: var(--yeti-ink-3); }

/* ============================================================================
   КАТЕГОРИАЛЬНАЯ ПАЛИТРА ГРАФИКОВ (.aw-st-* — доли каналов оплаты)
   ----------------------------------------------------------------------------
   У брендбука 4 цвета, а каналов оплаты для легенды — 5 (нал/карта/СБП/сервис/
   Лейка) плюс одиночный акцент графиков (столбцы/линия трендов). Тёплый занят
   под «требует реакции» (design-system.md §3) и в категориальную легенду не
   идёт — иначе доля «Сервис» читалась бы как тревога. Прежняя палитра решала
   это произвольными #2e9e6b/#d98a2b/#7e57c2 — тремя цветами мимо брендбука
   (ровно тот долг «четыре зелёных, семь жёлтых», что зафиксирован в
   design-system.md §12). Новая — оттенки/тени двух холодных и тёмного плюс
   нейтральный серый; тёплый не используется вовсе. */
.aw-bar, .aw-area, .aw-line, .aw-line-dot, .aw-hm-cell { fill: var(--yeti-cold-deep); }
.aw-hm-cell:hover { stroke: var(--yeti-cold-deep); }
.aw-st-cash    { fill: #9aa4b0; }                 /* нейтральный: наличные вне брендовых холодных/тёмного */
.aw-st-card    { fill: var(--yeti-cold-deep); }
.aw-st-sbp     { fill: var(--yeti-dark); }
.aw-st-service { fill: var(--yeti-cold); }
.aw-st-leyka   { fill: var(--yeti-dark-soft); }
.aw-st-sw.aw-st-cash    { background: #9aa4b0; }
.aw-st-sw.aw-st-card    { background: var(--yeti-cold-deep); }
.aw-st-sw.aw-st-sbp     { background: var(--yeti-dark); }
.aw-st-sw.aw-st-service { background: var(--yeti-cold); }
.aw-st-sw.aw-st-leyka   { background: var(--yeti-dark-soft); }
/* Промо-метки/полосы на тренде (скидка/наценка/бонус) — тоже мимо тёплого:
   это не тревога, а разметка ОКНА акции на графике. Различаются штрихом
   (сплошной/пунктир) и подписью в title, не только цветом. */
.aw-pmark { stroke: var(--yeti-ink-3); }
.aw-pmark-discount, .aw-pmark-bonus { stroke: var(--yeti-cold-deep); }
.aw-pmark-dynamic { stroke: var(--yeti-dark); }
.aw-pband { fill: #9aa4b0; fill-opacity: .10; }
.aw-pband-disc { fill: var(--yeti-cold-deep); fill-opacity: .10; }
.aw-pband-surge { fill: var(--yeti-dark); fill-opacity: .08; }
