/* ================= ТЕМА ПОРТАЛА =================
   Меняешь здесь — меняется везде. Для клиентских тем
   достаточно переопределить эти переменные.            */
:root {
  --ui-brand:        #00a0ff;
  --ui-danger:       #f87171;
  --ui-ok:           #34d399;   /* успех: «скопировано», «сохранено» — НЕ бренд-синий */
  --ui-ico:          #e8e8e8;
  --ui-ico-opacity:  .55;
  --ui-ico-size:     15px;
  /* Шеврон сворачивания в списках и карточках — белый (запрос Константина, 04.09.2026).
     Раньше был литерал #666 в .ui-fold-chev и инлайном на страницах: серая галка на тёмном
     фоне не читалась как «сюда можно нажать». Ховер по-прежнему уводит в акцентный цвет. */
  --ui-fold-chev:    #ffffff;

  /* --- поверхности и границы (были литералами в .ui-card) --- */
  --ui-page-bg:      #0e0e0e;
  --ui-card-bg:      #141414;
  --ui-card-border:  #262626;
  --ui-surface-2:    #1a1a1a;   /* фон полей и чипов ВНУТРИ карточки */
  --ui-row-hover:    #161616;   /* подсветка строки таблицы под курсором (эталон 30.08.2026) */
  --ui-muted:        #6a6a6a;   /* лейблы и мета */
  --ui-claude:       #D97757;   /* фирменный цвет значка Claude */

  /* --- 20.10.2026 «История» (/doclog): фиолетовая метка, себестоимость ₽, энергоны ⚡ (DESIGN-TOKENS.md) ---
     Одинаково читаются в обеих темах: основа подмешана к цвету текста темы (--ui-tx) — в тёмной теме светлее,
     в светлой темнее. soft-тройка — та же формула, что у .ui-st (фон 12%, рамка 32%, текст 60% к --ui-tx). */
  --ui-violet:            #a78bfa;
  --ui-violet-soft:       color-mix(in srgb, var(--ui-violet) 12%, var(--ui-surface, var(--ui-card-bg)));
  --ui-violet-soft-line:  color-mix(in srgb, var(--ui-violet) 32%, var(--ui-surface, var(--ui-card-bg)));
  --ui-violet-soft-tx:    color-mix(in srgb, var(--ui-violet) 60%, var(--ui-tx, #e8e8e8));
  --ui-cost:              color-mix(in srgb, #f59e0b 78%, var(--ui-tx, #e8e8e8));   /* суммы себестоимости, ₽ */
  --ui-energy:            color-mix(in srgb, #ca8a04 70%, var(--ui-tx, #e8e8e8));   /* энергоны, ⚡ */

  /* --- мобильные размеры --- */
  --ui-tap:          44px;      /* минимальный тач-таргет */
  --ui-tap-sm:       30px;
  --ui-chip-radius:  16px;
  --ui-seg-h:        4px;       /* высота сегмента чек-листа */
  --ui-sheet-radius: 22px;
  --ui-radius-lg:    24px;      /* большой радиус карточки iOS-стиля (.ui-ios-card), 19.10.2026 */
  --ui-actions-h:    96px;      /* высота нижнего ряда кнопок */

  /* --- свечения состояний карточки --- */
  --ui-glow-danger:  rgba(248,113,113,.14);
  --ui-glow-brand:   rgba(0,160,255,.05);

  /* Отступ при подскролле к якорю (09.09.2026). На мобиле кнопки ⟳/☰ закреплены
     у верхнего края — без этого отступа заголовок, к которому прыгнули по #якорю
     или через scrollIntoView(), уезжает ПОД них. */
  --ui-anchor-off:   16px;

  /* Высота шторки — ЕДИНЫЙ источник (04.10.2026): экран минус зазор --ui-sheet-top (/set → «Шторка»)
     минус вырез/статус-бар iPhone. Все шторки берут её отсюда: height: var(--ui-sheet-h-vh);
     height: var(--ui-sheet-h) (первая строка — фолбэк для движков без dvh). Свои слагаемые
     (клавиатура, нижний док, отступы) потребитель дописывает сам: calc(var(--ui-sheet-h) - X).
     Токен --ui-sheet-h переопределён ниже под dvh внутри supports: так он остаётся валидным и
     в старых движках (там var() с dvh сделал бы высоту auto, а не откат на строку vh). */
  --ui-sheet-h-vh:   calc(100vh - var(--ui-sheet-top, 64px) - env(safe-area-inset-top, 0px));
  --ui-sheet-h:      var(--ui-sheet-h-vh);
}
@supports (height: 100dvh) {
  :root { --ui-sheet-h: calc(100dvh - var(--ui-sheet-top, 64px) - env(safe-area-inset-top, 0px)); }
}

/* Якоря: правило одно на всю платформу, страницам ничего дописывать не нужно.
   scroll-margin-top срабатывает только в момент подскролла к элементу, на обычную
   вёрстку не влияет — поэтому вешается на любой [id], а не только на :target
   (переходы по JS через scrollIntoView() :target не поднимают). */
[id] { scroll-margin-top: var(--ui-anchor-off); }

@media (max-width: 768px) {
  :root { --ui-anchor-off: 96px; }
}

/* ===== ШРИФТ ПЛАТФОРМЫ — ОДНО ОБЪЯВЛЕНИЕ НА ВСЕ СТРАНИЦЫ (06.09.2026) =====
   Стек из docs/DESIGN-TOKENS.md. До этого его прописывала КАЖДАЯ страница у себя
   в <style> (set, medcard, habits, patients, scripts, sex, test…), а кто не прописал —
   рисовался дефолтным шрифтом браузера с засечками. Именно так жила страница
   «Каналы»: вся вёрстка правильная, а набрана Times — и выглядела как чужая.
   Правило стоит в ui.css, то есть ДО локальных <style> страниц: у кого объявлен
   свой шрифт (медкарта на Manrope, кабинеты клиентов), тот остаётся на своём. */
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }

/* ===== ADR-097: адаптивные горизонтальные ряды (вкладки/группы действий) =====
   Единый responsive-примитив: ряд переносится на новую строку на узком экране,
   ширина/паддинг элементов при этом не меняются (никакого сжатия и nowrap-обрезания).
   .ui-row — базовое поведение (display:flex + flex-wrap:wrap + min-width:0).
   .ui-tabs / .ui-actions — семантические варианты (отличаются только gap),
   локальную геометрию страницы (цвет, border-bottom, паддинг кнопки) не трогаем —
   примитив отвечает только за перенос, не за визуал.
   НЕ применять к: .lead-sidebar (другой паттерн — sidebar→верхний ряд через свой
   @media, не wrap) и к сегментированным pill-переключателям (uploads.html .tabs,
   medcard.html .tabs/.med-tabs, tasks.html .tt-tabs) — там уже осознанно выбран
   другой мобильный паттерн (overflow-x:auto скролл). */
.ui-row { display:flex; flex-wrap:wrap; min-width:0; }
.ui-tabs { gap:4px; }
.ui-actions { gap:8px; }

/* Компактная строка «два коротких поля + растяжимое посередине» (76px/1fr/76px) —
   образец: форма миссии в трекере привычек (medcard_habits.js, schedFields()).
   Пока единственный кейс — сознательно не оформляем как JS-хелпер (см. ADR-097). */
.ui-compact-row { display:flex; gap:10px; min-width:0; }
.ui-compact { flex:0 0 76px; min-width:0; }
.ui-grow { flex:1 1 auto; min-width:0; }

/* Строка формы «поле(я) + кнопка в ряд, перенос на мобиле» — до 30.08.2026 был
   локальный класс .row с ЭТИМ ЖЕ побайтово правилом в fields.html, kb.html и
   vo.html (три копии одного и того же). Класс назван НЕ .row: генерик-имя
   .row занято под другую задачу на других страницах платформы (подсветка
   строки таблицы <tr class="row">, свой .row под конкретную раскладку и т.д.) —
   промотать бы .row в общий файл значило сломать их. Заводить новую страницу
   с рядом «поле+кнопка» — брать этот класс, а не копировать правило заново. */
.ui-form-row { display:flex; gap:10px; margin-bottom:16px; flex-wrap:wrap; }
/* Модификатор: подписи/поля/кнопки разной высоты в ряд — центрировать по вертикали,
   а не растягивать на всю высоту строки (было отдельным align-items:center в
   b24fields.html и history.html, 30.08.2026). */
.ui-form-row.is-center { align-items:center; }

/* ===== АНТИ-ЗУМ ПОЛЕЙ ВВОДА НА iOS (ADR-081, ADR-082) =====
   Safari на iPhone сам зумит страницу при фокусе на input/select/textarea
   с вычисленным font-size < 16px — и зум иногда не откатывается после
   закрытия модалки. meta viewport (maximum-scale) тут не спасает и
   специально не используется, чтобы не блокировать pinch-zoom остальным.
   Правило только для мобильных: на десктопе такого бага нет, а плотная
   вёрстка таблиц (узкие колонки с input) не должна раздуваться.
   !important — единственный надёжный способ перебить множество локальных
   font-size:12–15px, разбросанных по конкретным страницам, без правки
   каждого файла по отдельности. Действует на все страницы, где подключён
   этот файл — включая кабинеты клиентов, текущих и будущих. */
@media (max-width:768px) {
  input, select, textarea { font-size:16px !important; }
}

/* ===== ИКОНКИ ДЕЙСТВИЙ (спрайт: stroke="currentColor" → красим color) ===== */
.i-del, .i-edit, .i-copy, .i-nocopy, .i-show, .i-hide, .i-link, .i-dots {
  width: var(--ui-ico-size); height: var(--ui-ico-size);
  color: var(--ui-ico) !important;
  opacity: var(--ui-ico-opacity);
  cursor: pointer;
  transition: color .15s, opacity .15s;
  display: inline-block; vertical-align: -2px; flex-shrink: 0;
}
.i-del:hover,  *:hover > .i-del,
.i-nocopy:hover, *:hover > .i-nocopy { color: var(--ui-danger) !important; opacity: 1; }
.i-edit:hover, *:hover > .i-edit,
.i-copy:hover, *:hover > .i-copy,
.i-show:hover, *:hover > .i-show,
.i-hide:hover, *:hover > .i-hide,
.i-dots:hover, *:hover > .i-dots,
.i-link:hover, *:hover > .i-link { color: var(--ui-brand) !important; opacity: 1; }

/* Иконка во ВКЛЮЧЁННОМ состоянии: действие уже применено и клик его снимает.
   Пример: запись журнала помечена «данные удалены» — корзина горит красным,
   клик возвращает запись. Цвет и размер те же переменные, что и у обычных иконок. */
.ico-on > .i-del, .ico-on > .i-nocopy { color: var(--ui-danger) !important; opacity: 1; }
.ico-on > .i-edit, .ico-on > .i-copy, .ico-on > .i-show,
.ico-on > .i-hide, .ico-on > .i-link { color: var(--ui-brand) !important; opacity: 1; }

/* обёртки вокруг иконок — прозрачные, без своих цветов */
button:has(.i-del), button:has(.i-edit), button:has(.i-copy), button:has(.i-nocopy),
button:has(.i-show), button:has(.i-hide), button:has(.i-dots),
span:has(> .i-del), span:has(> .i-edit), span:has(> .i-copy), span:has(> .i-nocopy),
span:has(> .i-show), span:has(> .i-hide), span:has(> .i-link), span:has(> .i-dots) {
  background: transparent !important; border: none !important;
  box-shadow: none !important; padding: 4px !important;
}

/* ===== ТОСТ ПЛАТФОРМЫ (.plt-toast) =====
   Единый вид всплывающего уведомления снизу экрана — не плодить свои
   реализации на страницах. Подключение: <script src="/toast.js"></script>,
   вызов: pltToast('Текст') / pltToast('Текст', {err:true}). Документация
   и живой пример — /set (вкладка «Дизайн»). Зелёный фон — успех, красный —
   ошибка (err:true). Ширина фиксирована ~75% экрана (18.08.2026, запрос
   Константина — раньше плашка сжималась под контент и длинный текст
   обрезался многоточием), текст переносится на несколько строк вместо
   обрезки. Полоска снизу — визуальный обратный отсчёт до автозакрытия;
   наведение мышью/тач (см. toast.js) ставит отсчёт на паузу — pointer-events
   поэтому включены только пока плашка показана (.show).
   19.08.2026 (запрос Константина): контейнер #plt-toast-stack — несколько
   плашек одновременно на экране (pltToast(text,{key:'...'})), column-reverse
   держит первую вызванную плашку снизу (там же, где раньше стоял единственный
   #plt-toast), а следующие вырастают вверх. Без key поведение и позиция не
   меняются — тот же #plt-toast внутри контейнера с теми же координатами. */
/* 31.08.2026: на мобиле снизу стоит док нижнего меню (bottom-nav.js), он публикует
   свою высоту в --cfbn-pad. Без этого слагаемого тост ложится прямо на кнопки дока
   (z-index тоста 9999 против 450 у дока). На десктопе переменной нет — те же 24px.
   29.09.2026: на телефоне при видимом доке (body.cfbn-on) координаты стопки берутся из
   настройки /set → «Чипы», как у uiToast, — см. блок «ТОСТЫ НАД ДОКОМ» ниже. */
#plt-toast-stack {
  position: fixed; left: 50%; bottom: calc(24px + var(--cfbn-pad, 0px)); transform: translateX(-50%);
  display: flex; flex-direction: column-reverse; align-items: center; gap: 10px;
  width: 75vw; max-width: 640px; z-index: 9999; pointer-events: none;
}
.plt-toast {
  position: relative; width: 100%; transform: translateY(10px);
  display: flex; align-items: flex-start; gap: 8px;
  /* 29.09.2026: светлая тема — цвета плашки из токенов /theme.css (themeVars в server.js):
     в тёмной те же #14351f/#1e5230/#4ade80, в светлой — светло-зелёная плашка с тёмным текстом. */
  background: var(--ui-toast-ok-bg, #14351f); border: 1px solid var(--ui-toast-ok-line, #1e5230); color: var(--ui-ok, #4ade80);
  padding: 10px 16px 12px; border-radius: 12px; font-size: 13px; line-height: 1.4;
  box-shadow: var(--ui-shadow-md, 0 6px 18px -2px rgba(0,0,0,.30)); /* 30.09.2026: тени — уровень md (/refs#shadows) */
  opacity: 0; pointer-events: none;
  transition: opacity .2s, transform .2s;
  overflow: hidden;
}
.plt-toast.show { opacity: 1; transform: translateY(0); pointer-events: auto; }
.plt-toast.err { background: var(--ui-toast-err-bg, #3a1416); border-color: var(--ui-toast-err-line, #63252a); color: var(--ui-danger, #f87171); }
.plt-toast .ic { flex-shrink: 0; margin-top: 1px; }
.plt-toast .txt { white-space: normal; overflow-wrap: break-word; }
/* 07.10.2026: ошибка не гаснет сама — «Копировать» и крестик (toast.js); у успеха блок скрыт */
.plt-toast .acts { display: none; flex-shrink: 0; align-items: center; gap: 4px; margin: -2px -8px 0 auto; }
.plt-toast.err .acts { display: flex; }
.plt-toast .acts button { background: transparent; border: 0; color: inherit; opacity: .75; cursor: pointer; padding: 4px; line-height: 1; font-size: 18px; border-radius: var(--ui-radius, 8px); display: flex; align-items: center; justify-content: center; min-width: 24px; min-height: 24px; }
.plt-toast .acts button:hover { opacity: 1; }
.plt-toast .acts button.done { opacity: 1; color: var(--ui-ok, #4ade80); }
.ui-toast .ui-toast-cp { position: absolute; top: 5px; right: 30px; color: var(--ui-tx-3, #777); cursor: pointer; line-height: 1; padding: 0; background: transparent; border: 0; }
.ui-toast .ui-toast-cp:hover { color: var(--ui-tx, #fff); }
.ui-toast .ui-toast-cp.done { color: var(--ui-ok, #3ec46d); }
.plt-toast .bar { position: absolute; left: 0; bottom: 0; height: 2px; width: 100%; background: currentColor; opacity: .55; }

/* ===== ЧИП uiToast (#ui-toasts) =====
   12.09.2026. Плашка ui-dialogs.js — «чип» на языке /set и /refs. Раньше её координаты
   стояли inline прямо в скрипте: left = calc(var(--sb-w) + 18px). На телефоне сайдбар
   уезжает в шторку, а --sb-w остаётся равным ширине меню портала (230px) — и чип вставал
   не слева сверху, как написано в /refs, а в ПРАВОМ верхнем углу, поверх кнопок шапки
   карточки лида: пока не досчитает до нуля, «Сохранить» и «Скачать» нажать нельзя.
   Теперь угол — настройка (/set → «Чипы»), восемь точек по краям экрана, отдельно для
   ПК и для телефона. Значения приезжают пятью переменными из /theme.css (toastCss в
   server.js); фолбэки ниже = верх слева, то есть прежнее задуманное поведение на ПК.
   Кегль --ui-toast-fs тоже из /theme.css; крестик и счётчик считаются от него в em,
   поэтому один ползунок двигает плашку целиком. Позиция pltToast НЕ настраивается —
   он снизу по центру над доком (--cfbn-pad выше) и с чипом за один угол не спорит.
   Исключение (29.09.2026): телефон с доком (body.cfbn-on) — там pltToast и #toast страниц
   встают в угол чипа, а нижние углы не опускаются под док (блок «ТОСТЫ НАД ДОКОМ» ниже). */
#ui-toasts {
  position: fixed; z-index: 2147483000;
  /* --ui-toast-skip — не настройка, а поправка, которую ui-dialogs.js считает перед показом:
     у карточки лида, проекта и задачи на телефоне сверху стоит ЗАКРЕПЛЁННЫЙ ряд действий
     (.modal-sidebar), и любой верхний угол лёг бы прямо на него — ровно та беда, с которой
     всё началось. Скрипт меряет ряд и опускает чип под него; ряда нет — поправка ноль. */
  top: calc(var(--ui-toast-top, 14px) + var(--ui-toast-skip, 0px)); bottom: var(--ui-toast-bottom, auto);
  left: var(--ui-toast-left, calc(var(--sb-w, 0px) + 18px)); right: var(--ui-toast-right, auto);
  transform: translate(var(--ui-toast-tx, 0), var(--ui-toast-ty, 0));
  /* Стопка растёт ВНУТРЬ экрана: у верхних углов вниз, у нижних вверх (column-reverse) —
     иначе вторая плашка у нижнего края уезжала бы за экран. Направление задаёт тот же
     toastCss() в server.js, что и координаты. */
  display: flex; flex-direction: var(--ui-toast-dir, column); gap: 8px;
  align-items: var(--ui-toast-align, flex-start);
  pointer-events: none;
  /* width:max-content — не косметика. Контейнер закреплён и сжимается по содержимому, а у
     центральных углов он начинается на left:50%, и «по содержимому» упирается в остаток
     экрана: на телефоне 390px плашка выходила 195px — ровно половина, вдвое уже, чем на
     остальных углах (проверено прогоном в браузере, 12.09.2026). max-content считает ширину
     по тексту, а не по остатку, и потолок задаёт строка ниже. */
  width: max-content; max-width: calc(100vw - 24px);
}
/* Плашка не шире экрана минус поля: при «сверху по центру» фиксированные 380px на телефоне
   вылезали бы за оба края. box-sizing обязателен: без него max-width считается ПО КОНТЕНТУ,
   к нему прибавляются 48px отступов и 4px кромок, и чип 366px становился 418px — он упирался
   в противоположный край экрана вплотную, без поля. */
.ui-toast {
  box-sizing: border-box;
  position: relative; max-width: min(380px, calc(100vw - 24px));
  font-size: var(--ui-toast-fs, 14px); line-height: 1.45;
  pointer-events: auto; overflow: hidden;
}
.ui-toast .ui-toast-x { position: absolute; top: 4px; right: 9px; color: var(--ui-tx-3, #777); font-size: 1.35em; line-height: 1; cursor: pointer; }
.ui-toast .ui-toast-cnt { position: absolute; bottom: 4px; right: 10px; color: var(--ui-tx-3, #666); font-size: .8em; font-variant-numeric: tabular-nums; }
/* Единый кегль у обоих общих чипов платформы — жалоба «мелко» была про оба. */
.plt-toast { font-size: var(--ui-toast-fs, 14px); }

/* ===== ТОСТЫ НАД ДОКОМ (личные страницы с bottom-nav.js, телефон) =====
   29.09.2026, жалоба с айфона: на /medcard/set после «Сохранить» плашка «Сохранено — обнови
   другие вкладки…» вставала снизу по центру прямо под док и его кнопку «+». Причины две:
   1) --cfbn-pad = высота дока + его отступ + 32px запаса, но БЕЗ safe-area, а сам док висит
      на отступ + safe-area (DOCK_BOTTOM в bottom-nav.js) — на айфоне это ещё 34px;
   2) у страниц свои тосты (#toast в set.html, medcard.html, sex.html, pdiary.html) с
      bottom:20–24px, про док они не знают вовсе.
   Правило одно на все три реализации: #ui-toasts (uiToast, ui-dialogs.js),
   #plt-toast-stack (pltToast, toast.js) и #toast (локальный toast() страниц).
   - Угол — из /set → «Чипы» (--ui-toast-* из /theme.css, toastCss() в server.js), тот же, что
     у uiToast: на телефоне с доком все тосты стоят в одном месте, а не каждый в своём.
   - Нижний угол не опускается ниже --ui-toast-dock — это кромка дока вместе с «+» и зазор.
     По умолчанию считаем её из --cfbn-pad + safe-area; toast.js и ui-dialogs.js перед показом
     меряют #cfbn и .cfbn-add и пишут точное значение в --ui-toast-dock-js на body (кнопка
     «+» может выступать выше 32px запаса при большом «подъёме» в настройках дока).
   - Зазор над доком = --ui-toast-gap = тот же, что у верхнего тоста от края экрана. Верхний
     угол на телефоне стоит от КРАЯ ЭКРАНА (position:fixed) плюс safe-area, а не под шапкой:
     --ui-toast-top = calc(safe-area-inset-top + 14px), mobTop в toastCss() server.js и top в
     tsApply() set.html (у «справа сверху» 64px — под бургер, это не зазор, а обход кнопки).
     Здесь берём только 14px, без safe-area: снизу её уже учитывает кромка дока.
     Меняешь 14px там — поменяй и здесь; toast.js/ui-dialogs.js читают значение отсюда.
   - Нижний угол при видимом доке стоит РОВНО на --ui-toast-dock, а не на max() с
     --ui-toast-bottom: тот = safe-area + --cfbn-pad (+32px запаса) + 14px, он всегда выше
     замера, и max() давал зазор ~46px вместо 14px. calc(var(--ui-toast-bottom) * 0 + …) —
     приём «только для нижних углов»: у верхних --ui-toast-bottom = auto, auto * 0 недопустим,
     свойство откатывается к auto, и верхние углы остаются ровно как были. Так же calc(auto + …) у top.
   - Док скрыт (html.cfbn-off — выключен в шестерёнке; .cfbn-kb — открыта клавиатура) —
     --ui-toast-dock = --ui-toast-bottom, то есть обычная позиция из настройки, как до правки.
   Правьте здесь, а не на страницах: копия правила на странице разойдётся с этой. */
@media (max-width: 768px) {
  body.cfbn-on {
    --ui-toast-gap: 14px;
    --ui-toast-dock: var(--ui-toast-dock-js, calc(var(--cfbn-pad, 0px) + env(safe-area-inset-bottom, 0px) + var(--ui-toast-gap)));
  }
  html.cfbn-off body.cfbn-on,
  body.cfbn-on:has(#cfbn.cfbn-kb) { --ui-toast-dock: var(--ui-toast-bottom, auto); }
  body.cfbn-on #ui-toasts,
  body.cfbn-on #plt-toast-stack,
  body.cfbn-on #toast {
    top: var(--ui-toast-top, calc(env(safe-area-inset-top, 0px) + 14px));
    bottom: calc(var(--ui-toast-bottom, auto) * 0 + var(--ui-toast-dock, 0px));
    left: var(--ui-toast-left, 12px); right: var(--ui-toast-right, auto);
    transform: translate(var(--ui-toast-tx, 0), var(--ui-toast-ty, 0));
    max-width: calc(100vw - 24px);
  }
  /* поправка на закреплённый ряд карточки (--ui-toast-skip) — только у uiToast, как выше */
  body.cfbn-on #ui-toasts { top: calc(var(--ui-toast-top, 14px) + var(--ui-toast-skip, 0px)); }
  /* стопка pltToast растёт внутрь экрана, как у чипа: у нижних углов вверх */
  body.cfbn-on #plt-toast-stack {
    flex-direction: var(--ui-toast-dir, column); align-items: var(--ui-toast-align, flex-start);
  }
}

/* ===== ТОЛЬКО ДЛЯ СУПЕР-АДМИНА (.pm-only) =====
   Всё, что видит только ПМ и не видит клиент, красится красным —
   чтобы с одного взгляда отличать свои кнопки от клиентских. */
/* Цвета — токены красной кнопки --ui-btnd-* из /theme.css (обе темы), фолбэки = прежний тёмный вид. */
.pm-only {
  background: var(--ui-btnd-bg, #3a0d0d) !important;
  border: 1px solid var(--ui-btnd-border, #7a2e0b) !important;
  color: var(--ui-btnd-text, #f87171) !important;
}
button.pm-only:hover, .btn.pm-only:hover, .tbtn.pm-only:hover, a.pm-only:hover, .kw-dd.pm-only:hover {
  background: var(--ui-btnd-hover-bg, #4a1010) !important;
  color: var(--ui-btnd-hover-text, #f87171) !important; filter: none;
}
/* Вложенные кнопки/ссылки внутри плашки .pm-only (details «Сравнение с Топвизором» и т.п.) берут её цвет */
.pm-only .btn, .pm-only .tbtn, .pm-only a { color: inherit !important; }
.pm-only .muted, .pm-only .hint, .pm-only small { color: var(--ui-tx-2, currentColor); }
.pm-only .err, .pm-only .error { color: var(--ui-danger, #ef4444); }
/* Карточка/виджет, который видит только ПМ. Та же логика, что и у кнопок:
   красный фон = «клиент этого не видит», можно не проверять каждый раз. */
.pm-card {
  background: #2a0a0a !important;
  border: 1px solid #7a2e0b !important;
}
.pm-card .pm-tag, .pm-tag {
  display: inline-block; font-size: 9px; font-weight: 700; letter-spacing: .6px;
  text-transform: uppercase; color: #f87171; border: 1px solid #7a2e0b;
  border-radius: 999px; padding: 1px 6px; margin-left: 6px; vertical-align: middle;
}

/* ===== САЙДБАР МОДАЛКИ (любая модалка) ===== */
.modal-sidebar { display: flex; flex-direction: column; gap: 10px; margin-right: 12px; align-self: center; z-index: 5; }
@media (max-width:768px){ .modal-sidebar { flex-direction: row; margin-right: 0; margin-bottom: 10px; position: fixed; top: 10px; left: 50%; transform: translateX(-50%); z-index: 110; } }
.btn-load, .btn-copy, .btn-close, .btn-save, .btn-del {
  width: 44px; height: 44px; border-radius: 50%; background: #fff; color: #111; box-shadow: var(--ui-shadow-sm, 0 2px 6px -1px rgba(0,0,0,.25));
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: background .15s, transform .1s, color .15s;
}
.btn-load:hover, .btn-copy:hover { background: #e6f4ff; color: var(--ui-brand); }
.btn-close:hover, .btn-del:hover { background: #ffe6e6; color: var(--ui-danger); }
/* главная — синяя заливка с тёмным значком (как .btn, 28.09.2026); ховер светлее, не прозрачный */
.btn-save { background: var(--ui-btn1-bg, var(--ui-brand, #00a0ff)); color: var(--ui-btn1-text, #04121e); }
.btn-save:hover { background: var(--ui-btn1-bg, var(--ui-brand, #00a0ff)); filter: brightness(1.1); }
.btn-load:active, .btn-copy:active, .btn-close:active, .btn-save:active, .btn-del:active { transform: scale(.94); }
.btn-load svg, .btn-copy svg, .btn-close svg, .btn-save svg, .btn-del svg { width: 18px !important; height: 18px !important; opacity: 1 !important; color: inherit !important; }

/* ===== ШТОРКА — ОДИН КОМПОНЕНТ НА ВСЮ ПЛАТФОРМУ (27.09.2026, ADR-231) =====
   Любое окно поверх страницы — нижняя шторка: прижата к низу, верхняя кромка ровно на
   --ui-sheet-top от верха экрана, высота ФИКСИРОВАННАЯ (calc(100dvh - зазор); строка со
   100vh — для движков без dvh), поэтому окно не прыгает ни от содержимого, ни от вкладки.
   Шапка не скроллится (flex:none), скроллится только тело (flex:1; min-height:0), страница
   под шторкой заперта (правило html:has() ниже). Кнопки шапки — один ряд у правого края.
   Все числа — токены из /set → «Шторка» (THEME_DEFAULTS в server.js, вывод в /theme.css):
     --ui-sheet-top       зазор сверху (не меньше 56px: кнопка ☰ занимает экран до 54px);
     --ui-sheet-btn       размер кнопки шапки (он же зона тапа);
     --ui-sheet-btn-bw    толщина окантовки кнопки, --ui-sheet-btn-bc — её цвет;
     --ui-sheet-btn-bg    заливка кнопки;
     --ui-sheet-title-fs  кегль заголовка шапки;
     --ui-sheet-radius    скругление верхних углов (/set → «Карточки»).
   Два входа в ОДИН вид — своей оболочки (высота, прижатие, скругление, скролл) страницы
   шторке НЕ пишут:
   1) канон .mdl-back > .mdl-card > .mdl-handle + .mdl-head (> .mdl-acts) + .mdl-body —
      шторка и на ПК (колонкой по центру), и на телефоне (во всю ширину);
   2) классы-метки для старых окон со своей разметкой (.mbox, .modal, .pm-card, .fbox…):
      .sheet-wrap (подложка), .sheet-card (окно), .sheet-grab (ручка), .sheet-head (шапка),
      .sheet-acts (ряд кнопок), .sheet-body (единственный скролл). На ПК такие окна
      остаются диалогом по центру, на телефоне — та же шторка, что у канона. Оболочка у
      них объявлена с !important: у старых окон есть базовые правила по #id, и без него
      они перебивали бы шторку. Содержимое страница оформляет у себя, как раньше.
   Действия окна — в шапке, всегда в порядке КОРЗИНА — ДИСКЕТА — КРЕСТИК, роль .ibtn
   (ADR-063): цвет значка — /set#btns, квадрат, окантовка и заливка — /set#sheet.
   Правило и образец — /refs → «Модалка». */
.mdl-back { position: fixed; inset: 0; bottom: var(--ui-kb, 0px); z-index: 600; display: none; /* 03.10.2026: --ui-kb — клавиатура iOS, ставит /ui-keyboard.js */
  align-items: flex-end; justify-content: center; padding: 0; overflow: hidden;
  overscroll-behavior: contain; background: rgba(0,0,0,.6); }
.mdl-back.is-open { display: flex; }
/* Селектор ДВОЙНОЙ (.ui-card.mdl-card) намеренно: .ui-card объявлена ниже по файлу и при
   равной специфичности её padding:var(--ui-card-pad) перебивал здешний ноль — шапка и тело
   окна не доходили до краёв, окно выглядело «плавающим» (ERR-55, 15.09.2026). Свои отступы
   есть у .mdl-head и .mdl-body, карточке они не нужны. */
.ui-card.mdl-card, .mdl-card { position: relative; display: flex; flex-direction: column; box-sizing: border-box;
  width: 100%; max-width: 700px; min-width: 0; margin: 0; padding: 0; overflow: hidden;
  /* 03.10.2026: + env(safe-area-inset-top) — на iPhone верх шторки не заходит под чёлку/статус-бар (на ПК env = 0) */
  height: calc(var(--ui-sheet-h-vh) - var(--ui-kb, 0px)); height: calc(var(--ui-sheet-h) - var(--ui-kb, 0px));
  max-height: calc(var(--ui-sheet-h-vh) - var(--ui-kb, 0px)); max-height: calc(var(--ui-sheet-h) - var(--ui-kb, 0px));
  border-bottom: 0; border-radius: var(--ui-sheet-radius, 22px) var(--ui-sheet-radius, 22px) 0 0;
  transform: none; }
/* Шапка вне скролла: не sticky, а обычный не сжимающийся flex-элемент над .mdl-body —
   на рикошете Safari sticky-шапка убегала за верхний край (26.09.2026, «убегание шапок»). */
.mdl-head { position: relative; z-index: 2; flex: none;
  display: flex; flex-wrap: nowrap; align-items: center; gap: 10px; padding: 10px 14px;
  background: var(--ui-surface-2, #1a1a1a); border-bottom: 1px solid var(--ui-card-border, #262626); }
.mdl-head__ttl { flex: 1 1 auto; min-width: 0; }
.mdl-head__t { display: block; font-size: var(--ui-sheet-title-fs, 14px); font-weight: 600; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mdl-head__c { display: block; margin-top: 2px; font-size: 11.5px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--ui-tx3, #666);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mdl-head__c:empty { display: none; }
/* Ряд кнопок шапки — ОДНА строка у правого края окна на любой ширине: не переносится,
   прижат вправо и сам по себе (margin-left:auto), даже если заголовка в шапке нет. */
.mdl-acts, .sheet-acts { flex: none; display: flex; flex-wrap: nowrap; align-items: center;
  justify-content: flex-end; gap: 8px; margin-left: auto; }
/* Кнопка шапки: квадрат, окантовка и заливка — из /set → «Шторка». Хвост :not() повторяет
   селектор роли .ibtn из btnCss() (server.js) и делает правило специфичнее её геометрии и
   покраски — иначе !important роли перебивал бы токены шторки. Цвет значка и его ховер
   остаются за /set#btns. */
:is(.mdl-acts, .sheet-acts) .ibtn:not(.no-ui-btn) {
  min-width: var(--ui-sheet-btn, 44px) !important; min-height: var(--ui-sheet-btn, 44px) !important; }
:is(.mdl-acts, .sheet-acts) .ibtn:not(.no-ui-btn):not(.pm-only):not([hidden]):not(.btn-sm):not(.sm):not(.mbtn-sm):not(.s) {
  border-style: solid !important; border-width: var(--ui-sheet-btn-bw, 1px) !important;
  border-color: var(--ui-sheet-btn-bc, transparent) !important;
  background: var(--ui-sheet-btn-bg, transparent) !important; }
/* Главное действие ряда — дискета (.is-main): от соседей отличается ТОЛЬКО акцентным цветом
   значка и кантовки (толщина — та же --ui-sheet-btn-bw). Корзина в ряду красная СРАЗУ, а не
   только на ховере: синяя дискета (главное), красная корзина (опасное), серый крестик.
   27.09.2026: до этого правила были записаны как .mdl-acts .is-main — (0,2,0) — и молча
   проигрывали покраске роли .ibtn из btnCss() ((0,4,0)+, тоже !important): дискета не была
   ни синей, ни в кантовке. Хвост :not() повторяет селектор роли, поэтому правило специфичнее
   её (и правила токенов шторки выше) — исправлено в одном месте, без новых !important. */
:is(.mdl-acts, .sheet-acts) .ibtn.is-main:not(.no-ui-btn):not(.pm-only):not([hidden]):not(.btn-sm):not(.sm):not(.mbtn-sm):not(.s) {
  border-color: var(--ui-brand, #00a0ff) !important; }
:is(.mdl-acts, .sheet-acts) .ibtn.is-main:not(.no-ui-btn):not(.pm-only):not([hidden]) > svg { color: var(--ui-brand, #00a0ff) !important; }
:is(.mdl-acts, .sheet-acts) .ibtn:not(.no-ui-btn):not(.pm-only):not([hidden]) > svg.i-del { color: var(--ui-danger, #ef4444) !important; }
.mdl-body { flex: 1 1 auto; min-height: 0; padding: 14px; overflow-x: hidden; overflow-y: auto;
  overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
/* ПК: ряд действий окна крупнее роли на 50% — на телефоне размер уже подпирает
   зона тапа (--ui-sheet-btn), а на ПК значок в 15px у края шапки слишком мелкий.
   Это единственное отступление от ADR-063 здесь, и только множитель от токенов
   /set#btns: свои пиксели кнопкам всё так же не пишем. 27.09.2026: селекторы подняты
   до специфичности роли .ibtn из btnCss() (геометрия (0,7,0), значок (0,3,1)) — прежние
   .mdl-acts .ibtn проигрывали, и множитель не работал вовсе. */
@media (min-width: 769px) {
  :is(.mdl-acts, .sheet-acts) .ibtn:not(.no-ui-btn):not([hidden]):not(.btn-sm):not(.sm):not(.mbtn-sm):not(.s) {
    padding: calc(var(--ui-btni-pad, 4px) * 1.5) !important; }
  :is(.mdl-acts, .sheet-acts) .ibtn:not(.no-ui-btn):not([hidden]) > svg {
    width: calc(var(--ui-btni-ico, 15px) * 1.5) !important; height: calc(var(--ui-btni-ico, 15px) * 1.5) !important; }
}
/* Заголовок шапки любой шторки — один кегль на платформу: --ui-sheet-title-fs
   (/set → «Шторка»). Канон — .mdl-head__t, старые окна ставят заголовку класс .sheet-title.
   !important — потому что у старых заголовков кегль бывает инлайном в разметке. */
.sheet-title { font-size: var(--ui-sheet-title-fs, 14px) !important; }
/* Ручка шторки — только на телефоне: на ПК окно колонкой по центру и тянуть его не за что.
   Ручка — только знак «это шторка»: окно не тянется пальцем и не «плавает» (transform
   у окна не бывает ни в покое, ни посреди жеста). */
.mdl-handle, .sheet-grab { display: none; }
@media (max-width: 768px) {
  /* Селектор ДВОЙНОЙ, как у базового правила выше: одинарный .mdl-card проигрывал
     .ui-card.mdl-card по специфичности (18.09.2026, /access). */
  .ui-card.mdl-card, .mdl-card { max-width: none; }
  .mdl-handle { display: block; flex: none; width: 36px; height: 4px; border-radius: 2px;
    margin: 8px auto 0; background: var(--ui-grip, #4a4a4a); } /* 29.09.2026: ручка на --ui-grip */
  /* 29.09.2026 (/bugs, светлая тема): ручка лежит ПОВЕРХ шапки, а не отдельной полосой над ней.
     В потоке она оставляла 12px фона карточки (белого в светлой теме) над серой шапкой
     (--ui-surface-2) — выглядело как срезанный верх окна. */
  .mdl-card > .mdl-handle { position: absolute; top: 0; left: 50%; z-index: 3; margin: 8px 0 0 -18px; }
  .mdl-card > .mdl-handle + .mdl-head { padding-top: 20px; }
  .mdl-body { padding-bottom: calc(16px + env(safe-area-inset-bottom)); }
  html.kb-open .mdl-body { padding-bottom: 16px; } /* клавиатура уже над safe-area */

  /* --- Старые окна (классы-метки .sheet-*): на телефоне та же шторка, что у канона --- */
  .sheet-wrap { align-items: flex-end !important; justify-content: center !important;
    padding: 0 !important; overflow: hidden !important; overscroll-behavior: contain; }
  .sheet-card { box-sizing: border-box !important; width: 100% !important; max-width: none !important;
    min-width: 0 !important; margin: 0 !important; transform: none !important;
    height: var(--ui-sheet-h-vh) !important; height: var(--ui-sheet-h) !important;
    max-height: var(--ui-sheet-h-vh) !important; max-height: var(--ui-sheet-h) !important;
    display: flex !important; flex-direction: column !important; overflow: hidden !important;
    border: 1px solid var(--ui-card-border, #232323) !important; border-bottom: 0 !important;
    border-radius: var(--ui-sheet-radius, 22px) var(--ui-sheet-radius, 22px) 0 0 !important;
    padding: 0 var(--ui-modal-pad, 14px) !important;
    background: var(--ui-sheet-bg, #1c1c1e) !important;
    box-shadow: 0 -16px 40px -8px color-mix(in srgb, var(--ui-shadow-c, #000) 35%, transparent); /* 30.09.2026: уровень lg для шторки (Y вверх, /refs#shadows) */ }
  /* 20.10.2026 (#341): клавиатура iPhone (html.kb-open и --ui-kb ставит /ui-keyboard.js) — как у .mdl-back/.mdl-card:
     подложка поднимается над клавиатурой, окно ниже на её высоту и не уходит под неё. Без клавиатуры правило не действует. */
  html.kb-open .sheet-wrap { bottom: var(--ui-kb, 0px) !important; }
  html.kb-open .sheet-card {
    height: calc(var(--ui-sheet-h-vh) - var(--ui-kb, 0px)) !important; height: calc(var(--ui-sheet-h) - var(--ui-kb, 0px)) !important;
    max-height: calc(var(--ui-sheet-h-vh) - var(--ui-kb, 0px)) !important; max-height: calc(var(--ui-sheet-h) - var(--ui-kb, 0px)) !important; }
  .sheet-grab { display: block !important; flex: none; width: 36px; height: 4px; border-radius: 2px;
    margin: 8px auto 2px; background: var(--ui-grip, #4a4a4a); } /* 29.09.2026: ручка на --ui-grip */
  /* Шапка во всю ширину окна: поля окна (--ui-modal-pad) она перекрывает отрицательным
     отступом, ширина объявлена явно (ADR-064), клэмп max-width страницы её не режет. */
  .sheet-head { flex: none !important; position: relative !important; top: auto !important; z-index: 4;
    display: flex; flex-wrap: nowrap; align-items: center; gap: 10px;
    box-sizing: border-box !important; max-width: none !important;
    width: calc(100% + var(--ui-modal-pad, 14px) * 2) !important;
    margin: 0 calc(var(--ui-modal-pad, 14px) * -1) 12px !important;
    padding: 8px var(--ui-modal-pad, 14px) 10px !important;
    background: var(--ui-sheet-bg, #1c1c1e); border-bottom: 1px solid var(--ui-line-2, #1e1e1e); }
  /* Единственный скролл окна. Запас снизу — под круглую панель действий (.modal-sidebar),
     которую старые окна на телефоне прибивают к низу экрана. */
  .sheet-body { flex: 1 1 auto !important; min-height: 0 !important;
    overflow-x: hidden !important; overflow-y: auto !important;
    overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
    padding-bottom: calc(var(--ui-actions-h, 96px) + env(safe-area-inset-bottom)); }
  .sheet-body::-webkit-scrollbar { width: 0; }
}
/* Страница под открытой шторкой не скроллится и не сдвигается: html запирается, место
   полосы прокрутки остаётся за ней (scrollbar-gutter), рикошет iOS гасится
   overscroll-behavior. Открытость: канон — .mdl-back.is-open; старые окна — класс
   .open/.is-open, display:flex, выставленный скриптом инлайном (браузер пишет его в
   атрибут как «display: flex», поэтому ищем именно это, а не голое flex — иначе ловился бы
   align-items:flex-start закрытого окна), или окно, которое страница прячет атрибутом
   hidden (метка data-sheet-hidden: открыто, пока hidden нет). */
html:has(.mdl-back.is-open),
html:has(.sheet-wrap.open), html:has(.sheet-wrap.is-open), html:has(.sheet-wrap[style*="display: flex"]),
html:has(.sheet-wrap[data-sheet-hidden]:not([hidden])) {
  overflow: hidden; scrollbar-gutter: stable; overscroll-behavior: none; }

/* ===== ШТОРКА: ЖЕСТЫ, ТРИ ВЫСОТЫ, БОКОВАЯ ПАНЕЛЬ НА ПК (03.10.2026, #33, развитие ADR-231) =====
   Поведение (жест закрытия, пружина, data-snaps, одна шторка за раз) — /ui-dialogs.js, блок «ОБЩАЯ ШТОРКА».
   Здесь только вид.
   Телефон: data-snaps=".15,.5,.92" на .mdl-back (или .sheet-wrap) — три высоты; высоту ставит JS (height карточки),
   тело скроллится только на full (.is-full на карточке). Без атрибута шторка как раньше.
   ПК (≥769px — граница мобильного режима платформы, 768 включительно мобильный): боковая панель справа — ТОЛЬКО opt-in,
   атрибут data-drawer на .mdl-back или .sheet-wrap (ширина max(320px, min(440px, 40vw)), на всю высоту, скругление
   только слева, въезд справа, фон .25). Включать, только если содержимое помещается в 440px (без таблиц и min-width).
   Без атрибута окна на ПК такие же, как раньше. Класс .mdl-back--dlg — окно-диалог (uiInfo): не заменяет открытую шторку. */
.mdl-handle, .sheet-grab { touch-action: none; }
@media (max-width: 768px) {
  .mdl-back[data-snaps] .mdl-card:not(.is-full) .mdl-body,
  .sheet-wrap[data-snaps] .sheet-card:not(.is-full) .sheet-body { overflow-y: hidden !important; }
}
@media (min-width: 769px) {
  .mdl-back[data-drawer] { align-items: stretch; justify-content: flex-end; background: rgba(0,0,0,.25); }
  .mdl-back[data-drawer] > .mdl-card {
    width: max(320px, min(440px, 40vw)); flex: none;
    height: 100vh; height: calc(100dvh - var(--ui-kb, 0px)); max-height: none;
    border: 0; border-left: 1px solid var(--ui-card-border, #262626);
    border-radius: var(--ui-sheet-radius, 22px) 0 0 var(--ui-sheet-radius, 22px); }
  .mdl-back.is-open[data-drawer] > .mdl-card { animation: mdl-slide-in .3s cubic-bezier(.32,.72,0,1) both; }
  /* старое окно (.sheet-wrap): !important, как у его оболочки на телефоне — у окон базовые правила по #id */
  .sheet-wrap[data-drawer] { align-items: stretch !important; justify-content: flex-end !important; padding: 0 !important;
    background: rgba(0,0,0,.25) !important; overflow: hidden !important; }
  .sheet-wrap[data-drawer] > .sheet-card {
    box-sizing: border-box !important; width: max(320px, min(440px, 40vw)) !important; max-width: none !important; flex: none;
    height: 100vh !important; height: 100dvh !important; max-height: none !important; margin: 0 !important;
    border: 0 !important; border-left: 1px solid var(--ui-card-border, #262626) !important;
    border-radius: var(--ui-sheet-radius, 22px) 0 0 var(--ui-sheet-radius, 22px) !important; }
  .sheet-wrap[data-drawer].open > .sheet-card, .sheet-wrap[data-drawer].is-open > .sheet-card { animation: mdl-slide-in .3s cubic-bezier(.32,.72,0,1) both; }
  @keyframes mdl-slide-in { from { transform: translateX(100%); } to { transform: none; } }
}
/* Выезд панели при закрытии: страницы снимают is-open мгновенно, /ui-dialogs.js на 330 мс ставит .is-closing
   (окно видно по нему, класс страницы не трогаем — повторное открытие работает). */
@media (min-width: 769px) {
  .mdl-back[data-drawer].is-closing { display: flex; pointer-events: none; animation: mdl-fade-out .3s ease both; }
  .mdl-back[data-drawer].is-closing > .mdl-card { animation: mdl-slide-out .3s cubic-bezier(.32,.72,0,1) both; }
  .sheet-wrap[data-drawer].is-closing { display: flex !important; pointer-events: none; animation: mdl-fade-out .3s ease both; }
  .sheet-wrap[data-drawer].is-closing > .sheet-card { animation: mdl-slide-out .3s cubic-bezier(.32,.72,0,1) both; }
  @keyframes mdl-slide-out { from { transform: none; } to { transform: translateX(100%); } }
  @keyframes mdl-fade-out { from { opacity: 1; } to { opacity: 0; } }
}
/* Состояние высоты (ставит /ui-dialogs.js на карточку): .is-peek / .is-half / .is-full. На peek фиксированная нижняя
   панель «Сохранить/Закрыть» не должна перекрывать шапку шторки — прячем (лид: .modal-sidebar в .mdl-back; задача: .tc-actions). */
@media (max-width: 768px) {
  :is(.mdl-back, .sheet-wrap):has(> :is(.mdl-card, .sheet-card).is-peek) > .modal-sidebar,
  :is(.mdl-card, .sheet-card).is-peek .modal-sidebar,
  .sheet-card.is-peek .tc-actions { display: none !important; }
}
@media (min-width: 769px) and (prefers-reduced-motion: reduce) {
  .mdl-back[data-drawer].is-closing, .mdl-back[data-drawer].is-closing > .mdl-card,
  .sheet-wrap[data-drawer].is-closing, .sheet-wrap[data-drawer].is-closing > .sheet-card { animation: none; }
  .mdl-back.is-open[data-drawer] > .mdl-card, .sheet-wrap[data-drawer].open > .sheet-card, .sheet-wrap[data-drawer].is-open > .sheet-card { animation: none; }
}
/* 06.10.2026 (#247): шторка слева — справа меню платформы. Только ПК (на телефоне — нижняя шторка, как у всех).
   Как и правая, панель на всю высоту (--ui-sheet-top в правой не используется — повторяем). */
@media (min-width: 769px) {
  .mdl-back[data-drawer="left"] { justify-content: flex-start; }
  .mdl-back[data-drawer="left"] > .mdl-card {
    border-left: 0; border-right: 1px solid var(--ui-card-border, #262626);
    border-radius: 0 var(--ui-sheet-radius, 22px) var(--ui-sheet-radius, 22px) 0; }
  .mdl-back.is-open[data-drawer="left"] > .mdl-card { animation: mdl-slide-in-l .3s cubic-bezier(.32,.72,0,1) both; }
  .mdl-back[data-drawer="left"].is-closing > .mdl-card { animation: mdl-slide-out-l .3s cubic-bezier(.32,.72,0,1) both; }
  @keyframes mdl-slide-in-l { from { transform: translateX(-100%); } to { transform: none; } }
  @keyframes mdl-slide-out-l { from { transform: none; } to { transform: translateX(-100%); } }
}
@media (min-width: 769px) and (prefers-reduced-motion: reduce) {
  .mdl-back[data-drawer="left"].is-closing > .mdl-card, .mdl-back.is-open[data-drawer="left"] > .mdl-card { animation: none; }
}

/* #658: шторка справа — стандарт ПК. Модификатор .mdl-right на .mdl-back: форма на всю высоту справа (как карточка задачи
   на /tasks, ширина ~720px), на телефоне (≤768px) правил нет — нижний лист как раньше. */
@media (min-width: 769px) {
  .mdl-back.mdl-right { align-items: stretch; justify-content: flex-end; background: rgba(0,0,0,.25); }
  .mdl-back.mdl-right > .ui-card.mdl-card {
    width: min(720px, 100vw); max-width: 100vw; flex: none;
    top: 0; bottom: 0; right: 0;
    height: 100vh; height: calc(100dvh - var(--ui-kb, 0px)); max-height: none;
    border: 0; border-left: 1px solid var(--ui-card-border, #262626);
    border-radius: var(--ui-sheet-radius, 22px) 0 0 var(--ui-sheet-radius, 22px);
    box-shadow: -8px 0 32px rgba(0,0,0,.35); }
  .mdl-back.mdl-right > .ui-card.mdl-card > .mdl-body { overflow-y: auto; min-height: 0; }
  .mdl-back.mdl-right.is-open > .ui-card.mdl-card { animation: mdl-slide-in .3s cubic-bezier(.32,.72,0,1) both; }
}
@media (min-width: 769px) and (prefers-reduced-motion: reduce) {
  .mdl-back.mdl-right.is-open > .ui-card.mdl-card { animation: none; }
}

/* ===== «i» — ОБЩАЯ КНОПКА ИНФОРМАЦИИ (.ui-info) + окно uiInfo() — 27.09.2026, ADR-231 =====
   Вид взят с кнопки правил ввода в чатах (crm-chats.html, .composer .info-btn): круг, тонкая
   окантовка, курсивная «i» с засечками. Все числа и цвета — токены /set → «Информация (i)»:
   --ui-info-size (диаметр), --ui-info-bw/--ui-info-bc (окантовка), --ui-info-bg (заливка),
   --ui-info-tx/--ui-info-hover (символ и ховер), --ui-info-fs (кегль текста в окне).
   Зона нажатия не меньше --ui-tap (44px) — невидимым ::after, сам круг остаётся маленьким.
   В флекс-строке кнопка сама уходит к правому краю (margin-left:auto).
   Окно — uiInfo(title, html) из ui-dialogs.js: общая шторка .mdl-* с одним крестиком. */
.ui-info { position: relative; flex: none; display: inline-flex; align-items: center; justify-content: center;
  box-sizing: border-box; width: var(--ui-info-size, 26px); height: var(--ui-info-size, 26px);
  margin-left: auto; padding: 0; border-radius: 50%; cursor: pointer;
  border: var(--ui-info-bw, 1px) solid var(--ui-info-bc, var(--ui-card-border, #2a3038));
  background: var(--ui-info-bg, transparent); color: var(--ui-info-tx, var(--ui-tx-2, #8a909a));
  font: italic 600 calc(var(--ui-info-size, 26px) / 2) / 1 Georgia, serif;
  text-transform: none; letter-spacing: 0;   /* «i» внутри подписи капсом не должна стать «I» */
  -webkit-tap-highlight-color: transparent; }
.ui-info::after { content: ""; position: absolute; left: 50%; top: 50%;
  width: max(100%, var(--ui-tap, 44px)); height: max(100%, var(--ui-tap, 44px)); transform: translate(-50%, -50%); }
.ui-info:hover, .ui-info:focus-visible { color: var(--ui-info-hover, var(--ui-brand, #00a0ff));
  border-color: color-mix(in srgb, var(--ui-info-hover, var(--ui-brand, #00a0ff)) 40%, transparent); outline: none; }
.ui-info-body { font-size: var(--ui-info-fs, 13.5px); line-height: 1.55; color: var(--ui-tx, #d8d8d8); }
.ui-info-body h4 { margin: 0 0 6px; font-size: 1em; font-weight: 600; color: var(--ui-tx, #e8e8e8); }
.ui-info-body p { margin: 0 0 14px; }
.ui-info-body code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .92em; color: var(--ui-tx-2, #8b8b8b); }
.ui-info-body a { color: var(--ui-brand, #00a0ff); text-decoration: none; }

/* ===== СПИСОК НА МОБИЛЕ (.mc-*) — 18.09.2026, первый — /access =====
   Страница-список на ПК — таблица, на телефоне (≤768px) — карточки: таблица на 10+
   колонок на 390px не читается. Карточка: ряд 1 — номер · название · бейдж статуса · ⋮,
   ряд 2 — главное значение (логин с копированием / комментарий) и справа срок/дата.
   Тап по карточке — открыть окно (.mdl-*), ⋮ — меню строки (uiRowMenu). Кнопкам внутри
   — класс no-ui-btn, их вид здесь. Правило и живой образец — /refs → «Список на мобиле». */
.mc-list { display: flex; flex-direction: column; gap: 8px; }
.mc { display: block; min-width: 0; padding: 12px; cursor: pointer;
  background: var(--ui-surface, #141414); border: 1px solid var(--ui-card-border, #262626);
  border-radius: var(--ui-card-radius, 12px); -webkit-tap-highlight-color: transparent; }
.mc:active { background: var(--ui-surface-2, #1a1a1a); }
.mc-top { display: flex; align-items: center; gap: 8px; min-width: 0; }
.mc-n { flex: 0 0 auto; font-size: 12px; font-weight: 600; color: var(--ui-id, #fbbf24); font-variant-numeric: tabular-nums; }
.mc-t { flex: 1 1 auto; min-width: 0; font-size: 15px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mc-m { flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  min-width: var(--ui-tap, 44px); min-height: 32px; margin: -6px -8px -6px 0; padding: 0;
  background: transparent; border: 0; color: var(--ui-tx3, #666); cursor: pointer; }
.mc-m svg { width: 18px; height: 18px; }
.mc-sub { display: flex; align-items: center; gap: 6px; min-width: 0; margin-top: 6px;
  font-size: 12.5px; color: var(--ui-tx-2, #8b8b8b); }
.mc-sub:empty { display: none; }
.mc-g { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mc-r { flex: 0 0 auto; margin-left: auto; }
.mc-cp { flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; margin: -6px 0 -6px -6px; padding: 0;
  background: transparent; border: 0; color: var(--ui-tx3, #666); cursor: pointer; }
.mc-cp svg { width: 15px; height: 15px; }
.mc-empty { padding: 26px 0; text-align: center; font-size: 13px; color: var(--ui-tx3, #666); }

/* ===== ИКОНКА КАЛЕНДАРЯ — единая на весь портал =====
   Прозрачность — через переменную --ui-ico-opacity, как у остальных иконок портала.
   Доп. filter/invert здесь не нужен — он давал двойную инверсию (иконка снова
   становилась чёрной). Сам значок ниже (блок «Lucide вместо браузерных») нарисован
   маской и красится --ui-ico, то есть уже следует теме.
   19.09.2026 (ADR-216): отсюда убран `color-scheme: dark !important`. Он прибивал
   тёмную схему нативным контролам НА ВСЕХ страницах, и в светлой теме выпадающий
   календарь оставался чёрным. Свойство наследуемое — значение приходит из :root,
   где его задаёт themeVars(): dark или light по реальной теме. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
  opacity: var(--ui-ico-opacity) !important;
  cursor: pointer;
  transition: opacity .15s;
}
input[type="date"]:hover::-webkit-calendar-picker-indicator,
input[type="datetime-local"]:hover::-webkit-calendar-picker-indicator {
  opacity: 1 !important;
}

/* ===== ПОЛЕ ДАТЫ/ВРЕМЕНИ НА ВСЮ ШИРИНУ (.ui-date) =====
   <input type="datetime-local" class="ui-date">  (и date/time/month)
   iOS Safari игнорирует width:100% у нативных date/time и берёт ширину по
   содержимому — поле вылезает за край модалки на айфоне. Лечится только
   appearance:none + min-width:0. Цвет, рамка, радиус, паддинг, шрифт — НЕ здесь,
   их даёт тема из /set (inpCss), инлайн-стили полям дат не писать. */
input.ui-date {
  -webkit-appearance: none; appearance: none;
  display: block; box-sizing: border-box;
  width: 100%; max-width: 100%; min-width: 0; margin: 0;
  text-align: left;
}
input.ui-date::-webkit-date-and-time-value { text-align: left; margin: 0; }


/* ===== ПОКАЗАННЫЙ ПАРОЛЬ — иконка глаза красная, пока раскрыт ===== */
.i-show.pw-open, .i-hide.pw-open {
  color: var(--ui-danger) !important;
  opacity: 1;
}

/* --- скругление кнопок, настраивается в /set --- */
.btn, .btn-sm, button.btn, .btn-primary, .btn-cancel, .btn-danger { border-radius: var(--ui-radius, 8px) !important; }

/* --- единая карточка платформы, значения из /set --- */
.ui-page { max-width: 1360px; margin: 0 auto; padding: 26px var(--ui-page-pad, 44px) 60px; }
.ui-card {
  background: var(--ui-card-bg, #141414);
  border: 1px solid var(--ui-card-border, #262626);
  border-radius: var(--ui-card-radius, 12px);
  padding: var(--ui-card-pad, 20px);
}
.ui-grid { display: grid; gap: var(--ui-gap, 22px); align-items: start; }
.ui-grid.auto { grid-template-columns: repeat(auto-fill, minmax(310px, 1fr)); }
.ui-stack { display: flex; flex-direction: column; gap: var(--ui-gap, 22px); }

/* --- сетка виджетов 12 колонок (как в Tilda), тянется за край — /wresize.js, 11.09.2026 ---
   Ширина виджета — число колонок: --span (выставляет wresize.js из localStorage),
   иначе --def из разметки. Каждый виджет — контейнер для @container-правил: содержимое
   перестраивается под СВОЮ ширину, а не под ширину экрана. На ≤900px сетка из 2 колонок,
   ширину задаёт --mspan (1 или 2), перетаскивание выключено.
   02.10.2026 (#170, этап 1б): на /app /wresize.js больше не подключается — плитки .dash-g.w12 лежат внутри
   .ui-glayout (display:contents, см. ниже), ширину и порядок ведёт /ui-grid-layout.js. Класс .w12 остаётся:
   от него зависят container-типы плиток и cqi-правила в dash.js. Других потребителей .w12 нет. */
.w12 { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--w12-gap, var(--ui-w12-gap, 16px)); align-items: stretch; }
/* --w12-gap — локальная перебивка страницы (если понадобится), --ui-w12-gap — из /set
   → «Карточки и сетка» → «Колонки», 11.09.2026. */
.w12 > [data-w] { grid-column: span var(--span, var(--def, 12)); position: relative; min-width: 0; container-type: inline-size; }
@media (max-width: 900px) {
  .w12 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .w12 > [data-w] { grid-column: span var(--mspan, 2); }
}

/* ===== РАСКЛАДКА ВИДЖЕТОВ (.ui-glayout) — /ui-grid-layout.js (задача #170, этапы 1 и 1б) =====
   Контейнер — сетка из 12 колонок; виджет — элемент с data-widget-key (любой глубины), ширину
   (grid-column: span N) и порядок (order) ставит модуль инлайном: они хранятся на сервере, у человека свои. Сам по себе класс
   выглядит как обычный столбик из виджетов на всю ширину. Отступы между виджетами — только gap
   (--ui-gl-gap), свои margin-bottom виджетов гасятся. Пустой виджет (ещё не отрисован) места не занимает.
   ≤768px (мобильный брейкпоинт платформы) — одна колонка, ширину перебивает !important, режим настройки
   выключен; скрытые виджеты остаются скрытыми. Отдельный класс: .w12 — только контейнерные размеры плиток. */
.ui-glayout { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--ui-gl-gap, 22px); position: relative; }
.ui-glayout [data-widget-key] { grid-column: span 12; min-width: 0; margin-bottom: 0 !important; }
/* 03.10.2026 (#170, ADR-311): каждый виджет сетки — контейнер для @container-правил самого виджета (ширина берётся
   из дорожки сетки minmax(0,1fr), от содержимого не зависит, поэтому inline-size не схлопывает). */
.ui-glayout [data-widget-key] { container-type: inline-size; }
.ui-glayout [data-widget-key]:empty { display: none; }
.ui-glayout [data-widget-key][hidden] { display: none !important; }
/* Виджет может лежать глубже прямого ребёнка (плитки, которые рисуют скрипты страницы внутрь своих корней):
   порядок задаёт CSS order, а промежуточные обёртки не создают бокса — плитки становятся ячейками одной сетки.
   Перечень обёрток — по странице; ключ у них не ставится. Всё лишнее внутри корня (сообщение об ошибке) — на всю ширину. */
.ui-glayout .w12, .ui-glayout .dash-g, .ui-glayout #dash, .ui-glayout #dashweek, .ui-glayout #dashtop { display: contents; }
.ui-glayout #dash > :not(.dash-g), .ui-glayout #dashweek > :not(.dash-g), .ui-glayout #dashtop > :not(.dash-g) { grid-column: 1 / -1; }
/* 03.10.2026 (#170, ADR-311): отступ между виджетами, настроенный человеком в режиме раскладки, — переменная --ui-gl-gap-d
   на контейнере (ставит модуль, хранится в localStorage 'gl-gap:'+page). Только ПК: на ≤768px правило не действует,
   там остаётся gap из --ui-gl-gap / 22px, как было. */
@media (min-width: 769px) {
  .ui-glayout { gap: var(--ui-gl-gap-d, var(--ui-gl-gap, 22px)); }
}
@media (max-width: 768px) {
  .ui-glayout { grid-template-columns: minmax(0, 1fr); }
  .ui-glayout [data-widget-key] { grid-column: 1 / -1; }   /* 15.10.2026: без !important — ширину больше не пишет inline (data-span, см. конец файла) */
}
/* режим «Настроить раскладку» (класс ставит модуль; в обычном виде ничего из ниже в DOM нет) */
.ui-glayout.is-editing [data-widget-key] {
  position: relative;
  outline: 1px dashed color-mix(in srgb, var(--ui-brand, #00a0ff) 55%, transparent);
  outline-offset: 4px; border-radius: var(--ui-card-radius, 12px);
}
.ui-gl-ctl {
  position: absolute; top: 8px; right: 50px; z-index: 6; display: flex; gap: 4px; padding: 3px;
  background: var(--ui-card-bg, #141414); border: 1px solid var(--ui-card-border, #262626);
  border-radius: var(--ui-radius, 8px); box-shadow: var(--ui-shadow-sm, 0 2px 6px -1px rgba(0, 0, 0, .25));
}
.ui-gl-ctl .ibtn { min-width: var(--ui-tap-sm, 30px); min-height: var(--ui-tap-sm, 30px); }
.ui-gl-ico { width: 16px; height: 16px; flex: 0 0 auto; vertical-align: -3px; }
.ui-gl-drag { cursor: grab; touch-action: none; }
.ui-gl-rs {
  position: absolute; right: -6px; bottom: -6px; width: 20px; height: 20px; z-index: 6; cursor: ew-resize;
  touch-action: none; opacity: 0; transition: opacity .15s;
  border-right: 3px solid var(--ui-brand, #00a0ff); border-bottom: 3px solid var(--ui-brand, #00a0ff);
  border-radius: 0 0 8px 0;
}
.ui-glayout.is-editing [data-widget-key]:hover > .ui-gl-rs, .ui-gl-rs.is-on { opacity: 1; }
.ui-gl-badge {
  position: absolute; right: 14px; bottom: 14px; z-index: 6; display: none; padding: 2px 8px; border-radius: 999px;
  background: var(--ui-brand, #00a0ff); color: var(--ui-btn1-text, #04121e); font-size: 11px; font-weight: 600;
  line-height: 16px; white-space: nowrap; pointer-events: none;
}
.ui-glayout .is-resizing > .ui-gl-badge { display: block; }
.ui-glayout.is-editing .is-drag {
  position: absolute; z-index: 60; margin: 0; opacity: .92; pointer-events: none;
  grid-column: auto; width: var(--gl-w, auto); left: var(--gl-x, 0); top: var(--gl-y, 0);   /* координаты ставит модуль переменными, не inline-свойствами */
  box-shadow: var(--ui-shadow-lg, 0 16px 40px -8px rgba(0, 0, 0, .35));
}
.ui-gl-ph {
  grid-column: span 12; min-width: 0; min-height: var(--gl-h, 0px);
  border: 2px dashed var(--ui-brand, #00a0ff); border-radius: var(--ui-card-radius, 12px);
  background: color-mix(in srgb, var(--ui-brand, #00a0ff) 8%, transparent);
}
.ui-gl-shield { position: fixed; inset: 0; z-index: 9999; }
.ui-gl-shield[data-cur="grabbing"] { cursor: grabbing; }
.ui-gl-shield[data-cur="ew-resize"] { cursor: ew-resize; }
body.ui-gl-noselect { user-select: none; -webkit-user-select: none; }
/* панель над сеткой: подсказка, состояние сохранения, «Сбросить», список скрытых */
.ui-gl-panel {
  margin-bottom: 18px; padding: 12px 16px; display: flex; flex-direction: column; gap: 10px;
  background: var(--ui-card-bg, #141414); border: 1px solid var(--ui-card-border, #262626);
  border-radius: var(--ui-card-radius, 12px);
}
.ui-gl-panel-row, .ui-gl-hidden { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.ui-gl-hint { flex: 1 1 260px; min-width: 0; font-size: 13px; color: var(--ui-tx-2, #8a8a93); }
.ui-gl-state { font-size: 12px; color: var(--ui-tx-2, #8a8a93); }
/* ползунок «Отступ между виджетами» (03.10.2026, #170) */
.ui-gl-gaprow { display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--ui-tx-2, #8a8a93); }
.ui-gl-gaprow input[type=range] { flex: 0 1 220px; width: 220px; min-width: 80px; margin: 0; accent-color: var(--ui-brand, #00a0ff); }
.ui-gl-gapval { min-width: 38px; font-variant-numeric: tabular-nums; color: var(--ui-tx, #e8e8e8); }
.ui-gl-none { font-size: 12.5px; color: var(--ui-tx-2, #8a8a93); }
.ui-gl-toggle { width: auto; }
.ui-gl-toggle.is-on { border-color: var(--ui-brand, #00a0ff); }

/* ===== ОТРЕНДЕРЕННЫЙ MARKDOWN (.ui-md) — пара к /md.js, 09.09.2026 =====
   Вешать на контейнер, в который положили результат mdToHtml(). Смысл класса —
   вернуть теги, прибитые глобальным `* { margin:0 }` на страницах платформы:
   без него h2 и p слипаются в кашу и рендер выглядит хуже сырого markdown.
   Сырой markdown показывается БЕЗ этого класса, в <pre> с моноширинным шрифтом. */
/* 29.09.2026: светлая тема. Токена --ui-tx-1 на платформе нет, и в светлой теме текст
   оставался #ccc на белом. Теперь «основной текст чуть тише»: 87% --ui-tx на фоне
   страницы — в тёмной это #cbcbcb (≈ прежний #ccc), в светлой тёмно-синий. */
.ui-md { font-size: 13.5px; line-height: 1.65;
  color: var(--ui-tx-1, color-mix(in srgb, var(--ui-tx, #e8e8e8) 87%, var(--ui-bg, #0a0a0a))); }
.ui-md > *:first-child { margin-top: 0; }
.ui-md h1, .ui-md h2, .ui-md h3, .ui-md h4, .ui-md h5, .ui-md h6 {
  margin: 18px 0 8px; line-height: 1.3; color: var(--ui-tx, #fff); font-weight: 600;
}
.ui-md h1 { font-size: 19px; }
.ui-md h2 { font-size: 16px; }
.ui-md h3 { font-size: 14.5px; }
.ui-md h4, .ui-md h5, .ui-md h6 { font-size: 13.5px; color: var(--ui-tx-2, #9a9a9a); }
.ui-md p { margin: 0 0 10px; }
.ui-md ul, .ui-md ol { margin: 0 0 10px; padding-left: 22px; }
.ui-md li { margin: 3px 0; }
.ui-md a { color: var(--ui-brand, #00a0ff); }
.ui-md strong { color: var(--ui-tx, #fff); }
/* цвет кода — акцент, разбавленный цветом текста: в тёмной ≈ прежний #7cc4ff, в светлой тёмно-синий (29.09.2026) */
.ui-md code {
  font-family: ui-monospace, monospace; font-size: 12.5px;
  background: var(--ui-surface-2, #1a1a1a); border: 1px solid var(--ui-line, #262626);
  border-radius: 4px; padding: 1px 5px; color: color-mix(in srgb, var(--ui-brand, #00a0ff) 55%, var(--ui-tx, #fff));
}
.ui-md pre {
  margin: 0 0 12px; padding: 12px 14px; overflow-x: auto; max-width: 100%;
  background: var(--ui-surface-2, #1a1a1a); border: 1px solid var(--ui-line, #262626);
  border-radius: 8px;
}
.ui-md pre code { background: none; border: 0; padding: 0; color: inherit; }
.ui-md blockquote {
  margin: 0 0 12px; padding: 2px 0 2px 12px;
  border-left: 2px solid var(--ui-line, #262626); color: var(--ui-tx-2, #9a9a9a);
}
.ui-md hr { border: 0; border-top: 1px solid var(--ui-line, #262626); margin: 16px 0; }

/* Сырой исходник (режим «<>»): показываем как есть, переносим длинные строки */
.ui-md-raw {
  white-space: pre-wrap; word-break: break-word;
  font-family: ui-monospace, monospace; font-size: 12.5px; line-height: 1.55;
  color: var(--ui-tx-2, #9a9a9a); margin: 0;
}

/* ===== ЧИП СОСТОЯНИЯ (.ui-chip) — единый источник =====
   Статус записи словом: «На связи», «Ошибка», «Черновик», «Работает».
   Заведён 06.09.2026: страница каналов писала <span class="chip ok">, а класса .chip
   на платформе нет НИ в ui.css, НИ в /theme.css — статус рисовался обычным текстом,
   и «Ошибка» ничем не отличалась от «На связи». Имя НЕ .chip намеренно, по той же
   причине, что .ui-form-row не назван .row: .chip уже занят локально под свои задачи
   (чип значения в /company, /contacts, /team; чип метаданных на /agents), и общее
   правило с этим именем перекрасило бы их.
   Цвета — только токенами (ADR-142): компонент обязан работать в обеих темах.
   Полупрозрачные подложки не токенизируются намеренно — они одинаково читаются
   на тёмном и светлом фоне (тот же приём, что у .ui-tile.is-ok / .is-bad ниже).
   Точка слева рисуется псевдоэлементом: цвет наследуется от состояния, отдельного
   узла в разметке не нужно.
   09.09.2026 добавлены два модификатора под чип-МЕТКУ (не состояние):
   .has-ico убирает точку и пускает внутрь <svg> из спрайта — иконка говорит, о чём
   метка (сервер, глобус), точка бы говорила «состояние», а его тут нет;
   .is-brand — брендовый синий, «наше / своё». Зелёный (.is-ok) для меток НЕ брать:
   он закреплён за «работает / на связи», и метка происхождения отберёт у цвета смысл.
   Образец — чип источника скилла на /skills. */
.ui-chip {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; flex: 0 0 auto;
  padding: 4px 10px; border-radius: var(--ui-chip-radius, 16px);
  font-size: 11px; font-weight: 600; line-height: 1.3;
  background: var(--ui-surface-2, #1a1a1a);
  border: 1px solid var(--ui-line, #262626);
  color: var(--ui-tx-2, #8b8b8b);
}
.ui-chip::before { content: ""; flex: 0 0 6px; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.ui-chip.has-ico::before { content: none; }
.ui-chip.has-ico > svg { flex: 0 0 12px; width: 12px; height: 12px; stroke: currentColor; fill: none; }
.ui-chip.is-brand  { color: var(--ui-brand, #00a0ff); background: rgba(0,160,255,.07); border-color: rgba(0,160,255,.28); }
.ui-chip.is-ok     { color: var(--ui-ok, #4ade80);     background: rgba(74,222,128,.06);  border-color: rgba(74,222,128,.26); }
.ui-chip.is-warn   { color: var(--ui-warn, #fbbf24);   background: rgba(251,191,36,.06);  border-color: rgba(251,191,36,.26); }
.ui-chip.is-danger { color: var(--ui-danger, #f87171); background: rgba(248,113,113,.06); border-color: rgba(248,113,113,.28); }
.ui-chip.is-violet { color: var(--ui-violet-soft-tx); background: var(--ui-violet-soft); border-color: var(--ui-violet-soft-line); }   /* метка-категория (УПД и т.п.), 20.10.2026 */
.ui-chip[hidden] { display: none !important; }   /* .ui-chip объявляет display — без этого атрибут hidden чип не прячет */

/* ===== МЕТКА СТАТУСА (.ui-st) — цвет из справочника (01.10.2026, ADR-285) =====
   Статус/стадия в списках, канбане, карточках: «лёгкий фон» от ОДНОГО цвета справочника.
   Цвет приходит только переменной: style="--c:#rrggbb" — строку собирает uiColorVar(hex)
   из /ui-color.js (разобранный hex, а не строка из базы как есть). Формула — здесь:
     фон    color-mix(--c 12%, --ui-surface)
     рамка  color-mix(--c 32%, --ui-surface)
     текст  color-mix(--c 50%, --ui-tx)
   Текст 50%, а не 60%: при 60% пять из 16 базовых цветов (зелёный, жёлтый, лайм, горчичный,
   бирюзовый) в светлой теме давали 3.6–4.0:1 — ниже AA 4.5:1; при 50% все 16 проходят в обеих
   темах. Те же доли — константы ST_BG/ST_TX в /ui-color.js (окно считает по ним контраст),
   менять парой.
   .is-solid — сплошная заливка цветом статуса, текст --on (uiColorVar(hex, true) пишет его
   от uiColorOnTx). Только для степпера карточки и активного чипа фильтра.
   Геометрия обёрнута в :where() — нулевая специфичность: страница со своим классом
   (.col-head, .st, .badge) задаёт размеры сама, а цвета остаются общими. */
:where(.ui-st) { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; box-sizing: border-box;
  padding: 2px 8px; border-radius: 999px; border: 1px solid transparent;
  font-size: 11.5px; font-weight: 500; line-height: 1.45; white-space: nowrap; }
.ui-st { --c: var(--ui-muted, #6b7280);
  background: color-mix(in srgb, var(--c) 12%, var(--ui-surface, #141414));
  border-color: color-mix(in srgb, var(--c) 32%, var(--ui-surface, #141414));
  color: color-mix(in srgb, var(--c) 50%, var(--ui-tx, #e8e8e8)); }
.ui-st.is-solid { background: var(--c); border-color: var(--c); color: var(--on, #ffffff); }

/* ===== ОКНО ВЫБОРА ЦВЕТА (uiColorPick из /ui-color.js) — 01.10.2026, ADR-285 =====
   ПК — поповер .uic-pop у кнопки; телефон — общая шторка .mdl-back/.mdl-card (оболочку не
   пишем, здесь только содержимое и подъём слоя: окно открывают и из модалок, а там z-index
   до 99999). Плитки цвета — 44px (зона тапа). Предпросмотр тем — та же .ui-st, у блока
   переопределены --ui-surface/--ui-tx на значения нужной темы. */
.uic-back.mdl-back { z-index: 100002; }
.uic-pop { position: fixed; z-index: 100002; width: 386px; max-width: calc(100vw - 16px); box-sizing: border-box;
  max-height: calc(100vh - 16px); overflow-y: auto; padding: 14px !important; margin: 0;
  box-shadow: var(--ui-shadow-md, 0 6px 18px -2px rgba(0,0,0,.30)); }
.uic-ttl { font-size: var(--ui-sheet-title-fs, 14px); font-weight: 600; margin: 0 0 10px; color: var(--ui-tx, #e8e8e8); }
.uic-h { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--ui-tx-3, #6a6a6a); margin: 12px 0 6px; }
.uic-grid { display: grid; grid-template-columns: repeat(8, 44px); gap: 0; justify-content: space-between; }
.uic-sw { width: 44px; height: 44px; padding: 0; margin: 0; border: 0; background: transparent; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; position: relative; }
.uic-sw::before { content: ""; position: absolute; inset: 7px; border-radius: 50%; background: var(--c);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ui-tx, #e8e8e8) 18%, transparent); }
.uic-sw > svg { position: relative; width: 16px; height: 16px; color: #fff; opacity: 0; filter: drop-shadow(0 0 1px rgba(0,0,0,.6)); }
.uic-sw.on > svg { opacity: 1; }
.uic-sw.on::before { box-shadow: 0 0 0 2px var(--ui-surface, #141414), 0 0 0 4px var(--c); }
.uic-sw:focus-visible { outline: 2px solid var(--ui-brand, #00a0ff); outline-offset: -2px; border-radius: 50%; }
.uic-row { display: flex; align-items: center; gap: 8px; margin-top: 12px; }
.uic-row > .uic-inp { flex: 1 1 auto; min-width: 0; width: auto; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.uic-eye { flex: none; position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: var(--ui-tap, 44px); height: var(--ui-tap, 44px); border: 1px solid var(--ui-line, #262626);
  border-radius: var(--ui-radius, 8px); color: var(--ui-tx-2, #8b8b8b); cursor: pointer; box-sizing: border-box; }
.uic-eye:hover { color: var(--ui-brand, #00a0ff); }
.uic-eye > svg { width: 18px; height: 18px; pointer-events: none; }
.uic-eye > input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; border: 0; padding: 0; }
.uic-conv { display: flex; align-items: center; gap: 8px; margin-top: 6px; font-size: 12px; color: var(--ui-tx-2, #8b8b8b);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; min-height: 18px; }
.uic-conv > i { flex: none; width: 12px; height: 12px; border-radius: 50%; background: var(--c); }
.uic-conv.is-err { color: var(--ui-danger, #f87171); font-family: inherit; }
.uic-warn { display: flex; gap: 8px; align-items: flex-start; margin-top: 8px; padding: 8px 10px; font-size: 12.5px; line-height: 1.45;
  border-radius: var(--ui-radius, 8px); color: color-mix(in srgb, var(--ui-warn, #fbbf24) 55%, var(--ui-tx, #e8e8e8));
  background: color-mix(in srgb, var(--ui-warn, #fbbf24) 10%, var(--ui-surface, #141414));
  border: 1px solid color-mix(in srgb, var(--ui-warn, #fbbf24) 30%, var(--ui-surface, #141414)); }
.uic-warn[hidden] { display: none; }
.uic-warn > svg { flex: none; width: 15px; height: 15px; margin-top: 1px; }
.uic-pv { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.uic-pvb { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 8px; min-width: 0;
  border-radius: var(--ui-radius, 8px); background: var(--ui-surface); color: var(--ui-tx);
  border: 1px solid color-mix(in srgb, var(--ui-tx) 12%, transparent); }
.uic-pvt { flex: 1 0 100%; font-size: 11px; color: color-mix(in srgb, var(--ui-tx) 55%, var(--ui-surface)); }
.uic-pvb > .ui-st { overflow: hidden; text-overflow: ellipsis; }
.uic-ct { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.uic-ct th, .uic-ct td { padding: 5px 4px; text-align: left; border-bottom: 1px solid var(--ui-line-2, #1e1e1e); font-weight: 400; }
.uic-ct thead th { font-size: 11px; color: var(--ui-tx-3, #6a6a6a); }
.uic-ct tbody th { color: var(--ui-tx-2, #8b8b8b); }
.uic-ct td { white-space: nowrap; font-variant-numeric: tabular-nums; }
.uic-ct td > svg { width: 13px; height: 13px; vertical-align: -2px; }
.uic-ct td.is-ok { color: var(--ui-ok, #4ade80); }
.uic-ct td.is-bad { color: var(--ui-danger, #f87171); }
.uic-note { font-size: 11.5px; line-height: 1.45; color: var(--ui-tx-3, #6a6a6a); margin-top: 6px; }
.uic-foot { display: flex; align-items: center; gap: 8px; margin-top: 14px; }
.uic-sp { flex: 1 1 auto; }
@media (max-width: 768px) {
  .uic-grid { grid-template-columns: repeat(8, minmax(0, 44px)); }
  .uic-pv { grid-template-columns: 1fr; }
}
/* Кнопка-кружок «цвет» в таблице справочника (/refs, refs-status.js): зона тапа 30px,
   кружок — цвет значения; нажатие открывает uiColorPick. */
.ui-colorbtn { flex: none; width: var(--ui-tap-sm, 30px); height: var(--ui-tap-sm, 30px); padding: 0; margin: 0; border: 0;
  background: transparent; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.ui-colorbtn::before { content: ""; width: 18px; height: 18px; border-radius: 50%; background: var(--c, var(--ui-muted, #6b7280));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ui-tx, #e8e8e8) 22%, transparent); }
.ui-colorbtn:hover::before, .ui-colorbtn:focus-visible::before { box-shadow: 0 0 0 2px var(--ui-surface, #141414), 0 0 0 3px var(--ui-brand, #00a0ff); }
.ui-colorbtn[disabled] { cursor: default; }
.ui-colorbtn[disabled]:hover::before { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ui-tx, #e8e8e8) 22%, transparent); }

/* ===== ШАПКА СТРАНИЦЫ (.ph) — ЕДИНСТВЕННЫЙ ИСТОЧНИК (ADR-147) =====
   Эталон — «Медкарта / Профиль». Своей вёрстки шапки на страницах больше нет:
   разметку либо пишут классами .ph* (см. ниже), либо её собирает из голого <h1>
   нормализатор /page-header.js. Проверяет соблюдение tools/check-page-headers.mjs.

   Анатомия — ровно три строки, всегда в этом порядке:
     .ph-row    заголовок + версия слева, обновить/бургер справа (одна строка);
     .ph-s      подзаголовок, ОДНА строка, режется многоточием;
     .ph-tools  кнопки действий страницы (необязательная).

   Чего в шапке нет и быть не может: иконки или эмодзи слева от H1, полосы-
   разделителя, капс-киккера над заголовком, ссылки «← AI-платформа» (навигация
   живёт в бургере), счётчика внутри H1 (он идёт в подзаголовок словами).

   !important здесь — по той же причине, что в btnCss(): у полусотни страниц
   есть свой `header{...}` и свой `h1{...}`, и без этого единый вид не приедет
   туда, где уже написана локальная вёрстка. Ради этого всё и затевалось. */
/* 24.09.2026 (ERR-164, /bugs): sticky теперь БАЗОВОЕ свойство .ph, а не надстройка
   над body.cf-pburger. Раньше это зависело от класса, который cab-sidebar.js ставит
   по жёсткому списку путей — и такая зависимость уже один раз тихо ломала шапку
   (переезд /habits → /habits/app увёл страницу мимо условия, сайдбар/класс/sticky
   пропали разом). Портал на мобиле сам глушит sticky через
   header.ph{position:static !important} в mhead.js (там своя, JS-управляемая
   свёрнутая шапка) — эта страница остаётся нетронутой этой правкой. */
.ph {
  display: block !important;
  max-width: 1360px; margin: 0 auto;
  padding: 26px var(--ui-page-pad, 44px) 0 !important;
  border: 0 !important;
  position: sticky; top: 0; z-index: 40;
  background: var(--ui-bg, #0a0a0a) !important; padding-bottom: 12px !important;
}
/* шапка, вставленная ВНУТРЬ уже отбитого контейнера (.wrap/.container/.ui-page):
   свои поля не добавляет, иначе к отступу страницы приедет второй */
.ph.ph-inner { max-width: none; margin: 0; padding: 0 !important; }

/* Ряд: слева заголовок, справа блок-виджет из кнопок и версии.
   align-items:flex-start — кнопки держатся у ПЕРВОЙ строки заголовка, даже когда
   он переносится на три. */
.ph-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }

/* Заголовок занимает всё оставшееся место и переносится на столько строк, сколько
   нужно. Ни nowrap, ни многоточия, ни line-clamp: название раздела — часть продукта,
   сокращать и обрезать его нельзя (решение Константина, 30.08.2026). */
.ph-ttl { flex: 1 1 auto; min-width: 0; }
.ph-ttl > h1, .ph-t {
  display: block !important;
  font-size: 34px; font-weight: 800; letter-spacing: -.02em; line-height: 1.2;
  margin: 0 !important; padding: 0 !important;
  color: var(--ui-tx, #fff);
  white-space: normal; overflow-wrap: anywhere; text-wrap: balance;
}
/* значок в заголовке не рисуем нигде — правило, а не оформление */
.ph-ttl > h1 > svg, .ph-t > svg { display: none !important; }
/* 23.09.2026: .ph-c — счётчик, который остаётся В строке заголовка («Авто (1)»,
   «Ключевые слова (240)»). Не попадает под COUNTER page-header.js (id/класс без cnt/count),
   поэтому в подзаголовок не уезжает. Кегль от H1, цвет подзаголовка, не переносится. */
.ph-ttl > h1 .ph-c, .ph-t .ph-c { font-size: .6em; font-weight: 600; color: var(--ui-tx-2, #8a8a93);
  margin-left: 6px; white-space: nowrap; }
.ph-ttl > h1 .ph-c:empty { display: none; }

/* Правый блок-виджет: первой строкой две кнопки, под ними версия со значком истории.
   Ширина фиксирована содержимым, поэтому заголовок слева всегда знает свою границу. */
.ph-side { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }
/* сюда /page-header.js кладёт #hard-refresh и #sb-burger — обе кнопки платформы */
.ph-act { display: flex; gap: 8px; }
.ph-act > #sb-burger, .ph-act > #hard-refresh, .ph-act > #ph-gear, .ph-act > #cab-burger {
  position: static !important; top: auto !important; right: auto !important; left: auto !important;
}
/* версия модуля: своей строкой под кнопками, прижата вправо */
.ph-ver { display: flex; align-items: center; justify-content: flex-end; gap: 4px; }
.ph-ver:empty { display: none; }
/* шапка только с H1: пустой правый блок и нижний запас не рендерим */
.ph-act:empty { display: none; }
.ph-side:not(:has(.ph-act > *, .ph-ver > *)) { display: none; }
.ph:not(:has(.ph-s:not(:empty), .ph-tools > *)) { padding-bottom: 0 !important; }

.ph-s {
  font-size: 15.5px; font-weight: 500; line-height: 1.35; margin: 4px 0 0 !important;
  color: var(--ui-tx-2, #8a8a93);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ph-s:empty { display: none; }
/* Счётчики и секции переезжают в подзаголовок ВМЕСТЕ С УЗЛОМ (страница продолжает
   писать в них по id), а вместе с узлом приезжает и его кегль: h2 рисовался 24px,
   а .count — 0.62em. Подзаголовок — одна строка одним кеглем, поэтому гасим. */
.ph-s > * { font: inherit !important; color: inherit !important;
            margin: 0 !important; padding: 0 !important; display: inline !important;
            letter-spacing: inherit !important; }

/* кнопки действий страницы — своим рядом под шапкой, слева; в ряд с H1 не ставим
   никогда: на мобиле они дерутся с бургером за место */
.ph-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 18px; }
.ph-tools:empty { display: none; }

/* отбивка от контента — воздухом, не полосой */
.ph + * { margin-top: 18px; }

/* ===== ПК: ряд действий возвращается на строку заголовка =====
   Сносить кнопки страницы под подзаголовок имело смысл ТОЛЬКО на мобиле, где они
   дерутся за место с бургером. На ПК бургера нет, места вдоволь, и до ADR-147 они
   веками стояли справа от заголовка — там им и место. Первая редакция уносила их
   вниз на любой ширине: на /tasks это уронило однострочную шапку задачи 235,
   потому что её раскладкой управляет fltLayout(), а на остальных страницах просто
   молча испортило вид. Раскладка тут гридом, а не флексом: .ph-tools лежит в DOM
   ПОСЛЕ подзаголовка (это его мобильное место), а на ПК его надо поднять на строку
   выше — флексом так не сделать, не трогая разметку. */
@media (min-width: 769px) {
  .ph { display: grid !important; grid-template-columns: minmax(0, 1fr) auto;
        column-gap: 16px; align-items: start; }
  .ph-row   { grid-column: 1; grid-row: 1; }
  .ph-s     { grid-column: 1; grid-row: 2; }
  .ph-tools { grid-column: 2; grid-row: 1 / span 2; margin-top: 0;
              align-self: center; justify-content: flex-end; }
}

/* ===== ВКЛАДКИ РАЗДЕЛА (.med-tabs) =====
   Сегментированный переключатель: подложка-«ванночка», активная вкладка — плашка.
   Переехал сюда из <style> в medcard.html (правило ADR-063: компонент на 2+ страницах
   живёт в ui.css, а не копией в каждой). Второй потребитель — образец на /refs#header.
   Не переносятся, а уезжают прокруткой вбок — осознанный выбор, см. ADR-098.
   Контейнер (.med-tabs) страница задаёт сама: ширина и отступы у неё свои. */
/* 15.09.2026: ряд стал компактнее (было 10px/18px и 13.5px) и переносится на любой
   ширине — разделов в нём теперь больше, и это ОДИН ряд на медкарту, трекер и
   путешествия (app-switch.js). Ссылка в ряду выглядит как кнопка: разделы вне
   медкарты (Путешествия) — обычные <a>. */
.med-tabs { flex-wrap: wrap; }
.med-tabs .med-tab-btn {
  display: inline-flex; align-items: center; gap: 6px; padding: 8px 13px; border: none;
  background: transparent; color: var(--ui-tx-2, #8a8a93); font-size: 12.5px; font-weight: 600;
  font-family: inherit; border-radius: 6px; cursor: pointer; white-space: nowrap;
  text-decoration: none; transition: background .15s, color .15s;
}
/* 19.09.2026 (ADR-216): подпись, ховер и активный сегмент — токенами. Ховер был
   rgba(255,255,255,.05): полупрозрачный БЕЛЫЙ на светлой теме не виден вовсе, поэтому
   color-mix от цвета текста — в тёмной даёт тот же еле заметный высветленный слой, в
   светлой затемняет. Активный сегмент берёт --ui-seg-on (правило из /refs «Светлая тема»),
   а не --ui-card-border: это роль «активный сегмент фильтра», а не линия. */
.med-tabs .med-tab-btn:hover { color: var(--ui-tx, #f2f2f4); background: color-mix(in srgb, var(--ui-tx, #fff) 6%, transparent); }
.med-tabs .med-tab-btn.active { background: var(--ui-seg-on, #1f1f1f); color: var(--ui-tx, #e8e8e8); box-shadow: none; }
@media (max-width: 768px) {
  /* 12.09.2026: было «значок сверху, подпись снизу, кнопки делят ширину поровну»
     (flex:1 1 0). Пока вкладок было пять, это работало; на семи на каждую оставалось
     по 47px, и подписи вроде «Анализы» вставали впритык к соседям. Теперь ряд
     ПЕРЕНОСИТСЯ: кнопки по содержимому, значок и подпись в строку — тот же приём,
     что у ряда разделов в трекере (ADR-175). Две строки на телефоне вместо одной
     сдавленной. */
  .med-tabs { flex-wrap: wrap; }
  .med-tabs .med-tab-btn {
    flex: 0 0 auto; min-width: 0; flex-direction: row; justify-content: center;
    gap: 6px; font-size: 12.5px; padding: 8px 12px; min-height: 40px;
  }
}

/* ===== ПАНЕЛЬ СПИСКА (.lt) — два ряда под шапкой (17.09.2026) =====
   Эталон — /ticket, /issues, /<slug>/tasks. Образец с сеткой — /refs#header → «ПК».
     ряд 1: [Фильтр N] [вкладки раздела] ………… [+ Сущность]
     ряд 2: [поиск 250px] [второе поле 200px: проект / страница / спринт]
   Всё, что человек видит в этих рядах, стоит на месте с первого кадра: кнопки не
   появляются после загрузки, чипов фильтров под рядом нет (активные фильтры — число
   на кнопке «Фильтр»), шторка фильтра не двигает контент, а ложится поверх.
   Кнопки — роли из /set#btns (.tbtn / .btn), своего вида у них здесь нет.
   Высота контрола — одна на кнопки и поля: --ui-ctl-h = --ui-field-h из /set (44px) на всех
   ширинах (28.09.2026; до этого на ПК считалась из геометрии кнопки и давала ~38px). Кнопки
   берут её как min-height (btnCss), поля — как height (inpCss). */
:root { --ui-ctl-h: var(--ui-field-h, 44px); }
.lt { margin: 22px 0; }
.lt-row { display: flex; align-items: center; gap: 8px; min-height: var(--ui-ctl-h); min-width: 0; }
.lt-row + .lt-row { margin-top: 12px; }
.lt-sp { flex: 1 1 auto; }
.lt-tabs { display: flex; align-items: center; gap: 6px; }
.lt-add { min-width: 120px; }
/* Кнопка «Фильтр» — вид как у вкладок кабинета (тёмная плашка, синяя кромка на ховере),
   а не синяя «основная»: она переключатель, а не главное действие. Роль платформы снята
   (no-ui-btn), геометрия — та же, что у кнопок /set: высота, кегль, отступы, значок. */
.lt-flt { height: var(--ui-ctl-h); box-sizing: border-box; display: inline-flex; align-items: center;
  gap: var(--ui-btn-gap, 7px); padding: 0 var(--ui-btn-px, 18px); cursor: pointer; white-space: nowrap;
  font: inherit; font-size: var(--ui-btn-fs, 13px); font-weight: var(--ui-btn-fw, 500); line-height: 1.2;
  color: var(--ui-tx, #e8e8e8); background: var(--ui-surface, #141414);
  border: 1px solid var(--ui-line, #2a2a2a); border-radius: var(--ui-radius, 8px);
  transition: border-color .15s, background .15s; }
.lt-flt svg { width: var(--ui-btn-ico, 15px); height: var(--ui-btn-ico, 15px); flex: 0 0 auto; }
.lt-flt:hover { border-color: var(--ui-brand, #00a0ff); }
body.lt-open .lt-flt { background: rgba(0,160,255,.12); border-color: var(--ui-brand, #00a0ff); }
/* число в кнопке: место под него держится всегда, пустое — невидимо, но ширину не теряет */
.lt-n { display: inline-block; min-width: 18px; height: 18px; line-height: 18px; padding: 0 5px;
  box-sizing: border-box; border-radius: 9px; font-size: 11px; font-weight: 600; text-align: center;
  font-variant-numeric: tabular-nums; background: color-mix(in srgb, var(--ui-tx, #fff) 8%, transparent); color: inherit; }
.lt-n:empty { visibility: hidden; }
.lt-n.is-acc { background: var(--ui-brand, #00a0ff); color: #fff; }
.primary > .lt-n { background: rgba(255,255,255,.22); }
.lt-find, .lt-pick { position: relative; display: flex; align-items: center; min-width: 0; }
.lt-find { flex: 0 0 250px; }
.lt-pick { flex: 0 0 200px; }
.lt-find > svg, .lt-pick > .lt-ico { position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  width: var(--ui-btn-ico, 15px); height: var(--ui-btn-ico, 15px); color: var(--ui-tx3, #666); pointer-events: none; }
.lt input, .lt select { height: var(--ui-ctl-h); box-sizing: border-box; }
.lt-find > input, .lt-pick > input, .lt-pick > select { width: 100%; padding-left: 34px !important; }
.lt-pick.is-on > input, .lt-pick.is-on > select { border-color: var(--ui-brand, #00a0ff); color: var(--ui-brand, #00a0ff); }
.lt-pick.is-on > .lt-ico { color: var(--ui-brand, #00a0ff); }
/* Выпадающий список проектов внутри .lt-pick (переехал из ticket.html 17.09.2026:
   второй потребитель — /timing/app). Разметка: .lt-pick.tk-pf > input + .tk-pf__x + .tk-pf__dd */
.tk-pf > input { padding-right: 28px !important; }
.tk-pf__x { position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  width: 22px; height: 22px; padding: 0; border: 0; background: transparent; cursor: pointer;
  font-size: 16px; line-height: 1; color: var(--ui-tx3, #666); }
.tk-pf__x:hover { color: var(--ui-tx, #e8e8e8); }
.tk-pf__dd { position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 50;
  max-height: 280px; overflow-y: auto; padding: 4px 0;
  background: var(--ui-surface, #111); border: 1px solid var(--ui-card-border, #262626);
  border-radius: var(--ui-radius, 8px); box-shadow: var(--ui-shadow-md, 0 6px 18px -2px rgba(0,0,0,.30)); }
.tk-pf__o { display: flex; align-items: center; gap: 8px; height: 30px; padding: 0 10px;
  font-size: 12.5px; color: var(--ui-tx, #e8e8e8); cursor: pointer; }
.tk-pf__o span:first-child { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tk-pf__o:hover, .tk-pf__o.is-hl { background: var(--ui-surface-2, #1a1a1a); }
.tk-pf__o.is-sel { color: var(--ui-brand, #00a0ff); }
.tk-pf__n { flex: 0 0 auto; font-size: 11px; color: var(--ui-tx3, #666); font-variant-numeric: tabular-nums; }
.tk-pf__e { padding: 8px 10px; font-size: 12px; color: var(--ui-tx3, #666); }

/* шторка фильтра — слева, от края сайдбара; на ПК СДВИГАЕТ рабочую область на свою
   ширину (как в кабинете), на телефоне ложится поверх с затемнением.
   --lt-left — где начинается шторка (край сайдбара), --lt-base — обычный отступ body
   слева. Портал: оба = --sb-w. Кабинет задаёт свои (сайдбар там не из sidebar.js). */
:root { --lt-w: 300px; }
.lt-drawer { position: fixed; top: 0; bottom: 0; left: var(--lt-left, var(--sb-w, 0px)); width: var(--lt-w);
  z-index: 460; box-sizing: border-box; display: flex; flex-direction: column; gap: 12px; padding: 20px 18px;
  background: var(--ui-surface, #121212); border-right: 1px solid var(--ui-line, #262626);
  transform: translateX(-105%); visibility: hidden; transition: transform .2s ease, visibility .2s; }
body.lt-open .lt-drawer { transform: none; visibility: visible; }
.lt-shade { position: fixed; top: 0; right: 0; bottom: 0; left: var(--lt-left, var(--sb-w, 0px)); z-index: 455;
  background: rgba(0,0,0,.45); opacity: 0; pointer-events: none; transition: opacity .2s; }
body.lt-open .lt-shade { opacity: 1; pointer-events: auto; }
/* Загрузка без спиннеров (#217, /refs/ui/skeleton_fade): серая полоска формы будущего контента + shimmer 1.2s.
   Размер задаёт страница (height/width), цвет — только токены. Смена на контент — startViewTransition или fade 150мс. */
.ui-sk { display: block; height: 14px; margin: 8px 0; border-radius: 6px; color: transparent; user-select: none;
  background: linear-gradient(90deg, var(--ui-surface-2, #1a1a1a) 25%, var(--ui-line, #262626) 50%, var(--ui-surface-2, #1a1a1a) 75%);
  background-size: 200% 100%; animation: ui-sk-sh 1.2s linear infinite; }
@keyframes ui-sk-sh { from { background-position: 200% 0; } to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .ui-sk { animation: none; } }
.lt-dh { display: flex; align-items: center; justify-content: space-between; min-height: 30px; }
.lt-dh b { display: flex; align-items: center; gap: 8px; font-size: 17px; font-weight: 600; color: var(--ui-tx, #fff); }
.lt-dh b svg { width: var(--ui-btn-ico, 15px); height: var(--ui-btn-ico, 15px); }
.lt-cap { margin-top: 6px; font-size: 11px; color: var(--ui-tx3, #6b6b6b); text-transform: uppercase; letter-spacing: .06em; }
.lt-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; overflow-y: auto; }
.lt-grid > button { justify-content: flex-start !important; min-width: 0; }
.lt-grid > button > span:first-of-type { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; text-align: left; }
.lt-foot { margin-top: auto; display: flex; gap: 8px; padding-top: 14px; border-top: 1px solid var(--ui-line, #232323); }
.lt-foot > * { flex: 1 1 0; }
/* мобильная раскладка рядов — отдельным шагом; пока только шторка от края экрана */
@media (min-width: 821px) {
  body.lt-open { padding-left: calc(var(--lt-base, var(--sb-w, 0px)) + var(--lt-w)) !important; }
  body.lt-anim { transition: padding-left .2s ease; }
  .lt-shade { display: none; }
}
@media (max-width: 820px) {
  .lt-drawer, .lt-shade { left: 0; }
  .lt-drawer { width: min(320px, 88vw); z-index: 620; }
  .lt-shade { z-index: 615; }
}
/* ===== ПАНЕЛЬ СПИСКА — ТЕЛЕФОН (17.09.2026, образец /refs#filters → «Мобильный») =====
   ряд 1: [Фильтр N] ……… [+]            — «+» квадратом 44, подпись прячется
   ряд 1б: [вкладки раздела поровну]      — своей строкой на всю ширину
   ряд 2: [поиск 1fr] [второе поле 1fr]  — оба 44px, кегль 16px (анти-зум iOS)
   Все контролы — тач-таргет --ui-tap (44px). */
@media (max-width: 768px) {
  :root { --ui-ctl-h: var(--ui-tap, 44px); }
  .lt { margin: 14px 0 16px; }
  .lt-row { flex-wrap: wrap; row-gap: 8px; }
  .lt-row + .lt-row { margin-top: 8px; }
  .lt-flt { padding: 0 14px; }
  .lt-add { min-width: var(--ui-tap, 44px) !important; width: var(--ui-tap, 44px); height: var(--ui-tap, 44px);
    padding: 0 !important; }
  .lt-add > .lt-l { display: none; }
  .lt-tabs { order: 3; flex: 1 1 100%; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 6px; }
  .lt-tabs > button { min-height: var(--ui-tap, 44px); padding: 0 8px !important; min-width: 0; }
  .lt-tabs > button > .lt-l { overflow: hidden; text-overflow: ellipsis; }
  .lt-find, .lt-pick { flex: 1 1 0; }
  .lt input, .lt select { font-size: 16px !important; }
}

@media (max-width: 768px) {
  .ph { padding: 14px var(--ui-page-pad-m, 14px) 0 !important; }
  /* Контейнер страницы держит те же боковые поля, что и шапка над ним (06.09.2026).
     До этого .ph уезжал на 14px, а .ui-page оставался на десктопных 44px: заголовок
     и карточки шли по разным линиям, а на телефоне 390px под контент оставалось 302px.
     Значение — тот же токен --ui-page-pad-m из /set. То же правило есть в
     medcard_mobile.css (там оно приехало раньше и с теми же значениями): дубль
     безобидный, медкарта грузит свой файл последним. */
  .ui-page { padding: 14px var(--ui-page-pad-m, 14px) 40px; }
  .ph-ttl > h1, .ph-t { font-size: 32px; }
  .ph-s { font-size: 15px; }
  .ph-tools { margin-top: 14px; }
  /* тач-таргет кнопок шапки */
  .ph-act > * { min-width: var(--ui-tap, 44px); min-height: 42px; }

  /* Кнопки шапки (⚙ и ☰) ЗАКРЕПЛЕНЫ у верхнего края экрана (05.09.2026): фиксируем весь блок .ph-act, порядок внутри
     задаёт page-header.js. В потоке он места не занимает — запас под него держит .ph-side (min-width ниже). */
  .ph-act { position: fixed; top: 12px; right: 12px; z-index: 600; }
  .ph-side { flex-direction: row; align-items: center; gap: 8px; }

  /* В шапке только ⚙ и ☰ (19.09 / 23.10.2026): ⟳ и версия модуля живут в шторке бургера (sidebar.js: #sb-refresh, /mhead.js). */
  .ph-act > #hard-refresh { display: none !important; }
  /* 23.10.2026 (Константин): ⚙ ВЕРНУЛАСЬ в шапку — справа ⚙ и ☰, даты нет. 42×42, радиус 10, фон/рамка токенами.
     Внутри fixed-ряда .ph-act (gap 8) ⚙ стоит слева от ☰ и с ним не пересекается; шторка (#sb-set) тоже остаётся. */
  .ph-act > #ph-gear { display: flex !important; width: 42px; min-width: 42px; height: 42px; flex: 0 0 42px; padding: 0; border-radius: 10px;
    align-items: center; justify-content: center; background: var(--ui-surface-2, #1a1a1a); border: 1px solid var(--ui-line, #2a2a2a); color: var(--ui-tx, #e8e8e8); }
  .ph-side, .ph-side:has(#ph-gear) { min-width: 106px; }   /* 12 + 42 + 8 + 42 + запас: H1 не уезжает под иконки */
  .ph-ttl { padding-right: 4px; min-width: 0; }
  .ph-ver { display: none !important; }
}

/* --- значки выбора даты и времени: Lucide вместо браузерных ---
   color-scheme здесь не задаём: свойство наследуется от :root, где его ставит
   themeVars() по реальной теме (ADR-216). Прибитый dark делал выпадающий календарь
   и списки времени чёрными в светлой теме. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator {
  opacity: 1;
  cursor: pointer;
  width: 15px; height: 15px;
  background-color: var(--ui-ico, #8a8a8a);
  background-image: none;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-size: contain;    mask-size: contain;
  -webkit-mask-position: center; mask-position: center;
  transition: background-color .15s;
}
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator {
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='18' rx='2'/><path d='M16 2v4M8 2v4M3 10h18'/></svg>");
          mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='18' rx='2'/><path d='M16 2v4M8 2v4M3 10h18'/></svg>");
}
input[type="time"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><polyline points='12 6 12 12 16 14'/></svg>");
          mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><polyline points='12 6 12 12 16 14'/></svg>");
}
input[type="date"]:hover::-webkit-calendar-picker-indicator,
input[type="time"]:hover::-webkit-calendar-picker-indicator,
input[type="datetime-local"]:hover::-webkit-calendar-picker-indicator,
input[type="month"]:hover::-webkit-calendar-picker-indicator { background-color: var(--ui-brand, #00a0ff); }

/* ===== ЧЕКБОКС ПЛАТФОРМЫ =====
   <label class="ui-check-row"><input type="checkbox" class="ui-check"> Подпись</label>
   Размер подписи не задаём — наследуется от родителя.

   19.10.2026: ЕДИНЫЙ вид для ВСЕХ нативных чекбоксов платформы (решение Константина, макет
   утверждён): 20x20, радиус 6, рамка 1.5px брендовая, фон ПУСТОЙ (токен карточки), галочка
   ::after брендовым цветом, на checked фон НЕ заливается. Исключения (не трогаются):
   .ui-switch (тумблер), .no-ui-check, [data-native], .ci-nb (круглая «не ошибка» в /crawl).
   Источник один — этот блок. Правило /theme.css (ui_check_all=1, server.js) подключается ПОСЛЕ
   ui.css с специфичностью 0,2,1, поэтому здесь тройной :not (0,4,1) — перебивает его и
   страничные width/height. Свой ::before у theme гасим (content:none), галка живёт на ::after
   с фиксированными px (проценты в grid-треке схлопывались в 0, ADR-067). Размер/радиус из /set
   (ui_check_size/radius) на нативные чекбоксы больше не влияют. */
input[type="checkbox"]:not(.ui-switch):not(.no-ui-check):not([data-native]):not(.ci-nb) {
  appearance: none; -webkit-appearance: none;
  box-sizing: border-box; width: 20px; height: 20px; min-width: 20px; flex: none; margin: 0; padding: 0;
  border: 1.5px solid var(--ui-brand, #00a0ff); border-radius: 6px;
  background: var(--ui-card-bg, #fff); box-shadow: none;
  cursor: pointer; vertical-align: middle; position: relative;
  display: inline-grid; place-content: center;
  transition: background .15s, border-color .15s, box-shadow .15s;
}
input[type="checkbox"]:not(.ui-switch):not(.no-ui-check):not([data-native]):not(.ci-nb)::before { content: none; display: none; }
input[type="checkbox"]:not(.ui-switch):not(.no-ui-check):not([data-native]):not(.ci-nb)::after {
  content: ""; position: static; display: block; box-sizing: content-box; inset: auto;
  width: 10px; height: 6px; margin-top: -2px; padding: 0; border-radius: 0; background: none;
  border: 0; border-left: 2px solid var(--ui-brand, #00a0ff); border-bottom: 2px solid var(--ui-brand, #00a0ff);
  transform: rotate(-45deg) scale(0); transition: transform .12s;
}
input[type="checkbox"]:not(.ui-switch):not(.no-ui-check):not([data-native]):not(.ci-nb):hover:not(:disabled) { background: rgba(0,160,255,.12); }
input[type="checkbox"]:not(.ui-switch):not(.no-ui-check):not([data-native]):not(.ci-nb):checked {
  background: var(--ui-card-bg, #fff); border-color: var(--ui-brand, #00a0ff);
}
input[type="checkbox"]:not(.ui-switch):not(.no-ui-check):not([data-native]):not(.ci-nb):checked:hover:not(:disabled) { background: rgba(0,160,255,.12); }
input[type="checkbox"]:not(.ui-switch):not(.no-ui-check):not([data-native]):not(.ci-nb):checked::after { transform: rotate(-45deg) scale(1); }
input[type="checkbox"]:not(.ui-switch):not(.no-ui-check):not([data-native]):not(.ci-nb):indeterminate::after {
  height: 0; margin-top: 0; border-left: 0; border-bottom: 2px solid var(--ui-brand, #00a0ff); transform: scale(1);
}
input[type="checkbox"]:not(.ui-switch):not(.no-ui-check):not([data-native]):not(.ci-nb):focus-visible {
  outline: none; box-shadow: 0 0 0 3px rgba(0,160,255,.28);
}
input[type="checkbox"]:not(.ui-switch):not(.no-ui-check):not([data-native]):not(.ci-nb):disabled {
  opacity: 1; cursor: not-allowed; border-color: var(--ui-line, #3a3a3a); background: var(--ui-card-bg, #fff);
}
input[type="checkbox"]:not(.ui-switch):not(.no-ui-check):not([data-native]):not(.ci-nb):disabled::after {
  border-left-color: var(--ui-tx-3, #8a8a8a); border-bottom-color: var(--ui-tx-3, #8a8a8a);
}
.ui-check-row { display: flex; align-items: center; gap: 7px; color: #ccc; cursor: pointer; }
.ui-check-row:has(.ui-check:disabled) { cursor: not-allowed; color: #7a7a7a; }

/* ===== ТУМБЛЕР ПЛАТФОРМЫ (.ui-switch) =====
   Разметка: <label class="sw-row"><span class="sw-txt">Подпись<span class="sw-hint">пояснение</span></span>
             <input type="checkbox" class="ui-switch no-ui-check" id="…"></label>

   Два правила, которые нельзя нарушать:
   1) нативный <input type=checkbox> остаётся на месте — .checked читают функции сохранения
      (saveTask()/openModal() на /tasks, save() в task-card.js). Тумблер — это ТОЛЬКО внешний вид.
   2) класс no-ui-check рядом ОБЯЗАТЕЛЕН: «фирменный вид чекбоксов» из /theme.css
      (ui_check_all=1) объявляет input[type=checkbox]:not(.no-ui-check) с той же
      специфичностью и при неудачном порядке подключения перебил бы тумблер.

   Жил в <style> внутри tasks.html (задача 217 / ADR-064). Переехал сюда в 1.37.0
   (задача 273 / ADR-067), когда тот же тумблер понадобился в карточке задачи
   кабинета клиента. */
input.ui-switch[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  flex: none; position: relative; cursor: pointer; vertical-align: middle;
  width: 44px !important; height: 26px !important; margin: 0; padding: 0 !important;
  border-radius: 13px; background: #2e2e2e; border: 1px solid #3a3a3a;
  transition: background .18s, border-color .18s;
}
input.ui-switch[type="checkbox"]::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%;
  background: #8a8a8a; box-shadow: 0 1px 3px rgba(0,0,0,.45);
  transition: transform .18s cubic-bezier(.4,.1,.2,1), background .18s;
}
input.ui-switch[type="checkbox"]:hover { border-color: #4a4a4a; }
input.ui-switch[type="checkbox"]:checked {
  background: var(--ui-brand, #00a0ff); border-color: var(--ui-brand, #00a0ff);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ui-brand, #00a0ff) 16%, transparent);
}
input.ui-switch[type="checkbox"]:checked::after { transform: translateX(18px); background: #fff; }
input.ui-switch[type="checkbox"]:active::after { width: 23px; }
input.ui-switch[type="checkbox"]:checked:active::after { transform: translateX(15px); }
input.ui-switch[type="checkbox"]:disabled { opacity: .45; cursor: not-allowed; }
/* строка «подпись слева — тумблер справа». Была под #modal — расширена на всю платформу:
   класс sw-row нигде, кроме модалки задачи, не встречался, так что вид /tasks не изменился. */
label.sw-row {
  display: flex; align-items: center; gap: 12px; margin: 12px 0 0; cursor: pointer;
  background: var(--ui-surface-2, #1a1a1a); border: 1px solid var(--ui-card-border, #262626);
  border-radius: 12px; padding: 10px 12px; color: #c9c9c9; font-size: 13px;
  text-transform: none; letter-spacing: 0;
  transition: border-color .15s;
}
label.sw-row:hover { border-color: #333; }
label.sw-row .sw-txt { flex: 1; min-width: 0; font-weight: 600; color: #dcdcdc; }
label.sw-row .sw-hint {
  display: block; margin-top: 2px; font-size: 11px; font-weight: 400; line-height: 1.35;
  color: var(--ui-muted, #6a6a6a);
}

/* ===== ЧЕК-ЛИСТ ПЛАТФОРМЫ (.cl-list) =====
   Разметка пункта — ровно та, что рисует renderChecklist():

   <div class="cl-list">
     <div class="cl-item">                      (+ .cl-sub, + .cl-sub-last у последнего подпункта)
       <span class="cl-box done" onclick="…"><svg><use href="/assets/icons.svg#i-check"></use></svg></span>
       <span class="cl-text done" contenteditable="true" …>Текст пункта</span>
       <span class="cl-acts">…i-edit, i-copy, i-subitem, cl-a-cancel(i-close), i-del…</span>
     </div>
   </div>

   Галочка — НЕ нативный <input type=checkbox>, а <span class="cl-box"> со значком
   i-check из спрайта. Это осознанно: нативный чекбокс тут пришлось бы согласовывать
   с «фирменным видом чекбоксов» из /theme.css (ui_check_all), у которого свой ::before,
   а данные всё равно живут строками «[ ] пункт» внутри comment, а не в .checked.

   Третий статус — «отменён» (26.08.2026): маркер «-» в comment вместо «x»/« »,
   взаимоисключим с done в самой разметке строки (пункт не может быть одновременно
   выполнен и отменён). .cl-box.cancelled и .cl-text.cancelled — тем же принципом,
   что .done, только опасным цветом и пунктирным зачёркиванием текста; иконка внутри
   галочки меняется на i-close. Переключается отдельной кнопкой cl-a-cancel в .cl-acts
   (тот же i-close), а не самим кликом по галочке — клик по галочке по-прежнему
   значит «выполнено/не выполнено» и сбрасывает cancelled, если он был.

   Жил в <style> внутри tasks.html (задача 217 / ADR-064). Переехал сюда в 1.38.0
   (задача 276 / ADR-070), когда тот же чек-лист понадобился в карточке задачи
   кабинета клиента. Контейнер (.cl-widget на /tasks, .tc-blk в кабинете) — за страницей,
   здесь только пункты. */
.cl-list .cl-item { display: flex; align-items: flex-start; gap: 8px; padding: 3px 0; position: relative; }
.cl-list .cl-box {
  width: 20px; height: 20px; flex-shrink: 0; margin-top: 0; box-sizing: border-box;
  border: 1.5px solid var(--ui-brand, #00a0ff); border-radius: 6px; background: var(--ui-card-bg, #fff);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; color: transparent;
  transition: border-color .15s, background .15s;
}
.cl-list .cl-box svg { width: 12px; height: 12px; stroke-width: 3; }
.cl-list .cl-box:hover { background: rgba(0,160,255,.12); }
/* отмеченный пункт — как нативный чекбокс платформы (19.10.2026): фон пустой, голубая галочка */
.cl-list .cl-box.done { background: var(--ui-card-bg, #fff); border-color: var(--ui-brand, #00a0ff); color: var(--ui-brand, #00a0ff); }
/* «отменён» — третий статус пункта (маркер «-» в comment, взаимоисключим с done в
   разметке), значок i-close. Красится опасным цветом ПОСТОЯННО, а не только на hover:
   это статус пункта, как и .done, а не иконочная кнопка-действие из /set#btns
   (ADR-069) — то правило про hover-only цвет касается только .cl-acts ниже. */
.cl-list .cl-box.cancelled { background: var(--ui-danger, #e05252); border-color: var(--ui-danger, #e05252); color: #fff; }
.cl-list .cl-text { flex: 1; font-size: 13px; line-height: 1.5; outline: none; color: #ddd; word-break: break-word; }
.cl-list .cl-text.done { color: #555; text-decoration: line-through; }
/* пунктирное зачёркивание — отличить на глаз от сплошного у «выполнено» */
.cl-list .cl-text.cancelled { color: #555; text-decoration: line-through; text-decoration-style: dashed; }
.cl-list .cl-acts { display: flex; align-items: center; gap: 1px; flex-shrink: 0; opacity: 0; transition: opacity .15s; }
.cl-list .cl-item:hover .cl-acts { opacity: 1; }
.cl-list .cl-acts span { cursor: pointer; padding: 2px 3px; color: #5a5a5a; display: inline-flex; transition: color .15s; }
.cl-list .cl-acts span:hover { color: var(--ui-brand, #00a0ff); }
/* «отменить» (cl-a-cancel) — обратимый переключатель статуса, а не удаление,
   поэтому hover — акцент, как у правки/копирования, а не опасный цвет корзины */
.cl-list .cl-acts span.cl-a-del:hover { color: var(--ui-danger, #e05252); }
.cl-list .cl-acts svg { width: 13px; height: 13px; }
/* второй уровень — как подменю в сайдбаре */
.cl-list .cl-sub { padding-left: 26px; }
.cl-list .cl-sub::before { content: ''; position: absolute; left: 7px; top: 0; bottom: 0; width: 1px; background: #1f1f1f; }
.cl-list .cl-sub.cl-sub-last::before { bottom: auto; height: 12px; }
.cl-list .cl-sub::after { content: ''; position: absolute; left: 8px; top: 11px; width: 10px; height: 1px; background: var(--ui-card-border, #262626); transition: background .15s, width .15s; }
.cl-list .cl-sub:hover::after { background: #3d3d3d; width: 12px; }
.cl-list .cl-sub .cl-box { width: 14px; height: 14px; border-radius: 4px; }
.cl-list .cl-sub .cl-box svg { width: 10px; height: 10px; }
.cl-list .cl-sub .cl-text { font-size: 12.5px; color: #b4b4b4; }
.cl-list .cl-sub .cl-text.done { color: #4a4a4a; }
.cl-list .cl-sub .cl-text.cancelled { color: #4a4a4a; }
/* шеврон сворачивания ветки (.cl-chev) — у пункта первого уровня, когда подпунктов
   больше порога (renderChecklist на /tasks; в кабинете его нет). Виден всегда, а не по
   hover, как .cl-acts: это состояние ветки, а не иконочная кнопка-действие. В свёрнутом
   виде шеврон повёрнут и рядом с ним число спрятанных подпунктов. */
.cl-list .cl-chev {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 2px;
  margin-top: 1px; padding: 1px 2px; cursor: pointer;
  color: #5a5a5a; font-size: 11px; line-height: 1; transition: color .15s;
}
.cl-list .cl-chev:hover { color: var(--ui-brand, #00a0ff); }
.cl-list .cl-chev svg { width: 13px; height: 13px; transition: transform .15s; }
.cl-list .cl-chev.folded svg { transform: rotate(-90deg); }
/* пункт только на чтение: клиент по чужой задаче отмечать и править не может.
   Класс вешает рендер, курсор и ховеры снимаем здесь, чтобы не выглядело кликабельным. */
.cl-list.cl-ro .cl-box { cursor: default; }
.cl-list.cl-ro .cl-box:hover { border-color: #3a3a3a; }

/* ручка драга (.cl-grip) — переставить пункт местами, родитель тащит подпункты
   с собой. В потоке flex, а не абсолютным позиционированием: рисуется только там,
   где есть <span class="cl-grip"> в разметке (сейчас — только renderChecklist() на
   /tasks; JS там же — clDragStart/clDragMove/clDragEnd). Кабинет клиента (task-card.js)
   её не добавляет и остаётся как был, пиксель в пиксель. */
.cl-list .cl-grip {
  width: 12px; flex-shrink: 0; align-self: stretch; margin: -3px 0;
  display: flex; align-items: center; justify-content: center;
  color: #4a4a4a; cursor: grab; opacity: 0; transition: opacity .15s, color .15s;
  touch-action: none;
}
.cl-list .cl-item:hover .cl-grip { opacity: 1; }
.cl-list .cl-grip:hover { color: var(--ui-brand, #00a0ff); }
.cl-list .cl-grip svg { width: 13px; height: 13px; }
/* если ручка есть — второй уровень сдвинут вправо на её ширину+gap (20px), соединитель
   подпункта подвинут вместе с ним, чтобы не уезжать мимо галочки (см. .cl-sub выше) */
.cl-list .cl-sub:has(.cl-grip)::before { left: 27px; }
.cl-list .cl-sub:has(.cl-grip)::after { left: 28px; }
.cl-list .cl-item.cl-drag-src { opacity: .35; }
.cl-list .cl-item.cl-drop-before { box-shadow: inset 0 2px 0 0 var(--ui-brand, #00a0ff); }
.cl-list .cl-item.cl-drop-after { box-shadow: inset 0 -2px 0 0 var(--ui-brand, #00a0ff); }
body.cl-dragging { cursor: grabbing !important; user-select: none; }

/* Чек-лист на тачскрине. Две правки по существу (ADR-064):
   1) .cl-acts были opacity:0 и проявлялись по :hover — на телефоне hover не наступает
      никогда, то есть редактировать / копировать / подпункт / удалить было недоступно.
   2) квадратик галочки 16px (у подпунктов 14px) при норме тач-таргета 44px.
   Разметку renderChecklist() и обработчики не трогаем — только размеры и видимость. */
@media (max-width: 768px) {
  /* padding-top/bottom, а НЕ сокращение «padding: 5px 0»: сокращение сбрасывало бы
     padding-left, а на нём держится отступ второго уровня (.cl-sub — 26px).
     Так это и было сломано на /tasks: мобильное правило было на два id специфичнее
     правила подпункта, и на телефоне подпункты вставали вровень с обычными,
     а соединитель-уголок проезжал прямо по галочке. Проявлялось только на мобиле. */
  .cl-list .cl-item { padding-top: 5px; padding-bottom: 5px; align-items: flex-start; gap: 7px; }
  .cl-list .cl-box { width: 20px; height: 20px; border-radius: 6px; margin-top: 1px; position: relative; }
  .cl-list .cl-box svg { width: 13px; height: 13px; }
  /* на тачскрине hover не наступает — ручка драга всегда чуть видна, как .cl-acts (ADR-064) */
  .cl-list .cl-grip { opacity: .45; width: 20px; }
  /* невидимое расширение зоны тапа до ~38px без сдвига вёрстки; справа оставляем
     зазор, чтобы не перехватывать тап по тексту (он contenteditable) */
  .cl-list .cl-box::before { content: ""; position: absolute; top: -9px; bottom: -9px; left: -9px; right: -4px; }
  .cl-list .cl-sub .cl-box { width: 18px; height: 18px; border-radius: 5px; }
  .cl-list .cl-sub .cl-box svg { width: 12px; height: 12px; }
  /* четыре действия в строке на 390px съедают текст, поэтому цель по ширине компактная (26px),
     а по высоте полная (30px) — палец промахивается по вертикали, а не по горизонтали */
  .cl-list .cl-acts { opacity: .45; gap: 0; align-self: flex-start; }
  .cl-list .cl-acts span { min-width: 26px; min-height: 30px; padding: 0; align-items: center; justify-content: center; }
  .cl-list .cl-acts span:active { opacity: 1; color: var(--ui-brand, #00a0ff); }
  .cl-list .cl-text { font-size: 13.5px; line-height: 1.45; }
  /* Карандаш на мобиле скрыт: тап по самому тексту уже включает редактирование
     (.cl-text contenteditable), а четвёртая кнопка отнимала у текста 26px из ~190.
     Вернуть — удалить это правило, обработчик focusCheckItem на месте. */
  .cl-list .cl-acts span:first-child { display: none; }
  /* соединитель подпункта — по центру квадратика после смены его размера */
  .cl-list .cl-sub::after { top: 16px; }
}

/* ===== СВОРАЧИВАЕМЫЙ БЛОК =====
   <div class="ui-fold" data-open="0">
     <div class="ui-fold-head" onclick="uiFold(this)">Заголовок<span class="ui-fold-badge">3 из 8</span><svg class="ui-fold-chev">…</svg></div>
     <div class="ui-fold-body"><div class="ui-fold-inner">…</div></div>
   </div>                                                       */
.ui-fold { border-radius: var(--ui-radius, 8px); }
.ui-fold-head {
  display: flex; align-items: center; gap: 8px; cursor: pointer; user-select: none;
  padding: 7px 8px; margin: 0 -8px; border-radius: var(--ui-radius, 8px);
  color: #9a9a9a; transition: background .15s, color .15s;
}
.ui-fold-head:hover { background: #ffffff08; color: #ddd; }
.ui-fold-badge {
  margin-left: auto; font-size: 11px; color: var(--ui-brand, #00a0ff);
  background: #00a0ff14; border: 1px solid #00a0ff33; border-radius: 20px; padding: 1px 9px;
}
.ui-fold-chev {
  width: 14px; height: 14px; flex-shrink: 0; color: var(--ui-fold-chev, #ffffff);
  transition: transform .25s cubic-bezier(.4,0,.2,1), color .15s;
}
.ui-fold-head:hover .ui-fold-chev { color: var(--ui-brand, #00a0ff); }
.ui-fold[data-open="1"] .ui-fold-chev { transform: rotate(90deg); }
.ui-fold-body {
  display: grid; grid-template-rows: 0fr; opacity: 0;
  transition: grid-template-rows .28s cubic-bezier(.4,0,.2,1), opacity .2s;
}
.ui-fold[data-open="1"] .ui-fold-body { grid-template-rows: 1fr; opacity: 1; }
.ui-fold-body > .ui-fold-inner { overflow: hidden; min-height: 0; }
.ui-fold[data-open="1"] .ui-fold-body > .ui-fold-inner { padding-top: 8px; }

/* ===== БЕЙДЖ И ТОЧКА (08.09.2026) =====
   Один компонент на всю платформу: счётчик непрочитанного в меню, в строке чата,
   в пункте кабинета. Значения — токены --ui-badge-* из /theme.css (/set → «Бейджи»),
   правила поведения (когда бейдж уместен, кап 99+, точка ИЛИ число) — /refs → «Бейджи и счётчики».

   Разметка:
     <span class="ui-badge">4</span>          — счётчик, число ставит скрипт через uiBadge()
     <span class="ui-badge ui-badge-dot"></span> — точка «что-то изменилось», без числа
   В строке-ссылке бейдж сам уезжает вправо (margin-left:auto). Точка и число на одной
   строке одновременно — ошибка: строка отвечает на один вопрос, а не на два.          */
.ui-badge {
  margin-left: auto; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: var(--ui-badge-h, 18px); height: var(--ui-badge-h, 18px);
  padding: 0 var(--ui-badge-px, 5px);
  background: var(--ui-badge-bg, #e05252); color: var(--ui-badge-text, #fff);
  font-size: var(--ui-badge-fs, 10px); font-weight: var(--ui-badge-fw, 600);
  line-height: 1; border-radius: var(--ui-badge-radius, 9px);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* Точка — тот же цвет, но без числа и без паддингов: ширина не зависит от содержимого. */
.ui-badge.ui-badge-dot {
  min-width: 0; width: var(--ui-badge-dot, 8px); height: var(--ui-badge-dot, 8px);
  padding: 0; border-radius: 50%; font-size: 0;
}
/* Пустой бейдж не рисуем вовсе — иначе на месте нуля висит красный кружок,
   и человек перестаёт замечать бейджи вообще. */
.ui-badge:empty:not(.ui-badge-dot) { display: none; }

/* ===== ВКЛАДКИ (.ui-tabs > .ui-tab) — ЕДИНЫЙ КОМПОНЕНТ, 23.09.2026 =====
   Один компонент на бизнес- и личные разделы, различие — модификатором, не копией:
     <div class="ui-tabs">                 сегментированная «таблетка» (по умолчанию; личные модули)
     <div class="ui-tabs is-line">         подчёркнутые вкладки (реестры бизнес-раздела)
       <button class="ui-tab is-on">Обзор</button>
       <button class="ui-tab">История <span class="ui-badge">3</span></button>
   Весь вид — токены --ui-tab-* из /set → «Вкладки», цвета по умолчанию ссылаются на токены
   темы (светлая тема сама). Локального CSS вкладкам на страницах не писать; правило и живой
   образец — /refs → «Вкладки». Старые .tabs/.tab по страницам сюда не относятся и НЕ
   задеваются: внешний вид дорожки включается только когда внутри есть .ui-tab (:has),
   поэтому .ui-tabs как голая раскладка (leads/kpi/notify/agents) работает как раньше.
   На узком экране ряд не переносится, а листается вбок (вкладки одной строкой). */
.ui-tabs:has(> .ui-tab) { display: flex; flex-wrap: nowrap; gap: var(--ui-tab-gap, 4px); min-width: 0;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  padding: 3px; background: var(--ui-tab-bg, var(--ui-surface-2, #1a1a1a));
  border: 1px solid var(--ui-card-border, #262626); border-radius: var(--ui-tab-radius, 8px); }
.ui-tabs:has(> .ui-tab)::-webkit-scrollbar { display: none; }
.ui-tab { flex: 1 0 auto; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: calc(var(--ui-tab-h, 36px) - 8px); padding: 0 var(--ui-tab-px, 12px); margin: 0;
  border: 0; border-radius: calc(var(--ui-tab-radius, 8px) - 2px); background: transparent;
  color: var(--ui-tab-tx, var(--ui-tx-2, #8b8b8b)); font: inherit; font-size: var(--ui-tab-fs, 13px);
  font-weight: var(--ui-tab-fw, 600); white-space: nowrap; cursor: pointer; text-decoration: none;
  -webkit-tap-highlight-color: transparent; }
.ui-tab:hover { color: var(--ui-tab-on-tx, var(--ui-tx, #e8e8e8)); }
.ui-tab.is-on { background: var(--ui-tab-on-bg, var(--ui-card-border, #262626)); color: var(--ui-tab-on-tx, var(--ui-tx, #e8e8e8)); }
.ui-tab:focus-visible { outline: 2px solid var(--ui-tab-line, var(--ui-brand, #00a0ff)); outline-offset: -2px; }
.ui-tab > svg { width: 15px; height: 15px; flex: 0 0 auto; }
/* .is-line — вкладки реестров: без дорожки, активная подчёркнута акцентом */
.ui-tabs.is-line:has(> .ui-tab) { padding: 0; background: transparent; border: 0; border-radius: 0;
  border-bottom: 1px solid var(--ui-card-border, #262626); gap: calc(var(--ui-tab-gap, 4px) * 4); }
.ui-tabs.is-line > .ui-tab { flex: 0 0 auto; min-height: var(--ui-tab-h, 36px); padding: 0 2px; border-radius: 0;
  margin-bottom: -1px; border-bottom: 2px solid transparent; }
.ui-tabs.is-line > .ui-tab.is-on { background: transparent; border-bottom-color: var(--ui-tab-line, var(--ui-brand, #00a0ff)); }
@media (max-width: 768px) { .ui-tab { min-height: max(calc(var(--ui-tab-h, 36px) - 8px), 36px); } }

/* ===== ПОДСКАЗКА ПО ПОЛЮ: <span class="fi-hint" tabindex="0">i<span class="fi-tip">текст</span></span> ===== */
.fi-hint {
  position: relative; flex: 0 0 auto; margin-left: 6px; cursor: help; outline: none;
  width: 16px; height: 16px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: #2a2a2a; color: #9a9a9a; border: 1px solid #3a3a3a;
  font-size: 11px; font-style: italic; font-weight: 600; line-height: 1;
  transition: background .15s, color .15s, border-color .15s;
}
.fi-hint:hover, .fi-hint:focus { background: #00a0ff1a; color: var(--ui-brand, #00a0ff); border-color: #00a0ff55; }
.fi-tip {
  position: absolute; right: 0; bottom: calc(100% + 7px); z-index: 950;
  width: 260px; padding: 9px 11px;
  background: var(--ui-card-bg, #141414); border: 1px solid var(--ui-card-border, #2a2a2a); border-radius: var(--ui-radius, 8px);
  box-shadow: var(--ui-shadow-md, 0 6px 18px -2px rgba(0,0,0,.30));
  color: color-mix(in srgb, var(--ui-tx, #e8e8e8) 80%, var(--ui-bg, #0a0a0a)); /* = #bbb в тёмной (29.09.2026) */ font-size: 12px; font-style: normal; font-weight: 400; line-height: 1.4;
  text-align: left; white-space: normal;
  opacity: 0; visibility: hidden; transform: translateY(4px);
  transition: opacity .15s, transform .15s, visibility .15s;
}
.fi-hint:hover .fi-tip, .fi-hint:focus .fi-tip { opacity: 1; visibility: visible; transform: translateY(0); }

/* =========================================================================
   МОБИЛЬНАЯ КАРТОЧКА ЗАДАЧИ В ЛЕНТЕ (задача 217, шаг 1 — только карточка)
   Классы .task-* нигде больше не используются: десктоп не затрагивается.
   Шапка /tasks, фильтры, модалка и спринты — НЕ трогаются, отдельными шагами.
   ========================================================================= */
@media (max-width: 768px) {

  .task-card {
    display: flex; flex-direction: column; gap: 4px;
    background: var(--ui-card-bg); border: 1px solid var(--ui-card-border);
    padding: 8px 10px; border-radius: var(--ui-card-radius, 12px);
    font: 400 13px/1.4 -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
    color: var(--ui-ico);
  }
  .task-card * { font-variant-numeric: tabular-nums; }

  /* 1. шапка */
  .task-card__head { display: flex; flex-wrap: nowrap; align-items: center;
    justify-content: space-between; gap: 8px; width: auto;
    padding: 0; border: 0; background: none;
    margin: -7px -8px -3px 0; }
  .task-card__meta { display: flex; align-items: center; gap: 7px; min-width: 0; flex: 1 1 auto; }
  .task-card__id { color: var(--ui-brand); font-weight: 600; font-size: 13px; flex: 0 0 auto; }
  /* огонёк и замок — ровно по базовой линии номера, без наследных отступов */
  .task-card__meta .fl-ic,
  .task-card__meta .lock-ic { margin: 0; flex: 0 0 auto; width: var(--ui-ico-size); height: var(--ui-ico-size); }
  .task-card__meta .badge { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }
  /* Claude / GPT — справа от статуса, размер тот же --ui-ico-size из /set */
  .task-card__meta .ai-ic {
    flex: 0 0 auto; cursor: pointer;
    width: var(--ui-ico-size); height: var(--ui-ico-size);
    background: var(--ui-muted);
    -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
    -webkit-mask-size: contain;    mask-size: contain;
    -webkit-mask-position: center; mask-position: center;
    transition: background .15s, opacity .15s;
  }
  .task-card__meta .ai-ic.is-claude {
    -webkit-mask-image: url(/img/claude_logo.svg); mask-image: url(/img/claude_logo.svg); }
  .task-card__meta .ai-ic.is-gpt {
    -webkit-mask-image: url(/img/gpt_logo.svg);    mask-image: url(/img/gpt_logo.svg); }
  .task-card__meta .ai-ic.is-claude[data-on="1"] { background: var(--ui-claude); }
  .task-card__meta .ai-ic.is-gpt[data-on="1"]    { background: var(--ui-brand); }
  .task-card__actions { display: flex; flex: 0 0 auto; }
  .task-card__actions > * {
    width: var(--ui-tap); height: var(--ui-tap); padding: 0;
    display: grid; place-items: center; cursor: pointer;
    background: none; border: 0; color: var(--ui-ico); opacity: var(--ui-ico-opacity);
  }
  .task-card__actions svg { width: var(--ui-ico-size); height: var(--ui-ico-size); }

  /* 2. название */
  .task-card__title {
    margin: 0;
    font-size: 15px; font-weight: 500; line-height: 1.25; color: var(--ui-tx, #fff);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; text-wrap: pretty;
  }

  /* 3. чек-лист: до 6 пунктов — сегменты, от 7 — сплошная полоса */
  .task-seg { display: flex; gap: 3px; }
  .task-seg > i { flex: 1; height: var(--ui-seg-h); border-radius: calc(var(--ui-seg-h) / 2);
    border: 1px solid var(--ui-card-border); }
  .task-seg > i.is-done { background: var(--ui-brand); border-color: var(--ui-brand); }
  .task-seg.is-bar { align-items: center; gap: 7px; }
  .task-seg.is-bar > .track { flex: 1; height: var(--ui-seg-h);
    border-radius: calc(var(--ui-seg-h) / 2); background: var(--ui-card-border); overflow: hidden; }
  .task-seg.is-bar > .track > span { display: block; height: 100%; background: var(--ui-brand);
    border-radius: calc(var(--ui-seg-h) / 2); }
  .task-seg.is-bar > .num { font-size: 10px; color: var(--ui-muted); }

  /* 4. деньги и время */
  .task-chips { display: flex; gap: 6px; }
  .task-chips > * {
    flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px;
    padding: 5px 7px; border-radius: calc(var(--ui-card-radius, 12px) - 4px);
    background: var(--ui-surface-2); border: 1px solid var(--ui-card-border);
  }
  .task-chips b { font-size: 9px; font-weight: 600; letter-spacing: .09em;
    text-transform: uppercase; color: var(--ui-muted); }
  .task-chips span { font-size: 13px; font-weight: 600; color: var(--ui-ico); }
  .task-chips .is-over span { color: var(--ui-danger); }
  .task-chips .is-free span { color: var(--ui-muted); text-decoration: line-through; }
  .task-chips .is-late { flex: none;
    background: color-mix(in srgb, var(--ui-danger) 12%, transparent);
    border-color: color-mix(in srgb, var(--ui-danger) 45%, transparent); }
  .task-chips .is-late b, .task-chips .is-late span { color: var(--ui-danger); }

  /* 5. таймер — слева время+проект одной группой, справа кнопки; группы выровнены по центру между собой */
  .task-timer { display: flex; align-items: center; gap: 6px; margin: 3px -5px -5px 0; }
  .task-timer__info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; justify-content: center; }
  .task-timer__val { display: flex; align-items: center; height: var(--ui-tap);
    line-height: 1; font-size: 21px; font-weight: 600; letter-spacing: -.02em;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--ui-muted); }
  .task-card.is-running .task-timer__val { color: var(--ui-brand); }
  .task-card.is-paused .task-timer__val { color: var(--ui-pass, #facc15); }
  .task-timer > .tbtn {
    width: var(--ui-tap); height: var(--ui-tap); padding: 0; cursor: pointer;
    display: grid; place-items: center; background: none;
    border: 1px solid var(--ui-btn-border, #333); border-radius: var(--ui-radius, 10px);
    color: var(--ui-btn-text, #bbb);
  }
  .task-timer > .tbtn > svg { width: var(--ui-ico-size); height: var(--ui-ico-size); }
  .task-timer > .tbtn.is-stop { color: var(--ui-danger);
    border-color: color-mix(in srgb, var(--ui-danger) 45%, transparent); }
  /* активная кнопка текущего состояния (идёт — «Пауза», на паузе — «Продолжить») — заливка главной кнопки;
     !important: роль .tbtn из /theme.css красит фон/рамку/значок с !important; токены --ui-btn1-* сами меняются по теме */
  .task-card:is(.is-running, .is-paused) .task-timer > .tbtn:first-of-type {
    background: var(--ui-btn1-bg) !important;
    border-color: var(--ui-btn1-border) !important;
    color: var(--ui-btn1-text) !important; }
  .task-card:is(.is-running, .is-paused) .task-timer > .tbtn:first-of-type > svg { color: var(--ui-btn1-text) !important; }

  /* 6. проект — вторая строка внутри .task-timer__info, не отдельный блок под всей строкой */
  .task-card__project { font-size: 11px; color: var(--ui-muted); line-height: 1.2; }

  /* состояния — независимы, могут гореть одновременно */
  .task-card.is-running {
    border-left: 3px solid var(--ui-brand);
    padding-left: 7px;
    box-shadow: inset 0 0 40px var(--ui-glow-brand);
  }
  .task-card.is-late {
    border-color: var(--ui-danger);
    box-shadow: inset 0 0 30px var(--ui-glow-danger);
  }
  .task-card.is-running.is-late {
    box-shadow: inset 0 0 30px var(--ui-glow-danger), inset 0 0 40px var(--ui-glow-brand);
  }
}

/* Замок номера счёта/акта в лиде (leads.html, renderNoLocks): класс .is-on ставит JS.
   Значок красит роль .ibtn > svg с !important, поэтому цвет span не доходил до него — перебиваем на самом svg. */
.ibtn.no-lock > svg { color: var(--ui-tx-3) !important; opacity: .7; }
/* Включённый замок — синяя заливка с белым значком (22.10.2026): раньше от выключенного отличался только цветом линии. */
.ibtn.no-lock.is-on { background: var(--ui-brand) !important; border-radius: 6px; }
.ibtn.no-lock.is-on > svg { color: #fff !important; opacity: 1; fill: currentColor; }
.ibtn.no-lock.is-on > svg * { fill: currentColor; }

/* Кнопки таймера в таблице задач на десктопе (tasks.html, tmBtn): роль .tbtn, 24px.
   .is-active — кнопка текущего состояния (Пауза / Продолжить), заливка токенами --ui-btn1-*, как в мобильной карточке;
   .is-stop — «Завершить», красная через --ui-danger. !important — роль .tbtn из /theme.css красит с !important. */
.tm-btns > .tbtn { width: 24px; height: 24px; min-height: 0; padding: 0; vertical-align: middle;
  display: inline-flex; align-items: center; justify-content: center; }
.tm-btns > .tbtn > svg { width: 13px; height: 13px; pointer-events: none; }
.tm-btns > .tbtn.is-active { background: var(--ui-btn1-bg) !important; border-color: var(--ui-btn1-border) !important;
  color: var(--ui-btn1-text) !important; }
.tm-btns > .tbtn.is-active > svg { color: var(--ui-btn1-text) !important; }
.tm-btns > .tbtn.is-stop { color: var(--ui-danger) !important;
  border-color: color-mix(in srgb, var(--ui-danger) 45%, transparent) !important; }
.tm-btns > .tbtn.is-stop > svg { color: var(--ui-danger) !important; }

/* =========================================================================
   КАРТОЧКА ПРИВЫЧКИ (.hab-card) — новый вид виджета «Мои привычки» (15.08.2026)
   Заменяет старую missionCard() в medcard_habits.js. Согласовано по PNG-мокапу:
   иконка (спрайт Lucide, ADR-095) + название/подпись/строка метрик слева,
   плашка «Сегодня» + кольцо общего прогресса цели справа, ряд дней Пн..Вс
   с 3 состояниями (полностью/частично/пусто) и ряд круглых action-кнопок
   (статистика/сдаться/+результат, опционально правка в первые 24ч — badge «24»).
   Все цвета/радиусы — токены темы, литералов нет (см. правило ui.css выше).
   ========================================================================= */
.hab-card{
  position:relative; /* якорь для .hab-chev — шеврон сворачивания в правом верхнем углу */
  background:var(--ui-card-bg,#141414); border:1px solid var(--ui-card-border,#262626);
  border-radius:var(--ui-card-radius,14px); padding:18px 20px; margin-bottom:14px;
}

/* =========================================================================
   «МЕСТО» — общий компонент ввода и показа локации (23.09.2026).
   Разметку и поведение даёт place-field.js (window.PlaceField), здесь только вид.
   Подключён в трекере привычек (модалка результата + история миссии) и во вкладке
   «Жизнь» (модалка момента + лента). Своё поле места на странице больше не верстаем.

   Почему textarea, а не input: длинный адрес из OSM («Beach Bar, …, 46628, Египет»)
   в однострочном поле обрезался за правым краем — не было видно, что записалось.
   Высоту считает pfGrow() в JS: CSS этого не умеет, field-sizing:content поддержан
   ещё не везде.

   Геометрия и цвет — только токены темы. Кнопкам внутри локального CSS не пишем:
   вид приезжает от .tbtn/.ibtn из btnCss(). Единственное исключение — зона тапа
   иконочной кнопки, и она задаётся ТОЛЬКО через min-width/min-height: иконочная роль
   объявляет width/height:auto !important, обычные width/height не сработают.
   ========================================================================= */
/* Шапка поля: слева пин и подпись, справа ОДНИМ РЯДОМ все действия — поиск,
   копирование, «Определить заново».

   Раньше пин, лупа и копирование стояли ВНУТРИ поля, и строка ввода делилась на три
   колонки. На телефоне длинный адрес («Siva Sharm Resort & Spa, Аль-Набк, Шарм Эль Шейх,
   Южный Синай, 46628, Египет») получал посередине полосу чуть шире половины поля и
   разъезжался на пять строк, а слева под пином и справа под двумя кнопками висел воздух
   (жалоба Константина, скрин 28.08.2026). Теперь под текст идёт ВСЯ ширина поля, и
   растягивать его больше нечем.

   flex-wrap — чтобы на узком экране ряд действий уезжал на свою строку целиком, а не
   сжимал подпись; margin-left:auto держит его у правого края в обоих случаях. */
.pf-head { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:6px; }
.pf-head-l { display:flex; align-items:center; gap:7px; min-width:0; flex:1 1 auto; }
.pf-head-r { display:flex; align-items:center; gap:2px; flex:0 0 auto; margin-left:auto; }
.pf-head-l > svg {
  width:15px; height:15px; flex-shrink:0; fill:none; stroke-width:var(--ui-ico-stroke,2);
  stroke-linecap:round; stroke-linejoin:round; color:var(--ui-ico,#e8e8e8); opacity:var(--ui-ico-opacity,.55);
  transition:color .15s, opacity .15s;
}
/* Подсветка пина при вводе осталась, только слушаем теперь весь блок: поле и пин
   больше не один элемент, :focus-within у .pf-field до шапки не достаёт. */
.pf-block:focus-within .pf-head-l > svg { color:var(--ui-brand,#00a0ff); opacity:1; }
.pf-label { font-size:var(--ui-inp-lbl-fs,13px); color:var(--ui-inp-lbl,#8a8a8a); }
/* Зона тапа в шапке — --ui-tap-sm (30px), а не 44: 44 разогнали бы строку с подписью
   вдвое. Задаётся только через min-*, у иконочной роли width/height прибиты !important. */
.pf-head-r > .ibtn {
  flex-shrink:0; min-width:var(--ui-tap-sm,30px); min-height:var(--ui-tap-sm,30px);
  display:inline-flex; align-items:center; justify-content:center;
}
.pf-field {
  display:flex; align-items:flex-start; min-width:0; box-sizing:border-box;
  background:var(--ui-inp-bg,#1a1a1a); border:1px solid var(--ui-inp-border,#333);
  border-radius:var(--ui-inp-radius,8px); padding:0 var(--ui-inp-px,11px);
  min-height:var(--ui-field-h,44px);
  transition:border-color .15s ease, box-shadow .15s ease;
}
.pf-field:focus-within {
  border-color:var(--ui-inp-focus,var(--ui-brand,#00a0ff));
  box-shadow:0 0 0 3px color-mix(in srgb, var(--ui-brand,#00a0ff) 18%, transparent);
}
/* фон/рамку/паддинг у textarea снимаем — их даёт контейнер выше, а не inpCss():
   селектор на класс перебивает :where() из темы, тот же приём, что у .hab-icofield input */
.pf-field textarea {
  flex:1 1 auto; min-width:0; display:block; box-sizing:border-box;
  background:transparent; border:none; outline:none; resize:none; overflow:hidden;
  padding:12px 0; margin:0; color:var(--ui-inp-text,#fff); font-family:inherit;
  font-size:var(--ui-inp-fs,13.5px); font-weight:400; line-height:1.42;
}
.pf-field textarea::placeholder { color:var(--ui-inp-ph,#666); }
.pf-note { font-size:11px; color:var(--ui-muted,#6a6a6a); margin-top:4px; min-height:14px; }
.pf-chips:not(:empty) { margin-top:8px; }
.pf-chips-title { font-size:11px; color:var(--ui-muted,#6a6a6a); margin-bottom:6px; }
.pf-chips-list { display:flex; flex-direction:column; gap:6px; min-width:0; }
/* Недавних мест хранится пять (MAX в place-field.js), но развёрнутым списком они
   занимали пол-экрана телефона. На виду две последние, остальные — под «Ещё N»
   (renderChips/pfMore). Список и кнопка — соседи, класс .on ставится обоим сразу:
   разметку перерисовывает renderChips целиком, состояние живёт в STATE поля. */
.pf-chips-more { margin-top:6px; }
.pf-chips-more:not(.on) { display:none; }
.pf-chip {
  font-family:inherit;
  display:flex; align-items:center; gap:7px; min-width:0; width:100%; box-sizing:border-box;
  min-height:var(--ui-tap-sm,30px); padding:8px 11px; cursor:pointer; text-align:left;
  border-radius:var(--ui-radius,8px); font-size:12.5px; font-weight:500;
  background:var(--ui-inp-bg,#1a1a1a); border:1px solid var(--ui-inp-border,#333);
  color:var(--ui-muted,#8b8b8b); transition:border-color .15s, color .15s;
}
.pf-chip:hover { border-color:var(--ui-brand,#00a0ff); color:var(--ui-inp-text,#e8e8e8); }
/* «Рядом» (25.09.2026) — предложенное по свежим координатам место из «моих», акцентным
   цветом, чтобы отличалось от обычного списка ниже. */
.pf-chip-near { border-color:var(--ui-brand,#00a0ff); color:var(--ui-brand,#00a0ff);
  background:color-mix(in srgb, var(--ui-brand,#00a0ff) 10%, transparent); }
.pf-chip-near b { font-weight:600; }
.pf-chip > svg {
  width:13px; height:13px; flex-shrink:0; fill:none; stroke-width:var(--ui-ico-stroke,2);
  stroke-linecap:round; stroke-linejoin:round; color:currentColor; opacity:.7;
}
.pf-chip > span { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Крестик «убрать из недавних» (30.08.2026): адрес занимает почти всю строку, крестик —
   узкую колонку у правого края со своей зоной тапа. Подстановка и удаление — разные
   мишени, поэтому в pfForget стоит stopPropagation. Кнопка без роли из BTN_ROLES
   (не .ibtn), чтобы btnCss не тянул сюда свои размеры и !important. */
.pf-chip-x {
  flex:0 0 auto; margin:-8px -7px -8px 0; padding:0; background:none; border:none;
  cursor:pointer; min-width:var(--ui-tap-sm,30px); min-height:var(--ui-tap-sm,30px);
  display:inline-flex; align-items:center; justify-content:center;
  color:currentColor; opacity:.55; transition:color .15s, opacity .15s;
}
.pf-chip-x:hover { color:var(--ui-danger,#f87171); opacity:1; }
.pf-chip-x > svg {
  width:14px; height:14px; fill:none; stroke-width:var(--ui-ico-stroke,2);
  stroke-linecap:round; stroke-linejoin:round; color:currentColor;
}

/* «Ещё N» / «Свернуть» — такая же строка, как места над ней (.pf-chip), а не мелкая
   кнопка: раньше это был .tbtn.btn-sm, и шеврон в нём приезжал размером --ui-btn-ico,
   то есть меньше 13px — в него было не попасть пальцем. Здесь значок 20px и вся строка
   в ширину списка. Правила идут ПОСЛЕ .pf-chip > svg: специфичность равная, решает порядок.
   Кнопка не берёт ни одной роли из BTN_ROLES (ни .btn, ни .tbtn, ни .ibtn), поэтому
   btnCss её не трогает и драки за !important нет. */
.pf-more { justify-content:center; min-height:38px; margin-top:6px; color:var(--ui-inp-text,#c9c9c9); }
.pf-more > svg { width:20px; height:20px; opacity:.9; transition:transform .15s; }
.pf-more.on > svg { transform:rotate(180deg); }
.pf-more > span { flex:0 0 auto; }

/* Автоподсказки при вводе места (07.10.2026, #444) — список ПОД полем в потоке (не absolute: шторка
   .pf-sheet-body режет overflow), до 5 строк, подпись провайдера внизу (атрибуция обязательна).
   Только токены --ui-*: светлая и тёмная тема приходят из themeVars() (/theme.css), литералов цвета нет
   (запасные значения в var() — как у соседних .pf-*). Класс .is-on — строка под стрелками/наведением. */
.pf-sug { display:flex; flex-direction:column; min-width:0; margin-top:6px; overflow:hidden; box-sizing:border-box;
  background:var(--ui-inp-bg,#1a1a1a); border:1px solid var(--ui-inp-border,#333); border-radius:var(--ui-inp-radius,8px); }
.pf-sug[hidden] { display:none; }
.pf-sug-i { display:flex; align-items:center; gap:7px; min-width:0; min-height:var(--ui-tap-sm,30px); padding:8px 11px;
  cursor:pointer; font-size:12.5px; color:var(--ui-inp-text,#e8e8e8); transition:background .12s; }
.pf-sug-i + .pf-sug-i { border-top:1px solid var(--ui-inp-border,#333); }
.pf-sug-i:hover, .pf-sug-i.is-on { background:color-mix(in srgb, var(--ui-brand,#00a0ff) 12%, transparent); }
.pf-sug-i > svg { width:13px; height:13px; flex-shrink:0; fill:none; stroke-width:var(--ui-ico-stroke,2);
  stroke-linecap:round; stroke-linejoin:round; color:var(--ui-muted,#8b8b8b); opacity:.8; }
.pf-sug-i > span { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pf-sug-attr { padding:4px 11px; text-align:right; font-size:10px; letter-spacing:.02em; color:var(--ui-muted,#6a6a6a);
  border-top:1px solid var(--ui-inp-border,#333); }

/* строка «место» под записью в списке (история миссии, лента моментов):
   зона тапа --ui-tap-sm, а не 44px — 44 разогнали бы список вдвое */
.pf-row { display:flex; align-items:center; gap:6px; min-width:0; margin-top:2px; font-size:12px; color:var(--ui-muted,#6a6a6a); }
.pf-row > svg {
  width:12px; height:12px; flex-shrink:0; fill:none; stroke-width:var(--ui-ico-stroke,2);
  stroke-linecap:round; stroke-linejoin:round; color:currentColor; opacity:.8;
}
.pf-row > span { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* =========================================================================
   «МЕСТО» — свёрнутая строка + шторка сверху (24.09.2026, PlaceField.compactHtml/
   openSheet/closeSheet). Раньше страница держала поле «Место» развёрнутым прямо в теле
   модалки — на телефоне это регулярно выталкивало кнопку сохранения за экран (жалоба
   Константина, трекер привычек). Теперь везде, где подключён place-field.js, страница
   может вместо html() вставить compactHtml(): одна строка «пин + адрес + изменить»,
   тап открывает те же поле/чипы в отдельной шторке (высота — общая, от --ui-sheet-top) — топ-10 своих мест сразу,
   без «Ещё N». Названия классов — pf-fieldrow и pf-sheet-* — специально НЕ переиспользуют
   .hrs-* трекера привычек: тот стиль локальный (habits.html), этот общий на все страницы.
   ========================================================================= */
/* width:100% + overflow:hidden ЯВНО на самой строке (25.09.2026, второй заход на ту же
   жалобу — код и так был верный, но подстраховка не помешает: если родитель когда-нибудь
   даст этой строке auto-ширину вместо 100%, обрезание всё равно сработает на этом уровне,
   а не только через min-width:0 у __t). */
/* min-width:0 (27.09.2026, ERR — скрин Ижевск): строка живёт flex-item'ом в колонке
   .edit-box (диалог правки записи дневника). У flex-item по умолчанию min-width:auto,
   и на кросс-оси (ширина в column-контейнере) он растягивается ДО min-content адреса,
   а не до ширины родителя — .pf-fieldrow__t внутри при этом честно ставил ellipsis, но
   сама строка вылезала за карточку целиком (тот же класс бага, что чинили в .lf-sheet,
   см. ADR-148/149). width:100%+overflow:hidden не спасали: это ограничение уже ПОСЛЕ
   того, как flex отвёл строке слишком широкий бокс. */
.pf-fieldrow { display:flex; align-items:center; gap:10px; min-height:44px; padding:10px 0; cursor:pointer; width:100%; max-width:100%; min-width:0; box-sizing:border-box; overflow:hidden; }
.pf-fieldrow > svg {
  width:18px; height:18px; flex:0 0 auto; fill:none; stroke:var(--ui-tx-2,#8b8b8b);
  stroke-width:var(--ui-ico-stroke,2); stroke-linecap:round; stroke-linejoin:round;
}
.pf-fieldrow__t { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--ui-tx,#e8e8e8); font-size:13.5px; }
/* «изменить» как чип, а не голый текст (25.09.2026, жалоба Константина): радиус —
   ТОЛЬКО токен платформы --ui-radius из /set, свой R не пишем. */
.pf-fieldrow__v {
  font-size:12.5px; color:var(--ui-brand,#00a0ff); flex:0 0 auto;
  padding:4px 10px; border-radius:var(--ui-radius,8px);
  background:color-mix(in srgb, var(--ui-brand,#00a0ff) 12%, transparent);
}

/* Высота — общая для всех шторок (27.09.2026): от --ui-sheet-top до низа экрана, а не 88vh. */
.pf-sheet {
  background:var(--ui-sheet-bg,#1c1c1e); border-radius:var(--ui-sheet-radius,22px) var(--ui-sheet-radius,22px) 0 0; width:100%; max-width:520px;
  height:var(--ui-sheet-h-vh); height:var(--ui-sheet-h);
  box-sizing:border-box; display:flex; flex-direction:column; overflow:hidden;
}
.pf-sheet-top { padding:10px 18px 14px; flex-shrink:0; border-bottom:0.5px solid color-mix(in srgb, var(--ui-tx, #fff) 8%, transparent); /* 29.09.2026: светлая тема */ }
.pf-sheet-handle { width:36px; height:4px; border-radius:2px; background:var(--ui-grip,#4a4a4a); margin:0 auto 14px; } /* 29.09.2026: ручка на --ui-grip */
.pf-sheet-head { display:flex; align-items:center; gap:12px; }
.pf-sheet-head__ico {
  width:40px; height:40px; border-radius:12px; background:var(--ui-brand,#00a0ff);
  display:flex; align-items:center; justify-content:center; flex:0 0 auto;
}
.pf-sheet-head__ico svg { width:20px; height:20px; fill:none; stroke:#fff; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
.pf-sheet-head__t { display:block; font-size:var(--ui-sheet-title-fs,14px); font-weight:600; color:var(--ui-tx,#e8e8e8); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pf-sheet-head__s { display:block; font-size:12.5px; color:var(--ui-tx-2,#8b8b8b); margin-top:2px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pf-sheet-x { margin-left:auto; background:none; border:none; color:var(--ui-tx-2,#8b8b8b); cursor:pointer; padding:6px; flex:0 0 auto; }
.pf-sheet-x svg { width:20px; height:20px; display:block; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; }
.pf-sheet-body { padding:12px 18px calc(18px + env(safe-area-inset-bottom)); overflow-y:auto; flex:1; }
.pf-row > .ibtn {
  flex-shrink:0; min-width:var(--ui-tap-sm,30px); min-height:var(--ui-tap-sm,30px);
  display:inline-flex; align-items:center; justify-content:center;
}

/* =========================================================================
   «СВОДКА» — общий компонент модалки-статистики (22.08.2026), образец: дневник
   (diary.html). Переиспользуется в «Жизни» (medcard_life.js) — одинаковый вид
   hero-плашки/плиток/списков/баров для любого раздела со своей статистикой.
   Цвета — ТОКЕНЫ --ui-* (29.08.2026, ADR-142): раньше тут стояли литералы, потому что
   компонент жил только в тёмной теме, и вкладка «Сводка» в «Жизни» в светлой теме
   осталась бы чёрной заплатой. Фолбэки в var() — прежние литералы, поэтому в тёмной
   теме вид не изменился. Новых литералов сюда не добавлять: тема настраивается в /set.
   Исключение — hero-плашка и заливка баров: это брендовая поверхность, белый текст
   на ней читается в обеих темах, и она сознательно одинаковая.
   ========================================================================= */
.stats-overlay { position:fixed; inset:0; z-index:99000; display:none; align-items:flex-start; justify-content:center;
  background:rgba(4,5,7,.72); -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  padding:0; overflow-y:auto; }
.stats-overlay.on { display:flex; }
.stats-card { width:100%; max-width:520px; min-height:100%; background:var(--ui-bg,#0b0d10); position:relative; }
@media (min-width:560px) { .stats-card { min-height:auto; margin:34px 0 60px; border-radius:20px; border:1px solid var(--ui-line,#242830); box-shadow:var(--ui-shadow-lg, 0 16px 40px -8px rgba(0,0,0,.35)); } }
.stats-head { position:sticky; top:0; z-index:2; display:flex; align-items:center; justify-content:space-between; padding:16px 18px 6px;
  background:var(--ui-bg,#0b0d10); }
.stats-head h2 { font-size:17px; margin:0; font-weight:700; color:var(--ui-tx,#e8eaed); }
.stats-close { width:32px; height:32px; border-radius:50%; border:1px solid var(--ui-line,#242830); background:var(--ui-surface,#15181c); color:var(--ui-tx-2,#8a909a); display:flex; align-items:center; justify-content:center; cursor:pointer; font-size:16px; line-height:1; }
.stats-close:hover { color:var(--ui-tx,#e8eaed); border-color:var(--ui-tx-3,#3a4048); }
.stats-body { padding:6px 18px 30px; display:flex; flex-direction:column; gap:14px; }
/* Плоский брендовый фон без градиента и без свечения (08.09.2026). Раньше здесь был
   диагональный градиент синий→фиолетовый плюс белый блик радиалкой в правом верхнем
   углу и тень-подсветка на 34px. Это украшение ничего не сообщало: герой уже выделен
   размером числа и площадью, а фиолетовый #7a5cff — единственный цвет на платформе,
   не входящий в палитру. Тень убрана: герой лежит в потоке, ни над чем не висит. */
.stats-hero { border-radius:12px; padding:22px 20px; background:var(--ui-brand,#00a0ff);
  position:relative; overflow:hidden; }
.stats-hero-top { font-size:13px; font-weight:700; color:rgba(255,255,255,.86); text-transform:uppercase; letter-spacing:.06em; margin-bottom:10px; position:relative; }
.stats-hero-grid { display:flex; align-items:flex-end; justify-content:space-between; gap:14px; position:relative; flex-wrap:wrap; }
.stats-hero-num { font-size:56px; font-weight:800; line-height:1; color:#fff; letter-spacing:-.02em; }
.stats-hero-sub { font-size:12.5px; color:rgba(255,255,255,.78); margin-top:4px; }
.stats-hero-side { display:flex; flex-direction:column; gap:10px; }
/* .is-row — пункты в ряд, а не колонкой (сводка «Секса»: их 3–4 и они короткие).
   Был инлайновый style в sex.js; вынесен сюда, чтобы мобильное правило ниже могло его
   перебить обычной специфичностью, без !important. */
.stats-hero-side.is-row { flex-flow:row wrap; gap:12px 26px; }
.stats-hero-item { display:flex; align-items:center; gap:8px; color:#fff; }
.stats-hero-item .n { font-size:19px; font-weight:800; }
.stats-hero-item .l { font-size:11.5px; color:rgba(255,255,255,.78); }
.stats-hero-item svg { width:16px; height:16px; opacity:.9; flex:0 0 auto; }
.stats-grid2 { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
/* Плитка в ДВЕ строки: значок и число рядом, подпись под ними во всю ширину
   (29.08.2026). Раньше было три строки — значок, число, подпись — и плитка занимала
   лишнюю высоту на пустом месте. Раскладка сделана через flex-wrap на самой плитке,
   без обёрток в разметке: тот же DOM из трёх детей рисуют и дневник, и «Жизнь». */
.stats-tile { background:var(--ui-surface,#15181c); border:1px solid var(--ui-line,#242830); border-radius:12px; padding:14px 16px;
  display:flex; flex-wrap:wrap; align-items:center; gap:0 12px; }
/* Значок без цветной плашки (08.09.2026): был квадрат 38×38 с радиусом 11 и заливкой
   rgba(0,160,255,.14). Плашка добавляла плитке вес, которого у неё нет по смыслу —
   главное в плитке число, а не иконка. Осталась сама иконка брендовым цветом. */
.stats-tile .icon { width:20px; height:20px; color:var(--ui-brand,#00a0ff); display:flex; align-items:center; justify-content:center; flex:0 0 auto; }
.stats-tile .icon svg { width:20px; height:20px; }
.stats-tile .num { font-size:30px; font-weight:800; letter-spacing:-.02em; line-height:1; color:var(--ui-tx,#e8eaed); }
.stats-tile .lbl { flex:1 0 100%; font-size:12px; line-height:1.35; color:var(--ui-tx-2,#8a909a); margin-top:9px; }
.stats-section-title { font-size:12px; color:var(--ui-tx-2,#8a909a); text-transform:uppercase; letter-spacing:.06em; margin:4px 0 -4px; }
.stats-list { background:var(--ui-surface,#15181c); border:1px solid var(--ui-line,#242830); border-radius:12px; overflow:hidden; }
.stats-list .row { display:flex; align-items:center; justify-content:space-between; padding:12px 14px; font-size:14px; }
.stats-list .row + .row { border-top:1px solid var(--ui-line,#242830); }
.stats-list .row .k { color:var(--ui-tx,#e8eaed); }
.stats-list .row .v { color:var(--ui-tx-2,#8a909a); font-weight:600; }
.stats-bars { display:flex; flex-direction:column; gap:9px; }
.stats-bar-row { display:flex; align-items:center; gap:10px; font-size:12.5px; }
.stats-bar-row .bl { width:120px; flex:0 0 auto; color:var(--ui-tx-2,#8a909a); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* .is-wide — ряды с длинными подписями (адреса локаций в сводке «Секса»). Раньше ширину
   ставил инлайновый style из sex.js; вынесена сюда, чтобы мобильный блок ниже перебивал
   её обычной специфичностью, без !important. */
.stats-bar-row.is-wide .bl { width:170px; }
.stats-bar-track { flex:1; height:8px; border-radius:5px; background:var(--ui-bg,#0b0d10); overflow:hidden; }
.stats-bar-fill { height:100%; border-radius:5px; background:var(--ui-brand,#00a0ff); }
.stats-bar-row .bv { width:38px; text-align:right; flex:0 0 auto; color:var(--ui-tx,#e8eaed); font-weight:600; }
.stats-empty { color:var(--ui-tx-2,#8a909a); text-align:center; padding:40px 0; font-size:14px; }
/* Сводка, развёрнутая НА СТРАНИЦЕ (вкладка «Сводка» в «Жизни»), а не в модалке 520px:
   плитки в четыре колонки и разделы в три. В модалке эти модификаторы не ставятся,
   и она остаётся прежней — двухколоночной. */
.stats-grid2.stats-wide { grid-template-columns:repeat(4, minmax(0, 1fr)); }
.stats-cols3 { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:14px; align-items:start; }
@media (max-width:900px) {
  .stats-grid2.stats-wide { grid-template-columns:1fr 1fr; }
  .stats-cols3 { grid-template-columns:1fr; }
}
/* ТЕЛЕФОН (02.09.2026). Две поломки, одинаковые во всех трёх сводках — дневник, «Жизнь»,
   «Секс», — поэтому чинятся здесь, у самого компонента, а не на странице:
   1) метка бара шире шкалы. На 390px строка занимает 120px (у .is-wide — 170px) под
      подпись + 38px под число, шкале остаётся ~104px: подпись длиннее столбика, сравнивать
      нечего. Кладём подпись и число первой строкой, шкалу — второй, во всю ширину.
   2) hero: число 56px и боковой ряд из 3–4 пунктов не делят 350px. Число мельче,
      пункты — сеткой в две колонки, длинные подписи режутся многоточием. */
@media (max-width:560px) {
  .stats-bar-row { flex-wrap:wrap; gap:5px 10px; }
  .stats-bar-row .bl { width:auto; flex:1 1 auto; order:1; color:var(--ui-tx,#e8eaed); }
  .stats-bar-row.is-wide .bl { width:auto; }
  .stats-bar-row .bv { order:2; }
  .stats-bar-row .stats-bar-track { order:3; flex:1 0 100%; }
  .stats-hero { padding:20px 18px; }
  .stats-hero-num { font-size:44px; }
  .stats-hero-grid { display:block; }
  .stats-hero-side, .stats-hero-side.is-row { display:grid; grid-template-columns:1fr 1fr;
    gap:12px 14px; margin-top:14px; padding-top:14px;
    border-top:1px solid rgba(255,255,255,.20); }
  .stats-hero-item { min-width:0; }
  .stats-hero-item .l { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
}

/* =========================================================================
   «ГЛОБУС МЕСТ» — карта посещённых точек в сводке «Жизни» (29.08.2026).
   Рисует medcard_life.js по mapPlaces из /api/profile/me/life/stats: точки суши по
   грубой маске 10x10 градусов, ортографическая проекция, метка = место, размер по
   числу посещений. Сам шар — на canvas, а не в SVG: 400+ узлов DOM на каждом кадре
   вращения подвешивают вкладку на телефоне.
   Кнопкам скорости здесь ничего не задаём — это .ibtn, вид приезжает из /theme.css.
   ========================================================================= */
/* Ширина глобуса (03.09.2026). Боковая колонка ужата с 340 до 300, а порог, за которым
   список уезжает ПОД шар, поднят с 900 до 1140: на типовом ноутбуке (1280-1440) карта
   получает всю ширину карточки, а не две трети. Вместе с потолком холста в 820 px
   (glResize в medcard_life.js) радиус шара вырос с 219 до ~270 css-px — это 24 км на
   пиксель вместо 29. Само по себе это мало что решает (25 км всё равно один пиксель),
   но каждый пиксель радиуса — это пиксель и на любом приближении тоже. */
.gl-wrap { display:grid; grid-template-columns:minmax(0, 1fr) minmax(0, 300px); gap:20px; align-items:start; }
.gl-stage { position:relative; border-radius:12px; border:1px solid var(--ui-line,#242830); padding:4px;
  background:var(--ui-bg,#0b0d10);
  cursor:grab; touch-action:none; user-select:none; -webkit-user-select:none; }
.gl-stage:active { cursor:grabbing; }
.gl-stage canvas { display:block; margin:0 auto; }
/* Две группы кнопок в одной строке: вращение и масштаб. Обязательно flex-wrap — на 360px
   восемь элементов в ряд не помещаются, и без переноса вторая группа уезжала бы за край
   карточки (та же ловушка, что с рядом дней в .hab-card). */
.gl-ctl { display:flex; align-items:center; justify-content:center; gap:10px 14px;
  flex-wrap:wrap; margin-top:10px; }
.gl-grp { display:inline-flex; align-items:center; gap:6px; padding:3px 5px; border-radius:8px;
  background:var(--ui-surface-3,#111); border:1px solid var(--ui-line,#242830); }
.gl-speed { min-width:56px; text-align:center; font-size:12px; font-weight:700;
  color:var(--ui-tx,#e8eaed); font-variant-numeric:tabular-nums; }
.gl-hint { display:flex; align-items:center; justify-content:center; gap:7px; margin-top:8px;
  font-size:11.5px; color:var(--ui-tx-3,#6a6a6a); }
.gl-hint svg { width:13px; height:13px; flex:0 0 auto; }
.gl-side { display:flex; flex-direction:column; gap:12px; min-width:0; }
.gl-sel { border:1px solid var(--ui-line,#242830); border-radius:12px; padding:14px 15px;
  background:var(--ui-surface-2,#1a1a1a); display:flex; flex-direction:column; gap:10px; }
.gl-sel-t { display:flex; align-items:center; gap:9px; font-size:16px; font-weight:700; color:var(--ui-tx,#e8eaed); }
.gl-sel-t svg { width:18px; height:18px; flex:0 0 auto; color:var(--ui-brand,#00a0ff); }
.gl-chips { display:flex; flex-wrap:wrap; gap:7px; }
.gl-chip { display:inline-flex; align-items:center; gap:6px; padding:5px 11px; border-radius:16px; font-size:12px;
  background:var(--ui-surface-3,#111); border:1px solid var(--ui-line,#242830); color:var(--ui-tx-2,#8a909a); }
.gl-chip b { color:var(--ui-tx,#e8eaed); font-weight:700; font-variant-numeric:tabular-nums; }
/* Чип с координатами — ссылка на настоящую карту. Подчёркивания не даём: в ряду
   одинаковых чипов оно читалось бы как поломка вёрстки, а не как ссылка; за неё
   отвечают цвет рамки на наведении и курсор. */
a.gl-chip { text-decoration:none; font-variant-numeric:tabular-nums; cursor:pointer; }
a.gl-chip:hover { color:var(--ui-brand,#00a0ff); border-color:var(--ui-brand,#00a0ff); }
.gl-list { display:flex; flex-direction:column; gap:2px; }
.gl-row { display:flex; align-items:center; gap:10px; padding:8px 10px; border-radius:9px; font-size:13px;
  cursor:pointer; border:1px solid transparent; min-height:var(--ui-tap-sm,30px); box-sizing:border-box; }
.gl-row:hover { background:var(--ui-surface-2,#1a1a1a); }
.gl-row.on { background:rgba(0,160,255,.10); border-color:rgba(0,160,255,.32); }
.gl-row .dot { width:8px; height:8px; border-radius:50%; flex:0 0 auto; background:var(--ui-brand,#00a0ff); }
.gl-row .nm { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--ui-tx,#e8eaed); }
.gl-row .ct { flex:0 0 auto; color:var(--ui-tx-2,#8a909a); font-weight:600; font-variant-numeric:tabular-nums; }
#glZoom { min-width:38px; }
@media (max-width:1140px) { .gl-wrap { grid-template-columns:1fr; } }
@media (max-width:768px) { .gl-row { min-height:var(--ui-tap,44px); } }
.hab-card.is-dim{ opacity:.55; }
/* Разметка карточки — повторяет согласованный макет (скрин 16:32, 15.08.2026).
   Сетка 2 колонки: слева сверху вниз — шапка (иконка + название/подпись), строка метрик
   (ритм/темп/прогноз), ряд дней Пн..Вс; справа два кольца друг над другом — крупное
   «сегодня» (% + дата) вверху и меньшее «цель» (только %) под ним. Отдельной строкой
   внизу на всю ширину — действия: круглые иконки слева, широкая кнопка «+ Результат»
   справа. Цвета/радиусы — только токены темы (макет был в другой палитре, её не берём). */
/* Шапка карточки: иконка + название слева, кольцо цели справа, шеврон в углу.
   Раньше здесь был grid "1fr auto" на три ряда (шапка / метрики / неделя слева,
   два кольца справа). Он и ломался на телефоне: ряд дней (7×26 + 6×5 = 212) и
   кольцо (96 + зазор 10) не сжимаются НИ ПРИ КАКОМ min-width — у .hab-day
   min-content равен 26px, — поэтому на 390px карточке не хватало 2px, на 375
   семнадцати, на 360 тридцати двух, и кольца выезжали за её правый край.
   Теперь ряд дней — отдельной строкой на всю ширину, и в шапке остаётся
   ровно одно кольцо. ЛЮБОЙ новый ряд из элементов фиксированной ширины внутри
   карточки заводить так же: своей строкой, а не вторым треком грида. */
.hab-card__top{ display:flex; align-items:center; gap:10px; min-width:0; padding-right:34px; }
.hab-card__head{ flex:1 1 auto; display:flex; align-items:center; gap:12px; min-width:0; }
.hab-card__ico{
  flex-shrink:0; width:52px; height:52px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
}
.hab-card__ico svg{ width:24px; height:24px; color:#fff; fill:none; stroke-width:var(--ui-ico-stroke,2); stroke-linecap:round; stroke-linejoin:round; }
.hab-card__body{ flex:1 1 auto; min-width:0; }
.hab-card__title{ font-size:19px; font-weight:700; color:var(--ui-tx,#e8e8e8); line-height:1.25; }
.hab-card__sub{ font-size:13px; color:var(--ui-tx-2,#8b8b8b); margin-top:3px;
  font-variant-numeric:tabular-nums; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* «Всего: 61:18 мин · 2 миссии» — итог цепочки повторов, строка под .hab-card__sub (#277);
   переносится целиком, без многоточия — рядом с кольцом текст иначе обрезался */
.hab-card__chain{ font-size:12.5px; color:var(--ui-tx-3,#6a6a6a); margin-top:2px;
  font-variant-numeric:tabular-nums; white-space:normal; overflow-wrap:anywhere; }
/* .hab-card__metrics (строка «Ритм · Темп · Прогноз») удалена 24.08.2026: карточка
   печатает эти числа плитками .hab-tile — с единицей и базой, а не голым «+14».
   На /projects своя копия рецепта (.p-met), к этому классу она не привязана. */

/* Шеврон сворачивания — правый верхний угол карточки, зона тапа --ui-tap.
   Развёрнута — «крышей» вверх, свёрнута — вниз. Именно вверх/вниз, а не
   rotate(-90deg), как у .sb-group в сайдбаре и у «Истории» в модалке: там
   стрелка стоит вплотную к подписи и читается вместе с ней, здесь она одна
   в углу. Место под неё держит padding-right у .hab-card__top и .hab-short__row —
   без него кольцо и кнопка записи залезают под шеврон. */
.hab-chev{
  position:absolute; top:4px; right:4px; width:var(--ui-tap,44px); height:var(--ui-tap,44px);
  display:flex; align-items:center; justify-content:center;
  border:none; background:transparent; padding:0; cursor:pointer;
}
.hab-chev svg{
  width:18px; height:18px; color:var(--ui-tx3,#666); fill:none; stroke:currentColor;
  stroke-width:var(--ui-ico-stroke,2); stroke-linecap:round; stroke-linejoin:round;
  transition:color .15s, transform .18s;
}
.hab-chev:hover svg{ color:var(--ui-brand,#00a0ff); }
.hab-card:not(.is-short) .hab-chev svg{ transform:rotate(180deg); }

/* ===== СВЁРНУТАЯ КАРТОЧКА — только текущий день =====
   Остаётся то, ради чего экран открывают: сколько осталось сегодня, полоса
   «сделано / минимум / план» и кнопка записи. Цель, темп, ритм, неделя и
   последняя запись — за шевроном. 94px против 515px у развёрнутой. */
.hab-card.is-short{ padding:14px 16px 16px; }
.hab-short__row{ display:flex; align-items:center; gap:12px; min-width:0; padding-right:34px; }
.hab-short__sub{ font-size:13px; color:var(--ui-tx-2,#8b8b8b); margin-top:3px;
  font-variant-numeric:tabular-nums; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hab-short__sub b{ color:var(--ui-tx,#e8e8e8); font-weight:700; font-size:15px; }
.hab-short__sub .is-ok{ color:var(--ui-ok,#4ade80); font-weight:700; }
.hab-quick{
  flex:0 0 auto; width:var(--ui-tap,44px); height:var(--ui-tap,44px); cursor:pointer;
  border-radius:var(--ui-radius,8px); display:flex; align-items:center; justify-content:center;
  background:color-mix(in srgb, var(--ui-brand,#00a0ff) 12%, transparent);
  border:1px solid color-mix(in srgb, var(--ui-brand,#00a0ff) 35%, transparent);
}
.hab-quick svg{ width:20px; height:20px; color:var(--ui-brand,#00a0ff); fill:none;
  stroke-width:2.5; stroke-linecap:round; stroke-linejoin:round; }

/* ===== СЕГОДНЯ — главный ответ карточки, числом =====
   Заменяет кольцо «сегодня», у которого в центре стояла дата: дуга показывала
   долю дневного плана, а сколько осталось — не показывал никто. */
.hab-today{ margin-top:14px; padding-top:12px; border-top:1px solid var(--ui-line,#1e1e1e); }
.hab-today__head{ display:flex; align-items:baseline; justify-content:space-between; gap:10px;
  font-size:11px; color:var(--ui-tx3,#666); text-transform:uppercase; letter-spacing:.05em; }
.hab-today__head .v{ font-size:12.5px; letter-spacing:0; text-transform:none;
  color:var(--ui-tx-2,#8b8b8b); font-variant-numeric:tabular-nums; }
.hab-today__head .v b{ color:var(--ui-tx,#e8e8e8); font-weight:700; }
.hab-today__hero{ margin-top:5px; font-size:14px; color:var(--ui-tx-2,#8b8b8b);
  display:flex; align-items:baseline; gap:7px; }
.hab-today__hero b{ font-size:30px; font-weight:800; letter-spacing:-.02em;
  color:var(--ui-tx,#e8e8e8); line-height:1; font-variant-numeric:tabular-nums; }
.hab-today__hero b.is-ok{ color:var(--ui-ok,#4ade80); }

/* полоса дня: заливка — факт, жёлтая засечка — минимум, по которому миссия
   уходит в «Под угрозой» (met.min_amount; до этого его знал только сервер) */
.hab-bar{ position:relative; height:10px; border-radius:5px; background:var(--ui-line,#1e1e1e);
  margin-top:11px; overflow:hidden; }
.hab-bar.is-short{ margin-top:12px; height:8px; }
.hab-bar__fill{ position:absolute; left:0; top:0; bottom:0; border-radius:5px;
  background:var(--ui-brand,#00a0ff); transition:width .3s; }
.hab-bar__fill.is-ok{ background:var(--ui-ok,#4ade80); }
.hab-bar__min{ position:absolute; top:-1px; bottom:-1px; width:2px; background:var(--ui-warn,#facc15); }
.hab-legend{ position:relative; height:14px; margin-top:5px; font-size:10.5px;
  color:var(--ui-tx3,#666); font-variant-numeric:tabular-nums; }
.hab-legend .l-now{ position:absolute; left:0; }
.hab-legend .l-min{ position:absolute; transform:translateX(-50%); color:var(--ui-warn,#facc15); }
.hab-legend .l-plan{ position:absolute; right:0; }

/* ===== ПЛИТКА-ВИДЖЕТ ПЛАТФОРМЫ (.ui-tiles / .ui-tile) =====
   Ритм / темп / прогноз в трекере привычек были первым потребителем, отсюда историческое
   имя .hab-*. Второй — сводка денег во вкладке «Финансы» карточки лида (04.09.2026).
   Копию рецепта в <style> страницы НЕ заводить: селекторы просто дописываются сюда через
   запятую, правило остаётся одно. Новое имя — .ui-tiles/.ui-tile, .hab-* оставлен рабочим.
   Число колонок — переменная --ui-tile-cols (2 по умолчанию), модификатор .is-3 ставит три:
   у плитки только подпись и число, они жмутся до 3 в строку даже на 360px, в отличие от
   чипов .frow с полем ввода (тем по-прежнему одна колонка на телефоне, ADR-088). */
.hab-tiles,.ui-tiles{ display:grid; grid-template-columns:repeat(var(--ui-tile-cols,3), minmax(0, 1fr));
  gap:var(--ui-tile-gap,8px); }
/* Трекеру привычек двойка прибита ЯВНО: --ui-tile-cols едет из /set (ключ ui_tile_cols) и
   меняет число колонок у .ui-tiles; без этой строки настройка молча перестроила бы и его
   карточки, где плитка «Темп» с длинной подписью в треть ширины не помещается.
   Отступ сверху тоже был только у .hab-tiles — оставлен как был. */
.hab-tiles{ --ui-tile-cols:2; margin-top:12px; }
/* Жёстко зафиксировать число колонок, не глядя на настройку: .is-2 / .is-3 */
.ui-tiles.is-2{ --ui-tile-cols:2; }
.ui-tiles.is-3{ --ui-tile-cols:3; }
.hab-tile,.ui-tile{ background:var(--ui-surface-2,#1a1a1a); border:1px solid var(--ui-card-border,#262626);
  border-radius:var(--ui-radius,8px); padding:9px 10px; min-width:0; }
.hab-tile.is-wide,.ui-tile.is-wide{ grid-column:1 / -1; }
.hab-tile__lbl,.ui-tile__lbl{ font-size:10.5px; text-transform:uppercase; letter-spacing:.05em; color:var(--ui-tx3,#666);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.hab-tile__val,.ui-tile__val{ margin-top:2px; font-size:16px; font-weight:700; color:var(--ui-tx,#e8e8e8);
  font-variant-numeric:tabular-nums; display:flex; align-items:baseline; gap:6px; flex-wrap:wrap; }
.hab-tile__val .u,.ui-tile__val .u{ font-size:12px; font-weight:500; color:var(--ui-tx-2,#8b8b8b); }
.hab-tile__val .d,.ui-tile__val .d{ font-size:13px; font-weight:700; }
.hab-tile__val .d.is-ok,.ui-tile__val .d.is-ok{ color:var(--ui-ok,#4ade80); }
.hab-tile__val .d.is-bad,.ui-tile__val .d.is-bad{ color:var(--ui-danger,#f87171); }
.hab-tile__sub,.ui-tile__sub{ margin-top:2px; font-size:11px; color:var(--ui-tx3,#666); line-height:1.35; }
/* Плитка «плохого» итога — тем же опасным цветом, что и остальные красные места платформы */
.ui-tile.is-bad{ background:rgba(248,113,113,.06); border-color:rgba(248,113,113,.28); }
.ui-tile.is-ok{ background:rgba(74,222,128,.06); border-color:rgba(74,222,128,.26); }

/* Последняя запись: правка на расстоянии одного тапа, остаток окна — числом.
   Раньше «исправить» жило только в свёрнутой «Истории» внутри модалки статистики. */
.hab-last{ margin-top:12px; display:flex; align-items:center; gap:8px; min-width:0;
  background:var(--ui-surface-2,#1a1a1a); border:1px solid var(--ui-card-border,#262626);
  border-radius:var(--ui-radius,8px); padding:0 6px 0 10px; min-height:var(--ui-tap,44px);
  font-size:12px; color:var(--ui-tx-2,#8b8b8b); }
.hab-last > svg{ width:14px; height:14px; flex:0 0 auto; color:var(--ui-tx3,#666); fill:none;
  stroke-width:var(--ui-ico-stroke,2); stroke-linecap:round; stroke-linejoin:round; }
.hab-last__txt{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; font-variant-numeric:tabular-nums; }
.hab-last__txt b{ color:var(--ui-tx,#e8e8e8); font-weight:700; }
.hab-last__win{ flex:0 0 auto; font-size:10.5px; color:var(--ui-tx3,#666);
  padding-right:4px; font-variant-numeric:tabular-nums; }

.hab-ring{ position:relative; flex:0 0 auto; width:76px; height:76px; }
.hab-ring svg{ width:100%; height:100%; transform:rotate(-90deg); }
.hab-ring circle{ fill:none; }
.hab-ring circle.track{ stroke:var(--ui-card-border,#262626); stroke-width:7; }
.hab-ring circle.val{ stroke:var(--ui-brand,#00a0ff); stroke-width:7; stroke-linecap:round; transition:stroke-dashoffset .3s; }
.hab-ring__txt{ position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:1px; }
.hab-ring__pct{ font-size:19px; font-weight:700; color:var(--ui-tx,#e8e8e8); line-height:1.1; font-variant-numeric:tabular-nums; }
/* подпись, что именно считает кольцо — без неё оно читается как прогресс дня
   (жалоба 15.08.2026: «почему планка 67%, если сделал 2 мин из 198») */
.hab-ring__cap{ font-size:9px; letter-spacing:.06em; text-transform:uppercase; color:var(--ui-tx3,#666); line-height:1.1; }
/* Модификаторов --goal/--today больше нет: кольцо на карточке ОДНО, «сегодня»
   считают числа в .hab-today (24.08.2026). .hab-ring__frac удалён вместе с ними —
   дробь показывалась только в убранном кольце дня. */

.hab-card__week{ margin-top:12px; min-width:0; }
.hab-week-days{ display:flex; justify-content:space-between; gap:5px; min-width:0; }
.hab-day{ display:flex; flex-direction:column; align-items:center; gap:7px; }
.hab-day__lbl{ font-size:11px; color:var(--ui-tx3,#666); }
.hab-day__mark{
  width:30px; height:30px; border-radius:50%; display:flex; align-items:center; justify-content:center;
  border:1.5px solid var(--ui-card-border,#333);
}
.hab-day__mark svg{ width:15px; height:15px; color:#fff; fill:none; stroke-width:2.5; stroke-linecap:round; stroke-linejoin:round; }
.hab-day__mark.is-full{ background:var(--ui-brand,#00a0ff); border-color:var(--ui-brand,#00a0ff); }
.hab-day__mark.is-partial{ background:var(--ui-warn,#facc15); border-color:var(--ui-warn,#facc15); }
.hab-day__mark.is-partial svg{ color:#3a2e00; }

/* нижняя строка на всю ширину: иконки-действия слева, кнопка «+ Результат» справа.
   Иконки без окружности (правка 15.08.2026) — только сам значок, крупнее, чтобы читался. */
/* Зона тапа — --ui-tap (44px), как у .pf-field и .pf-row: сам значок остаётся 26px,
   растёт только кликабельная область. До 24.08.2026 кнопка была 32×32, и на телефоне
   «статистика» и «сдаться» промахивались мимо пальца. Из-за 44px уменьшен gap: две
   кнопки по 44 с зазором 16 съедали ширину у «+ Результат». */
.hab-card__actions{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:12px; min-width:0; }
.hab-abtn{
  width:var(--ui-tap,44px); height:var(--ui-tap,44px); display:flex; align-items:center; justify-content:center;
  border:none; background:transparent; cursor:pointer; flex-shrink:0; position:relative; padding:0;
}
.hab-abtn svg{ width:26px; height:26px; color:var(--ui-brand,#00a0ff); fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; transition:color .15s, transform .1s; }
.hab-abtn:hover svg{ transform:scale(1.08); }
.hab-abtn.is-danger svg{ color:var(--ui-danger,#f87171); }
.hab-abtn.is-danger:hover svg{ color:var(--ui-danger,#f87171); }
.hab-abtn__badge{
  position:absolute; top:2px; right:1px; background:var(--ui-brand,#00a0ff); color:#fff;
  font-size:10px; font-weight:700; border-radius:9px; padding:1px 6px; line-height:1.4;
  border:2px solid var(--ui-card-bg,#141414);
}
.hab-btn-result{
  flex:1 1 150px; min-width:0; margin-left:6px; display:inline-flex; align-items:center; justify-content:center; gap:8px;
  height:52px; border-radius:8px; border:none; cursor:pointer;
  background:var(--ui-btn1-bg, var(--ui-brand,#00a0ff)); color:#fff; font-size:16px; font-weight:600;
  transition:background .15s;
}
.hab-btn-result svg{ width:18px; height:18px; color:#fff; fill:none; stroke-width:2.5; stroke-linecap:round; stroke-linejoin:round; }
.hab-btn-result:hover{ background:#31b6ff; }

/* иконка привычки в заголовке модалки просмотра (раньше там печатался эмодзи из m.icon) */
.hab-modal-ico{
  width:30px; height:30px; border-radius:50%; flex-shrink:0;
  display:inline-flex; align-items:center; justify-content:center;
}
.hab-modal-ico svg{ width:15px; height:15px; color:#fff; fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }

/* сетка выбора иконки — в модалке создания/правки и в отдельной модалке смены иконки
   (клик по иконке на карточке). Только id из общего спрайта Lucide, эмодзи больше нет. */
.hab-icogrid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(52px,1fr)); gap:8px; }
.hab-icopick{
  aspect-ratio:1; display:flex; align-items:center; justify-content:center; cursor:pointer;
  background:var(--ui-surface-2,#1a1a1a); border:1px solid var(--ui-card-border,#262626);
  border-radius:var(--ui-radius,10px); padding:0; transition:border-color .15s, background .15s;
}
.hab-icopick svg{ width:22px; height:22px; color:var(--ui-tx-2,#8b8b8b); fill:none; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
.hab-icopick:hover{ border-color:var(--ui-brand,#00a0ff); }
.hab-icopick:hover svg{ color:var(--ui-brand,#00a0ff); }
.hab-icopick.is-on{ border-color:var(--ui-brand,#00a0ff); background:color-mix(in srgb, var(--ui-brand,#00a0ff) 14%, transparent); }
.hab-icopick.is-on svg{ color:var(--ui-brand,#00a0ff); }
/* иконка на карточке кликабельна — открывает пикер */
.hab-card__ico{ cursor:pointer; }
/* Маскот-осьминог вместо символа спрайта (16.09.2026, /img/habiticons): картинка
   занимает весь контейнер, брендовая подложка снимается (синее на синем не читается). */
.hab-mico{ width:100%; height:100%; object-fit:contain; display:block; pointer-events:none; }
.hab-card__ico:has(> .hab-mico), .hab-modal-ico:has(> .hab-mico), .hrs-head__ico:has(> .hab-mico){ background:transparent !important; }
.hab-icopick:has(> .hab-mico){ padding:3px; }
/* Плитка пикера (16.09.2026): тап — просмотр крупно (/ui-viewer.js), галочка в углу —
   выбор. Плитка теперь div role=button, поэтому position/выделение/выноска задаются здесь:
   долгое нажатие на iPhone не должно открывать системное меню картинки. */
.hab-icopick{ position:relative; -webkit-touch-callout:none; -webkit-user-select:none; user-select:none; }
.hab-icopick:focus-visible{ outline:2px solid var(--ui-brand,#00a0ff); outline-offset:2px; }
.hab-icosel{
  position:absolute; top:-6px; right:-6px; width:26px; height:26px; padding:0; margin:0;
  border-radius:50%; cursor:pointer; display:flex; align-items:center; justify-content:center;
  background:var(--ui-card-bg,#141414); border:1px solid var(--ui-card-border,#262626);
}
/* зона тапа галочки больше видимого кружка — палец в 26px не попадает */
.hab-icosel::before{ content:""; position:absolute; inset:-8px; }
.hab-icopick .hab-icosel svg{ width:14px; height:14px; color:var(--ui-muted,#6a6a6a); stroke-width:3; }
.hab-icosel:hover{ border-color:var(--ui-brand,#00a0ff); }
.hab-icopick.is-on .hab-icosel{ background:var(--ui-brand,#00a0ff); border-color:var(--ui-brand,#00a0ff); }
.hab-icopick.is-on .hab-icosel svg{ color:#fff; }
/* галочка выступает за плитку — сетке нужен отступ, иначе крайние кружки режутся */
.hab-icogrid:has(.hab-icosel){ gap:12px; padding:6px 6px 0 0; }

/* Мобильная (узкий экран) — та же раскладка, чуть меньше кольцо и дни, чтобы влезало.
   Зону тапа (.hab-abtn) здесь НЕ уменьшаем: раньше она сжималась до 30px именно там,
   где палец, а не мышь. */
@media (max-width:600px){
  .hab-card{ padding:16px; }
  .hab-card.is-short{ padding:14px 16px 16px; }
  .hab-card__ico{ width:46px; height:46px; }
  .hab-card__ico svg{ width:21px; height:21px; }
  .hab-card__title{ font-size:17px; }
  .hab-card__sub{ font-size:12.5px; }
  .hab-day__lbl{ font-size:10px; }
  .hab-day__mark{ width:26px; height:26px; }
  .hab-day__mark svg{ width:13px; height:13px; }
  .hab-btn-result{ height:46px; font-size:15px; border-radius:8px; }
}
/* узкая карточка (360–430px): иконки одним рядом, «+ Результат» не влезает — уходит на свою строку во всю ширину;
   margin-left гасим, чтобы у перенесённой кнопки не было отступа слева (расстояние даёт gap) */
@media (max-width:480px){
  .hab-card__actions{ row-gap:10px; }
  .hab-btn-result{ margin-left:0; }
}

/* ===== ADR-146: универсальный компонент загрузки файлов (.dz-*, dropzone.js) =====
   Один загрузчик на всю платформу — портал и кабинеты клиентов, тема через переменные
   выше (--ui-brand/--ui-card-bg/--ui-card-border/--ui-danger/--ui-surface-2/--ui-muted),
   своей палитры нет. */
.dz-wrap { display:flex; flex-direction:column; gap:10px; width:100%; min-width:0; box-sizing:border-box; }
.dz-zone {
  display:flex; align-items:center; gap:12px; padding:16px; min-width:0;
  border:1.5px dashed var(--ui-card-border); border-radius:8px;
  background:var(--ui-surface-2); cursor:pointer; transition:.15s;
}
.dz-zone:hover, .dz-zone:focus-visible { border-color:var(--ui-brand); outline:none; }
.dz-zone.dz-over { border-color:var(--ui-brand); background:var(--ui-glow-brand); }
.dz-zone-ic {
  flex:0 0 auto; width:38px; height:38px; border-radius:9px;
  display:flex; align-items:center; justify-content:center;
  background:var(--ui-glow-brand); color:var(--ui-brand);
}
.dz-zone-ic svg { width:18px; height:18px; }
.dz-zone-txt { flex:1 1 auto; min-width:0; }
.dz-zone-title { font-weight:600; font-size:14px; overflow-wrap:break-word; }
.dz-zone-hint { font-size:12px; color:var(--ui-muted); margin-top:2px; overflow-wrap:break-word; }
.dz-browse { color:var(--ui-brand); text-decoration:underline; }

.dz-list { display:flex; flex-direction:column; gap:6px; }
.dz-row {
  display:flex; align-items:center; gap:10px; padding:8px 10px; min-width:0; box-sizing:border-box;
  border:1px solid var(--ui-card-border); border-radius:9px; background:var(--ui-card-bg);
}
.dz-row.dz-done { border-color:var(--ui-ok, #4ade80); }
.dz-row.dz-dup { border-color:var(--ui-danger); }
.dz-row.dz-err { border-color:var(--ui-danger); }

.dz-thumb {
  flex:0 0 auto; width:38px; height:38px; border-radius:8px; overflow:hidden; position:relative;
  display:flex; align-items:center; justify-content:center; background:var(--ui-surface-2); color:var(--ui-muted);
}
.dz-thumb svg { width:18px; height:18px; }
.dz-thumb-img img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.dz-img-ghost { filter:grayscale(1) brightness(.4); }
.dz-img-live { clip-path:inset(0 100% 0 0); transition:clip-path .12s linear; }

.dz-meta { flex:1 1 auto; min-width:0; }
.dz-name { font-size:13px; font-weight:500; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.dz-status { font-size:11.5px; color:var(--ui-muted); margin-top:1px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.dz-status .dz-added { color:var(--ui-ok, #4ade80); font-weight:600; }
.dz-status .dz-skipped { color:var(--ui-danger); font-weight:600; }
.dz-row.dz-err .dz-status { color:var(--ui-danger); }
.dz-bar { height:3px; border-radius:2px; background:var(--ui-surface-2); margin-top:5px; overflow:hidden; }
.dz-bar > i { display:block; height:100%; width:0%; background:var(--ui-brand); transition:width .12s linear; }
.dz-row.dz-done .dz-bar > i { background:var(--ui-ok, #4ade80); }
.dz-row.dz-dup .dz-bar > i { background:var(--ui-danger); }
.dz-row.dz-err .dz-bar { display:none; }

.dz-ok { display:none; flex:0 0 auto; color:var(--ui-ok, #4ade80); }
.dz-ok svg { width:16px; height:16px; }
.dz-row.dz-done .dz-ok, .dz-row.dz-dup .dz-ok { display:flex; }
.dz-row.dz-dup .dz-ok { color:var(--ui-danger); }
.dz-retry, .dz-x {
  flex:0 0 auto; width:26px; height:26px; border-radius:6px; border:none; background:transparent;
  color:var(--ui-muted); display:flex; align-items:center; justify-content:center; cursor:pointer;
}
.dz-retry svg, .dz-x svg { width:15px; height:15px; }
.dz-retry { color:var(--ui-danger); }
.dz-retry:hover, .dz-x:hover { background:var(--ui-surface-2); }

.dz-foot { display:flex; align-items:center; justify-content:space-between; font-size:12px; color:var(--ui-muted); }
.dz-clear { background:none; border:none; color:var(--ui-brand); font-size:12px; cursor:pointer; padding:0; }
.dz-clear:hover { text-decoration:underline; }

/* Вариант «3 кнопки» (photoPick, на сравнение с обычной зоной — 30.08.2026) */
.dz-pickrow { display:flex; gap:8px; }
.dz-pick {
  flex:1 1 0; display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:6px; padding:14px 6px; border:1.5px solid var(--ui-card-border); border-radius:8px;
  background:var(--ui-surface-2); cursor:pointer; transition:.15s;
}
.dz-pick:hover, .dz-pick:focus-visible { border-color:var(--ui-brand); outline:none; }
.dz-pick:active { background:var(--ui-glow-brand); }
.dz-pick-ic { width:28px; height:28px; border-radius:8px; display:flex; align-items:center; justify-content:center; background:var(--ui-glow-brand); color:var(--ui-brand); }
.dz-pick-ic svg { width:15px; height:15px; }
.dz-pick-lbl { font-size:12.5px; font-weight:600; }
.dz-pick-hint { text-align:center; margin-top:2px; }

/* ===== ПОДСВЕТКА СТРОКИ ТАБЛИЦЫ ПРИ НАВЕДЕНИИ =====
   Эталонный цвет для платформы — #161616 (выбран Константином 30.08.2026,
   самый частый из вариантов, гулявших по страницам: 141414/161616/171717/
   191919/1a1a1a/0f0f0f). Правило ниже покрывает и généric tr:hover, и
   tr.row:hover — раньше было раздельно, до 30.08.2026 второе было #151515
   в 6 файлах отдельной строкой, теперь один цвет на оба случая.
   Специфичные переопределения (мобильные карточные раскладки, построчный
   выбор типа .runs tr.sel, #tasks-body на телефоне) НЕ трогать — они
   осознанно отключают/меняют hover под свою раскладку и не конфликтуют:
   их селектор специфичнее (или медиазапрос), поэтому продолжат побеждать. */
tr:hover td, tr.row:hover td { background:var(--ui-row-hover,#161616); }

/* ===== МОДАЛКА-ПОДЛОЖКА (.mask) =====
   До 30.08.2026 было побайтово одинаковое правило в 5 файлах (brief/docs/links/
   renew/soric.html). Класс НЕ переименован при выносе — под именем .mask 13+ мест
   в разметке с разными id/onclick в этих же файлах, риск опечататься при массовом
   переименовании выше пользы. Если заводишь новую страницу с модалкой поверх
   тёмной подложки — можно смело брать этот же класс, .mask уже общий. */
.mask { position:fixed; inset:0; background:rgba(0,0,0,.6); display:none;
        align-items:flex-start; justify-content:center; z-index:900;
        overflow-y:auto; padding:40px 16px; }
.mask.on { display:flex; }

/* ===== ЭКРАН ПАРОЛЯ ПЕРЕД ПРИЛОЖЕНИЕМ (#login / #app) =====
   Внутренние инструменты платформы (не клиентский кабинет) держат пароль одним
   полем и прячут само приложение до входа. До 30.08.2026 было побайтово
   одинаковое правило в 14 файлах. Есть соседний, чуть другой вариант с
   margin:15vh — тот НЕ объединён с этим (другое значение, другие страницы:
   access/med/set/habits/medcard), его трогать отдельно. */
#login { max-width:320px; margin:80px auto; text-align:center; }
#app { display:none; }

/* Второй вариант того же экрана пароля — margin:15vh вместо 80px (используют
   access/med/set/habits/medcard.html). Т.к. ОБА варианта используют id="login",
   а бы просто класс .ui-login-15vh НЕ победил бы: специфичность ID (#login,
   80px-правило выше) всегда выше специфичности класса, независимо от порядка
   в файле. Поэтому селектор здесь составной — #login.ui-login-15vh — то же
   самое ID+класс вместе, специфичность выше базового #login. Обнаружено и
   исправлено при перепроверке 30.08.2026 (первая версия была живым багом:
   тихо игнорировалась, margin оставался 80px). */
#login.ui-login-15vh { max-width:320px; margin:15vh auto; text-align:center; }
.ui-login-15vh.pad { padding:0 16px; }

/* Третий вариант — «карточка» с фоном и рамкой (не голый текст). До 30.08.2026
   было побайтово одинаковое правило в 4 файлах (client/invoices/notify/services.html)
   — этот дубль пропущен в первой волне уборки #login, найден только при
   перепроверке 31.08.2026. Тоже составной селектор #login.ui-login-card —
   по той же причине, что и .ui-login-15vh выше (ID-специфичность иначе победила
   бы класс). */
#login.ui-login-card {
  max-width:340px; margin:14vh auto; background:#161616; border:1px solid #2a2a2a;
  border-radius:12px; padding:28px 24px; text-align:center;
}
/* .ui-login-card теперь покрывает 6 файлов: client/invoices/notify/services
   (найдены 30.08.2026) + clients/crm-tenant (найдены при перепроверке 31.08.2026,
   были пропущены из-за другого написания селектора — "#login {" с пробелом
   вместо "#login{" без — обычный grep их не находил). */

/* Четвёртый вариант — модалка по центру экрана, изначально СКРЫТА (display:none
   по умолчанию, а не видна). Тоже найден только при перепроверке 31.08.2026,
   тоже пропущен из-за пробела в селекторе. 2 файла: crm.html, projects.html. */
#login.ui-login-modal {
  max-width:340px; margin:120px auto; background:#1a1a1a; border:1px solid #2a2a2a;
  border-radius:12px; padding:28px; display:none;
}

/* Бейдж-«таблетка» в реестрах документов — До 31.08.2026 было побайтово
   одинаковое правило в 6 файлах (brief/doclog/docs/links/renew/soric.html),
   с расхождением padding 2px 7px vs 2px 8px (3 на 3) — взял 8px как эталон,
   разница на глаз незаметна. Цветовые модификаторы (.pill.t-inv и т.д. в
   doclog/docs) трогают только color/border-color, с базой не конфликтуют. */
.pill { display:inline-block; font-size:10.5px; padding:2px 8px; border-radius:20px;
        border:1px solid #2a2a2a; color:#aaa; white-space:nowrap; }

/* Футер модалки (кнопки в ряд снизу) — 5 файлов, побайтовый дубль, имя
   достаточно отличительное (не встречается больше нигде на платформе,
   в отличие от .row/.empty/.card — проверено перед выносом 31.08.2026). */
.mfoot { display:flex; gap:8px; margin-top:18px; align-items:center; }

/* Колонка с номером/ID в реестрах — 6 файлов, 2 подгруппы (с font-size:12px и
   без). Третий, более простой вариант (только color) — в crm-dashboard.html,
   он НЕ сюда, защищён локально составным селектором .trow .idcol. */
.idcol { color:#fbbf24; font-weight:600; white-space:nowrap; }
.idcol.sm { font-size:12px; }

/* Ссылка в реестре («открыть», «Сделать выгрузку» и т.п.) — 4 файла, побайтовый
   дубль. НЕ путать с .lnk без тега a — тот встречается ещё в 3 местах с другим
   смыслом (uploads.html/crm-dashboard.html защищены выше специфичностью,
   registry-mobile.css/.rc-r .v.lnk намеренно не тронут — свой оттенок). */
a.lnk { color:#6ab0f5; text-decoration:none; }
a.lnk:hover { text-decoration:underline; }

/* Текст ошибки под полем пароля — 2 файла (access/med), побайтовый дубль.
   Другие .err по платформе — все составные селекторы (#login .err, .toast.err,
   .wrap .err) и не конфликтуют с этим базовым. */
.err { color:#f87171; font-size:12px; min-height:16px; margin-bottom:8px; }

/* Приглушённый текст в реестрах — 10 файлов, побайтовый дубль. Другая
   подгруппа (#555, без font-size, 4 файла: client/invoices/services/clients)
   защищена локально через `body .muted{...}` — специфичность выше без
   переименования разметки (у client.html 20+ мест использования, трогать
   рискованно). Составные варианты (.tbl .muted, .upc .muted) не задеты. */
.muted { color:#666; font-size:11px; }

/* Сумма/цена в реестрах (зелёный, жирный) — 4 файла, побайтовый дубль,
   имя нигде больше не встречается на платформе. */
.price { color:#4ade80; font-weight:600; white-space:nowrap; }

/* Заголовок группы в реестре счетов/УПД («Проект: Х») — 2 файла (docs/invoices),
   расхождение только в padding (8px vs 8px 12px) — взял более частый по
   платформе вариант с горизонтальным отступом. */
.proj-row td { background:#131a20; color:#00a0ff; font-weight:700; font-size:13px;
               padding:8px 12px; border-bottom:1px solid #1f2a33; }
.proj-row .sub { color:#888; font-weight:400; font-size:12px; }

/* =========================================================================
   ЭКРАН МИССИИ ТРЕКЕРА: вкладки «Статистика» / «История» (31.08.2026).
   Рисует medcard_habits.js (habitOpenCard). Плитки, списки и заголовки разделов
   берутся у сводки медкарты (.stats-* выше) — здесь только то, чего там нет:
   вкладки, герой цели с засечками чекпоинтов, календарь активности и лента истории.

   Цвета — токены --ui-*. Осознанных исключений два, и оба те же, что у .stats-*
   (см. ADR-143): брендовая заливка героя (белый текст на ней читается в обеих темах)
   и зелёная шкала календаря — она кодирует ДАННЫЕ, а не поверхность, и обязана быть
   одинаковой в светлой и тёмной теме, иначе «больше/меньше» перестанет читаться.
   ========================================================================= */

/* Панель вкладки. hidden сам по себе не спрячет флекс — нужен явный display:none. */
.hab-pane { display:flex; flex-direction:column; gap:14px; }
.hab-pane[hidden] { display:none; }

.hab-tabs { display:flex; border-bottom:1px solid var(--ui-line,#262626); }
.hab-tab {
  flex:1; min-height:var(--ui-tap,44px); display:flex; align-items:center; justify-content:center;
  gap:8px; padding:0 6px; border:none; background:transparent; cursor:pointer;
  font-size:15px; font-weight:600; color:var(--ui-tx-2,#8b8b8b);
}
.hab-tab svg { width:18px; height:18px; flex:0 0 auto; fill:none; stroke:currentColor;
  stroke-width:var(--ui-ico-stroke,2); stroke-linecap:round; stroke-linejoin:round; }
.hab-tab b { font-size:12px; font-weight:700; color:var(--ui-tx-3,#666); font-variant-numeric:tabular-nums; }
.hab-tab.is-on { color:var(--ui-tx,#e8e8e8); box-shadow:inset 0 -2px 0 0 var(--ui-brand,#00a0ff); }

/* ----- герой цели: главный ответ экрана числом ----- */
.hab-hero {
  position:relative; overflow:hidden; border-radius:12px; padding:22px 20px;
  /* Плоский брендовый фон (08.09.2026) — по тем же причинам, что у .stats-hero:
     градиент, белый блик и свечение убраны, герой держится числом и площадью. */
  background:var(--ui-brand,#00a0ff);
}
.hab-hero > * { position:relative; z-index:1; }
.hab-hero__top { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:14px; }
.hab-hero__cap { font-size:13px; font-weight:700; color:rgba(255,255,255,.86);
  text-transform:uppercase; letter-spacing:.06em; }
.hab-hero__state { display:inline-flex; align-items:center; gap:6px; padding:5px 11px; white-space:nowrap;
  border-radius:var(--ui-chip-radius,16px); background:rgba(0,0,0,.22);
  font-size:11.5px; font-weight:700; color:#fff; }
.hab-hero__state::before { content:""; width:7px; height:7px; border-radius:50%; background:rgba(255,255,255,.7); }
.hab-hero__state.is-warn::before { background:var(--ui-warn,#fbbf24); }
.hab-hero__state.is-ok::before { background:var(--ui-ok,#4ade80); }
.hab-hero__grid { display:flex; align-items:center; justify-content:space-between; gap:16px; }
.hab-hero__left { min-width:0; }
.hab-hero__num { font-size:56px; font-weight:800; line-height:1; letter-spacing:-.02em; color:#fff;
  font-variant-numeric:tabular-nums; }
.hab-hero__sub { font-size:13px; color:rgba(255,255,255,.82); margin-top:6px; }
.hab-hero__ring { position:relative; width:88px; height:88px; flex:0 0 auto; }
.hab-hero__ring svg { width:88px; height:88px; transform:rotate(-90deg); }
.hab-hero__ring circle { fill:none; stroke-width:8; }
.hab-hero__ring circle.track { stroke:rgba(255,255,255,.24); }
.hab-hero__ring circle.val { stroke:#fff; stroke-linecap:round; }
.hab-hero__pct { position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  font-size:22px; font-weight:800; color:#fff; font-variant-numeric:tabular-nums; }
/* Полоса цели с засечками чекпоинтов: отдельного ряда чипов больше нет — чекпоинт
   это доля той же цели, что и полоса, и на ней он читается без второй шкалы. */
.hab-hero__bar { position:relative; height:10px; border-radius:5px; background:rgba(0,0,0,.26); margin-top:20px; }
.hab-hero__bar > i { position:absolute; left:0; top:0; bottom:0; border-radius:5px; background:#fff; }
.hab-hero__tick { position:absolute; top:-3px; width:2px; height:16px; background:rgba(0,0,0,.30); }
.hab-hero__tick.is-on { background:rgba(255,255,255,.55); }
.hab-hero__marks { position:relative; height:16px; margin-top:9px; font-size:10.5px; font-weight:700; }
.hab-hero__mark { position:absolute; transform:translateX(-50%); white-space:nowrap;
  display:inline-flex; align-items:center; gap:3px; color:rgba(255,255,255,.55);
  font-variant-numeric:tabular-nums; }
.hab-hero__mark.is-on { color:#fff; }
.hab-hero__mark.is-end { right:0; transform:none; }
.hab-hero__mark svg { width:9px; height:9px; fill:none; stroke:currentColor; stroke-width:3;
  stroke-linecap:round; stroke-linejoin:round; }
.hab-hero__foot { display:flex; justify-content:space-between; gap:10px; margin-top:12px;
  font-size:12px; color:rgba(255,255,255,.80); font-variant-numeric:tabular-nums; }
.hab-hero__next { margin-top:4px; font-size:12px; color:rgba(255,255,255,.66); font-variant-numeric:tabular-nums; }

/* ----- плитки показателей: модификаторы к общему .stats-tile ----- */
.stats-tile.is-wide { grid-column:1 / -1; }
.stats-tile .icon.is-bad { background:color-mix(in srgb, var(--ui-danger,#f87171) 14%, transparent);
  color:var(--ui-danger,#f87171); }
.stats-tile .icon.is-ok { background:color-mix(in srgb, var(--ui-ok,#4ade80) 14%, transparent);
  color:var(--ui-ok,#4ade80); }
.stats-tile .icon svg { fill:none; stroke:currentColor; stroke-width:var(--ui-ico-stroke,2);
  stroke-linecap:round; stroke-linejoin:round; }
.stats-tile .lbl b { font-weight:700; color:var(--ui-tx,#e8eaed); }
.stats-tile .lbl b.is-bad { color:var(--ui-danger,#f87171); }
.stats-tile .lbl b.is-ok { color:var(--ui-ok,#4ade80); }
.stats-list .row .v.is-warn { color:var(--ui-warn,#fbbf24); }

/* ----- календарь активности ----- */
/* Одна клетка — один день миссии, неделя в строке. Годовой grid GitHub на короткой
   миссии занимал четыре колонки из 53 и оставлял три четверти карточки пустыми. */
.hab-cal, .hab-chart { background:var(--ui-surface,#111); border:1px solid var(--ui-line,#262626);
  border-radius:12px; padding:16px; }
.hab-cal__head { display:flex; align-items:baseline; justify-content:space-between; gap:10px;
  margin-bottom:14px; font-size:12.5px; color:var(--ui-tx-2,#8b8b8b); font-variant-numeric:tabular-nums; }
.hab-cal__head span:first-child { font-size:14px; color:var(--ui-tx,#e8e8e8); }
.hab-cal__grid { display:grid; grid-template-columns:repeat(7, minmax(0,1fr)); gap:6px; }
.hab-cal__dow { font-size:11px; color:var(--ui-tx-3,#666); text-align:center; padding-bottom:2px; }
.hab-cal__d { aspect-ratio:1; border-radius:9px; display:flex; align-items:center; justify-content:center;
  font-size:12px; font-weight:600; font-variant-numeric:tabular-nums; }
.hab-cal__d.is-off { background:transparent; color:var(--ui-tx-3,#666); opacity:.35; }
.hab-cal__d.l0 { background:var(--ui-surface-2,#1a1a1a); color:var(--ui-tx-3,#666); }
.hab-cal__d.l1, .hab-cal__legend i.l1 { background:#0d3a2e; color:rgba(255,255,255,.62); }
.hab-cal__d.l2, .hab-cal__legend i.l2 { background:#0f6b45; color:rgba(255,255,255,.82); }
.hab-cal__d.l3, .hab-cal__legend i.l3 { background:#14a35a; color:#04240f; }
.hab-cal__d.l4, .hab-cal__legend i.l4 { background:#22e07a; color:#063a1e; }
.hab-cal__legend { display:flex; align-items:center; justify-content:flex-end; gap:6px; margin-top:12px;
  font-size:10.5px; color:var(--ui-tx-3,#666); }
.hab-cal__legend i { width:12px; height:12px; border-radius:3px; flex:0 0 auto; }

/* ----- график: переключатель периода и полотно ----- */
.hab-seg { display:flex; gap:4px; padding:4px; margin-bottom:14px; border-radius:8px;
  background:var(--ui-bg,#0b0d10); border:1px solid var(--ui-line,#262626); }
.hab-seg__b { flex:1; min-height:var(--ui-tap,44px); border:none; background:transparent; cursor:pointer;
  border-radius:5px; font-size:13px; font-weight:600; color:var(--ui-tx-2,#8b8b8b); }
.hab-seg__b.is-on { background:var(--ui-surface-2,#1f1f1f); color:var(--ui-tx,#e8e8e8); }   /* фолбэк намеренно 1f1f1f: это активный сегмент, у сервера он --ui-seg-on:#1f1f1f, а не поверхность */
.hab-chart__box { position:relative; height:190px; }

/* ----- лента истории ----- */
/* Записи сгруппированы по дням с итогом за день. До 31.08.2026 лента обрывалась
   на 30-й записи молча (results.slice(0,30)) — остальные не показывало ничто. */
.hab-hist__sum { display:flex; background:var(--ui-surface,#111);
  border:1px solid var(--ui-line,#262626); border-radius:12px; overflow:hidden; }
.hab-hist__sum > div { flex:1; min-width:0; padding:14px 10px; text-align:center; }
.hab-hist__sum > div + div { border-left:1px solid var(--ui-line,#262626); }
.hab-hist__sum b { display:block; font-size:20px; font-weight:800; line-height:1;
  color:var(--ui-tx,#e8e8e8); font-variant-numeric:tabular-nums; }
.hab-hist__sum span { display:block; margin-top:6px; font-size:11.5px; color:var(--ui-tx-2,#8b8b8b); }
.hab-hist__day { background:var(--ui-surface,#111); border:1px solid var(--ui-line,#262626);
  border-radius:12px; overflow:hidden; }
.hab-hist__dh { display:flex; align-items:baseline; justify-content:space-between; gap:10px;
  padding:12px 14px; border-bottom:1px solid var(--ui-line,#262626); }
.hab-hist__dh .d { font-size:14px; font-weight:700; color:var(--ui-tx,#e8e8e8); }
.hab-hist__dh .d i { font-style:normal; font-weight:400; color:var(--ui-tx-3,#666); }
.hab-hist__dh .t { font-size:14px; font-weight:700; white-space:nowrap;
  color:var(--ui-brand,#00a0ff); font-variant-numeric:tabular-nums; }
.hab-hist__rec { display:flex; align-items:center; gap:12px; padding:10px 14px;
  min-height:var(--ui-tap,44px); box-sizing:border-box; }
.hab-hist__rec + .hab-hist__rec { border-top:1px solid var(--ui-line-2,#1e1e1e); }
.hab-hist__rec .tm { flex:0 0 auto; font-size:13px; color:var(--ui-tx-2,#8b8b8b);
  font-variant-numeric:tabular-nums; }
.hab-hist__rec .mid { flex:1 1 auto; min-width:0; }
.hab-hist__rec .am { font-size:15px; font-weight:700; color:var(--ui-tx,#e8e8e8);
  font-variant-numeric:tabular-nums; }
.hab-hist__rec .ed { margin-left:6px; font-size:11px; font-style:normal; color:var(--ui-tx-3,#666); }
.hab-hist__more { width:100%; }
.hab-hist__empty { padding:40px 0; text-align:center; font-size:14px; color:var(--ui-tx-3,#666); }

/* =========================================================================
   «ЖИЗНЬ» И ФОРМА СИМПТОМА — 26.09.2026, повторный разбор (Константин: «шторку ты
   придумал с нуля, бери из другого раздела нормальную»). Раньше здесь была своя пара
   .lf-scrim/.lf-sheet — за день на ней всплыли z-index-конфликт с шторкой места,
   нефиксированная шапка при скролле и раздутие по ширине. Вместо очередного патча —
   переезд на общий канон платформы .mdl-back/.mdl-card/.mdl-head/.mdl-body (ui.css,
   раздел «МОДАЛКА С ШАПКОЙ ДЕЙСТВИЙ», первым внедрён на /issues): шапка position:sticky,
   тело — единственный скролл-контейнер, весь класс багов исчезает сам собой. medcard_life.js
   (sheetHead/openSheet) собирает именно эту разметку. Остаётся локальным здесь: .lf-* —
   поля формы момента/симптома, .sym-* — шторка ввода симптома.
   ========================================================================= */
.lf-sub { margin:-10px 0 16px; font-size:12px; color:var(--ui-muted,#6a6a6a); }
.lf-field { margin-bottom:14px; min-width:0; }
.lf-field.is-last { margin-bottom:0; }
.lf-label { margin-bottom:6px; font-size:10.5px; font-weight:700; letter-spacing:.14em;
  text-transform:uppercase; color:var(--ui-muted,#6a6a6a); }
.lf-label.is-flush { margin-bottom:0; }
.lf-input { width:100%; min-width:0; box-sizing:border-box; padding:10px 12px;
  background:var(--ui-surface-2,#1a1a1a); border:1px solid var(--ui-card-border,#262626);
  border-radius:var(--ui-radius,8px); color:var(--ui-tx,#e8e8e8); font-size:14px; font-family:inherit; }
.lf-input:focus { outline:none; border-color:var(--ui-brand,#00a0ff); }
/* Низ шторки момента/симптома — тот же рецепт, что .iss-foot на /issues: полноширинная
   «Сохранить»/«Добавить» + иконка вне тела .mdl-body, чтобы кнопка не уезжала со скроллом. */
.lf-foot { display:flex; gap:8px; flex:0 0 auto;
  padding:12px 16px max(34px, calc(env(safe-area-inset-bottom) + 12px));
  border-top:1px solid var(--ui-card-border,#262626); background:var(--ui-surface-2,#1a1a1a); }
.lf-foot .btn { flex:1 1 auto; height:44px; min-height:44px; }
.lf-foot .ibtn { flex:0 0 44px; width:44px !important; height:44px !important; min-width:44px !important; min-height:44px !important; }
/* «Место» — визуально тот же виджет, что «Когда» (26.09.2026, Константин: pf-fieldrow
   голой строкой без рамки выглядел чужеродно рядом с .ui-date/.lf-input). Только в
   «Жизни»: в дневнике и «Сексе» тот же pf-fieldrow — осознанно строка списка, их не трогаем. */
.lf-field > .pf-fieldrow {
  border:1px solid var(--ui-card-border,#262626); background:var(--ui-surface-2,#1a1a1a);
  border-radius:var(--ui-radius,8px); padding:10px 12px; box-sizing:border-box;
  align-items:flex-start; min-height:auto;
}
/* 26.09.2026, повторная жалоба после боксовой рамки: адрес всё ещё вылезал — однострочный
   nowrap+ellipsis у __t зависит от точного расчёта ширины по всей цепочке предков, и на
   телефоне регулярно ломается на длинных адресах. Вместо очередной охоты за нужным
   min-width:0 — резиновое поле: текст ПЕРЕНОСИТСЯ на новую строку внутри рамки вместо
   попытки влезть в одну, переполнение горизонтали в принципе невозможно (правило из
   ai-platform: строки ввода всегда резиновые). Только в «Жизни» — pf-fieldrow.js это
   не трогает, только оболочка тут. */
.lf-field > .pf-fieldrow > svg { margin-top:3px; }
.lf-field > .pf-fieldrow .pf-fieldrow__t {
  white-space:normal; overflow:visible; text-overflow:clip; overflow-wrap:anywhere; line-height:1.4;
}
.lf-field > .pf-fieldrow .pf-fieldrow__v { align-self:flex-start; margin-top:1px; }
/* 26.09.2026: раньше resize:vertical — фиксированная высота (2 строки), тянуть вручную.
   Теперь растёт под текст сама (JS: taGrow в symptoms_entry.js/medcard_life.js). */
textarea.lf-input { resize:none; overflow:hidden; }
.lf-search { margin-bottom:10px; }
.lf-inline { display:flex; gap:6px; min-width:0; }
.lf-inline > .lf-input { flex:1 1 auto; }
.lf-qty { display:flex; gap:6px; align-items:center; min-width:0; }
.lf-qty-btn { min-width:var(--ui-tap,44px); background:var(--ui-surface-2,#1a1a1a);
  border:1px solid var(--ui-card-border,#262626); }
.lf-qty .lf-input { flex:1 1 auto; text-align:center; }
.lf-chips { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:8px; }
.lf-chip { display:inline-flex; align-items:center; padding:6px 12px; cursor:pointer; font-size:12.5px;
  border-radius:var(--ui-chip-radius,16px); background:var(--ui-surface-2,#1a1a1a);
  border:1px solid var(--ui-card-border,#262626); color:var(--ui-tx-2,#8b8b8b); }
.lf-chip.is-on { color:var(--ui-brand,#00a0ff); border-color:var(--ui-brand,#00a0ff);
  background:color-mix(in srgb, var(--ui-brand,#00a0ff) 14%, transparent); }
.lf-tabs { margin-bottom:16px; }
.lf-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(84px,1fr)); gap:10px; margin-bottom:26px; }
.lf-grid-empty { grid-column:1 / -1; padding:4px 2px 8px; font-size:12.5px; color:var(--ui-muted,#6a6a6a); }
.lf-tile { position:relative; aspect-ratio:1; min-width:0; padding:6px; cursor:pointer; text-align:center;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px;
  background:var(--ui-surface-2,#1a1a1a); border-radius:var(--ui-card-radius,12px); }
.lf-tile-add { background:transparent; border:1.5px dashed var(--ui-card-border,#3a3a3d); }
.lf-ava { width:30px; height:30px; border-radius:50%; display:flex; align-items:center; justify-content:center;
  font-size:13px; font-weight:700; color:var(--ui-brand,#00a0ff);
  background:color-mix(in srgb, var(--ui-brand,#00a0ff) 14%, transparent); }
.lf-tile-add .lf-ava { background:transparent; border:1.5px dashed var(--ui-tx3,#666);
  color:var(--ui-tx-2,#8b8b8b); font-size:16px; }
.lf-tile-lbl { font-size:11px; line-height:1.2; color:var(--ui-tx,#e8e8e8); overflow-wrap:anywhere; }
.lf-tile-add .lf-tile-lbl { color:var(--ui-tx-2,#8b8b8b); }
.lf-tile-del { position:absolute; top:2px; right:2px; width:26px; height:26px; padding:0; line-height:1;
  background:none; border:0; cursor:pointer; font-size:16px; color:var(--ui-muted,#6a6a6a); }
.lf-pending { margin-bottom:12px; padding:9px 14px; font-size:13px; color:var(--ui-warn,#fbbf24);
  border-radius:var(--ui-radius,8px);
  background:color-mix(in srgb, var(--ui-warn,#fbbf24) 8%, transparent);
  border:1px solid color-mix(in srgb, var(--ui-warn,#fbbf24) 30%, transparent); }
.lf-empty { font-size:13px; color:var(--ui-muted,#6a6a6a); }
.lf-row { display:flex; justify-content:space-between; align-items:flex-start; gap:10px; cursor:pointer;
  margin-bottom:6px; padding:12px 14px; border-radius:var(--ui-radius,8px);
  background:var(--ui-card-bg,#141414); border:1px solid var(--ui-card-border,#262626); }
.lf-row.is-ro { cursor:default; }
.lf-row-main { flex:1 1 auto; min-width:0; }
.lf-row-title { font-size:13.5px; font-weight:600; color:var(--ui-tx,#e8e8e8); overflow-wrap:anywhere; }
.lf-row-note { margin-top:2px; font-size:12px; color:var(--ui-tx-2,#8b8b8b); overflow-wrap:anywhere; }
.lf-row-time { font-size:12px; white-space:nowrap; color:var(--ui-muted,#6a6a6a); }
.lf-sev { font-weight:700; color:var(--ui-brand,#00a0ff); }
.lf-dim { color:var(--ui-muted,#6a6a6a); }
.lf-more { width:100%; margin-top:6px; }
.lf-more[hidden] { display:none; }
.lf-hint { margin-bottom:14px; padding:12px 13px; font-size:12.5px; line-height:1.5; color:var(--ui-tx-2,#9a9a9a);
  background:var(--ui-card-bg,#141414); border:1px solid var(--ui-card-border,#262626);
  border-radius:var(--ui-card-radius,12px); }
.lf-hint-act { margin-top:10px; }
.lf-day { margin:16px 0 8px; font-size:10.5px; font-weight:700; letter-spacing:.14em;
  text-transform:uppercase; color:var(--ui-muted,#6a6a6a); }
.lf-card { display:flex; justify-content:space-between; align-items:flex-start; gap:10px;
  margin-bottom:8px; padding:11px 13px; background:var(--ui-card-bg,#141414);
  border:1px solid var(--ui-card-border,#262626); border-radius:var(--ui-card-radius,12px); }
.lf-card-main { min-width:0; }
.lf-card-title { font-size:13.5px; font-weight:600; color:var(--ui-tx,#e8e8e8); }
.lf-card-trig { margin-top:4px; font-size:12px; color:var(--ui-tx-2,#a8a8a8); }
.lf-card-meta { margin-top:3px; font-size:11.5px; color:var(--ui-muted,#6a6a6a); overflow-wrap:anywhere; }
.lf-card-acts { display:flex; align-items:center; gap:4px; flex-shrink:0; }
.lf-x, .lf-ico-btn { flex-shrink:0; padding:0 2px; background:none; border:0; cursor:pointer; color:var(--ui-muted,#6a6a6a); }
.lf-x { font-size:18px; line-height:1; }
.lf-x:disabled { opacity:.4; }
.lf-ico-btn svg { width:15px; height:15px; fill:none; stroke:currentColor;
  stroke-width:var(--ui-ico-stroke,2); stroke-linecap:round; stroke-linejoin:round; }
.lf-sev-row { display:flex; gap:6px; margin-bottom:16px; }
.lf-sev-btn { flex:1; min-width:var(--ui-tap,44px); height:38px; cursor:pointer; font-size:14px; font-weight:700;
  font-family:inherit; border-radius:var(--ui-radius,8px); background:var(--ui-surface-2,#1a1a1a);
  border:1px solid var(--ui-card-border,#333); color:var(--ui-tx,#c8c8c8); }
.lf-sev-btn.is-on { background:var(--ui-brand,#00a0ff); border-color:var(--ui-brand,#00a0ff); color:#00121f; }
.lf-stack { display:flex; flex-direction:column; gap:14px; }
.stats-hero-side.lf-hero-row { flex-direction:row; gap:26px; flex-wrap:wrap; }
.stats-section-title.lf-sec-t { margin-bottom:10px; }
.stats-list.lf-list-pad { padding:14px; }
.stats-bar-row .bl.is-wide { width:170px; }
.gl-hint.gl-diag { text-align:left; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:11px;
  line-height:1.65; white-space:normal; user-select:text; -webkit-user-select:text; }
.gl-hint.gl-diag[hidden] { display:none; }
.gl-diag-btn { margin-top:10px; }

/* ----- шторка ввода симптома (symptoms_entry.js) ----- */
.sym-scrim { position:fixed; inset:0; z-index:9998; background:rgba(0,0,0,.6); }
.sym-sheet { position:fixed; left:0; right:0; bottom:var(--ui-kb,0px); z-index:9999; overflow:auto; overscroll-behavior:contain;
  /* 03.10.2026: --ui-kb ставит /ui-keyboard.js (iOS не меняет dvh при клавиатуре); без клавиатуры = 0 */
  height:calc(var(--ui-sheet-h-vh) - var(--ui-kb,0px)); height:calc(var(--ui-sheet-h) - var(--ui-kb,0px));
  box-sizing:border-box; padding:16px 16px calc(16px + env(safe-area-inset-bottom));
  background:var(--ui-card-bg,#111); border-top:1px solid var(--ui-card-border,#262626);
  border-radius:var(--ui-sheet-radius,22px) var(--ui-sheet-radius,22px) 0 0; }
html.kb-open .sym-sheet { padding-bottom:16px; } /* клавиатура уже над safe-area */
.sym-top { position:sticky; top:-16px; z-index:2; margin:-16px -16px 10px; padding:16px 16px 10px;
  display:flex; justify-content:space-between; align-items:center;
  background:var(--ui-card-bg,#111); }
.sym-h { font-size:var(--ui-sheet-title-fs,14px); font-weight:700; color:var(--ui-tx,#e8e8e8); }
.sym-status { margin-left:8px; font-size:11.5px; font-weight:400; color:var(--ui-muted,#6a6a6a); }
.sym-status.is-err { color:#ff6b6b; }
.sym-close { background:none; border:0; cursor:pointer; font-size:22px; line-height:1; color:var(--ui-tx-2,#8b8b8b); }
.sym-intro { margin-bottom:12px; padding:12px 13px; font-size:12.5px; line-height:1.5; color:var(--ui-tx-2,#9a9a9a);
  background:var(--ui-surface-2,#141414); border:1px solid var(--ui-card-border,#262626);
  border-radius:var(--ui-card-radius,12px); }
.sym-intro-ok { display:block; margin-top:9px; padding:0; background:none; border:0; cursor:pointer;
  font-size:12.5px; font-weight:700; color:var(--ui-brand,#00a0ff); }
.sym-lead { margin-bottom:10px; font-size:12px; color:var(--ui-muted,#6a6a6a); }
.sym-group { margin-bottom:12px; }
.sym-chip { margin:0 6px 6px 0; padding:8px 13px; cursor:pointer; font-size:13px; font-family:inherit;
  border-radius:var(--ui-chip-radius,16px); background:var(--ui-surface-2,#1a1a1a);
  border:1px solid var(--ui-card-border,#333); color:var(--ui-tx,#c8c8c8); }
.sym-chip.is-on { border-color:var(--ui-brand,#00a0ff); color:var(--ui-tx,#fff);
  background:color-mix(in srgb, var(--ui-brand,#00a0ff) 12%, transparent); }
.sym-q { color:var(--ui-brand,#00a0ff); }
.sym-empty { margin-bottom:12px; font-size:13px; color:var(--ui-muted,#6a6a6a); }
.sym-um { margin-bottom:12px; padding:12px 13px; background:var(--ui-surface-2,#141414);
  border:1px solid var(--ui-brand,#00a0ff); border-radius:var(--ui-card-radius,12px); }
.sym-um-t { margin-bottom:4px; font-size:13.5px; font-weight:700; color:var(--ui-tx,#e8e8e8); }
.sym-um-s { margin-bottom:9px; font-size:12px; color:var(--ui-tx-2,#8b8b8b); }
.sym-sev-box { margin-bottom:12px; padding-top:12px; border-top:1px solid var(--ui-card-border,#1f1f1f); }
.sym-sev-item { margin-bottom:11px; }
.sym-sev-item .lf-sev-row { margin-bottom:0; }
.sym-sev-name { margin-bottom:6px; font-size:13px; color:var(--ui-tx,#e8e8e8); }
.sym-help { margin-top:5px; font-size:11.5px; color:var(--ui-muted,#6a6a6a); }
.sym-save { width:100%; height:46px; cursor:pointer; border:0; font-size:15px; font-weight:700; font-family:inherit;
  border-radius:var(--ui-radius,8px); background:var(--ui-brand,#00a0ff); color:#00121f; }
.sym-save.is-off, .sym-save:disabled { opacity:.45; }

/* ----- плитки и значок записи Картотеки (ADR-290 §7, 02.10.2026) -----
   Один вид на всех: /cards (наборы с иконкой), модалка «Секса» (позы/места/игрушки — пациент,
   кабинет, админ), чип эмоции в шторке самочувствия. Иконка — своя data:-картинка или
   /img/emoji/*.png, без неё — первая буква. Страницы своего CSS и инлайна для них не пишут.
   Размер значка — переменная --kt-ava, плотная сетка — модификатор .is-compact. */
.kt-tiles { display:grid; grid-template-columns:repeat(auto-fill, minmax(var(--kt-tile-min,96px), 1fr)); gap:var(--kt-tile-gap,8px); }
.kt-tile { display:flex; flex-direction:column; align-items:center; gap:5px; min-width:0; padding:10px 6px; box-sizing:border-box;
  text-align:center; cursor:pointer; background:var(--ui-surface,#141414); border:1px solid var(--ui-line,#262626);
  border-radius:var(--ui-card-radius,12px); }
.kt-tile:hover { border-color:var(--ui-brand,#00a0ff); }
.kt-tile:focus-visible { outline:2px solid var(--ui-brand,#00a0ff); outline-offset:2px; }
.kt-tile.is-off { opacity:.5; }
.kt-tile.is-sug { color:var(--ui-tx-3,#6f6f78); border-color:var(--ui-line-2,#1e1e1e); }
.kt-tile--add { background:transparent; border-style:dashed; color:var(--ui-tx-2,#8b8b8b); }
.kt-ava { width:var(--kt-ava,44px); height:var(--kt-ava,44px); flex:none; border-radius:50%; overflow:hidden; box-sizing:border-box;
  display:flex; align-items:center; justify-content:center; font-weight:700; font-size:calc(var(--kt-ava,44px) * 0.41);
  color:var(--ui-tx,#e8e8e8); background:color-mix(in srgb, var(--ui-brand,#00a0ff) 14%, transparent); }
.kt-ava img { width:100%; height:100%; object-fit:cover; display:block; }
/* Цвет аватара-кружка на мягких статусных токенах (19.10.2026, /mail): без модификатора — как раньше */
.kt-ava.is-brand { background:var(--ui-brand-soft); color:var(--ui-brand-soft-tx); }
.kt-ava.is-ok { background:var(--ui-ok-soft); color:var(--ui-ok-soft-tx); }
.kt-ava.is-warn { background:var(--ui-warn-soft); color:var(--ui-warn-soft-tx); }
.kt-tile--add .kt-ava { background:transparent; border:1.5px dashed var(--ui-tx-3,#6f6f78); color:var(--ui-tx-2,#8b8b8b); }
.kt-tile__t { font-size:12px; line-height:1.25; min-width:0; max-width:100%; overflow-wrap:anywhere; }
.kt-tile__c { font-size:10.5px; color:var(--ui-tx-3,#6f6f78); max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.kt-tiles.is-compact { --kt-tile-min:78px; --kt-tile-gap:6px; --kt-ava:38px; }
.kt-tiles.is-compact .kt-tile { padding:9px 4px; color:var(--ui-tx-2,#8b8b8b); background:var(--ui-surface-2,#1a1a1a);
  border-color:var(--ui-card-border,#262626); border-radius:var(--ui-radius,8px); }
.kt-tiles.is-compact .kt-tile.is-sug { color:var(--ui-tx-3,#6f6f78); border-color:var(--ui-line-2,#1e1e1e); }
.kt-tiles.is-compact .kt-tile--add { background:transparent; border:1.5px dashed var(--ui-inp-border,#333); }
.kt-tiles.is-compact .kt-tile__t { font-size:11.5px; line-height:1.2; }
.kt-ava.is-chip { --kt-ava:20px; display:inline-flex; vertical-align:middle; margin:-3px 6px -3px -4px; background:none; }
/* 03.10.2026: векторная картинка (SVG, позы «Секса») — крупнее, квадрат без обрезки кругом, белая подложка
   (рисунки чёрно-красные — на тёмной теме без неё не видны). Ставит avaHtml/ava по типу иконки. */
.kt-ava.is-pic { --kt-ava:76px; border-radius:var(--ui-radius,8px); background:#fff; padding:3px; }
.kt-ava.is-pic img { object-fit:contain; }
.kt-tiles.is-compact .kt-ava.is-pic { --kt-ava:56px; }
.kt-tiles:has(.kt-ava.is-pic) { --kt-tile-min:120px; }

/* =========================================================================
   БАЗОВЫЕ СТИЛИ ФОРМ (28.09.2026) — правила: docs/rules/ui.md «Формы: кнопки, поля,
   подсказки». Вид ролей кнопок и полей — btnCss()/inpCss() в /theme.css; здесь только
   компоненты, которые рисует /ui-forms.js, и ссылка-действие.
   ========================================================================= */

/* Фокус с клавиатуры у ссылок и прочих нажимаемых элементов без роли кнопки.
   :where — нулевой вес: страница со своим видом фокуса остаётся при своём. */
:where(a, button, summary, [role=button], [tabindex]):focus-visible {
  outline:2px solid var(--ui-brand,#00a0ff); outline-offset:2px; }

/* ---- ссылка-действие: второстепенное и редкое («Войти как…», «Показать ещё») ---- */
.ui-link { display:inline-flex; align-items:center; gap:6px; background:none; border:0; padding:8px 0;
  margin:0; color:var(--ui-brand,#00a0ff); font:inherit; font-size:13px; line-height:1.3; cursor:pointer;
  text-decoration:none; text-align:left; }
.ui-link:hover { text-decoration:underline; text-underline-offset:3px; }
.ui-link:focus-visible { outline:2px solid var(--ui-brand,#00a0ff); outline-offset:2px; border-radius:4px; }
.ui-link:disabled, .ui-link[aria-disabled=true] { opacity:.5; cursor:not-allowed; text-decoration:none; }
.ui-link svg { width:14px; height:14px; flex:0 0 auto; }

/* ---- плавающая подпись: имя поля живёт в плейсхолдере (/ui-forms.js оборачивает поле) ----
   В покое подпись стоит внутри поля на месте плейсхолдера; при фокусе или вводе уезжает
   наверх мелким текстом 11px и не пропадает. Поле 44px: подпись 5px сверху, текст ниже. */
.ui-fl { position:relative; display:block; min-width:0; box-sizing:border-box; }
.ui-fl.is-inl { display:inline-block; vertical-align:middle; }
.ui-fl > input, .ui-fl > textarea { width:100% !important; max-width:100%; margin:0 !important;
  padding-top:18px !important; padding-bottom:4px !important; }
.ui-fl > textarea { padding-top:22px !important; padding-bottom:8px !important; }
.ui-fl > input::placeholder, .ui-fl > textarea::placeholder { color:transparent !important; }
.ui-fl > .ui-fl-l { position:absolute; left:calc(var(--fl-pl, var(--ui-inp-px, 11px)) + 1px); right:10px;
  top:calc(var(--fl-h, var(--ui-ctl-h, 44px)) / 2); transform:translateY(-50%); margin:0; pointer-events:none;
  font-size:var(--ui-inp-fs,13px); line-height:1.2; font-weight:400; color:var(--ui-inp-ph, var(--ui-tx-2,#8b8b8b));
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  transition:top .15s ease-out, transform .15s ease-out, font-size .15s ease-out, color .15s ease-out; }
.ui-fl.is-ta > .ui-fl-l { top:22px; transform:none; }
.ui-fl > :is(input,textarea):focus ~ .ui-fl-l,
.ui-fl > :is(input,textarea):not(:placeholder-shown) ~ .ui-fl-l,
.ui-fl.is-fl > .ui-fl-l { top:5px; transform:none; font-size:11px; }
.ui-fl > :is(input,textarea):focus ~ .ui-fl-l { color:var(--ui-brand,#00a0ff); }
.ui-fl > :is(input,textarea):disabled ~ .ui-fl-l { opacity:.55; }
@media (max-width:768px) { .ui-fl > .ui-fl-l { font-size:16px; } }

/* ---- маска даты/времени («__.__.____», «дд.мм.гггг»): формат, а не имя поля (29.09.2026) ----
   Наверх не уезжает: /ui-forms.js кладёт за полем «призрак» маски, остаток маски стоит
   сразу за набранными цифрами — «25.1_.____». Шрифт и левый отступ призраку ставит скрипт
   (копия с поля), здесь только положение и цвет плейсхолдера. */
.ui-mk { position:relative; display:block; min-width:0; box-sizing:border-box; }
.ui-mk.is-inl { display:inline-block; vertical-align:middle; }
.ui-mk > input { width:100% !important; max-width:100%; margin:0 !important; }
.ui-mk > input::placeholder { color:transparent !important; }
.ui-mk > .ui-mk-g { position:absolute; top:0; bottom:0; display:flex; align-items:center; pointer-events:none;
  white-space:pre; overflow:hidden; color:var(--ui-inp-ph, var(--ui-tx-2,#8b8b8b)); }
.ui-mk > .ui-mk-g > i { font-style:normal; visibility:hidden; }
.ui-mk > input:disabled ~ .ui-mk-g { opacity:.55; }

/* ---- подсказка ПОД полем: пример, формат, правило (data-hint на поле → /ui-forms.js) ---- */
.ui-hint { display:block; margin-top:6px; font-size:12px; line-height:1.4; color:var(--ui-tx-2,#8b8b8b); }
.ui-hint.is-bad { color:var(--ui-danger,#f87171); }

/* ---- загрузка кнопки: uiBusy(btn,true|false) и uiDone(btn) из /ui-forms.js ----
   Подпись не меняется, а становится прозрачной — ширина кнопки не прыгает. Селектор
   привязан к кнопкам: класс .is-done у строк списков (.tk-row, .rh-card) не задевается. */
:is(button, a, [role=button]).is-busy, :is(button, a, [role=button]).is-done {
  position:relative; -webkit-text-fill-color:transparent; pointer-events:none; }
:is(button, a, [role=button]).is-busy > svg, :is(button, a, [role=button]).is-done > svg { visibility:hidden; }
:is(button, a, [role=button]).is-busy::after { content:""; position:absolute; left:50%; top:50%;
  width:16px; height:16px; margin:-8px 0 0 -8px; box-sizing:border-box; border-radius:50%;
  border:2px solid currentColor; border-right-color:transparent; animation:ui-spin .7s linear infinite; }
:is(button, a, [role=button]).is-done::after { content:""; position:absolute; left:50%; top:50%;
  width:6px; height:11px; margin:-8px 0 0 -3px; box-sizing:border-box;
  border:solid currentColor; border-width:0 2px 2px 0; transform:rotate(45deg); }
@keyframes ui-spin { to { transform:rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  :is(button, a, [role=button]).is-busy::after { animation-duration:1.6s; }
  .ui-fl > .ui-fl-l { transition:none; }
}

/* =========================================================================
   ЗНАЧОК «СЕРВИСНЫЙ АККАУНТ — ВЛАДЕЛЕЦ В SEARCH CONSOLE» (29.09.2026, ADR-243)
   Разметку рисует /gsa-owner.js: <button class="gsa-king is-on|is-off"> без ролевых
   классов (нестандартный значок в строке) + i-chess-king из спрайта. Горит — --ui-ok,
   нет — приглушённый --ui-tx-3. Клик копирует email сервисного аккаунта.
   ========================================================================= */
.gsa-king { display:inline-flex; align-items:center; justify-content:center; vertical-align:middle;
  min-width:var(--ui-tap-sm,30px); min-height:var(--ui-tap-sm,30px); padding:0; margin:0 0 0 4px;
  background:none; border:0; cursor:pointer; flex:0 0 auto; }
.gsa-king svg { width:var(--ui-nav-ico,18px); height:var(--ui-nav-ico,18px); fill:none; stroke:currentColor;
  stroke-width:var(--ui-ico-stroke,2); stroke-linecap:round; stroke-linejoin:round; }
.gsa-king.is-on { color:var(--ui-ok,#4ade80); }
.gsa-king.is-off { color:var(--ui-tx-3,#6a6a6a); opacity:.6; }
.gsa-king.is-off:hover { opacity:1; }

/* =========================================================================
   МОБИЛЬНЫЙ КИТ (M-xx) — 01.10.2026. Образцы и квиз — /refs#mobile.
   Страница собирается из этих классов; новую вёрстку при наличии M-xx не писать.
   Акцент экрана — ОДНА переменная --ui-acc на контейнере (по умолчанию --ui-brand).
   Заливки — пастель color-mix от акцента, градиентов нет. Только токены --ui-*:
   работает в обеих темах без селекторов темы (ADR-216/254). Старые .stats-* и .hab-*
   не затронуты. Имя .ui-stack занято (flex-колонка, ui.css:599) — полоса долей
   названа .ui-stackbar.
   ========================================================================= */
:where(.ui-mscr,.ui-mcard,.ui-hello,.ui-hero,.ui-kpi,.ui-mult,.ui-chart,.ui-ring,.ui-minibars,.ui-stackbar,
  .ui-legend,.ui-seg,.btn.is-cta,.ui-fab,.ui-item,.ui-check-round,.ui-prog,.ui-icgrid,.ui-pair,.ui-more,
  .ui-streak,.ui-banner,.ui-note,.ui-bubble,.ui-fold.is-m,.ui-mhead) {
  --a: var(--ui-acc, var(--ui-brand,#00a0ff));
  --a-soft: color-mix(in srgb, var(--a) 14%, var(--ui-surface,#141414));
  --a-soft2: color-mix(in srgb, var(--a) 24%, var(--ui-surface,#141414));
  --a-on: var(--ui-btn1-text,#fff);
}
.ui-mscr { display:flex; flex-direction:column; gap:16px; padding:16px; box-sizing:border-box; min-width:0;
  background:var(--ui-bg,#0a0a0a); color:var(--ui-tx,#e8e8e8); font-size:16px; line-height:1.4; }
.ui-mscr > * { min-width:0; }
.ui-mcard { background:var(--ui-surface,#141414); border-radius:24px; padding:var(--ui-card-pad,20px); box-sizing:border-box;
  box-shadow:var(--ui-shadow-sm); display:flex; flex-direction:column; gap:16px; min-width:0; }
.ui-mcard.is-flat { box-shadow:none; background:transparent; padding:0; border-radius:0; }
.ui-mcard__h { margin:0; font-size:20px; font-weight:800; line-height:1.2; color:var(--ui-tx,#e8e8e8); }
.ui-mcard__s { margin:0; font-size:14px; color:var(--ui-tx-2,#8b8b8b); line-height:1.45; }
.ui-mcard__row { display:flex; align-items:center; justify-content:space-between; gap:12px; }

/* надзаголовок */
.ui-eyebrow { display:block; font-size:12px; font-weight:600; text-transform:uppercase; letter-spacing:.14em;
  line-height:1.3; color:var(--ui-tx-2,#8b8b8b); }

/* M-01 шапка «eyebrow + title + действия» (дополняет .ph) */
.ui-mhead { display:flex; align-items:flex-end; justify-content:space-between; gap:12px; }
.ui-mhead__t { margin:4px 0 0; font-size:34px; line-height:1.1; font-weight:800; letter-spacing:-.01em;
  color:var(--ui-tx,#e8e8e8); }
.ui-mhead__acts { display:flex; gap:10px; flex:0 0 auto; }

/* M-32 круглые иконки-кнопки (<button> без ролевых классов) */
.ui-fab { display:inline-flex; align-items:center; justify-content:center; flex:0 0 auto; box-sizing:border-box;
  width:48px; height:48px; min-width:var(--ui-tap,44px); min-height:var(--ui-tap,44px); padding:0; margin:0;
  border:0; border-radius:50%; cursor:pointer; font-family:inherit; position:relative;
  background:var(--ui-tx,#e8e8e8); color:var(--ui-bg,#0a0a0a); transition:transform .12s ease-out; }
.ui-fab:active { transform:scale(.96); }
.ui-fab svg { width:22px; height:22px; fill:none; stroke:currentColor; stroke-width:1.9; stroke-linecap:round;
  stroke-linejoin:round; }
.ui-fab.is-dark { background:var(--ui-tx,#e8e8e8); color:var(--ui-bg,#0a0a0a); }
.ui-fab.is-light { background:var(--ui-surface,#141414); color:var(--ui-tx,#e8e8e8); box-shadow:var(--ui-shadow-sm);
  border:1px solid var(--ui-line,#262626); }
.ui-fab.is-glass { background:color-mix(in srgb, var(--ui-tx,#e8e8e8) 12%, transparent); color:var(--ui-tx,#e8e8e8);
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px); }
.ui-fab.is-sm { width:36px; height:36px; min-width:36px; min-height:36px; }
.ui-fab.is-sm svg { width:18px; height:18px; }
.ui-fab .ui-dot { position:absolute; top:11px; right:12px; width:8px; height:8px; border-radius:50%;
  background:var(--ui-danger,#f87171); }

/* M-02 приветственная шапка: плоская пастельная заливка (без градиента) */
.ui-hello { background:var(--a-soft); border-radius:28px; padding:22px; box-sizing:border-box; display:flex;
  flex-direction:column; gap:18px; color:var(--ui-tx,#e8e8e8); }
.ui-hello__top { display:flex; justify-content:space-between; align-items:center; gap:12px; }
.ui-hello__pill { display:inline-flex; gap:4px; padding:4px; border-radius:999px;
  background:color-mix(in srgb, var(--ui-tx,#e8e8e8) 8%, transparent); }
.ui-hello__body { display:flex; align-items:flex-end; justify-content:space-between; gap:12px; }
.ui-hello__t { margin:0; font-size:28px; line-height:1.15; font-weight:800; letter-spacing:-.01em; }
.ui-hello__s { margin:6px 0 0; font-size:16px; color:var(--ui-tx-2,#8b8b8b); }
.ui-hello__art { flex:0 0 auto; width:72px; height:72px; border-radius:50%; display:flex; align-items:center;
  justify-content:center; background:var(--a-soft2); color:var(--a); }
.ui-hello__art svg { width:34px; height:34px; fill:none; stroke:currentColor; stroke-width:1.75;
  stroke-linecap:round; stroke-linejoin:round; }

/* M-52 облачко-подсказка */
.ui-bubble { position:relative; display:inline-block; max-width:100%; box-sizing:border-box; padding:9px 16px;
  border-radius:999px; font-size:14px; font-weight:600; line-height:1.3; color:var(--ui-tx,#e8e8e8);
  background:var(--ui-surface,#141414); box-shadow:var(--ui-shadow-sm); }
.ui-bubble::after { content:""; position:absolute; right:14px; bottom:-9px; width:9px; height:9px; border-radius:50%;
  background:inherit; box-shadow:var(--ui-shadow-sm); }
.ui-bubble::before { content:""; position:absolute; right:6px; bottom:-16px; width:5px; height:5px; border-radius:50%;
  background:inherit; }

/* M-10 hero-сумма / M-11 цветная hero-карточка (.is-fill) */
.ui-hero { display:block; min-width:0; }
.ui-hero__lbl { display:block; font-size:12px; font-weight:600; text-transform:uppercase; letter-spacing:.14em;
  color:var(--ui-tx-2,#8b8b8b); }
.ui-hero__val { display:flex; align-items:baseline; gap:.12em; margin-top:8px; flex-wrap:wrap; }
.ui-hero__num, .ui-hero__cur { font-size:clamp(44px,14vw,64px); line-height:1; font-weight:800;
  font-variant-numeric:tabular-nums; letter-spacing:-.02em; color:var(--ui-tx,#e8e8e8); }
.ui-hero__sub { display:block; margin-top:10px; font-size:14px; line-height:1.4; color:var(--ui-tx-2,#8b8b8b); }
.ui-hero.is-line { padding:18px 0; border-top:1px solid var(--ui-line-2,#1e1e1e);
  border-bottom:1px solid var(--ui-line-2,#1e1e1e); }
.ui-hero.is-fill { background:var(--a-soft); border-radius:24px; padding:22px; box-sizing:border-box; }
.ui-hero.is-fill .ui-hero__head { display:flex; align-items:center; justify-content:space-between; gap:12px; }
.ui-hero.is-fill .ui-hero__ttl { display:flex; align-items:center; gap:10px; color:var(--a); }
.ui-hero.is-fill .ui-hero__ttl svg { width:22px; height:22px; fill:none; stroke:currentColor; stroke-width:1.9;
  stroke-linecap:round; stroke-linejoin:round; }
.ui-hero.is-fill .ui-hero__ttl .ui-hero__lbl { color:var(--a); }
.ui-hero__cnt { min-width:36px; height:36px; padding:0 8px; box-sizing:border-box; border-radius:999px;
  display:inline-flex; align-items:center; justify-content:center; font-size:15px; font-weight:700;
  font-variant-numeric:tabular-nums; background:var(--a); color:var(--a-on); }
.ui-hero.is-fill .ui-hero__row { display:flex; justify-content:space-between; align-items:flex-end; gap:16px;
  margin-top:18px; flex-wrap:wrap; }
.ui-hero.is-fill .ui-hero__num, .ui-hero.is-fill .ui-hero__cur { font-size:clamp(34px,10.5vw,46px); }
.ui-hero.is-fill .ui-hero__val { margin-top:6px; }
.ui-hero__pair { text-align:right; }
.ui-hero__pair b { display:block; margin-top:4px; font-size:20px; font-weight:700; font-variant-numeric:tabular-nums;
  color:var(--ui-tx,#e8e8e8); }

/* M-12 KPI-плитки 2 в ряд / M-13 три в ряд с иконкой (.is-3.is-ico) */
.ui-kpi { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:12px; }
.ui-kpi__it { background:var(--ui-surface-2,#1a1a1a); border-radius:18px; padding:16px; box-sizing:border-box;
  min-width:0; display:flex; flex-direction:column; gap:6px; }
.ui-kpi__lbl { font-size:12px; font-weight:600; text-transform:uppercase; letter-spacing:.14em;
  color:var(--ui-tx-2,#8b8b8b); line-height:1.3; }
.ui-kpi__val { font-size:22px; font-weight:700; font-variant-numeric:tabular-nums; letter-spacing:-.01em;
  color:var(--ui-tx,#e8e8e8); line-height:1.15; }
.ui-kpi__u { font-size:13px; font-weight:500; color:var(--ui-tx-2,#8b8b8b); }
.ui-kpi.is-3 { grid-template-columns:repeat(3,minmax(0,1fr)); gap:10px; }
.ui-kpi.is-ico .ui-kpi__it { background:var(--ui-surface,#141414); box-shadow:var(--ui-shadow-sm); align-items:flex-start;
  padding:14px 12px; border-radius:20px; }
.ui-kpi.is-ico .ui-kpi__val { font-size:28px; }
.ui-kpi__ico { width:40px; height:40px; border-radius:50%; display:flex; align-items:center; justify-content:center;
  background:var(--a-soft); color:var(--a); }
.ui-kpi__ico svg { width:20px; height:20px; fill:none; stroke:currentColor; stroke-width:1.9; stroke-linecap:round;
  stroke-linejoin:round; }
.ui-kpi.is-ico .ui-kpi__lbl { font-size:11px; letter-spacing:.08em; }

/* M-14 бейдж-множитель */
.ui-mult { display:inline-flex; align-items:center; justify-content:center; min-width:40px; height:30px; padding:0 12px;
  box-sizing:border-box; border:0; border-radius:999px; cursor:pointer; font-family:inherit; font-size:14px;
  font-weight:700; font-variant-numeric:tabular-nums; background:var(--ui-tx,#e8e8e8); color:var(--ui-bg,#0a0a0a); }

/* M-20/M-22 график (рисует /ui-chart.js) и CSS-минибары */
.ui-chart { position:relative; width:100%; height:190px; }
.ui-chart canvas { display:block; width:100% !important; height:100% !important; }
.ui-chart.is-sm { height:120px; }
.ui-minibars { display:grid; grid-template-columns:repeat(7,minmax(0,1fr)); gap:8px; align-items:end; }
.ui-minibars__c { display:flex; flex-direction:column; align-items:center; gap:6px; }
.ui-minibars__trk { width:100%; max-width:28px; height:96px; border-radius:999px; overflow:hidden; display:flex;
  align-items:flex-end; background:var(--ui-surface-2,#1a1a1a); }
.ui-minibars__trk i { display:block; width:100%; height:calc(var(--h,50) * 1%); border-radius:999px; background:var(--a); }
.ui-minibars__d { font-size:12px; color:var(--ui-tx-2,#8b8b8b); }

/* M-23 кольцо прогресса: --p 0..100, значок в центре */
.ui-ring { position:relative; display:inline-flex; align-items:center; justify-content:center; width:96px; height:96px; }
.ui-ring svg.ui-ring__svg { width:100%; height:100%; transform:rotate(-90deg); fill:none; }
.ui-ring__trk { stroke:var(--a-soft2); stroke-width:9; }
.ui-ring__arc { stroke:var(--a); stroke-width:9; stroke-linecap:round; stroke-dasharray:calc(var(--p,0) * 1px) 100px; }
.ui-ring__ico { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; color:var(--a); }
.ui-ring__ico svg { width:28px; height:28px; fill:none; stroke:currentColor; stroke-width:1.9; stroke-linecap:round;
  stroke-linejoin:round; }

/* M-24 стековый бар долей + легенда (.ui-stack занят — см. шапку блока) */
.ui-stackbar { display:flex; gap:2px; height:12px; border-radius:999px; overflow:hidden; background:var(--ui-surface-2,#1a1a1a); }
.ui-stackbar > i { display:block; min-width:4px; background:var(--a); }
.ui-stackbar > i.s1, .ui-legend .s1 { background:var(--a); }
.ui-stackbar > i.s2, .ui-legend .s2 { background:color-mix(in srgb, var(--a) 72%, var(--ui-surface-2,#1a1a1a)); }
.ui-stackbar > i.s3, .ui-legend .s3 { background:color-mix(in srgb, var(--a) 50%, var(--ui-surface-2,#1a1a1a)); }
.ui-stackbar > i.s4, .ui-legend .s4 { background:color-mix(in srgb, var(--a) 32%, var(--ui-surface-2,#1a1a1a)); }
.ui-stackbar > i.s5, .ui-legend .s5 { background:color-mix(in srgb, var(--a) 18%, var(--ui-surface-2,#1a1a1a)); }
.ui-legend { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; }
.ui-legend > li { display:flex; align-items:center; gap:12px; min-height:44px; font-size:16px;
  border-bottom:1px solid var(--ui-line-2,#1e1e1e); color:var(--ui-tx,#e8e8e8); }
.ui-legend > li:last-child { border-bottom:0; }
.ui-legend > li > i { flex:0 0 auto; width:10px; height:10px; border-radius:50%; }
.ui-legend > li > span { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ui-legend > li > b { font-weight:700; font-variant-numeric:tabular-nums; }
.ui-legend > li.is-more { color:var(--ui-tx-2,#8b8b8b); cursor:pointer; }
.ui-legend > li > svg { flex:0 0 auto; width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round; transform:rotate(-90deg); }

/* M-30 сегмент из 2 пилюль: активная залита акцентом */
.ui-seg { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; }
.ui-seg__b { min-height:52px; padding:8px 16px; box-sizing:border-box; border-radius:999px; cursor:pointer;
  font-family:inherit; font-size:15px; font-weight:600; line-height:1.2; text-align:center; display:flex;
  align-items:center; justify-content:center; background:var(--ui-surface-2,#1a1a1a); color:var(--ui-tx,#e8e8e8);
  border:1px solid var(--ui-line,#262626); transition:background .15s,color .15s,border-color .15s; }
.ui-seg__b.is-on { background:var(--a); border-color:var(--a); color:var(--a-on); }

/* M-31 главная CTA во всю ширину — роль .btn, модификатор .is-cta (ADR-063).
   Геометрия роли объявлена с !important и длинной цепочкой :not(), поэтому :not(#_)
   поднимает специфичность (id) и модификатор побеждает. Цвет остаётся из роли. */
.btn.is-cta:not(#_) { display:flex !important; width:100%; box-sizing:border-box; min-height:56px !important;
  border-radius:20px !important; font-size:18px !important; font-weight:700 !important; padding:0 24px !important; }

/* M-33 фолд-строка: заголовок капсом + описание + круглый шеврон (ADR-083, один шеврон) */
.ui-fold.is-m { background:var(--ui-surface,#141414); border-radius:24px; padding:16px 20px; box-shadow:var(--ui-shadow-sm); }
.ui-fold.is-m .ui-fold-head { margin:0; padding:0; min-height:var(--ui-tap,44px); gap:12px; color:var(--ui-tx,#e8e8e8);
  background:none; }
.ui-fold.is-m .ui-fold-head:hover { background:none; color:var(--ui-tx,#e8e8e8); }
.ui-fold.is-m .ui-fold-t { flex:1; min-width:0; display:flex; flex-direction:column; gap:3px; }
.ui-fold.is-m .ui-fold-d { font-size:14px; color:var(--ui-tx-2,#8b8b8b); }
.ui-fold.is-m .ui-fab svg { transition:transform .25s cubic-bezier(.4,0,.2,1); }
.ui-fold.is-m[data-open="1"] .ui-fab svg { transform:rotate(180deg); }
.ui-fold.is-m[data-open="1"] .ui-fold-body > .ui-fold-inner { padding-top:14px; }

/* M-40 строка-привычка/задача, M-41 строка-прогресс */
.ui-item { display:flex; align-items:center; gap:14px; padding:14px 16px; box-sizing:border-box; min-width:0;
  background:var(--ui-surface,#141414); border-radius:20px; box-shadow:var(--ui-shadow-sm); }
.ui-item__ico { flex:0 0 auto; width:44px; height:44px; border-radius:14px; display:flex; align-items:center;
  justify-content:center; background:var(--a-soft); color:var(--a); }
.ui-item__ico svg { width:22px; height:22px; fill:none; stroke:currentColor; stroke-width:1.9; stroke-linecap:round;
  stroke-linejoin:round; }
.ui-item__body { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
.ui-item__tt { font-size:17px; font-weight:600; line-height:1.25; color:var(--ui-tx,#e8e8e8); overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.ui-item__sub { font-size:14px; color:var(--ui-tx-2,#8b8b8b); line-height:1.3; }
.ui-item__end { flex:0 0 auto; display:flex; flex-direction:column; align-items:flex-end; gap:6px; }
.ui-item__st { font-size:13px; font-weight:600; color:var(--ui-tx-2,#8b8b8b); }
.ui-item__bdg { font-size:12px; font-weight:700; padding:3px 10px; border-radius:999px; background:var(--a-soft);
  color:var(--a); font-variant-numeric:tabular-nums; }
.ui-item .ui-prog { margin-top:8px; }
.ui-check-round { display:inline-flex; align-items:center; justify-content:center; flex:0 0 auto; position:relative;
  width:28px; height:28px; min-width:28px; padding:0; margin:0; box-sizing:border-box; border-radius:50%;
  border:2px solid var(--ui-line,#262626); background:transparent; cursor:pointer; transition:background .15s,border-color .15s; }
.ui-check-round.is-done { background:var(--ui-ok,#34d399); border-color:var(--ui-ok,#34d399); }
.ui-check-round.is-done::after { content:""; position:absolute; left:50%; top:46%; width:6px; height:11px;
  box-sizing:border-box; border:solid var(--ui-bg,#0a0a0a); border-width:0 2.5px 2.5px 0;
  transform:translate(-50%,-50%) rotate(45deg); }
.ui-prog { display:flex; gap:4px; width:100%; }
.ui-prog > i { flex:1; height:8px; border-radius:999px; background:var(--ui-surface-2,#1a1a1a); }
.ui-prog > i.on { background:var(--a); }
.ui-prog.is-ok > i.on { background:var(--ui-ok,#34d399); }

/* M-42 сетка «иконка + подпись», M-43 пара через разделитель, M-44 ссылка-действие */
.ui-icgrid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:18px 12px; }
.ui-icgrid__it { display:flex; align-items:center; gap:12px; min-width:0; font-size:16px; color:var(--ui-tx,#e8e8e8); }
.ui-icgrid__c { flex:0 0 auto; width:56px; height:56px; border-radius:50%; display:flex; align-items:center;
  justify-content:center; background:var(--a-soft); color:var(--a); }
.ui-icgrid__c svg { width:26px; height:26px; fill:none; stroke:currentColor; stroke-width:1.75; stroke-linecap:round;
  stroke-linejoin:round; }
.ui-pair { display:grid; grid-template-columns:minmax(0,1fr) 1px minmax(0,1fr); gap:16px; align-items:center; }
.ui-pair__sep { align-self:stretch; background:var(--ui-line-2,#1e1e1e); }
.ui-pair__it { display:flex; flex-direction:column; gap:4px; min-width:0; }
.ui-pair__it svg { width:22px; height:22px; fill:none; stroke:var(--a); stroke-width:1.9; stroke-linecap:round;
  stroke-linejoin:round; }
.ui-pair__t { font-size:12px; font-weight:600; text-transform:uppercase; letter-spacing:.14em; color:var(--ui-tx-2,#8b8b8b); }
.ui-pair__v { font-size:20px; font-weight:700; font-variant-numeric:tabular-nums; color:var(--ui-tx,#e8e8e8); }
.ui-more { display:inline-flex; align-items:center; gap:4px; min-height:var(--ui-tap,44px); font-size:16px;
  font-weight:700; color:var(--ui-tx,#e8e8e8); text-decoration:underline; text-underline-offset:3px; cursor:pointer;
  background:none; border:0; padding:0; font-family:inherit; }
.ui-more svg { width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round;
  stroke-linejoin:round; transform:rotate(-90deg); }

/* M-50 стрик-полоса недели */
.ui-streak { display:flex; flex-direction:column; gap:16px; }
.ui-streak__top { display:flex; align-items:center; gap:14px; }
.ui-streak__art { flex:0 0 auto; width:64px; height:64px; border-radius:50%; display:flex; align-items:center;
  justify-content:center; background:var(--a-soft); color:var(--a); }
.ui-streak__art svg { width:30px; height:30px; fill:none; stroke:currentColor; stroke-width:1.75; stroke-linecap:round;
  stroke-linejoin:round; }
.ui-streak__n { font-size:28px; font-weight:800; line-height:1.1; letter-spacing:-.01em; color:var(--ui-tx,#e8e8e8); }
.ui-streak__s { margin-top:2px; font-size:14px; color:var(--ui-tx-2,#8b8b8b); }
.ui-streak__week { display:grid; grid-template-columns:repeat(7,minmax(0,1fr)); gap:2px; padding:10px 8px;
  border-radius:999px; background:var(--a-soft); }
.ui-streak__d { display:flex; flex-direction:column; align-items:center; gap:6px; font-size:12px; font-weight:600;
  color:var(--ui-tx-2,#8b8b8b); }
.ui-streak__c { width:32px; height:32px; border-radius:50%; box-sizing:border-box; display:flex; align-items:center;
  justify-content:center; font-size:14px; font-weight:600; font-variant-numeric:tabular-nums; color:var(--ui-tx-3,#6a6a6a); }
.ui-streak__c svg { width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:2.4; stroke-linecap:round;
  stroke-linejoin:round; }
.ui-streak__d.is-done .ui-streak__c { background:var(--a); color:var(--a-on); }
.ui-streak__d.is-today .ui-streak__c { box-shadow:0 0 0 4px color-mix(in srgb, var(--a) 35%, transparent);
  color:var(--ui-tx,#e8e8e8); background:var(--ui-surface,#141414); }

/* M-51 прогресс-баннер: насыщенная заливка акцентом, чипы-подсказки */
.ui-banner { display:flex; flex-direction:column; gap:14px; padding:22px; box-sizing:border-box; border-radius:24px;
  background:var(--a); color:var(--a-on); }
.ui-banner__top { display:flex; align-items:center; gap:14px; }
.ui-banner__art { flex:0 0 auto; width:56px; height:56px; border-radius:50%; display:flex; align-items:center;
  justify-content:center; background:color-mix(in srgb, var(--a-on) 20%, transparent); }
.ui-banner__art svg { width:28px; height:28px; fill:none; stroke:currentColor; stroke-width:1.75; stroke-linecap:round;
  stroke-linejoin:round; }
.ui-banner__t { font-size:20px; font-weight:800; line-height:1.2; }
.ui-banner .ui-prog > i { background:color-mix(in srgb, var(--a-on) 28%, transparent); }
.ui-banner .ui-prog > i.on { background:var(--a-on); }
.ui-banner__chips { display:flex; flex-wrap:wrap; gap:8px; }
.ui-banner__chip { padding:6px 14px; border-radius:999px; font-size:13px; font-weight:600;
  background:color-mix(in srgb, var(--a-on) 20%, transparent); }

/* M-60 инфо-заметка между разделителями (заменяет локальный .br-doc) */
.ui-note { display:flex; gap:12px; align-items:flex-start; padding:16px 0; font-size:16px; line-height:1.45;
  color:var(--ui-tx-2,#8b8b8b); border-top:1px solid var(--ui-line-2,#1e1e1e); border-bottom:1px solid var(--ui-line-2,#1e1e1e); }
.ui-note__i { flex:0 0 auto; width:28px; height:28px; border-radius:50%; display:flex; align-items:center;
  justify-content:center; background:var(--a-soft); color:var(--a); }
.ui-note__i svg { width:16px; height:16px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round;
  stroke-linejoin:round; }
.ui-hello__col { display:flex; flex-direction:column; align-items:flex-end; gap:16px; }
.ui-end { display:flex; justify-content:flex-end; }
.ui-list { display:flex; flex-direction:column; gap:12px; }
@media (prefers-reduced-motion: reduce) {
  .ui-fab, .ui-seg__b, .ui-check-round, .ui-fold.is-m .ui-fab svg, .ui-fabcam, .ui-curchip__b,
  .ui-segsum__b, .ui-interval__btn { transition:none; }
}

/* =========================================================================
   МОБИЛЬНЫЙ КИТ, АВТО (M-63..M-71) — задача #434, 02.10.2026. Образцы — /refs#mobile.
   Те же правила, что у M-01..M-62: акцент --ui-acc (--a), пастель color-mix, без градиентов,
   только токены --ui-* (обе темы, ADR-216/254). Тон «внимание» — модификатор .is-warn/.is-bad.
   ========================================================================= */
:where(.ui-cover,.ui-segsum,.ui-evcheck,.ui-fabcam,.ui-remring,.ui-perkm,.ui-buyer,.ui-curchip,.ui-interval) {
  --a: var(--ui-acc, var(--ui-brand,#00a0ff));
  --a-soft: color-mix(in srgb, var(--a) 14%, var(--ui-surface,#141414));
  --a-soft2: color-mix(in srgb, var(--a) 24%, var(--ui-surface,#141414));
  --a-on: var(--ui-btn1-text,#fff);
}
.ui-remring.is-warn, .ui-evcheck.is-warn { --a: var(--ui-warn,#fbbf24); --a-on: var(--ui-bg,#0a0a0a); }
.ui-remring.is-bad { --a: var(--ui-danger,#f87171); --a-on: var(--ui-bg,#0a0a0a); }
.ui-remring.is-ok, .ui-evcheck.is-ok { --a: var(--ui-ok,#4ade80); --a-on: var(--ui-bg,#0a0a0a); }

/* M-63 обложка-фото авто с пробегом: <img class="ui-cover__img"> или плоская заглушка (без градиента) */
.ui-cover { position:relative; overflow:hidden; border-radius:24px; min-height:176px; box-sizing:border-box;
  display:flex; flex-direction:column; justify-content:flex-end; background:var(--a-soft2); color:var(--ui-tx,#e8e8e8); }
.ui-cover__img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block; }
.ui-cover__ph { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; color:var(--a); opacity:.55; }
.ui-cover__ph svg { width:72px; height:72px; fill:none; stroke:currentColor; stroke-width:1.4; stroke-linecap:round;
  stroke-linejoin:round; }
.ui-cover__cap { position:relative; display:flex; align-items:baseline; justify-content:space-between; gap:12px;
  padding:12px 18px; background:color-mix(in srgb, var(--ui-bg,#0a0a0a) 78%, transparent);
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px); }
.ui-cover__nm { margin:0; font-size:22px; font-weight:800; line-height:1.15; letter-spacing:-.01em; min-width:0; }
.ui-cover__sub { display:block; margin-top:2px; font-size:13px; color:var(--ui-tx-2,#8b8b8b); }
.ui-cover__od { flex:0 0 auto; font-size:18px; font-weight:700; font-variant-numeric:tabular-nums; white-space:nowrap; }

/* M-64 сегмент 4 вкладки + сумма периода */
.ui-segsum { display:flex; flex-direction:column; gap:14px; }
.ui-segsum__tabs { display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:2px; padding:3px; border-radius:999px;
  background:var(--ui-surface-2,#1a1a1a); border:1px solid var(--ui-line,#262626); }
.ui-segsum__b { min-height:40px; padding:6px 4px; box-sizing:border-box; border:0; border-radius:999px; cursor:pointer;
  font-family:inherit; font-size:14px; font-weight:600; background:transparent; color:var(--ui-tx-2,#8b8b8b);
  transition:background .15s,color .15s; }
.ui-segsum__b.is-on { background:var(--a); color:var(--a-on); }
.ui-segsum__sum { display:flex; align-items:flex-end; justify-content:space-between; gap:12px; padding-bottom:12px;
  border-bottom:1px solid var(--ui-line-2,#1e1e1e); }
.ui-segsum__val { display:block; margin-top:4px; font-size:30px; font-weight:800; line-height:1.1; letter-spacing:-.02em;
  font-variant-numeric:tabular-nums; color:var(--ui-tx,#e8e8e8); }
.ui-segsum__n { font-size:14px; color:var(--ui-tx-2,#8b8b8b); white-space:nowrap; }

/* M-65 строка события с миниатюрой чека (<img class="ui-evcheck__th"> или плоская заглушка с иконкой) */
.ui-evcheck { display:flex; align-items:center; gap:14px; padding:12px 16px 12px 12px; box-sizing:border-box; min-width:0;
  background:var(--ui-surface,#141414); border-radius:20px; box-shadow:var(--ui-shadow-sm); }
.ui-evcheck__th { flex:0 0 auto; width:48px; height:58px; border-radius:10px; box-sizing:border-box; object-fit:cover;
  display:flex; align-items:center; justify-content:center; background:var(--ui-surface-2,#1a1a1a);
  border:1px solid var(--ui-line,#262626); color:var(--ui-tx-3,#6a6a6a); }
.ui-evcheck__th svg { width:22px; height:22px; fill:none; stroke:currentColor; stroke-width:1.8; stroke-linecap:round;
  stroke-linejoin:round; }
.ui-evcheck__body { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
.ui-evcheck__tt { font-size:17px; font-weight:600; line-height:1.25; color:var(--ui-tx,#e8e8e8); overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.ui-evcheck__sub { font-size:14px; color:var(--ui-tx-2,#8b8b8b); line-height:1.3; }
.ui-evcheck__amt { flex:0 0 auto; padding:4px 12px; border-radius:999px; font-size:14px; font-weight:700; white-space:nowrap;
  font-variant-numeric:tabular-nums; background:var(--a-soft); color:var(--a); }

/* M-66 кнопка-камера «скан в 1 тап» с подписью: <button class="ui-fabcam"><span class="ui-fabcam__lbl">…</span>
   <span class="ui-fabcam__c">svg</span></button>; поверх экрана — добавить position:fixed своим контейнером */
.ui-fabcam { display:inline-flex; align-items:center; gap:10px; padding:0; margin:0; border:0; background:none; cursor:pointer;
  font-family:inherit; color:inherit; min-height:var(--ui-tap,44px); }
.ui-fabcam__lbl { padding:6px 12px; border-radius:10px; font-size:13px; font-weight:700; background:var(--ui-tx,#e8e8e8);
  color:var(--ui-bg,#0a0a0a); }
.ui-fabcam__c { flex:0 0 auto; width:56px; height:56px; border-radius:50%; display:flex; align-items:center;
  justify-content:center; background:var(--a); color:var(--a-on); box-shadow:var(--ui-shadow-md); transition:transform .12s ease-out; }
.ui-fabcam:active .ui-fabcam__c { transform:scale(.96); }
.ui-fabcam__c svg { width:26px; height:26px; fill:none; stroke:currentColor; stroke-width:1.9; stroke-linecap:round;
  stroke-linejoin:round; }

/* M-67 кольцо напоминания «осталось км / дни»: --p 0..100 (доля израсходованного ресурса), тон — .is-warn/.is-bad/.is-ok */
.ui-remring { display:flex; align-items:center; gap:16px; padding:16px; box-sizing:border-box; min-width:0;
  background:var(--ui-surface,#141414); border-radius:24px; box-shadow:var(--ui-shadow-sm); }
.ui-remring__r { position:relative; flex:0 0 auto; width:76px; height:76px; display:flex; align-items:center; justify-content:center; }
.ui-remring__svg { width:100%; height:100%; transform:rotate(-90deg); fill:none; }
.ui-remring__trk { stroke:var(--a-soft2); stroke-width:9; }
.ui-remring__arc { stroke:var(--a); stroke-width:9; stroke-linecap:round; stroke-dasharray:calc(var(--p,0) * 1px) 100px; }
.ui-remring__pc { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; font-size:15px;
  font-weight:700; font-variant-numeric:tabular-nums; color:var(--ui-tx,#e8e8e8); }
.ui-remring__body { flex:1; min-width:0; display:flex; flex-direction:column; gap:3px; }
.ui-remring__tt { font-size:18px; font-weight:700; line-height:1.2; color:var(--ui-tx,#e8e8e8); }
.ui-remring__left { font-size:14px; color:var(--ui-tx-2,#8b8b8b); line-height:1.35; }
.ui-remring__left b { font-weight:700; color:var(--ui-tx,#e8e8e8); font-variant-numeric:tabular-nums; }

/* M-68 плашка «стоимость км» */
.ui-perkm { display:inline-flex; align-items:baseline; gap:8px; max-width:100%; box-sizing:border-box; padding:12px 16px;
  background:var(--a-soft); border-radius:18px; color:var(--ui-tx,#e8e8e8); }
.ui-perkm__v { font-size:30px; font-weight:800; line-height:1; letter-spacing:-.02em; font-variant-numeric:tabular-nums; }
.ui-perkm__u { font-size:14px; font-weight:600; color:var(--ui-tx-2,#8b8b8b); }

/* M-69 карточка «история для покупателя» */
.ui-buyer { display:flex; flex-direction:column; gap:12px; padding:20px; box-sizing:border-box; min-width:0;
  background:var(--ui-surface,#141414); border-radius:24px; box-shadow:var(--ui-shadow-sm); }
.ui-buyer__row { display:flex; align-items:baseline; justify-content:space-between; gap:12px; min-height:28px;
  border-bottom:1px solid var(--ui-line-2,#1e1e1e); padding-bottom:10px; font-size:15px; color:var(--ui-tx-2,#8b8b8b); }
.ui-buyer__row:last-of-type { border-bottom:0; padding-bottom:0; }
.ui-buyer__row b { font-weight:700; text-align:right; font-variant-numeric:tabular-nums; color:var(--ui-tx,#e8e8e8); }

/* M-70 чип валюты (группа из 2-4 чипов, активный залит акцентом) */
.ui-curchip { display:inline-flex; gap:6px; }
.ui-curchip__b { min-width:var(--ui-tap,44px); min-height:36px; padding:0 14px; box-sizing:border-box; border-radius:999px;
  cursor:pointer; font-family:inherit; font-size:14px; font-weight:700; background:var(--ui-surface-2,#1a1a1a);
  color:var(--ui-tx,#e8e8e8); border:1px solid var(--ui-line,#262626); transition:background .15s,color .15s,border-color .15s; }
.ui-curchip__b.is-on { background:var(--a); border-color:var(--a); color:var(--a-on); }

/* M-71 интервал «N км или M мес»: два степпера через «или» */
.ui-interval { display:flex; flex-wrap:wrap; align-items:center; justify-content:center; gap:10px 12px; padding:14px 16px;
  box-sizing:border-box; background:var(--ui-surface,#141414); border-radius:20px; box-shadow:var(--ui-shadow-sm);
  font-size:15px; color:var(--ui-tx-2,#8b8b8b); }
.ui-interval__g { display:inline-flex; align-items:center; gap:8px; }
.ui-interval__btn { width:36px; height:36px; min-width:36px; padding:0; box-sizing:border-box; border-radius:50%; cursor:pointer;
  font-family:inherit; font-size:18px; line-height:1; background:var(--ui-surface-2,#1a1a1a); color:var(--ui-tx,#e8e8e8);
  border:1px solid var(--ui-line,#262626); transition:background .15s; }
.ui-interval__v { min-width:3ch; text-align:center; font-size:20px; font-weight:800; font-variant-numeric:tabular-nums;
  color:var(--ui-tx,#e8e8e8); }
.ui-interval__or { font-size:12px; font-weight:600; text-transform:uppercase; letter-spacing:.14em; }

/* =========================================================================
   МОБИЛЬНЫЙ КИТ, ДОБАВКИ (M-72..M-76) — 06.10.2026. Образцы — /refs#mobile.
   Кольцо со значением, сегмент на N кнопок, поле с единицей, ползунок, аннотации графика.
   ========================================================================= */

/* M-72 кольцо с процентом: <div class="ui-ring is-val" style="--p:77;--ring:96px"> svg как у M-23 +
   <span class="ui-ring__val">77%</span>. Размер задаёт --ring, шрифт значения считается от него.
   Дуга с плоским концом; при --p>0 она не тоньше 2 (min/max), при --p=0 её нет совсем. */
.ui-ring.is-val { width:var(--ring,96px); height:var(--ring,96px); }
.ui-ring.is-val .ui-ring__trk { stroke:var(--a-soft2); }
.ui-ring.is-val .ui-ring__arc { stroke:var(--ui-brand,#00a0ff); stroke-linecap:butt;
  stroke-dasharray:min(max(calc(var(--p,0) * 1px), 2px), calc(var(--p,0) * 1000px)) 100px; }
.ui-ring__val { position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  font-size:calc(var(--ring,96px) * .24); font-weight:800; line-height:1; letter-spacing:-.02em;
  font-variant-numeric:tabular-nums; color:var(--ui-tx,#e8e8e8); }

/* M-73 сегмент на N кнопок: <div class="ui-seg is-n"> с любым числом .ui-seg__b; активная — цвета вкладок /set */
.ui-seg.is-n { grid-template-columns:none; grid-auto-flow:column; grid-auto-columns:minmax(0,1fr); gap:6px; }
.ui-seg.is-n .ui-seg__b { min-height:var(--ui-tap,44px); padding:6px 8px; font-size:14px; }
.ui-seg.is-n .ui-seg__b.is-on { background:var(--ui-tab-on-bg,var(--ui-card-border,#262626));
  border-color:var(--ui-tab-on-bg,var(--ui-card-border,#262626)); color:var(--ui-tab-on-tx,var(--ui-tx,#e8e8e8)); }

/* M-74 поле с единицей: <div class="pf-field has-suffix"><input ...><span class="pf-field__suffix">₽</span></div>.
   Единица — отдельный flex-сосед справа, поверх поля не лежит: плавающая подпись ui-forms.js (.ui-fl вокруг
   input) остаётся внутри своей обёртки и суффикса не касается. */
.pf-field.has-suffix { align-items:center; }
.pf-field.has-suffix > input, .pf-field.has-suffix > .ui-fl { flex:1 1 auto; min-width:0; }
.pf-field.has-suffix input { background:transparent; border:0; outline:0; box-shadow:none; margin:0; min-width:0;
  padding-left:0; padding-right:0; color:var(--ui-inp-text,#fff); font-family:inherit; font-size:var(--ui-inp-fs,13.5px); }
.pf-field.has-suffix .ui-fl { --fl-pl:0px; }
.pf-field__suffix { flex:0 0 auto; margin-left:8px; line-height:1; white-space:nowrap; user-select:none;
  pointer-events:none; font-size:var(--ui-inp-fs,13.5px); color:var(--ui-tx-2,#8b8b8b); }
@media (max-width:768px) { .pf-field.has-suffix input, .pf-field__suffix { font-size:16px; } }

/* M-75 ползунок: <input type="range" class="ui-range"> + <div class="ui-range__ends"><span class="ui-hint">0</span>
   <span class="ui-hint">100</span></div>. Размеры — --ui-range-trk (трек) и --ui-range-thumb (бегунок). */
.ui-range { -webkit-appearance:none; appearance:none; display:block; width:100%; margin:0; padding:0; box-sizing:border-box;
  min-height:var(--ui-tap,44px); background:transparent; cursor:pointer; accent-color:var(--ui-brand,#00a0ff); }
.ui-range::-webkit-slider-runnable-track { height:var(--ui-range-trk,6px); border-radius:999px; background:var(--ui-surface-2,#1a1a1a);
  border:1px solid var(--ui-line,#262626); box-sizing:border-box; }
.ui-range::-moz-range-track { height:var(--ui-range-trk,6px); border-radius:999px; background:var(--ui-surface-2,#1a1a1a);
  border:1px solid var(--ui-line,#262626); box-sizing:border-box; }
.ui-range::-moz-range-progress { height:var(--ui-range-trk,6px); border-radius:999px; background:var(--ui-brand,#00a0ff); }
.ui-range::-webkit-slider-thumb { -webkit-appearance:none; appearance:none; box-sizing:border-box; border-radius:50%;
  width:var(--ui-range-thumb,24px); height:var(--ui-range-thumb,24px); background:var(--ui-brand,#00a0ff);
  border:3px solid var(--ui-surface,#141414); box-shadow:var(--ui-shadow-sm);
  margin-top:calc((var(--ui-range-trk,6px) - var(--ui-range-thumb,24px)) / 2); }
.ui-range::-moz-range-thumb { box-sizing:border-box; border-radius:50%; width:var(--ui-range-thumb,24px);
  height:var(--ui-range-thumb,24px); background:var(--ui-brand,#00a0ff); border:3px solid var(--ui-surface,#141414);
  box-shadow:var(--ui-shadow-sm); }
.ui-range:disabled { opacity:.5; cursor:not-allowed; }
.ui-range__ends { display:flex; justify-content:space-between; gap:12px; }
.ui-range__ends .ui-hint { margin-top:0; }

/* M-76 аннотации графика (рисует /ui-chart.js, опции hline / marker): DOM-слой поверх canvas внутри .ui-chart */
.ui-chart__hline { position:absolute; height:0; margin:0; padding:0; pointer-events:none; z-index:1;
  border-top:1px dashed var(--ui-tx-2,#8b8b8b); }
.ui-chart__hline > span { position:absolute; right:0; bottom:3px; font-size:12px; line-height:1.2; white-space:nowrap;
  color:var(--ui-tx-2,#8b8b8b); }
.ui-chart__marker { position:absolute; width:0; height:0; pointer-events:none; z-index:2; }
.ui-chart__marker > i { position:absolute; left:-7px; top:-7px; width:14px; height:14px; box-sizing:border-box;
  border-radius:50%; background:var(--a); border:3px solid var(--ui-surface,#141414); }
.ui-chart__marker > span { position:absolute; left:0; bottom:12px; transform:translateX(-50%); padding:3px 8px;
  border-radius:999px; font-size:12px; font-weight:600; line-height:1.2; white-space:nowrap;
  background:var(--ui-surface,#141414); color:var(--ui-tx,#e8e8e8); box-shadow:var(--ui-shadow-sm); }

/* Панель разделов (шаблон: /sets, /refs) — task #217
   Разметка: .wrap > .panel > (.set-nav + .set-pane). Слева меню со строкой «Поиск раздела»
   (.set-search), группами (.set-grp) и строками (.set-item > svg.si-ico + .si-txt), справа раздел.
   Правила перенесены из <style> set.html без изменения вида (панель нарисована литералами и в
   светлой теме остаётся тёмной — так было на /set). Базовые правила .panel и .wrap привязаны
   через :has(> .set-nav): на страницах со своим .panel (crawl.html) они не срабатывают.
   Ширина: обёртка тянется до правого края окна, справа тот же зазор, что слева (28px, на телефоне —
   --ui-page-pad-m); на очень широких экранах потолок 2200px, панель прижата влево. */
.wrap:has(> .panel > .set-nav){padding:26px 28px;max-width:2200px;margin:0 auto 0 0;}
.wrap:has(> .panel > .set-nav) > h1{margin:0 0 18px;}
.panel:has(> .set-nav){display:flex;background:#111;border:1px solid #1e1e1e;border-radius:14px;overflow:hidden;overflow:clip;min-height:540px;box-shadow:var(--ui-shadow-md,0 6px 18px -2px rgba(0,0,0,.30));}
.set-nav{width:230px;flex-shrink:0;background:#0d0d0d;border-right:1px solid #1a1a1a;padding:16px 12px;}
.set-search{width:100%;background:#141414;border:1px solid #242424;border-radius:9px;color:#ddd;padding:8px 11px;font-size:13px;margin-bottom:14px;}
.set-search::placeholder{color:#555;}
.set-item{display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:9px;color:#aaa;font-size:14px;cursor:pointer;user-select:none;transition:background .15s,color .15s;}
.set-item:hover{background:#161616;color:#fff;}
.set-item.active{background:var(--ui-brand,#00a0ff);color:#fff;font-weight:600;}
.set-item svg{width:16px;height:16px;flex-shrink:0;}
.set-item .si-c{margin-left:auto;font-size:12px;font-weight:400;color:#666;white-space:nowrap;}
.set-item.active .si-c{color:rgba(255,255,255,.75);}
.set-grp{padding:14px 12px 6px;font-size:10px;letter-spacing:.07em;text-transform:uppercase;color:var(--ui-tx-3,#6a6a6a);}
.set-grp:first-child{padding-top:2px;}
.set-pane{flex:1;padding:26px 30px;min-width:0;}
.set-pane h2{font-size:20px;margin:0 0 6px;}
.set-pane .sub{color:#777;font-size:13px;margin:0 0 22px;line-height:1.5;}
/* Мобильные части списка разделов — на десктопе их нет: строка возврата к списку,
   подпись «Разделы» над поиском, пояснение под названием раздела и шеврон «вперёд». */
.set-nav .sn-bar,
.set-nav .sn-cap{display:none;}
.set-item .si-note,
.set-item .si-go{display:none;}
@media (max-width:768px){
  .wrap:has(> .panel > .set-nav){width:100%;max-width:100%;padding:14px var(--ui-page-pad-m,14px) calc(24px + env(safe-area-inset-bottom));}
  .wrap:has(> .panel > .set-nav) > h1{margin-right:54px;}   /* место под ☰ портала в правом верхнем углу */
  .panel:has(> .set-nav){flex-direction:column;min-height:0;width:100%;border-radius:var(--ui-card-radius,14px);}
  .set-pane{padding:var(--ui-page-pad-m,14px) var(--ui-page-pad-m,14px) 20px;}
  /* Разделы на мобиле — сначала СПИСОК, потом раздел: тап по строке показывает раздел, шапка списка
     превращается в кнопку возврата. Состояние держит класс .sec-open на .panel (ставит openSec/openXxx,
     снимает secBack). На ПК он ни на что не влияет: все правила состояния — внутри этого медиазапроса. */
  .set-nav{
    width:auto;flex-shrink:1;background:transparent;
    border-right:0;border-bottom:0;
    padding:var(--ui-page-pad-m,14px) 0 0;
  }
  .panel:not(.sec-open) .set-pane{display:none;}
  .panel.sec-open .set-nav{border-bottom:1px solid var(--ui-line-2,#1e1e1e);}
  .panel.sec-open .set-nav .sn-cap,
  .panel.sec-open .set-nav .sn-body{display:none;}
  .set-nav .sn-cap{
    display:block;
    padding:0 var(--ui-page-pad-m,14px) 10px;font-size:10px;letter-spacing:.07em;
    text-transform:uppercase;color:var(--ui-tx-3,#6a6a6a);
  }
  .set-nav .sn-body{display:block;}
  .set-search{
    display:block;width:auto;margin:0 var(--ui-page-pad-m,14px) 12px;
    padding:11px 12px;font-size:15px;
  }
  /* Строка раздела — тот же компонент, что строка шторки нижнего дока (.cfbn-row):
     плитка со значком, название, пояснение, шеврон, зона тапа 56px. */
  .set-item{
    gap:14px;min-height:56px;margin-bottom:0;padding:8px var(--ui-page-pad-m,14px);
    border-radius:0;border-top:1px solid var(--ui-line-2,#1e1e1e);
    color:var(--ui-tx,#e8e8e8);font-size:15px;
  }
  .set-grp{padding:16px var(--ui-page-pad-m,14px) 8px;}
  /* Выбранный раздел в списке не подсвечиваем: список — это выбор, а не «где я сейчас». */
  .set-item.active{background:transparent;color:var(--ui-tx,#e8e8e8);font-weight:400;}
  .set-item .si-ico{
    width:36px;height:36px;padding:8px;border-radius:10px;
    background:var(--ui-surface-2,#1a1a1a);color:var(--ui-brand,#00a0ff);
  }
  .set-item .si-txt{flex:1;min-width:0;}
  .set-item .si-c{margin-left:0;}
  .set-item .si-note{
    display:block;margin-top:2px;font-size:12px;line-height:1.4;color:var(--ui-tx-3,#6a6a6a);
  }
  .set-item .si-go{
    display:block;width:18px;height:18px;flex-shrink:0;
    color:var(--ui-tx-3,#6a6a6a);transform:rotate(-90deg);
  }
  /* Строка возврата вместо шапки-аккордеона. Классов ролей (.btn/.tbtn/.ibtn) кнопке НЕ даём
     намеренно: без них btnCss() её не трогает, и вид задаётся здесь (ADR-063). */
  .panel.sec-open .set-nav .sn-bar{
    display:flex;align-items:center;gap:12px;
    padding:0 var(--ui-page-pad-m,14px) var(--ui-page-pad-m,14px);
  }
  .sn-back{
    display:flex;align-items:center;gap:7px;flex:0 0 auto;
    min-height:var(--ui-field-h,44px);padding:0 14px 0 10px;
    background:var(--ui-surface,#141414);border:1px solid var(--ui-line,#262626);
    border-radius:var(--ui-radius,10px);color:var(--ui-tx,#e8e8e8);
    font-family:inherit;font-size:15px;cursor:pointer;
    -webkit-tap-highlight-color:transparent;
  }
  .sn-back svg{width:17px;height:17px;flex-shrink:0;color:var(--ui-brand,#00a0ff);transform:rotate(90deg);}
  .sn-now{display:flex;align-items:center;gap:8px;min-width:0;color:var(--ui-tx-2,#8b8b8b);font-size:13px;}
  .sn-now .sn-cur-ico{width:15px;height:15px;flex-shrink:0;color:var(--ui-brand,#00a0ff);}
  .sn-now span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  /* последний рубеж: ничего не должно вылезать за экран и тянуть страницу вбок */
  .set-pane img,.set-pane table,.set-pane pre{max-width:100%;}
}

/* Раскладка на flex (06.10.2026, #217): см. docs/rules/ui.md. Без @media и !important. */
.fx-row{display:flex;align-items:center;gap:var(--fx-gap,12px)}
.fx-col{display:flex;flex-direction:column;gap:var(--fx-gap,12px)}
.fx-wrap{display:flex;flex-wrap:wrap;gap:var(--fx-gap,8px)}
.fx-grow{flex:1 1 auto;min-width:0}
.fx-fit{flex:none}
.fx-tile{flex:1 1 var(--fx-tile,220px);min-width:0}
.fx-ellipsis{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fx-center{display:flex;justify-content:safe center;align-items:safe center}

/* Шаблоны v73 (06.10.2026). .ui-grid.is-2 — две колонки, на ≤360px одна; .wide — на всю ширину. Подписи над полями не рисует (ui.md: имя поля — в placeholder). */
.ui-grid.is-2{grid-template-columns:repeat(2,minmax(0,1fr))}
.ui-grid.is-2>.wide{grid-column:1 / -1}
@media (max-width:360px){.ui-grid.is-2{grid-template-columns:minmax(0,1fr)}}
/* .ui-grid.is-2 > label — подпись над select/датой столбцом (/ui-forms.js плавающую подпись им не делает; готового паттерна на платформе нет). */
.ui-grid.is-2>label{display:grid;gap:4px;min-width:0;font-size:12px;color:var(--ui-tx-2,#8b8b8b)}
.ui-grid.is-2>label>:is(input,select){min-width:0;max-width:100%}
/* .ui-dock-pad — отступ под нижний док: --cfbn-pad публикует bottom-nav.js (только на мобиле, без safe-area), на ПК 0. */
.ui-dock-pad{padding-bottom:calc(var(--cfbn-pad,0px) + env(safe-area-inset-bottom,0px))}

/* ===== .insta-sheet — «инста снизу» (13.10.2026, #381): нижняя шторка-карточки, листание как в Instagram, над доком =====
   Подложка и шторка заканчиваются НАД нижним меню (bottom = высота дока): док #cfbn (z 450) остаётся виден и доступен.
   z-index 520: выше дока и его подложки (>445), ниже .mdl-back (600). Высота — от --ui-sheet-h (минус док), не vh.
   Листание (сегменты .insta-sheet__bars, тап по третям, горизонтальный свайп с упругими краями, свайп вниз) — в JS страницы
   (pqGestures в pair-app.html); здесь только вид. Состав: __card > __grab, __bars, __close, __slide. ПК (≥769px): по центру снизу, max-width 520.
   Поля ввода внутри — 16px. Открытость: класс .on. */
.insta-sheet{position:fixed;left:0;right:0;top:0;bottom:calc(var(--cfbn-pad,0px) + env(safe-area-inset-bottom,0px));z-index:520;
  display:flex;align-items:flex-end;justify-content:center;background:rgba(0,0,0,.55);opacity:0;transition:opacity .2s;overscroll-behavior:contain}
.insta-sheet.on{opacity:1}
.insta-sheet__card{position:relative;box-sizing:border-box;width:100%;max-width:520px;flex:none;overflow:hidden;
  height:calc(var(--ui-sheet-h-vh) - var(--cfbn-pad,0px) - env(safe-area-inset-bottom,0px));
  height:calc(var(--ui-sheet-h) - var(--cfbn-pad,0px) - env(safe-area-inset-bottom,0px));max-height:100%;
  background:var(--ui-sheet-bg,#1c1c1e);border:1px solid var(--ui-card-border,#232323);border-bottom:0;
  border-radius:var(--ui-sheet-radius,22px) var(--ui-sheet-radius,22px) 0 0;
  box-shadow:0 -16px 40px -8px color-mix(in srgb,var(--ui-shadow-c,#000) 35%,transparent);
  touch-action:pan-y;-webkit-user-select:none;user-select:none;outline:0;transform:translateY(24px);transition:transform .24s cubic-bezier(.22,.8,.3,1)}
.insta-sheet.on .insta-sheet__card{transform:none}
.insta-sheet__grab{position:absolute;left:50%;top:8px;width:36px;height:4px;margin-left:-18px;border-radius:2px;background:var(--ui-grip,#4a4a4a);pointer-events:none}
.insta-sheet__bars{position:absolute;left:14px;right:52px;top:24px;display:flex;gap:4px;z-index:3;pointer-events:none}
.insta-sheet__bar{flex:1;height:3px;border-radius:2px;background:color-mix(in srgb,currentColor 25%,transparent);transition:background .2s}
.insta-sheet__bar.on{background:currentColor}
.insta-sheet__close{position:absolute;right:6px;top:12px;z-index:4}
.insta-sheet__slide{position:absolute;left:0;right:0;top:48px;bottom:0;overflow-y:auto;overflow-x:hidden;padding:12px 20px 16px;will-change:transform;scrollbar-width:none}
.insta-sheet__slide::-webkit-scrollbar{display:none}
.insta-sheet :is(input,textarea,select){font-size:16px}
@media (prefers-reduced-motion:reduce){.insta-sheet,.insta-sheet__card,.insta-sheet__bar{transition:none}}
/* Мелкие хелперы строк и таблиц (13.10.2026, /rs): вместо style="…" в JS-разметке. Отступы — токены. */
.ui-ml-auto{margin-left:auto !important}
.ui-nowrap{white-space:nowrap}
.ui-tac{text-align:center}
.ui-dim{opacity:.55}
.ui-w-min{width:1%}
.ui-mt{margin-top:var(--ui-tile-gap,8px)}
.ui-mb{margin-bottom:var(--ui-tile-gap,8px)}
.ui-empty{padding:var(--ui-card-pad,20px)}
.ui-empty.is-c{text-align:center}
/* Пустое состояние с иконкой (19.10.2026, /mail «Файлы»): <div class="ui-empty is-c"><svg class="ui-empty__ico">…</svg><b class="ui-empty__t">Заголовок</b><p class="ui-empty__s">Пояснение</p></div> */
.ui-empty__ico{display:block;width:32px;height:32px;margin:0 auto 10px;color:var(--ui-tx-3);fill:none;stroke:currentColor}
.ui-empty__t{display:block;font-size:14px;font-weight:600;color:var(--ui-tx)}
.ui-empty__s{margin:4px 0 0;font-size:12.5px;line-height:1.5;color:var(--ui-tx-2)}
/* Глобальный [hidden]: класс с display (.ui-hint и др.) не перебивает атрибут. Без !important (ui.md): специфичность 0,1,0, стоит последним в файле. */
[hidden]{display:none}

/* Общая таблица .ui-table (07.10.2026): <div class="ui-table-wrap"><table class="ui-table">. Только токены --ui-*.
   .is-num — число по правому краю; tr.is-bad — строка с ошибкой (цвет --ui-danger, как .ui-chip.is-danger);
   .ui-table__ico — ячейка-иконка (значок из /assets/icons.svg). На телефоне обёртка скроллится вбок. */
.ui-table-wrap{overflow-x:auto;max-width:100%;-webkit-overflow-scrolling:touch}
.ui-table{width:100%;border-collapse:collapse}
.ui-table th,.ui-table td{padding:10px 12px;text-align:left;font-size:13px;vertical-align:middle}
.ui-table th{color:var(--ui-muted);font-weight:400;white-space:nowrap}
.ui-table td{border-top:1px solid var(--ui-line-2,#1e1e1e);color:var(--ui-tx,#e8e8e8)}
.ui-table .is-num{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}
.ui-table tbody tr:hover td{background:var(--ui-row-hover)}
.ui-table tr.is-bad td{background:color-mix(in srgb,var(--ui-danger,#f87171) 7%,transparent)}
.ui-table tr.is-bad:hover td{background:color-mix(in srgb,var(--ui-danger,#f87171) 12%,transparent)}
.ui-table__ico{width:26px;padding-right:0}
.ui-table__ico>span{display:flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:7px;background:var(--ui-surface-2);border:1px solid var(--ui-card-border)}
.ui-table__ico svg{width:15px;height:15px;fill:none;stroke:var(--ui-ico);opacity:.55}
.ui-table tr.is-bad .ui-table__ico>span{border-color:color-mix(in srgb,var(--ui-danger,#f87171) 27%,transparent)}
.ui-table tr.is-bad .ui-table__ico svg{stroke:var(--ui-danger,#f87171);opacity:.85}
/* Список как в iOS Mail (19.10.2026, /mail этап 2A): .ui-table-wrap.is-grp — сгруппированный блок на --ui-surface с --ui-radius, строки разделены --ui-line (без рамок).
   .ui-table.is-rows — на ≤768 таблица становится списком строк: шапка скрыта, подписи берутся из data-l ячейки.
   tr.is-click — строка открывает карточку, tr.is-unread — жирная строка с точкой у первой ячейки. */
.ui-table-wrap.is-grp{background:var(--ui-surface,#141414);border-radius:var(--ui-radius,8px)}
.is-grp>.ui-table th{background:var(--ui-surface,#141414);color:var(--ui-tx-2,#8b8b8b);font-weight:500;border-bottom:1px solid var(--ui-line,#262626)}
.is-grp>.ui-table td{border-top:1px solid var(--ui-line,#262626);vertical-align:top}
.is-grp>.ui-table tbody tr:first-child td{border-top:0}
.ui-table tr.is-click{cursor:pointer}
.ui-table tr.is-unread td{font-weight:600}
.ui-table tr.is-unread td:first-child::after{content:"";display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--ui-brand,#00a0ff);margin-left:6px;vertical-align:middle}
@media(max-width:768px){
  .ui-table.is-rows thead{display:none}
  .ui-table.is-rows,.ui-table.is-rows tbody,.ui-table.is-rows tr,.ui-table.is-rows td{display:block}
  .ui-table.is-rows tr{padding:10px 12px;border-top:1px solid var(--ui-line,#262626)}
  .ui-table.is-rows tr:first-child{border-top:0}
  .ui-table.is-rows td{padding:3px 0;border:0;min-width:0;overflow-wrap:anywhere}
  .ui-table.is-rows td:empty{display:none}
  .ui-table.is-rows td[data-l]::before{content:attr(data-l);display:block;font-size:11px;line-height:1.3;color:var(--ui-tx-3,#6a6a6a)}
}

/* Тулбар списка «одна строка» .lt-one (07.10.2026; docs/rules/ui.md, эталон /access). Класс ставится на контейнер тулбара.
   Общее: высота --ui-ctl-h 36px (40px на телефоне), квадрат-фильтр .lt-flt (подпись .lt-l скрыта, бейдж .lt-n в углу),
   поиск .lt-find 300px (на телефоне ряд с фильтром, flex:1). order, margin-left:auto и действия — в страницах. */
.lt-one{--ui-ctl-h:36px}
@media(max-width:768px){ .lt-one{--ui-ctl-h:40px} }
.lt-one .lt-flt{flex:none;position:relative;width:var(--ui-ctl-h) !important;height:var(--ui-ctl-h) !important;min-width:var(--ui-ctl-h) !important;padding:0 !important;justify-content:center;gap:0;background:transparent !important;border:1px solid var(--ui-card-border,#2c2c2c) !important;border-radius:8px !important;color:var(--ui-tx-2,#aaa) !important;box-shadow:none !important}
.lt-one .lt-flt svg{width:18px !important;height:18px !important}
.lt-one .lt-flt .lt-l{display:none}
.lt-one .lt-flt .lt-n:not(:empty){position:absolute;top:-6px;right:-6px}
.lt-one .lt-flt .lt-n:empty{display:none}
.lt-one .lt-find{flex:0 0 300px;width:300px;max-width:100%;min-width:0}
@media(max-width:600px){ .lt-one .lt-find{flex:1 1 calc(100% - var(--ui-ctl-h) - 8px);width:auto} }

/* Единый шаблон строки тулбара [data-lt-tpl] (13.10.2026; порядок слотов — /list-toolbar.js ltBuild() + /toolbar-template.json).
   Слоты — прямые дети .lt-one с data-lt-slot: filter, search, project, tabs, spacer, export, import, add. Без .lt-row.
   ПК: ОДНА строка в порядке шаблона; на узком окне переносится, но высота строки от вкладок не зависит.
   Телефон (<=768): вкладки на всю ширину; ряд 1 — фильтр · поиск (flex) · выгрузка · загрузка · добавить; ряд 2 — проект на всю ширину.
   Скрытый слот: .lt-ghost (ПК без вкладок — visibility; в ряду с вкладками и на телефоне — display:none, поиск на ПК шире на 208px). */
.lt-one[data-lt-tpl]{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-height:var(--ui-ctl-h);min-width:0}
.lt-one[data-lt-tpl] [data-lt-slot][hidden]{display:none !important}
.lt-one[data-lt-tpl]>[data-lt-slot]{min-width:0}
.lt-one[data-lt-tpl]>.lt-sp{flex:1 1 0}
.lt-one[data-lt-tpl]>.lt-find{flex:1 1 160px;width:auto;max-width:300px}
.lt-one[data-lt-tpl]>.lt-pick{flex:1 1 140px;max-width:200px}
.lt-one[data-lt-tpl]>.lt-tabs{flex:none;display:flex;flex-wrap:nowrap;align-items:center;gap:4px}
.lt-one[data-lt-tpl]>.lt-tabs>button{height:var(--ui-ctl-h) !important;min-height:var(--ui-ctl-h) !important;padding:0 12px !important;min-width:0}
.lt-one[data-lt-tpl]>.lt-tabs>button>.lt-l{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lt-one[data-lt-tpl]>.ibtn{flex:none;position:relative;box-sizing:border-box;padding:0 !important;display:inline-flex;align-items:center;justify-content:center;width:var(--ui-ctl-h) !important;height:var(--ui-ctl-h) !important;min-width:var(--ui-ctl-h) !important;min-height:var(--ui-ctl-h) !important;background:transparent !important;border:1px solid var(--ui-card-border,#2c2c2c) !important;border-radius:8px !important;color:var(--ui-tx-2,#aaa) !important;box-shadow:none !important}
.lt-one[data-lt-tpl]>.ibtn svg{width:18px !important;height:18px !important;fill:none;stroke:currentColor}
.lt-one[data-lt-tpl]>.lt-add{flex:none;height:var(--ui-ctl-h);min-height:var(--ui-ctl-h);justify-content:center}
.lt-one[data-lt-tpl]>.lt-ghost{visibility:hidden;pointer-events:none}
@media(min-width:769px){
  .lt-one[data-lt-tpl]>.lt-add{width:auto !important;min-width:0 !important;padding:0 14px !important}
  .lt-one[data-lt-tpl]>.lt-add>.lt-l{display:inline}
  /* ряд с вкладками (/access): фиксированные ширины поиска/проекта; когда проект скрыт (.lt-ghost) — он не занимает место,
     а поиск шире на его ширину (200+8), поэтому вкладки и правые кнопки стоят на одном месте на всех вкладках */
  .lt-one[data-lt-tpl]:has(>.lt-tabs)>.lt-find{flex:0 1 300px;max-width:300px}
  .lt-one[data-lt-tpl]:has(>.lt-tabs)>.lt-pick{flex:0 1 200px;max-width:200px}
  .lt-one[data-lt-tpl]:has(>.lt-tabs)>.lt-ghost{display:none}
  .lt-one[data-lt-tpl]:has(>.lt-tabs):has(>.lt-ghost)>.lt-find{flex:0 1 508px;max-width:508px}
}
@media(max-width:768px){
  /* ряды: 0 вкладки · 1 фильтр · поиск (растягивается) · [выгрузка · загрузка] · «+» · 2 проект на всю ширину · потом .lt-xtra */
  .lt-one[data-lt-tpl]{row-gap:8px}
  /* перенос между рядом 1 и 2: пустой элемент на всю ширину; -8px съедает двойной row-gap */
  .lt-one[data-lt-tpl]::after{content:"";order:6;flex:0 0 100%;height:0;margin-top:-8px}
  .lt-one[data-lt-tpl]>.lt-tabs{order:0;flex:1 1 100%;display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:6px}
  .lt-one[data-lt-tpl]>.lt-tabs>button{padding:0 8px !important}
  .lt-one[data-lt-tpl]>.lt-flt{order:1}
  .lt-one[data-lt-tpl]>.lt-find{order:2;flex:1 1 0;max-width:none;width:auto}
  .lt-one[data-lt-tpl]>.lt-sp{display:none}
  .lt-one[data-lt-tpl]>.ibtn[data-lt-slot=export]{order:3}
  .lt-one[data-lt-tpl]>.ibtn[data-lt-slot=import]{order:4}
  .lt-one[data-lt-tpl]>.lt-add{order:5;width:var(--ui-ctl-h);min-width:var(--ui-ctl-h) !important;padding:0 !important}
  .lt-one[data-lt-tpl]>.lt-add>.lt-l{display:none}
  .lt-one[data-lt-tpl]>.lt-pick{order:7;flex:1 1 100%;max-width:none}
  /* нет видимого проекта: ряда 2 нет, разрыв не нужен */
  .lt-one[data-lt-tpl]:not(:has(>.lt-pick:not(.lt-ghost):not([hidden])))::after{display:none}
  .lt-one[data-lt-tpl]>.lt-ghost{display:none}
  .lt-one[data-lt-tpl]>.lt-xtra{order:9;flex:1 1 100%}
}
/* .lt-xtra — слот-обёртка для доп. кнопок/подписей страницы, которым нет места в шаблоне (/tasks спринты, /trip) */
.lt-one[data-lt-tpl]>.lt-xtra{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
@media(min-width:769px){ .lt-one[data-lt-tpl]>.lt-xtra{flex:none} }
/* Слот extra (13.10.2026) — одиночный нестандартный элемент страницы (счётчик, «Очистить корзину», второй выбор), на ПК в конце строки;
   на телефоне остаётся в ряду 1, а не прыгает перед фильтром. .lt-pick/.lt-find со своими order (7/8) не затрагиваются. */
@media(max-width:768px){
  .lt-one[data-lt-tpl]>[data-lt-slot=extra]:not(.lt-pick):not(.lt-find){order:5}
}
/* Вкладки-иконки .lt-tabs-ico (13.10.2026, /crm/leads): квадраты --ui-ctl-h; на телефоне стоят в ряду проекта (ряд 2), проект растягивается */
.lt-one[data-lt-tpl]>.lt-tabs-ico>button{width:var(--ui-ctl-h);min-width:var(--ui-ctl-h) !important;padding:0 !important;display:inline-flex;align-items:center;justify-content:center}
.lt-one[data-lt-tpl]>.lt-tabs-ico>button svg{width:18px;height:18px}
@media(max-width:768px){
  .lt-one[data-lt-tpl]>.lt-tabs.lt-tabs-ico{order:8;flex:none;display:flex;gap:8px}
  .lt-one[data-lt-tpl]:has(>.lt-tabs-ico)>.lt-pick{flex:1 1 0}
}

/* Шторка фильтра .accd (/access, /integrations): на ПК боковая .lt-drawer, на телефоне шторка снизу от 64px.
   Квадраты .accd-sq: 40x40, рамка 1px, без заливки (перенесено из access.html, 07.10.2026). */
.lt-drawer.accd{padding:0 !important;gap:0 !important}
.accd-handle{display:none}
.accd-head{display:flex;align-items:center;gap:10px;padding:16px 16px 12px;border-bottom:1px solid var(--ui-line,#262626)}
.accd-ttl{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px}
.accd-ttl b{font-size:18px;font-weight:600;color:var(--ui-tx,#e8e8e8);line-height:1.2}
.accd-ttl span{font-size:12px;color:var(--ui-tx-2,#8b8b8b)}
.accd-sq{width:40px !important;height:40px !important;min-width:40px !important;min-height:40px !important;padding:0 !important;flex:none;box-sizing:border-box;display:inline-flex !important;align-items:center;justify-content:center;background:transparent !important;border:1px solid var(--ui-card-border,#2c2c2c) !important;border-radius:8px !important;color:var(--ui-tx-2,#aaa) !important}
.accd-sq svg{width:18px !important;height:18px !important}
.accd-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:0 16px 16px}
.accd-cap{font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--ui-tx-3,#6a6a6a);margin:18px 0 10px}
.accd-chips{display:flex;flex-wrap:wrap;gap:8px}
.accd-chip{display:inline-flex;align-items:center;gap:8px;height:40px;padding:0 14px;box-sizing:border-box;border-radius:20px;border:1px solid var(--ui-card-border,#2c2c2c);background:transparent;color:var(--ui-tx,#ccc);font:inherit;font-size:14px;cursor:pointer;white-space:nowrap}
.accd-chip .d{width:8px;height:8px;border-radius:50%;flex:none}
.accd-chip .n{font-size:12px;color:var(--ui-tx-3,#6a6a6a);font-variant-numeric:tabular-nums}
.accd-chip.on{border-color:var(--ui-brand,#00a0ff);background:rgba(0,160,255,.1);color:var(--ui-tx,#fff)}
.accd-chip.on .n{color:var(--ui-brand,#00a0ff)}
.accd-sel{position:relative;display:flex;align-items:center}
.accd-sel svg{position:absolute;left:12px;width:18px;height:18px;color:var(--ui-tx-2,#aaa);pointer-events:none}
.accd-sel select{width:100%;height:44px;box-sizing:border-box;padding:0 12px 0 40px !important;border:1px solid var(--ui-card-border,#2c2c2c);border-radius:8px;background:transparent;color:var(--ui-tx,#ccc);font-size:14px}
.accd-foot{display:flex;gap:8px;padding:12px 16px 16px;border-top:1px solid var(--ui-line,#262626)}
.accd-foot .btn{flex:4 1 0;min-height:48px;font-size:16px;justify-content:center}
.accd-foot .accd-sq{flex:1 1 0;width:auto !important;height:48px !important}
@media(max-width:768px){
  .lt-drawer.accd{top:64px;left:0;right:0;bottom:0;width:auto !important;border-right:0;border-top:1px solid var(--ui-line,#262626);border-radius:16px 16px 0 0;transform:translateY(105%);background:var(--ui-surface,#141414)}
  body.lt-open .lt-drawer.accd{transform:none}
  .accd-handle{display:block;width:36px;height:4px;border-radius:2px;background:var(--ui-grip,#4a4a4a);margin:8px auto 0;flex:none}
  .accd-head{padding-top:10px}
  .accd-sel select{font-size:16px}
  .accd-foot{padding-bottom:calc(16px + env(safe-area-inset-bottom))}
}

/* layout utilities (#217) — раскладка классами вместо inline style="display:flex;…".
   Имена .row/.col заняты страничными стилями, .split — в doclog.html (там grid), поэтому
   «растяжка» названа .spread. Гэп по умолчанию — --ui-gap; .gap-* — мелкие шаги (литералы,
   токенов малого гэпа в теме нет). Модификаторы .reverse / .gap-* вешаются рядом с классом. */
.stack   { display: flex; flex-direction: column; gap: var(--ui-gap, 22px); }
.cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ui-gap, 22px); }
.spread  { display: flex; align-items: center; justify-content: space-between; gap: var(--ui-gap, 22px); }
.grid-auto { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--grid-min, 220px), 1fr)); gap: var(--ui-gap, 22px); }
.stack.reverse { flex-direction: column-reverse; }
.cluster.reverse, .spread.reverse { flex-direction: row-reverse; }
.stack.gap-0, .cluster.gap-0, .spread.gap-0, .grid-auto.gap-0 { gap: 0; }
.stack.gap-s, .cluster.gap-s, .spread.gap-s, .grid-auto.gap-s { gap: 8px; }
.stack.gap-m, .cluster.gap-m, .spread.gap-m, .grid-auto.gap-m { gap: 10px; }
.stack.gap-l, .cluster.gap-l, .spread.gap-l, .grid-auto.gap-l { gap: 12px; }

/* ===== АВТО-ФОРМАТ: резиновые сетки без inline и !important (14.10.2026, ADR «авто-формат») =====
   Только ДОБАВЛЕНО: старые .ui-grid.auto, .grid-auto, .ui-tiles, .ui-kpi, .kt-tiles работают как раньше, страницы
   переводим по одной на новые имена (переход), потом старые становятся алиасами и удаляются. Своих grid-template-columns
   на странице больше не писать: выбрать класс, при нужде задать --min / --gap (в style допустимы ТОЛЬКО переменные).
   1) .ui-auto — однородные карточки и списки; колонок ровно столько, сколько влезает, min(…,100%) не даёт колонке
      вылезти за узкий контейнер. --min: .is-s 160 / по умолчанию 260 / .is-m 300 / .is-l 340.
   2) .ui-tiles.is-auto — плитки с числом по ширине (по умолчанию от 140px); .ui-tiles.is-steps — ступени 2 → 3 → 6
      по ширине ВИДЖЕТА (@container), как KPI-ряд в макете; ступени и колонки — --c1/--c2/--c3.
   3) .ui-cq — контейнер для @container там, где предка-виджета нет. Только на карточку/блок, не на body, .ui-page и
      обёртку попапа: container-type делает потомка с position:fixed привязанным к блоку — попапы рендерить в body.
   Выбор: карточки → .ui-auto; плитки → .ui-tiles.is-steps (число плиток известно) или .is-auto (число любое);
   двигаемые пользователем виджеты → .ui-glayout; лендинг → .cf-grid. Две колонки по дизайну — .ui-tiles.is-2.
   Расчёт: двум колонкам нужно 2×min + gap; на карточке 305px при --min:150 и gap 22 будет ОДНА колонка.
   @container здесь без обёртки @media(min-width:769px): правило проекта относилось к уже существующим виджетам, которым
   мобильные [style*=] перебивают контейнерные; у новых классов таких перебивок нет. */
.ui-auto { display: grid; gap: var(--gap, var(--ui-gap, 22px));
  grid-template-columns: repeat(auto-fit, minmax(min(var(--min, 260px), 100%), 1fr)); }
.ui-auto > * { min-width: 0; }
.ui-auto.is-s { --min: 160px; }
.ui-auto.is-m { --min: 300px; }
.ui-auto.is-l { --min: 340px; }
.ui-auto.is-top { align-items: start; }
.ui-auto.gap-0, .ui-tiles.is-auto.gap-0, .ui-tiles.is-steps.gap-0 { --gap: 0px; }
.ui-auto.gap-s, .ui-tiles.is-auto.gap-s, .ui-tiles.is-steps.gap-s { --gap: 8px; }
.ui-auto.gap-m, .ui-tiles.is-auto.gap-m, .ui-tiles.is-steps.gap-m { --gap: 10px; }
.ui-auto.gap-l, .ui-tiles.is-auto.gap-l, .ui-tiles.is-steps.gap-l { --gap: 12px; }
.ui-tiles.is-auto { gap: var(--gap, var(--ui-tile-gap, 8px));
  grid-template-columns: repeat(auto-fit, minmax(min(var(--min, 140px), 100%), 1fr)); }
.ui-tiles.is-steps { gap: var(--gap, var(--ui-tile-gap, 8px)); --ui-tile-cols: var(--c1, 2); }
.ui-cq { container-type: inline-size; }
@container (min-width: 480px) { .ui-tiles.is-steps { --ui-tile-cols: var(--c2, 3); } }
@container (min-width: 720px) { .ui-tiles.is-steps { --ui-tile-cols: var(--c3, 6); } }

/* Раскладка виджетов без inline (15.10.2026, #170): модуль /ui-grid-layout.js (v6+) пишет не style.gridColumn/order,
   а атрибут data-span="1…12" и переменную --gl-order. Плейсхолдер перетаскивания .ui-gl-ph получает то же.
   Страницы на модуле: /app и медкарта — им подняты ui.css?v и ui-grid-layout.js?v одновременно, иначе виджеты
   встанут на все 12 колонок. На телефоне — одна колонка (последнее правило). */
.ui-glayout [data-widget-key], .ui-glayout .ui-gl-ph { order: var(--gl-order, 0); }
.ui-glayout [data-span="1"]  { grid-column: span 1; }
.ui-glayout [data-span="2"]  { grid-column: span 2; }
.ui-glayout [data-span="3"]  { grid-column: span 3; }
.ui-glayout [data-span="4"]  { grid-column: span 4; }
.ui-glayout [data-span="5"]  { grid-column: span 5; }
.ui-glayout [data-span="6"]  { grid-column: span 6; }
.ui-glayout [data-span="7"]  { grid-column: span 7; }
.ui-glayout [data-span="8"]  { grid-column: span 8; }
.ui-glayout [data-span="9"]  { grid-column: span 9; }
.ui-glayout [data-span="10"] { grid-column: span 10; }
.ui-glayout [data-span="11"] { grid-column: span 11; }
.ui-glayout [data-span="12"] { grid-column: span 12; }
@media (max-width: 768px) {
  .ui-glayout [data-span] { grid-column: 1 / -1; }
}

/* ===== Уровни и индикаторы без inline (15.10.2026, авто-формат) =====
   data-lvl="ok|warn|bad" на любом элементе задаёт --lvl (цвет уровня); .is-lvl красит текст этим цветом, заливка полосы
   .ui-bar > i берёт --c, иначе --lvl, иначе бренд. Ширина полосы — переменная --w С процентами (style="--w:42%"):
   в style допустимы только переменные, свойств нет. */
[data-lvl="ok"]   { --lvl: var(--ui-ok, #34d399); }
[data-lvl="warn"] { --lvl: var(--ui-warn, #fbbf24); }
[data-lvl="bad"]  { --lvl: var(--ui-danger, #f87171); }
.is-lvl { color: var(--lvl); }
.ui-bar { height: 6px; border-radius: 6px; overflow: hidden; background: var(--ui-bar-bg, rgba(255, 255, 255, .07)); }
.ui-bar > i { display: block; height: 100%; border-radius: inherit; width: var(--w, 0%); background: var(--c, var(--lvl, var(--ui-brand, #00a0ff))); }

/* ===== iOS-стиль (inset grouped): секции, строки, капсулы (19.10.2026, /set → «Паттерны (iOS-стиль)») =====
   Только ДОБАВЛЕНО, существующие классы не менялись. Цвета — только токены темы (--ui-card-bg, --ui-card-border, --ui-tx,
   --ui-tx-2, --ui-brand, --ui-shadow-md): обе темы работают сами. Радиус карточки — токен --ui-radius-lg (24px, объявлен в :root выше).
   Разметка секции:
     <div class="ui-ios-sec"><div class="ui-ios-cap">Сведения</div>
       <div class="ui-ios-card">
         <div class="ui-ios-row"><svg class="ui-ios-ico">…</svg><span class="ui-ios-ttl">Название</span><span class="ui-ios-val">Значение</span></div>
         <a class="ui-ios-row" href="#"><svg class="ui-ios-ico">…</svg><span class="ui-ios-txt"><span class="ui-ios-ttl">Название</span><span class="ui-ios-sub">Подпись</span></span><svg class="ui-ios-chev">…</svg></a>
         <label class="ui-ios-row ui-ios-sw"><svg class="ui-ios-ico">…</svg><span class="ui-ios-ttl">Активно</span><input type="checkbox" class="ui-switch no-ui-check"></label>
       </div><div class="ui-ios-note">Пояснение серым</div></div>
   Строка — div, a, button или label. Без иконки: класс .is-noico (разделитель начинается от края отступа).
   .ui-ios-capsule — плавающая капсула. В демо position:relative. В реальном экране: position:sticky (top) или position:fixed
   (top/bottom + safe-area), z-index не выше 500 (меню 500, .mdl-back 600 выше). .ui-ios-pill — главная кнопка-пилюля: фон --ui-tx,
   текст --ui-card-bg (в тёмной теме светлая пилюля с тёмным текстом, в светлой наоборот); внизу экрана — над доком (.ui-dock-pad). */
.ui-ios-sec { margin: 0 0 24px; }
.ui-ios-cap { padding: 0 16px 8px; font-size: 13px; line-height: 1.3; color: var(--ui-tx-2, #8b8b8b); }
.ui-ios-card { overflow: hidden; padding: 0; background: var(--ui-card-bg, #141414); border: 1px solid var(--ui-card-border, #262626); border-radius: var(--ui-radius-lg, 24px); }
.ui-ios-note { padding: 8px 16px 0; font-size: 13px; line-height: 1.4; color: var(--ui-tx-2, #8b8b8b); }
.ui-ios-row { --ios-pad: 16px; --ios-gap: 14px; --ios-div-l: calc(var(--ios-pad) + 24px + var(--ios-gap));
  position: relative; box-sizing: border-box; display: flex; align-items: center; gap: var(--ios-gap); width: 100%; min-height: 56px;
  margin: 0; padding: 8px var(--ios-pad); border: 0; background: transparent; color: var(--ui-tx, #e8e8e8);
  font: inherit; font-size: 16px; text-align: left; text-decoration: none; cursor: default; -webkit-tap-highlight-color: transparent; }
.ui-ios-row.is-noico { --ios-div-l: var(--ios-pad); }
.ui-ios-row::after { content: ""; position: absolute; left: var(--ios-div-l); right: 0; bottom: 0; height: 1px; background: var(--ui-card-border, #262626); }
.ui-ios-row:last-child::after { display: none; }
a.ui-ios-row, button.ui-ios-row, label.ui-ios-sw, .ui-ios-row.is-tap { cursor: pointer; }
a.ui-ios-row:active, button.ui-ios-row:active, label.ui-ios-sw:active, .ui-ios-row.is-tap:active { background: color-mix(in srgb, var(--ui-tx, #e8e8e8) 8%, transparent); }
.ui-ios-ico { flex: none; width: 24px; height: 24px; color: var(--ui-tx-2, #8b8b8b); fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.ui-ios-ttl { flex: 1 1 auto; min-width: 0; font-size: 16px; line-height: 1.3; color: var(--ui-tx, #e8e8e8); }
.ui-ios-txt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ui-ios-sub { font-size: 13px; line-height: 1.3; color: var(--ui-tx-2, #8b8b8b); }
.ui-ios-val { flex: none; max-width: 55%; font-size: 16px; color: var(--ui-tx-2, #8b8b8b); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-ios-chev { flex: none; width: 18px; height: 18px; margin-left: -6px; color: var(--ui-tx-2, #8b8b8b); opacity: .7; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ui-ios-sw > input.ui-switch { margin-left: auto; }
.ui-ios-capsule { position: relative; box-sizing: border-box; display: inline-flex; align-items: center; gap: 8px; max-width: 100%; min-width: 0; height: 44px; padding: 0 16px;
  border: 1px solid var(--ui-card-border, #262626); border-radius: 999px; background: var(--ui-card-bg, #141414); color: var(--ui-tx, #e8e8e8);
  box-shadow: var(--ui-shadow-md, 0 6px 18px -2px rgba(0,0,0,.30)); font: inherit; font-size: 15px; text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.ui-ios-capsule > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-ios-capsule > svg { flex: none; width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ui-ios-capsule.is-round { width: 44px; padding: 0; justify-content: center; }
.ui-ios-capsule:active { filter: brightness(.9); }
.ui-ios-pill { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; gap: 10px; height: 52px; padding: 0 26px; border: 0; border-radius: 999px;
  background: var(--ui-tx, #e8e8e8); color: var(--ui-card-bg, #141414); box-shadow: var(--ui-shadow-md, 0 6px 18px -2px rgba(0,0,0,.30));
  font: inherit; font-size: 16px; font-weight: 600; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.ui-ios-pill > svg { flex: none; width: 20px; height: 20px; fill: currentColor; stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; }
.ui-ios-pill:active { filter: brightness(.88); }

/* ===== M-78..M-80 (23.10.2026, ADR-295): карточка-заявка, панель выбора, подпись KPI =====
   .ui-req — карточка списка на ≤768 (таблица → карточки, ADR-138). Строки «ключ слева, значение справа» — .ui-req .ui-pair
   (общий .ui-pair выше — сетка с разделителем, не трогаем). Кнопки .ui-req__acts — 50/50, высота --ui-tap.
   .ui-selbar — нижняя панель массовых действий; видна только с .is-on (0 выбранных → скрыта). Список под ней
   добирает отступ классом .ui-dock-pad или padding-bottom. .ui-kpi__sub — суффикс в строке значения. */
.ui-id { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; color: var(--ui-id, #fbbf24); }
.ui-req { position: relative; box-sizing: border-box; min-width: 0; padding: 16px; margin-bottom: 12px;
  background: var(--ui-card-bg, #141414); border: 1px solid var(--ui-card-border, #262626); border-radius: var(--ui-card-radius, 12px); color: var(--ui-tx, #e8e8e8); }
.ui-req.is-sel { border-color: var(--ui-brand, #00a0ff); box-shadow: 0 0 0 1px var(--ui-brand, #00a0ff); }
.ui-req__top { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.ui-req.has-check .ui-req__top { padding-right: 36px; }
.ui-req > h3 { margin: 10px 0 8px; font-size: 16px; font-weight: 600; line-height: 1.3; }
.ui-req .ui-pair { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; padding: 5px 0; font-size: 14px;
  border-top: 1px solid var(--ui-line, #262626); }
.ui-req .ui-pair > :first-child { color: var(--ui-tx-2, #8b8b8b); }
.ui-req__acts { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 12px; }
.ui-req__acts > * { min-height: var(--ui-tap, 44px); height: var(--ui-tap, 44px); box-sizing: border-box; }
/* 23.10.2026: общее правило чекбоксов (~1402, специфичность 0,5,1) ставит position:relative и перебивало absolute — чекбокс вставал в поток слева и налезал на ID.
   Селектор тут нарочно той же силы (+ класс карточки), правее по каскаду. */
.ui-req > input.ui-req__chk[type="checkbox"]:not(.ui-switch):not(.no-ui-check):not([data-native]):not(.ci-nb) { position: absolute; top: 14px; right: 14px; margin: 0; z-index: 1; }
.ui-selbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 480; box-sizing: border-box; display: none;
  justify-content: space-between; align-items: center; gap: 12px; padding: 12px 14px calc(12px + env(safe-area-inset-bottom, 0px));
  background: var(--ui-card-bg, #141414); border-top: 1px solid var(--ui-card-border, #262626); color: var(--ui-tx, #e8e8e8); }
.ui-selbar.is-on { display: flex; }
.ui-selbar b { font-size: 15px; }
.ui-kpi__sub { font-size: 12px; font-weight: 400; color: var(--ui-tx-2, #8b8b8b); margin-left: 4px; letter-spacing: 0; white-space: normal; }

/* ===== Карточка уведомления (ui-notif.js). Только токены --ui-*, без hex, без теней ===== */
.ui-notif-list { display: flex; flex-direction: column; gap: 16px; }
.ui-notif {
  box-sizing: border-box; display: flex; flex-direction: column; gap: 8px;
  padding: 12px;
  background: var(--ui-card-bg); border: 1px solid var(--ui-card-border);
  border-radius: var(--ui-radius-lg); color: var(--ui-tx);
}
.ui-notif-head { display: flex; align-items: center; gap: 12px; }
.ui-notif-ico { width: 24px; height: 24px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; color: var(--ui-tx-2); }
.ui-notif-meta { flex: 1; min-width: 0; font-size: 13px; line-height: 1.3; color: var(--ui-tx-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ui-notif-close {
  box-sizing: border-box; flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: var(--ui-sheet-btn, 44px); height: var(--ui-sheet-btn, 44px); min-width: 44px; min-height: 44px; padding: 0; margin: -4px -2px -4px 0;
  border: var(--ui-sheet-btn-bw, 1px) solid var(--ui-sheet-btn-bc, var(--ui-card-border));
  border-radius: var(--ui-btni-radius, 8px);
  background: var(--ui-sheet-btn-bg, transparent); color: var(--ui-btni-text, var(--ui-tx-2));
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.ui-notif-close svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ui-notif-close:active { filter: brightness(.9); }
.ui-notif-close:disabled { opacity: .5; cursor: default; }
.ui-notif-close:focus-visible, .ui-notif-btn:focus-visible, .ui-notif-btn2:focus-visible, .ui-notif-shot:focus-visible { outline: 2px solid var(--ui-inp-focus, var(--ui-brand)); outline-offset: 2px; }
.ui-notif-body { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.ui-notif-tag {
  align-self: flex-start; font-size: 12px; line-height: 1; padding: 6px 10px; border-radius: var(--ui-radius);
  background: var(--ui-danger-soft); border: 1px solid var(--ui-danger-soft-line); color: var(--ui-danger);
}
.ui-notif-tag.is-brand { background: var(--ui-brand-soft); border-color: var(--ui-brand-soft-line); color: var(--ui-brand); }
.ui-notif-ttl { margin: 0; font-size: 16px; font-weight: 600; line-height: 1.25; color: var(--ui-tx); overflow-wrap: anywhere; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
.ui-notif-txt { margin: 0; font-size: 14px; line-height: 1.3; color: var(--ui-tx-2); overflow-wrap: anywhere; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
.ui-notif-shots { display: grid; gap: 8px; grid-template-columns: repeat(3, 1fr); }
.ui-notif-shots.is-1 { grid-template-columns: 1fr; }
.ui-notif-shots.is-2 { grid-template-columns: repeat(2, 1fr); }
.ui-notif-shot {
  box-sizing: border-box; position: relative; display: flex; align-items: center; justify-content: center; overflow: hidden;
  height: 92px; background: var(--ui-surface-2); border: 1px solid var(--ui-card-border); border-radius: var(--ui-radius);
  color: var(--ui-tx-2); text-decoration: none;
}
.ui-notif-shots.is-1 .ui-notif-shot { height: 148px; }
.ui-notif-shot img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ui-notif-more { background: var(--ui-brand-soft); border-color: var(--ui-brand-soft-line); color: var(--ui-brand); font-size: 16px; font-weight: 600; }
.ui-notif-acts { display: flex; gap: 10px; margin-top: 4px; }
.ui-notif-btn, .ui-notif-btn2 {
  box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: var(--ui-ctl-h, 44px); padding: 0 20px; border-radius: var(--ui-radius, 8px);
  font-size: 16px; font-weight: 600; text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.ui-notif-btn {
  flex: 1; background: var(--ui-btn1-bg, var(--ui-brand)); color: var(--ui-btn1-text);
  border: 1px solid var(--ui-btn1-border, var(--ui-btn1-bg, var(--ui-brand)));
}
.ui-notif-btn2 { background: var(--ui-btn-bg, transparent); color: var(--ui-btn-text, var(--ui-tx)); border: 1px solid var(--ui-card-border); }
.ui-notif-btn:active, .ui-notif-btn2:active { filter: brightness(.9); }
/* Инфографика: цифра + «Предыдущие» + дельта слева, столбики справа. Высота столбиков — токен --ui-ctl-h */
.ui-notif-stat { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--ui-gap, 16px); min-width: 0; }
.ui-notif-stat-l { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.ui-notif-stat-v { font-size: 28px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; color: var(--ui-tx); overflow-wrap: anywhere; }
.ui-notif-stat-p { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 13px; line-height: 1.3; color: var(--ui-tx-2); }
.ui-notif-delta { font-weight: 600; }
.ui-notif-delta.is-up { color: var(--ui-ok); }
.ui-notif-delta.is-down { color: var(--ui-danger); }
.ui-notif-bars { flex: 0 1 auto; display: flex; align-items: flex-end; gap: var(--ui-tile-gap, 8px); width: calc(var(--ui-ctl-h, 44px) * 2); height: var(--ui-ctl-h, 44px); }
.ui-notif-bar { flex: 1 1 0; min-width: 0; background: var(--ui-surface-2); border-radius: var(--ui-radius); }
.ui-notif-bar.is-on { background: var(--ui-brand); }
.ui-notif-lnk-ico { width: 18px; height: 18px; flex: none; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ui-notif-acts { flex-wrap: wrap; align-items: center; }
.ui-notif-empty { margin-top: 80px; text-align: center; font-size: 16px; color: var(--ui-tx-2); }
/* ПК (21.10.2026): карточки колонками по 360–420px, одной высоты; главная кнопка по ширине текста. Телефон — как выше. */
@media (min-width: 769px) {
  .ui-notif-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: stretch; gap: 16px; }
  .ui-notif-acts { margin-top: auto; padding-top: 4px; }
  .ui-notif-btn { flex: 0 1 auto; }
}

