/* Manrope, SIL Open Font License 1.1 — self-hosted on purpose. Loading it from
   fonts.googleapis.com meant CSS waiting on CSS waiting on the font before the
   first paint, and every metric in the cabinet shifted whenever Google Fonts
   was slow or unreachable. */
@font-face {
    font-family: "Manrope";
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url("/static/fonts/manrope-cyrillic.woff2") format("woff2");
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-family: "Manrope";
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url("/static/fonts/manrope-cyrillic-ext.woff2") format("woff2");
    unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
    font-family: "Manrope";
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url("/static/fonts/manrope-latin.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Manrope";
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url("/static/fonts/manrope-latin-ext.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------------------------------------------------------------------------
   Контрольные точки кабинета.

   Было двадцать три значения: 420, 430, 520, 560, 600, 620, 640, 680, 700,
   720, 760, 800, 820, 880, 881, 900, 950, 980, 1080, 1100, 1180, 1280, 1399.
   Часть из них отличалась на десять-двадцать пикселей, то есть выбиралась
   наугад под конкретный экран, а не по правилу.

   Осталось тринадцать:

     420   очень узкий телефон
     560   телефон
     640   крупный телефон
     700   телефон в альбомной / узкий планшет
     760   планшет
     820   планшет в альбомной
     900   граница «сайдбар против бургера» (парная к min-width: 901px)
     980   узкий ноутбук
    1100   ноутбук
    1180   широкий ноутбук
    1280   десктоп
    1399   широкий десктоп

   Слияние делалось только вверх: max-width, сдвинутый вверх, начинает
   действовать на чуть более широком экране, то есть блок схлопывается раньше
   и переполниться не может. Вниз не сдвигалось ничего, кроме 430 -> 420.

   Дальнейшее сокращение до пяти точек упирается в глаза: свести 980 к 900
   значит оставить широкую раскладку на экранах 900-980, а это уже проверяется
   только в браузере. Новую точку не заводить — брать существующую.
   --------------------------------------------------------------------------- */
:root {
    /* ------------------------------------------------------------------
       Роли, а не краски.

       Раньше один --green нёс четыре разных смысла сразу: главное действие,
       «вы здесь», ховер и «сделано». Развести их переназначением было
       нельзя — подложки подбирались руками, а .tag.ok красился по зелёной
       рампе напрямую, минуя --ok. Теперь смысл объявлен здесь, и смена тона
       акцента — это одно значение --brand, а не обход файла.

       Зелёный знака #2d7d61 остался в --logo, favicon.svg и pwa-icon.svg;
       цвет строки браузера задаёт _theme_color.html по контурам.
       ------------------------------------------------------------------ */

    /* Действие: первичная кнопка, кольцо фокуса, акцентная граница.

       Графит, а не зелёный. Зелёный в кабинете означал одновременно «главное
       действие» и «сделано»; на строке, где «Сохранить» стоит рядом с
       «Оплачено», цвет не помогал различить их. Теперь зелёный остался ровно
       значением (--ok), а действие ушло в ахромат: на экране администратора
       хроматическими остаются только осмысленные краски — статус, сигнал и
       направление занятия.

       Знак студии этим не задет: в studio-logo.png он почти чёрный с лаймовыми
       точками (133°), и нефрит 167° никогда не был цветом бренда. */
    --brand: #3f5d7d;
    /* Тот же тон под текстом: 13,0:1 на карточке. */
    --brand-ink: #345271;
    /* Заливка под курсором. Отдельно от --brand-ink, потому что это разные
       роли: текстовый акцент обязан быть темнее фона, а ховер — всего лишь
       отличим от покоя. У зелёного они совпадали, и токен был один; у тёмного
       акцента совпасть не могут — почти чёрное, ставшее ещё чернее, не читается
       как отклик, и кнопка выглядит мёртвой. */
    --brand-hover: #244160;
    --on-brand: #ffffff;

    /* Подложки выводятся из действия, а не подбираются. Из-за ручного
       подбора смена тона кнопки оставляла под ней мятную заливку, мятную
       границу и мятный ховер. */
    --brand-tint: color-mix(in oklab, var(--brand) 10%, var(--card));
    --brand-strong: color-mix(in oklab, var(--brand) 18%, var(--card));
    --brand-border: color-mix(in oklab, var(--brand) 34%, var(--card));
    --brand-border-strong: color-mix(in oklab, var(--brand) 52%, var(--card));

    /* Состояния — нейтральные ступени, а не бренд. Ховер, нажатие и «вы
       здесь» были одной мятной заливкой в 1,18:1 к карточке: ни одно из
       трёх не читалось, и ховер кнопки выглядел выбранным пунктом. */
    --hover: #f1f5f9;        /* 1,09:1 к карточке */
    --selected: #e0ebf7;     /* 1,20:1 к карточке */

    /* Ориентир: «вы здесь» в пространстве и «сегодня» во времени.

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

       Поэтому ориентир говорит формой. --selected заливает выбранное тихо,
       --marker заливает сегодняшнее плотно и выворачивает текст. Это две
       ступени одного ахроматического канала, и они складываются: день может
       быть одновременно сегодняшним и выбранным, и обе метки видны.

       Отдельный токен, а не var(--brand): действие и ориентир совпали по тону
       случайно. Ровно так уже утекла подсветка выбранного дня — она была
       написана как var(--brand-ink), и смена акцента на графит сравняла её с
       обычным текстом. Следующая смена акцента не должна утащить метку. */
    --marker: #3f5d7d;       /* 13,0:1 под --on-marker */
    --on-marker: #ffffff;

    /* Статус «хорошо» — отдельная краска, а не var(--brand). Пока тон тот
       же, но «Оплачено» и «Сохранить» больше не связаны одним токеном. */
    /* Знак продукта. Отдельно от действия сознательно: главное открытие всей
       перекраски в том, что акцент интерфейса никогда не был цветом бренда —
       в studio-logo.png знак почти чёрный с лаймовыми точками. Раз акцент не
       был брендом, смена акцента не имеет права перекрашивать знак. Зелёный
       на экране входа остаётся зелёным. */
    --logo: #2d7d61;
    --on-logo: #ffffff;

    --ok: #16a34a;
    --ok-bg: #eefaf1;
    --ok-ink: #146c34;       /* 6,6:1 на --ok-bg */
    --ok-border: #bbe7c9;

    /* Псевдонимы старых зелёных имён сняты: 139 обращений на 112 строках
       переписаны в роли. Пока они жили, файл читался так, будто в кабинете
       ещё есть цвет по имени «зелёный», и правило, красившее текст «зелёным
       тёмным», выглядело осмысленным — хотя означало «графит цвета текста».
       Именно так молча умерла подсветка выбранного дня: имя обещало цвет,
       которого в кабинете уже не было. Роль теперь названа в самом правиле,
       а возврат псевдонимов ловит тест test_the_green_aliases_stay_removed. */

    /* Ахроматическая светлая тема строится как рабочий документ: белый холст,
       тёпло-серая навигация и чуть более светлые панели. Карточка отделяется
       от холста тихой заливкой и рамкой, а не тяжёлой серой подложкой всей
       страницы. */
    --surface-2: #eef2f7;
    --surface-raised: #ffffff;
    --bg: #f6f7f9;
    --topbar: #ffffff;
    --sidebar: #131c26;
    --card: #ffffff;
    --search-bg: #ffffff;
    --ink: #0f172a;          /* 16,5:1 на карточке */
    --muted: #545f6e;        /* 6,9:1 на карточке */
    --faint: #5a6473;        /* 4,6:1 даже на выбранной строке */
    --border: #d9e0e9;       /* 1,32:1 к карточке */
    --text: var(--ink);

    /* Signal colours. The schedule board, the chat list and the task queue used
       to carry three unrelated reds and two unrelated blues; they share these. */
    --info: #2f7370;
    --info-soft: #e9f5f4;
    --info-border: #b7dedb;
    --danger: #c8342a;
    --on-danger: #ffffff;
    --danger-soft: #fdeeed;
    --danger-border: #f2c4c0;
    --warn: #8a5a06;
    --warn-soft: #fdf6e6;
    /* Фон внутренней заметки и полосы истории: заметно светлее, чем бейдж
       ожидания, иначе служебный блок выглядит как предупреждение. */
    --warn-tint: #fdf8ec;
    --warn-border: #e6d5a8;
    --warn-bg: #fbf1dd;
    --err: var(--danger);

    /* Панель, оторвавшаяся от страницы: липкая панель сохранения, всплывшее
       уведомление. Токен использовался в трёх правилах и нигде не был
       объявлен, поэтому те элементы оставались вовсе без тени. */
    --shadow: 0 1px 2px rgb(15 23 42 / 6%), 0 10px 28px rgb(15 23 42 / 8%);
    /* Toast общий для нескольких контуров; только кабинет задаёт ему свою тень. */
    --hui-toast-shadow: var(--shadow);
    --radius-sm: 6px;
    --radius-md: 10px;
    --radius-lg: 12px;

    /* Motion. Every interactive surface reads from these so the cabinet has one
       speed instead of a handful of ad-hoc durations. */
    --dur-fast: .12s;
    --dur: .18s;
    --ease: cubic-bezier(.2, .8, .2, 1);

    /* Отступы карточки от краёв экрана. Верхний — не просто отступ, а
       точка привязки: карточка растёт вниз от него, а не в обе стороны от центра.
       Потолки высоты считаются от этих двух чисел, поэтому поменять отступ
       значит поменять одно значение, а не восемь calc по файлу. */
    --dialog-top: min(6vh, 56px);
    --dialog-bottom: 24px;
    /* Сумма боковых отступов окна от краёв экрана — одна на все ступени
       ширины (было 24, 28, 32 и 36 px у разных окон). */
    --dialog-gutter: 32px;

    /* Stacking order, so a new overlay never needs another guessed 9999. */
    --z-raised: 2;
    --z-sticky: 5;
    --z-sidebar: 60;
    --z-menu: 70;
    --z-submenu: 80;
    --z-toast: 90;

    /* Затемнение под всплывающим слоем. Было три близких значения на трёх
       подложках: rgba(30,42,35,.38) у диалога, .42 у выдвижной карточки и
       rgb(20 32 26 / 38%) у поиска. Разницу между ними никто не выбирал. */
    --scrim: rgb(13 17 23 / 45%);
    --z-skip: 100;

    /* ------------------------------------------------------------------
       Категориальные палитры.

       Это не сигнальные цвета: они не значат «хорошо» или «ошибка», они
       отвечают на вопрос «чей» и «какое направление». Поэтому лежат отдельно
       от --info/--danger/--warn.
       ------------------------------------------------------------------ */

    /* Администраторы в графике смен: подложка дня и полоса слева. */
    --admin-0-bg: #dff2e8; --admin-0-accent: #2d7d61;
    --admin-1-bg: #e2ecfa; --admin-1-accent: #4677b8;
    --admin-2-bg: #f7e6ee; --admin-2-accent: #b45f82;
    --admin-3-bg: #f7eddc; --admin-3-accent: #ad762d;
    --admin-4-bg: #eae5f8; --admin-4-accent: #7358ad;
    --admin-5-bg: #dff1f2; --admin-5-accent: #33858b;
    --admin-6-bg: #f4e8df; --admin-6-accent: #a8663c;
    --admin-7-bg: #e7f0dc; --admin-7-accent: #6b8c3b;
    --admin-8-bg: #f2e6f4; --admin-8-accent: #9655a0;
    --admin-9-bg: #e8eaf5; --admin-9-accent: #5d68a8;

    /* Аналитика: рампа — десять акцентов администраторов и два своих тона.
       Когорты рисуются своей, более насыщенной рампой из двенадцати тонов
       и своим тоном тепловой карты. */
    --analytics-teal-deep: #257d73;
    --analytics-rose-deep: #a64f78;
    --cohort-0: #1673b9;
    --cohort-1: #c13f78;
    --cohort-2: #14805e;
    --cohort-3: #6d4bc3;
    --cohort-4: #d9534f;
    --cohort-5: #008ca0;
    --cohort-6: #6c941f;
    --cohort-7: #3046a3;
    --cohort-8: #9c46a8;
    --cohort-9: #3f8fd2;
    --cohort-10: #0d8879;
    --cohort-11: #d5689b;
    --cohort-heat: #136fa8;

    /* Каналы переписки в карточке клиента. Цвет здесь — опознавательный знак
       чужого канала, а не статус: он говорит, где лежит переписка, и подобран
       так, чтобы штрих 1.75 держал 3:1 на белой карточке (фирменные #04E061
       и #2AABEE этого не держат). */
    --channel-telegram: #0088cc;
    --channel-vk: #0077ff;
    --channel-instagram: #d62976;
    --channel-avito: #965eeb;

    /* Направления в расписании: восьмёрка, разведённая по кругу с шагом 37,5°
       так, что сектор бренда (167° ± 30°) остаётся пустым. Раньше четыре из
       восьми стояли в 176-202°, то есть вплотную к акценту, и на самом плотном
       экране кабинета категория занятия и главное действие читались как одно
       семейство.

       Второй признак различия — светлота: соседние по кругу чередуются между
       0,905 и 0,862 по OKLCH, потому что 37,5° по тону на пастели различаются
       хуже, чем хочется на доске из тридцати карточек.

       Регистр отличает их от сигналов: категория это бледная заливка с тёмным
       текстом, сигнал — насыщенная краска под текстом и границей. Поэтому
       --sched-6 (25°) не читается как ошибка, хотя стоит рядом с --danger. */
    --sched-1-bg: #d9daff; --sched-1-ink: var(--ink);   /* 285.0° */
    --sched-2-bg: #eac5f1; --sched-2-ink: var(--ink);   /* 322.5° */
    --sched-3-bg: #ffcce0; --sched-3-ink: var(--ink);   /*   0.0° */
    --sched-4-bg: #ffc3b5; --sched-4-ink: var(--ink);   /*  37.5° */
    --sched-5-bg: #ffd8ac; --sched-5-ink: var(--ink);   /*  75.0° */
    --sched-6-bg: #d8d8a1; --sched-6-ink: var(--ink);   /* 112.5° */
    --sched-7-bg: #c3edc2; --sched-7-ink: var(--ink);   /* 150.0° */
    --sched-8-bg: #9ee4d6; --sched-8-ink: var(--ink);   /* 187.5° */
    /* Мероприятие на доске: «магическая» плашка, как в виджете расписания и в
       приложении. Своя пара цветов, а не тон направления: у мероприятия
       направления нет, и во всех схемах кабинета плашка одинакова. */
    --event-magic-from: #2e2168; --event-magic-via: #62349a; --event-magic-to: #b24a86;
    --event-magic-gold: #ffd98c; --event-magic-ink: #fff;
    --event-magic-glow: rgb(255 204 112 / 30%);
    --event-magic-muted-ink: rgb(255 246 234 / 82%);
    --event-magic-full-ring: rgb(255 190 190 / 85%);
    --event-magic-shadow: 0 6px 16px rgb(62 30 120 / 22%);

    /* Нейтральные слои поверх цветной подложки: полоса зала на карточке
       занятия, штриховка «мест нет», блик сегмента когорт. Без тона, чтобы
       не спорить с краской под ними. */
    --shade: rgb(0 0 0 / 8%);
    --shade-stripe: rgb(0 0 0 / 10%);
    --gloss: rgb(255 255 255 / 72%);

    /* Сегмент и ИИ-агент: две несигнальные идентичности со своим тоном. */
    --segment-bg: #f0e9fa; --segment-border: #ddcff0; --segment-ink: #68458b;
    --ai-bg: #eceefb; --ai-border: #c3c8ee; --ai-ink: #3f4796;
    --ai-tag-bg: #e2e5fa;
    /* ------------------------------------------------------------------
       Чернила борта.

       Боковая панель перестала быть ступенью холста и стала отдельной
       почти чёрной плоскостью. Значит,
       и текст на ней свой — --ink на #17171a не читается вовсе. Три роли те же,
       что у содержимого: основной пункт, иконка, подпись раздела.

       Метка «вы здесь» на борту — лайм из знака студии: в studio-logo.png
       точки нарисованы #78c030, и это единственная краска, которая на борту
       принадлежит продукту. Она не статус и не действие, поэтому живёт
       отдельным токеном.
       ------------------------------------------------------------------ */
    --nav-ink: #c3cdd9;
    --nav-icon: #93a1b1;
    --nav-section: #9aa8b8;
    --nav-hover: #1e2b39;
    --nav-active-bg: #26374a;
    --nav-active-ink: #ffffff;
    --nav-marker: #8fb3d9;

}

/* ---------------------------------------------------------------------------
   Визуальный язык shadcn, перенесённый токенами.

   Сам shadcn — это React, Radix и Tailwind, и целиком сюда он не едет. Но
   «современно» в нём делает не React, а несколько решений о поверхности:
   граница вместо тени, кольцо фокуса со смещением, приглушённый заголовок без
   капитализации, крупная строка, цифры моноширинными знаками. Это переносится
   значениями.

   Токены построены поверх палитры кабинета, а не рядом с ней: --row-hover
   считается из --surface-2, --ring из --brand. Поэтому схема оформления
   ([data-scheme]), которая переопределяет палитру, получает их без второго
   набора правил.

   Осторожно с --muted: в этом файле это цвет ТЕКСТА, тогда как в shadcn
   --muted — это фон. Здесь ничего не переименовано; фон приглушённой
   поверхности так и остался --surface-2.
   --------------------------------------------------------------------------- */
:root {
    /* Кольцо фокуса. Раньше видимый фокус в кабинете рисовался где обводкой,
       где рамкой, где сменой фона, и на тёмной строке таблицы его не было
       видно вовсе. Смещение в 2px обязательно: без него кольцо садится вплотную
       к границе ячейки и сливается с ней. */
    --ring: var(--brand);
    --ring-w: 2px;
    --ring-offset: 2px;

    /* Ритм таблицы. Строка была 9px сверху и снизу — при 14px шрифта это 32px
       высоты, то есть плотность отчёта, а не рабочего списка: строки сливаются
       и глаз теряет ту, по которой ведёт. 48px — та же высота, что у кнопки и
       поля ввода, поэтому строка с элементом управления внутри не распирает
       соседние. --row-h-sm остаётся для вложенных таблиц в панелях, где на
       экран должно поместиться больше. */
    --row-h: 44px;
    --row-h-sm: 38px;
    /* Высота однострочного контрола. Ровно та же, что у .hui-button: поле и
       кнопка стоят рядом в каждой панели фильтров, и до этого расходились на
       четыре пикселя — поле 36, кнопка 40. При align-items: end это давало
       заметный уступ. Одно число на оба, чтобы они не разъезжались снова. */
    --control-h: 36px;
    --cell-x: 14px;
    --head-h: 40px;

    /* Подъём панели над холстом. Панель отделяется границей, тень только
       намекает на слой — один пиксель, а не облако. Тёмная тема
       переопределяет его ниже: там та же тень должна быть плотнее. */
    --lift: 0 1px 2px rgb(15 23 42 / 5%);

    /* Наведение и выделение строки. Прежний --surface-2 целиком давал плашку
       заметнее, чем выделение выбранной строки, — наведение кричало громче
       состояния. Через color-mix та же краска берётся вполсилы. */
    --row-hover: color-mix(in srgb, var(--surface-2) 55%, transparent);
    --row-selected: color-mix(in srgb, var(--brand-tint) 70%, transparent);

    /* Цвет подписи колонки. Заголовок перестал быть прописным и разряженным:
       ЗАГЛАВНЫЕ с letter-spacing читаются по буквам, а не словом, и в русском
       это дороже, чем в английском — слова длиннее. Вес 500 и обычный регистр
       отделяют заголовок от данных не криком, а тоном. */
    --head-ink: var(--muted);

    /* Ширина, ниже которой таблица уезжает в горизонтальную прокрутку вместо
       того, чтобы ломать колонки в нечитаемые столбики по одному слову. */
    --table-min: 720px;
}

/* ---------------------------------------------------------------------------
   Схемы кабинета.

   Тёмной темы больше нет: одна светлая поверхность, три палитры поверх неё.
   Схема — это акцент и борт вместе, а не два независимых тумблера: борт под
   акцент подбирается так, чтобы чернила на нём брали AA, и разрешать их
   произвольные пары значило бы разрешить нечитаемые.

   Базовая схема живёт в :root выше — она же значение по умолчанию, если
   в localStorage ничего нет. Ниже только отличия.

   Каждая схема несёт и свою восьмёрку направлений: сектор акцента ±33°
   остаётся пустым, иначе категория занятия читается как родственница главной
   кнопки. Значения посчитаны, а не подобраны, и проверяются тестом
   test_cabinet_colour_contract.
   --------------------------------------------------------------------------- */

/* Хвоя */
:root[data-scheme="forest"] {
    --brand: #2f5d4a;
    --brand-ink: #24523f;
    --brand-hover: #4e7d69;
    --on-brand: #ffffff;
    --marker: #2f5d4a;
    --on-marker: #ffffff;
    --selected: #deeee6;
    --info: #2563eb; --info-soft: #eff6ff; --info-border: #bfdbfe;

    --sidebar: #ffffff;
    --nav-ink: #44514a;
    --nav-icon: #5e6b65;
    --nav-section: #5e6b65;
    --nav-hover: #eef3ef;
    --nav-active-bg: #e4efe8;
    --nav-active-ink: #14231c;
    --nav-marker: #2f5d4a;
    /* Борт светлый — знак студии выворачивать нельзя, он и так почти чёрный. */
    --logo-filter: none;

    --sched-1-bg: #a6eff1; --sched-1-ink: var(--ink);   /* 198.0° */
    --sched-2-bg: #a5dcfc; --sched-2-ink: var(--ink);   /* 234.7° */
    --sched-3-bg: #cedeff; --sched-3-ink: var(--ink);   /* 271.5° */
    --sched-4-bg: #e1c7f9; --sched-4-ink: var(--ink);   /* 308.2° */
    --sched-5-bg: #ffcdeb; --sched-5-ink: var(--ink);   /* 345.0° */
    --sched-6-bg: #ffc2bf; --sched-6-ink: var(--ink);   /*  21.7° */
    --sched-7-bg: #ffd5b1; --sched-7-ink: var(--ink);   /*  58.5° */
    --sched-8-bg: #e2d49e; --sched-8-ink: var(--ink);   /*  95.2° */
}

/* Уголь — кабинет, каким он был до круга схем: тот же стальной акцент, но борт
   нейтрально-чёрный, а не уведённый в синеву акцента, и ориентир на нём
   лаймовый. Оставлен схемой по просьбе Ярослава.

   От «Основной» отличается только бортом и его лестницей: холст, панель
   и чернила содержимого те же. --faint взят нынешний, а не прежний: тот стоял
   ровно на пороге AA и на «выбранном» уходил под него. */
:root[data-scheme="charcoal"] {
    --brand: #3f5d7d;
    --brand-ink: #33506e;
    --brand-hover: #557697;
    --marker: #3f5d7d;
    --selected: #e6edf4;

    --sidebar: #17171a;
    --nav-ink: #c8ccd4;
    --nav-icon: #9aa0ab;
    --nav-section: #959aa4;
    --nav-hover: #26262b;
    --nav-active-bg: #2c2c33;
    --nav-active-ink: #ffffff;
    --nav-marker: #a3e635;

    --sched-1-bg: #dadaff; --sched-1-ink: var(--ink);
    --sched-2-bg: #ebc4f0; --sched-2-ink: var(--ink);
    --sched-3-bg: #ffccde; --sched-3-ink: var(--ink);
    --sched-4-bg: #ffc4b2; --sched-4-ink: var(--ink);
    --sched-5-bg: #fcdaab; --sched-5-ink: var(--ink);
    --sched-6-bg: #d4d9a3; --sched-6-ink: var(--ink);
    --sched-7-bg: #beeec7; --sched-7-ink: var(--ink);
    --sched-8-bg: #9ce3dc; --sched-8-ink: var(--ink);
}

/* Бухта */
:root[data-scheme="bay"] {
    --brand: #0f617d;
    --brand-ink: #005671;
    --brand-hover: #004560;
    --marker: #0f617d;
    --selected: #d8eef8;
    --hover: #e7f6fd;
    /* Справка уходит в синий: тил стоит в 37° от циана. Порог контракта (32°)
       он проходит, но впритык, а «подсказка» рядом с действием читается как
       приглушённое действие. Запас взят до 40°. */
    --info: #2563eb; --info-soft: #eff6ff; --info-border: #bfdbfe;

    /* Холст холоднее базового, борт — ступень под ним. Светлый борт держится
       ступенью, а не границей: это вторая механика из мокапов, у «Хвои» другая. */
    --bg: #f4f6f8;
    --surface-2: #eaeff3;
    --border: #d1dae3;

    --sidebar: #e5ebf2;
    --nav-ink: #33424c;
    --nav-icon: #4c5c66;
    --nav-section: #51616b;
    --nav-hover: #dbe4ed;
    --nav-active-bg: #d0dde9;
    --nav-active-ink: #12242e;
    --nav-marker: #0f617d;
    --logo-filter: none;

    --sched-1-bg: #cbdfff; --sched-1-ink: var(--ink);   /* 267.5° */
    --sched-2-bg: #dcc9fc; --sched-2-ink: var(--ink);   /* 302.5° */
    --sched-3-bg: #ffcef1; --sched-3-ink: var(--ink);   /* 337.5° */
    --sched-4-bg: #ffc1c6; --sched-4-ink: var(--ink);   /*  12.5° */
    --sched-5-bg: #ffd2b7; --sched-5-ink: var(--ink);   /*  47.5° */
    --sched-6-bg: #ebd09e; --sched-6-ink: var(--ink);   /*  82.5° */
    --sched-7-bg: #dbe7b1; --sched-7-ink: var(--ink);   /* 117.5° */
    --sched-8-bg: #b0e2bd; --sched-8-ink: var(--ink);   /* 152.5° */
}

* { box-sizing: border-box; }
/* Те же пиксели, что и раньше, но из токенов: --ring-w и --ring-offset уже
   держат кнопки HeroUI и заголовки таблиц. Раньше это правило повторяло их
   значения числами, и сменить толщину кольца значило найти все места. */
*:focus-visible { outline: var(--ring-w) solid var(--ring); outline-offset: var(--ring-offset); }
/* The reduced-motion block below already turned this off; it was overriding a
   declaration that never existed, so in-page anchors jumped. */
html { scroll-behavior: smooth; }
/* Атрибут hidden прячет всегда. Браузерное [hidden] проигрывает любому
   правилу с display — flex у label, grid у формы, inline-flex у кнопки, — и
   каждая такая пара заводила своё «X[hidden] { display: none }»: их было
   три десятка по файлу, а забытая давала элемент, видимый с hidden.
   Показать скрытое значит снять атрибут, а не перебить его стилем. */
[hidden] { display: none !important; }
body {
    margin: 0;
    font-family: "Manrope", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    background: var(--bg);
    color: var(--ink);
    font-size: 15px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}
/* Ссылка отличается от текста не только цветом.

   Требование WCAG 1.4.1: если ссылку в тексте выделяет один цвет, он обязан
   отстоять от цвета текста на 3:1. Тёмно-зелёный давал 2,07:1 к чернилам, то
   есть критерий был провален и до графита; с ахроматическим действием стало
   бы 1,21:1. Подчёркивание снимает вопрос и заодно возвращает ссылке привычный
   вид. Компоненты, которым подчёркивание не нужно (навигация, кнопки-ссылки,
   карточки), гасят его сами — таких правил в файле три десятка. */
a {
    color: var(--brand-ink);
    text-decoration: underline;
    /* Волосяная линия, а не жирная черта: в таблице кабинета ссылка стоит в
       каждой второй ячейке, и сплошное подчёркивание превращает плотный
       экран в частокол. Признак при этом остаётся, а под курсором линия
       набирает полный вес. */
    text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
    transition: color var(--dur) ease, text-decoration-color var(--dur) ease;
}
a:hover { text-decoration-color: currentColor; }

/* App shell */
.app-shell { display: flex; align-items: flex-start; min-height: 100dvh; }
.sidebar {
    position: sticky; top: 0; align-self: flex-start; flex: 0 0 250px; width: 250px;
    height: 100dvh; min-height: 0; display: flex; flex-direction: column; gap: 5px;
    background: var(--sidebar); border-right: 1px solid var(--border); padding: 18px 14px;
    overflow: visible;
    z-index: var(--z-sidebar);
    transition: width var(--dur) var(--ease), flex-basis var(--dur) var(--ease), padding var(--dur) var(--ease);
}
.sidebar-header {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    min-width: 0; min-height: 38px; flex-shrink: 0;
}
.sidebar-logo {
    display: flex; flex: 1 1 auto; align-items: center;
    min-width: 0; height: 38px; overflow: hidden;
}
.sidebar-logo img {
    display: block; width: auto; max-width: 100%; height: auto; max-height: 38px;
    object-fit: contain; object-position: left center;
}
/* Знак нарисован почти чёрным (#101010) на прозрачном фоне, поэтому на тёмном
   холсте от него оставались одни лаймовые точки. Плашку логотипа делит с
   кабинетом клиентский контур, значит перерисовывать сам файл нельзя — берём
   тот же приём, которым это уже решено в client.css для .cp-brand-logo.
   Тень оттуда не переносится: там знак лежит на фотографии, здесь — на
   ровной поверхности, и тень была бы украшением. */
/* Знак нарисован почти чёрным. На тёмном борту его выворачивают, на светлом
   он читается как есть — поэтому фильтр принадлежит схеме, а не элементу. */
.sidebar-logo img {
    filter: var(--logo-filter, brightness(0) invert(1));
}
.sidebar-collapse {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; flex: 0 0 34px; padding: 0;
    border: 1px solid color-mix(in srgb, var(--nav-ink) 20%, var(--sidebar));
    border-radius: var(--radius-sm);
    background: var(--nav-hover); color: var(--nav-icon); font: inherit; cursor: pointer;
    transition: color var(--dur) ease, background var(--dur) ease, border-color var(--dur) ease;
}
.sidebar-collapse:hover {
    color: var(--nav-active-ink); background: var(--nav-active-bg);
    border-color: color-mix(in srgb, var(--nav-ink) 38%, var(--sidebar));
}
.sidebar-collapse:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.sidebar-collapse svg {
    width: 15px; height: 15px; flex: 0 0 15px; fill: none; stroke: currentColor;
    stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round;
    transition: transform var(--dur) var(--ease);
}
.brand {
    display: flex; align-items: center; gap: 10px; padding: 6px 8px 14px;
    text-decoration: none; color: var(--ink);
}
.brand-mark {
    width: 30px; height: 30px; border-radius: 10px; display: inline-flex;
    align-items: center; justify-content: center; background: var(--logo);
    color: var(--on-logo); font-weight: 700; font-size: 16px;
}
.brand.big { font-size: 26px; color: var(--logo); }
.sidenav {
    display: flex; flex: 1 1 auto; flex-direction: column; gap: 2px; padding-bottom: 12px;
    min-height: 0; overflow-y: auto; overflow-x: hidden;
    overscroll-behavior: contain; scrollbar-width: thin;
}
.sidenav > * { flex-shrink: 0; }
.nav-section {
    padding: 14px 8px 4px; color: var(--nav-section); font-size: 10.5px;
    font-weight: 600; letter-spacing: .09em; text-transform: uppercase;
}
.nav-item {
    display: flex; align-items: center; gap: 10px; width: 100%;
    padding: 8px 10px; border: none; border-radius: var(--radius-md);
    background: transparent; color: var(--nav-ink); text-align: left; text-decoration: none;
    font: inherit; font-size: 14px; line-height: 1.2; cursor: pointer;
}
.nav-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-item:hover { background: var(--nav-hover); }
.nav-item:active { background: var(--nav-active-bg); }
/* «Вы здесь» на борту: плотная плашка плюс лаймовая метка слева.
   Лайм взят из знака студии — точки в studio-logo.png, — и это
   единственная краска, которая на тёмном борту принадлежит продукту.
   Значение живёт в --nav-marker, а не здесь. */
.nav-item.active {
    background: var(--nav-active-bg); color: var(--nav-active-ink); font-weight: 600;
    box-shadow: inset 2px 0 0 var(--nav-marker);
}
.nav-dropdown { position: relative; }
.nav-parent { padding-right: 8px; }
.nav-caret { display: inline-flex; margin-left: auto; color: var(--nav-section); }
.nav-caret svg {
    width: 15px; height: 15px; fill: none; stroke: currentColor;
    stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
    transition: transform var(--dur) var(--ease);
}
.nav-parent[aria-expanded="true"] .nav-caret svg,
.nav-dropdown:hover .nav-caret svg,
.nav-dropdown:focus-within .nav-caret svg { transform: rotate(90deg); }
.nav-submenu {
    position: absolute;
    left: 100%;
    top: 0;
    z-index: var(--z-submenu);
    min-width: 210px;
    display: none;
    padding: 6px;
    background: var(--nav-active-bg);
    border: 1px solid color-mix(in srgb, var(--nav-ink) 22%, var(--nav-active-bg));
    border-radius: var(--radius-md);
    box-shadow: var(--shadow);
}
.nav-dropdown:hover > .nav-submenu,
.nav-dropdown:focus-within > .nav-submenu { display: grid; gap: 3px; }
.nav-subitem {
    display: block;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    color: var(--nav-ink);
    text-decoration: none;
    font-size: 13px;
    line-height: 1.2;
}
.nav-subitem:hover { background: var(--nav-hover); color: var(--nav-active-ink); }
.nav-subitem.active {
    background: color-mix(in srgb, var(--nav-ink) 16%, var(--nav-active-bg));
    color: var(--nav-active-ink); font-weight: 600;
}
.nav-icon {
    width: 22px; height: 22px; flex: 0 0 22px; display: inline-flex;
    align-items: center; justify-content: center; color: var(--nav-icon);
}
/* Один набор символов вместо юникодных глифов: одинаковая сетка, одинаковая
   толщина обводки, ни одного повтора среди видимых пунктов меню. */
.icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.nav-icon svg {
    width: 19px; height: 19px;
    fill: none; stroke: currentColor; stroke-width: 1.75;
    stroke-linecap: round; stroke-linejoin: round;
}
.nav-item:hover .nav-icon { color: var(--nav-active-ink); }
.nav-item.active .nav-icon { color: var(--nav-active-ink); }
@media (min-width: 901px) {
    html[data-sidebar-collapsed="true"] .sidebar {
        flex-basis: 68px;
        width: 68px;
        padding-right: 12px;
        padding-left: 12px;
    }
    html[data-sidebar-collapsed="true"] .sidebar-header { justify-content: flex-end; }
    html[data-sidebar-collapsed="true"] .sidebar-logo,
    html[data-sidebar-collapsed="true"] .nav-section,
    html[data-sidebar-collapsed="true"] .nav-label,
    html[data-sidebar-collapsed="true"] .nav-caret { display: none; }
    html[data-sidebar-collapsed="true"] .sidebar-collapse {
        width: 34px;
        padding: 0;
    }
    html[data-sidebar-collapsed="true"] .sidebar-collapse svg { transform: rotate(180deg); }
    html[data-sidebar-collapsed="true"] .sidenav { align-items: stretch; }
    /* Свёрнутая карточка — снова флекс: остаются одни кнопки. */
    html[data-sidebar-collapsed="true"] .sidebar-account {
        display: flex;
        width: 100%;
        justify-content: center;
        gap: 0;
        padding-right: 4px;
        padding-left: 4px;
    }
    html[data-sidebar-collapsed="true"] .sidebar-account-icon,
    html[data-sidebar-collapsed="true"] .sidebar-account-copy { display: none; }
    /* В свёрнутом меню две кнопки не помещаются в ряд — встают столбиком. */
    html[data-sidebar-collapsed="true"] .sidebar-account:has(.sidebar-account-link) {
        flex-direction: column;
        gap: 6px;
    }
    html[data-sidebar-collapsed="true"] .sidebar-account-link,
    html[data-sidebar-collapsed="true"] .sidebar-account-link + .sidebar-logout-form { margin: 0; }
    html[data-sidebar-collapsed="true"] .sidebar-logout-form {
        width: auto;
        height: 34px;
        margin-right: auto;
        margin-left: auto;
    }
    html[data-sidebar-collapsed="true"] .sidebar-logout {
        width: 34px;
        height: 34px;
        min-height: 34px;
        padding-right: 0;
        padding-left: 0;
    }
    html[data-sidebar-collapsed="true"] .nav-item {
        position: relative;
        justify-content: center;
        gap: 0;
        padding: 8px;
    }
    html[data-sidebar-collapsed="true"] .nav-parent { padding-right: 8px; }
    html[data-sidebar-collapsed="true"] .nav-submenu { left: calc(100% + 12px); }
    /* Невидимый мост перекрывает визуальный зазор между иконкой и слоем.
       Без него курсор на 12px покидал весь .nav-dropdown, :hover снимался и
       подменю исчезало раньше, чем до него можно было дойти. */
    html[data-sidebar-collapsed="true"] .nav-submenu::before {
        content: "";
        position: absolute;
        inset-block: -1px;
        inset-inline-end: 100%;
        inline-size: 13px;
    }
    html[data-sidebar-collapsed="true"] .nav-badge {
        position: absolute;
        top: 1px;
        right: 0;
        min-width: 16px;
        height: 16px;
        padding: 0 4px;
        font-size: 9px;
    }
}
.avatar {
    width: 30px; height: 30px; border-radius: 50%; flex: 0 0 auto; display: inline-flex;
    align-items: center; justify-content: center; background: var(--brand); color: var(--on-brand);
    font-size: 13px; font-weight: 700;
}
.username { display: block; font-size: 13.5px; font-weight: 600; line-height: 1.2; }
.main-shell { flex: 1; min-width: 0; }
.topbar {
    position: sticky; top: 0; z-index: var(--z-sticky); display: flex; align-items: center; gap: 12px;
    padding: 6px 26px; background: color-mix(in srgb, var(--topbar) 94%, transparent);
    backdrop-filter: blur(6px); border-bottom: 1px solid var(--border);
}
.topbar-heading {
    display: flex; align-items: center; gap: 7px; min-width: 0;
    white-space: nowrap; font-size: 14px; font-weight: 600; line-height: 1.2; letter-spacing: -.01em;
}
.topbar-section, .topbar-title {
    min-width: 0; margin: 0; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; font: inherit;
}
.topbar-section { flex: 0 1 auto; color: var(--muted); }
.topbar-divider { flex: 0 0 auto; color: var(--faint); font: inherit; font-weight: 400; }
.topbar-title { flex: 1 1 auto; color: var(--ink); }
.topbar-chips {
    --topbar-control-height: 32px;
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
    flex-wrap: wrap;
}
/* Учётка и завершение сессии замыкают сайдбар одним нижним блоком. */
.sidebar-account-stack {
    display: flex;
    flex-shrink: 0;
    align-items: stretch;
    gap: 6px;
    min-width: 0;
    margin-top: auto;
}
/* Карточка — сетка в две строки. Первая — значок, имя и кнопки «База знаний»
   и «Выйти», выровненные по общему центру; вторая — роль, от колонки имени до
   правого края. Пока роль стояла под именем в узкой колонке между значком и
   двумя кнопками, «Администратор» обрезался до «Администра…» и читался только
   во всплывающей подсказке. Имя по-прежнему может обрезаться; роль
   переносится, но не обрезается. */
.sidebar-account {
    display: grid; grid-template-columns: 28px minmax(0, 1fr) auto auto;
    flex: 1 1 auto; align-items: center; column-gap: 9px; row-gap: 0; width: 100%; min-width: 0;
    min-height: 48px; margin-top: 0; padding: 8px 9px;
    border: 1px solid color-mix(in srgb, var(--nav-ink) 18%, var(--sidebar));
    border-radius: var(--radius-sm);
    background: var(--nav-hover); color: var(--nav-ink); white-space: nowrap;
}
.sidebar-account-icon {
    width: 28px; height: 28px; grid-column: 1; grid-row: 1;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--radius-sm);
    background: var(--nav-active-bg); color: var(--nav-ink);
}
.sidebar-account-icon svg {
    width: 19px; height: 19px; fill: none; stroke: currentColor;
    stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.sidebar-account-copy { display: contents; line-height: 1; }
.sidebar-account-name {
    grid-column: 2; grid-row: 1; min-width: 0;
    overflow: hidden; text-overflow: ellipsis;
    font-size: 14px; font-weight: 700;
}
.sidebar-account-role {
    grid-column: 2 / -1; grid-row: 2; align-self: start; margin-top: 2px;
    color: var(--nav-section); font-size: 12px; line-height: 1.25;
    white-space: normal; overflow-wrap: anywhere;
}
/* Бургер и затемнение нужны только на узких экранах. */
.nav-burger, .nav-scrim { display: none; }
/* ---------------------------------------------------------------------------
   Combobox, перенесённый из shadcn/ui.

   Там это Popover + Command на Radix и cmdk; сюда едет не React, а решения о
   поверхности: контурный триггер во всю ширину с шевроном вполсилы, всплывающий
   список без своих отступов, пункт с галочкой слева — она занимает место всегда,
   чтобы подписи не прыгали при смене выбора. Строка фильтра из cmdk не поехала:
   схем три, и поле поиска над тремя строками только просит, чтобы в него печатали.

   Живёт в верхней полосе на месте прежнего тумблера темы. Тёмной темы больше
   нет, переключается схема — акцент и борт вместе.
   --------------------------------------------------------------------------- */
.hui-combobox { position: relative; display: inline-flex; }
.hui-combobox-trigger {
    display: inline-flex; align-items: center; justify-content: space-between; gap: 8px;
    min-width: 168px; height: var(--topbar-control-height); padding: 0 10px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--surface-raised); color: var(--ink);
    font: inherit; font-size: 13px; font-weight: 500; line-height: 1;
    white-space: nowrap; cursor: pointer;
    box-shadow: var(--lift);
    transition: background var(--dur) ease, border-color var(--dur) ease;
}
.hui-combobox-trigger:hover { background: var(--hover); }
.hui-combobox-trigger:focus-visible {
    outline: var(--ring-w) solid var(--ring); outline-offset: var(--ring-offset);
}
.hui-combobox-caret {
    width: 16px; height: 16px; flex: 0 0 16px;
    fill: none; stroke: currentColor; stroke-width: 2;
    stroke-linecap: round; stroke-linejoin: round;
    /* Шеврон в shadcn стоит вполсилы: это подсказка, а не элемент управления. */
    opacity: .5;
}
.hui-combobox-popover {
    position: absolute; top: calc(100% + 6px); right: 0; z-index: var(--z-menu);
    /* 208px здесь стояли под строку фильтра. Её нет — список равняется по
       триггеру, как в shadcn, и дальше растёт по самой длинной подписи. */
    min-width: 100%; padding: 0;
    border: 1px solid var(--border); border-radius: var(--radius-md);
    background: var(--surface-raised); box-shadow: var(--shadow);
    overflow: hidden;
}
.hui-combobox-list { display: grid; gap: 2px; padding: 4px; }
.hui-combobox-option {
    display: flex; align-items: center; gap: 8px; width: 100%;
    padding: 7px 8px; border: 0; border-radius: var(--radius-sm);
    background: transparent; color: var(--ink);
    font: inherit; font-size: 13.5px; line-height: 1.2; text-align: left; cursor: pointer;
}
.hui-combobox-option:hover { background: var(--hover); }
.hui-combobox-option:focus-visible {
    outline: none; background: var(--selected);
}
.hui-combobox-option[aria-selected="true"] { background: var(--selected); font-weight: 600; }
.hui-combobox-check {
    width: 16px; height: 16px; flex: 0 0 16px;
    fill: none; stroke: currentColor; stroke-width: 2.2;
    stroke-linecap: round; stroke-linejoin: round;
    /* Галочка занимает место всегда: иначе подписи прыгают при смене выбора. */
    opacity: 0;
}
.hui-combobox-option[aria-selected="true"] .hui-combobox-check { opacity: 1; }

/* HeroUI Popover для серверной Jinja-разметки. В React-компоненте содержимое
   живёт в portal; здесь app.js делает то же самое, поэтому слой не обрезается
   таблицей, drawer или прокруткой контейнера. */
.hui-popover { position: relative; display: inline-flex; }
.hui-popover__content {
    position: fixed; z-index: var(--z-menu);
    width: max-content; max-width: min(380px, calc(100vw - 24px));
    border: 1px solid var(--border); border-radius: var(--radius-md);
    background: var(--surface-raised); color: var(--ink); box-shadow: var(--shadow);
    outline: none;
}
.hui-popover__dialog {
    max-height: min(360px, calc(100vh - 32px));
    padding: 14px; overflow: auto;
}
.hui-popover__heading {
    margin: 0 0 8px; color: var(--ink);
    font-size: 14px; font-weight: 700; line-height: 1.3;
}
.hui-popover__arrow {
    position: absolute; left: var(--hui-popover-arrow-left, 50%);
    width: 10px; height: 10px;
    border: solid var(--border); background: var(--surface-raised);
    transform: translateX(-50%) rotate(45deg); pointer-events: none;
}
.hui-popover__content[data-placement="bottom"] .hui-popover__arrow {
    top: -6px; border-width: 1px 0 0 1px;
}
.hui-popover__content[data-placement="top"] .hui-popover__arrow {
    bottom: -6px; border-width: 0 1px 1px 0;
}

.chip {
    display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--card); color: var(--ink); font-size: 12.5px; font-weight: 600;
}
.sidebar-logout-form {
    display: inline-flex;
    width: auto;
    height: 34px;
    flex: 0 0 auto;
    grid-column: 4; grid-row: 1;
    margin: 0 0 0 auto;
}
.sidebar-logout {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    min-height: 34px;
    padding: 0;
    border-radius: var(--radius-sm);
    /* Выход завершает сессию, но не удаляет данные, поэтому остаётся
       контурным. Необратимые удаления используют заполненный danger-вариант. */
    border: 1px solid color-mix(in srgb, var(--danger) 42%, var(--sidebar));
    background: var(--nav-hover);
    color: color-mix(in srgb, var(--danger) 62%, var(--nav-ink));
    font: inherit;
    line-height: 1;
    cursor: pointer;
    transition: background .18s ease, border-color .18s ease, color .18s ease, transform .18s ease;
}
.sidebar-logout:hover {
    border-color: var(--danger);
    background: color-mix(in srgb, var(--danger) 26%, var(--sidebar));
    color: var(--on-danger);
}
.sidebar-logout:active { transform: translateY(1px); }
/* База знаний — соседняя кнопка той же формы, но нейтральная: это переход,
   а не завершение сессии. Кнопка забирает auto-отступ, выход встаёт рядом
   на обычный зазор карточки. */
.sidebar-account-link {
    display: inline-flex;
    flex: 0 0 auto;
    grid-column: 3; grid-row: 1;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    margin-left: auto;
    border: 1px solid color-mix(in srgb, var(--nav-ink) 18%, var(--sidebar));
    border-radius: var(--radius-sm);
    background: var(--nav-hover);
    color: var(--nav-ink);
    text-decoration: none;
    transition: background .18s ease, color .18s ease;
}
.sidebar-account-link:hover { background: var(--nav-active-bg); color: var(--nav-active-ink); }
.sidebar-account-link + .sidebar-logout-form { margin-left: 0; }
.sidebar-logout-icon { display: inline-flex; width: 18px; height: 18px; flex: 0 0 18px; }
.sidebar-logout-icon svg {
    width: 18px; height: 18px; fill: none; stroke: currentColor;
    stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.chip.dark { background: var(--ink); border-color: var(--ink); color: var(--bg); }

.container { max-width: 1100px; margin: 22px auto; padding: 0 18px; }
.container.wide { max-width: 1360px; }
.app-shell .container { max-width: 1280px; margin: 0 auto; padding: 24px 26px 52px; }
.app-shell .container.wide { max-width: 1500px; }
.app-shell .container.dashboard-container { max-width: none; width: 100%; }
.app-shell .container.expenses-container { max-width: none; width: 100%; }
/* Мероприятия — список, как остальные модули-списки, во всю ширину: общий
   потолок .operations-container не действовал, его перебивал .app-shell. */
.app-shell .container.events-container { max-width: none; width: 100%; }
.app-shell .container.branches-container { max-width: none; width: 100%; margin: 0; padding-left: 18px; padding-right: 18px; }
.app-shell .container.shelf-products-container { max-width: none; width: 100%; margin: 0; padding-left: 18px; padding-right: 18px; }
/* Оптимизатор расписания: три вкладки на 20 % шире обычной страницы кабинета — сетка с колонкой
   «Относительно шаблона» и таблица преподавателей иначе не помещаются. */
.container.schedule-optimizer-container { max-width: 1320px; }
.app-shell .container.schedule-optimizer-container { max-width: 1536px; }
.app-shell .container.checkout-orders-container { max-width: none; width: 100%; margin: 0; padding-left: 18px; padding-right: 18px; }
.app-shell .container.shifts-container { max-width: none; width: 100%; margin: 0; padding-left: 18px; padding-right: 18px; }
.shifts-open-header h2 { margin: 0; }
.app-shell .container.contracts-container { max-width: none; width: 100%; margin: 0; padding-left: 18px; padding-right: 18px; }
.shifts-table { width: 100%; }
.shifts-table th, .shifts-table td { width: auto; white-space: nowrap; }
.shifts-history-pagination { margin-top: 16px; }
.cash-delta { font-weight: 800; }
.cash-delta.positive { color: var(--ok-ink); }
.cash-delta.negative { color: var(--err); }
.app-shell .container.communications-container,
.app-shell .container.wide-container,
.app-shell .container.tasks-container { max-width: none; width: 100%; margin: 0; padding-left: 18px; padding-right: 18px; }
.app-shell .container.clients-container {
    max-width: none;
    width: 100%;
    margin: 0;
    padding-left: 18px;
    padding-right: 18px;
}
.app-shell .container.staff-container {
    max-width: none;
    width: 100%;
    margin: 0;
    padding-left: 18px;
    padding-right: 18px;
}
.app-shell .container.users-container {
    max-width: none;
    width: 100%;
    margin: 0;
    padding-left: 18px;
    padding-right: 18px;
}
.branch-multiselect-field {
    display: grid;
    flex: 1 1 100%;
    min-width: 0;
    gap: 4px;
}
/* Подпись поля без <label> (у выпадающего списка галочек) — тем же видом. */
.branch-multiselect-label { color: var(--ink); font-size: 12px; font-weight: 700; }
.branch-multiselect { min-width: 0; }
.branch-multiselect > summary {
    display: flex;
    width: 100%;
    min-width: 0;
    height: var(--control-h);
    box-sizing: border-box;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 0 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card);
    color: var(--ink);
    font-size: 15px;
    cursor: pointer;
    list-style: none;
}
.branch-multiselect > summary::-webkit-details-marker { display: none; }
.branch-multiselect > summary::after {
    width: 7px;
    height: 7px;
    flex: 0 0 7px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    opacity: .55;
    content: "";
    transform: translateY(-2px) rotate(45deg);
    transition: transform var(--dur-fast) ease;
}
.branch-multiselect[open] > summary {
    border-color: var(--brand-border-strong);
    box-shadow: 0 0 0 1px var(--brand-border-strong);
}
.branch-multiselect[open] > summary::after { transform: translateY(2px) rotate(225deg); }
.branch-multiselect > summary:focus-visible {
    outline: var(--ring-w) solid var(--ring);
    outline-offset: var(--ring-offset);
}
.branch-multiselect [data-branch-summary] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.branch-multiselect-menu {
    display: grid;
    max-height: 250px;
    gap: 3px;
    margin-top: 5px;
    padding: 6px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-raised);
    box-shadow: var(--lift);
}
.branch-multiselect-hint,
.branch-multiselect-empty {
    margin: 2px 6px 5px;
    color: var(--muted);
    font-size: 12px;
    line-height: 1.4;
}
.branch-multiselect-option {
    display: flex;
    min-width: 0;
    flex-direction: row;
    align-items: center;
    gap: 9px;
    padding: 8px 9px;
    border-radius: var(--radius-sm);
    color: var(--ink);
    cursor: pointer;
}
.branch-multiselect-option:hover { background: var(--hover); }
.branch-multiselect-option:has(input:focus-visible) {
    outline: var(--ring-w) solid var(--ring);
    outline-offset: var(--ring-offset);
}
.branch-multiselect-option input[type="checkbox"] {
    width: 16px;
    height: 16px;
    flex: 0 0 16px;
    accent-color: var(--brand);
}
.branch-multiselect-id { margin-left: auto; color: var(--faint); font-size: 12px; }
.branch-multiselect-clear {
    justify-self: start;
    margin: 3px 4px 1px;
    padding: 4px 5px;
    border: 0;
    background: transparent;
    color: var(--brand-ink);
    font: inherit;
    font-size: 12.5px;
    font-weight: 650;
}
.branch-multiselect-clear:hover { text-decoration: underline; }
.branch-multiselect-field > small { color: var(--muted); font-size: 12px; line-height: 1.4; }
.app-shell .container.passes-container {
    max-width: none;
    width: 100%;
    margin: 0;
    padding-left: 18px;
    padding-right: 18px;
}
.app-shell .container.client-passes-container {
    max-width: none;
    width: 100%;
    margin: 0;
    padding-left: 18px;
    padding-right: 18px;
}
.app-shell .container.pass-operations-container {
    max-width: none;
    width: 100%;
    margin: 0;
    padding-left: 18px;
    padding-right: 18px;
}
.app-shell .container.catalog-container {
    max-width: none;
    width: 100%;
    margin: 0;
    padding-left: 18px;
    padding-right: 18px;
}
.app-shell .container.classes-container {
    max-width: none;
    width: 100%;
    margin: 0;
    padding: 10px 12px 44px;
}
.app-shell .container.payroll-module-container {
    max-width: none;
    width: 100%;
    margin: 0;
    padding-left: 18px;
    padding-right: 18px;
}
h1 { font-size: 22px; margin: 0 0 16px; }
h2 { font-size: 17px; margin: 28px 0 10px; }
h3 { font-size: 15px; margin: 18px 0 8px; color: var(--muted); }
.muted { color: var(--muted); }
code { background: var(--surface-2); padding: 1px 5px; border-radius: 4px; }
.page-header {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    flex-wrap: wrap; margin-bottom: 14px;
}
.page-header p { margin: 0; }
.page-header > .hui-button:only-child,
.page-header > a.hui-button:only-child,
.page-header > form:only-child { margin-left: auto; }
/* Ряд действий страницы: кнопка без иконки стоит на одной линии с кнопками
   с иконкой (строчные кнопки выравнивались по базовой линии и съезжали). */
.page-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.page-subtitle { margin: 0; color: var(--muted); font-size: 14px; }

/* Cards */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; }
/* Было align-items: start — карточки в одном ряду обрывались на трёх разных
   высотах, потому что у «Расходов» есть переключатель разбивки, а у «Прибыли»
   одна строка. Растяжка выравнивает нижнюю кромку ряда; содержимое карточки
   и так прижато к верху. */
.container.roster-page { width: 100%; max-width: none; }
.roster-toolbar { display: flex; align-items: end; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 16px; }
.roster-branch-picker { min-width: 220px; margin-right: auto; }
/* Форма выбора филиала не участвует в раскладке панели: флекс-элементом
   остаётся подпись с полем, как до перехода на GET-форму. */
.roster-branch-form { display: contents; }
.roster-period-nav { display: inline-flex; align-items: center; justify-content: flex-end; gap: 6px; margin-left: auto; }
.roster-period-title { min-width: 155px; text-align: center; white-space: nowrap; }
.roster-period-button { width: 38px; min-width: 38px; padding-inline: 0; text-align: center; }
.roster-month { display: grid; grid-template-columns: repeat(7,minmax(120px,1fr)); gap: 1px; overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--border); }
.roster-weekday { padding: 9px; background: var(--surface-2); color: var(--muted); font-size: 12px; font-weight: 700; text-align: center; }
.roster-month-day { min-width: 0; min-height: 118px; display: flex; flex-direction: column; align-items: flex-start; gap: 7px; padding: 10px; border: 0; border-radius: 0; background: var(--card); color: var(--text); text-align: left; }
.roster-month-day.empty { cursor: default; background: var(--surface-2); }
.roster-month-day.today { box-shadow: inset 0 0 0 2px var(--marker); }
.roster-day-assignments { display: grid; gap: 6px; width: 100%; }
.roster-edit-status { min-height: 22px; margin: 0 0 8px; font-size: 13px; color: var(--muted); }
.roster-edit-status.is-error { color: var(--danger); }
.roster-month-day[data-roster-cell] { cursor: cell; }
.roster-month[data-roster-grid] { user-select: none; }
.roster-month-day[aria-selected="true"] { outline: 2px solid var(--brand); outline-offset: -2px; background: var(--surface-2); }
.roster-month-day[data-roster-cell]:focus-visible { outline: 3px solid var(--brand); outline-offset: -3px; }
.roster-assignment-chip.is-roster-selected { outline: 2px solid var(--brand); outline-offset: 1px; }
.roster-cell-editor { width: 100%; }
.roster-cell-editor select { width: 100%; min-width: 0; }
.roster-month[aria-busy="true"] { cursor: progress; }
.roster-assignment-chip { display: grid; gap: 2px; width: 100%; min-width: 0; overflow-wrap: anywhere; padding: 7px 8px; border: 1px solid var(--roster-admin-accent, var(--border)); border-radius: 8px; background: var(--roster-admin-bg, var(--brand-tint)); color: var(--text); text-align: left; cursor: pointer; }
.roster-assignment-chip:hover { background: color-mix(in srgb, var(--roster-admin-bg, var(--brand-tint)) 86%, var(--ink)); }
.roster-assignment-chip.admin-color-0 { --roster-admin-bg: var(--admin-0-bg); --roster-admin-accent: var(--admin-0-accent); }
.roster-assignment-chip.admin-color-1 { --roster-admin-bg: var(--admin-1-bg); --roster-admin-accent: var(--admin-1-accent); }
.roster-assignment-chip.admin-color-2 { --roster-admin-bg: var(--admin-2-bg); --roster-admin-accent: var(--admin-2-accent); }
.roster-assignment-chip.admin-color-3 { --roster-admin-bg: var(--admin-3-bg); --roster-admin-accent: var(--admin-3-accent); }
.roster-assignment-chip.admin-color-4 { --roster-admin-bg: var(--admin-4-bg); --roster-admin-accent: var(--admin-4-accent); }
.roster-assignment-chip.admin-color-5 { --roster-admin-bg: var(--admin-5-bg); --roster-admin-accent: var(--admin-5-accent); }
.roster-assignment-chip.admin-color-6 { --roster-admin-bg: var(--admin-6-bg); --roster-admin-accent: var(--admin-6-accent); }
.roster-assignment-chip.admin-color-7 { --roster-admin-bg: var(--admin-7-bg); --roster-admin-accent: var(--admin-7-accent); }
.roster-assignment-chip.admin-color-8 { --roster-admin-bg: var(--admin-8-bg); --roster-admin-accent: var(--admin-8-accent); }
.roster-assignment-chip.admin-color-9 { --roster-admin-bg: var(--admin-9-bg); --roster-admin-accent: var(--admin-9-accent); }
.roster-add-shift.hui-button { width: 100%; min-width: 0; height: auto; min-height: 32px; padding-block: 6px; white-space: normal; margin-top: auto; }
@media (pointer: coarse) { .roster-add-shift.hui-button { min-height: 44px; } }
.roster-plan-fact { margin-top: 18px; }
.roster-assignment-modal .actions { flex-wrap: wrap; }
.roster-month-day small { color: var(--muted); overflow-wrap: anywhere; }
.roster-date-number { display: grid; width: 27px; height: 27px; place-items: center; border-radius: 50%; font-weight: 800; }
/* Текст метки — токен --on-marker, а не литерал white: цвет цифры идёт в паре
   с цветом метки. */
.roster-month-day.today .roster-date-number { background: var(--marker); color: var(--on-marker); }
@media (max-width: 760px) { .roster-toolbar { align-items: stretch; } .roster-branch-picker { width: 100%; } .roster-period-nav { width: 100%; } .roster-month { grid-template-columns: repeat(7,minmax(150px,1fr)); } .roster-month-day { min-height: 96px; padding: 7px; } }

.card { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 16px 18px; box-shadow: var(--lift); }
.card-label { color: var(--muted); font-size: 13px; font-weight: 500; }
.card-value {
    font-size: 26px;
    /* 700 в Manrope на 26px даёт плотную, тяжёлую цифру: карточка кричит
       громче заголовка страницы. 650 держит вес числа, не перебивая её. */
    font-weight: 650;
    /* Крупные числа набираются плотнее: на кегле 26 стандартный трекинг
       разносит разряды и сумма распадается на цифры. */
    letter-spacing: -0.02em;
    /* Главное здесь. В карточках стоят деньги и счётчики, они обновляются
       по htmx каждую минуту, и без моноширинных знаков число дёргается
       по ширине при каждой подмене. */
    font-variant-numeric: tabular-nums;
    margin: 6px 0;
}
.card-sub { font-size: 13px; color: var(--muted); }
/* Сводка над рабочей таблицей — не отдельный дашборд. Показатели идут
   одной плотной полосой высотой с обычный контрол, чтобы таблица оставалась
   главным уровнем страницы. Модификатор ставится только на строки метрик,
   а содержательные карточки и дашборд сохраняют обычную высоту. */
.table-summary-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 18px;
}
.table-summary-cards .card {
    display: inline-flex;
    flex: 0 1 auto;
    align-items: center;
    gap: 9px;
    min-width: 0;
    max-width: 100%;
    height: var(--control-h);
    padding: 0 14px;
    border-radius: var(--radius-sm);
}
.table-summary-cards .card-label {
    flex: 0 0 auto;
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
}
.table-summary-cards .card-value {
    flex: 0 0 auto;
    margin: 0;
    font-size: 16px;
    line-height: 1;
    white-space: nowrap;
}
.table-summary-cards .card-sub {
    min-width: 0;
    overflow: hidden;
    color: var(--faint);
    font-size: 12.5px;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.table-summary-cards .card-sub::before {
    content: "·";
    margin-right: 8px;
    color: var(--border);
}
.table-summary-toolbar { margin-bottom: 12px; }
.table-summary-toolbar .table-summary-cards {
    flex: 1 1 auto;
    margin: 0;
}
.table-summary-toolbar > .hui-button { flex: 0 0 auto; margin-left: auto; }
.metric-deltas { display: flex; gap: 6px; flex-wrap: wrap; }
.metric-delta {
    display: inline-flex; align-items: center; min-height: 24px; padding: 3px 8px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--surface-2); color: var(--muted); font-size: 12px; font-weight: 600;
}
.metric-delta.up { color: var(--ok-ink); border-color: var(--ok-border); background: var(--ok-bg); }
.metric-delta.down { color: var(--danger); border-color: var(--danger-border); background: var(--danger-soft); }

/* Forms */
.form-card, .filterbar {
    background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-md);
    box-shadow: var(--lift);
}
.form-card { padding: 16px 18px; margin-bottom: 16px; }
/* Панель фильтров — не форма, а полоса инструментов над списком, и поля у неё
   ниже, чем у карточки формы. */
.filterbar { display: flex; gap: 12px; align-items: end; flex-wrap: wrap; padding: 12px 14px; margin-bottom: 14px; }
.filter-actions {
    /* Было flex: 1 0 100% — кнопки всегда уезжали на собственную строку во всю
       ширину, даже когда фильтров два и место оставалось. Из-за этого панель
       занимала два яруса там, где хватало одного. Теперь строка переносится
       по надобности, как любой другой элемент ряда. */
    flex: 0 0 auto;
    display: flex;
    gap: 10px;
    align-items: center;
    flex-wrap: wrap;
}
.filterbar-inline { flex-wrap: nowrap; }
.filterbar-inline > label { flex: 0 1 320px; min-width: 0; }
.filterbar-inline > label > select { width: 100%; }
.filterbar-inline > .filter-actions { flex: 0 0 auto; flex-wrap: nowrap; }
@media (max-width: 640px) {
    .filterbar-inline { flex-wrap: wrap; }
    .filterbar-inline > label { flex: 1 1 100%; }
}
.teacher-schedule-shell { min-height: 0; }
.teacher-schedule-toolbar .crm-schedule-toolbar-filters {
    grid-template-columns: repeat(2, minmax(170px, 1fr));
}
.teacher-schedule-submit {
    min-height: 34px;
    padding: 7px 14px;
    white-space: nowrap;
}
.teacher-schedule-card { cursor: default; }
.teacher-schedule-card:hover {
    filter: none;
    outline: none;
}
@media (max-width: 700px) {
    .teacher-schedule-toolbar .crm-schedule-toolbar-filters {
        grid-template-columns: 1fr;
    }
}
@media (max-width: 560px) {
    .teacher-schedule-submit { width: 100%; }
}
.form-row { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 10px; }
.form-row.wrap label { flex: 0 0 auto; min-width: 150px; }
.online-booking-fields > label,
.online-booking-fields :is(input, select) { max-width: 100%; }

/* Выбор цвета направления. Свободное поле hex заменено палитрой расписания:
   восемь образцов плюс «Авто». Образец берётся из --sched-N-bg, поэтому
   форма и доска не могут разъехаться. */
/* «Авто» рисуется диагональю, а не пустотой: пустой квадрат в ряду цветов
   читается как «белый», а не как «цвет назначит система». */
/* Подпись держит выбор доступным без наведения мышью и озвучивается
   скринридером; на экране её заменяет сам образец. */
.shift-form-section {
    padding: 12px;
    border: 1px solid var(--brand-border);
    border-radius: var(--radius-sm);
    background: var(--brand-tint);
}
/* Подпись поля — один вид на кабинет (решение владельца 25.09.2026): 12px,
   жирная, цветом текста. Голый <label> и .field-label макроса field() пишутся
   одинаково; было три вида — 13px обычная, 12px жирная и 13px жирная в окне
   «Нового клиента». Пояснение внутри подписи — обычным весом.
   Подпись группы полей, у которой нет своего <label>, — «Первый месяц» над
   парой «Год + Месяц», «Фильтры всей страницы» в «Метриках» — пишется этим же
   правилом; своих подписей у панелей фильтров «Аналитики» и шапок «Сводки» и
   обзора маркетинга больше нет. */
label, .month-filter-caption, .metrics-control-label { color: var(--ink); font-size: 12px; font-weight: 700; }
label { display: flex; flex-direction: column; gap: 4px; }
label :where(small, .muted, .hint, .field-hint, .form-hint, .field-help) { color: var(--muted); font-weight: 400; }
/* Галочка и переключатель — не подпись к полю, а сам выбор: текст обычный. */
label:where(.checkline, :has(input[type="checkbox"], input[type="radio"])) { font-size: 13px; font-weight: 400; }
label.wide { flex: 1 1 100%; }
label.checkline { flex-direction: row; align-items: center; color: var(--ink); min-width: auto; }
input, select, textarea {
    font-size: 15px; border: 1px solid var(--border);
    border-radius: var(--radius-sm); background: var(--card); color: var(--ink);
    font-family: inherit;
}
/* Отступ и ширина однострочного поля; у textarea они свои — ниже, с высотой. */
input, select { padding: 0 12px; min-width: 120px; }
/* Поиск — отдельная интерактивная поверхность. На серых панелях он остаётся
   белым; все модули меняют его одним
   токеном вместо локальных background. */
input[type="search"] { background: var(--search-bg); }
/* Высота однострочного контрола. Селекторы намеренно голые, без :not():
   select:not([multiple]) весит больше, чем класс, и продавил бы страничные
   варианты вроде .contract-editor-select с его собственными 34px. Исключения
   ниже перечислены отдельными правилами — каждое и так специфичнее голого
   элемента, а класс на странице по-прежнему выигрывает у обоих. */
input, select { height: var(--control-h); }
/* Считают высоту сами: у textarea её задаёт число строк, у select[multiple] —
   атрибут size, у галочки — её собственный размер, а у выбора файла внутри
   стоит кнопка браузера, которую фиксированная высота обрезает. */
textarea { height: auto; min-width: 100%; resize: vertical; line-height: 1.45; padding: 9px 12px; }
select[multiple] { height: auto; padding: 6px 8px; }
input[type="file"] { height: auto; padding: 8px 12px; }
input[type="checkbox"], input[type="radio"] { height: auto; min-width: auto; width: auto; padding: 0; }

/* ShadCN Attachment, перенесённый на Jinja/HTMX без React-зависимости.
   Сохраняем его состав Media + Content + Actions и состояния загрузки:
   https://ui.shadcn.com/docs/components/base/attachment */
.attachment {
    position: relative;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-width: 0;
    padding: 11px 12px;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card);
    color: var(--ink);
    font-size: 13px;
    transition: border-color var(--dur-fast) ease, background-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}
.attachment--picker { cursor: pointer; }
.attachment--picker:hover { border-color: var(--brand-border-strong); background: var(--surface-2); }
.attachment--picker:has(.attachment__input:focus-visible) {
    outline: var(--ring-w) solid var(--ring);
    outline-offset: var(--ring-offset);
}
.attachment .attachment__input {
    position: absolute;
    width: 1px;
    height: 1px;
    min-width: 0;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
.attachment__media {
    display: inline-flex;
    width: 38px;
    height: 38px;
    flex: 0 0 38px;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    background: var(--brand-tint);
    color: var(--brand-ink);
}
.attachment__media svg,
.attachment__action svg {
    width: 19px;
    height: 19px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.attachment__content { display: grid; flex: 1 1 auto; gap: 2px; min-width: 0; }
.attachment__title {
    min-width: 0;
    overflow: hidden;
    color: var(--ink);
    font-weight: 650;
    line-height: 1.35;
    text-overflow: ellipsis;
    white-space: nowrap;
}
a.attachment__title { color: var(--brand-ink); text-decoration: none; }
a.attachment__title:hover { text-decoration: underline; }
.attachment__description { min-width: 0; overflow: hidden; color: var(--muted); font-size: 12px; line-height: 1.4; text-overflow: ellipsis; white-space: nowrap; }
.attachment__actions { display: flex; flex: 0 0 auto; align-items: center; margin-left: auto; }
.attachment__actions form { margin: 0; }
.attachment__action { display: inline-flex; align-items: center; justify-content: center; color: var(--muted); }
.attachment__code { overflow: hidden; color: var(--muted); font-size: 11px; line-height: 1.4; text-overflow: ellipsis; white-space: nowrap; }
.attachment--sm { padding: 8px 9px; }
.attachment--sm .attachment__media { width: 32px; height: 32px; flex-basis: 32px; }
.attachment--sm .attachment__media svg { width: 17px; height: 17px; }
.attachment[data-state="done"] .attachment__media { background: var(--ok-bg); color: var(--ok-ink); }
.attachment[data-state="error"] { border-color: var(--danger-border); }
.attachment[data-state="error"] .attachment__media { background: var(--danger-soft); color: var(--danger); }
.attachment[data-state="uploading"] { border-color: var(--brand-border-strong); pointer-events: none; }
.attachment[data-state="uploading"]::after {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--brand), transparent);
    content: "";
    animation: attachment-upload 1.1s linear infinite;
    transform: translateX(-100%);
}
.attachment-group { display: grid; gap: 8px; }
.attachment-upload-form { display: grid; gap: 8px; }
.attachment-upload-form .actions { margin-top: 0; }
@keyframes attachment-upload { to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) { .attachment[data-state="uploading"]::after { animation: none; transform: none; } }

/* Подсказка внутри поля — не текст, а его отсутствие. Тоном --ink она читалась
   как уже введённое значение. opacity: 1 обязателен: Firefox приглушает
   плейсхолдер своей прозрачностью поверх цвета. */
input::placeholder, textarea::placeholder { color: var(--faint); opacity: 1; }

/* Своя стрелка вместо системной. Дело не в рисунке: ширину зоны под системной
   стрелкой задаёт ОС, и правое поле у списка выходило не таким, как у соседнего
   текстового поля в том же ряду. */
select {
    appearance: none;
    padding-right: 34px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%234e5952' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 11px center;
}
/* У списка с size стрелки нет вовсе, и место под неё не нужно. */
select[multiple] { appearance: auto; padding-right: 8px; background-image: none; }

input:disabled, select:disabled, textarea:disabled { background: var(--surface-2); color: var(--muted); }
/* Поле, помеченное недействительным без обёртки .field: у формы не всегда есть
   разметка поля, а сказать об ошибке она обязана. */
input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"] { border-color: var(--danger-border); }
label.checkline input[type="checkbox"] { min-width: auto; width: auto; padding: 0; }
/* Две колонки: обе проверки открытия встают в одну строку, четыре проверки
   закрытия — в две. На телефоне подписи не помещаются, там одна колонка. */
.shift-open-checks,
.shift-close-checks {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
    margin: 0 0 12px;
}
.shift-open-checks .checkline,
.shift-close-checks .checkline {
    min-height: 34px;
    padding: 7px 9px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
@media (max-width: 640px) {
    .shift-open-checks,
    .shift-close-checks { grid-template-columns: 1fr; }
}
.shift-attendance-warning {
    margin: 0 0 18px;
    padding: 14px 16px;
    border: 1px solid var(--warn-border);
    border-radius: var(--radius-sm);
    background: var(--warn-soft);
    color: var(--ink);
}
.shift-attendance-warning h2 { margin: 0 0 6px; color: var(--warn); }
.shift-attendance-warning p { margin: 0 0 8px; }
.shift-attendance-warning ul { margin: 0 0 12px; padding-left: 20px; }
.shift-attendance-warning li + li { margin-top: 4px; }
.shift-attendance-confirm {
    padding: 8px 10px;
    border: 1px solid var(--warn-border);
    border-radius: var(--radius-sm);
    background: var(--card);
    font-weight: 700;
}
.shift-close-form .form-card { margin-bottom: 12px; }
.shift-close-main-card > h3:first-of-type { margin-top: 0; }
.shift-close-checks-card > h3 { margin: 0 0 10px; }
.shift-close-checks-card .shift-close-checks { margin-bottom: 0; }
.shift-close-submit-card { display: grid; gap: 12px; }
.shift-close-submit-card .actions { margin-top: 0; }
.shift-alert-message { margin: 0 0 14px; color: var(--ink); font-weight: 600; }
.shift-alert-modal .modal-header { margin-bottom: 10px; }
.plain-fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
.plain-fieldset:disabled { opacity: 1; }
.actions { display: flex; gap: 10px; align-items: center; margin-top: 8px; }
/* Ряд действий выравнивается по месту, а не по вкусу автора формы: в окне —
   к правому краю, на странице — под колонкой полей. Раньше это решало
   переопределение в каждом окне, и два окна из одной карточки расходились. */
.modal-form > .actions { justify-content: flex-end; }
.modal {
    width: min(980px, calc(100vw - var(--dialog-gutter))); max-height: calc(100dvh - 48px);
    padding: 0; border: 0; border-radius: var(--radius-md);
    background: var(--card); color: var(--ink);
    box-shadow: var(--shadow);
}
/* Затемнение вынесено в токен: тот же цвет задавали три подложки — диалога,
   выдвижной карточки и поиска по разделам — тремя разными числами. */
.modal::backdrop { background: var(--scrim); backdrop-filter: blur(2px); }
.modal .form-card { margin: 0; border: 0; border-radius: 0; }
.modal-header {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    margin-bottom: 14px;
}
.modal-header h2 { margin: 0; color: var(--ink); }
/* Закрытие — не действие карточки, а выход из неё. Рамка и подложка делали
   из крестика полноценную кнопку, которая по весу спорила с заголовком
   диалога и с настоящей кнопкой сохранения внизу. Теперь он проявляется
   подложкой только под курсором. */
.modal-close {
    width: 32px; height: 32px; padding: 0; border: 1px solid transparent;
    border-radius: var(--radius-sm); background: transparent; color: var(--muted);
    font-size: 20px; line-height: 1; display: inline-flex; align-items: center;
    justify-content: center; flex: none;
}
.modal-close:hover { background: var(--surface-2); color: var(--ink); }
.modal-form, .expense-modal-form { max-height: calc(100dvh - 48px); overflow: auto; }
.client-balance-dialog-form { display: grid; gap: 14px; }
.client-balance-dialog-form .modal-header { margin-bottom: 0; }
.client-balance-dialog-form label { gap: 7px; }
.client-balance-cash-fields {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}
.client-balance-dialog-hint { margin: -6px 0 0; font-size: 12px; }
.client-balance-dialog-actions { margin-top: 0; }
.client-booking-form { display: grid; gap: 14px; }
.client-booking-form .modal-header { margin-bottom: 0; }
.client-booking-person {
    display: grid;
    gap: 3px;
    padding: 13px 14px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.client-booking-person span { color: var(--muted); font-size: 12px; font-weight: 600; }
.client-booking-person strong { color: var(--ink); font-size: 16px; font-weight: 650; }
.client-booking-person > .client-booking-person-branch {
    margin-top: 5px;
    padding-top: 8px;
    border-top: 1px solid var(--border);
    font-size: 13px;
}
.client-booking-filters {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}
.client-booking-filter-control { gap: 7px; min-width: 0; }
.client-booking-filter-control :is(input, select) { width: 100%; min-width: 0; }
.client-booking-picker { display: grid; gap: 14px; min-height: 0; }
.client-booking-options {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}
.client-booking-option-list {
    display: grid;
    max-height: min(52dvh, 560px);
    overflow-y: auto;
    overscroll-behavior: contain;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card);
}
.crm-schedule-card.client-booking-option {
    min-height: 84px;
    border-radius: 0;
    box-shadow: none;
    cursor: pointer;
}
.client-booking-option + .client-booking-option { border-top: 0; }
.client-booking-option:hover { z-index: 1; }
.client-booking-option:has(.client-booking-option-input:checked) {
    z-index: 2;
    background: color-mix(in srgb, var(--brand) 10%, var(--card));
    box-shadow: inset 0 0 0 2px var(--brand);
}
.client-booking-option:focus-within {
    z-index: 3;
    outline: 3px solid color-mix(in srgb, var(--brand) 42%, transparent);
    outline-offset: -3px;
}
.client-booking-option .crm-schedule-card-body { padding: 9px 12px; }
.client-booking-empty {
    margin: 0;
    padding: 28px 18px;
    color: var(--muted);
    font-size: 13px;
    text-align: center;
}
.client-booking-actions { margin-top: 0; }
@media (max-width: 640px) {
    .client-booking-filters { grid-template-columns: 1fr; }
    .client-booking-option-list { max-height: 48dvh; }
}

/* Запись с карточки занятия. Зеркало .client-booking-*: там известен клиент и
   выбирают занятие, здесь наоборот — занятие в шапке формы, а клиента ищут. */
.class-booking-form { display: grid; gap: 14px; }
.class-booking-form .modal-header { margin-bottom: 0; }
.class-booking-target, .class-cancel-target {
    display: grid;
    gap: 3px;
    padding: 13px 14px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.class-booking-target strong, .class-cancel-target strong { color: var(--ink); font-size: 16px; font-weight: 650; }
.class-booking-target span, .class-cancel-target span { color: var(--ink); font-size: 13px; font-variant-numeric: tabular-nums; }
.class-booking-target small { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.class-booking-actions { margin-top: 0; }
/* Окно «Отменить занятие»: занятие сверху, как в окне записи, под ним — что станет с записями. */
.class-cancel-form { display: grid; gap: 14px; }
.class-cancel-form > .actions { margin-top: 0; }
.class-cancel-form > p { margin: 0; }
.class-cancel-form select, .class-cancel-form input[type="text"] { width: 100%; }
.class-cancel-effects { display: grid; gap: 6px; margin: 0; padding-left: 18px; color: var(--ink); font-size: 14px; }
.class-cancel-effects .class-cancel-warning { color: var(--warn); font-weight: 600; }
/* Режимы «Клиент студии / Гость», тип записи и отказ, который можно снять. */
.class-booking-mode { border: 0; margin: 0; padding: 0; }
.class-booking-kind, .class-booking-guest { display: grid; gap: 6px; color: var(--muted); font-size: 13px; }
.class-booking-kind select, .class-booking-guest input { width: 100%; }
.inline-alert.class-booking-conflict { display: grid; gap: 4px; }
.class-booking-conflict span { color: var(--muted); font-size: 13px; }
.client-pass-sale-form { display: grid; gap: 14px; }
.client-pass-sale-form > label select,
.client-pass-sale-adjustments select,
.client-pass-sale-adjustments input { width: 100%; }
.client-pass-sale-adjustments {
    display: grid;
    gap: 9px;
    margin: 0;
    padding: 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.client-pass-sale-adjustments legend {
    padding: 0;
    color: var(--ink);
    font-size: 15px;
    font-weight: 700;
}
.client-pass-sale-adjustments-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}
.client-pass-sale-certificate-hint { margin: 0; font-size: 12px; line-height: 1.4; }
.client-pass-sale-section { display: grid; gap: 14px; }
.client-pass-sale-paid input { width: 100%; }
.client-pass-sale-activation {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: end;
    gap: 10px;
}
.client-pass-sale-activation label { min-width: 0; }
.client-pass-sale-activation select,
.client-pass-sale-activation input { width: 100%; min-width: 0; }
.client-pass-sale-form .payment-channel-group .radio-group__options {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
}
/* HeroUI v3 Radio + RadioGroup, adapted for native HTML/HTMX.
   Раскладка взята из базового примера RadioGroup: подпись группы, под ней
   пояснение, ниже вертикальный список. У пункта слева квадратный контрол со
   скруглением, справа подпись и пояснение под ней. Состояния React Aria
   отображены на нативные псевдоклассы input, цвета и фокус берутся из токенов
   кабинета. Лицензия: vendor/heroui-button-LICENSE.txt. */
.radio-group {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}
.radio-group__label {
    display: block;
    padding: 0;
    color: var(--ink);
    font-size: 14px;
    font-weight: 700;
    line-height: 1.35;
}
/* Отступы у трёх частей группы заданы полями, а не общим gap: fieldset рисует
   legend как подпись рамки, и в этой роли он не участвует в раскладке
   контейнера, то есть gap до него не доходит. */
.radio-group__description {
    margin: 4px 0 0;
    color: var(--muted);
    font-size: 13px;
    line-height: 1.4;
}
.radio-group__options {
    display: flex;
    min-width: 0;
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
    margin-top: 12px;
}
.radio-group[data-orientation="horizontal"] .radio-group__options {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 20px;
}
.radio {
    position: relative;
    display: block;
    max-width: 100%;
    min-width: 0;
    color: var(--ink);
    cursor: pointer;
    outline: none;
}
.radio__input {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
.radio__content {
    display: flex;
    min-width: 0;
    flex-direction: row;
    align-items: flex-start;
    gap: 10px;
    color: var(--ink);
    cursor: inherit;
    user-select: none;
}
.radio__control {
    position: relative;
    display: inline-flex;
    box-sizing: border-box;
    width: 20px;
    height: 20px;
    flex: 0 0 20px;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border);
    /* Квадрат со скруглением, а не круг: так контрол выглядит в HeroUI v3. */
    border-radius: 5px;
    background: var(--card);
    transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.radio__indicator {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}
/* Метка выбора — один элемент во всю площадь контрола: в покое он залит цветом
   самого контрола и потому не виден, при выборе сжимается до квадратика и
   перекрашивается. Одна анимация вместо появления и исчезновения. */
.radio__indicator::before {
    width: 100%;
    height: 100%;
    /* Радиус внутренней рамки контрола: в покое метка ложится на неё в точности,
       а при сжатии до 0.45 остаётся углом в 1.8px, то есть квадратом, а не точкой. */
    border-radius: 4px;
    background: var(--card);
    content: "";
    transform: scale(1);
    transition: transform var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.radio:hover .radio__control { border-color: var(--brand-border-strong); }
.radio:active .radio__control { transform: scale(.94); }
.radio:has(.radio__input:checked) .radio__control {
    border-color: var(--brand);
    background: var(--brand);
}
.radio:has(.radio__input:checked) .radio__indicator::before {
    background: var(--on-brand);
    transform: scale(.45);
}
.radio:has(.radio__input:focus-visible) .radio__control {
    outline: var(--ring-w) solid var(--ring);
    outline-offset: var(--ring-offset);
}
.radio:has(.radio__input:disabled) { opacity: .5; cursor: not-allowed; }
.radio__copy {
    display: grid;
    min-width: 0;
    gap: 2px;
}
.radio__label {
    color: var(--ink);
    font-size: 15px;
    font-weight: 600;
    /* Ровно высота контрола: первая строка подписи встаёт с ним вровень без
       подгонки отступом сверху. */
    line-height: 20px;
}
.radio__description {
    color: var(--muted);
    font-size: 13px;
    line-height: 1.4;
}
.client-pass-sale-actions { margin-top: 0; }
@media (max-width: 640px) {
    .client-pass-sale-adjustments-grid { grid-template-columns: 1fr; }
}

button { cursor: pointer; font-size: 15px; }
button.link {
    background: none; border: none; color: var(--brand-ink); padding: 0; text-decoration: underline;
    text-decoration-thickness: 1px; text-underline-offset: 2px;
    transition: color var(--dur) ease;
}
button.link:hover { text-decoration-thickness: 2px; }
.inline { display: inline; }

/* ---------- HeroUI v3: изолированный порт кнопки ----------
   Adapted from HeroUI v3 Button:
   https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/button.css

   Изменено для Мята.OS: Tailwind @apply раскрыт в обычный CSS, классы получили
   префикс hui-, контрольная точка сведена к принятой в кабинете шкале, цвета
   читаются из существующих токенов кабинета, а upstream
   rounded-3xl заменён на компактный радиус CRM. Все стандартные кнопки кабинета
   используют этот контракт; специализированные кнопки навигации и клиентский
   cp-btn остаются отдельными компонентами.
   Upstream license: /static/vendor/heroui-button-LICENSE.txt. */
.hui-button {
    --hui-button-bg: transparent;
    --hui-button-bg-hover: var(--hui-button-bg);
    --hui-button-bg-pressed: var(--hui-button-bg-hover);
    --hui-button-fg: currentColor;

    position: relative;
    isolation: isolate;
    display: inline-flex;
    width: fit-content;
    height: 40px;
    flex: 0 0 auto;
    transform-origin: center;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 0 16px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    outline: none;
    background-color: var(--hui-button-bg);
    color: var(--hui-button-fg);
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    line-height: 1;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transform: translateZ(0);
    will-change: transform;
    transition:
        transform 250ms var(--ease),
        background-color 100ms ease,
        border-color 100ms ease,
        box-shadow 100ms ease;
}
.hui-button:focus-visible,
.hui-button[data-focus-visible="true"] {
    outline: var(--ring-w) solid var(--ring);
    outline-offset: var(--ring-offset);
}
.hui-button:disabled,
.hui-button[aria-disabled="true"],
.hui-button.disabled {
    opacity: .5;
    cursor: not-allowed;
    pointer-events: none;
}
.hui-button[data-pending="true"] {
    opacity: .7;
    cursor: progress;
    pointer-events: none;
}
.hui-button:active,
.hui-button[data-pressed="true"] {
    background-color: var(--hui-button-bg-pressed);
    transform: scale(.97);
}
@media (hover: hover) {
    .hui-button:hover,
    .hui-button[data-hovered="true"] {
        background-color: var(--hui-button-bg-hover);
    }
}
.hui-button svg:not([data-slot="spinner"] svg, [data-slot="link-icon"] svg) {
    width: 20px;
    height: 20px;
    flex: 0 0 20px;
    margin: 2px -2px;
    align-self: center;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
    pointer-events: none;
}

/* HeroUI sizes: 40/36/44px on touch-first layouts and 36/32/40px from the
   cabinet's existing tablet breakpoint. */
.hui-button--sm { height: 32px; padding-inline: 11px; }
.hui-button--md { height: 36px; }
.hui-button--lg { height: 40px; font-size: 15px; }
.hui-button--sm:active,
.hui-button--sm[data-pressed="true"] { transform: scale(.98); }
.hui-button--lg:active,
.hui-button--lg[data-pressed="true"] { transform: scale(.96); }
.hui-button--sm svg:not([data-slot="spinner"] svg, [data-slot="link-icon"] svg) {
    width: 16px;
    height: 16px;
    flex-basis: 16px;
}
@media (min-width: 760px) {
    .hui-button,
    .hui-button--md { height: 36px; }
    .hui-button--sm { height: 32px; }
    .hui-button--lg { height: 40px; }
}
/* На сенсорном ресепшене размер цели важнее десктопной плотности. */
@media (pointer: coarse) {
    .hui-button,
    .hui-button--sm,
    .hui-button--md,
    .hui-button--lg { min-height: 44px; }
}

/* Варианты меняют только локальные переменные: геометрия и состояния остаются
   едиными, как в исходном компоненте HeroUI. */
.hui-button--primary {
    --hui-button-bg: var(--brand);
    --hui-button-bg-hover: var(--brand-hover);
    --hui-button-bg-pressed: var(--brand-hover);
    --hui-button-fg: var(--on-brand);
}
/* Мягкая акцентная: единственный вариант, который остаётся брендовым. */
.hui-button--secondary {
    --hui-button-bg: var(--brand-tint);
    --hui-button-bg-hover: var(--brand-strong);
    --hui-button-bg-pressed: var(--brand-strong);
    --hui-button-fg: var(--brand-ink);
}
/* Остальные нейтральны: ховер кнопки больше не выглядит выбранным пунктом
   меню, потому что это разные ступени. */
.hui-button--tertiary {
    --hui-button-bg: var(--surface-2);
    --hui-button-bg-hover: var(--hover);
    --hui-button-bg-pressed: var(--selected);
    --hui-button-fg: var(--ink);
}
.hui-button--ghost,
.hui-button--outline {
    --hui-button-bg: transparent;
    --hui-button-bg-hover: var(--hover);
    --hui-button-bg-pressed: var(--selected);
    --hui-button-fg: var(--ink);
}
.hui-button--outline { border-color: var(--border); }
.hui-button--danger {
    --hui-button-bg: var(--danger);
    --hui-button-bg-hover: color-mix(in srgb, var(--danger) 82%, var(--ink));
    --hui-button-bg-pressed: var(--hui-button-bg-hover);
    --hui-button-fg: var(--on-brand);
}
/* Корзина в строке списка — мягкий регистр опасного.

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

   Подтверждение в диалоге остаётся сплошным: там кнопка одна и она главная. */
.row-actions .hui-button--danger,
td.row-actions .hui-button--danger {
    --hui-button-bg: var(--danger-soft);
    --hui-button-bg-hover: color-mix(in srgb, var(--danger-soft) 70%, var(--danger));
    --hui-button-bg-pressed: var(--hui-button-bg-hover);
    --hui-button-fg: var(--err);
    border-color: var(--danger-border);
}

.hui-button--danger-soft {
    --hui-button-bg: var(--danger-soft);
    --hui-button-bg-hover: color-mix(in srgb, var(--danger-soft) 75%, var(--danger));
    --hui-button-bg-pressed: var(--hui-button-bg-hover);
    --hui-button-fg: var(--err);
}
/* Предупреждение, а не запрет: неявка — не ошибка администратора и не удаление,
   поэтому у неё свой тон между тёмной галочкой и красной отменой. */
.hui-button--warn {
    --hui-button-bg: var(--warn-soft);
    --hui-button-bg-hover: color-mix(in srgb, var(--warn-soft) 70%, var(--warn));
    --hui-button-bg-pressed: var(--hui-button-bg-hover);
    --hui-button-fg: var(--warn);
}

.hui-button--icon-only { width: 36px; padding: 0; }
.hui-button--danger.hui-button--icon-only svg {
    color: currentColor;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.hui-button--icon-only.hui-button--sm { width: 32px; }
.hui-button--icon-only.hui-button--lg { width: 40px; }
.hui-button--full-width { width: 100%; }

/* HeroUI v3 ButtonGroup, перенесённый на нативные кнопки Jinja/HTMX.
   Прямые дочерние кнопки образуют одну геометрию, а press-scale отключён,
   чтобы между сегментами группы не появлялась щель.
   Source: https://heroui.com/en/docs/react/components/button-group */
.button-group {
    position: relative;
    display: inline-flex;
    max-width: 100%;
    align-items: stretch;
    isolation: isolate;
}
.button-group > .hui-button { border-radius: 0; }
.button-group > .hui-button:first-of-type {
    border-top-left-radius: var(--radius-sm);
    border-bottom-left-radius: var(--radius-sm);
}
.button-group > .hui-button:last-of-type {
    border-top-right-radius: var(--radius-sm);
    border-bottom-right-radius: var(--radius-sm);
}
.button-group > .hui-button + .hui-button {
    border-left: 1px solid color-mix(in srgb, var(--brand-ink) 18%, transparent);
}
.button-group > .hui-button:focus-visible { z-index: 1; }
.button-group > .hui-button:active,
.button-group > .hui-button[data-pressed="true"] { transform: none; }
@media (min-width: 760px) {
    .hui-button--icon-only { width: 36px; }
    .hui-button--icon-only.hui-button--sm { width: 32px; }
    .hui-button--icon-only.hui-button--lg { width: 40px; }
}
@media (pointer: coarse) {
    .hui-button--icon-only,
    .hui-button--icon-only.hui-button--sm,
    .hui-button--icon-only.hui-button--lg { min-width: 44px; }
}
@media (prefers-reduced-motion: reduce) {
    .hui-button {
        transform: none;
        will-change: auto;
        transition: none;
    }
}

/* Tables */
.table-scroll { width: 100%; overflow-x: auto; }
/* Таблица шире экрана раньше просто ломала колонки: заголовок «Последний
   визит» вставал в четыре строки, и высота шапки прыгала от фильтра к фильтру.
   Минимальная ширина отдаёт такой случай горизонтальной прокрутке. */
.table-scroll > table.grid { min-width: var(--table-min); }
table.grid { width: 100%; border-collapse: collapse; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden; box-shadow: var(--lift); }
table.grid th, table.grid td { text-align: left; padding: 0 var(--cell-x); border-bottom: 1px solid var(--border); }
table.grid tbody td { height: var(--row-h); }
/* Ячейка с переносом текста не должна схлопывать высоту до одной строки:
   height на td работает как min-height, но только пока внутри одна строка. */
table.grid tbody td > * { vertical-align: middle; }
table.grid thead th { height: var(--head-h); font-size: 13px; color: var(--head-ink); font-weight: 500; letter-spacing: 0; text-transform: none; white-space: nowrap; }
/* Своя плоскость у шапки. Без неё заголовок остался без яруса: прозрачный
   фон, приглушённый тон и вес 500 — три приёма приглушения разом, и шапка
   читалась как ещё одна строка данных.

   Краска та же, что под наведённой строкой, но в полную силу против её
   половины (--row-hover). Поэтому нового цвета не появилось, а порядок веса
   стал правильным: постоянная структура заметнее временной подсветки. */
table.grid thead th { background: var(--card); }
table.grid thead tr:first-child th:first-child { border-top-left-radius: var(--radius-md); }
table.grid thead tr:first-child th:last-child { border-top-right-radius: var(--radius-md); }
/* Единственная линия под шапкой вместо заливки: заголовок отделяется от данных
   тоном подписи, а не второй плоскостью. */
table.grid thead th { border-bottom: 1px solid var(--border); }
table.grid tbody tr:last-child td { border-bottom: 0; }
table.grid td.num, table.grid th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Колонка в одну строку: дата, телефон, счётчик, кнопки действий. Ставится и
   на заголовок, и на ячейку — white-space не колоночное свойство, через th на
   всю колонку оно, в отличие от ширины, не распространяется. */
table.grid th.nowrap, table.grid td.nowrap { white-space: nowrap; }
/* Цифры моноширинными знаками не только в колонках .num: суммы и даты стоят и
   в обычных ячейках, а прыгающая ширина единицы ломает их вертикаль. */
table.grid { font-variant-numeric: tabular-nums; }
table.grid .strong { font-weight: 600; }
table.grid tr.warn { background: var(--warn-bg); }
table.grid tfoot td { font-weight: 600; background: var(--surface-2); height: var(--row-h-sm); }
/* Плотный режим для таблиц внутри панелей и выдвижных карточек, где на экран
   должно поместиться больше строк, чем на отдельной странице списка. Имя
   .compact-grid уже занято этим смыслом в карточке занятия и истории клиента,
   поэтому здесь оно и переопределяется, а не заводится второе. */
table.grid.compact-grid tbody td { height: var(--row-h-sm); }
table.grid.compact-grid thead th { height: var(--row-h-sm); }
/* Several grids run past 1300px wide, so the eye loses its place halfway
   through a horizontal scroll. Highlighting the hovered row fixes that. */
table.grid tbody tr { transition: background var(--dur-fast) ease; }
table.grid tbody tr:hover { background: var(--row-hover); }
table.grid tbody tr.warn:hover { background: var(--warn-soft); }
table.grid tbody tr:focus-within { background: var(--row-hover); }
/* Выделенная строка обязана быть заметнее наведённой, иначе состояние тонет в
   курсоре. Отсюда полновесная зелёная подложка против полупрозрачной. */
table.grid tbody tr[aria-selected="true"] { background: var(--row-selected); }

table.grid th.expense-category-pnl-column,
table.grid td.expense-category-pnl-cell {
    width: 1%;
    text-align: center;
    white-space: nowrap;
}
.expense-category-pnl-cell input[type="checkbox"] {
    width: 18px;
    height: 18px;
    margin: 0;
    vertical-align: middle;
    accent-color: var(--brand);
    opacity: 1;
    cursor: default;
}

.teacher-payroll-lines-wrap {
    margin-bottom: 24px;
}
.payroll-header-actions,
.teacher-payroll-header-actions {
    margin-top: 0;
    margin-left: auto;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
}
.payroll-finalize-form,
.teacher-payroll-finalize-form {
    margin: 0;
}
.payroll-finalize-form .hui-button--primary,
.teacher-payroll-finalize-form .hui-button--primary {
    white-space: nowrap;
}
.payroll-premium-section {
    width: 100%;
    margin-top: 24px;
}
.payroll-premium-section > summary { cursor: pointer; padding-block: 12px; font-weight: 600; }
.payroll-premium-section > .muted { margin-top: 0; }
.payroll-results { min-width: 0; }
.payroll-results.htmx-request { cursor: progress; opacity: .62; }
.table-scroll > table.grid.payroll-table {
    width: auto;
    min-width: 0;
    table-layout: auto;
    margin-inline: 0 auto;
}
.payroll-bonus-eligibility-col,
.payroll-bonus-eligibility-cell {
    text-align: center;
}
.premium-cell {
    display: grid; justify-items: end; gap: 5px;
    white-space: nowrap;
}
.premium-cell__amount { display: flex; align-items: baseline; justify-content: flex-end; gap: 4px; }
.premium-value { font-weight: 500; }
.payroll-bonus-toggle-form { display: flex; align-items: center; justify-content: center; gap: 6px; margin: 0; }
.payroll-bonus-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 34px; min-height: 28px; cursor: pointer;
}
.payroll-bonus-toggle__control { position: relative; display: inline-flex; flex: 0 0 auto; width: 34px; height: 20px; }
.payroll-bonus-toggle__control input {
    position: absolute; inset: 0; z-index: 1; width: 100%; min-width: 0; height: 100%;
    margin: 0; padding: 0; opacity: 0; cursor: pointer;
}
.payroll-bonus-toggle__control > span {
    width: 100%; border: 1px solid var(--border); border-radius: 999px; background: var(--surface-2);
    transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.payroll-bonus-toggle__control > span::after {
    content: ""; position: absolute; top: 3px; left: 3px; width: 12px; height: 12px;
    border-radius: 50%; background: var(--muted);
    transition: transform var(--dur) var(--ease), background var(--dur) var(--ease);
}
.payroll-bonus-toggle__control input:checked + span { border-color: var(--brand); background: var(--brand); }
.payroll-bonus-toggle__control input:checked + span::after { background: var(--on-brand); transform: translateX(14px); }
.payroll-bonus-toggle__control input:focus-visible + span { outline: 2px solid var(--brand); outline-offset: 2px; }
.payroll-bonus-toggle__fallback { display: none; }
.payroll-bonus-toggle-form.is-submitting { pointer-events: none; opacity: .62; }
.payroll-bonus-state { color: var(--muted); font-size: 11px; }
.premium-breakdown { margin: 0; text-align: left; font-weight: 400; }
.premium-breakdown__trigger,
.payroll-adjustment-details__trigger {
    min-height: 28px; padding: 0 2px; border: 0;
    background: transparent; color: var(--brand-ink);
    font: inherit; font-size: 11.5px; font-weight: 700; line-height: 1;
    text-decoration: underline dotted; text-underline-offset: 3px;
    white-space: nowrap; cursor: pointer;
}
.premium-breakdown__trigger:hover,
.payroll-adjustment-details__trigger:hover { color: var(--ink); }
.premium-breakdown__trigger:focus-visible,
.payroll-adjustment-details__trigger:focus-visible {
    outline: var(--ring-w) solid var(--ring); outline-offset: var(--ring-offset);
    border-radius: var(--radius-sm);
}
.premium-breakdown__content {
    min-width: min(340px, calc(100vw - 24px));
    text-align: left; white-space: normal;
}
.premium-breakdown__summary {
    margin: 0 0 10px; color: var(--muted); font-size: 12px; line-height: 1.4;
    font-variant-numeric: tabular-nums;
}
.premium-breakdown__summary > span { display: block; }
.premium-breakdown__summary-total { color: var(--ink); font-weight: 600; }
.premium-breakdown__list {
    display: grid; gap: 9px; margin: 0; padding: 0; list-style: none;
    color: var(--muted); font-size: 12px; line-height: 1.4;
    font-variant-numeric: tabular-nums;
}
.premium-breakdown__list li { display: grid; gap: 2px; }
.premium-breakdown__label { color: var(--ink); font-weight: 600; }
@media (pointer: coarse) {
    .premium-breakdown__trigger,
    .payroll-adjustment-details__trigger { min-height: 44px; }
}
.payroll-adjustment-form,
.teacher-payroll-adjustment-form {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 12px;
    align-items: end;
    margin-bottom: 18px;
}
.payroll-adjustment-form label,
.teacher-payroll-adjustment-form label {
    min-width: 0;
}
.payroll-adjustment-form input,
.payroll-adjustment-form select,
.teacher-payroll-adjustment-form input,
.teacher-payroll-adjustment-form select {
    width: 100%;
    min-width: 0;
}
.payroll-adjustment-form .hui-button,
.teacher-payroll-adjustment-form .hui-button {
    width: 100%;
    text-align: center;
    white-space: normal;
}
.teacher-payroll-adjustment-modal h3 {
    margin: 0 0 10px;
    color: var(--muted);
}

@media (max-width: 1180px) {
    .payroll-header-actions,
    .teacher-payroll-header-actions {
        flex-basis: 100%;
    }
}

@media (max-width: 700px) {
    .payroll-header-actions .hui-button,
    .payroll-finalize-form,
    .payroll-finalize-form .hui-button--primary,
    .teacher-payroll-header-actions .hui-button,
    .teacher-payroll-finalize-form,
    .teacher-payroll-finalize-form .hui-button--primary {
        width: 100%;
    }
    .payroll-adjustment-form,
    .teacher-payroll-adjustment-form {
        grid-template-columns: 1fr;
    }
}

/* Weekly schedule grid: fixed layout so columns line up across every day. */
.schedule-grid { table-layout: fixed; }
.schedule-grid td { overflow-wrap: anywhere; }
.schedule-grid tr.daysep td {
    background: var(--surface-2);
    font-weight: 700;
    color: var(--ink);
    text-transform: none;
    letter-spacing: 0;
}

/* CRM schedule board */
.crm-schedule-shell {
    min-height: calc(100dvh - 96px);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
}
.crm-schedule-toolbar {
    display: grid;
    grid-template-columns: minmax(230px, 0.8fr) minmax(390px, 1.5fr) max-content;
    grid-template-areas: "period filters actions";
    align-items: end;
    gap: 10px 18px;
    padding: 12px;
    border-bottom: 1px solid var(--border);
    background: var(--card);
}
.crm-schedule-toolbar-main {
    display: contents;
}
.crm-schedule-toolbar-actions {
    grid-area: actions;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 12px;
    min-width: 0;
}
.crm-schedule-toolbar-filters {
    grid-area: filters;
    display: grid;
    /* Средняя колонка — input[type=week]. Его содержимое рисует браузер, и
       «Неделя 35, 2026» вместе с кнопкой календаря требует ~165px: на 135px
       год обрезался посреди строки. Ширина взята по самому длинному варианту
       («Неделя 35, 2026»), а не по текущему экрану. */
    grid-template-columns: minmax(120px, 0.85fr) minmax(168px, 0.8fr) minmax(170px, 1.25fr);
    gap: 10px;
    align-items: end;
    min-width: 0;
}
.crm-schedule-period {
    grid-area: period;
    display: grid;
    grid-template-columns: 30px max-content 30px;
    align-items: center;
    gap: 10px;
    width: max-content;
    min-height: 34px;
}
.crm-schedule-arrow {
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    color: var(--muted);
    text-decoration: none;
    font-size: 26px;
    font-weight: 700;
    line-height: 1;
}
/* Стрелка периода и подпись периода — навигация, а не сообщение. Раньше
   обе брали --info, то есть тратили сигнальный синий на «где я», а в
   шаблонах расписания та же подпись была зелёной. */
.crm-schedule-arrow:hover { background: var(--hover); }
.crm-schedule-caption {
    min-width: 0;
    color: var(--ink);
    font-size: 18px;
    font-weight: 800;
    letter-spacing: 0;
    white-space: nowrap;
}
.crm-schedule-control {
    min-width: 0;
    gap: 2px;
}
.crm-schedule-control input,
.crm-schedule-control select {
    min-width: 0;
    width: 100%;
    height: 34px;
    padding: 5px 9px;
    border-radius: 3px;
    font-size: 14px;
}
.crm-schedule-new {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    height: 34px;
    padding: 7px 14px;
    line-height: 1;
    white-space: nowrap;
}
.crm-schedule-modes {
    display: flex;
    align-items: stretch;
    gap: 12px;
    height: 34px;
}
.crm-schedule-modes a {
    display: inline-flex;
    align-items: center;
    padding: 0 2px;
    border-bottom: 4px solid transparent;
    color: var(--muted);
    text-decoration: none;
    font-size: 13px;
    font-weight: 700;
}
/* Подчёркивание активной вкладки — «вы здесь», а не ошибка. Здесь стоял
   --danger, то есть красная черта под нормальным состоянием экрана. */
.crm-schedule-modes a.active {
    border-color: var(--brand);
    color: var(--ink);
}
@media (max-width: 980px) {
    .crm-schedule-toolbar {
        grid-template-columns: minmax(0, 1fr) max-content;
        grid-template-areas:
            "period actions"
            "filters filters";
    }
    .crm-schedule-toolbar-filters {
        grid-template-columns: repeat(3, minmax(150px, 1fr));
    }
}
@media (max-width: 700px) {
    .crm-schedule-toolbar {
        grid-template-columns: 1fr;
        grid-template-areas:
            "period"
            "filters"
            "actions";
    }
    .crm-schedule-toolbar-actions {
        width: 100%;
        justify-content: space-between;
    }
    .crm-schedule-toolbar-filters {
        grid-template-columns: repeat(2, minmax(150px, 1fr));
    }
    .crm-schedule-toolbar-filters .crm-schedule-control:last-child {
        grid-column: 1 / -1;
    }
}
@media (max-width: 560px) {
    .crm-schedule-toolbar-actions {
        align-items: stretch;
        flex-direction: column;
    }
    .crm-schedule-toolbar-filters {
        grid-template-columns: 1fr;
    }
    .crm-schedule-toolbar-filters .crm-schedule-control:last-child {
        grid-column: auto;
    }
    .crm-schedule-caption {
        font-size: 16px;
        text-align: center;
    }
    .crm-schedule-new { width: 100%; }
}
.crm-schedule-board {
    width: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    background: var(--card);
}
.crm-schedule-day-head,
.crm-schedule-day-row {
    display: grid;
    grid-template-columns: 92px minmax(720px, 1fr);
}
.crm-schedule-day-head {
    position: sticky;
    top: 0;
    z-index: var(--z-raised);
    min-width: 880px;
    border-bottom: 1px solid var(--border);
    background: var(--card);
    color: var(--ink);
    font-size: 13px;
    font-weight: 800;
}
.crm-schedule-day-head > div {
    padding: 8px 12px;
    text-align: center;
}
.crm-schedule-day-row {
    min-width: 880px;
    min-height: 126px;
    border-bottom: 1px solid var(--border);
}
.crm-schedule-time-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 10px 8px;
    border-right: 1px solid var(--border);
    color: var(--ink);
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    background: var(--card);
}
.crm-schedule-day-events {
    display: grid;
    gap: 2px;
    padding: 0;
    background: var(--card);
}
.crm-schedule-week-grid { min-width: 1260px; }
.crm-schedule-week-head,
.crm-schedule-week-row {
    display: grid;
    grid-template-columns: 92px repeat(7, minmax(160px, 1fr));
}
.crm-schedule-week-head {
    position: sticky;
    top: 0;
    z-index: var(--z-raised);
    background: var(--card);
    border-bottom: 1px solid var(--border);
}
.crm-schedule-week-time-head,
.crm-schedule-week-day {
    min-height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px;
    border-right: 1px solid var(--border);
    font-size: 12.5px;
    font-weight: 600;
}
/* Два разных вопроса, два разных канала.

   «Выбрано» — про намерение человека, оно меняется по клику и должно быть
   тихим: заливка на ступень --selected. «Сегодня» — про факт, он не зависит
   от кликов и запрашивается за смену десятки раз: плотная метка с вывернутым
   текстом. Раньше выбранный день отличался только тоном текста — var(--brand-ink)
   против var(--ink), — и после перекраски эти два тона стали соседними
   графитовыми: колонка переставала быть видимой вовсе. «Сегодня» же на доске
   не было и до перекраски.

   Каналы намеренно разные, поэтому день, который одновременно сегодняшний и
   выбранный, читается как оба: плотная шапка и тихая заливка не спорят. */
.crm-schedule-week-day.selected { background: var(--selected); }
.crm-schedule-week-day.today { background: var(--marker); color: var(--on-marker); }
/* Обе метки сразу: заливка занята фактом, поэтому намерение показывает кольцо
   внутри неё. Без этого правила «сегодня» просто перекрыло бы «выбрано» по
   порядку источника, и в самый частый день недели селекция пропадала бы. */
.crm-schedule-week-day.today.selected { box-shadow: inset 0 0 0 2px var(--selected); }
/* Колонку целиком не подсвечиваем. Пробовали рельсы inset-тенью по краям
   ячейки — карточка занятия заливает ячейку без отступов и закрывает тень
   собой, а на пустых ячейках со штриховкой рельсы проступают. Метка выходила
   через раз. Шапка недели липкая (position: sticky выше), поэтому плотный
   заголовок виден на любой глубине прокрутки и отвечает на вопрос сам. */
.crm-schedule-week-row {
    min-height: 108px;
    border-bottom: 1px solid var(--border);
}
.crm-schedule-week-cell {
    display: grid;
    gap: 4px;
    min-height: 108px;
    padding: 4px;
    border-right: 1px solid var(--border);
    background: var(--bg);
}
.crm-schedule-week-cell.empty {
    background-image: none;
}

/* The staff board is a calendar, not a list of unique start times. One minute
   has one stable vertical measure; exact starts therefore stay close, while
   readable event hit areas move into parallel lanes when they would collide. */
.crm-schedule-timeline {
    --timeline-minute: 1.4px;
    --timeline-axis-width: 76px;
    --timeline-event-min-height: 44px;

    width: 100%;
    background: var(--card);
}
.crm-schedule-timeline--day { min-width: 880px; }
.crm-schedule-timeline--week { min-width: 1260px; }
.crm-schedule-timeline-head,
.crm-schedule-timeline-untimed,
.crm-schedule-timeline-body {
    display: grid;
    grid-template-columns: var(--timeline-axis-width) minmax(0, 1fr);
}
.crm-schedule-timeline-head {
    position: sticky;
    top: 0;
    z-index: var(--z-raised);
    border-bottom: 1px solid var(--border);
    background: var(--card);
}
.crm-schedule-timeline-corner,
.crm-schedule-timeline-untimed-label {
    position: sticky;
    left: 0;
    z-index: 3;
    display: flex;
    justify-content: center;
    padding: 8px;
    border-right: 1px solid var(--border);
    background: var(--card);
    font-size: 12px;
    font-weight: 700;
}
.crm-schedule-timeline-corner {
    align-items: center;
    min-height: 48px;
    color: var(--ink);
}
.crm-schedule-timeline-untimed-label {
    align-items: flex-start;
    min-height: 72px;
    padding-top: 12px;
    color: var(--muted);
    text-align: center;
}
.crm-schedule-timeline-day-heads,
.crm-schedule-timeline-days,
.crm-schedule-timeline-untimed-days {
    display: grid;
    min-width: 0;
}
.crm-schedule-timeline--day .crm-schedule-timeline-day-heads,
.crm-schedule-timeline--day .crm-schedule-timeline-days,
.crm-schedule-timeline--day .crm-schedule-timeline-untimed-days {
    grid-template-columns: minmax(720px, 1fr);
}
.crm-schedule-timeline--week .crm-schedule-timeline-day-heads,
.crm-schedule-timeline--week .crm-schedule-timeline-days,
.crm-schedule-timeline--week .crm-schedule-timeline-untimed-days {
    grid-template-columns: repeat(7, minmax(160px, 1fr));
}
.crm-schedule-timeline .crm-schedule-week-day {
    min-height: 48px;
    flex-direction: column;
    gap: 1px;
    line-height: 1.2;
}
.crm-schedule-timeline .crm-schedule-week-day small {
    color: inherit;
    font-size: 10.5px;
    font-weight: 500;
    opacity: .75;
}
.crm-schedule-timeline-untimed {
    border-bottom: 1px solid var(--border);
    background: var(--surface-2);
}
.crm-schedule-timeline-untimed-day {
    display: grid;
    align-content: start;
    gap: 4px;
    min-width: 0;
    min-height: 72px;
    padding: 4px;
    border-right: 1px solid var(--border);
}
.crm-schedule-timeline-untimed-day .crm-schedule-card { min-height: 64px; }
.crm-schedule-timeline-body { position: relative; }
.crm-schedule-timeline-axis,
.crm-schedule-timeline-day {
    height: calc(var(--timeline-duration) * var(--timeline-minute));
    min-height: 84px;
}
.crm-schedule-timeline-day { position: relative; }
.crm-schedule-timeline-axis {
    position: sticky;
    left: 0;
    z-index: 3;
    border-right: 1px solid var(--border);
    background: var(--card);
    font-variant-numeric: tabular-nums;
}
.crm-schedule-timeline-marker,
.crm-schedule-timeline-line {
    position: absolute;
    top: calc(var(--marker-offset) * var(--timeline-minute));
}
.crm-schedule-timeline-marker {
    right: 0;
    width: 100%;
    padding-right: 10px;
    color: var(--muted);
    font-size: 11px;
    font-weight: 650;
    line-height: 1;
    text-align: right;
    transform: translateY(-50%);
}
.crm-schedule-timeline-marker.is-first { transform: none; }
.crm-schedule-timeline-marker.is-last { transform: translateY(-100%); }
.crm-schedule-timeline-day {
    min-width: 0;
    border-right: 1px solid var(--border);
    background-color: var(--bg);
    background-image: linear-gradient(
        to bottom,
        transparent calc(100% - 1px),
        color-mix(in srgb, var(--border) 55%, transparent) calc(100% - 1px)
    );
    background-size: 100% calc(30 * var(--timeline-minute));
}
.crm-schedule-timeline-day.selected {
    background-color: color-mix(in srgb, var(--selected) 35%, var(--bg));
}
.crm-schedule-timeline-line {
    left: 0;
    z-index: 0;
    width: 100%;
    border-top: 1px solid var(--border);
    pointer-events: none;
}
.crm-schedule-timeline-line.is-first { border-top-color: transparent; }
.crm-schedule-timeline-line.is-last { border-top-color: var(--border); }

.crm-schedule-timeline-day > .crm-schedule-timeline-event {
    position: absolute;
    top: calc(var(--event-start) * var(--timeline-minute));
    left: calc((100% / var(--event-lanes)) * var(--event-lane) + 2px);
    z-index: 1;
    width: calc((100% / var(--event-lanes)) - 4px);
    height: max(
        calc(var(--event-duration) * var(--timeline-minute)),
        var(--timeline-event-min-height)
    );
    min-height: 0;
}
.crm-schedule-timeline-event:hover,
.crm-schedule-timeline-event:focus-visible { z-index: 4; }
.crm-schedule-timeline-event .crm-schedule-card-body {
    gap: 2px;
    padding: 6px 8px;
}
.crm-schedule-timeline-event .crm-schedule-meta {
    display: flex;
    max-width: 100%;
    gap: 4px;
    white-space: nowrap;
}
.crm-schedule-timeline-event .crm-schedule-name {
    display: -webkit-box;
    overflow: hidden;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
}
.crm-schedule-timeline-event .crm-schedule-teacher {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.crm-schedule-timeline-event :is(.crm-schedule-full-status) {
    position: absolute;
    top: 4px;
    right: 4px;
    z-index: 2;
    min-height: 18px;
    padding: 2px 5px;
    border: 0;
    border-radius: 4px;
    font-size: 8.5px;
    line-height: 1;
}
.crm-schedule-timeline-event.is-full .crm-schedule-time { padding-right: 48px; }
.crm-schedule-timeline-event.is-short .crm-schedule-meta,
.crm-schedule-timeline-event.is-short .crm-schedule-teacher,
.crm-schedule-timeline-event.is-narrow .crm-schedule-meta,
.crm-schedule-timeline-event.is-narrow .crm-schedule-teacher {
    display: none;
}
.crm-schedule-timeline-event.is-short .crm-schedule-card-body {
    justify-content: center;
    padding-block: 4px;
}
.crm-schedule-timeline-event.is-short .crm-schedule-name,
.crm-schedule-timeline-event.is-narrow .crm-schedule-name {
    -webkit-line-clamp: 1;
}
.crm-schedule-timeline-event.is-narrow .crm-schedule-time {
    gap: 2px;
    font-size: 10.5px;
}
.crm-schedule-timeline-event.is-narrow .crm-schedule-time-separator,
.crm-schedule-timeline-event.is-narrow .crm-schedule-time span:last-child {
    display: none;
}
.crm-schedule-timeline-event.is-narrow :is(.crm-schedule-full-status) {
    width: 8px;
    padding: 0;
    color: transparent;
}
/* Тон направления и светлота темы — разные вещи.

   Цвет направления приходит из базы одним hex и про тему ничего не знает.
   Пока он красил карточку целиком, светлота карточки была светлотой этого
   hex: тёмно-зелёное направление давало тёмную карточку, на которой серое
   время и подпись преподавателя не читались вовсе. Разметка пыталась
   спасти положение переменной --schedule-text, посчитанной на сервере, но её
   наследовал только заголовок: у времени, счётчиков и преподавателя цвет
   задан правилом и наследование перебивал.

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

   Первая строка каждой пары — запас для браузеров без относительного синтаксиса
   цвета: подмес в 14% даёт те же 4,6:1 на любом тоне, только тон видно слабее. */
.crm-schedule-card {
    --schedule-tone: var(--border);
    --schedule-fill-l: .965;
    --schedule-rail-l: .52;

    position: relative;
    display: flex;
    flex-direction: column;
    min-height: 100px;
    border: 1px solid var(--border);
    border-left-width: 3px;
    border-radius: var(--radius-sm);
    box-shadow: var(--lift);
    background: color-mix(in oklab, var(--schedule-tone) 14%, var(--card));
    background: oklch(from var(--schedule-tone) var(--schedule-fill-l) calc(c * .55) h);
    border-left-color: color-mix(in oklab, var(--schedule-tone) 58%, var(--ink));
    border-left-color: oklch(from var(--schedule-tone) var(--schedule-rail-l) calc(c * 1.25) h);
    color: var(--ink);
    text-decoration: none;
    overflow: hidden;
}
/* Та же формула, другие две константы: заливка уходит вглубь, рельс — в свет. */
.crm-schedule-card.compact { min-height: 96px; }
.crm-schedule-card:hover {
    filter: brightness(.98);
    outline: 2px solid color-mix(in srgb, var(--brand) 25%, transparent);
    outline-offset: -2px;
}
.crm-schedule-room {
    min-height: 20px;
    padding: 3px 8px;
    background: var(--shade);
    font-size: 11px;
    font-weight: 800;
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.crm-schedule-card-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 2px;
    padding: 8px 10px;
    text-align: left;
}
.crm-schedule-time {
    display: flex;
    align-items: baseline;
    justify-content: flex-start;
    gap: 5px;
    /* Время было 28px — крупнее заголовка страницы. Первым в карточке должно
       читаться название занятия, а час — подписью к нему. */
    font-size: 13px;
    line-height: 1;
    font-weight: 600;
    color: var(--muted);
    white-space: nowrap;
}
.crm-schedule-card.compact .crm-schedule-time {
    font-size: 13px;
    line-height: 1;
}
.crm-schedule-time-separator {
    font-size: .72em;
    font-weight: 600;
}
.crm-schedule-name {
    max-width: 100%;
    font-size: 13.5px;
    line-height: 1.25;
    font-weight: 600;
    letter-spacing: -.01em;
    overflow-wrap: anywhere;
}
.crm-schedule-card.compact .crm-schedule-name { font-size: 13.5px; }
.crm-schedule-meta {
    font-size: 11.5px;
    line-height: 1.2;
    font-weight: 400;
    color: var(--muted);
}
.crm-schedule-teacher {
    margin-top: 3px;
    font-size: 11.5px;
    line-height: 1.2;
    font-weight: 500;
    color: var(--muted);
}
.crm-schedule-color-1 { --schedule-tone: var(--sched-1-bg); color: var(--sched-1-ink); }
.crm-schedule-color-2 { --schedule-tone: var(--sched-2-bg); color: var(--sched-2-ink); }
.crm-schedule-color-3 { --schedule-tone: var(--sched-3-bg); color: var(--sched-3-ink); }
.crm-schedule-color-4 { --schedule-tone: var(--sched-4-bg); color: var(--sched-4-ink); }
.crm-schedule-color-5 { --schedule-tone: var(--sched-5-bg); color: var(--sched-5-ink); }
.crm-schedule-color-6 { --schedule-tone: var(--sched-6-bg); color: var(--sched-6-ink); }
.crm-schedule-color-7 { --schedule-tone: var(--sched-7-bg); color: var(--sched-7-ink); }
.crm-schedule-color-8 { --schedule-tone: var(--sched-8-bg); color: var(--sched-8-ink); }

.crm-schedule-card.is-cancelled {
    opacity: .58;
    text-decoration: line-through;
}
.crm-schedule-card.is-full {
    box-shadow: inset 0 0 0 2px var(--danger);
}
/* Мероприятие на доске — «магическая» плашка, как в виджете расписания: среди
   пастельных занятий её видно сразу. Цвета свои, а не тон направления: у
   мероприятия направления нет, и плашка одинакова во всех схемах кабинета. */
.crm-schedule-card.crm-schedule-card--event {
    border-color: color-mix(in srgb, var(--event-magic-gold) 50%, transparent);
    border-left-color: var(--event-magic-gold);
    background:
        radial-gradient(120% 90% at 100% 0%, var(--event-magic-glow), transparent 58%),
        linear-gradient(140deg, var(--event-magic-from), var(--event-magic-via) 58%, var(--event-magic-to));
    color: var(--event-magic-ink);
    box-shadow: var(--event-magic-shadow);
}
.crm-schedule-card--event .crm-schedule-name { color: var(--event-magic-ink); }
.crm-schedule-card--event .crm-schedule-time,
.crm-schedule-card--event .crm-schedule-meta,
.crm-schedule-card--event .crm-schedule-teacher { color: var(--event-magic-muted-ink); }
.crm-schedule-card--event .crm-schedule-meta.crm-schedule-event-label {
    display: inline-flex; align-items: center; gap: 4px;
    color: var(--event-magic-gold); font-weight: 700;
}
.crm-schedule-card.crm-schedule-card--event:hover {
    filter: brightness(1.07);
    outline-color: color-mix(in srgb, var(--event-magic-gold) 55%, transparent);
}
.crm-schedule-card.crm-schedule-card--event.is-full {
    box-shadow: inset 0 0 0 2px var(--event-magic-full-ring), var(--event-magic-shadow);
}
.crm-schedule-full-status {
    position: relative;
    z-index: 1;
    flex: 0 0 auto;
    min-height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4px 8px;
    border-bottom: 2px solid var(--card);
    background-color: var(--danger);
    background-image: repeating-linear-gradient(
        -45deg,
        var(--shade-stripe) 0,
        var(--shade-stripe) 7px,
        transparent 7px,
        transparent 14px
    );
    color: var(--card);
    font-size: 11px;
    font-weight: 900;
    letter-spacing: .08em;
    text-align: center;
    text-transform: uppercase;
}
.crm-schedule-card.compact .crm-schedule-full-status { min-height: 23px; padding: 3px 6px; font-size: 10px; }
.crm-schedule-empty {
    min-height: 260px;
    display: grid;
    place-content: center;
    justify-items: center;
    gap: 6px;
    padding: 26px 20px;
    color: var(--muted);
    text-align: center;
    line-height: 1.5;
    text-wrap: pretty;
}
.row-actions { display: flex; gap: 12px; align-items: center; flex-wrap: nowrap; white-space: nowrap; }
.row-actions .hui-button { flex: 0 0 auto; }
/* Кнопки строки не переносятся на вторую строку. Раньше это задавала последняя
   колонка каждой таблицы через th:nth-child со своим номером — шесть правил,
   каждое считало колонки заново. Класс на ячейке уже был, номер не нужен. */
table.grid td.row-actions { display: table-cell; vertical-align: middle; white-space: nowrap; }
table.grid td.row-actions > * + * { margin-left: 8px; }
table.grid td.row-actions > .inline { display: inline-block; vertical-align: middle; }
table.grid td.row-actions > .hui-button { vertical-align: middle; }
.expenses-container .form-card, .expenses-container .table-scroll { box-sizing: border-box; width: 100%; }
/* The expense editor shares one layout for creation, editing and the full page. */
.expense-modal { padding: 0; }
.expense-modal .expense-modal-form { margin: 0; padding: 0; border: 0; border-radius: 0; }
.expense-modal-form .modal-header { padding: 24px 24px 18px; margin: 0; }
.expense-modal-form .modal-header h2 { margin: 0; font-size: 21px; }
.expense-modal-form .modal-header p { margin: 6px 0 0; font-size: 13px; }
.expense-form-body { display: grid; gap: 24px; padding: 0 24px 24px; }
.expense-fields-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 20px; align-items: start; }
.expense-fields-grid > label, .expense-comment { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.expense-field-wide { grid-column: 1 / -1; }
.expense-form-body input, .expense-form-body select, .expense-form-body textarea { width: 100%; min-width: 0; box-sizing: border-box; }
.expense-form-body input, .expense-form-body select { min-height: 42px; }
.expense-form-body textarea { resize: vertical; min-height: 76px; }
.expense-field-help { font-size: 13px; line-height: 1.5; font-weight: 400; color: var(--muted); }
.expense-amount-field input { font-variant-numeric: tabular-nums; font-size: 20px; font-weight: 600; }
.expense-accrual { min-width: 0; margin: 0; padding: 18px 0 0; border: 0; border-top: 1px solid var(--border); }
.expense-accrual legend { padding: 0 8px 0 0; font-weight: 600; font-size: 14px; }
.expense-accrual legend span { margin-left: 6px; }
.expense-accrual > p { margin: 0 0 14px; }
.expense-comment > .expense-field-help { display: inline; }
.expense-modal-form > .actions { position: sticky; bottom: 0; margin: 0; padding: 16px 24px; background: var(--surface-raised); border-top: 1px solid var(--border); justify-content: flex-end; }
/* Ошибка над формой — общая плашка alert(); шаг до полей задаёт сетка формы. */
.expense-form-body > .inline-alert { margin: 0; overflow-wrap: anywhere; }
.expense-page-form { max-width: 640px; }
.expense-page-form .expense-form-body { padding: 0; }
@media (max-width: 560px) {
    .expense-modal-form .modal-header { padding: 20px 16px 18px; }
    .expense-form-body { padding: 0 16px 20px; gap: 20px; }
    .expense-fields-grid { grid-template-columns: minmax(0, 1fr); gap: 16px; }
    .expense-accrual .expense-fields-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; }
    .expense-form-body input, .expense-form-body select, .expense-form-body textarea { font-size: 16px; }
    .expense-amount-field input { font-size: 20px; }
    .expense-modal-form > .actions { padding: 14px 16px; }
    .expense-modal-form > .actions > button { flex: 1; }
}
.expense-table { min-width: 1320px; }
.expense-table .accrual-col { min-width: 190px; white-space: nowrap; }
/* В этой сортируемой колонке после ссылки стоит отдельная подсказка. Блочная
   flex-ссылка занимала всю строку заголовка и вытесняла ⓘ вниз, к данным
   таблицы. Оставляем обе цели раздельными, но собираем их в одну строку. */
.expense-table .sortable-th.accrual-col > a {
    display: inline-flex;
    margin-right: 0;
    padding-right: 4px;
    vertical-align: middle;
}
.expense-table .sortable-th.accrual-col > .hint {
    display: inline-flex;
    align-items: center;
    line-height: 1;
    vertical-align: middle;
}
.expense-table .amount-col { min-width: 130px; white-space: nowrap; }
.expense-table .actions-col { width: 170px; min-width: 170px; white-space: nowrap; }
.checkout-orders-container .table-scroll { box-sizing: border-box; width: 100%; }
.checkout-orders-table { min-width: 1180px; }
.checkout-orders-table td { vertical-align: top; }
.checkout-orders-table .row-actions { min-width: 330px; white-space: nowrap; }

.tasks-table { min-width: 1320px; table-layout: fixed; }
.section-title-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.section-title-row h2 { margin: 0; }
/* Пустые состояния были то серым прямоугольником, то строкой текста, то
   центрированной надписью — теперь у всех троих одна форма. */
.empty-state {
    display: grid;
    justify-items: center;
    gap: 8px;
    /* Было 26px. Пустое состояние — единственное содержимое блока, и тесные
       поля делали из него узкую серую полосу, а не место, где нечему быть. */
    padding: 38px 24px;
    color: var(--muted);
    /* Пунктир обещает область, куда что-то перетаскивают; ни одно из этих мест
       ничего не принимает. Сплошная линия просто очерчивает границу пустого. */
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    text-align: center;
    line-height: 1.5;
    text-wrap: pretty;
}
td.empty-state { display: table-cell; border: 0; border-radius: 0; }
/* Внутри ячейки .empty-state сброшен в table-cell, поэтому раскладку держит
   вложенный блок: заголовок, причина и действие в столбик по центру. */
.empty-state-body { display: grid; justify-items: center; gap: 8px; }
.empty-state-title { color: var(--ink); font-size: 15px; font-weight: 600; }
.empty-state-hint { margin: 0; }
/* Заливки здесь больше нет. Шапка теперь тоже --surface-2, и у пустой
   таблицы шапка и единственная строка сливались в одну серую плиту. */
.empty-row td { background: transparent; }

/* App communications -------------------------------------------------------
   Publications are a table-first surface. Creation and editing live in
   dialogs, so the list can use the whole operational workspace. */
.app-shell .container.app-communications-container {
    width: 100%;
    max-width: none;
    margin: 0;
    padding: 10px 18px 44px;
}
.studio-posts-index {
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--card);
}
.studio-posts-heading {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 20px;
    padding: 20px 22px;
    border-bottom: 1px solid var(--border);
}
.studio-posts-heading h2 { margin: 0; color: var(--ink); }
.studio-posts-heading p { margin: 5px 0 0; }
.studio-posts-summary { display: flex; align-items: center; gap: 16px; color: var(--muted); font-size: 12px; }
.studio-posts-summary span { white-space: nowrap; }
.studio-posts-summary strong { margin-right: 4px; color: var(--ink); font-variant-numeric: tabular-nums; }
.studio-posts-index .table-scroll { border: 0; border-radius: 0; }
.studio-posts-table { width: 100%; min-width: 920px; }
.studio-posts-table td { vertical-align: middle; }
.studio-posts-table th:first-child { width: 46%; }
.studio-post-cell { display: flex; align-items: center; gap: 12px; min-width: 0; }
.studio-post-thumbnail {
    width: 72px;
    height: 52px;
    flex: 0 0 72px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    object-fit: cover;
}
.studio-post-copy { display: grid; justify-items: start; gap: 3px; min-width: 0; }
.studio-post-copy > strong,
.studio-post-copy > span { max-width: 100%; }
.studio-post-copy > .muted { line-height: 1.45; }
.studio-post-form { display: grid; gap: 18px; }
.studio-post-form .modal-header { margin-bottom: 0; }
.studio-post-form .modal-header p { margin: 5px 0 0; }
.studio-post-form-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(220px, .55fr);
    gap: 16px;
}
.studio-post-form-grid > label,
.studio-post-fields-row > label,
.studio-post-image-field { display: grid; align-content: start; gap: 7px; min-width: 0; }
.studio-post-form-grid input,
.studio-post-form-grid select,
.studio-post-form-grid textarea { width: 100%; min-width: 0; }
.studio-post-fields-row {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: start;
    gap: 16px;
    min-width: 0;
}
.studio-post-title-field,
.studio-post-body-field,
.studio-post-image-field { grid-column: 1 / -1; }
.studio-post-body-field textarea { min-height: 150px; resize: vertical; }
.studio-post-current-image {
    width: fit-content;
    padding: 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-2);
}
.studio-post-current-image img { display: block; width: 132px; height: 82px; border-radius: var(--radius-sm); object-fit: cover; }
.studio-post-image-delete { justify-self: start; }
.studio-post-form-actions { margin-top: 0; }

/* Manual PUSH broadcasts ---------------------------------------------------
   The composer is deliberately a separate communications surface, not a tab
   inside event-driven automation. A quiet two-column document keeps the
   message and its exact audience calculation visible at the same time. */
.app-shell .container.push-broadcasts-container {
    width: 100%;
    max-width: none;
}
.push-broadcast-layout {
    display: grid;
    grid-template-columns: minmax(0, 1.25fr) minmax(320px, .75fr);
    gap: 18px;
    align-items: start;
    width: 100%;
}
.push-broadcast-composer,
.push-broadcast-preview,
.push-broadcast-journal {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--card);
}
.push-broadcast-composer { padding: 22px; }
.push-broadcast-preview {
    position: sticky;
    top: 74px;
    padding: 22px;
}
.push-broadcast-section-heading {
    display: flex;
    align-items: start;
    justify-content: space-between;
    gap: 16px;
}
.push-broadcast-section-heading h2,
.push-broadcast-preview > h2 {
    margin: 0;
    color: var(--ink);
}
.push-broadcast-section-heading p { margin: 5px 0 0; font-size: 13px; }
.push-broadcast-form { display: grid; gap: 24px; margin-top: 20px; }
.push-broadcast-form-section { display: grid; gap: 14px; min-width: 0; }
.push-broadcast-form-section + .push-broadcast-form-section {
    padding-top: 22px;
    border-top: 1px solid var(--border);
}
.push-broadcast-form-section-heading { display: grid; gap: 4px; }
.push-broadcast-form-section-heading h3 { margin: 0; color: var(--ink); font-size: 15px; }
.push-broadcast-form-section-heading p { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.5; }
.push-broadcast-field { position: relative; display: grid; gap: 7px; font-weight: 700; }
.push-broadcast-field textarea { min-height: 122px; resize: vertical; }
.push-broadcast-counter {
    position: absolute;
    right: 10px;
    bottom: 8px;
    padding: 2px 5px;
    background: var(--card);
    color: var(--faint);
    font-size: 11px;
    font-weight: 500;
}
.push-broadcast-options {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 10px;
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}
.push-broadcast-choice {
    display: grid;
    grid-template-columns: 18px minmax(0, 1fr);
    align-items: start;
    column-gap: 10px;
    min-width: 0;
    min-height: 78px;
    padding: 13px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
    cursor: pointer;
}
.push-broadcast-choice:has(input:checked) {
    border-color: var(--brand-border-strong);
    background: var(--selected);
    box-shadow: inset 0 0 0 1px var(--brand-border);
}
.push-broadcast-choice input { width: 18px; height: 18px; margin: 1px 0 0; accent-color: var(--brand); }
.push-broadcast-choice-copy { display: grid; gap: 3px; min-width: 0; }
.push-broadcast-choice strong { color: var(--ink); font-size: 13px; }
.push-broadcast-choice small { color: var(--muted); font-size: 11px; line-height: 1.45; }
.push-broadcast-picker {
    position: relative;
    display: grid;
    gap: 10px;
    padding: 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-2);
}
.push-broadcast-filter-builder {
    display: grid;
    gap: 0;
    margin-top: 4px;
    padding-top: 20px;
    border-top: 1px solid var(--border);
}
.push-broadcast-filter-heading { display: grid; gap: 4px; padding-bottom: 18px; }
.push-broadcast-filter-heading h3 { margin: 0; color: var(--ink); }
.push-broadcast-filter-heading p { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.5; }
.push-broadcast-filter-section {
    display: grid;
    gap: 12px;
    min-width: 0;
    margin: 0;
    padding: 18px 0;
    border: 0;
    border-top: 1px solid var(--border);
}
.push-broadcast-filter-section:last-child { padding-bottom: 0; }
.push-broadcast-filter-section > legend {
    padding: 0;
    color: var(--ink);
    font-size: 14px;
    font-weight: 800;
}
.push-broadcast-filter-section > .field-hint { margin: -6px 0 0; }
.push-broadcast-segment-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 5px 10px;
}
.push-broadcast-segment-grid label {
    display: grid;
    grid-template-columns: 18px minmax(0, 1fr);
    align-items: center;
    gap: 8px;
    min-height: 36px;
    padding: 6px 8px;
    border-radius: var(--radius-sm);
    color: var(--ink);
    font-size: 12px;
    cursor: pointer;
}
.push-broadcast-segment-grid label:hover { background: var(--hover); }
.push-broadcast-segment-grid label:has(input:checked) { background: var(--selected); }
.push-broadcast-segment-grid input {
    width: 18px;
    height: 18px;
    margin: 0;
    accent-color: var(--brand);
}
.push-broadcast-filter-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 24px;
    align-items: start;
}
.push-broadcast-control-group { display: grid; min-width: 0; align-content: start; gap: 8px; }
.push-broadcast-control-title { color: var(--ink); font-size: 12px; font-weight: 700; }
.push-broadcast-range {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}
.push-broadcast-range label,
.push-broadcast-select-condition { display: grid; gap: 6px; }
.push-broadcast-range label > span { color: var(--muted); font-size: 11px; }
.push-broadcast-select-condition small { color: var(--muted); font-size: 11px; line-height: 1.45; }
.push-broadcast-control-group > .field-hint { margin: 0; }
.push-broadcast-toggle-list { display: grid; gap: 6px; }
.push-broadcast-toggle {
    display: grid;
    grid-template-columns: 18px minmax(0, 1fr);
    align-items: start;
    gap: 9px;
    padding: 7px;
    border-radius: var(--radius-sm);
    color: var(--ink);
    cursor: pointer;
}
.push-broadcast-toggle:hover { background: var(--hover); }
.push-broadcast-toggle:has(input:checked) { background: var(--selected); }
.push-broadcast-toggle input {
    width: 18px;
    height: 18px;
    margin: 1px 0 0;
    accent-color: var(--brand);
}
.push-broadcast-toggle > span { display: grid; gap: 2px; }
.push-broadcast-toggle strong { font-size: 12px; }
.push-broadcast-toggle small { color: var(--muted); font-size: 11px; line-height: 1.4; }
.push-broadcast-toggle--single { min-height: 74px; }
.push-broadcast-filter-row--communications { align-items: center; }
[data-communication-history-fields][aria-disabled="true"] { opacity: .5; }
.push-broadcast-form-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; }
.push-broadcast-form-actions > span { color: var(--muted); font-size: 11px; }
.push-broadcast-search-results {
    position: absolute;
    z-index: 8;
    top: 76px;
    right: 14px;
    left: 14px;
    max-height: 280px;
    overflow-y: auto;
    padding: 5px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
    box-shadow: var(--shadow);
}
.push-broadcast-search-result {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    padding: 9px 10px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--ink);
    text-align: left;
    cursor: pointer;
}
.push-broadcast-search-result:hover:not(:disabled),
.push-broadcast-search-result.is-active { background: var(--hover); }
.push-broadcast-search-result:disabled { cursor: default; opacity: .7; }
.push-broadcast-search-result > span:first-child { display: grid; gap: 2px; }
.push-broadcast-search-result small { color: var(--muted); font-size: 11px; }
.push-broadcast-search-result > span:last-child { color: var(--brand-ink); font-size: 11px; font-weight: 800; }
.push-broadcast-search-note { margin: 0; padding: 10px; color: var(--muted); font-size: 12px; }
.push-broadcast-selection { display: flex; flex-wrap: wrap; gap: 6px; }
.push-broadcast-selection > p { width: 100%; margin: 0; font-size: 12px; }
.push-broadcast-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    max-width: 100%;
    padding: 5px 6px 5px 9px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-raised);
    color: var(--ink);
    font-size: 12px;
}
.push-broadcast-chip > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.push-broadcast-chip button {
    display: grid;
    width: 20px;
    height: 20px;
    place-items: center;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
}
.push-broadcast-chip button:hover { background: var(--hover); color: var(--ink); }
.push-broadcast-summary {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1px;
    overflow: hidden;
    margin-top: 18px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--border);
}
.push-broadcast-summary > div { display: grid; gap: 2px; padding: 12px; background: var(--surface-raised); }
.push-broadcast-summary strong { color: var(--ink); font-size: 22px; font-variant-numeric: tabular-nums; }
.push-broadcast-summary span { color: var(--muted); font-size: 10px; line-height: 1.3; }
.push-broadcast-filter-summary { margin-top: 16px; }
.push-broadcast-filter-summary h3 { margin: 0 0 5px; color: var(--ink); }
.push-broadcast-filter-summary p { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.55; }
.push-broadcast-exclusions h3,
.push-broadcast-recipients-preview h3 { margin: 18px 0 7px; color: var(--ink); }
.push-broadcast-exclusions ul,
.push-broadcast-recipients-preview ul { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; }
.push-broadcast-exclusions li,
.push-broadcast-recipients-preview li {
    align-items: center;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
    font-size: 12px;
}
.push-broadcast-exclusions li { display: flex; justify-content: space-between; gap: 10px; }
.push-broadcast-recipients-preview li { display: grid; justify-content: stretch; gap: 1px; }
.push-broadcast-exclusions strong { color: var(--ink); font-variant-numeric: tabular-nums; }
.push-broadcast-recipients-preview small { color: var(--muted); }
.push-broadcast-recipients-preview > p { margin: 7px 0 0; font-size: 12px; }
.push-broadcast-confirm { display: grid; gap: 10px; margin-top: 18px; }
.push-broadcast-confirm p { margin: 0; color: var(--muted); font-size: 11px; line-height: 1.5; }
.push-broadcast-copy-required {
    display: grid;
    gap: 4px;
    margin-top: 18px;
    padding: 12px;
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.push-broadcast-copy-required strong { color: var(--ink); font-size: 12px; }
.push-broadcast-copy-required p { margin: 0; color: var(--muted); font-size: 11px; line-height: 1.5; }
.push-broadcast-preview-placeholder {
    display: grid;
    min-height: 280px;
    align-content: center;
    justify-items: center;
    gap: 10px;
    color: var(--muted);
    text-align: center;
}
.push-broadcast-preview-placeholder > svg {
    display: grid;
    width: 44px;
    height: 44px;
    padding: 11px;
    border: 1px solid var(--border);
    border-radius: 50%;
    color: var(--faint);
    fill: none;
    stroke: currentColor;
    stroke-linecap: round;
    stroke-linejoin: round;
    stroke-width: 1.6;
}
.push-broadcast-preview-placeholder p { max-width: 34ch; margin: 0; font-size: 13px; line-height: 1.55; }
.push-broadcast-journal { width: 100%; padding: 22px; }
.push-broadcast-journal .table-scroll { margin-top: 16px; }
.push-broadcast-table { min-width: 760px; }
.push-broadcast-table td { vertical-align: top; }
.push-broadcast-table td > strong,
.push-broadcast-table td > small { display: block; }
.push-broadcast-table td > small { margin-top: 3px; color: var(--muted); font-size: 11px; }
.push-broadcast-delivery-status { color: var(--ink); font-weight: 700; }
@media (max-width: 980px) {
    .push-broadcast-layout { grid-template-columns: 1fr; }
    .push-broadcast-preview { position: static; }
}
@media (max-width: 640px) {
    .app-shell .container.app-communications-container { padding-inline: 10px; }
    .studio-posts-heading { display: grid; padding: 16px; }
    .studio-posts-summary { justify-content: space-between; }
    .studio-post-form-grid { grid-template-columns: 1fr; }
    .studio-post-fields-row { grid-template-columns: 1fr; }
    .studio-post-title-field,
    .studio-post-body-field,
    .studio-post-image-field { grid-column: auto; }
    .studio-post-current-image img { width: 132px; height: 82px; }
    .push-broadcast-composer,
    .push-broadcast-preview,
    .push-broadcast-journal { padding: 16px; }
    .push-broadcast-options { grid-template-columns: 1fr; }
    .push-broadcast-segment-grid,
    .push-broadcast-filter-row { grid-template-columns: 1fr; }
    .push-broadcast-form-actions { align-items: stretch; }
    .push-broadcast-form-actions .hui-button { width: 100%; }
    .push-broadcast-summary strong { font-size: 18px; }
}
.chat-poll-state { display: none; }
.conversation-list, .conversation-detail {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 14px;
}
.conversation-list { max-height: 760px; overflow: auto; }
.conversation-card {
    display: grid;
    gap: 4px;
    padding: 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--ink);
    text-decoration: none;
    background: var(--card);
    margin-bottom: 8px;
}
.conversation-card.active { border-color: var(--brand); background: var(--brand-tint); }
.conversation-title { font-weight: 700; }
.conversation-preview { color: var(--muted); font-size: 13px; }
.conversation-preview { line-height: 1.35; }
.conversation-header { display: flex; justify-content: space-between; gap: 14px; align-items: start; margin-bottom: 14px; }
.conversation-header h2 { margin: 0 0 4px; }
.message-thread { display: grid; gap: 10px; margin-bottom: 14px; }
.message-bubble { max-width: 78%; border: 1px solid var(--border); border-radius: var(--radius-md); padding: 10px; background: var(--card); }
.message-bubble.outbound { margin-left: auto; background: var(--brand-tint); border-color: var(--brand-border); }
.message-bubble.inbound { margin-right: auto; background: var(--surface-2); }
.message-bubble.system, .message-bubble.internal { max-width: 100%; background: var(--warn-tint); border-color: var(--warn-border); }
.message-meta { color: var(--muted); font-size: 12px; margin-bottom: 4px; }
.message-body { white-space: pre-wrap; line-height: 1.45; }
.message-attachments { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.message-attachment.image {
    display: inline-flex;
    max-width: 260px;
    overflow: hidden;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--surface-2);
}
.message-attachment.image img {
    display: block;
    max-width: 100%;
    max-height: 260px;
    object-fit: contain;
}
.message-attachment.sticker {
    max-width: 152px;
    border: 0;
    background: transparent;
}
.message-attachment.sticker img { max-height: 152px; }
.message-attachment.file { align-self: center; }
.message-audio { width: min(280px, 100%); }
.message-audio-wrap { display: grid; gap: 5px; min-width: min(280px, 100%); }
.message-audio-wrap > span { color: var(--muted); font-size: 12px; font-weight: 700; }
.message-video-wrap { display: grid; gap: 5px; width: min(320px, 100%); min-width: 0; }
.message-video-wrap > span { overflow-wrap: anywhere; }
.message-video { display: block; width: 100%; max-height: 320px; border-radius: var(--radius-sm); background: var(--surface-2); }
.message-video-unavailable { color: var(--muted); }
.chat-refresh-notice {
    position: fixed;
    right: 24px;
    bottom: 24px;
    z-index: var(--z-toast);
    border: 1px solid var(--brand);
    border-radius: 999px;
    padding: 10px 14px;
    background: var(--brand);
    color: var(--on-brand);
    box-shadow: var(--shadow);
    cursor: pointer;
}
.pager.compact { margin-top: 10px; }
.communications-container { max-width: 1680px; }
/* Chats occupy the viewport below the real topbar height. The shell and page
   are fixed; only the conversation list and message history scroll. */
.main-shell:has(.communications-container) { display: flex; flex-direction: column; height: 100dvh; overflow: hidden; }
.main-shell:has(.communications-container) > .topbar { flex: 0 0 auto; }
.main-shell:has(.communications-container) > .communications-container { display: flex; flex: 1 1 auto; flex-direction: column; min-height: 0; overflow: hidden; padding-top: 12px; padding-bottom: 12px; }
.communications-container > .inline-alert { flex: 0 0 auto; }
.communications-container > .chat-controls, .communications-container > .chat-channels { flex: 0 0 auto; }
/* Одна строка фильтров прямо на фоне страницы: поиск, чьи диалоги, канал,
   папка, статус. Каналы, папки и статусы — выпадающими списками, а не
   отдельной полосой. Поиск уступает место трём меню: flex-wrap переносит
   раньше, чем сжимает, и при основе 340 px «Статус» на 1440 уходил вниз. */
.chat-controls { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.chat-search { position: relative; flex: 1 1 230px; min-width: 190px; }
.chat-search::before { content: ""; position: absolute; left: 12px; top: 50%; width: 16px; height: 16px; transform: translateY(-50%); background: var(--faint); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='6.5'/%3E%3Cpath d='m16 16 4 4'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='6.5'/%3E%3Cpath d='m16 16 4 4'/%3E%3C/svg%3E") center / contain no-repeat; pointer-events: none; }
.chat-search input { width: 100%; padding-left: 36px; }
.chat-controls-spacer { flex: 1 1 0; min-width: 0; }
.chat-segments { display: flex; gap: 2px; padding: 3px; background: var(--surface-2); border-radius: var(--radius-sm); }
.chat-segments a { padding: 6px 12px; border-radius: 6px; color: var(--muted); text-decoration: none; font-size: 13px; font-weight: 600; white-space: nowrap; }
.chat-segments a.active { background: var(--card); color: var(--ink); box-shadow: var(--lift); }
.chat-segments b { margin-left: 5px; font-size: 12px; color: var(--faint); font-variant-numeric: tabular-nums; }
.chat-segments a.active b { color: var(--brand); }
.chat-filter { position: relative; flex: none; }
.chat-filter-button { display: inline-flex; align-items: center; gap: 6px; height: var(--control-h); padding: 0 9px 0 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--card); color: var(--ink); font: inherit; font-size: 13px; font-weight: 600; white-space: nowrap; cursor: pointer; }
.chat-filter-button:hover, .chat-filter-button[aria-expanded="true"] { background: var(--hover); }
.chat-filter-name { color: var(--muted); font-weight: 500; }
.chat-filter-caret { width: 15px; height: 15px; fill: none; stroke: var(--muted); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.chat-menu.chat-channel-menu { width: max-content; min-width: 250px; max-width: calc(100vw - 32px); }
.chat-channel-menu .chat-channels { display: grid; gap: 1px; }
.chat-channel-menu .chat-channels a { display: flex; align-items: center; gap: 8px; padding: 7px 10px; border-radius: 7px; color: var(--ink); text-decoration: none; font-size: 13.5px; white-space: nowrap; }
.chat-channel-menu .chat-channels .label { flex: 1 1 auto; margin-right: 10px; }
.chat-channel-menu .chat-channels a:hover { background: var(--surface-2); }
.chat-channel-menu .chat-channels a.active { background: var(--selected); font-weight: 700; }
.chat-channels .glyph { display: grid; flex: none; place-items: center; width: 18px; height: 18px; color: var(--muted); }
.chat-channels .glyph svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.chat-channels .n { font-size: 12px; color: var(--faint); font-variant-numeric: tabular-nums; }
/* Счётчики в стиле значка бокового меню (.nav-badge): красный — диалоги без ответа, бирюзовый — не прочитано вами. */
.chat-channels i { min-width: 20px; height: 20px; padding: 0 6px; display: inline-flex; flex: none; align-items: center; justify-content: center; border-radius: var(--radius-sm); background: var(--danger-soft); color: var(--err); font-size: 11.5px; font-style: normal; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.chat-channels i.unread { background: var(--info-soft); color: var(--info); }
/* Меню «Папка» — то же меню, что у каналов. «Реклама» и «Настроить папки»
   отделены чертой, как «Снять ответственного». */
.chat-channel-menu .chat-folders a.chat-menu-separated { margin-top: 4px; padding-top: 10px; border-top: 1px solid var(--border); border-radius: 0 0 7px 7px; }
.chat-channel-menu .chat-folders a.chat-folders-manage { color: var(--muted); }
.communications-workspace { display: grid; flex: 1 1 auto; grid-template-columns: 330px minmax(430px, 1fr) 290px; gap: 12px; height: auto; min-height: 0; overflow: hidden; align-items: stretch; }
.communications-workspace.panel-hidden { grid-template-columns: 330px minmax(430px, 1fr); }
.communications-workspace.panel-hidden .client-context { display: none; }
.communications-workspace .conversation-list, .communications-workspace .conversation-detail, .client-context-card { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-md); }
.communications-workspace .conversation-list { height: 100%; min-height: 0; padding: 0; max-height: none; display: flex; flex-direction: column; overflow: hidden; }
.conversation-list-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 6px; scrollbar-gutter: stable; }
.communications-workspace .conversation-list-pager { flex: 0 0 auto; justify-content: center; gap: 8px; margin: 0; padding: 9px 10px; border-top: 1px solid var(--border); background: var(--card); }
.conversation-list-page { min-width: 42px; color: var(--muted); font-size: 12px; font-weight: 600; text-align: center; white-space: nowrap; font-variant-numeric: tabular-nums; }
.chat-menu { position: absolute; z-index: var(--z-menu); min-width: 190px; margin-top: 6px; padding: 5px; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-md); box-shadow: var(--shadow); display: grid; gap: 1px; }
.chat-menu.right { right: 0; }
.chat-menu a, .chat-menu button { display: block; width: 100%; text-align: left; padding: 8px 10px; border: 0; border-radius: 7px; background: none; color: var(--ink); text-decoration: none; font-size: 13px; cursor: pointer; }
.chat-menu a:hover, .chat-menu button:hover { background: var(--surface-2); }
.chat-menu a.active { color: var(--brand); font-weight: 700; }
.chat-menu button.danger { color: var(--danger); }
.chat-menu form { margin: 0; }
.chat-status-picker, .chat-more { position: relative; }
/* Карточка говорит «важно» одним способом на состояние: новое — жирным
   именем и счётчиком, ожидание — цветом времени, канал — значком на аватаре. */
.communications-workspace .conversation-card { grid-template-columns: 42px minmax(0,1fr); gap: 12px; padding: 12px; margin-bottom: 1px; border: 0; border-radius: 8px; background: transparent; }
.communications-workspace .conversation-card:hover { background: var(--hover); }
.communications-workspace .conversation-card.active { background: var(--selected); }
.conversation-avatar { position: relative; width: 42px; height: 42px; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; background: var(--brand-strong); color: var(--brand-ink); font-size: 16px; font-weight: 700; text-transform: uppercase; }
.conversation-avatar.large { width: 44px; height: 44px; font-size: 17px; }
.conversation-avatar.anonymous { background: var(--surface-2); color: var(--muted); }
.conversation-avatar.anonymous > svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; }
.conversation-channel-mark { position: absolute; right: -3px; bottom: -3px; width: 19px; height: 19px; display: grid; place-items: center; border: 1px solid var(--border); border-radius: 50%; background: var(--card); color: var(--muted); font-style: normal; }
.conversation-channel-mark svg { width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.conversation-card-body { min-width: 0; display: grid; gap: 3px; align-content: center; }
.conversation-card-top, .conversation-card-line { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.conversation-card-top b, .conversation-preview { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conversation-card-top b { font-size: 15px; font-weight: 600; }
.communications-workspace .conversation-preview { font-size: 14px; }
.conversation-card-top time { flex: none; color: var(--faint); font-size: 12.5px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.conversation-card.unread .conversation-card-top b { font-weight: 700; }
.conversation-card.unread .conversation-preview { color: var(--ink); }
.conversation-card.unread .conversation-card-top time { color: var(--brand-ink); font-weight: 600; }
.unread-count { flex: none; align-self: center; min-width: 21px; height: 21px; padding: 0 6px; border-radius: 999px; background: var(--brand); color: var(--on-brand); font-size: 11.5px; font-style: normal; font-weight: 700; line-height: 21px; text-align: center; font-variant-numeric: tabular-nums; }
.waiting-badge { width: fit-content; padding: 3px 8px; border-radius: 7px; background: var(--brand-strong); color: var(--brand-ink); font-size: 11px; font-weight: 700; }
.waiting-badge.warning { background: var(--warn-soft); color: var(--warn); }
.waiting-badge.overdue { background: var(--danger-soft); color: var(--danger); }
/* Строка состояния: ожидание, отложен до, кто отвечает. Пустая не занимает места. */
.conversation-state-badges { display: flex; align-items: center; gap: 8px; min-width: 0; margin-top: 3px; color: var(--faint); font-size: 12.5px; }
.conversation-state-badges:empty { display: none; }
.conversation-owner { margin-left: auto; white-space: nowrap; }
.conversation-owner.none { font-style: italic; }
.snoozed-badge { width: fit-content; padding: 3px 8px; border-radius: 7px; background: var(--surface-2); color: var(--muted); font-size: 11px; font-weight: 700; }
/* Папка диалога — мягкой капсулой со значком, как «Отложен». */
.conversation-folder { display: inline-flex; align-items: center; gap: 4px; flex: none; padding: 2px 8px 2px 6px; border-radius: 7px; background: var(--surface-2); color: var(--muted); font-size: 12px; font-weight: 600; line-height: 1.35; white-space: nowrap; }
.conversation-folder svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.conversation-subtitle .conversation-folder { margin-left: 6px; vertical-align: 1px; }
.communications-workspace .snoozed-badge { padding: 0; background: none; color: inherit; font-size: inherit; font-weight: 500; white-space: nowrap; }
.communications-workspace .conversation-card.snoozed:not(.active) .conversation-card-body { opacity: .72; }
/* Ожидание в списке и в шапке — плашкой: цветом текста его не читали. */
.communications-workspace .waiting-badge { flex: none; padding: 3px 8px; font-size: 12px; line-height: 1.35; white-space: nowrap; font-variant-numeric: tabular-nums; }
.chat-menu-group { display: grid; gap: 1px; padding: 4px 0; margin: 3px 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
/* Две группы подряд («Отложить» и «Папка») — одна черта между ними, а не две. */
.chat-menu-group + .chat-menu-group { margin-top: 0; border-top: 0; }
.chat-menu-label { padding: 2px 10px; color: var(--muted); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; }
.thread-history-bar { display: flex; justify-content: center; gap: 6px; padding: 7px 10px; margin-bottom: 10px; border-radius: 8px; background: var(--warn-tint); border: 1px solid var(--warn-border); color: var(--warn); font-size: 12px; }
.message-thread.history-mode { background: var(--surface-2); }
.communications-workspace .conversation-detail { height: 100%; min-height: 0; display: flex; flex-direction: column; min-width: 0; padding: 0; overflow: hidden; }
.communications-workspace .conversation-header { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 12px; padding: 11px 14px; margin: 0; border-bottom: 1px solid var(--border); }
.communications-workspace .conversation-header form { display: flex; gap: 6px; margin: 0; }
.conversation-title { display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1 1 150px; }
.conversation-title > div { min-width: 0; }
.conversation-title h2 { margin: 0; font-size: 17px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conversation-subtitle { overflow: hidden; color: var(--muted); font-size: 12.5px; white-space: nowrap; text-overflow: ellipsis; }
.conversation-subtitle .waiting-badge { display: inline-block; padding: 1px 7px; font-size: 12px; }
.conversation-subtitle .snoozed-badge { font-size: 12.5px; }
/* Пока список виден, ожидание читается в его карточке; в шапке оно нужно,
   когда на узком экране открыт один диалог. Данные для живого счёта остаются. */
.conversation-subtitle-wait { display: none; }
.chat-back { display: none; }
.conversation-header-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
/* Ответственный — кнопка с меню того же вида, что «Канал» и «Статус». В шапке
   она ростом с соседние кнопки. */
.conversation-header .chat-filter-button { height: 32px; }
.chat-filter-value { max-width: 180px; overflow: hidden; text-overflow: ellipsis; }
.chat-filter-value.is-empty { color: var(--muted); font-weight: 500; }
.communications-workspace .conversation-header .chat-menu form { display: grid; gap: 1px; }
.chat-menu button.active { color: var(--brand); font-weight: 700; }
.chat-menu .chat-menu-separated { margin-top: 4px; padding-top: 10px; border-top: 1px solid var(--border); border-radius: 0 0 7px 7px; color: var(--muted); }
.chat-icon-button { width: 32px; height: 32px; display: grid; place-items: center; padding: 0; border: 0; border-radius: 8px; background: transparent; color: var(--muted); cursor: pointer; }
.chat-icon-button:hover, .chat-icon-button[aria-expanded="true"] { background: var(--hover); color: var(--ink); }
.chat-icon-button svg { width: 20px; height: 20px; fill: currentColor; }
/* Date separators and the personal unread line keep a long thread readable. */
.thread-day { justify-self: center; padding: 3px 12px; border: 1px solid var(--border); border-radius: 999px; background: var(--card); color: var(--muted); font-size: 11px; font-weight: 700; }
.thread-unread-line { justify-self: stretch; display: flex; align-items: center; gap: 10px; color: var(--info); font-size: 11px; font-weight: 700; }
.thread-unread-line::before, .thread-unread-line::after { content: ""; flex: 1; height: 1px; background: currentColor; opacity: 0.35; }
.late-flag { margin-left: 6px; padding: 1px 6px; border-radius: 5px; background: var(--warn-soft); color: var(--warn); font-size: 10px; font-weight: 700; }
/* Обёртка ленты. Нужна кнопке «вниз»: та висит над сообщениями, а не над
   страницей, и с прокруткой не уезжает. Сама лента осталась тем же
   контейнером прокрутки, что и была. */
.communications-workspace .thread-viewport { position: relative; flex: 1; min-height: 0; display: flex; }
.communications-workspace .message-thread { flex: 1; min-height: 0; max-height: none; overflow-y: auto; scrollbar-gutter: stable; padding: 16px 20px; margin: 0; gap: 4px; background: var(--surface-2); align-content: start; grid-auto-rows: max-content; overscroll-behavior: contain; }
/* Часовой у нижнего края. Высота в пиксель, а не ноль: элемент нулевой высоты
   браузер не считает пересекающимся, и лента никогда не была бы прицепленной. */
.thread-sentinel { height: 1px; }
/* Кнопка возврата к последнему сообщению. Появляется только когда лента
   отцеплена от низа — внизу она не нужна и закрывала бы сообщение. */
.thread-jump {
    position: absolute; right: 20px; bottom: 14px; z-index: var(--z-raised);
    display: inline-flex; align-items: center; gap: 7px;
    height: 34px; padding: 0 14px; border-radius: 999px;
    border: 1px solid var(--brand-border); background: var(--card); color: var(--brand-ink);
    font: 600 13px/1 inherit; font-family: inherit; cursor: pointer;
    box-shadow: var(--shadow);
}
.thread-jump:hover { border-color: var(--brand-border-strong); background: var(--brand-tint); }
.thread-jump:focus-visible { outline: var(--ring-w) solid var(--ring); outline-offset: var(--ring-offset); }
.thread-jump-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 19px; height: 19px; padding: 0 5px; border-radius: 999px;
    background: var(--brand); color: var(--on-brand); font-size: 11px;
    font-variant-numeric: tabular-nums;
}
/* Пузырь: текст и время в одной строке, если хватает места; автор, вложения
   и строка правки — на всю ширину. */
.communications-workspace .message-bubble { width: fit-content; min-width: 0; max-width: min(76%, 680px); height: auto; padding: 7px 10px 6px 12px; border-radius: 14px; align-self: start; justify-self: start; box-shadow: var(--lift); }
.communications-workspace .message-bubble.series-start { margin-top: 8px; }
.message-line { display: flex; flex-wrap: wrap; align-items: flex-end; column-gap: 12px; }
.message-line > .message-body { flex: 0 1 auto; min-width: 0; }
.message-line--end { margin-top: 4px; }
.message-author { margin-bottom: 2px; color: var(--muted); font-size: 11.5px; font-weight: 600; }
.message-stamp { display: inline-flex; align-items: center; gap: 4px; margin: 0 -2px -1px auto; color: var(--faint); font-size: 11px; line-height: 1.4; white-space: nowrap; font-variant-numeric: tabular-nums; }
.delivery-ticks { display: inline-flex; }
.delivery-ticks svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.delivery-ticks.read { color: var(--brand); }
.communications-workspace .message-bubble.outbound:has(> .delivery-failed, > .delivery-dead, > .delivery-unsupported, > .delivery-permanent_failure) { border-color: var(--danger-border); }
.communications-workspace .message-bubble.inbound { margin: 0; background: var(--surface-raised); border-color: var(--border); }
.communications-workspace .message-bubble.outbound { margin: 0; justify-self: end; background: var(--brand-strong); border-color: var(--brand-border); }
.communications-workspace .message-bubble.internal,
.communications-workspace .message-bubble.system { max-width: min(86%, 760px); justify-self: center; }
/* An internal note never leaves the CRM, so it must not look like a reply. */
.communications-workspace .message-bubble.internal { background: var(--warn-tint); border-color: var(--warn-border); }
.communications-workspace .message-bubble.internal { border-style: dashed; border-radius: 10px; }
.communications-workspace .message-bubble.internal .message-author { color: var(--warn); }
.communications-workspace .message-body { overflow-wrap: anywhere; }
.message-edited { color: var(--muted); font-size: 10px; }
/* Строка под отправленным: ошибка доставки, «Редактировать · Удалить». */
.delivery-state { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 5px; margin-top: 4px; color: var(--muted); font-size: 11px; text-align: right; }
.delivery-state:empty { display: none; }
.delivery-state > .message-edit-button:first-child::before,
.delivery-state > .message-provider-delete:first-child::before { content: none; }
.delivery-state small { flex-basis: 100%; }
.delivery-state form { margin: 0; }
.delivery-failed, .delivery-dead, .delivery-unsupported { color: var(--danger); }
.message-bubble.provider-deleted { background: var(--surface-2); border-style: dashed; }
.provider-deleted-message { color: var(--muted); font-style: italic; }
.message-provider-delete { display: inline-flex; align-items: center; margin: 0; }
.message-provider-delete::before { content: "·"; margin-right: 5px; color: var(--muted); }
.message-delete-button {
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--danger);
    font: inherit;
    font-size: 11px;
    cursor: pointer;
}
.message-delete-button:hover { text-decoration: underline; }
/* «Редактировать» под отправленным открывает окно правки (.message-edit-dialog). */
.message-edit-button {
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--brand-ink);
    font: inherit;
    font-size: 11px;
    cursor: pointer;
}
.message-edit-button::before { content: "·"; margin-right: 5px; color: var(--muted); }
.message-edit-button:hover { text-decoration: underline; }
.message-edit-dialog textarea { width: 100%; min-height: 110px; resize: vertical; }
.provider-edit-state { color: var(--muted); font-size: 11px; }
.provider-edit-error { color: var(--danger); }
.provider-delete-state { color: var(--muted); font-size: 11px; text-align: right; }
.provider-delete-state.failed { color: var(--danger); }
.provider-delete-error { color: var(--danger); }
/* Поле ответа — одна рамка: тип сообщения, текст, инструменты и отправка. */
.chat-composer { display: grid; gap: 8px; padding: 10px 14px 12px; border-top: 1px solid var(--border); background: var(--card); }
.chat-composer > [data-form-dirty-status] { display: none; }
.composer-box { display: grid; gap: 2px; padding: 6px 8px; border: 1px solid var(--border); border-radius: 12px; background: var(--card); }
.composer-box:focus-within { border-color: var(--brand-border-strong); box-shadow: 0 0 0 3px var(--brand-tint); }
.chat-composer.note-mode .composer-box { border-color: var(--warn-border); background: var(--warn-tint); }
.chat-composer textarea { display: block; width: 100%; min-width: 0; min-height: 68px; max-height: 40vh; padding: 4px 5px; border: 0; border-radius: 0; background: transparent; box-shadow: none; font-size: 16px; resize: none; }
.chat-composer textarea:focus, .chat-composer textarea:focus-visible { outline: none; }
.composer-recipient-error { margin: 0; padding: 8px 10px; border: 1px solid var(--danger-border); border-radius: var(--radius-sm); background: var(--danger-soft); color: var(--danger); font-size: 12px; font-weight: 700; }
.composer-mode { display: flex; gap: 2px; width: fit-content; }
.composer-mode button { padding: 3px 9px; border: 0; border-radius: 6px; background: none; color: var(--muted); font-size: 16px; font-weight: 600; cursor: pointer; }
.composer-mode button:hover { color: var(--ink); }
.composer-mode button.active { background: var(--surface-2); color: var(--ink); }
.chat-composer.note-mode .composer-mode button.active { background: var(--warn-bg); color: var(--warn); }
.composer-field { position: relative; }
.composer-toolbar { display: flex; align-items: center; gap: 4px; }
/* Под рамкой, как до разгрузки: подсказка по клавишам и кнопка отправки справа. */
.composer-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; }
.composer-footer .hui-button--primary { margin-left: auto; }
.composer-keys { color: var(--faint); font-size: 11.5px; }
.composer-keys kbd { padding: 1px 5px; border: 1px solid var(--border); border-radius: 4px; background: var(--surface-2); color: var(--muted); font-family: inherit; font-size: 10.5px; font-weight: 700; line-height: 1.6; }
.composer-tool { display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 8px; border: 0; border-radius: 7px; background: none; color: var(--muted); font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer; }
.composer-tool:hover, .composer-tool[aria-expanded="true"] { background: var(--surface-2); color: var(--ink); }
.composer-tool svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.composer-tool svg .dot { fill: currentColor; stroke: none; }
.composer-tool kbd { padding: 0 5px; border: 1px solid var(--border); border-radius: 4px; background: var(--card); color: var(--muted); font: inherit; font-size: 11px; font-weight: 700; line-height: 16px; }
.emoji-picker { position: relative; z-index: var(--z-menu); }
.emoji-trigger { width: 30px; padding: 0; justify-content: center; }
.emoji-menu { position: absolute; left: 0; bottom: calc(100% + 8px); grid-template-columns: repeat(5, 38px); gap: 3px; padding: 7px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card); box-shadow: var(--shadow); }
.emoji-menu:not([hidden]) { display: grid; }
.emoji-menu button { display: grid; place-items: center; width: 38px; height: 38px; padding: 0; border: 0; border-radius: 8px; background: transparent; font-size: 22px; cursor: pointer; }
.emoji-menu button:hover, .emoji-menu button:focus-visible { background: var(--surface-2); }
.composer-templates { position: absolute; left: 0; bottom: calc(100% + 8px); z-index: var(--z-menu); width: min(430px, 100%); padding: 6px; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-md); box-shadow: var(--shadow); }
.composer-templates-label { padding: 6px 10px 4px; color: var(--faint); font-size: 10.5px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; }
.composer-templates button { display: grid; gap: 2px; width: 100%; text-align: left; padding: 8px 10px; border: 0; border-radius: 7px; background: none; cursor: pointer; }
.composer-templates button:hover, .composer-templates button.active { background: var(--surface-2); }
.composer-templates b { font-size: 13px; }
.composer-templates span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: 12px; }
.conversation-history ul { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.conversation-history li b { color: var(--ink); font-weight: 600; }
.history-actor { color: var(--faint); }
.conversation-history { min-width: 0; overflow: hidden; }
.conversation-history li { display: grid; grid-template-columns: 72px minmax(0, 1fr); gap: 8px; min-width: 0; font-size: 12px; color: var(--muted); }
.conversation-history time { font-variant-numeric: tabular-nums; }
.conversation-history li > span { min-width: 0; overflow-wrap: anywhere; word-break: break-word; }
/* Кнопки связи стоят в одну строку под карточкой клиента: раньше это была
   колонка внизу панели, далеко от данных, по которым связь и правят. */
.client-link-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.client-link-actions.unlinked-client-actions { display: grid; grid-template-columns: minmax(0, 1fr); }
.client-link-actions.unlinked-client-actions > * { width: 100%; }
.client-link-actions > *, .client-link-actions form { flex: 1 1 0; min-width: 0; margin: 0; }
.client-link-actions form .hui-button { width: 100%; }
.client-link-actions .wide { flex-basis: 100%; width: 100%; text-align: center; }
.client-link-actions p { flex-basis: 100%; margin: 2px 0 0; font-size: 12px; }
.client-context section > .client-link-actions { margin-top: 12px; }
/* Карточка клиента — одна, разделы отбиты линией, а не отдельными рамками. */
.client-context-section, .client-context-card > .conversation-history { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }
.client-context-section h4, .conversation-history h4 { margin: 0 0 9px; color: var(--faint); font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.client-context-note { margin: 0 0 14px; color: var(--muted); font-size: 12px; line-height: 1.5; }
.communication-link-dialog .modal-form { display: grid; gap: 12px; max-height: min(780px, calc(100dvh - 40px)); }
.communication-link-dialog .modal-header { margin-bottom: 0; }
.communication-link-dialog .modal-header p { margin: 4px 0 0; }
.client-link-preview { display: grid; gap: 10px; padding: 12px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); }
.client-link-preview > div:not(.client-link-conflicts) { display: grid; gap: 3px; }
.client-link-conflicts { display: grid; gap: 8px; padding: 11px; border: 1px solid var(--warn-border); border-radius: var(--radius-sm); background: var(--warn-tint); }
.client-link-conflicts > div { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.client-link-transfer { margin-top: 2px; font-weight: 700; }
.client-link-conflicts p { margin: 0; }
.client-context { display: flex; flex-direction: column; gap: 10px; }
.communications-workspace > .client-context { min-height: 0; overflow-y: auto; scrollbar-gutter: stable; }
.client-context-card { padding: 16px; }
.communications-metrics-header { display: block; }
.communications-metric-grid { display: grid; grid-template-columns: repeat(4,minmax(150px,1fr)); gap: 10px; margin: 14px 0; }
.communications-metric-grid article { display: grid; gap: 5px; padding: 16px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card); }
.communications-metric-grid article span, .communications-metric-grid article small { color: var(--muted); }
.communications-metric-grid article strong { font-size: 28px; line-height: 1; }
.communications-metric-grid .metric-danger { border-color: var(--danger-border); background: var(--danger-soft); }
.metrics-method-note { margin: -6px 0 18px; font-size: 12.5px; }
.danger-text { color: var(--danger); font-weight: 700; }
.client-context h3 { margin: 0 0 10px; }
.client-context-person { display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; align-items: center; gap: 11px; margin-bottom: 14px; }
.client-context-person > div { min-width: 0; }
.client-context-person h3, .client-context-person span { margin: 0; }
.client-context-person span { color: var(--muted); font-size: 12px; }
.client-context dl { display: grid; gap: 7px; margin: 0 0 13px; }
.client-context dl div { display: flex; justify-content: space-between; gap: 8px; font-size: 12px; }
.client-context dt { color: var(--muted); }
.client-context dd { margin: 0; text-align: right; overflow-wrap: anywhere; }
.client-context .wide { width: 100%; text-align: center; }
/* Абонемент — три коротких строки; заголовочные отступы разгоняли их так,
   будто это три отдельных блока. */
.client-pass-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.client-pass-head b { line-height: 1.35; }
.client-pass-head span { flex: none; color: var(--muted); font-size: 12px; }
.client-pass-meter { height: 6px; margin: 8px 0 6px; overflow: hidden; border-radius: 99px; background: var(--surface-2); }
.client-pass-meter i { display: block; height: 100%; border-radius: inherit; background: var(--brand); }
.client-pass p { margin: 2px 0 0; color: var(--muted); font-size: 12px; line-height: 1.35; }
.upcoming-item { display: grid; grid-template-columns: 92px minmax(0, 1fr); column-gap: 8px; padding: 4px 0; font-size: 12.5px; }
.upcoming-item b { font-weight: 600; }
.upcoming-item span { grid-column: 2; font-size: 12px; }
.upcoming-item time, .upcoming-item span { color: var(--muted); }
.unlinked-context p { color: var(--muted); font-size: 12px; line-height: 1.5; }
@media (max-width: 1280px) {
    .communications-workspace, .communications-workspace.panel-hidden { grid-template-columns: 300px minmax(400px,1fr); }
    .communications-workspace .client-context { display: none; }
}
@media (max-width: 1100px) {
    .communications-metric-grid { grid-template-columns: repeat(2,minmax(0,1fr)); }
}
.shift-close-communications { padding: 12px 14px; }
.shift-close-communications > h2 { margin: 0 0 4px; }
.shift-close-communications > .muted { margin: 0; font-size: 13px; }
.shift-close-communication-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    margin: 10px 0 0;
}
.shift-close-communication-grid article {
    min-width: 0;
    gap: 3px;
    padding: 10px 11px;
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.shift-close-communication-grid article span {
    font-size: 12px;
    line-height: 1.25;
}
.shift-close-communication-grid article strong { font-size: 21px; }
.shift-close-communication-grid article small { font-size: 10.5px; line-height: 1.3; }
@media (max-width: 1100px) {
    .shift-close-communication-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
    .shift-close-communication-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 420px) {
    .shift-close-communication-grid { grid-template-columns: 1fr; }
}
/* Narrow screens show one pane at a time, like a messenger. */
@media (max-width: 900px) {
    .communications-workspace, .communications-workspace.panel-hidden {
        grid-template-columns: 1fr;
        height: auto;
        min-height: 0;
    }
    .communications-workspace .conversation-list { max-height: none; }
    body[data-chat-pane="thread"] .communications-workspace .conversation-list { display: none; }
    body[data-chat-pane="list"] .communications-workspace .conversation-detail { display: none; }
    .chat-back { display: inline-flex; align-items: center; }
    .chat-search { flex: 1 1 100%; }
    .conversation-subtitle-wait { display: inline; }
    .conversation-subtitle { white-space: normal; }
    .chat-segments { flex: 1 1 100%; overflow-x: auto; }
    .composer-keys { display: none; }
}
.clients-filterbar .clients-search { flex: 1 1 320px; }
.clients-filterbar .clients-search input { width: 100%; }
/* Полоса показателей стоит в ряду заголовка, слева от «Создать клиента»,
   и ровно той же высоты. Плита в три яруса — подпись, число, пояснение —
   занимала 76px и отбирала у списка полторы строки на каждом экране;
   те же три факта помещаются в строку высотой с кнопку рядом. */
.clients-container .clients-stat-cards {
    flex: 1 1 auto;
    margin: 0;
}
.clients-page-header { margin-bottom: 12px; }
.clients-page-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }

/* Дедубликация клиентов: плотный операционный экран сравнения, без отдельной
   визуальной системы поверх существующего кабинета. */
.app-shell .container.client-deduplication-container {
    width: 100%; max-width: none; margin: 0; padding-left: 18px; padding-right: 18px;
}
.client-deduplication-header h1 { margin-bottom: 4px; }
.client-deduplication-manual { width: 100%; max-width: none; margin-top: 18px; }
.client-deduplication-workspace { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; margin: 0; }
.client-deduplication-dialog .modal-header[data-sticky] { margin: -16px -18px 0; padding-inline: 18px; }
.client-deduplication-dialog .modal-header p { margin: 3px 0 0; }
.client-deduplication-selector,
.client-deduplication-accounts,
.client-deduplication-wallet,
.client-deduplication-impact,
.client-deduplication-blockers,
.client-deduplication-confirm { margin: 0; }
.client-deduplication-section-heading { margin-bottom: 14px; }
.client-deduplication-section-heading h2 { margin: 0 0 4px; }
.client-deduplication-section-heading p { margin: 0; color: var(--muted); }
.client-deduplication-section-heading--wide p { max-width: none; }
.client-deduplication-pickers {
    display: grid; grid-template-columns: minmax(0, 1fr) 28px minmax(0, 1fr) auto;
    align-items: end; gap: 12px;
}
.client-deduplication-direction {
    display: grid; min-height: var(--control-h); place-items: center;
    color: var(--muted); font-size: 20px;
}
.client-deduplication-comparison {
    min-width: 0; overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card);
}
.client-deduplication-comparison > .client-deduplication-section-heading { padding: 18px 18px 0; }
.client-deduplication-table { margin: 0; border: 0; border-radius: 0; }
.client-deduplication-table th:first-child { width: 22%; }
.client-deduplication-table td { width: 39%; padding: 0; }
.client-deduplication-choice {
    display: flex; min-height: 48px; align-items: center; gap: 10px; margin: 0; padding: 10px 12px;
    color: var(--ink); font-weight: 600; cursor: pointer;
}
.client-deduplication-choice:hover { background: var(--hover); }
.client-deduplication-choice:has(input:checked) { background: var(--brand-tint); }
.client-deduplication-choice input { flex: 0 0 auto; margin: 0; }
.client-deduplication-choice span { min-width: 0; overflow-wrap: anywhere; }
.client-deduplication-account-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.client-deduplication-account {
    display: flex; align-items: flex-start; gap: 10px; margin: 0; padding: 12px;
    border: 1px solid var(--border); border-radius: var(--radius-sm); cursor: pointer;
}
.client-deduplication-account:hover { background: var(--hover); }
.client-deduplication-account:has(input:checked) { border-color: var(--brand); background: var(--brand-tint); }
.client-deduplication-account input { margin: 3px 0 0; }
.client-deduplication-account span { display: grid; gap: 2px; }
.client-deduplication-account small { color: var(--muted); }
.client-deduplication-wallet-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.client-deduplication-wallet-option {
    display: flex; align-items: flex-start; gap: 10px; min-width: 0; margin: 0; padding: 12px;
    border: 1px solid var(--border); border-radius: var(--radius-sm); cursor: pointer;
}
.client-deduplication-wallet-option:hover { background: var(--hover); }
.client-deduplication-wallet-option:has(input:checked) { border-color: var(--brand); background: var(--brand-tint); }
.client-deduplication-wallet-option input { flex: 0 0 auto; margin: 3px 0 0; }
.client-deduplication-wallet-option span { display: grid; min-width: 0; gap: 2px; }
.client-deduplication-wallet-option strong,
.client-deduplication-wallet-option small { overflow-wrap: anywhere; }
.client-deduplication-wallet-option small { color: var(--muted); }
.client-deduplication-balance {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 3px 18px;
    margin-bottom: 10px; padding: 12px; border: 1px solid var(--border);
    border-radius: var(--radius-sm); background: var(--surface-2);
}
.client-deduplication-balance strong { font-variant-numeric: tabular-nums; }
.client-deduplication-balance small { grid-column: 1 / -1; color: var(--muted); }
.client-deduplication-impact-list {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 24px;
    margin: 0; padding: 0; list-style: none;
}
.client-deduplication-impact-list li {
    display: flex; justify-content: space-between; gap: 16px; padding: 9px 0;
    border-bottom: 1px solid var(--border);
}
.client-deduplication-impact-list strong { font-variant-numeric: tabular-nums; }
.client-deduplication-blockers { border-color: var(--danger-border); background: var(--danger-soft); }
.client-deduplication-blockers h2 { margin-top: 0; color: var(--err); }
.client-deduplication-blockers p { margin: 0; }
.client-deduplication-blockers ul { margin-bottom: 0; }
.client-deduplication-confirm textarea { resize: vertical; }
.client-deduplication-confirmation {
    display: flex; flex-direction: row; align-items: flex-start; gap: 10px; margin-top: 14px; font-weight: 600;
}
.client-deduplication-confirmation input { margin-top: 3px; }
.client-deduplication-confirmation span { min-width: 0; color: var(--ink); overflow-wrap: anywhere; }
.client-duplicate-queue {
    overflow: hidden; margin-top: 18px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card);
}
.client-duplicate-queue__header {
    display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; padding: 18px;
}
.client-duplicate-queue__header .client-deduplication-section-heading {
    flex: 1 1 auto; min-width: 0; margin: 0;
}
.client-duplicate-queue__header h2 > span {
    display: inline-flex; min-width: 25px; min-height: 25px; align-items: center; justify-content: center;
    margin-left: 5px; padding: 2px 7px; border-radius: 999px; background: var(--surface-2);
    color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; vertical-align: 2px;
}
.client-duplicate-filter {
    display: grid; grid-template-columns: minmax(180px, 240px) auto; gap: 5px 8px; flex: 0 0 auto; margin: 0;
}
.client-duplicate-filter label { grid-column: 1 / -1; margin: 0; }
.client-duplicate-filter select { min-height: var(--control-h); margin: 0; }
.client-duplicate-queue__table-wrap { width: 100%; border-top: 1px solid var(--border); }
table.grid.client-duplicate-queue__table {
    min-width: 980px; margin: 0; border: 0; border-radius: 0; table-layout: fixed; box-shadow: none;
}
table.grid.client-duplicate-queue__table th { padding: 10px 16px; }
table.grid.client-duplicate-queue__table td {
    height: 96px; padding: 12px 16px; vertical-align: middle;
}
.client-duplicate-signals { display: grid; justify-items: start; gap: 6px; }
.client-duplicate-signals > div {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 6px; min-width: 0;
}
.client-duplicate-signals strong { font-size: 13px; }
.client-duplicate-signals small { color: var(--muted); overflow-wrap: anywhere; }
.client-duplicate-confidence {
    display: inline-flex; padding: 3px 7px; border-radius: 999px; font-size: 12px; font-weight: 700;
}
.client-duplicate-confidence--high { color: var(--ok-ink); background: var(--ok-bg); }
.client-duplicate-confidence--medium { color: var(--warn); background: var(--warn-soft); }
.client-duplicate-card { display: grid; align-content: center; justify-items: start; gap: 5px; min-width: 0; }
.client-duplicate-card__title { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 7px; min-width: 0; }
.client-duplicate-card__title a { color: var(--ink); font-weight: 750; overflow-wrap: anywhere; }
.client-duplicate-card__title span { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.client-duplicate-card__meta { display: flex; flex-wrap: wrap; gap: 3px 10px; color: var(--muted); font-size: 12px; }
.client-duplicate-card__meta span { overflow-wrap: anywhere; }
.client-duplicate-card__archived {
    display: inline-flex; padding: 2px 6px; border-radius: 999px; background: var(--surface-2);
    color: var(--muted); font-size: 11px; font-weight: 700;
}
table.grid.client-duplicate-queue__table td.client-duplicate-queue__action {
    text-align: right; vertical-align: middle; white-space: nowrap;
}
.client-duplicate-queue__empty { padding: 28px 18px; border-top: 1px solid var(--border); text-align: center; }
.client-duplicate-queue__empty p { margin: 5px 0 0; color: var(--muted); }
@media (max-width: 900px) {
    .client-duplicate-queue__header { align-items: stretch; flex-direction: column; gap: 14px; }
    .client-duplicate-filter { grid-template-columns: minmax(0, 1fr) auto; width: 100%; }
    .client-deduplication-pickers { grid-template-columns: 1fr; }
    .client-deduplication-direction { min-height: 16px; transform: rotate(90deg); }
    .client-deduplication-pickers > .hui-button { width: 100%; }
    .client-deduplication-account-list,
    .client-deduplication-wallet-list,
    .client-deduplication-impact-list { grid-template-columns: 1fr; }
    .client-deduplication-balance { grid-template-columns: 1fr; }
    .client-deduplication-balance small { grid-column: auto; }
}
@media (max-width: 640px) {
    .clients-page-actions { width: 100%; flex-wrap: wrap; }
    .clients-page-actions .hui-button { flex: 1 1 auto; }
    .client-deduplication-table { min-width: 680px; }
    .client-duplicate-filter { grid-template-columns: 1fr; }
    .client-duplicate-filter label { grid-column: auto; }
    .client-duplicate-filter .hui-button { width: 100%; }
}
.clients-container .clients-table-wrap { width: 100%; }
.clients-table { min-width: 100%; table-layout: fixed; }
.staff-table { min-width: 1180px; table-layout: fixed; }
.users-table-wrap { width: 100%; }
.users-table { min-width: 1180px; table-layout: fixed; }
.users-table td { overflow-wrap: anywhere; }

.groups-table { min-width: 1320px; }
.passes-container .table-scroll { width: 100%; }
.client-passes-container .table-scroll { width: 100%; }
.client-passes-table { width: 100%; min-width: 1420px; }
.client-passes-table .client-pass-sale-date { white-space: nowrap; font-variant-numeric: tabular-nums; }
.catalog-tabs {
    display: flex;
    align-items: stretch;
    gap: 24px;
    margin: -4px 0 18px;
    overflow-x: auto;
    border-bottom: 1px solid var(--border);
    scrollbar-width: thin;
}
.catalog-tabs > a,
.catalog-tabs > button {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    min-height: 44px;
    justify-content: center;
    gap: 7px;
    padding: 10px 1px 9px;
    border: 0;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    background: transparent;
    color: var(--muted);
    font: inherit;
    font-weight: 700;
    line-height: 1.5;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}
.catalog-tabs > a:hover,
.catalog-tabs > button:hover { color: var(--ink); }
.catalog-tabs > .active,
.catalog-tabs > [aria-selected="true"] { border-bottom-color: var(--brand); color: var(--brand-ink); }
.payroll-task-tabs { margin-bottom: 0; }
.catalog-tabs-toolbar {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    min-width: 0;
    margin: -4px 0 18px;
}
.catalog-tabs-toolbar > .catalog-tabs {
    flex: 0 1 auto;
    min-width: 0;
    margin: 0;
}
.catalog-tabs-toolbar > .hui-button {
    flex: 0 0 auto;
    margin-top: 2px;
}
.catalog-tabs-toolbar > .hui-button:first-of-type { margin-left: auto; }
/* :first-of-type считает <button> и <a> порознь: кнопка окна рядом со
   ссылкой «Новая рассылка» получала бы свой auto-отступ и уезжала в середину
   полосы. Все кнопки после первой стоят вплотную к ней. */
.catalog-tabs-toolbar > .hui-button ~ .hui-button { margin-left: 0; }
.catalog-tabs-toolbar.module-workspace-toolbar { align-items: center; flex-wrap: wrap; }
@media (max-width: 640px) {
    .catalog-tabs.module-workspace-tabs { flex-wrap: wrap; column-gap: 24px; row-gap: 0; }
}
.sales-workspace-container .catalog-tabs-toolbar { align-items: center; flex-wrap: wrap; }
.workspace-card > .client-card-pass-section { margin-top: 20px; }
.workspace-card .client-card-pass-details > div { min-width: 0; }
.workspace-card .client-card-pass-details dt { color: var(--muted); font-size: 12px; }
.workspace-card .client-card-pass-details dd { margin: 5px 0 0; overflow-wrap: anywhere; }
.workspace-card .actions { flex-wrap: wrap; }
.workspace-card .table-scroll { max-width: 100%; }
.catalog-tabs-toolbar.payroll-toolbar { align-items: center; flex-wrap: wrap; }
.payroll-role-select { display: flex; align-items: center; gap: 8px; margin: 0; }
.payroll-role-select label { margin: 0; }
.payroll-role-select select { min-height: 44px; margin: 0; }
.payroll-role-select__fallback { display: none; }
.payroll-adjustment-cell { display: flex; align-items: baseline; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
.payroll-adjustment-details { display: inline-flex; }
.payroll-adjustment-details__list { display: grid; gap: 12px; margin: 0; padding: 0; list-style: none; text-align: left; }
.payroll-adjustment-details__list li { display: block; white-space: normal; overflow-wrap: anywhere; }
.payroll-adjustment-details__note { margin: 0 0 12px; color: var(--muted); white-space: normal; }
/* На шаге ожидания в ячейке две кнопки: на узком экране они переносятся,
   а не растягивают колонку действий. */
.payroll-approval-actions { white-space: nowrap; }
.payroll-approval-actions form { display: inline-block; margin: 0 6px 4px 0; }
/* Выплата закрыла долг не того месяца, которым её отметили: до этой подписи
   две одинаковые строки истории выглядели повтором, и деньги выдавали второй раз. */
.payroll-credited-elsewhere { color: var(--warn); font-weight: 600; }
.teacher-payroll-detail-modal .form-card { width: 100%; max-width: none; }
.app-shell .container.class-templates-container {
    width: 100%;
    max-width: none;
    margin: 0;
    padding: 10px 12px 44px;
}
.schedule-template-shell { min-height: 0; }
.schedule-template-toolbar {
    grid-template-columns: minmax(190px, .7fr) minmax(180px, 1fr) minmax(0, 400px);
}
.schedule-template-toolbar-filters { grid-template-columns: minmax(180px, 320px); }
.schedule-template-actions {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    width: min(400px, 100%);
    min-width: 0;
    gap: 10px;
    justify-self: end;
}
@media (max-width: 980px) {
    .schedule-template-toolbar {
        grid-template-columns: minmax(0, 1fr) minmax(0, 400px);
        grid-template-areas:
            "period actions"
            "filters filters";
    }
    .schedule-template-toolbar-filters {
        grid-template-columns: minmax(0, 1fr);
    }
}
@media (max-width: 700px) {
    .schedule-template-toolbar {
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas:
            "period"
            "filters"
            "actions";
    }
    .schedule-template-toolbar-filters {
        grid-template-columns: minmax(0, 1fr);
    }
    .schedule-template-actions {
        width: 100%;
        min-width: 0;
        justify-self: stretch;
    }
    .schedule-template-actions button { max-width: 100%; }
}
.schedule-template-shell .crm-schedule-caption { color: var(--ink); }
.schedule-template-action-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 100%;
    height: 36px;
    padding: 0 14px;
    font-size: 14px;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
    text-decoration: none;
}
.schedule-template-board {
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-inline: contain;
}
.schedule-template-empty-grid {
    width: 100%;
    min-width: 0;
}
.schedule-template-empty-grid .crm-schedule-week-head,
.schedule-template-empty-grid .crm-schedule-week-row {
    grid-template-columns: 84px repeat(7, minmax(0, 1fr));
}
.schedule-template-empty-row,
.schedule-template-empty-row .crm-schedule-week-cell { min-height: 72px; }
.schedule-template-empty-row .crm-schedule-time-cell {
    color: var(--muted);
    font-size: 12px;
    text-align: center;
}
@media (max-width: 1180px) {
    .schedule-template-empty-grid { min-width: 1050px; }
    .schedule-template-empty-grid .crm-schedule-week-head,
    .schedule-template-empty-grid .crm-schedule-week-row {
        grid-template-columns: 78px repeat(7, minmax(138px, 1fr));
    }
}
.schedule-template-card {
    border-left: 3px solid var(--brand);
    background: var(--brand-tint);
    outline-offset: -2px;
}
.schedule-template-card:focus-visible {
    outline: 3px solid var(--brand);
    outline-offset: -3px;
}
.client-drawer.class-template-drawer {
    width: min(720px, calc(100vw - 32px));
    min-height: min(380px, calc(100dvh - var(--dialog-top) - var(--dialog-bottom)));
}
.schedule-template-entry-panel .client-panel-header p { margin: 0; }
.schedule-template-entry-form { margin: 0; }
.schedule-template-entry-fields {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
}
.schedule-template-entry-fields label:first-child,
.schedule-template-entry-fields label:nth-child(4) { grid-column: 1 / -1; }
.schedule-template-entry-fields input,
.schedule-template-entry-fields select { width: 100%; }
.schedule-template-entry-actions { justify-content: flex-start; flex-wrap: wrap; margin-top: 18px; }
.schedule-template-entry-actions--editing .schedule-template-entry-cancel { margin-left: auto; }
.schedule-template-entry-readonly {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    margin: 0;
}
.schedule-template-entry-readonly > div {
    min-width: 0;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.schedule-template-entry-readonly dt { color: var(--muted); font-size: 12px; }
.schedule-template-entry-readonly dd { margin: 4px 0 0; color: var(--ink); font-weight: 700; }
.schedule-template-delete-form {
    margin: 0;
}
.schedule-template-publish-form { display: grid; gap: 16px; }
.schedule-template-publish-form .modal-header { margin-bottom: 0; }
.schedule-template-publish-form .modal-header p { margin: 5px 0 0; }
.schedule-template-publish-form input[type="week"] { width: 100%; }
.schedule-template-publish-errors {
    padding: 12px 14px;
    border: 1px solid var(--danger-border);
    border-radius: var(--radius-sm);
    background: var(--danger-soft);
    color: var(--ink);
}
.schedule-template-publish-errors ol { margin: 8px 0 0; padding-left: 22px; }
.schedule-template-publish-errors li + li { margin-top: 6px; }
.schedule-template-publish-warning {
    padding: 12px 14px;
    border: 1px solid var(--warn-border);
    border-radius: var(--radius-sm);
    background: var(--warn-soft);
    color: var(--ink);
}
.schedule-template-publish-warning p { margin: 6px 0 0; }
.schedule-template-publish-scope {
    padding: 12px 14px;
    border: 1px solid var(--info-border);
    border-radius: var(--radius-sm);
    background: var(--info-soft);
    color: var(--ink);
}
.schedule-template-publish-scope ul { margin: 6px 0 0; padding-left: 20px; }
.schedule-template-publish-scope ul.schedule-template-publish-branches { list-style: none; padding-left: 0; display: grid; gap: 6px; }
.schedule-template-publish-branches li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; font-size: 13px; }
.schedule-template-publish-warning ul { margin: 6px 0 0; padding-left: 20px; }
.schedule-template-publish-scope p { margin: 6px 0 0; }
.schedule-template-publish-actions { margin-top: 0; }
.class-template-reference { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.class-template-reference a { font-size: 13px; font-weight: 700; }
@media (max-width: 760px) {
    .schedule-template-entry-fields,
    .schedule-template-entry-readonly { grid-template-columns: 1fr; }
    .schedule-template-entry-fields label:first-child,
    .schedule-template-entry-fields label:nth-child(4) { grid-column: auto; }
    .client-drawer.class-template-drawer {
        --dialog-top: 8px;
        --dialog-bottom: 8px;
        width: calc(100vw - 16px);
        height: calc(100dvh - var(--dialog-top) - var(--dialog-bottom));
    }
    .schedule-template-publish-actions { align-items: stretch; flex-direction: column-reverse; }
    .schedule-template-publish-actions button { width: 100%; }
}
@media (max-width: 560px) {
    .schedule-template-actions { grid-template-columns: 1fr; }
    .schedule-template-actions button { width: 100%; }
}
.access-page-header { align-items: flex-end; }
.access-page-header h1 { margin-bottom: 6px; }
.access-role-toolbar {
    display: grid;
    grid-template-columns: minmax(220px, 300px) minmax(280px, 1fr) auto;
    align-items: end;
    gap: 18px;
    margin-bottom: 18px;
    padding: 16px 18px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
}
.access-role-toolbar > label { margin: 0; }
.access-role-context {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 10px;
    min-width: 0;
    padding-bottom: 2px;
}
.access-role-context strong { flex-basis: 100%; }
.access-role-context > span:not(.tag) {
    overflow: hidden;
    max-width: 100%;
    color: var(--muted);
    font-size: 13px;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.access-role-groups {
    display: grid;
    gap: 10px;
}
.access-role-group {
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
}
.access-role-group > summary {
    display: flex;
    min-height: 50px;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    color: var(--ink);
    cursor: pointer;
    list-style: none;
    transition: background-color var(--dur-fast) ease;
}
.access-role-group > summary::-webkit-details-marker { display: none; }
.access-role-group > summary:hover { background: var(--hover); }
.access-role-group > summary:focus-visible {
    outline: var(--ring-w) solid var(--ring);
    outline-offset: calc(-1 * var(--ring-w));
}
.access-role-group > summary::after {
    width: 7px;
    height: 7px;
    flex: 0 0 7px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    opacity: .55;
    content: "";
    transform: translateY(-2px) rotate(45deg);
    transition: transform var(--dur-fast) ease;
}
.access-role-group[open] > summary {
    border-bottom: 1px solid var(--border);
    background: var(--surface-2);
}
.access-role-group[open] > summary::after { transform: translateY(2px) rotate(225deg); }
.access-role-group-summary > span {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 14px;
    font-weight: 750;
}
.access-role-group-summary > small {
    flex: 0 0 auto;
    color: var(--muted);
    font-size: 12px;
    font-weight: 600;
}
.access-role-group-table-wrap { border: 0; border-radius: 0; }
table.grid.access-compact-table {
    min-width: 680px;
    border: 0;
    border-radius: 0;
}
.access-compact-table th:first-child,
.access-compact-table td:first-child { width: auto; min-width: 260px; }
.access-compact-table .access-permission-column,
.access-compact-table .access-permission-cell { width: 130px; text-align: center; }
.access-compact-table tbody tr:last-child td { border-bottom: 0; }
.access-permission-check {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    margin: 0;
    color: var(--muted);
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
}
.access-permission-check input { margin: 0; }
.role-directory-wrap {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
table.grid.role-directory-table { min-width: 920px; border: 0; border-radius: 0; }
.role-directory-table .role-description { color: var(--muted); }
.access-settings-form {
    display: grid;
    gap: 18px;
}
.access-section {
    display: grid;
    gap: 14px;
    scroll-margin-top: 20px;
}
.access-section-heading {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 0 2px 10px;
    border-bottom: 2px solid var(--brand-border);
}
.access-section-heading h2,
.access-module-group-heading h3 { margin: 0; }
.access-section-heading h2 { font-size: 22px; }
.access-section-heading > span {
    color: var(--faint);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
}
.access-module-groups {
    display: grid;
    gap: 14px;
}
.access-module-group {
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
    box-shadow: var(--shadow);
}
.access-module-group-heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: 48px;
    padding: 11px 14px;
    background: var(--surface-2);
}
.access-module-group-heading h3 { font-size: 15px; }
.access-module-group-heading > span {
    min-width: 24px;
    padding: 3px 7px;
    border-radius: 999px;
    background: var(--surface-raised);
    color: var(--muted);
    font-size: 12px;
    font-weight: 700;
    text-align: center;
}
table.grid.access-table {
    min-width: 1180px;
    border: 0;
    border-radius: 0;
}
table.grid.access-admin-table { min-width: 900px; }
.access-table th:first-child,
.access-table td:first-child { min-width: 210px; }
.access-table tbody tr:last-child td { border-bottom: 0; }
.access-table .checkline { white-space: nowrap; }
.access-module-note {
    display: inline-flex;
    margin: 5px 4px 0 0;
    padding: 2px 6px;
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--faint);
    font-size: 11px;
    line-height: 1.4;
}
.access-module-note.locked { background: var(--warn-bg); color: var(--warn); }
.access-intro-card { margin-bottom: 22px; }
.access-save-button { justify-self: center; margin-top: 2px; }
.access-save-actions {
    position: sticky;
    bottom: 12px;
    z-index: 2;
    inline-size: max-content;
    justify-self: end;
    margin: -4px 0 0 auto;
    padding: 6px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--surface-raised) 92%, transparent);
    box-shadow: var(--shadow);
    backdrop-filter: blur(8px);
}
@media (max-width: 760px) {
    .access-page-header { align-items: stretch; }
    .access-role-toolbar { grid-template-columns: 1fr; align-items: stretch; gap: 12px; }
    .access-role-context > span:not(.tag) { white-space: normal; }
    .access-role-group > summary { align-items: flex-start; }
    .access-role-group-summary > small { display: none; }
}
.catalog-tab-count {
    min-width: 20px;
    padding: 2px 6px;
    border-radius: 999px;
    background: var(--danger-soft);
    color: var(--err);
    font-size: 11px;
    line-height: 1.35;
    text-align: center;
}
.passes-table { width: 100%; min-width: 1510px; table-layout: auto; }
.passes-table .pass-type-description {
    display: block;
    white-space: nowrap;
}
.passes-table td { overflow-wrap: anywhere; }
.pass-types-table { width: 100%; min-width: 1120px; }
#pass-drawer {
    width: min(1560px, calc(100vw - 24px));
    height: auto;
}
#pass-drawer .client-drawer-body {
    height: auto;
}
#pass-drawer .client-panel { padding: 14px 18px 18px; }
#pass-drawer .client-panel-header {
    margin: -14px -18px 12px;
    padding: 14px 18px 10px;
}
#pass-drawer .pass-edit-form {
    margin-bottom: 12px;
    padding: 14px;
}
#pass-drawer .pass-edit-form .form-row { margin-bottom: 8px; }
#pass-drawer .pass-edit-form textarea { min-height: 72px; }
.pass-visits-field .pass-field-title {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    white-space: nowrap;
}
.promo-codes-table { width: 100%; min-width: 1360px; }
.promo-form-sections {
    display: grid;
}
.promo-form-section {
    display: grid;
    grid-template-columns: minmax(160px, .42fr) minmax(0, 1fr);
    gap: 28px;
    padding: 24px 0;
    border-top: 1px solid var(--border);
}
.promo-form-section:first-child {
    padding-top: 0;
    border-top: 0;
}
.promo-form-section-head h2 {
    margin: 0 0 5px;
    font-size: 16px;
    line-height: 1.3;
}
.promo-form-section-head p {
    margin: 0;
    color: var(--muted);
    font-size: 12px;
    line-height: 1.5;
}
.promo-form-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    min-width: 0;
}
.promo-form-grid > label {
    min-width: 0;
}
.promo-form-grid input,
.promo-form-grid select,
.promo-form-grid textarea {
    width: 100%;
    min-width: 0;
}
.promo-form-wide {
    grid-column: 1 / -1;
}
.promo-checkline {
    align-self: end;
    min-height: 42px;
    padding-bottom: 10px;
}
.promo-role-picker {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}
.promo-role-picker legend {
    margin-bottom: 8px;
    padding: 0;
    color: var(--muted);
    font-size: 13px;
}
.promo-role-options {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 24px;
}
.promo-condition-builder,
.promo-condition-list {
    display: grid;
    gap: 14px;
    min-width: 0;
}
.promo-condition-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}
.promo-condition-toolbar p,
.promo-condition-empty,
.promo-condition-description {
    margin: 0;
    color: var(--muted);
    font-size: 12px;
    line-height: 1.5;
}
.promo-condition-row {
    display: grid;
    gap: 10px;
    padding: 14px 0;
    border-top: 1px solid var(--border);
}
.promo-condition-row:last-child {
    border-bottom: 1px solid var(--border);
}
.promo-condition-row.is-scope-invalid {
    padding-inline-start: 10px;
    border-inline-start: 2px solid var(--danger);
}
.promo-condition-scope-error {
    padding: 10px 12px;
    border: 1px solid var(--danger-border);
    border-radius: var(--radius-sm);
    background: var(--danger-soft);
}
.promo-condition-main {
    display: grid;
    grid-template-columns: minmax(220px, 1fr) auto;
    align-items: end;
    gap: 12px;
}
.promo-condition-main select,
.promo-condition-fields input {
    width: 100%;
    min-width: 0;
}
.promo-condition-remove {
    margin-bottom: 1px;
}
.promo-condition-description:empty {
    display: none;
}
.promo-condition-parameters {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 190px));
    gap: 12px;
}
.promo-condition-fields {
    min-width: 0;
}
.promo-unique-codes {
    margin-top: 24px;
    border-top: 1px solid var(--border);
}
.promo-unique-body {
    display: grid;
    gap: 14px;
    align-content: start;
    min-width: 0;
}
.promo-unique-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 28px;
    margin: 0;
}
.promo-unique-stats dt {
    color: var(--muted);
    font-size: 12px;
}
.promo-unique-stats dd {
    margin: 2px 0 0;
    font-size: 20px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.promo-unique-batches {
    width: 100%;
}
.promo-unique-links {
    white-space: nowrap;
    text-align: right;
}
.promo-unique-links a + a {
    margin-left: 12px;
}
.promo-unique-dialog-form { display: grid; gap: 14px; }
.promo-unique-dialog-form .modal-header { margin-bottom: 0; }
.promo-unique-dialog-form label { gap: 7px; }
.promo-unique-dialog-form label small { line-height: 1.45; }
@media (max-width: 820px) {
    .promo-form-section {
        grid-template-columns: 1fr;
        gap: 14px;
    }
}
@media (max-width: 560px) {
    .promo-form-grid,
    .promo-condition-parameters {
        grid-template-columns: 1fr;
    }
    .promo-condition-toolbar {
        align-items: flex-start;
        flex-direction: column;
    }
    .promo-condition-main {
        grid-template-columns: 1fr;
        align-items: stretch;
    }
    .promo-condition-remove {
        justify-self: start;
    }
}
.certificates-table { width: 100%; min-width: 100%; }
.class-bookings-table { min-width: 1320px; }
.class-queue-table { min-width: 1180px; }
.sales-table { min-width: 1440px; }
.sale-promotion-cell { min-width: 180px; max-width: 240px; }
.sale-promotion-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; margin-top: 3px; }
.sale-promotion-reason {
    display: -webkit-box;
    max-width: 26ch;
    margin-top: 3px;
    overflow: hidden;
    overflow-wrap: anywhere;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
}
.payments-table { min-width: 1180px; }
.locations-table-wrap { width: 100%; }
.locations-table { width: 100%; min-width: 100%; table-layout: fixed; }
.locations-table td { overflow-wrap: anywhere; vertical-align: top; }
.shelf-products-table-wrap { --table-min: 1280px; width: 100%; }
.shelf-products-container .filterbar .hui-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
}
.filterbar-inline > label.shelf-products-filter-toggle {
    flex: 0 0 auto;
    min-height: var(--control-h);
    flex-direction: row;
    align-items: center;
    align-self: flex-end;
    gap: 8px;
    color: var(--ink);
    white-space: nowrap;
}
.shelf-products-table { width: 100%; table-layout: fixed; }
.shelf-products-table td { overflow-wrap: anywhere; vertical-align: top; }
.shelf-sale-form { display: grid; gap: 16px; }
.shelf-sale-form .modal-header { align-items: flex-start; margin-bottom: 0; }
.shelf-sale-form .modal-header p { margin: 5px 0 0; }
.shelf-sale-client-picker { display: grid; gap: 5px; min-width: 0; }
.shelf-sale-fields {
    display: grid;
    grid-template-columns: minmax(120px, .65fr) minmax(220px, 1.35fr);
    gap: 12px;
}
.shelf-sale-fields input,
.shelf-sale-fields select { width: 100%; min-width: 0; }
.shelf-sale-actions { margin-top: 0; }
@media (max-width: 640px) {
    .filterbar-inline > label.shelf-products-filter-toggle {
        flex: 0 0 auto;
        min-height: auto;
        align-self: center;
    }
    .shelf-sale-fields { grid-template-columns: 1fr; }
}
.field-hint {
    display: block;
    margin-top: 4px;
    color: var(--muted);
    font-size: 11px;
    line-height: 1.4;
}
/* Карточка была центрирована по вертикали. Пока высота была прибита
   числом, это не чувствовалось. Как только высоту стало задавать содержимое,
   центрирование показало себя с худшей стороны: при переключении вкладок
   высота меняется, и у центрированного блока едут оба края сразу — шапка
   уходит из-под курсора вместе с вкладками, по которым только что кликнули.
   Теперь верх прибит к --dialog-top, двигается только нижний край. */
.client-drawer {
    position: fixed;
    inset: var(--dialog-top) auto auto 50%;
    transform: translateX(-50%);
    width: min(1120px, calc(100vw - 48px));
    max-width: none;
    height: auto;
    max-height: calc(100vh - var(--dialog-top) - var(--dialog-bottom));
    max-height: calc(100dvh - var(--dialog-top) - var(--dialog-bottom));
    margin: 0;
    border-radius: var(--radius-md);
    overflow: hidden;
}
.client-drawer::backdrop { background: var(--scrim); backdrop-filter: blur(2px); }
.client-drawer-body {
    max-height: calc(100vh - var(--dialog-top) - var(--dialog-bottom));
    max-height: calc(100dvh - var(--dialog-top) - var(--dialog-bottom));
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-gutter: stable;
    background: var(--bg);
}
/* Каркас вместо надписи «Загрузка…» по центру пустого окна: панель сразу
   занимает свой размер, и содержимое не прыгает, когда ответ приходит.
   Правило одно, поэтому его получают все тридцать мест, где панель
   подгружается через htmx, без правки шаблонов. */
.drawer-loading {
    display: grid;
    gap: 14px;
    align-content: start;
    min-height: 240px;
    padding: 22px 20px;
    color: var(--muted);
    font-size: 13px;
    font-weight: 600;
}
.drawer-loading::after {
    content: "";
    display: block;
    min-height: 176px;
    background:
        linear-gradient(var(--border) 0 0) 0 0 / 42% 15px no-repeat,
        linear-gradient(var(--border) 0 0) 0 32px / 100% 58px no-repeat,
        linear-gradient(var(--border) 0 0) 0 106px / 88% 13px no-repeat,
        linear-gradient(var(--border) 0 0) 0 131px / 96% 13px no-repeat,
        linear-gradient(var(--border) 0 0) 0 156px / 62% 13px no-repeat;
    animation: skeleton-pulse 1.4s ease-in-out infinite;
}
@keyframes skeleton-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .5; }
}
.client-panel { padding: 18px 20px 30px; }
.client-panel-header {
    position: sticky;
    top: 0;
    z-index: var(--z-raised);
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin: -18px -20px 18px;
    padding: 18px 20px 14px;
    /* Холст шторки сквозь лёгкое размытие: шапка липнет поверх прокрутки. */
    background: color-mix(in srgb, var(--bg) 96%, transparent);
    border-bottom: 1px solid var(--border);
    backdrop-filter: blur(6px);
}
.client-panel-header h1 { margin: 4px 0 8px; }
.client-panel-kicker { color: var(--faint); font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
.client-drawer-close { flex: 0 0 auto; }
.class-panel-header-actions {
    display: flex;
    flex: 0 1 auto;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 8px;
    min-width: 0;
}
.class-panel-header-actions form { margin: 0; }
.class-panel-header-actions .hui-button {
    white-space: nowrap;
}
.class-panel-title { min-width: 0; }
/* Название и преподаватель в одной строке: занятие узнают по паре «группа +
   кто ведёт». Имя набрано тише заголовка, но тем же чернильным цветом — в
   приглушённой нижней строке оно терялось. */
.class-panel-heading {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 10px;
    margin: 4px 0 6px;
}
.class-panel-heading h1 { margin: 0; }
.class-panel-teacher {
    color: var(--ink);
    font-size: 15px;
    font-weight: 500;
    overflow-wrap: anywhere;
}
.class-panel-heading .tag { align-self: center; }
.client-edit-form { margin-bottom: 18px; }
/* Опасное действие остаётся справа в общей строке, а связанная отдельная
   форма сохраняет валидный HTML и подтверждение удаления. */
.staff-profile-actions { flex-wrap: wrap; }
.staff-profile-actions > .staff-delete-action { margin-inline-start: auto; }
.staff-delete-form { display: none; }
.client-edit-form h2 { margin-top: 0; }
.client-edit-form .form-row label { flex: 1 1 190px; }
.client-edit-form .checkline { flex: 0 0 auto; }
/* Ряд действий карточки справочника (_catalog_panel.html): «В архив» и
   «Удалить» стоят в том же ряду, что «Закрыть» и «Сохранить», но в правом
   углу — соседство с «Сохранить» приглашало промахнуться. Второе такое
   действие встаёт вплотную к первому, а не делит с ним пустое место. */
.catalog-edit-actions { flex-wrap: wrap; }
.catalog-edit-actions > .catalog-delete-action { margin-inline-start: auto; }
.catalog-edit-actions > .catalog-delete-action ~ .catalog-delete-action { margin-inline-start: 0; }
.catalog-delete-note {
    flex: 1 1 240px;
    min-width: 0;
    color: var(--muted);
    font-size: 0.86rem;
    line-height: 1.35;
}
.class-summary-strip {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    margin-bottom: 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card);
    overflow: hidden;
}
.class-summary-item {
    display: flex;
    align-items: baseline;
    gap: 7px;
    min-width: 0;
    padding: 9px 12px;
    white-space: nowrap;
}
.class-summary-item + .class-summary-item { border-left: 1px solid var(--border); }
.class-summary-item > span {
    color: var(--muted);
    font-size: 12px;
    font-weight: 700;
}
.class-summary-item > strong {
    color: var(--ink);
    font-size: 18px;
    font-variant-numeric: tabular-nums;
}
.class-summary-item > small {
    min-width: 0;
    overflow: hidden;
    color: var(--faint);
    font-size: 11px;
    text-overflow: ellipsis;
}
.class-edit-form > h2 {
    margin: 0 0 12px;
    font-size: 18px;
}
.class-form { display: grid; gap: 16px; }
.class-create-form { gap: 0; }
.class-form .plain-fieldset { display: grid; gap: 16px; }
.class-kind-fieldset > legend {
    margin-bottom: 8px;
    color: var(--ink);
    font-size: 14px;
    font-weight: 700;
}
.class-kind-switch {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    width: min(100%, 420px);
    padding: 3px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.class-kind-switch label { position: relative; min-width: 0; cursor: pointer; }
.class-kind-switch input { position: absolute; opacity: 0; pointer-events: none; }
.class-kind-switch span {
    display: flex;
    min-height: 38px;
    align-items: center;
    justify-content: center;
    padding: 8px 12px;
    border: 1px solid transparent;
    border-radius: calc(var(--radius-sm) - 2px);
    color: var(--muted);
    font-size: 13px;
    font-weight: 650;
}
.class-kind-switch input:checked + span {
    border-color: var(--border);
    background: var(--card);
    color: var(--ink);
}
.class-kind-switch input:focus-visible + span { outline: 2px solid var(--brand); outline-offset: 2px; }
.class-kind-switch input:disabled + span { color: var(--faint); cursor: not-allowed; }
.class-format-fields { min-width: 0; }
.class-participant-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    margin-top: 14px;
}
.class-participant-grid > * { min-width: 0; }
.class-payment-total {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin-top: 14px;
    padding: 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.class-payment-total span { display: block; font-size: 13px; font-weight: 650; }
.class-payment-total small { display: block; margin-top: 3px; color: var(--muted); font-size: 12px; }
.class-payment-total output { font-size: 22px; font-weight: 750; font-variant-numeric: tabular-nums; white-space: nowrap; }
.class-notes { display: grid; gap: 6px; margin-top: 14px; }
.class-notes textarea { width: 100%; min-height: 64px; resize: vertical; }
.class-form-section {
    margin-bottom: 18px;
    min-width: 0;
}
.class-form .class-form-section { margin-bottom: 0; }
.class-form-section + .class-form-section {
    padding-top: 14px;
    border-top: 1px solid var(--border);
}
.class-create-form .class-form-section + .class-form-section {
    margin-top: 18px;
}
.class-form-section h3 {
    margin: 0 0 10px;
    color: var(--ink);
    font-size: 14px;
}
.class-form-grid {
    display: grid;
    gap: 12px;
    min-width: 0;
}
.class-form-grid-time { grid-template-columns: 1.15fr .85fr .85fr; }
.class-form-grid-location {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
    margin-top: 12px;
}
.class-form-grid-details { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.class-form-grid-details-inline { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.class-form-grid label { min-width: 0; }
.class-form-grid input,
.class-form-grid select,
.class-form-grid textarea {
    box-sizing: border-box;
    min-width: 0;
    width: 100%;
}
.class-form-actions {
    justify-content: flex-end;
    margin-top: 0;
    padding-top: 2px;
}
.class-form-actions > span {
    margin-right: auto;
    color: var(--muted);
    font-size: 12px;
}
.class-create-error { position: sticky; top: 74px; z-index: var(--z-raised); }
/* Итоги в форме продажи с карточки клиента. Клиентский checkout такой блок
   имел, касса — нет, и администратор называл цену, которой не видел. */
.client-pass-sale-total {
    margin: 0; padding: 12px 14px;
    border: 1px solid var(--brand-border); border-radius: var(--radius-md);
    background: var(--brand-tint);
}
.client-pass-sale-total-row { display: flex; justify-content: space-between; gap: 16px; padding: 3px 0; font-size: 14px; }
.client-pass-sale-total-row b { font-variant-numeric: tabular-nums; }
.client-pass-sale-total-row.total {
    margin-top: 6px; padding-top: 8px; border-top: 1px solid var(--brand-border);
    font-size: 16px; font-weight: 700;
}
.client-pass-sale-total-error { margin: 8px 0 0; }
.client-pass-sale-total-row.debt b { color: var(--warn); }

/* Ростер занятия: один список вместо «Записано» и «Посетило». Прежняя
   раскладка держала четыре секции с полосами по левому краю и правило order,
   которым отмеченные отжимались вниз, — при одном списке всё это не нужно. */
.class-roster-section {
    min-width: 0;
    margin-bottom: 14px;
    padding: 14px 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
}
.class-roster-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 4px;
}
.class-roster-head h2 { margin: 0; font-size: 16px; }
.class-roster-head > span { color: var(--muted); font-size: 13px; }

.class-roster { margin: 0; padding: 0; list-style: none; }
.class-roster-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) max-content max-content;
    align-items: center;
    gap: 8px 16px;
    padding: 9px 0;
    border-top: 1px solid var(--border);
}
.class-roster-row:first-child { border-top: 0; }
/* Отмеченные приглушены: строка сделана, глаз должен цепляться за
   оставшихся. Раньше отмеченные стояли первыми и в том же весе. */
.class-roster-row.is-marked .class-roster-person a,
.class-roster-row.is-marked .class-roster-person > span:first-child { color: var(--muted); }
.class-roster-row.is-quiet { padding: 7px 0; }
.class-roster-row--cancelled {
    grid-template-columns: minmax(180px, .75fr) minmax(300px, 1.25fr);
}

.class-roster-person { display: grid; min-width: 0; gap: 1px; }
/* Имя и значок абонемента идут одной строкой, телефон — под ними. */
.class-roster-name { display: flex; align-items: center; gap: 8px; min-width: 0; flex-wrap: wrap; }
.class-roster-when { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pass-badge,
.booking-source-badge {
    display: inline-flex;
    flex: 0 0 32px;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    line-height: 1;
    border-radius: 8px;
    cursor: help;
}
/* Значок в размер кнопок действий справа (32px): состояние абонемента читают
   с того же расстояния, что и строку целиком. */
.pass-badge svg,
.booking-source-badge svg {
    display: block;
    width: 32px;
    height: 32px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.pass-badge--ok { color: var(--ok); }
.pass-badge--warn { color: var(--warn); }
.pass-badge--none { color: var(--danger); }
/* Первое занятие: звезда рядом с абонементом, тон акцента, а не статуса.
   Закрашена, чтобы не теряться между контурными значками. */
.pass-badge--first { color: var(--brand); }
.pass-badge--first svg { fill: currentColor; stroke-width: 1.2; }
.booking-source-badge { color: var(--muted); }
.booking-source-badge--mobile-app,
.booking-source-badge--client-portal,
.booking-source-badge--schedule-widget { color: var(--brand); }
.pass-badge:focus-visible,
.booking-source-badge:focus-visible {
    outline: var(--ring-w) solid var(--ring);
    outline-offset: 1px;
}
.hover-detail { cursor: help; }
.hover-detail:focus-visible {
    outline: var(--ring-w) solid var(--ring);
    outline-offset: 2px;
}
/* Значки одного клиента стоят теснее, чем соседние поля строки. */
.class-roster-badges { display: inline-flex; align-items: center; flex: 0 0 auto; gap: 2px; }
.class-roster-person a { overflow-wrap: anywhere; }
.class-roster-phone { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }

.class-roster-status {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 7px;
    min-width: 132px;
    color: var(--muted);
    font-size: 13px;
}
.class-roster-status time { font-variant-numeric: tabular-nums; }
.class-roster-row--cancelled .class-roster-status {
    justify-content: flex-end;
    text-align: right;
}
.class-roster-row--cancelled .cancellation-status { justify-content: flex-end; }
.cancellation-status {
    display: inline-flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 1px 6px;
    max-width: 100%;
    padding: 5px 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: 12px;
    line-height: 1.4;
}
.cancellation-status strong { font-weight: 700; }
.cancellation-status-separator { color: currentColor; opacity: .55; }
.cancellation-status--none {
    border-color: var(--ok-border);
    background: var(--ok-bg);
    color: var(--ok-ink);
}
.cancellation-status--penalty {
    border-color: var(--danger-border);
    background: var(--danger-soft);
    color: var(--err);
}
.cancellation-status--unknown {
    border-color: var(--warn-border);
    background: var(--warn-bg);
    color: var(--warn);
}
.client-cancellation-history-table { min-width: 1080px; }
.client-cancellation-status-cell { text-align: right; }
.client-cancellation-status-cell .cancellation-status { justify-content: flex-end; }
.client-cancellation-history-table .client-cancellation-status-cell { min-width: 360px; }

/* Действия с записью — общий набор иконок (_attendance_actions.html). В ростере
   группа прижата вправо: «Отменить запись» и «Удалить запись» идут последними и
   стоят друг под другом на соседних строках, сколько бы отметок ни было слева. */
.attendance-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.attendance-actions form { margin: 0; }

/* Список мероприятий: поиск слева, «Создать мероприятие» справа в той же
   строке, вне панели поиска. Кнопка опущена на внутренний отступ панели,
   чтобы стоять вровень с «Найти». */
.events-toolbar { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.events-toolbar > .events-search { flex: 0 1 auto; flex-wrap: nowrap; margin-bottom: 0; }
.events-toolbar > .events-search label { width: min(360px, 60vw); }
.events-toolbar > .events-create { flex: 0 0 auto; margin-left: auto; margin-bottom: 13px; }
#events-results .events-row-actions { width: 1%; text-align: right; white-space: nowrap; }

/* Окно мероприятия: три колонки, поля по смыслу. */
.event-form-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.event-form-span-2 { grid-column: span 2; }
.event-form-span-3 { grid-column: 1 / -1; }
.event-form-heading { min-width: 0; }
.event-form-heading p { margin: 2px 0 0; color: var(--muted); font-size: 13px; overflow-wrap: anywhere; }
.event-form .class-form-section > .checkline { margin-top: 10px; }
.event-sessions { width: 100%; }
@media (max-width: 760px) {
    .event-form-grid { grid-template-columns: minmax(0, 1fr); }
    .event-form-span-2 { grid-column: auto; }
}

.class-roster-actions { display: flex; align-items: center; justify-content: flex-end; }
.class-roster-actions .attendance-actions { justify-content: flex-end; }

.class-attendance-notice {
    margin: 6px 0 2px;
    padding: 8px 10px;
    border: 1px solid var(--info-border);
    border-radius: var(--radius-sm);
    background: var(--info-soft);
    color: var(--muted);
    font-size: 12px;
    line-height: 1.4;
}
.class-attendance-empty {
    padding: 8px 0 2px;
    font-weight: 600;
}

/* Причина, по которой физическое удаление не пройдёт, стоит отдельной
   строкой под кнопками: рядом с ними она налезала на крестик закрытия. */
.class-remove-note {
    flex-basis: 100%;
    margin-top: 2px;
    color: var(--muted);
    font-size: 12px;
    text-align: right;
}

.class-edit-form { margin-top: 4px; }
/* Дата, время и место — подписанной полосой под шапкой. В шапке они шли строкой
   через точки, а внизу карточки повторялись блоком «Параметры занятия»: одни и
   те же шесть фактов стояли в карточке дважды. Полоса и есть блок значений —
   «Редактировать» меняет её на те же поля на том же месте. */
.class-edit { margin-bottom: 10px; }
.class-facts {
    display: flex;
    align-items: stretch;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card);
    overflow: hidden;
}
.class-fact {
    display: flex;
    flex: 1 1 0;
    flex-direction: column;
    justify-content: center;
    gap: 2px;
    min-width: 0;
    padding: 9px 14px;
}
.class-fact + .class-fact { border-left: 1px solid var(--border); }
.class-fact > span { color: var(--muted); font-size: 12px; font-weight: 700; }
.class-fact > strong {
    color: var(--ink);
    font-size: 14px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}
.class-facts-action {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    padding: 6px 10px;
    border-left: 1px solid var(--border);
}
.class-edit-card {
    padding: 14px 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
}
/* Ряды формы идут без заголовков: полоса над ней называет те же поля. */
.class-edit-card .class-form-section { margin-bottom: 0; }
.class-edit-card .class-form-section + .class-form-section { padding-top: 0; border-top: 0; }
@media (max-width: 820px) {
    .client-panel-header { flex-wrap: wrap; }
    .class-panel-header-actions {
        width: 100%;
        justify-content: flex-start;
        flex-wrap: wrap;
    }
    .class-form-grid-time,
    .class-form-grid-details { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .class-summary-strip { grid-template-columns: 1fr; }
    .class-summary-item + .class-summary-item {
        border-top: 1px solid var(--border);
        border-left: 0;
    }
    /* Полоса фактов складывается так же, как сводка: колонкой с линиями сверху. */
    .class-facts { flex-direction: column; }
    .class-fact + .class-fact,
    .class-facts-action {
        border-top: 1px solid var(--border);
        border-left: 0;
    }
    /* Кнопки уходят на свою строку: раньше ростер был таблицей с
       min-width: 760px и уезжал в горизонтальную прокрутку. */
    .class-roster-row {
        grid-template-columns: minmax(0, 1fr) max-content;
        row-gap: 6px;
    }
    .class-roster-row--cancelled { grid-template-columns: minmax(0, 1fr); }
    .class-roster-actions { grid-column: 1 / -1; justify-content: flex-start; }
    .class-roster-actions .attendance-actions { justify-content: flex-start; }
    .class-roster-status { min-width: 0; }
    .class-remove-note { text-align: left; }
}
@media (max-width: 560px) {
    .class-form-grid-time,
    .class-form-grid-location,
    .class-form-grid-details { grid-template-columns: 1fr; }
    .class-form-actions { align-items: stretch; flex-direction: column; }
    .class-form-actions > span { margin-right: 0; }
    .class-form-actions .hui-button { width: 100%; }
    .class-participant-grid { grid-template-columns: 1fr; }
    .class-payment-total { align-items: flex-start; flex-direction: column; }
    .class-summary-item { white-space: normal; }
    .class-panel-header-actions form { flex: 1 1 100%; }
    .class-panel-header-actions form .hui-button { width: 100%; }
    .class-panel-header-actions .client-drawer-close { margin-left: auto; }
}
/* Только панель самой страницы. Окна карточки клиента (абонемент, продажа)
   лежат в её разметке, и широкий селектор снимал поля и у них: содержимое
   абонемента липло к левому краю окна, а кнопки — к нижнему. */
.client-full-page > .client-panel { padding: 16px 0 0; }
.client-page-header { align-items: flex-start; }
.client-page-header h1 { margin: 12px 0 8px; }
.client-tags { display: flex; gap: 6px; flex-wrap: wrap; }
.client-summary-cards { margin-bottom: 20px; grid-template-columns: repeat(4, minmax(210px, 1fr)); }
.client-panel > .client-summary-cards {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
}
.client-panel > .client-summary-cards .card {
    min-width: 0;
    padding: 12px;
}
.client-panel > .client-summary-cards .card-value {
    font-size: 20px;
    line-height: 1.15;
    overflow-wrap: anywhere;
}
.client-panel > .client-summary-cards .card-label,
.client-panel > .client-summary-cards .card-sub {
    font-size: 12px;
}
.client-metrics-cards {
    margin-top: -8px;
}
.client-sticky-note {
    margin-bottom: 18px;
    background: var(--warn-tint);
    border-color: var(--warn-border);
}
.client-sticky-note h2 {
    margin-top: 0;
}
.client-delete-form {
    clear: both;
    margin-top: 34px;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}
.client-activity {
    display: block;
    margin-top: 0;
    margin-bottom: 30px;
}
.client-activity-content {
    display: flow-root;
}
.client-activity .drawer-loading { min-height: 120px; padding-inline: 0; }
.client-activity .drawer-loading::after {
    min-height: 96px;
    background:
        linear-gradient(var(--border) 0 0) 0 0 / 34% 13px no-repeat,
        linear-gradient(var(--border) 0 0) 0 26px / 92% 13px no-repeat,
        linear-gradient(var(--border) 0 0) 0 51px / 78% 13px no-repeat,
        linear-gradient(var(--border) 0 0) 0 76px / 86% 13px no-repeat;
}
.client-panel-v2 { padding-top: 0; }
/* Высота карточки была прибита к 820 пикселям. Короткая форма
   справочника занимала столько же, сколько карточка клиента со всей историей:
   сверху поля, снизу полоса пустоты в полэкрана. Теперь высоту задаёт
   содержимое, а потолок и прокрутка включаются, только когда содержимое
   действительно не влезает в экран.

   Нижняя граница нужна из-за htmx: сначала в карточке заглушка на 240
   пикселей, потом приезжает содержимое. Без пола карточка прыгала бы
   от заглушки к полному росту на каждом открытии. */
.client-drawer {
    min-height: min(380px, calc(100dvh - var(--dialog-top) - var(--dialog-bottom)));
}
.client-drawer-body { height: auto; }
.client-drawer.class-drawer {
    width: min(1344px, calc(100vw - 24px));
    min-height: min(420px, calc(100dvh - var(--dialog-top) - var(--dialog-bottom)));
}
.client-drawer.class-drawer.class-create-dialog {
    width: min(1120px, calc(100vw - 32px));
}
#client-drawer {
    width: min(80vw, 1440px);
    max-width: none;
    /* Высота по содержимому. Было min(85dvh, 900px): карточка с тремя
       полями занимала столько же, сколько карточка со всей историей посещений.
       Позицию и потолок задаёт .client-drawer — здесь они повторялись
       дословно и только мешали менять их в одном месте. */
    min-height: min(420px, calc(100dvh - var(--dialog-top) - var(--dialog-bottom)));
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
}
/* Пол нужен только загрузочному skeleton. После htmx-подмены содержимое уже
   задаёт естественную высоту: короткие вкладки не оставляют белый хвост
   диалога под последней строкой. */
#client-drawer:has(.client-panel-v2) { min-height: 0; }
/* Форма статьи расходов ниже пола: под «Отмена» и «Сохранить» оставалась
   пустая полоса. */
#expense-category-drawer:has(.client-panel) { min-height: 0; }
/* Только тело самой карточки клиента: вложенные окна сохраняют свою прокрутку. */
#client-drawer > .client-drawer-body {
    width: 100%;
    height: auto;
    max-height: none;
    overflow: visible;
    scrollbar-gutter: auto;
}
.client-panel-v2 .client-profile-header {
    align-items: center;
    flex-wrap: wrap;
    margin-top: 0;
    margin-bottom: 0;
    padding-block: 14px;
}
.client-profile-avatar {
    display: grid;
    flex: 0 0 52px;
    width: 52px;
    height: 52px;
    place-items: center;
    border-radius: 50%;
    background: var(--brand-strong);
    color: var(--brand);
    font-size: 18px;
    font-weight: 800;
}
.client-profile-identity { min-width: 0; flex: 1 1 auto; }
/* Карточка клиента: кампания привлечения показывается строкой рядом с полями
   «Источник» и «Филиал» — как значение, а не как поле. */
.client-profile-campaign,
.client-profile-first-contact { align-self: flex-end; padding-bottom: 9px; color: var(--muted); font-size: 13px; }
.client-profile-campaign a { color: var(--brand-ink); font-weight: 600; text-decoration: none; }
.client-profile-campaign a:hover { text-decoration: underline; text-underline-offset: 3px; }
.client-profile-title,
.client-profile-contacts,
.client-primary-actions,
.client-tab-heading {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}
/* Согласия переехали из карточки «Контакты и согласия» в строку контактов
   шапки: «как с ним можно связаться» нужно рядом с телефоном, а не в
   отдельном блоке на треть экрана. */
.client-consents { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.client-profile-title h2 { margin: 0 4px 0 0; font-size: 24px; }
.client-profile-contacts { margin-top: 7px; color: var(--muted); font-size: 13px; }
.client-profile-contacts > * + *::before { content: "·"; margin-right: 8px; color: var(--faint); }
.tag.segment { background: var(--segment-bg); border-color: var(--segment-border); color: var(--segment-ink); }
.client-profile-header-actions {
    display: flex;
    flex: 0 1 auto;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    min-width: 0;
    margin-left: auto;
}
.client-primary-actions { justify-content: flex-end; }
.client-action-group { gap: 7px; }
.client-action-group > .hui-button {
    flex: 0 0 auto;
    border-radius: var(--radius-sm);
}
.client-action-group > .hui-button + .hui-button { border-left: 0; }
.client-action-label--short { display: none; }
.client-action-caret { transition: transform var(--dur-fast) var(--ease); }
[data-menu-button][aria-expanded="true"] .client-action-caret { transform: rotate(180deg); }
.client-actions-menu {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: var(--z-menu);
    display: grid;
    width: max-content;
    min-width: 250px;
    max-width: min(310px, calc(100vw - 32px));
    gap: 2px;
    padding: 6px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
    box-shadow: var(--shadow);
}
.client-actions-menu a,
.client-actions-menu button {
    display: flex;
    width: 100%;
    min-height: 36px;
    align-items: center;
    gap: 9px;
    padding: 8px 10px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--ink);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    line-height: 1.35;
    text-align: left;
    text-decoration: none;
    transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease;
}
.client-actions-menu a:hover,
.client-actions-menu button:hover,
.client-actions-menu a:focus-visible,
.client-actions-menu button:focus-visible { background: var(--surface-2); color: var(--brand-ink); outline: none; }
.client-actions-menu button:disabled {
    opacity: .5;
    color: var(--muted);
    cursor: not-allowed;
    pointer-events: none;
}
.client-actions-menu button.client-action-menu-item--unavailable { opacity: 1; }
.client-action-menu-item--unavailable > svg,
.client-action-menu-item--unavailable .client-action-menu-label { opacity: .5; }
.client-action-menu-copy {
    display: grid;
    min-width: 0;
    gap: 2px;
}
.client-action-unavailable-reason {
    color: var(--muted);
    font-size: 12px;
    font-weight: 500;
    line-height: 1.35;
    overflow-wrap: anywhere;
}
.client-actions-menu svg {
    width: 18px;
    height: 18px;
    flex: 0 0 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.client-message-dialog-form { gap: 18px; }
.client-message-dialog-form .field { gap: 7px; }
.client-message-dialog-form textarea { min-height: 128px; resize: vertical; }
.client-message-recipient {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.client-message-recipient > svg {
    width: 22px;
    height: 22px;
    flex: 0 0 22px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.client-message-recipient > svg { color: var(--brand-ink); }
.client-message-recipient > div { display: grid; gap: 2px; }
.client-message-recipient span,
.client-message-recipient small { color: var(--muted); font-size: 12px; }
.client-message-dialog-actions { margin-top: 2px; }
.client-panel-v2 > .catalog-tabs { margin-top: 8px; }
.client-tab-panel { padding-top: 0; }
.staff-site-form .client-tab-heading { margin-bottom: 18px; }
.staff-site-warning {
    margin: 0 0 18px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--warn-bg);
    color: var(--ink);
}
.staff-site-publish { align-self: end; min-height: 44px; }
.staff-site-photo-field { margin-top: 18px; }
.staff-site-photo-field > .attachment { max-width: 520px; }
.staff-site-photo-preview {
    display: block;
    width: min(260px, 100%);
    aspect-ratio: 6 / 7;
    margin-top: 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    object-fit: cover;
}
.staff-site-photo-delete { margin-top: 12px; }
/* Обзор: заметка, вывод о состоянии, полоса показателей и две колонки —
   работа слева, хроника справа. Раньше здесь была справочная колонка слева
   и сводка справа; справочные поля уехали в «Профиль», а сводка из четырёх
   одинаковых плиток заменена показателями с разными ролями. */
.client-overview { display: grid; align-content: start; gap: 14px; }

/* Заметка — единственное на карточке, что написал человек. Тёплая подложка
   остаётся постоянным ориентиром и в заполненном, и в пустом состоянии. */
.client-state-note {
    padding: 14px 16px;
    border: 1px solid var(--warn-border);
    border-radius: var(--radius-sm);
    background: var(--warn-tint);
}
.client-state-note-display {
    display: grid;
    grid-template-columns: minmax(0, 1fr) max-content;
    align-content: start;
    align-items: center;
    gap: 10px 12px;
}
.client-state-note-label { color: var(--ink); font-size: 16px; font-weight: 700; line-height: 1.25; }
.client-state-note-text {
    grid-column: 1 / -1;
    min-width: 0;
    padding-top: 10px;
    border-top: 1px solid var(--warn-border);
    line-height: 1.45;
    overflow-wrap: anywhere;
    white-space: pre-wrap;
}
.client-state-note-text p { margin: 0; }
.client-state-note-text p + p { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--warn-border); }
.client-state-note-action {
    padding: 0;
    border: 0;
    background: none;
    color: var(--muted);
    font: inherit;
    font-size: 13px;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}
.client-state-note-action:hover,
.client-state-note-action:focus-visible { color: var(--ink); }
.client-state-note-display > .client-state-note-action { grid-column: 2; grid-row: 1; }
.client-state-note-form {
    display: grid;
    grid-template-columns: minmax(0, 1fr) max-content;
    align-items: start;
    gap: 10px 12px;
}
.client-state-note-form > .client-state-note-label { grid-column: 1; grid-row: 1; }
.client-state-note-form > label { grid-column: 1 / -1; grid-row: 2; min-width: 0; }
.client-state-note-form textarea { width: 100%; min-height: 78px; resize: vertical; }
.client-state-note-actions {
    grid-column: 2;
    grid-row: 1;
    align-self: start;
    justify-self: end;
    display: flex;
    align-items: center;
    gap: 8px;
}
.client-state-note--empty .client-state-note-text {
    color: color-mix(in srgb, var(--ink) 68%, var(--warn-tint));
}

/* Вывод о клиенте и человеческая заметка читаются как одна рабочая строка. */
.client-overview-summary {
    grid-area: summary;
    display: grid;
    grid-template-columns: minmax(400px, 1.9fr) minmax(0, 4fr);
    align-items: stretch;
    align-self: stretch;
    gap: 10px;
    width: 100%;
}
.client-overview-summary > .client-state-note { align-self: stretch; }
.client-overview-summary > .client-state:only-child { grid-column: 1 / -1; }
.client-state {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px 20px;
    padding: 16px 18px;
    border: 1px solid var(--border);
    border-left: 3px solid var(--faint);
    border-radius: var(--radius-md);
    background: var(--card);
}
.client-overview-summary .client-state {
    align-content: start;
    align-items: flex-start;
    padding: 12px 14px;
    border-radius: var(--radius-sm);
}
.client-overview-summary .client-state-main { flex-basis: 100%; }
.client-overview-summary .client-state h2 { font-size: 18px; }
.client-overview-summary .client-state-reasons {
    display: grid;
    gap: 3px;
    margin-top: 7px;
}
.client-overview-summary .client-state-reasons li + li { padding-left: 0; border-left: 0; }
.client-overview-summary .client-state-risk {
    width: 100%;
    margin: 0;
    padding-top: 8px;
    border-top: 1px solid var(--border);
    text-align: left;
}
.client-overview-summary .client-state-risk-value { justify-content: flex-start; }
.client-state-main { flex: 1 1 380px; min-width: 0; }
.client-state h2 { margin: 0; font-size: 21px; line-height: 1.2; letter-spacing: -.01em; }
.client-state-reasons {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 14px;
    margin: 9px 0 0;
    padding: 0;
    list-style: none;
    color: var(--muted);
    font-size: 13px;
}
.client-state-reasons li + li { padding-left: 14px; border-left: 1px solid var(--border); }
.client-state-risk {
    flex: 0 1 auto;
    min-width: 0;
    margin-left: auto;
    text-align: right;
}
.client-state-risk-segment {
    margin: 0 0 3px;
    color: var(--muted);
    font-size: 12px;
    font-weight: 600;
}
.client-state-risk-value {
    display: flex;
    align-items: baseline;
    justify-content: flex-end;
    gap: 5px;
    margin: 0;
    color: var(--muted);
    font-size: 12px;
}
.client-state-risk-value strong { color: var(--ink); font-size: 20px; font-variant-numeric: tabular-nums; }
.client-state-risk-action { margin: 4px 0 0; color: var(--muted); font-size: 12px; line-height: 1.35; }

.client-state--ok { border-color: var(--ok-border); border-left-color: var(--ok); background: var(--ok-bg); }
.client-state--ok h2 { color: var(--ok-ink); }
.client-state--ok .client-state-reasons li + li { border-left-color: var(--ok-border); }
.client-state--warn { border-color: var(--warn-border); border-left-color: var(--warn); background: var(--warn-tint); }
.client-state--warn h2 { color: var(--warn); }
.client-state--warn .client-state-reasons li + li { border-left-color: var(--warn-border); }
.client-state--danger { border-color: var(--danger-border); border-left-color: var(--danger); background: var(--danger-soft); }
.client-state--danger h2 { color: var(--danger); }
.client-state--danger .client-state-reasons li + li { border-left-color: var(--danger-border); }

/* Показатели — компактная сетка 2×2 вместо четырёх вытянутых колонок. Число
   тона не несёт, тон уходит в подпись под ним. */
.client-state-metrics {
    grid-area: metrics;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: repeat(2, minmax(0, 1fr));
    align-self: stretch;
    gap: 8px;
    margin: 0;
}
.client-state-metrics--compact { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.client-state-metric {
    min-width: 0;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card);
}
.client-state-metric dt { margin-bottom: 5px; color: var(--muted); font-size: 12px; }
.client-state-metric dd { display: grid; gap: 2px; min-width: 0; margin: 0; }
.client-state-metric strong {
    font-size: 20px;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -.01em;
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}
.client-state-metric small { color: var(--muted); font-size: 12px; }
.client-state-metric--warn small { color: var(--warn); font-weight: 600; }
.client-state-metric--danger small { color: var(--danger); font-weight: 600; }

/* Слева то, что предстоит сделать, справа показатели и то, что уже было. */
.client-overview-columns {
    display: grid;
    grid-template-areas:
        "summary metrics"
        "work activity";
    grid-template-columns: minmax(0, 1fr) minmax(330px, 420px);
    align-items: start;
    gap: 14px;
}
.client-overview-work { grid-area: work; display: grid; min-width: 0; align-content: start; gap: 14px; }
.client-overview-columns > .client-recent-activity { grid-area: activity; }

/* Каналы приёма сообщений стоят последней строкой левой колонки: значок ведёт
   в диалог с клиентом, серый значок означает, что переписки в этом канале не
   было. Подсказка на сером значке — единственное объяснение, почему он серый,
   поэтому указатель на нём не гасится, как у disabled-кнопки. */
.client-chat-channels {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 10px;
}
.client-chat-channels-label { color: var(--muted); font-size: 12px; font-weight: 700; }
.client-chat-channels ul {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;
}
/* Значок ростом с кнопки шапки карточки: «Записать на занятие» и «Продать
   абонемент» тоже 36px, ряд каналов не выглядит мелкой сноской под ними. */
.client-chat-channels .hui-button.hui-button--icon-only svg {
    width: 24px;
    height: 24px;
    flex-basis: 24px;
    margin: 0;
}
/* Цвет — опознавательный знак чужого канала, а не статус (--channel-* в :root). */
.client-chat-channel--telegram { --hui-button-fg: var(--channel-telegram); }
.client-chat-channel--vk { --hui-button-fg: var(--channel-vk); }
.client-chat-channel--instagram { --hui-button-fg: var(--channel-instagram); }
.client-chat-channel--avito { --hui-button-fg: var(--channel-avito); }
.client-chat-channel--site { --hui-button-fg: var(--brand); }
.client-chat-channel--empty {
    --hui-button-fg: var(--faint);
    --hui-button-bg: var(--surface-2);
    --hui-button-bg-hover: var(--surface-2);
    --hui-button-bg-pressed: var(--surface-2);
    opacity: .6;
    cursor: default;
}
.client-overview-card {
    min-width: 0;
    padding: 15px 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
}
.client-overview-card h2 { margin: 0 0 12px; font-size: 16px; }
.client-tab-heading { justify-content: space-between; }
.client-tab-heading h2 { margin: 0; font-size: 15px; }
.client-tab-heading > span,
.client-tab-heading .link,
.client-tab-heading > a { color: var(--muted); font-size: 13px; }
.client-tab-heading-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.client-overview-card .muted { display: block; padding: 10px 0 2px; font-size: 13px; }
.client-upcoming-row {
    display: grid;
    grid-template-columns: 116px minmax(0, 1fr) auto;
    align-items: start;
    gap: 12px;
    padding: 10px 0;
    border-top: 1px solid var(--border);
}
.client-task-row {
    display: grid;
    grid-template-columns: 116px minmax(0, 1fr) auto;
    align-items: start;
    gap: 12px;
    padding: 10px 0;
    border-top: 1px solid var(--border);
}
.client-task-row .hui-button { align-self: start; }
.client-task-row.overdue time { color: var(--danger); font-weight: 700; }
.client-upcoming-row time,
.client-task-row time { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.client-upcoming-info,
.client-task-row > div { display: grid; gap: 3px; }
.client-upcoming-info { min-width: 0; overflow-wrap: anywhere; }
.client-upcoming-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.client-upcoming-actions form { margin: 0; }
.client-upcoming-row b,
.client-task-row b { display: block; font-size: 13px; line-height: 1.35; }
.client-upcoming-row span,
.client-task-row span { color: var(--muted); font-size: 12px; }
.client-overview-card .client-tab-heading + .client-upcoming-row,
.client-overview-card .client-tab-heading + .client-task-row { padding-top: 4px; border-top: 0; }
.client-history-subtitle { margin: 26px 0 10px; font-size: 16px; }
.client-history-pagination .pager { margin-top: 10px; }

.client-consents span {
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--muted);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .02em;
}
.client-profile-panel {
    padding: 0;
    background: transparent;
}
.client-profile-panel .client-edit-form {
    display: grid;
    gap: 14px;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
}
.client-profile-section {
    display: grid;
    gap: 12px;
    min-width: 0;
}
.client-profile-section + .client-profile-section {
    padding-top: 16px;
    border-top: 1px solid var(--border);
}
.client-profile-section h2 {
    margin: 0;
    font-size: 15px;
}
.client-profile-section .form-row { margin: 0; }
/* Профиль: поля в один ряд. Раньше имена шли одной строкой, дата и пол — другой,
   и правая половина карточки пустовала. Дата и пол вдвое уже имён: им и нужно
   вдвое меньше. */
.client-edit-form .client-profile-name-row {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr);
    gap: 14px;
    align-items: start;
}
.client-edit-form .client-profile-contact-row {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
    gap: 14px;
    /* Подписи полей выстраиваются по верхнему краю: у телефона под полем
       есть пояснение, и по центру соседние поля уезжали вниз. */
    align-items: start;
}
.client-edit-form .client-profile-contact-row--with-alt {
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr);
}
/* Записанный номер не правится, но в ряду должен выглядеть как остальные
   поля: подпись сверху, значение под ней. */
.client-profile-phone-fixed { display: grid; gap: 4px; font-size: 13px; color: var(--muted); }
.client-profile-phone-fixed > p { margin: 0; color: var(--ink); font-size: 15px; font-weight: 650; }
.client-profile-phone-fixed > p.muted { color: var(--muted); font-size: 13px; font-weight: 400; }
.client-edit-form .client-profile-name-row > *,
.client-edit-form .client-profile-contact-row > * { min-width: 0; }
@media (max-width: 900px) {
    .client-edit-form .client-profile-name-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .client-edit-form .client-profile-contact-row,
    .client-edit-form .client-profile-contact-row--with-alt { grid-template-columns: minmax(0, 1fr); }
}
.client-profile-options {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
}
.client-profile-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
}
.client-profile-actions .client-delete-form {
    margin: 0 0 0 auto;
    padding: 0;
    border: 0;
}
.client-activity-feed { display: grid; }
.client-activity-event { display: grid; grid-template-columns: 118px 10px minmax(0, 1fr); align-items: start; gap: 9px; padding: 8px 0; border-top: 1px solid var(--border); }
.client-activity-event:first-child { border-top: 0; }
.client-activity-event > div { display: grid; gap: 2px; }
.client-activity-event > div span, .client-activity-event time { color: var(--muted); font-size: 12px; }
.client-activity-event time { padding-top: 1px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.client-activity-dot { width: 8px; height: 8px; margin-top: 6px; border-radius: 50%; background: var(--brand); }
.client-activity-event.no_show .client-activity-dot { background: var(--err); }
.client-activity-event.payment .client-activity-dot { background: var(--info); }
.client-activity-event.purchase .client-activity-dot { background: var(--segment-ink); }
.client-loyalty-dashboard {
    display: grid;
    grid-template-areas:
        "balance nps"
        "history referral";
    grid-template-columns: minmax(0, 1.35fr) minmax(290px, .65fr);
    gap: 12px;
    align-items: start;
    margin-top: 14px;
}
.client-loyalty-card {
    min-width: 0;
    padding: 18px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
}
.client-loyalty-eyebrow { color: var(--muted); font-size: 13px; font-weight: 600; }
.client-loyalty-balance-card { grid-area: balance; border-color: var(--brand-border); background: var(--brand-tint); }
.client-loyalty-balance-card > header { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.client-loyalty-tier { padding: 4px 8px; border: 1px solid var(--brand-border); border-radius: 7px; color: var(--brand-ink); font-size: 12px; font-weight: 700; }
.client-loyalty-primary-value { display: flex; align-items: baseline; gap: 8px; margin-top: 19px; }
.client-loyalty-primary-value strong { color: var(--brand-ink); font-size: 42px; line-height: .95; letter-spacing: -.04em; font-variant-numeric: tabular-nums; }
.client-loyalty-primary-value span { color: var(--muted); font-size: 13px; }
.client-loyalty-balance-card > footer { display: flex; align-items: center; gap: 8px; margin-top: 13px; color: var(--muted); font-size: 12px; }
.client-loyalty-nps-card { grid-area: nps; }
.client-loyalty-nps-card > header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.client-loyalty-nps-card h3 { margin: 3px 0 0; font-size: 16px; }
.client-nps-value { display: grid; flex: 0 0 52px; width: 52px; height: 52px; place-items: center; border-radius: 14px; background: var(--ok-bg); color: var(--ok-ink); font-size: 22px; font-variant-numeric: tabular-nums; }
.client-loyalty-metrics { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0; margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--border); }
.client-loyalty-metrics > div { min-width: 0; }
.client-loyalty-metrics > div + div { padding-left: 16px; border-left: 1px solid var(--border); }
.client-loyalty-metrics dt { color: var(--muted); font-size: 12px; }
.client-loyalty-metrics dd { margin: 4px 0 0; font-size: 20px; font-weight: 700; font-variant-numeric: tabular-nums; }
.client-loyalty-caption, .client-loyalty-empty { margin: 12px 0 0; color: var(--muted); font-size: 12px; }
.client-loyalty-history-card { grid-area: history; }
.client-loyalty-card-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 8px; }
.client-loyalty-card-heading h3 { margin: 0; font-size: 16px; }
.client-loyalty-card-heading > span { color: var(--muted); font-size: 12px; }
.client-loyalty-history { min-width: 0; }
.client-loyalty-history > h3 { margin-top: 0; }
.client-loyalty-history > article { display: grid; grid-template-columns: 64px minmax(0,1fr); gap: 10px; padding: 10px 0; border-top: 1px solid var(--border); }
.client-loyalty-history > article > div { display: grid; gap: 2px; }
.client-loyalty-history > article span, .client-loyalty-history > article small { color: var(--muted); font-size: 12px; }
.client-loyalty-history-card > article:first-of-type { border-top: 0; }
.client-loyalty-referral-card { grid-area: referral; }
.client-referral-metrics { margin-top: 4px; padding: 10px 0 16px; border-top: 0; border-bottom: 1px solid var(--border); }
.client-referral-codes { margin-top: 15px; }
.client-referral-codes h4 { margin: 0 0 7px; color: var(--muted); font-size: 12px; font-weight: 600; }
.client-referral-code { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 0; }
.client-referral-code + .client-referral-code { border-top: 1px solid var(--border); }
.client-referral-code code { overflow: hidden; color: var(--ink); font-size: 12px; font-weight: 700; text-overflow: ellipsis; }
.client-referral-status { display: inline-flex; flex: none; align-items: center; gap: 6px; color: var(--muted); font-size: 11px; font-weight: 600; }
.client-referral-status i { width: 7px; height: 7px; border-radius: 50%; background: var(--faint); }
.client-referral-status.active { color: var(--ok-ink); }
.client-referral-status.active i { background: var(--ok); }
.client-referral-status.inactive i { background: var(--err); }
.client-loyalty-form { display: grid; gap: 9px; margin: 0; }
.client-document-list { display: grid; gap: 10px; margin-top: 14px; }
.client-document-card { display: grid; grid-template-columns: 58px minmax(0,1fr) auto; align-items: center; gap: 14px; padding: 15px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card); }
.client-document-icon { display: grid; width: 52px; height: 52px; place-items: center; border-radius: 12px; background: var(--info-soft); color: var(--info); font-size: 10px; font-weight: 800; }
.client-document-main { min-width: 0; }
.client-document-main > div { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.client-document-main h3 { margin: 0; font-size: 16px; }
.client-document-main p { margin: 5px 0 0; color: var(--muted); font-size: 13px; }
.client-document-main .client-document-accepted { color: var(--ok-ink); }
.client-document-main .client-document-pending { color: var(--warn); }
.client-document-download { white-space: nowrap; text-decoration: none; }
.client-legal-signing-actions { display: flex; align-items: center; justify-content: space-between; gap: 18px; margin-top: 14px; padding: 16px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card); }
.client-legal-signing-actions h3, .client-document-section-title { margin: 0; }
.client-legal-signing-actions p { margin: 6px 0 0; color: var(--muted); font-size: 13px; }
.client-legal-signing-actions form { flex: none; margin: 0; }
.client-document-section-title { margin-top: 20px; font-size: 15px; }
.client-document-card.signed .client-document-icon { background: var(--ok-bg); color: var(--ok-ink); font-size: 23px; }
.contract-editor-field { display: grid; gap: 7px; min-width: 0; }
.contract-editor-label { color: var(--ink); font-size: 12px; font-weight: 700; }
.contract-editor { overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card); }
.contract-editor:focus-within { border-color: var(--brand); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 14%, transparent); }
.contract-editor-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 5px; padding: 8px; border-bottom: 1px solid var(--border); background: var(--surface-2); }
.contract-editor-select { width: auto; height: 34px; padding: 5px 30px 5px 9px; font-size: 13px; }
.contract-editor-format { min-width: 154px; }
.contract-editor-font-family { min-width: 148px; }
.contract-editor-font-size { min-width: 92px; font-variant-numeric: tabular-nums; }
.contract-tool-button { display: inline-grid; flex: 0 0 34px; width: 34px; height: 34px; min-height: 34px; padding: 0; place-items: center; border: 1px solid transparent; border-radius: 5px; background: transparent; color: var(--text); font-size: 15px; line-height: 1; }
.contract-tool-button:hover, .contract-tool-button:focus-visible { border-color: var(--border); background: var(--card); }
.contract-tool-button.is-active, .contract-tool-button[aria-pressed="true"] { border-color: color-mix(in srgb, var(--brand) 55%, var(--border)); background: var(--selected); color: var(--ink); }
.contract-tool-bold { font-weight: 800; }
.contract-tool-italic { font-family: Georgia, serif; font-style: italic; }
.contract-tool-underline { text-decoration: underline; text-underline-offset: 2px; }
.contract-toolbar-separator { width: 1px; height: 24px; margin: 0 3px; background: var(--border); }
.contract-align-icon { width: 17px; height: 14px; background-repeat: no-repeat; }
.contract-align-icon.align-left { background-image: linear-gradient(currentColor,currentColor),linear-gradient(currentColor,currentColor),linear-gradient(currentColor,currentColor),linear-gradient(currentColor,currentColor); background-position: left 1px,left 5px,left 9px,left 13px; background-size: 100% 1.5px,68% 1.5px,88% 1.5px,58% 1.5px; }
.contract-align-icon.align-center { background-image: linear-gradient(currentColor,currentColor),linear-gradient(currentColor,currentColor),linear-gradient(currentColor,currentColor),linear-gradient(currentColor,currentColor); background-position: center 1px,center 5px,center 9px,center 13px; background-size: 100% 1.5px,68% 1.5px,88% 1.5px,58% 1.5px; }
.contract-align-icon.align-right { background-image: linear-gradient(currentColor,currentColor),linear-gradient(currentColor,currentColor),linear-gradient(currentColor,currentColor),linear-gradient(currentColor,currentColor); background-position: right 1px,right 5px,right 9px,right 13px; background-size: 100% 1.5px,68% 1.5px,88% 1.5px,58% 1.5px; }
.contract-align-icon.align-justify { background-image: linear-gradient(currentColor,currentColor),linear-gradient(currentColor,currentColor),linear-gradient(currentColor,currentColor),linear-gradient(currentColor,currentColor); background-position: left 1px,left 5px,left 9px,left 13px; background-size: 100% 1.5px,100% 1.5px,100% 1.5px,100% 1.5px; }
.contract-list-icon { font-size: 23px; padding-bottom: 7px; }
.contract-numbered-icon { font-size: 12px; font-weight: 700; }
.contract-table-icon > span { width: 17px; height: 15px; border: 1.5px solid currentColor; background: linear-gradient(to right, transparent 31%, currentColor 32%, currentColor 37%, transparent 38%, transparent 64%, currentColor 65%, currentColor 70%, transparent 71%), linear-gradient(to bottom, transparent 30%, currentColor 31%, currentColor 37%, transparent 38%, transparent 63%, currentColor 64%, currentColor 70%, transparent 71%); }
.contract-table-tools { display: contents; }
.contract-row-add, .contract-row-remove, .contract-column-add, .contract-column-remove { position: relative; padding: 0 0 0 13px; font-weight: 700; }
.contract-row-add::before, .contract-row-remove::before { content: ""; position: absolute; left: 5px; width: 10px; height: 13px; border: 1px solid currentColor; background: linear-gradient(to bottom, transparent 45%, currentColor 46%, currentColor 55%, transparent 56%); }
.contract-column-add::before, .contract-column-remove::before { content: ""; position: absolute; left: 5px; width: 13px; height: 10px; border: 1px solid currentColor; background: linear-gradient(to right, transparent 45%, currentColor 46%, currentColor 55%, transparent 56%); }
.contract-editor-surface { min-height: 540px; max-height: 72vh; overflow: auto; padding: 28px clamp(20px, 5vw, 72px); outline: none; color: var(--text); background: var(--card); }
.contract-editor-surface:empty::before { content: "Введите текст договора"; color: var(--faint); pointer-events: none; }
.contract-editor-help { color: var(--muted); font-size: 12px; line-height: 1.45; }
.contract-rich-body { font-family: Arial, Helvetica, sans-serif; font-size: 11pt; line-height: 1.55; overflow-wrap: anywhere; }
.contract-rich-body [data-font-family="arial"] { font-family: Arial, Helvetica, sans-serif; }
.contract-rich-body [data-font-family="times-new-roman"] { font-family: "Times New Roman", Times, serif; }
.contract-rich-body [data-font-family="georgia"] { font-family: Georgia, "Times New Roman", serif; }
.contract-rich-body [data-font-family="verdana"] { font-family: Verdana, Geneva, sans-serif; }
.contract-rich-body [data-font-family="courier-new"] { font-family: "Courier New", Courier, monospace; }
.contract-rich-body [data-font-size="9"] { font-size: 9pt; }
.contract-rich-body [data-font-size="10"] { font-size: 10pt; }
.contract-rich-body [data-font-size="11"] { font-size: 11pt; }
.contract-rich-body [data-font-size="12"] { font-size: 12pt; }
.contract-rich-body [data-font-size="14"] { font-size: 14pt; }
.contract-rich-body [data-font-size="16"] { font-size: 16pt; }
.contract-rich-body [data-font-size="18"] { font-size: 18pt; }
.contract-rich-body [data-font-size="20"] { font-size: 20pt; }
.contract-rich-body [data-font-size="24"] { font-size: 24pt; }
.contract-rich-body p, .contract-rich-body div { margin: 0 0 12px; }
.contract-rich-body h2 { margin: 26px 0 12px; font-size: 20px; letter-spacing: 0; }
.contract-rich-body h3 { margin: 20px 0 10px; font-size: 16px; letter-spacing: 0; }
.contract-rich-body ul, .contract-rich-body ol { margin: 8px 0 14px; padding-left: 26px; }
.contract-rich-body [data-align="left"] { text-align: left; }
.contract-rich-body [data-align="center"] { text-align: center; }
.contract-rich-body [data-align="right"] { text-align: right; }
.contract-rich-body [data-align="justify"] { text-align: justify; }
.contract-rich-body table { width: max-content; min-width: 100%; margin: 16px 0; border-collapse: collapse; table-layout: auto; }
.contract-rich-body th, .contract-rich-body td { min-width: 96px; max-width: 420px; padding: 9px 11px; border: 1px solid var(--border); vertical-align: top; white-space: normal; overflow-wrap: anywhere; }
.contract-rich-body th { background: var(--surface-2); font-weight: 700; }
.contract-editor-surface td:focus, .contract-editor-surface th:focus { outline: 2px solid var(--brand); outline-offset: -2px; }
.legal-preview.contract-rich-body { overflow-x: auto; }
.contract-table-size-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 12px; }
.contract-table-size-grid input { width: 100%; }
@media (max-width: 640px) {
    .contract-editor-toolbar { align-items: stretch; }
    .contract-editor-select { flex: 1 1 auto; min-width: 0; }
    .contract-editor-format { flex-basis: 100%; }
    .contract-editor-font-family { flex-basis: 150px; }
    .contract-editor-font-size { flex-basis: 92px; }
    .contract-editor-surface { min-height: 440px; max-height: none; padding: 18px 14px; }
    .contract-toolbar-separator { display: none; }
}
.client-activity-content > .client-tab-panel { padding-top: 0; }
/* Карточка живёт в шторке min(80vw, 1440px), поэтому две колонки надо
   складывать раньше общего мобильного порога кабинета: правая колонка
   зафиксирована на 330-420 пикселях и первой начинает давить левую. */
@media (max-width: 1100px) {
    .client-overview-summary { grid-template-columns: minmax(0, 1fr); }
    .client-overview-columns {
        grid-template-areas: "summary" "metrics" "work" "activity";
        grid-template-columns: minmax(0, 1fr);
    }
}
@media (max-width: 820px) {
    #client-drawer {
        inset: 10px;
        transform: none;
        width: auto;
        height: auto;
        max-height: none;
    }
    .client-drawer {
        --dialog-top: 10px;
        --dialog-bottom: 10px;
        width: calc(100vw - 20px);
        height: calc(100dvh - var(--dialog-top) - var(--dialog-bottom));
    }
    .client-loyalty-dashboard {
        grid-template-areas: "balance" "nps" "history" "referral";
        grid-template-columns: minmax(0, 1fr);
    }
    .client-document-card { grid-template-columns: 48px minmax(0,1fr); }
    .client-legal-signing-actions { align-items: stretch; flex-direction: column; }
    .client-legal-signing-actions button { width: 100%; }
    .client-document-download { grid-column: 1 / -1; justify-self: stretch; text-align: center; }
    .client-profile-contacts > * + *::before { content: none; margin: 0; }
}
@media (max-width: 560px) {
    .client-panel { padding-inline: 14px; }
    .client-panel-v2 .client-profile-header { margin-inline: -14px; padding-inline: 14px; align-items: flex-start; }
    .client-profile-avatar { flex-basis: 42px; width: 42px; height: 42px; }
    .client-profile-title h2 { width: 100%; font-size: 20px; }
    .client-profile-header-actions { flex: 1 1 100%; }
    .client-primary-actions,
    .client-action-group { flex: 1 1 auto; width: 100%; min-width: 0; }
    .client-action-group > .hui-button { flex: 1 1 0; min-width: 0; padding-inline: 9px; }
    .client-action-group > [data-menu-button] { flex: 0 0 auto; }
    .client-action-label--long { display: none; }
    .client-action-label--short { display: inline; }
    .client-state-risk { margin-left: 0; text-align: left; }
    .client-state-risk-value { justify-content: flex-start; }
    .client-loyalty-card { padding: 14px; }
    .client-upcoming-row,
    .client-task-row { grid-template-columns: 1fr; gap: 4px; }
    .client-upcoming-actions { margin-top: 4px; }
    .client-task-row .hui-button { justify-self: start; margin-top: 4px; }
    .client-balance-cash-fields { grid-template-columns: 1fr; }
}
.client-detail-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 18px;
    align-items: start;
}
.client-history-grid { margin-top: 8px; }
.client-history-section {
    margin-top: 22px;
}
.client-history-section h2 {
    margin-top: 0;
}
.client-history-table {
    min-width: 860px;
}
.client-history-table td {
    vertical-align: top;
}
.client-pass-history-link {
    max-width: 100%;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--brand-ink);
    font: inherit;
    text-align: left;
    text-decoration: underline;
    text-underline-offset: 3px;
}
.client-pass-history-link:hover { color: var(--brand); }
.client-card-pass-dialog,
#client-pass-drawer { width: min(920px, calc(100vw - 36px)); height: auto; }
/* Потолок прокрутки совпадает с окном, включая его отступы от краёв экрана. */
.client-card-pass-dialog > .client-drawer-body { height: auto; max-height: inherit; }
.client-card-pass-panel { padding-bottom: 18px; }
.client-card-pass-heading { min-width: 0; }
.client-card-pass-header h1 { margin-bottom: 3px; }
.client-card-pass-product {
    margin: 0;
    color: var(--ink);
    font-size: 15px;
    font-weight: 650;
    line-height: 1.4;
}
.client-card-pass-header-meta { margin-top: 10px; }
.client-card-pass-id {
    color: var(--muted);
    font-weight: inherit;
    white-space: nowrap;
}
.client-card-pass-sections { display: grid; gap: 20px; }
.client-card-pass-section h2 { margin: 0 0 12px; font-size: 14px; }
.client-card-pass-details {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px 28px;
    margin: 0;
    padding: 0;
}
.client-card-pass-detail {
    min-width: 0;
}
.client-card-pass-detail dt {
    color: var(--muted);
    font-size: 12px;
    font-weight: 600;
    line-height: 1.35;
}
.client-card-pass-detail dd {
    margin: 5px 0 0;
    color: var(--ink);
    font-size: 16px;
    font-variant-numeric: tabular-nums;
    font-weight: 650;
    line-height: 1.35;
    overflow-wrap: anywhere;
}
.client-card-pass-detail-note {
    display: block;
    margin-top: 3px;
    color: var(--muted);
    font-size: 12px;
    line-height: 1.35;
}
/* Карточка абонемента: сводка с двумя мерками и три одинаковых блока. */
.client-card-pass-summary {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px 28px;
    margin-top: 18px;
    padding: 16px 18px;
    border-radius: 9px;
    background: var(--surface-2);
}
.client-card-pass-metric { display: grid; gap: 7px; align-content: start; min-width: 0; }
.client-card-pass-metric-top { display: flex; align-items: baseline; gap: 8px; margin: 0; min-width: 0; }
.client-card-pass-metric-top b {
    font-size: 28px;
    font-weight: 800;
    letter-spacing: -.025em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}
.client-card-pass-metric-top span { color: var(--muted); font-size: 13px; font-weight: 650; line-height: 1.3; }
.client-card-pass-metric-note { color: var(--muted); font-size: 12px; line-height: 1.35; }
/* Дорожка мерки не может совпадать с подложкой сводки: иначе шкала читается
   как обрубленная линия, а не как доля. */
.client-card-pass-meter {
    height: 6px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--ink) 12%, transparent);
    overflow: hidden;
}
.client-card-pass-meter > i { display: block; height: 100%; border-radius: 999px; background: var(--ok); }
.client-card-pass-meter--term > i { background: var(--brand); }
.client-card-pass-blocks {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
    margin-top: 16px;
}
.client-card-pass-block {
    display: grid;
    gap: 10px;
    align-content: start;
    min-width: 0;
    padding: 13px 14px;
    border: 1px solid var(--border);
    border-radius: 9px;
}
.client-card-pass-block h2 {
    margin: 0;
    color: var(--muted);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}
.client-card-pass-block dl { display: grid; gap: 8px; margin: 0; }
.client-card-pass-block-metric { display: flex; align-items: baseline; gap: 7px; margin: 0; min-width: 0; }
/* «90 из 90» у годового абонемента рвалось на две строки: переносится
   подпись рядом, а не число. */
.client-card-pass-block-metric b {
    font-size: 22px;
    font-weight: 800;
    letter-spacing: -.02em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.client-card-pass-block-metric span { color: var(--muted); font-size: 12.5px; font-weight: 650; line-height: 1.3; }
/* Место сначала получает значение, подпись переносится по словам. Было наоборот,
   и в узком окне «0 из 90» рассыпалось по букве в строку. */
.client-card-pass-row { display: grid; grid-template-columns: 1fr auto; gap: 6px 10px; align-items: baseline; }
.client-card-pass-row dt { color: var(--muted); font-size: 13px; line-height: 1.35; }
.client-card-pass-row dd {
    margin: 0;
    color: var(--ink);
    font-size: 14px;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    line-height: 1.35;
    text-align: right;
    overflow-wrap: anywhere;
}
/* Ряд действий карточки живёт в окне, поэтому прижат вправо — как у форм
   в окне, см. DESIGN.md, «Действия формы». */
.client-card-pass-actions {
    flex-wrap: wrap;
    justify-content: flex-end;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
}
.client-card-pass-actions form { margin: 0; }
/* Окна операций карточки абонемента: заморозка и корректировка занятий. */
.client-pass-operation-dialog .modal-form { display: grid; gap: 14px; }
.client-pass-operation-dialog .modal-form > p { margin: 0; }
.client-pass-operation-dialog .modal-form > .actions { margin-top: 0; }
.client-pass-operation-dialog .client-card-pass-details { grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 0; }
.client-pass-adjust-direction .radio-group__options { flex-direction: row; flex-wrap: wrap; gap: 8px 16px; }
.client-pass-adjust-direction .radio-group__options .radio { flex: 1 1 200px; }
@media (max-width: 760px) {
    .client-card-pass-details {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: 18px;
    }
    .client-card-pass-summary,
    .client-card-pass-blocks { grid-template-columns: minmax(0, 1fr); }
    .client-card-pass-actions { justify-content: flex-start; }
}
@media (max-width: 560px) {
    .client-card-pass-actions { grid-template-columns: 1fr; }
    .client-card-pass-actions > :only-child { grid-column: 1; width: 100%; }
}
.kv-list { margin: 0; display: grid; gap: 8px; }
.kv-list div {
    display: grid;
    grid-template-columns: minmax(130px, 0.42fr) 1fr;
    gap: 12px;
    align-items: start;
    padding: 7px 0;
    border-bottom: 1px solid var(--surface-2);
}
.kv-list.compact div { grid-template-columns: 100px 1fr; }
.kv-list dt { color: var(--muted); font-size: 13px; }
.kv-list dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
/* Только горизонтальный отступ: высоту строки держит --row-h-sm выше, а
   вертикальный padding поверх height давал ячейку то в 40, то в 54 пикселя
   в зависимости от того, переносится ли текст. */
.compact-grid th, .compact-grid td { padding: 0 12px; }
.contact-col { overflow-wrap: anywhere; }
.pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 0 0 12px;
    flex-wrap: wrap;
}
.pager.bottom { margin: 14px 0 0; }
.pager-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
@media (max-width: 560px) {
    /* «Первая · Назад · Страница X из Y · Далее · Последняя» — пять элементов,
       которые в 390px не помещаются в строку, и последняя кнопка оставалась
       висеть одна под остальными. Счётчик уходит на свою строку: четыре
       кнопки после этого встают в один ряд и переносить нечего. */
    .pager-actions { justify-content: center; }
    .pager-actions > span { order: -1; flex: 1 0 100%; text-align: center; }
}
/* Статусный бейдж.

   Рамки здесь не было, хотя .tag.segment уже задавал border-color, а
   border-width не задавал никто — цвет не рисовался вовсе. Рамка не
   добавлена, а дописана.

   Форма — таблетка, а не скруглённый прямоугольник. Рядом стоит .metric-delta с
   радиусом --radius-sm, и разная форма разводит два разных смысла: таблетка —
   состояние, прямоугольник — величина. При радиусе 6px и высоте 20px бейдж с
   рамкой начинал читаться как маленькая кнопка. */
.tag {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 9px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: transparent;
    color: var(--muted);
    font-size: 12px;
    font-weight: 500;
    line-height: 1.45;
    white-space: nowrap;
    /* В бейдже бывают числа — остаток занятий, номер попытки. Без моноширинных
       знаков соседние строки таблицы расходятся по ширине. */
    font-variant-numeric: tabular-nums;
}
/* Тон статуса — один словарь кабинета: ok, warn, danger, info. Бейдж .tag и
   плашка .inline-alert красятся одной тройкой «подложка, рамка, текст».
   Раньше у плашки были свои слова (success, warning), у бейджа — err, у
   выплат и у оптимизатора расписания — свои капсулы, а плашка info не
   красилась вовсе. Текст «хорошо» — не var(--ok): зелёный акцент на этой
   подложке даёт 4,29:1. */
.tag.ok, .inline-alert.ok { background: var(--ok-bg); border-color: var(--ok-border); color: var(--ok-ink); }
.tag.warn, .inline-alert.warn { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn); }
.tag.danger, .inline-alert.danger { background: var(--danger-soft); border-color: var(--danger-border); color: var(--err); }
/* Синий тон — «идёт», «запланировано»: без притворства предупреждением. */
.tag.info, .inline-alert.info { background: var(--info-soft); border-color: var(--info-border); color: var(--info); }
.hint { cursor: help; color: var(--muted); }
/* Причина недоступного действия. Раньше она жила в title на disabled-кнопке:
   такой элемент не фокусируется, и причина была недостижима и с клавиатуры,
   и скринридером. */

@media (max-width: 980px) {
    .clients-stat-cards,
    .client-summary-cards { grid-template-columns: repeat(2, minmax(180px, 1fr)); }
    .client-panel > .client-summary-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .client-detail-grid { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
    .clients-stat-cards,
    .client-summary-cards { grid-template-columns: 1fr; }
    .client-panel > .client-summary-cards { grid-template-columns: 1fr; }
    .kv-list div { grid-template-columns: 1fr; gap: 2px; }
    .client-drawer {
        --dialog-top: 8px;
        --dialog-bottom: 8px;
        width: calc(100vw - 16px);
    }
    .client-panel { padding: 16px 14px 26px; }
    .client-panel-header { margin: -16px -14px 16px; padding: 16px 14px 12px; }
}

/* Постоянное сообщение, которое должно оставаться рядом с данными страницы.
   Разметку и роль даёт макрос alert() из _alert.html: тон danger объявляется
   как role="alert", остальные — role="status". Тоны — в словаре выше. */
.inline-alert {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 11px 12px 11px 14px; border: 1px solid transparent;
    border-radius: var(--radius-sm); margin-bottom: 14px;
}
.shift-telegram-alert { align-items: center; flex-wrap: wrap; }
.shift-telegram-alert-copy { display: grid; flex: 1 1 42rem; gap: 3px; min-width: 0; overflow-wrap: anywhere; }
.shift-telegram-alert-copy a { color: inherit; font-weight: 650; text-underline-offset: 2px; }
.shift-telegram-alert-action { flex: 0 0 auto; margin-inline-start: auto; }

/* Login */
.login-body { display: flex; align-items: center; justify-content: center; min-height: 100dvh; padding: 24px 16px; }
.login-card {
    background: var(--card); border: 1px solid var(--border); border-radius: 16px;
    padding: 32px; width: 340px; display: flex; flex-direction: column; gap: 12px;
    box-shadow: var(--shadow);
}
.login-card-wide { width: min(420px, calc(100vw - 32px)); }
.login-card label { color: var(--ink); }
.login-brand { display: flex; justify-content: center; margin-bottom: 2px; }
.login-studio-logo { display: block; width: min(240px, 100%); height: auto; object-fit: contain; }
.login-intro { margin: 0 0 4px; text-align: center; line-height: 1.5; }
.login-field { gap: 6px; }
.login-field-heading {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}
.login-password-reset { flex: 0 0 auto; font-size: 12px; font-weight: 600; white-space: nowrap; }
.login-submit { align-self: center; min-width: 140px; margin-top: 4px; }
.login-portal-switch { margin: 0; text-align: center; line-height: 1.5; }
.login-portal-link { display: block; margin-top: 2px; }
.small-center { text-align: center; font-size: 13px; margin: 0; }

.error-page {
    display: flex;
    justify-content: center;
    padding: 42px 0;
}
.error-card {
    width: min(820px, 100%);
    padding: 24px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
    box-shadow: var(--shadow);
}
.error-code {
    display: inline-flex;
    margin-bottom: 10px;
    padding: 4px 9px;
    border-radius: var(--radius-sm);
    background: var(--danger-soft);
    color: var(--err);
    font-size: 12px;
    font-weight: 700;
}
.error-page h1 {
    margin-bottom: 8px;
    color: var(--ink);
}
.error-page p {
    max-width: 720px;
    margin: 0 0 18px;
    color: var(--muted);
}
.error-actions {
    margin-top: 18px;
}
.error-actions h2 {
    margin: 0 0 8px;
}
.error-actions ul {
    margin: 0;
    padding-left: 20px;
    color: var(--muted);
}
.error-details {
    margin-top: 18px;
}
.error-details summary {
    cursor: pointer;
    color: var(--brand-ink);
    font-weight: 700;
}
.error-buttons {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 20px;
}

/* Native analytics */
/* Категориальная рампа объявлена один раз: «Сводка» рисует те же графики
   тем же словарём, что и остальная аналитика. */
.app-shell .container.analytics-container,
.app-shell .container.financial-report {
    --analytics-0: var(--admin-1-accent);
    --analytics-1: var(--admin-5-accent);
    --analytics-2: var(--admin-0-accent);
    --analytics-3: var(--admin-4-accent);
    --analytics-4: var(--admin-3-accent);
    --analytics-5: var(--admin-2-accent);
    --analytics-6: var(--admin-7-accent);
    --analytics-7: var(--admin-9-accent);
    --analytics-8: var(--admin-8-accent);
    --analytics-9: var(--admin-6-accent);
    --analytics-10: var(--analytics-teal-deep);
    --analytics-11: var(--analytics-rose-deep);
    --analytics-heat: var(--analytics-1);
}
.app-shell .container.analytics-container {
    width: 100%;
    max-width: none;
    margin: 0;
    /* Верхний отступ общий для всех вкладок раздела, включая «Сводку» и «Метрики». */
    padding-inline: clamp(16px, 2vw, 28px);
    padding-bottom: 40px;
}
.app-shell .analytics-container.analytics-container--cohorts {
    --analytics-0: var(--cohort-0);
    --analytics-1: var(--cohort-1);
    --analytics-2: var(--cohort-2);
    --analytics-3: var(--cohort-3);
    --analytics-4: var(--cohort-4);
    --analytics-5: var(--cohort-5);
    --analytics-6: var(--cohort-6);
    --analytics-7: var(--cohort-7);
    --analytics-8: var(--cohort-8);
    --analytics-9: var(--cohort-9);
    --analytics-10: var(--cohort-10);
    --analytics-11: var(--cohort-11);
    --analytics-heat: var(--cohort-heat);
}
.analytics-page-heading {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 24px;
    margin-bottom: 12px;
}
.analytics-page-heading > div { flex: 1 1 auto; min-width: 0; }
/* Одна шкала шапок для вкладок «Аналитики» — «Сводки» (financial-*),
   «Посещаемости» и «Когорт» (analytics-*): заголовок страницы — роль
   headline из DESIGN.md, заголовок панели — роль title. Раньше у каждой
   вкладки был свой размер (28, 20–26 и 24–30 px). financial-report.css
   подключается раньше app.css, поэтому правила живут здесь. */
.analytics-page-heading h1,
.financial-heading h1 {
    margin: 0 0 4px;
    font-size: clamp(21px, 2vw, 28px);
    font-weight: 700;
    letter-spacing: -.025em;
    line-height: 1.2;
}
.analytics-page-heading p,
.financial-heading-title p {
    margin: 0;
    color: var(--muted);
    font-size: 13.5px;
    line-height: 1.55;
}
.analytics-freshness {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 7px;
    min-height: 32px;
    padding: 5px 9px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card);
    color: var(--muted);
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.analytics-freshness svg {
    width: 16px;
    height: 16px;
    fill: none;
    stroke: var(--analytics-1);
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.analytics-attendance-overview {
    position: sticky;
    top: 44px;
    z-index: calc(var(--z-sticky) - 1);
    display: grid;
    grid-template-columns: minmax(460px, .9fr) minmax(420px, 1.1fr);
    gap: 10px;
    margin-bottom: 10px;
    background: var(--bg);
}
.analytics-filterbar {
    position: sticky;
    top: 44px;
    z-index: calc(var(--z-sticky) - 1);
    display: grid;
    grid-template-columns: repeat(3, minmax(180px, 1fr)) auto;
    align-items: end;
    gap: 8px;
    margin-bottom: 12px;
    padding: 9px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
}
/* Посещаемость: полей от четырёх до семи (свой период, филиалы) — полоса
   переносится по ширине, кнопка «Показать» держится в ряду с полями. */
.analytics-filterbar--attendance {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
}
.analytics-filterbar--attendance > label { flex: 1 1 170px; max-width: 300px; }
.analytics-filterbar--attendance > .filter-actions { flex: 0 0 auto; margin-left: auto; }
.analytics-filterbar--attendance select,
.analytics-filterbar--attendance input { width: 100%; }
.analytics-filterbar--attendance > .analytics-filter-chips { flex: 1 1 100%; }
.analytics-filterbar--compact {
    grid-template-columns: minmax(240px, 360px) auto;
    width: min(100%, 470px);
}
/* Когорты: филиал и канал привлечения (этап 3 «Маркетинга») — два фильтра рядом. */
.analytics-filterbar--cohorts {
    grid-template-columns: repeat(2, minmax(200px, 1fr)) auto;
    width: min(100%, 680px);
}
.analytics-filterbar label { min-width: 0; }
/* Вид подписи — общий, от label; здесь только её место над полем. */
.analytics-filterbar label > span {
    display: block;
    margin-bottom: 3px;
}
.analytics-filterbar select { width: 100%; }
.analytics-filterbar[aria-busy="true"] { cursor: progress; }
.analytics-filterbar[aria-busy="true"] :is(select, button, a) { pointer-events: none; }
.analytics-filter-chips {
    display: flex;
    grid-column: 1 / -1;
    align-items: center;
    gap: 6px;
    min-width: 0;
    padding-top: 7px;
    overflow-x: auto;
    border-top: 1px solid var(--border);
    scrollbar-width: thin;
}
.analytics-filter-chips-label {
    flex: 0 0 auto;
    color: var(--faint);
    font-size: 10.5px;
    font-weight: 700;
}
.analytics-filter-chip {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 5px;
    min-height: 27px;
    padding: 3px 7px 3px 9px;
    border: 1px solid color-mix(in srgb, var(--brand) 28%, var(--border));
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--ink);
    font: 600 11px/1.2 "Manrope", sans-serif;
    cursor: pointer;
}
.analytics-filter-chip b { color: var(--brand-ink); font-weight: 700; }
.analytics-filter-chip svg {
    width: 13px;
    height: 13px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
}
.analytics-filter-chip:hover { border-color: var(--brand); background: var(--card); }
.analytics-filter-chip:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.analytics-filter-reset {
    flex: 0 0 auto;
    align-self: center;
    color: var(--brand-ink);
    font-size: 12.5px;
    font-weight: 700;
    text-decoration: none;
}
.analytics-filter-reset:hover { text-decoration: underline; text-underline-offset: 3px; }
.analytics-kpis {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    margin: 0 0 12px;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
}
.analytics-kpis--compact {
    align-self: stretch;
    margin: 0;
}
.analytics-kpis > div {
    position: relative;
    min-width: 0;
    padding: 11px 14px 10px;
    border-right: 1px solid var(--border);
}
.analytics-kpis--compact > div { padding: 9px 10px 8px; }
.analytics-kpis > div:last-child { border-right: 0; }
.analytics-kpis > div::after {
    position: absolute;
    inset: auto 14px 0;
    height: 2px;
    background: var(--analytics-1);
    content: "";
}
.analytics-kpis > div:nth-child(2)::after { background: var(--analytics-0); }
.analytics-kpis > div:nth-child(3)::after { background: var(--analytics-2); }
.analytics-kpis > div:nth-child(4)::after { background: var(--analytics-3); }
.analytics-kpis dt { color: var(--muted); font-size: 12px; font-weight: 700; }
.analytics-kpis dd {
    margin: 3px 0 2px;
    color: var(--ink);
    font-size: clamp(22px, 2vw, 29px);
    font-weight: 700;
    letter-spacing: -.03em;
    font-variant-numeric: tabular-nums;
}
.analytics-kpis--compact dd { font-size: clamp(20px, 1.55vw, 25px); }
.analytics-kpis small { color: var(--faint); font-size: 11.5px; }
.analytics-kpis--compact small { font-size: 10.5px; }
.analytics-page-state { margin: 18px 0; }
.analytics-grid {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: 8px;
}
.analytics-panel {
    grid-column: span 6;
    min-width: 0;
    padding: 11px 12px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
}
.analytics-panel--wide { grid-column: span 6; }
.analytics-panel-heading {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 18px;
    min-height: 38px;
    margin-bottom: 6px;
}
.analytics-panel-heading > div { min-width: 0; }
.analytics-panel-heading h2,
.financial-panel-head h2,
.financial-section-heading h2 {
    margin: 0 0 2px;
    color: var(--ink);
    font-size: 15px;
    font-weight: 700;
    letter-spacing: -.01em;
    line-height: 1.3;
}
.analytics-panel-heading p {
    margin: 0;
    color: var(--muted);
    font-size: 11px;
    line-height: 1.4;
}
.analytics-panel-heading p strong { color: var(--ink); font-weight: 700; }
.analytics-unit {
    flex: 0 0 auto;
    padding-top: 2px;
    color: var(--faint);
    font-size: 10.5px;
    font-weight: 700;
    white-space: nowrap;
}
.analytics-chart-scroll { width: 100%; overflow-x: auto; scrollbar-width: thin; }
.analytics-line-chart {
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
}
.analytics-chart-grid { stroke: var(--surface-2); stroke-width: 1; }
.analytics-chart-domain { stroke: var(--border); stroke-width: 1; }
.analytics-chart-axis {
    fill: var(--faint);
    font-family: "Manrope", sans-serif;
    font-size: 10px;
    font-variant-numeric: tabular-nums;
}
.analytics-chart-axis--y { text-anchor: end; }
.analytics-chart-axis--x { text-anchor: middle; }
/* Axes and point targets stay in screen pixels; only the SVG geometry scales.
   The y-axis reserves its actual text width, including long money labels. */
.analytics-chart { container: analytics-chart / inline-size; }
.analytics-chart-axes {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    grid-template-rows: 208px 32px;
    gap: 10px 12px;
    padding: 12px 14px 0 0;
    margin-top: 8px;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    color: var(--muted);
}
.analytics-y-axis { display: flex; flex-direction: column-reverse; justify-content: space-between; text-align: right; }
.analytics-y-axis span { display: block; line-height: 0; white-space: nowrap; }
.analytics-line-plot { position: relative; min-width: 0; overflow: clip; overflow-clip-margin: 14px; }
.analytics-plot-svg { display: block; width: 100%; height: 100%; overflow: hidden; }
.analytics-x-axis { grid-column: 2; position: relative; min-width: 0; line-height: 1.5; }
.analytics-x-axis span { position: absolute; white-space: nowrap; transform: translateX(-50%); }
.analytics-x-axis span:first-child { transform: none; }
.analytics-x-axis span:last-child:not(:first-child) { transform: translateX(-100%); }
.analytics-x-axis .is-sync-x { color: var(--ink); font-weight: 700; }
.analytics-chart-point {
    position: absolute;
    display: grid;
    place-items: center;
    width: 24px;
    height: 24px;
    min-height: 0;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    transform: translate(-50%, -50%);
    cursor: crosshair;
}
.analytics-chart-point::after { content: ''; width: 8px; height: 8px; border: 2px solid var(--point-color); border-radius: 50%; background: var(--card); }
.analytics-chart-point:hover,
.analytics-chart-point:focus-visible { z-index: 2; }
.analytics-chart-point:hover::after,
.analytics-chart-point.is-sync-source::after { background: var(--point-color); }
.analytics-chart-point:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
@container analytics-chart (min-width: 351px) and (max-width: 700px) {
    .analytics-x-axis span:nth-child(even):not(:last-child),
    .analytics-x-axis span:nth-last-child(2):not(:first-child) { display: none; }
}
@container analytics-chart (max-width: 350px) {
    .analytics-x-axis span { display: none; }
    .analytics-x-axis span:first-child,
    .analytics-x-axis span:nth-child(4),
    .analytics-x-axis span:last-child { display: block; }
}
.analytics-chart-line {
    fill: none;
    stroke-width: 2.5;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
    opacity: .94;
    transition: opacity .16s var(--ease), stroke-width .16s var(--ease);
}
.analytics-chart-dot {
    fill: var(--card);
    stroke-width: 2;
    vector-effect: non-scaling-stroke;
    transition: opacity .16s var(--ease), r .16s var(--ease);
}
.analytics-chart-dot:hover,
.analytics-chart-dot:focus,
.analytics-chart-dot.is-sync-source { r: 5px; opacity: 1; outline: none; }
.analytics-chart-dot:focus-visible { stroke-width: 4; }
.analytics-tooltip {
    position: fixed;
    z-index: var(--z-menu);
    max-width: min(280px, calc(100vw - 16px));
    padding: 7px 9px;
    border-radius: var(--radius-sm);
    background: var(--ink);
    box-shadow: var(--shadow);
    color: var(--card);
    font: 700 11px/1.35 "Manrope", sans-serif;
    font-variant-numeric: tabular-nums;
    pointer-events: none;
}
.analytics-chart [data-chart-series].is-hidden { opacity: .07; pointer-events: none; }
.analytics-chart[data-cohort-chart] [data-chart-series].is-hidden { visibility: hidden; }
.analytics-container.is-syncing-series .analytics-chart-line[data-analytics-sync-series]:not(.is-sync-series) {
    opacity: .16;
}
.analytics-chart-line.is-sync-series { stroke-width: 4; opacity: 1; }
.analytics-chart-dot.is-sync-x:not(.is-sync-source) {
    fill: var(--surface-2);
    stroke-width: 2.5;
    opacity: .72;
}
.analytics-chart-axis.is-sync-x { fill: var(--ink); font-weight: 700; }
.analytics-chart-series-0 { stroke: var(--analytics-0); }
.analytics-chart-series-1 { stroke: var(--analytics-1); }
.analytics-chart-series-2 { stroke: var(--analytics-2); }
.analytics-chart-series-3 { stroke: var(--analytics-3); }
.analytics-chart-series-4 { stroke: var(--analytics-4); }
.analytics-chart-series-5 { stroke: var(--analytics-5); }
.analytics-chart-series-6 { stroke: var(--analytics-6); }
.analytics-chart-series-7 { stroke: var(--analytics-7); }
.analytics-chart-series-8 { stroke: var(--analytics-8); }
.analytics-chart-series-9 { stroke: var(--analytics-9); }
.analytics-chart-series-10 { stroke: var(--analytics-10); }
.analytics-chart-series-11 { stroke: var(--analytics-11); }
.analytics-color-0 { background: var(--analytics-0); }
.analytics-color-1 { background: var(--analytics-1); }
.analytics-color-2 { background: var(--analytics-2); }
.analytics-color-3 { background: var(--analytics-3); }
.analytics-color-4 { background: var(--analytics-4); }
.analytics-color-5 { background: var(--analytics-5); }
.analytics-color-6 { background: var(--analytics-6); }
.analytics-color-7 { background: var(--analytics-7); }
.analytics-color-8 { background: var(--analytics-8); }
.analytics-color-9 { background: var(--analytics-9); }
.analytics-color-10 { background: var(--analytics-10); }
.analytics-color-11 { background: var(--analytics-11); }
.analytics-legend-shell {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    margin: 0 0 6px;
}
.analytics-legend-caption {
    flex: 0 0 auto;
    color: var(--faint);
    font-size: 10.5px;
    font-weight: 700;
}
.analytics-legend {
    display: flex;
    gap: 4px;
    margin: 0;
    padding: 0;
    overflow-x: auto;
    list-style: none;
    color: var(--muted);
    font-size: 10.5px;
    scrollbar-width: thin;
}
.analytics-legend li { display: inline-flex; white-space: nowrap; }
.analytics-legend-toggle {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    min-height: 26px;
    padding: 3px 7px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
}
.analytics-legend-toggle:hover { background: var(--surface-2); color: var(--ink); }
.analytics-legend-toggle:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.analytics-legend-toggle[aria-pressed="false"] { opacity: .5; text-decoration: line-through; }
.analytics-legend-toggle i { width: 16px; height: 3px; border-radius: 2px; }
.analytics-tabs { min-width: 0; }
.analytics-tablist {
    display: flex;
    gap: 3px;
    margin: 0 0 9px;
    padding: 3px;
    overflow-x: auto;
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    scrollbar-width: thin;
}
.analytics-tablist button {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 30px;
    padding: 5px 10px;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: var(--muted);
    font: 700 11.5px/1.25 "Manrope", sans-serif;
    cursor: pointer;
}
.analytics-tablist button:hover { color: var(--ink); }
.analytics-tablist button[aria-selected="true"] {
    background: var(--card);
    color: var(--ink);
    box-shadow: var(--lift);
}
.analytics-tablist button:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.analytics-tablist button span {
    min-width: 19px;
    padding: 1px 5px;
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--faint);
    font-size: 9.5px;
    font-variant-numeric: tabular-nums;
}
.analytics-chart-empty {
    display: grid;
    min-height: 132px;
    place-items: center;
    align-content: center;
    gap: 10px;
    color: var(--muted);
    font-size: 12.5px;
    text-align: center;
}
.analytics-chart-empty svg {
    width: 28px;
    height: 28px;
    fill: none;
    stroke: var(--border);
    stroke-width: 1.7;
    stroke-linecap: round;
}
.analytics-bars {
    display: grid;
    gap: 5px;
    margin: 0;
    padding: 0;
    list-style: none;
}
.analytics-bars li {
    display: grid;
    grid-template-columns: 22px minmax(105px, .8fr) minmax(100px, 1.6fr) minmax(66px, auto);
    align-items: center;
    gap: 9px;
    min-height: 26px;
}
.analytics-bar-rank { color: var(--faint); font-size: 10.5px; font-variant-numeric: tabular-nums; }
.analytics-bar-copy { display: grid; min-width: 0; }
.analytics-bar-copy small {
    overflow: hidden;
    color: var(--faint);
    font-size: 9.5px;
    line-height: 1.15;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.analytics-bar-label {
    overflow: hidden;
    color: var(--ink);
    font-size: 12px;
    font-weight: 600;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.analytics-cell-filter {
    display: inline-flex;
    min-width: 0;
    align-items: center;
    gap: 5px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--ink);
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.analytics-cell-filter span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.analytics-cell-filter svg {
    flex: 0 0 auto;
    width: 12px;
    height: 12px;
    fill: none;
    stroke: var(--faint);
    stroke-width: 1.7;
    stroke-linejoin: round;
    opacity: .35;
}
.analytics-cell-filter:hover { color: var(--brand-ink); }
.analytics-cell-filter:hover svg,
.analytics-cell-filter:focus-visible svg { opacity: 1; stroke: var(--brand); }
.analytics-cell-filter:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.analytics-bar-track {
    display: block;
    height: 7px;
    overflow: hidden;
    border-radius: 2px;
    background: var(--surface-2);
}
.analytics-bar-track i { display: block; width: max(2px, var(--bar-size)); height: 100%; }
.analytics-bars strong {
    color: var(--ink);
    font-size: 11.5px;
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}
.analytics-table-scroll { max-height: 304px; }
.analytics-table { min-width: 860px; }
.analytics-table td,
.analytics-table th { font-size: 12px; }
/* Посещаемость. Плитки показателей — вкладки графика: выбранная задаёт ряд
   динамики, рядом со значением — изменение к периоду сравнения. */
.analytics-page-note { margin-top: 3px; color: var(--warn); font-size: 12px; }
.analytics-kpi-tabs {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    margin: 0 0 10px;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
}
.analytics-kpi-tab {
    position: relative;
    display: grid;
    align-content: start;
    gap: 3px;
    min-width: 0;
    min-height: 0;
    padding: 10px 14px 12px;
    border: 0;
    border-right: 1px solid var(--border);
    border-radius: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.analytics-kpi-tab:last-child { border-right: 0; }
.analytics-kpi-tab:hover { background: var(--hover); }
.analytics-kpi-tab[aria-selected="true"] { background: color-mix(in srgb, var(--analytics-0) 7%, var(--card)); }
.analytics-kpi-tab[aria-selected="true"]::after {
    position: absolute;
    inset: auto 0 0;
    height: 3px;
    background: var(--analytics-0);
    content: "";
}
.analytics-kpi-tab:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.analytics-kpi-label { color: var(--muted); font-size: 12px; font-weight: 700; }
.analytics-kpi-value {
    color: var(--ink);
    font-size: clamp(21px, 1.7vw, 26px);
    font-weight: 700;
    letter-spacing: -.03em;
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.analytics-kpi-foot { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 6px; min-width: 0; }
.analytics-kpi-foot small { color: var(--faint); font-size: 11px; }
.analytics-delta {
    display: inline-flex;
    align-items: baseline;
    gap: 2px;
    font-size: 11.5px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.analytics-delta b { font-size: 8.5px; }
.analytics-delta--bad { color: var(--err); }
.analytics-delta--good { color: var(--ok-ink); }
.analytics-delta--neutral { color: var(--muted); }
.analytics-panel--attendance-trend,
.analytics-panel--breakdown { margin-bottom: 10px; }
.analytics-step-switch {
    display: inline-flex;
    flex: 0 0 auto;
    gap: 3px;
    padding: 3px;
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.analytics-step-switch button {
    min-height: 30px;
    padding: 5px 10px;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: var(--muted);
    font: 700 11.5px/1.25 "Manrope", sans-serif;
    cursor: pointer;
}
.analytics-step-switch button:hover { color: var(--ink); }
.analytics-step-switch button[aria-pressed="true"] { background: var(--card); color: var(--ink); box-shadow: var(--lift); }
.analytics-step-switch button:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }

/* Динамика: SVG тянет только линии; подписи, точки и полосы наведения — HTML. */
.analytics-trend { container: analytics-trend / inline-size; min-width: 0; }
.analytics-trend-legend { flex-wrap: wrap; margin: 0 0 4px; }
.analytics-trend-note { display: inline-flex; align-items: center; gap: 5px; padding: 3px 7px; }
.analytics-trend-key { display: inline-block; width: 16px; height: 0; border-top: 2px solid; }
.analytics-trend-key--raw { border-top-color: color-mix(in srgb, var(--analytics-0) 45%, var(--card)); }
.analytics-trend-key--raw.is-main,
.analytics-trend-key--smooth { border-top: 3px solid var(--analytics-0); }
.analytics-trend-key--compare { border-top: 2px dashed var(--faint); }
.analytics-trend-key--band { width: 10px; height: 10px; border: 0; border-radius: 2px; background: var(--surface-2); }
.analytics-trend-key--running { width: 9px; height: 9px; border: 1.5px dashed var(--analytics-0); border-radius: 50%; }
.analytics-trend-axes {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr) max-content;
    grid-template-rows: 260px 34px;
    gap: 8px 12px;
    padding-top: 10px;
    color: var(--muted);
    font-size: 12px;
    font-variant-numeric: tabular-nums;
}
.analytics-trend-plot { position: relative; min-width: 0; }
.analytics-trend-band { fill: var(--surface-2); }
.analytics-trend-line {
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
}
.analytics-trend-line--raw { stroke: color-mix(in srgb, var(--analytics-0) 45%, var(--card)); stroke-width: 1.5; }
.analytics-trend-line--raw.is-main { stroke: var(--analytics-0); stroke-width: 2.5; }
.analytics-trend-line--tail { stroke: color-mix(in srgb, var(--analytics-0) 55%, var(--card)); stroke-width: 1.5; stroke-dasharray: 3 3; }
.analytics-trend-line--smooth { stroke: var(--analytics-0); stroke-width: 2.8; }
.analytics-trend-line--compare { stroke: var(--faint); stroke-width: 1.7; stroke-dasharray: 5 4; }
.analytics-trend-running {
    position: absolute;
    width: 9px;
    height: 9px;
    border: 1.5px dashed var(--analytics-0);
    border-radius: 50%;
    background: var(--card);
    transform: translate(-50%, -50%);
    pointer-events: none;
}
.analytics-trend-hit {
    position: absolute;
    top: 0;
    bottom: 0;
    min-width: 24px;
    min-height: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    transform: translateX(-50%);
    cursor: crosshair;
}
.analytics-trend-hit::before {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    border-left: 1px solid var(--ink);
    opacity: 0;
    content: "";
}
.analytics-trend-hit:hover::before,
.analytics-trend-hit:focus-visible::before { opacity: .3; }
.analytics-trend-hit:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.analytics-trend-dot {
    position: absolute;
    left: 50%;
    width: 9px;
    height: 9px;
    border: 2px solid var(--card);
    border-radius: 50%;
    opacity: 0;
    transform: translate(-50%, -50%);
}
.analytics-trend-hit:hover .analytics-trend-dot,
.analytics-trend-hit:focus-visible .analytics-trend-dot { opacity: 1; }
.analytics-trend-dot--raw { background: color-mix(in srgb, var(--analytics-0) 55%, var(--card)); }
.analytics-trend-dot--smooth { background: var(--analytics-0); }
.analytics-trend-dot--compare { background: var(--faint); }
.analytics-trend [data-chart-series].is-hidden { opacity: .07; }
.analytics-trend .analytics-trend-dot.is-hidden { display: none; }
.analytics-trend-ends { position: relative; min-width: 104px; }
.analytics-trend-end {
    position: absolute;
    left: 0;
    color: var(--muted);
    font-size: 11px;
    white-space: nowrap;
    transform: translateY(-50%);
}
.analytics-trend-end b { color: var(--ink); font-size: 13px; }
.analytics-trend-end--compare,
.analytics-trend-end--compare b { color: var(--faint); }
.analytics-trend-x span small { display: block; color: var(--muted); font-size: 11px; font-weight: 700; }
@container analytics-trend (max-width: 640px) {
    .analytics-trend-x span.is-minor { display: none; }
}

/* Разрез: сумма столбца «Изменение» равна изменению итога; полоса растёт от
   середины влево (меньше) или вправо (больше) в масштабе самой большой строки. */
.analytics-breakdown-scroll {
    max-height: 520px;
    overflow: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
}
/* clip, а не hidden: у table.grid скругление режет углы, а hidden сделал бы
   таблицу своим контейнером прокрутки, и шапка с итогом не прилипали бы. */
table.grid.analytics-breakdown { overflow: clip; box-shadow: none; }
.analytics-breakdown thead th { position: sticky; top: 0; z-index: 1; }
.analytics-breakdown .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.analytics-breakdown tfoot td {
    position: sticky;
    bottom: 0;
    height: 40px;
    padding: 0 var(--cell-x);
    border-top: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--ink);
    font-size: 12px;
    font-weight: 700;
}
.analytics-before { color: var(--faint); }
.analytics-change-head { width: 30%; }
.analytics-change { display: flex; align-items: center; gap: 10px; min-width: 190px; }
.analytics-change-track { position: relative; flex: 1 1 auto; height: 8px; }
.analytics-change-track::before {
    position: absolute;
    top: -5px;
    bottom: -5px;
    left: 50%;
    border-left: 1px solid var(--border);
    content: "";
}
.analytics-change-track--total::before { display: none; }
.analytics-change-bar { position: absolute; top: 0; width: calc(var(--bar) / 2); height: 8px; border-radius: 2px; }
.analytics-change-bar--down { right: 50%; background: color-mix(in srgb, var(--danger) 70%, var(--card)); }
.analytics-change-bar--up { left: 50%; background: color-mix(in srgb, var(--ok) 70%, var(--card)); }
.analytics-change-value { flex: 0 0 64px; text-align: right; font-variant-numeric: tabular-nums; }
.analytics-change-value--down { color: var(--err); }
.analytics-change-value--up { color: var(--ok-ink); }
.analytics-change-value--flat { color: var(--muted); }
.analytics-panel-note { margin: 8px 0 0; color: var(--faint); font-size: 12px; }
.analytics-panel-note a { color: var(--brand-ink); font-weight: 700; }

.analytics-columns {
    display: flex;
    align-items: stretch;
    gap: 6px;
    min-height: 198px;
    padding: 2px 2px 0;
    overflow-x: auto;
    scrollbar-width: thin;
}
.analytics-column {
    display: grid;
    grid-template-rows: 18px minmax(140px, 1fr) 26px;
    flex: 1 0 42px;
    min-width: 42px;
    max-width: 82px;
    text-align: center;
    transition: background-color .16s var(--ease);
}
.analytics-column.is-sync-series {
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.analytics-column > strong {
    color: var(--ink);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
}
.analytics-column > span {
    align-self: center;
    color: var(--faint);
    font-size: 9.5px;
    line-height: 1.2;
}
.analytics-column-space { display: flex; align-items: end; border-bottom: 1px solid var(--border); }
.analytics-column-stack {
    display: flex;
    flex-direction: column-reverse;
    width: 100%;
    height: max(2px, var(--column-height));
    overflow: hidden;
    border-radius: 3px 3px 0 0;
}
.analytics-column-stack > :is(i, button) {
    position: relative;
    flex-grow: var(--segment-value);
    min-height: 1px;
}
.analytics-container--cohorts .analytics-column-stack > :is(i, button) {
    box-shadow: inset 0 1px var(--gloss);
}
.analytics-column-segment {
    width: 100%;
    padding: 0;
    border: 0;
    cursor: pointer;
}
.analytics-column-segment:hover,
.analytics-column-segment:focus-visible {
    z-index: 1;
    filter: brightness(1.12) saturate(1.12);
    outline: 2px solid var(--ink);
    outline-offset: -2px;
}
.analytics-heatmap-scroll { overflow: auto; scrollbar-width: thin; }
.analytics-heatmap {
    width: 100%;
    min-width: 680px;
    border-collapse: separate;
    border-spacing: 3px;
}
.analytics-heatmap th,
.analytics-heatmap td {
    height: 26px;
    padding: 3px 5px;
    border-radius: 4px;
    font-size: 10.5px;
    font-variant-numeric: tabular-nums;
    text-align: center;
    white-space: nowrap;
}
.analytics-heatmap thead th { color: var(--faint); font-weight: 700; }
.analytics-heatmap tbody th { color: var(--muted); font-weight: 700; text-align: left; }
.analytics-heatmap td { color: var(--ink); }
.analytics-heatmap tr.is-sync-series th,
.analytics-heatmap tr.is-sync-series td { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--brand) 36%, transparent); }
.analytics-heatmap td.is-sync-x { box-shadow: inset 0 0 0 2px var(--brand); }
.analytics-heatmap td:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.analytics-heat--1 { background: color-mix(in oklab, var(--analytics-heat) 12%, var(--card)); }
.analytics-heat-0 { background: color-mix(in oklab, var(--analytics-heat) 8%, var(--card)); }
.analytics-heat-1 { background: color-mix(in oklab, var(--analytics-heat) 18%, var(--card)); }
.analytics-heat-2 { background: color-mix(in oklab, var(--analytics-heat) 32%, var(--card)); }
.analytics-heat-3 { background: color-mix(in oklab, var(--analytics-heat) 48%, var(--card)); }
.analytics-heat-4 { background: color-mix(in oklab, var(--analytics-heat) 66%, var(--card)); color: var(--ink); }
.analytics-heat-5 {
    background: color-mix(in srgb, var(--analytics-heat) 78%, var(--ink));
    color: var(--on-brand);
}
.analytics-heatmap td.analytics-heat-5 { color: var(--on-brand); }
.analytics-heat-legend {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
    margin-top: 7px;
    color: var(--faint);
    font-size: 10px;
}
.analytics-heat-legend i { width: 18px; height: 8px; border-radius: 2px; }

/* Когортам нужна более спокойная плотность: здесь 12 рядов сравнивают
   глазами дольше, чем оперативные показатели посещаемости. Шапки страницы и
   панелей и подписи фильтров при этом общие со всеми вкладками «Аналитики». */
.analytics-container--cohorts .analytics-filterbar select {
    min-height: 38px;
    font-size: 14px;
}
.analytics-container--cohorts .analytics-panel {
    padding: 14px 16px 15px;
}
.analytics-container--cohorts .analytics-panel-heading {
    min-height: 44px;
    margin-bottom: 9px;
}
.analytics-container--cohorts .analytics-panel-heading > div {
    flex: 1 1 auto;
}
.analytics-container--cohorts .analytics-panel-heading p { max-width: none; }
.analytics-container--cohorts .analytics-unit { font-size: 11.5px; }
.analytics-container--cohorts .analytics-legend-caption,
.analytics-container--cohorts .analytics-legend { font-size: 11.5px; }
.analytics-container--cohorts .analytics-legend-toggle {
    min-height: 28px;
    padding-inline: 8px;
}
.analytics-container--cohorts .analytics-chart-axis { font-size: 11.5px; }
.analytics-container--cohorts .analytics-column > strong { font-size: 12.5px; }
.analytics-container--cohorts .analytics-column > span { font-size: 11px; }
.analytics-container--cohorts .analytics-heatmap th,
.analytics-container--cohorts .analytics-heatmap td {
    height: 29px;
    font-size: 11.5px;
}
.analytics-container--cohorts .analytics-heat-legend { font-size: 11.5px; }
.analytics-cohort-controls { grid-column: 1 / -1; }
.analytics-cohort-controls { min-width: 0; padding: 8px 0; }
.analytics-cohort-actions { display: flex; flex-wrap: wrap; align-items: end; gap: 12px; margin-bottom: 8px; }
.analytics-cohort-actions > div { flex: 1 1 260px; }
.analytics-cohort-actions h2 { margin: 0; font-size: 15px; }
.analytics-cohort-actions p { margin: 4px 0 0; color: var(--muted); font-size: 12px; }
.analytics-cohort-actions label { display: grid; gap: 4px; font-size: 12px; }
.analytics-cohort-actions select { min-height: 36px; font-size: 13px; }
.analytics-cohort-controls .analytics-legend,
.analytics-panel--cohort-sizes .analytics-legend { flex-wrap: wrap; overflow: visible; }
.analytics-cohort-controls .analytics-legend-toggle { min-height: 36px; }
.analytics-heatmap tbody th { position: sticky; left: 0; z-index: 1; background: var(--card); }
.analytics-panel--cohort-sizes {
    display: flex;
    flex-direction: column;
}
.analytics-panel--cohort-sizes > .analytics-chart {
    display: flex;
    flex: 1 1 auto;
    min-height: 0;
    flex-direction: column;
}
.analytics-panel--cohort-sizes .analytics-columns {
    flex: 1 1 auto;
}

/* «Приток и отток»: синий — пришли, медный — ушли (analytics-blue и
   analytics-copper из DESIGN.md). Пара различима при дальтонизме и держит
   контраст 3:1 на белой карточке. */
.app-shell .analytics-container.analytics-container--flow {
    --flow-in: var(--admin-1-accent);
    --flow-out: var(--admin-6-accent);
    --flow-delta: var(--admin-4-accent);
}
.analytics-container--flow .analytics-attendance-overview {
    position: static;
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
}
/* Филиал — своей строкой, под ним две пары «Год + Месяц» под общей подписью
   «Первый месяц» / «Последний месяц» (_period_filters.html, group_label) и
   кнопка: рядом с KPI шесть полей в одну строку не помещаются. */
.analytics-filterbar.analytics-filterbar--flow {
    position: static;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
    width: 100%;
    align-self: start;
    margin: 0;
}
.analytics-filterbar--flow > label:first-child { grid-column: 1 / -1; }
.month-filter-group { min-width: 0; }
.month-filter-fields { display: grid; grid-template-columns: 62px minmax(0, 1fr); gap: 8px; }
.analytics-filterbar .month-filter-caption {
    display: block;
    margin-bottom: 3px;
}
/* Показатели не тянутся за фильтром, ставшим выше: черта — сразу под подписью. */
.analytics-kpis--flow { align-self: start; }
.analytics-filterbar--flow :is(select, input) {
    width: 100%;
    min-width: 0;
    min-height: 38px;
    font-size: 13px;
}
/* Год — четыре цифры: без стрелок он помещается в узкую колонку. */
.analytics-filterbar--flow .month-filter-year input { padding-inline: 10px; appearance: textfield; }
.analytics-filterbar--flow .month-filter-year input::-webkit-inner-spin-button { appearance: none; margin: 0; }
.analytics-flow-apply { min-height: 38px; white-space: nowrap; }
.analytics-kpis--flow > div::after { background: var(--flow-in); }
.analytics-kpis--flow > div:nth-child(2)::after,
.analytics-kpis--flow > div:nth-child(4)::after { background: var(--flow-out); }
.analytics-kpis--flow > div:nth-child(3)::after { background: var(--flow-delta); }
.analytics-panel--flow { grid-column: 1 / -1; }
.analytics-flow-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;
    margin: 0 0 4px;
    padding: 0;
    list-style: none;
    color: var(--muted);
    font-size: 11.5px;
    font-weight: 600;
}
.analytics-flow-legend li { display: inline-flex; align-items: center; gap: 7px; }
.analytics-flow-key {
    display: inline-block;
    width: 16px;
    height: 0;
    border-top: 2px solid var(--flow-in);
    vertical-align: middle;
}
.analytics-flow-key.is-out { border-top-color: var(--flow-out); }
.analytics-flow-key.is-delta { border-top-color: var(--flow-delta); }
.analytics-flow-key.is-dashed { border-top-style: dashed; }
.analytics-flow-chart { min-width: 720px; }
.analytics-flow-marks { pointer-events: none; }
.analytics-flow-hit { fill: transparent; cursor: crosshair; outline: none; }
.analytics-flow-hit:hover,
.analytics-flow-hit:focus-visible,
.analytics-flow-hit.is-sync-x { fill: var(--surface-2); }
.analytics-flow-hit:focus-visible { stroke: var(--brand); stroke-width: 1.5; }
.analytics-flow-wash.is-gain { fill: color-mix(in srgb, var(--flow-in) 13%, transparent); }
.analytics-flow-wash.is-loss { fill: color-mix(in srgb, var(--flow-out) 15%, transparent); }
.analytics-flow-line {
    fill: none;
    stroke: var(--flow-in);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.analytics-flow-line.is-out { stroke: var(--flow-out); }
.analytics-flow-line.is-delta { stroke: var(--flow-delta); stroke-width: 2.5; }
.analytics-flow-line.is-provisional { stroke-dasharray: 5 4; }
.analytics-flow-whisker { stroke: var(--flow-out); stroke-width: 1.5; }
.analytics-flow-dot { fill: var(--flow-in); stroke: var(--card); stroke-width: 2; }
.analytics-flow-dot.is-out { fill: var(--flow-out); }
.analytics-flow-dot.is-open { fill: var(--card); stroke: var(--flow-out); }
.analytics-flow-dot.is-delta { fill: var(--flow-delta); }
.analytics-flow-dot.is-delta.is-open { fill: var(--card); stroke: var(--flow-delta); }
.analytics-flow-value {
    fill: var(--ink);
    font: 700 11px "Manrope", sans-serif;
    font-variant-numeric: tabular-nums;
    paint-order: stroke;
    stroke: var(--card);
    stroke-width: 3px;
    stroke-linejoin: round;
}
.analytics-flow-value--end { fill: var(--muted); font-weight: 600; text-anchor: end; }
.analytics-flow-value-label { fill: var(--muted); font-weight: 600; }
.analytics-flow-leader { fill: none; stroke: var(--border); stroke-width: 1; }
.analytics-flow-year { fill: var(--faint); font-weight: 600; }
.analytics-flow-note {
    margin: 8px 0 0;
    padding: 8px 10px;
    border: 1px solid var(--warn-border);
    border-radius: var(--radius-sm);
    background: var(--warn-tint);
    color: var(--ink);
    font-size: 12px;
    line-height: 1.45;
}
.analytics-flow-table {
    width: 100%;
    min-width: 760px;
    border-collapse: collapse;
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
}
.analytics-flow-table :is(th, td) {
    padding: 7px 10px;
    border-bottom: 1px solid var(--surface-2);
    text-align: right;
    white-space: nowrap;
}
.analytics-flow-table :is(thead, tbody, tfoot) th:first-child { text-align: left; }
.analytics-flow-table thead th { border-bottom-color: var(--border); color: var(--faint); font-size: 11px; font-weight: 700; }
.analytics-flow-table thead .analytics-flow-key { margin-right: 6px; }
.analytics-flow-table tbody th { color: var(--ink); font-weight: 600; }
.analytics-flow-table td { color: var(--ink); }
.analytics-flow-table tfoot :is(th, td) { border-top: 1px solid var(--border); border-bottom: 0; font-weight: 700; }
.analytics-flow-table tbody tr.is-sync-x :is(th, td) { background: var(--surface-2); }
.analytics-flow-defs {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0 24px;
    margin: 0;
}
.analytics-flow-defs > div { min-width: 0; padding: 8px 0; border-top: 1px solid var(--surface-2); }
.analytics-flow-defs dt { color: var(--ink); font-size: 12.5px; font-weight: 700; }
.analytics-flow-defs dd { margin: 2px 0 0; color: var(--muted); font-size: 12px; line-height: 1.45; }
@media (min-width: 1280px) {
    .analytics-container--flow .analytics-attendance-overview {
        grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
    }
}
@media (max-width: 1100px) {
    .analytics-filterbar.analytics-filterbar--flow { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .analytics-flow-apply { grid-column: 1 / -1; }
    .analytics-flow-defs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
    /* Общие графики аналитики сжимаются до 510px; здесь подписей больше —
       шире и с прокруткой, чтобы текст оставался читаемым. */
    .analytics-line-chart.analytics-flow-chart { min-width: 720px; }
}
@media (max-width: 560px) {
    /* Пара «Год + Месяц» — своей строкой. */
    .analytics-filterbar.analytics-filterbar--flow { grid-template-columns: minmax(0, 1fr); }
    .analytics-flow-defs { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 1100px) {
    .analytics-panel,
    .analytics-panel--wide { grid-column: 1 / -1; }
}
@media (max-width: 1180px) {
    .analytics-attendance-overview {
        position: static;
        grid-template-columns: 1fr;
    }
    .analytics-filterbar { grid-template-columns: repeat(3, minmax(150px, 1fr)); }
    .analytics-filterbar--compact { grid-template-columns: minmax(240px, 380px) auto; }
    .analytics-filterbar--cohorts { grid-template-columns: repeat(2, minmax(180px, 1fr)) auto; }
}
@media (max-width: 760px) {
    .analytics-page-heading { display: grid; gap: 10px; }
    .analytics-freshness { justify-self: start; }
    .analytics-filterbar,
    .analytics-filterbar--compact,
    .analytics-filterbar--cohorts { grid-template-columns: 1fr; }
    .analytics-filterbar { position: static; }
    .analytics-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .analytics-kpis > div:nth-child(2) { border-right: 0; }
    .analytics-kpis > div:nth-child(-n + 2) { border-bottom: 1px solid var(--border); }
    .analytics-line-chart { min-width: 510px; }
    .analytics-kpi-tabs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .analytics-kpi-tab:nth-child(2) { border-right: 0; }
    .analytics-kpi-tab:nth-child(-n + 2) { border-bottom: 1px solid var(--border); }
    .analytics-trend-axes { grid-template-rows: 220px 34px; }
    .analytics-trend-ends { min-width: 64px; }
    .analytics-legend-shell { align-items: flex-start; flex-direction: column; gap: 2px; }
}
@media (max-width: 560px) {
    .app-shell .container.analytics-container { padding-inline: 12px; padding-bottom: 38px; }
    .analytics-kpis > div { padding: 10px 11px 9px; }
    .analytics-panel { padding: 12px 11px 13px; }
    .analytics-panel-heading { display: grid; gap: 5px; }
    .analytics-bars li { grid-template-columns: 18px minmax(100px, 1fr) minmax(60px, auto); }
    .analytics-bar-track { grid-column: 2 / -1; grid-row: 2; }
}
@media (prefers-reduced-motion: reduce) {
    .analytics-chart-line,
    .analytics-chart-dot { transition: none; }
}
.code-block {
    overflow-x: auto;
    margin: 10px 0;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.page-header.compact {
    margin-bottom: 12px;
}
.json-pre {
    max-width: 520px;
    max-height: 320px;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-word;
    margin: 10px 0 0;
    padding: 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    font-size: 12px;
    line-height: 1.45;
}

@media (max-width: 900px) {
    /* Раньше сайдбар раскладывался в строку поверх контента: девятнадцать
       одинаковых чипсов без группировки (.nav-section скрывался), и до самой
       страницы приходилось прокручивать половину экрана. Теперь это выдвижная
       панель, а шапка получает кнопку вызова. */
    .app-shell { flex-direction: row; }
    .sidebar-collapse { display: none; }
    .sidebar {
        position: fixed;
        inset: 0 auto 0 0;
        width: min(292px, 86vw);
        max-width: 86vw;
        flex: none;
        padding: 16px 14px;
        height: 100dvh;
        max-height: 100dvh;
        overflow: hidden;
        overscroll-behavior: contain;
        scrollbar-width: thin;
        transform: translateX(-100%);
        transition: transform .24s var(--ease);
        box-shadow: var(--shadow);
        z-index: var(--z-submenu);
    }
    .nav-dropdown { display: grid; }
    .nav-submenu {
        position: static;
        min-width: 0;
        gap: 1px;
        margin: 2px 0 4px 20px;
        padding: 0 0 0 10px;
        border: 0;
        border-left: 1px solid var(--border);
        border-radius: 0;
        box-shadow: none;
    }
    .nav-subitem { padding: 7px 10px; color: var(--muted); line-height: 1.25; }
    .nav-dropdown:hover > .nav-submenu,
    .nav-dropdown:focus-within > .nav-submenu { display: none; }
    .nav-dropdown > .nav-parent[aria-expanded="true"] + .nav-submenu { display: grid; }
    body[data-nav-open="1"] .sidebar { transform: translateX(0); }
    .nav-scrim {
        display: block;
        position: fixed;
        inset: 0;
        z-index: var(--z-sidebar);
        background: var(--scrim);
        opacity: 0;
        pointer-events: none;
        transition: opacity .24s ease;
    }
    body[data-nav-open="1"] .nav-scrim { opacity: 1; pointer-events: auto; }
    .nav-burger {
        display: inline-flex; align-items: center; justify-content: center;
        width: 38px; height: 38px; flex: 0 0 38px; padding: 0;
        border: 1px solid var(--border); border-radius: var(--radius-sm);
        background: var(--card); color: var(--ink);
        transition: background var(--dur) ease, border-color var(--dur) ease;
    }
    .nav-burger:hover { background: var(--hover); border-color: var(--border); }
    .nav-burger svg {
        width: 20px; height: 20px; fill: none; stroke: currentColor;
        stroke-width: 2; stroke-linecap: round;
    }
    .main-shell { width: 100%; }
    /* Шапка держится в одну строку; учётка теперь находится в сайдбаре. */
    .topbar { flex-wrap: nowrap; gap: 8px; padding: 5px 14px; }
    .topbar-heading { flex: 1 1 auto; min-width: 0; }
    .topbar-section { max-width: 38%; }
    .topbar-chips { flex: 0 0 auto; flex-wrap: nowrap; gap: 6px; }
    .hui-combobox-trigger { min-width: 0; padding: 0 8px; }
    .hui-combobox-value { max-width: 78px; overflow: hidden; text-overflow: ellipsis; }
    .app-shell .container { padding: 20px 18px 42px; }
}

/* «Мой день» — рабочая очередь задач админа */
.myday-page-header { align-items: baseline; flex-wrap: wrap; gap: 12px; }
.myday-date { color: var(--muted); }
.myday-all-link { margin-left: auto; font-size: 14px; font-weight: 600; text-decoration: none; }
.myday-status-strip {
    display: flex; align-items: stretch; flex-wrap: wrap;
    margin-bottom: 12px;
    border: 1px solid var(--border); border-radius: var(--radius-md);
    background: var(--card); overflow: hidden;
}
.myday-status-item {
    display: inline-flex; flex: 1 1 150px; align-items: center; justify-content: space-between;
    gap: 12px; min-height: 42px; padding: 7px 13px;
    border-inline-end: 1px solid var(--border); color: var(--muted); font-size: 13px;
}
.myday-status-item:last-child { border-inline-end: 0; }
.myday-status-item strong { color: var(--ink); font-size: 15px; font-variant-numeric: tabular-nums; }
.myday-status-item.is-overdue strong { color: var(--err); }
.myday-status-item.is-done strong { color: var(--ok); }

/* Сводка и фильтры — одна строка: очередь начинается сразу под ними. */
.myday-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 16px; margin-bottom: 20px; }
.myday-toolbar .myday-status-strip { flex: 1 1 520px; min-width: 0; margin-bottom: 0; }
.myday-filters { display: flex; min-width: 0; max-width: 100%; flex-wrap: wrap; align-items: center; gap: 10px 16px; }
.myday-seg {
    display: inline-flex; max-width: 100%; height: var(--control-h); overflow-x: auto;
    border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--card);
}
.myday-seg-item {
    display: inline-flex; align-items: center; padding: 0 12px;
    border-inline-start: 1px solid var(--border); color: var(--muted);
    font-size: 13px; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.myday-seg-item:first-child { border-inline-start: 0; }
.myday-seg-item:hover { background: var(--hover); color: var(--ink); }
.myday-seg-item.is-on { background: var(--selected); color: var(--ink); }
.myday-seg-item:focus-visible,
.myday-others:focus-visible { outline: var(--ring-w) solid var(--ring); outline-offset: calc(var(--ring-offset) * -1); }
.myday-branch-form { display: flex; align-items: flex-end; gap: 10px; margin: 0; }
.myday-branch-form > label { min-width: 200px; }
.myday-others {
    display: inline-flex; align-items: center; gap: 8px; min-height: var(--control-h);
    border-radius: var(--radius-sm); color: var(--muted);
    font-size: 13px; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.myday-others:hover { color: var(--ink); }
.myday-others-box {
    display: inline-grid; place-items: center; width: 16px; height: 16px;
    border: 1.5px solid color-mix(in oklab, var(--muted) 55%, var(--card)); border-radius: 4px;
    background: var(--card); color: var(--on-brand);
}
.myday-others.is-on .myday-others-box { border-color: var(--brand); background: var(--brand); }
.myday-others-box svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }

.myday-group { margin-bottom: 24px; }
.myday-group-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.myday-group-head h2 { margin: 0; color: var(--ink); font-size: 15px; font-weight: 700; }
.myday-count {
    min-width: 22px; padding: 1px 7px; border-radius: 999px; background: var(--surface-2);
    color: var(--muted); font-size: 12px; font-weight: 600; text-align: center; font-variant-numeric: tabular-nums;
}
.myday-overdue .myday-count { background: var(--danger-soft); color: var(--err); }
.myday-note { color: var(--faint); font-size: 13px; }

/* Строка очереди — это звонок: срок и филиал, кто и зачем, два факта о
   клиенте, номер на кнопке и итог в одно нажатие. */
/* Без overflow: hidden — иначе меню «⋯» обрезается рамкой списка. Скругление
   поэтому несут крайние строки. */
.myday-rows { border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card); }
.myday-row:first-child { border-top-left-radius: calc(var(--radius-md) - 1px); border-top-right-radius: calc(var(--radius-md) - 1px); }
.myday-row:last-child { border-bottom-left-radius: calc(var(--radius-md) - 1px); border-bottom-right-radius: calc(var(--radius-md) - 1px); }
.myday-row {
    display: grid; grid-template-columns: 124px minmax(0, 1fr) auto; align-items: center;
    gap: 16px; min-height: 68px; padding: 12px 16px; border-top: 1px solid var(--border);
}
.myday-row:first-child { border-top: 0; }
.myday-row:focus { outline: var(--ring-w) solid var(--ring); outline-offset: calc(var(--ring-offset) * -1); }
.myday-row.is-next { background: color-mix(in oklab, var(--selected) 55%, var(--card)); box-shadow: inset 3px 0 0 var(--marker); }
.myday-row-due { display: flex; min-width: 0; flex-direction: column; gap: 3px; }
.myday-due {
    display: inline-flex; align-items: center; gap: 6px; color: var(--ink);
    font-size: 13px; font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums;
}
.myday-due.is-overdue { color: var(--err); }
.myday-due.is-soon { color: var(--warn); }
.myday-due.is-later, .myday-due.is-none { color: var(--muted); font-weight: 500; }
.myday-due-dot { width: 7px; height: 7px; flex: 0 0 7px; border-radius: 50%; background: var(--err); }
.myday-row-branch { overflow: hidden; color: var(--faint); font-size: 12.5px; text-overflow: ellipsis; white-space: nowrap; }
.myday-row-main { min-width: 0; }
.myday-row-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; }
.myday-name, .myday-name a { color: var(--ink); font-size: 15px; font-weight: 700; text-decoration: none; }
.myday-name:hover, .myday-name a:hover { text-decoration: underline; text-underline-offset: 3px; }
.myday-goal { color: var(--muted); font-size: 13px; font-weight: 500; text-decoration: none; }
.myday-goal:hover { color: var(--brand-ink); text-decoration: underline; text-underline-offset: 3px; }
.myday-row-facts { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 0; margin-top: 4px; color: var(--muted); font-size: 13px; }
.myday-fact + .myday-fact::before { content: "·"; margin: 0 8px; color: var(--faint); }
.myday-attempt {
    display: inline-flex; align-items: center; margin-right: 10px; padding: 1px 8px;
    border: 1px solid var(--warn-border); border-radius: 999px; background: var(--warn-soft);
    color: var(--warn); font-size: 12px; font-weight: 500; white-space: nowrap;
}
.myday-row-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
.myday-outcome { display: flex; margin: 0; }
.myday-phone { font-variant-numeric: tabular-nums; }
.t-tel { text-decoration: none; font-variant-numeric: tabular-nums; white-space: nowrap; }
.myday-chip { font-size: 12px; color: var(--faint); }
.myday-empty {
    border: 1px dashed var(--border); border-radius: var(--radius-md);
    padding: 16px; text-align: center; color: var(--faint); font-size: 14px;
}

/* «⋯»: остальные итоги и перенос. Перенос намеренно спрятан сюда — рядом с
   номером он забирал звонки на «потом». */
.myday-more { position: relative; flex: 0 0 auto; }
.myday-more > [data-menu-button][aria-expanded="true"] { background: var(--surface-2); color: var(--ink); }
.myday-more-menu {
    position: absolute; z-index: var(--z-menu); top: calc(100% + 5px); right: 0;
    min-width: 220px; padding: 4px;
    border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--card); box-shadow: var(--shadow);
}
.myday-more-menu form { margin: 0; }
.myday-more-menu button {
    width: 100%; min-height: 34px; padding: 6px 9px;
    border: 0; border-radius: 6px; background: transparent; color: var(--ink);
    font: inherit; font-size: 13px; font-weight: 600; text-align: left; cursor: pointer;
}
.myday-more-menu button:hover { background: var(--surface-2); }
.myday-more-menu button:focus-visible { outline: var(--ring-w) solid var(--ring); outline-offset: -2px; }
.myday-more-sep { height: 1px; margin: 4px 2px; background: var(--border); }

.myday-modal-sub { color: var(--muted); font-size: 13px; margin: -6px 0 4px; }
.task-outcome-group { margin-bottom: 16px; }

.nav-badge {
    margin-left: auto; min-width: 20px; height: 20px; padding: 0 6px;
    display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center;
    border-radius: var(--radius-sm); background: var(--danger-soft); color: var(--err);
    font-size: 11.5px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums;
}
.nav-badge:empty { display: none; }
.nav-badge:not(:empty) + .nav-caret { margin-left: 0; }

/* Ссылка занимает всю ячейку, а не только надпись: колонка «Статус» шириной в
   сто пикселей давала цель для курсора в двадцать, и промах по ней означал
   клик мимо сортировки. Отрицательные поля возвращают заголовку отступы
   ячейки, съеденные растягиванием. */
.sortable-th > a {
    display: flex; align-items: center; gap: 6px;
    height: 100%; margin: 0 calc(var(--cell-x) * -1); padding: 0 var(--cell-x);
    color: inherit; text-decoration: none; white-space: nowrap;
    border-radius: var(--radius-sm);
}
/* Подчёркивание при наведении сдвигало базовую линию подписи на пиксель, и
   шапка «дышала» под курсором. Тон и подложка сообщают то же самое молча. */
.sortable-th > a:hover { color: var(--ink); background: var(--row-hover); }
.sortable-th > a:focus-visible {
    outline: var(--ring-w) solid var(--ring);
    outline-offset: calc(var(--ring-offset) * -1);
    color: var(--ink);
}
.sortable-th.num > a { justify-content: flex-end; }

@media (max-width: 1100px) {
    .myday-row { grid-template-columns: 110px minmax(0, 1fr); }
    .myday-row-actions { grid-column: 2; flex-wrap: wrap; justify-content: flex-start; }
}
@media (max-width: 700px) {
    .myday-status-item { flex-basis: 50%; }
    .myday-row { grid-template-columns: minmax(0, 1fr); gap: 8px; }
    .myday-row { padding: 12px; }
    .myday-row-due { flex-direction: row; align-items: baseline; gap: 10px; }
    /* На телефоне факты идут столбиком: точка-разделитель в начале
       перенесённой строки читается как опечатка. */
    .myday-row-facts { flex-direction: column; align-items: flex-start; }
    .myday-fact + .myday-fact::before { content: none; }
    /* Главная кнопка и «⋯» — первой строкой, итоги — второй. */
    .myday-row-actions { grid-column: 1; flex-wrap: wrap; gap: 6px; }
    .myday-row-actions .myday-call { flex: 1 1 calc(100% - 44px); order: 0; justify-content: center; }
    .myday-row-actions .myday-more { order: 1; }
    .myday-row-actions .myday-outcome { order: 2; }
}
@media (pointer: coarse) {
    .myday-more-menu button { min-height: 44px; }
}
/* ---------------------------------------------------------------------------
   Interaction states.

   The cabinet used to ship four transitions and two pressed states in total, so
   nothing acknowledged a click. Everything clickable now shares one duration
   and one easing curve; the reduced-motion block below still switches it off.
   --------------------------------------------------------------------------- */
.nav-item,
.nav-subitem,
.conversation-card,
.chat-segments a,
.chat-channels a,
.chat-menu a,
.chat-menu button,
.catalog-tabs > a,
.catalog-tabs > button,
.composer-mode button,
.composer-templates button,
.crm-schedule-modes a,
.roster-month-day,
.modal-close,
.snooze button,
.sortable-th > a {
    transition: background var(--dur) ease, border-color var(--dur) ease, color var(--dur) ease, box-shadow var(--dur) ease;
}
.conversation-card:active,
.modal-close:active,
.chip.action:active { transform: translateY(1px); }

/* A card that opens something should say so before it is clicked. */
a.card, button.card, .card.is-clickable {
    display: block; text-decoration: none; color: inherit;
    transition: border-color var(--dur) ease, box-shadow var(--dur) ease, transform var(--dur-fast) ease;
}
a.card:hover, button.card:hover, .card.is-clickable:hover {
    border-color: var(--brand-border);
    box-shadow: var(--shadow);
}
a.card:active, button.card:active, .card.is-clickable:active { transform: translateY(1px); }

/* Quiet background refreshes keep content readable and interactive, matching
   the progress bar's data-quiet-htmx opt-out in app.js. */
.htmx-request.htmx-swapping:not([data-quiet-htmx]),
.htmx-request:not(form):not(body):not([data-quiet-htmx]) {
    opacity: .55;
    pointer-events: none;
    transition: opacity var(--dur) ease;
}
#htmx-progress {
    position: fixed;
    inset: 0 auto auto 0;
    z-index: var(--z-toast);
    width: 0;
    height: 2px;
    background: var(--brand);
    opacity: 0;
    pointer-events: none;
    transition: width .25s var(--ease), opacity .2s ease;
}
#htmx-progress.active { width: 65%; opacity: 1; }
#htmx-progress.done { width: 100%; opacity: 0; }

/* Оперативный пульс за 24 часа — подпись и единая группа действий. Кнопки
   собраны на тихой поверхности, но не превращены обратно в таблицу. */
.topbar-activity {
    position: relative; display: inline-flex; min-width: 0;
    font-size: 14px; font-weight: 600; line-height: 1.2; letter-spacing: -.01em;
}
.topbar-activity-strip {
    display: inline-flex; align-items: center; gap: 10px; height: var(--topbar-control-height);
    border: 0; background: transparent; color: var(--ink); overflow: visible; white-space: nowrap;
}
.topbar-activity-period {
    display: inline-flex; align-items: center; padding: 0;
    background: transparent; color: var(--muted);
    font: inherit;
}
.topbar-activity-actions {
    display: inline-flex; align-items: center; gap: 2px;
    height: var(--topbar-control-height); padding: 3px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.topbar-activity-metric {
    display: inline-flex; align-items: center; gap: 5px; min-height: 24px; padding: 0 8px;
    border: 0; border-inline-start: 0; background: transparent; color: var(--muted);
    border-radius: var(--radius-sm); font: inherit; font-size: 14px; line-height: 1.2; cursor: pointer;
}
.topbar-activity-strip > .topbar-activity-period,
.topbar-activity-strip > .topbar-activity-actions { height: 100%; }
.topbar-activity-metric:not(:disabled):hover,
.topbar-activity-metric[data-active="true"] { background: var(--hover); color: var(--ink); }
.topbar-activity-metric:focus-visible {
    outline: var(--ring-w) solid var(--ring); outline-offset: var(--ring-offset);
}
.topbar-activity-metric:disabled { cursor: default; opacity: .62; }
.topbar-activity-metric strong {
    color: var(--ink); font-size: 14px; font-weight: 750;
    font-variant-numeric: tabular-nums;
}
.topbar-activity-metric small { color: var(--faint); font: inherit; }
.topbar-activity-compact { display: none; position: relative; }
.topbar-activity-compact > summary {
    display: inline-flex; align-items: center; justify-content: center; gap: 5px;
    height: var(--topbar-control-height); padding: 0 8px; list-style: none;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--card); color: var(--ink); cursor: pointer;
    font-size: 14px; font-weight: 700; white-space: nowrap;
}
.topbar-activity-compact > summary::-webkit-details-marker { display: none; }
.topbar-activity-compact > summary:hover { background: var(--hover); }
.topbar-activity-compact > summary:focus-visible {
    outline: var(--ring-w) solid var(--ring); outline-offset: var(--ring-offset);
}
.topbar-activity-compact > summary svg {
    width: 16px; height: 16px; fill: none; stroke: currentColor;
    stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.topbar-activity-popover {
    position: absolute; top: calc(100% + 7px); right: 0; z-index: var(--z-menu);
    display: grid; width: min(310px, calc(100vw - 28px)); padding: 6px;
    border: 1px solid var(--border); border-radius: var(--radius-md);
    background: var(--surface-raised); box-shadow: var(--shadow);
}
.topbar-activity-popover .topbar-activity-period {
    min-height: 30px; justify-content: flex-start; border-radius: var(--radius-sm);
}
.topbar-activity-popover .topbar-activity-actions {
    display: grid; height: auto; padding: 3px;
}
.topbar-activity-popover .topbar-activity-metric {
    justify-content: space-between; min-height: 34px; border-inline-start: 0;
}
.topbar-activity-popover .topbar-activity-metric strong { font-size: 14px; }
@media (max-width: 1399px) {
    .topbar-activity-strip { display: none; }
    .topbar-activity-compact { display: inline-flex; }
}
@media (max-width: 640px) {
    .topbar-activity-popover {
        position: fixed; top: 47px; right: max(14px, env(safe-area-inset-right));
    }
}

/* Детали метрики загружаются только по нажатию. На десктопе это компактный
   поповер у выбранного показателя, на телефоне — нижняя панель. */
.topbar-activity-detail-popover {
    position: fixed; inset: auto;
    top: var(--topbar-activity-detail-top, 48px);
    left: var(--topbar-activity-detail-left, 14px);
    width: min(410px, calc(100vw - 28px));
    max-height: min(540px, calc(100dvh - var(--topbar-activity-detail-top, 48px) - 14px));
    margin: 0; padding: 0; overflow: hidden;
    border: 1px solid var(--border); border-radius: var(--radius-md);
    background: var(--surface-raised); color: var(--ink); box-shadow: var(--shadow);
}
.topbar-activity-detail-popover::backdrop { background: transparent; }
.topbar-activity-detail-popover[data-open="true"] { display: block; }
#topbar-activity-detail-content { max-height: inherit; overflow-y: auto; }
.topbar-activity-detail { display: grid; }
.topbar-activity-detail-header {
    position: sticky; top: 0; z-index: 1;
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    min-height: 58px; padding: 10px 12px 9px 14px;
    border-bottom: 1px solid var(--border); background: var(--surface-raised);
}
.topbar-activity-detail-header h2 { margin: 0; font-size: 14px; line-height: 1.25; }
.topbar-activity-detail-header span { color: var(--faint); font-size: 11.5px; }
.topbar-activity-detail-close {
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; flex: 0 0 30px; padding: 0;
    border: 0; border-radius: var(--radius-sm); background: transparent;
    color: var(--muted); font: 400 22px/1 inherit; cursor: pointer;
}
.topbar-activity-detail-close:hover { background: var(--hover); color: var(--ink); }
.topbar-activity-detail-close:focus-visible,
.topbar-activity-detail-filter button:focus-visible {
    outline: var(--ring-w) solid var(--ring); outline-offset: var(--ring-offset);
}
.topbar-activity-detail-filter {
    display: flex; gap: 3px; margin: 10px 14px 4px; padding: 3px;
    border-radius: var(--radius-sm); background: var(--surface-2);
}
.topbar-activity-detail-filter button {
    min-height: 28px; padding: 0 9px; border: 0; border-radius: var(--radius-sm);
    background: transparent; color: var(--muted); font: inherit;
    font-size: 12px; font-weight: 700; cursor: pointer;
}
.topbar-activity-detail-filter button:hover { color: var(--ink); }
.topbar-activity-detail-filter button[aria-pressed="true"] {
    background: var(--surface-raised); color: var(--ink); box-shadow: var(--lift);
}
.topbar-activity-detail-list { margin: 0; padding: 4px 0; list-style: none; }
.topbar-activity-detail-list > li + li { border-top: 1px solid var(--border); }
.topbar-activity-detail-row {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px;
    align-items: start; padding: 10px 14px;
}
.topbar-activity-detail-main { min-width: 0; }
.topbar-activity-detail-name {
    display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
    min-width: 0; font-size: 13px; font-weight: 750;
}
.topbar-activity-detail-name a {
    min-width: 0; overflow: hidden; color: var(--ink); text-overflow: ellipsis;
    white-space: nowrap; text-decoration-thickness: 1px; text-underline-offset: 3px;
}
.topbar-activity-detail-name a:hover { color: var(--brand); }
.topbar-activity-detail-name .tag { font-size: 10px; }
.topbar-activity-detail-name .booking-source-badge,
.topbar-activity-detail-name .cancellation-penalty-badge {
    width: 24px; height: 24px; flex-basis: 24px; border-radius: var(--radius-sm);
}
.topbar-activity-detail-name .cancellation-penalty-badge {
    display: inline-flex; align-items: center; justify-content: center;
    flex: 0 0 24px; color: var(--err); cursor: help;
}
.topbar-activity-detail-name .booking-source-badge svg,
.topbar-activity-detail-name .cancellation-penalty-badge svg {
    width: 24px; height: 24px; fill: none; stroke: currentColor;
    stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.topbar-activity-detail-name .cancellation-penalty-badge:focus-visible {
    outline: var(--ring-w) solid var(--ring); outline-offset: 1px;
}
.topbar-activity-detail-meta {
    margin-top: 3px; overflow: hidden; color: var(--muted); font-size: 11.5px;
    line-height: 1.35; text-overflow: ellipsis; white-space: nowrap;
}
.topbar-activity-detail-row time {
    color: var(--faint); font-size: 11px; line-height: 1.4; white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.topbar-activity-detail-empty,
.topbar-activity-detail-loading,
.topbar-activity-detail-error { padding: 24px 16px; text-align: center; font-size: 13px; }
.topbar-activity-detail-empty,
.topbar-activity-detail-loading { color: var(--muted); }
.topbar-activity-detail-error { color: var(--err); }
.topbar-activity-detail-footer {
    position: sticky; bottom: 0; display: flex; justify-content: flex-end;
    padding: 9px 14px 11px; border-top: 1px solid var(--border);
    background: var(--surface-raised);
}
.topbar-activity-detail-footer a {
    display: inline-flex; align-items: center; gap: 6px; color: var(--brand);
    font-size: 12.5px; font-weight: 750; text-decoration: none;
}
.topbar-activity-detail-footer a:hover { text-decoration: underline; text-underline-offset: 3px; }
@media (max-width: 640px) {
    .topbar-activity-detail-popover {
        inset: auto 8px max(8px, env(safe-area-inset-bottom)); width: auto;
        max-height: min(72dvh, 560px); border-radius: var(--radius-lg);
    }
    .topbar-activity-detail-popover::backdrop { background: var(--scrim); }
    .topbar-activity-detail-row { padding-block: 11px; }
}

/* Подтверждение паролем заменяет небезопасный window.prompt(). */
.password-confirm .form-card, .confirm-dialog .form-card { display: grid; gap: 12px; }
.password-confirm input { width: 100%; }
.confirm-message { margin: 0; color: var(--ink); line-height: 1.45; }
.confirm-actions { justify-content: flex-end; }
.field-error { margin: 0; color: var(--err); font-size: 11px; font-weight: 600; line-height: 1.4; }

/* Keyboard accessibility primitives shared by every operational page. */
.skip-link {
    position: fixed; left: 1rem; top: -5rem; z-index: var(--z-skip);
    padding: .75rem 1rem; background: var(--card); color: var(--ink);
    border: 2px solid currentColor; border-radius: .5rem;
}
.skip-link:focus { top: 1rem; }
.sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
/* Kept for keyboard and no-JS users: the search submits itself while typing. */
.sr-only-focusable:not(:focus):not(:focus-within) { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
dialog:focus-visible, [tabindex="-1"]:focus-visible { outline: 3px solid var(--brand); outline-offset: 3px; }

/* ---------------------------------------------------------------------------
   Появление диалогов и дроуэров.

   Ни одно из тридцати с лишним окон кабинета не имело входа и выхода: карточка
   клиента, форма справочника и подтверждение возникали и пропадали кадром.
   Правило одно на весь кабинет, потому что открытием заведует единственная
   пара openDialogEl/closeDialogEl в app.js — править шаблоны не нужно.

   Масштаб .98 и var(--dur), а не размашистые 300 мс: карточку клиента
   открывают десятки раз за смену, и на этой частоте движение обязано быть на
   грани незаметности, иначе кабинет начинает казаться медленным.

   Уменьшение берётся свойством scale, а не transform: у .client-drawer в
   transform уже стоит translate(-50%, -50%) центровки, и transform стёр бы её.

   --------------------------------------------------------------------------- */
dialog {
    opacity: 0;
    scale: .98;
    transition:
        opacity var(--dur) var(--ease),
        scale var(--dur) var(--ease),
        overlay var(--dur) var(--ease) allow-discrete,
        display var(--dur) var(--ease) allow-discrete;
}
dialog[open] { opacity: 1; scale: 1; }
@starting-style {
    dialog[open] { opacity: 0; scale: .98; }
}
dialog::backdrop {
    opacity: 0;
    transition:
        opacity var(--dur) var(--ease),
        overlay var(--dur) var(--ease) allow-discrete,
        display var(--dur) var(--ease) allow-discrete;
}
dialog[open]::backdrop { opacity: 1; }
@starting-style {
    dialog[open]::backdrop { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto !important; }
    *, *::before, *::after {
        animation-duration: 1ms !important;
        animation-iteration-count: 1 !important;
        animation-delay: 0s !important;
        /* Остаются только немоторные свойства: цвет, фон, граница, тень,
           прозрачность. Сдвиг, масштаб и изменение размеров не анимируются. */
        transition-property: color, background-color, border-color, box-shadow, opacity !important;
        transition-duration: 120ms !important;
        transition-delay: 0s !important;
    }
    /* Проблеск снимается целиком, а не замирает: глобальное правило свело бы
       анимацию к 1 мс и оставило поперёк кнопки статичную светлую полосу.
       Признак работы остаётся приглушением, курсором и aria-busy. */
    [data-busy]::after { content: none; }
}

/* ---------------------------------------------------------------------------
   Кнопка отправки на время запроса.

   Проблеск поперёк кнопки, а не спиннер в её середине. Спиннер пришлось бы
   красить: чтобы он был виден, надо спрятать подпись через color: transparent,
   а тогда и сам спиннер, взяв currentColor, станет прозрачным — и цвет
   пришлось бы прописывать отдельно для каждого варианта кнопки. Проблеск
   берёт currentColor как есть, поэтому одинаково читается на светлой,
   зелёной и опасной кнопке, и не меняет размер — строка таблицы не дёргается.
   --------------------------------------------------------------------------- */
[data-busy] {
    position: relative;
    overflow: hidden;
    pointer-events: none;
    cursor: progress;
    opacity: .72;
}
[data-busy]::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: linear-gradient(90deg,
        transparent 0%,
        color-mix(in srgb, currentColor 24%, transparent) 50%,
        transparent 100%);
    animation: busy-sweep 1s linear infinite;
}
@keyframes busy-sweep {
    from { transform: translateX(-100%); }
    to { transform: translateX(100%); }
}

/* Operating modules */
.operations-container { max-width: 1600px; }
/* «Сообщения клиентам»: рассылки и сценарии — вкладки одного раздела, поэтому
   у всех его страниц один контейнер и одна полоса вкладок. */
.app-shell .container.client-messages-container {
    max-width: none;
    width: 100%;
}
.client-messages-container > .catalog-tabs-toolbar > .catalog-tabs {
    width: auto;
    max-width: calc(1280px - 52px);
    margin-right: 0;
    margin-left: 0;
}
.domain-event-catalog-table { min-width: 920px; }
.domain-event-log-table { min-width: 1080px; }
.domain-event-log-table td { vertical-align: top; }
.domain-event-log-table .json-pre { margin-bottom: 0; }
.operations-form-grid { display: grid; grid-template-columns: repeat(auto-fit,minmax(320px,1fr)); gap: 16px; margin: 18px 0 24px; }
.operations-form-grid .form-card, .operations-inline-form { display: grid; gap: 10px; align-content: start; }
.operations-form-grid > .form-card { min-width: 0; width: 100%; }
.operations-form-grid .form-card label { min-width: 0; width: 100%; }
.operations-form-grid .form-card input,
.operations-form-grid .form-card select,
.operations-form-grid .form-card textarea { min-width: 0; max-width: 100%; width: 100%; }

.operations-form-grid .form-card button { max-width: 100%; }
.operations-inline-form { grid-template-columns: repeat(auto-fit,minmax(180px,1fr)); align-items: end; margin-bottom: 22px; }
.operations-inline-form h2 { grid-column: 1 / -1; }
#certificate-issue-dialog,
#certificate-activation-dialog,
[id^="certificate-edit-"] {
    overflow: visible;
}
#certificate-issue-dialog .modal-form,
#certificate-activation-dialog .modal-form,
[id^="certificate-edit-"] .modal-form {
    display: grid;
    max-height: none;
    gap: 14px;
    overflow: visible;
}
#certificate-issue-dialog .modal-header p,
#certificate-activation-dialog .modal-header p,
[id^="certificate-edit-"] .modal-header p { margin: 4px 0 0; }
#certificate-issue-dialog .form-row > label { flex: 1 1 220px; min-width: min(220px, 100%); }
/* Одна форма на «Выпустить» в «Выданных» и «Продать» из карточки клиента:
   блоки идут сеткой с общим шагом, список найденных клиентов выходит за
   край диалога, поэтому у формы и диалога overflow: visible. */
.certificate-issue-form { display: grid; gap: 16px; max-height: none; overflow: visible; }
.certificate-issue-form .modal-header { margin-bottom: 0; align-items: flex-start; }
.certificate-issue-form .form-row { margin-bottom: 0; }
.certificate-issue-form .form-row > label { flex: 1 1 220px; min-width: min(220px, 100%); }
.certificate-issue-form .radio-group__options { flex-direction: row; flex-wrap: wrap; gap: 8px 16px; }
.certificate-issue-form .radio-group__options .radio { flex: 1 1 220px; }
/* Режим «Продажа / Без оплаты» — две карточки в ряд, как у формы сертификата. */
.certificate-issue-form .certificate-issue-actions { margin-top: 4px; }
.client-certificate-sale-dialog { overflow: visible; }
.client-certificate-sale-dialog .modal-form { overflow: visible; }
.certificate-operation-form { min-width: 320px; margin-top: 8px; }
#certificate-activation-dialog [data-certificate-redemption-fields] { display: grid; gap: 12px; }
.app-shell .container.loyalty-container { max-width: none; width: 100%; margin: 0; padding-left: 18px; padding-right: 18px; }
.loyalty-search { margin-bottom: 18px; }
.loyalty-settings-fields { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 14px; margin-bottom: 10px; }
.loyalty-settings-fields label { min-width: 0; justify-content: flex-end; }
.loyalty-settings-fields input { width: 100%; min-width: 0; }
.loyalty-visit-multipliers { display: flex; flex-wrap: nowrap; align-items: end; gap: 8px; width: max-content; }
.loyalty-visit-multipliers label { flex: 0 0 auto; white-space: nowrap; }
.loyalty-visit-multipliers input[type="time"] { width: 8rem; }
.loyalty-tier-heading { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 18px 0 8px; }
.loyalty-tier-heading h3 { margin: 0; }
@media (max-width: 980px) { .loyalty-settings-fields { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 640px) { .loyalty-settings-fields { grid-template-columns: 1fr; } }
.task-panel { padding-bottom: 24px; }
.task-panel-page .task-panel { padding: 0; }
.task-card-back { margin: 0 0 12px; }
.task-panel .form-card { margin: 0; }

/* Шапка карточки задачи: кому и зачем слева, номер — главная кнопка справа. */
.task-card-head {
    display: flex; align-items: flex-start; justify-content: space-between; gap: 20px;
    padding: 20px 24px 18px; border-bottom: 1px solid var(--border); background: var(--card);
}
.task-panel-page .task-card-head { margin-bottom: 16px; border: 1px solid var(--border); border-radius: var(--radius-md); }
.task-card-title { min-width: 0; }
.task-card-title h1 {
    margin: 4px 0 8px;
    font-size: 24px; line-height: 1.2; letter-spacing: -.02em; text-wrap: pretty;
}
.task-card-title h1 a { color: var(--ink); text-decoration: none; }
.task-card-title h1 a:hover { text-decoration: underline; text-underline-offset: 4px; }
.task-card-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; }
.task-card-goal { color: var(--muted); font-size: 14px; font-weight: 600; }
.task-card-branch { color: var(--faint); font-size: 13px; }
.task-card-call { display: flex; flex: 0 0 auto; align-items: center; gap: 12px; }
.task-card-phone { font-variant-numeric: tabular-nums; }

.task-card-grid {
    display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(320px, 1fr);
    gap: 16px; align-items: start; padding: 20px 24px 0;
}
.task-panel-page .task-card-grid { padding: 0; }
.task-card-grid .form-card > h2 { margin-top: 0; }
.task-card-main, .task-card-side { display: grid; gap: 16px; min-width: 0; }
/* Контекст и история — слева; справа только итог и планирование. История
   идёт после действий в DOM, поэтому на телефоне не отодвигает форму итога. */
.task-card-main { grid-column: 1; grid-row: 1; }
.task-card-side { grid-column: 2; grid-row: 1 / span 2; }
.task-card-history { grid-column: 1; grid-row: 2; min-width: 0; }
.task-card-side:not(:has(> *)) { display: none; }
.task-card-grid:not(:has(.task-card-side > *)) { grid-template-columns: minmax(0, 1fr); }
.task-card-notes { white-space: pre-wrap; margin: 0; }
.task-card-facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px 20px; margin: 0; }
.task-card-facts .is-wide { grid-column: span 2; }
.task-card-facts dt { color: var(--muted); font-size: 12.5px; }
.task-card-facts dd { margin: 3px 0 0; color: var(--ink); font-size: 14px; font-weight: 600; }
.task-card-facts dd.is-warn { color: var(--warn); }
.task-card-quick { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }

/* Итог прямо в карточке: переключатели в две колонки, ряд действий внизу. */
.task-card-result .task-outcome-group { margin-bottom: 14px; }
.task-card-result .task-outcome-group .radio-group__options {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 12px; margin-top: 0;
}
.task-card-result .radio__label { font-size: 13px; }
.task-card-result > label + label, .task-card-plan > label + label { margin-top: 12px; }
@media (pointer: coarse) {
    .task-card-result .radio__content { min-height: 44px; }
}
.task-card-note { display: flex; flex-direction: column; gap: 6px; margin: 0; color: var(--muted); font-size: 13px; }
.task-card-note textarea { width: 100%; min-height: 64px; }
.task-card-actions { justify-content: flex-end; margin-top: 14px; }
.task-card-snooze .myday-more-menu { top: auto; bottom: calc(100% + 5px); left: 0; right: auto; min-width: 190px; }
.task-card-outcome { padding: 12px 14px; border-radius: var(--radius-sm); background: var(--surface-2); }
.task-card-outcome p { margin: 6px 0 0; }
.task-card-outcome small { color: var(--muted); }

/* Комментарии и события — одна лента, новое сверху. */
.task-timeline { display: grid; margin: 0; padding: 0; list-style: none; }
.task-timeline li { display: grid; grid-template-columns: 112px minmax(0, 1fr); gap: 2px 12px; padding: 9px 0; border-top: 1px solid var(--border); }
.task-timeline li:first-child { padding-top: 0; border-top: 0; }
.task-timeline time { color: var(--muted); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.task-timeline b { font-size: 14px; }
.task-timeline span { display: block; color: var(--muted); font-size: 13px; }
.task-timeline p { margin: 4px 0 0; white-space: pre-wrap; }
.task-card-facts dd, .task-card-notes, .task-timeline p, .task-card-sent-list li { overflow-wrap: anywhere; }
.task-card-comment { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); }
.task-card-comment .actions { justify-content: flex-end; margin-top: 10px; }
@media (max-width: 900px) {
    .task-card-grid { grid-template-columns: 1fr; }
    .task-card-main, .task-card-side, .task-card-history { grid-column: 1; grid-row: auto; }
    /* Номер уходит под имя, крестик остаётся в углу окна. */
    .task-card-head { position: relative; flex-direction: column; padding-right: 52px; }
    .task-card-head .client-drawer-close { position: absolute; top: 14px; right: 14px; }
}
@media (max-width: 560px) {
    .task-card-grid { padding-inline: 16px; }
    .task-card-head { padding-inline: 16px; }
    .task-card-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .task-card-result .task-outcome-group .radio-group__options { grid-template-columns: 1fr; }
}
.task-settings-section { margin-top: 26px; }
.task-settings-section h2 { margin-bottom: 4px; }
.task-limit-form { margin-bottom: 10px; padding: 12px 16px; }
.task-limit-form .form-row { align-items: end; gap: 14px; }
.task-limit-name { font-weight: 700; min-width: 180px; }
.task-limit-toggle { flex-direction: row; align-items: center; gap: 7px; white-space: nowrap; }
@media (max-width: 700px) {
  .task-limit-name { min-width: 0; }
}
/* Подбор клиента — одна разметка на кабинет (_client_picker.html). */
/* Шаг тот же, что у обычного label (4px): в ряду фильтров и полей подбор
   обязан стоять вровень с соседями, а не выше и не ниже их. */
.client-picker { display: grid; gap: 4px; min-width: 0; }
.client-picker input[type="search"] { width: 100%; min-width: 0; }
/* В ряду полей подбор — такое же поле, как соседние label. */
.form-row > .client-picker { flex: 1 1 220px; min-width: min(220px, 100%); max-width: 340px; }
/* Выбранный клиент отмечается в самом поле: галочка и тон границы. */
.client-picker--chosen input[type="search"] {
    border-color: var(--ok);
    padding-right: 30px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2316a34a' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 9px center;
    background-size: 15px 15px;
}
/* Поиск и «Создать клиента» одной строкой: кнопка нужна ровно тогда, когда
   поиск ничего не нашёл, поэтому стоит вплотную к полю. */
.client-picker-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
.client-picker-row input[type="search"] { flex: 1 1 auto; min-width: 0; }
.client-picker-row .hui-button { flex: 0 0 auto; }
/* Список стоит в потоке и раздвигает форму. Всплывающим он быть не может:
   у .modal стоит overflow: auto, и абсолютно позиционированный список
   обрезается нижней границей окна — видно первые две-три строки из десяти. */
.client-search-results button.is-active { background: var(--surface-2); }
.client-search-results { max-height: 260px; overflow-y: auto; padding: 5px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--card); box-shadow: var(--shadow); }
.client-search-results button { display: grid; width: 100%; gap: 2px; padding: 9px 10px; border: 0; border-radius: 7px; background: transparent; color: var(--ink); text-align: left; cursor: pointer; }
.client-search-results button:hover, .client-search-results button:focus-visible { background: var(--surface-2); }
.client-search-results button span { color: var(--muted); font-size: 12px; }
.client-search-selection { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding: 8px 10px; border-radius: 7px; background: var(--selected); color: var(--ink); font-size: 13px; font-weight: 700; }
.client-search-selection-action { margin-left: auto; flex: 0 0 auto; }
.certificate-purchaser-row { display: grid; gap: 4px; }
.certificate-purchaser-row > .muted { margin: 0; }
/* Клиент без действующего абонемента: тот же блок, но предупреждающий. */
.client-search-selection--warn { background: var(--danger-soft); color: var(--err); }
.client-search-empty { padding: 12px 10px; color: var(--muted); text-align: center; }
.loyalty-section { padding: 18px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card); }
.loyalty-section-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; margin-bottom: 16px; }
.loyalty-section-head h2 { margin: 0 0 4px; }
.loyalty-section-head p { margin: 0; color: var(--muted); }
.loyalty-summary { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }
.loyalty-summary span { color: var(--muted); font-size: 13px; white-space: nowrap; }
.loyalty-summary b { color: var(--ink); font-variant-numeric: tabular-nums; }
.loyalty-two-columns { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(320px, .9fr); gap: 18px; align-items: start; }
.loyalty-feed, .nps-feedback-list, .recovery-list { min-width: 0; }
.loyalty-feed h3, .nps-feedback-list h3, .recovery-list h3 { margin-top: 0; }
.loyalty-feed article { display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: 10px; padding: 10px 0; border-top: 1px solid var(--border); }
.loyalty-feed article > div { display: grid; gap: 2px; }
.loyalty-feed article span, .loyalty-feed article small { color: var(--muted); font-size: 12px; }
.loyalty-operation-value { align-self: start; padding: 4px 7px; border-radius: 7px; font-weight: 800; text-align: center; }
.loyalty-operation-value.positive { background: var(--ok-bg); color: var(--ok-ink); }
.loyalty-operation-value.negative { background: var(--danger-soft); color: var(--err); }
.referral-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 12px; }
.referral-card { display: grid; gap: 13px; padding: 15px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); }
.referral-code { width: fit-content; padding: 5px 9px; border: 1px dashed var(--brand); border-radius: 7px; color: var(--brand-ink); font-family: ui-monospace, monospace; font-weight: 800; letter-spacing: .04em; }
.referral-route { display: grid; grid-template-columns: minmax(0,1fr) auto minmax(0,1fr); align-items: center; gap: 10px; }
.referral-route div { display: grid; gap: 3px; }
.referral-route div span, .referral-state small { color: var(--muted); font-size: 12px; }
.referral-arrow { color: var(--faint); font-size: 20px; }
.referral-state { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.nps-breakdown { display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: 10px; margin-bottom: 20px; }
.nps-breakdown > div { display: grid; gap: 4px; padding: 13px; border-radius: var(--radius-md); background: var(--surface-2); }
.nps-breakdown span, .nps-breakdown small { color: var(--muted); font-size: 12px; }
.nps-breakdown strong { font-size: 25px; }
.nps-breakdown .promoter { background: var(--ok-bg); }
.nps-breakdown .passive { background: var(--warn-soft); }
.nps-breakdown .detractor { background: var(--danger-soft); }
.nps-layout { display: grid; grid-template-columns: minmax(0,1fr) minmax(360px,1fr); gap: 18px; align-items: start; }
.nps-feedback-list article { display: grid; grid-template-columns: 48px minmax(0,1fr); gap: 11px; padding: 11px 0; border-top: 1px solid var(--border); }
.survey-request-list { margin-bottom: 22px; }
.survey-request-list h3 { margin-top: 0; }
.survey-request-list article { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 9px 0; border-top: 1px solid var(--border); }
.survey-request-list article > div { display: grid; gap: 2px; }
.survey-request-list small { color: var(--muted); }
.nps-feedback-list article > div { min-width: 0; }
.nps-feedback-list p { margin: 4px 0; overflow-wrap: anywhere; }
.nps-feedback-list small { color: var(--muted); }
.nps-score { display: grid; width: 42px; height: 42px; place-items: center; border-radius: 50%; background: var(--warn-soft); color: var(--warn); font-size: 17px; font-weight: 800; }
.nps-score.good { background: var(--ok-bg); color: var(--ok-ink); }
.nps-score.bad { background: var(--danger-soft); color: var(--err); }
.recovery-list { display: grid; gap: 10px; }
.recovery-list > h3 { margin-bottom: 0; }
.recovery-card { padding: 13px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); }
.recovery-card.open { border-color: var(--danger-border); background: var(--danger-soft); }
.recovery-card > div:first-child { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.recovery-card p { margin: 8px 0; }
.recovery-card small { color: var(--muted); }
.recovery-card form { display: grid; gap: 8px; margin-top: 10px; }
.recovery-resolution { margin-top: 9px; padding: 8px; border-radius: 7px; background: var(--ok-bg); color: var(--ok-ink); }
@media (max-width: 980px) { .nps-breakdown { grid-template-columns: repeat(2,minmax(0,1fr)); } .loyalty-two-columns, .nps-layout { grid-template-columns: 1fr; } }
@media (max-width: 640px) { .nps-breakdown { grid-template-columns: 1fr; } .loyalty-section-head { flex-direction: column; } .referral-list { grid-template-columns: 1fr; } }
.qr-card { text-align: center; }
/* Белое поле вокруг QR обязательно: сканеру нужна светлая тихая зона,
   поэтому этот белый не следует за темой. */
.qr-card img { max-width: 100%; background: #fff; border-radius: 12px; padding: 8px; }

/* Sales funnel: dense operational workspace with explicit priority queues. */

/* Своя высота, а не min-height: базовое правило задаёт height, и минимум
   рядом с ним ничего не решал — панель всё равно вытягивалась до общей. */


.client-drawer-header { display: flex; align-items: start; justify-content: space-between; gap: 16px; }
.client-drawer-header h2 { margin: 2px 0 7px; }
.client-drawer-header p { margin: 0; }

@media (max-width: 760px) { .operations-form-grid { grid-template-columns: 1fr; } .operations-inline-form { grid-template-columns: 1fr; } }

/* Чаты → ИИ-агент: settings page and the assistant's mark inside a thread. */
.ai-status-strip { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-bottom: 18px; }
.ai-status-strip .card-value { font-size: 22px; }
.ai-status-strip .card-value.ai-on { color: var(--ok); }
.ai-status-strip .card-value.ai-off { color: var(--muted); }
.ai-status-strip .card-value.ai-model { font-size: 17px; overflow-wrap: anywhere; }
.form-section-title { font-size: 14px; margin: 4px 0 10px; }
/* Разделитель ставится между разделами, а не перед первым: :not(:first-child)
   срабатывал и на самом верхнем заголовке, потому что перед ним в форме
   стоят csrf и скрытые поля — получалась полоса в начале блока. */
.form-card .form-section-title ~ .form-section-title { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border); }

.sms-settings-form { max-width: 720px; }
.sms-provider-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin-top: 14px; }
.chat-settings-page { max-width: 1260px; }
.chat-settings-header { margin-bottom: 24px; }
.chat-settings-header h1 { margin: 0 0 6px; }
.chat-settings-header p { margin: 0; color: var(--muted); }
.chat-settings-workspace {
    display: grid;
    grid-template-columns: 286px minmax(0, 760px);
    gap: 22px;
    align-items: start;
}
.chat-settings-nav,
.chat-settings-panel {
    min-width: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
}
.chat-settings-nav { padding: 8px; }
.chat-settings-nav-group + .chat-settings-nav-group { margin-top: 6px; padding-top: 7px; border-top: 1px solid var(--border); }
.chat-settings-nav-group h2 {
    margin: 0;
    padding: 8px 10px 5px;
    color: var(--muted);
    font-size: 11px;
    font-weight: 800;
    letter-spacing: .04em;
    text-transform: uppercase;
}
.chat-settings-nav-items { display: grid; gap: 2px; }
.chat-settings-nav-item {
    display: grid;
    grid-template-columns: 36px minmax(0, 1fr) 14px;
    gap: 10px;
    align-items: center;
    min-width: 0;
    padding: 9px 10px;
    border-radius: var(--radius-sm);
    color: var(--ink);
    text-decoration: none;
    transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.chat-settings-nav-item:hover { background: var(--surface-2); color: var(--ink); }
.chat-settings-nav-item.is-active { background: var(--selected); color: var(--ink); font-weight: 700; }
.chat-channel-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    color: var(--muted);
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .02em;
}
.chat-settings-nav-item.is-active .chat-channel-mark {
    border-color: var(--brand-border);
    background: var(--card);
    color: var(--brand-ink);
}
.chat-channel-mark.is-large { width: 44px; height: 44px; flex: 0 0 44px; font-size: 12px; }
.chat-channel-nav-copy { display: grid; min-width: 0; gap: 1px; }
.chat-channel-nav-copy strong { overflow: hidden; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }
.chat-channel-status { overflow: hidden; color: var(--muted); font-size: 11px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.chat-channel-status.status-enabled { color: var(--ok); }
.chat-channel-status.status-error { color: var(--err); }
.chat-channel-chevron { color: var(--faint); font-size: 20px; line-height: 1; }
.chat-settings-panel { overflow: hidden; }
.chat-settings-panel form { display: grid; }
.chat-settings-panel-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 28px;
    padding: 22px 24px;
    border-bottom: 1px solid var(--border);
}
.chat-settings-panel-title { display: flex; align-items: flex-start; min-width: 0; gap: 12px; }
.chat-settings-panel-title h2 { margin: 0 0 4px; font-size: 18px; }
.chat-settings-panel-title p { margin: 0; color: var(--muted); font-size: 13px; line-height: 1.45; }
.chat-channel-switch { display: flex; flex: 0 0 auto; align-items: center; gap: 12px; cursor: pointer; }
.chat-channel-switch-copy { display: grid; gap: 1px; text-align: right; }
.chat-channel-switch-copy strong { font-size: 12px; }
.chat-channel-switch-copy small { color: var(--muted); font-size: 10px; white-space: nowrap; }
.chat-channel-switch-control { position: relative; display: inline-flex; flex: 0 0 auto; width: 42px; height: 24px; }
.chat-channel-switch-control input { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.chat-channel-switch-control > span {
    width: 100%;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-2);
    transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.chat-channel-switch-control > span::after {
    content: "";
    position: absolute;
    top: 4px;
    left: 4px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--muted);
    transition: transform var(--dur) var(--ease), background var(--dur) var(--ease);
}
.chat-channel-switch-control input:checked + span { border-color: var(--brand); background: var(--brand); }
.chat-channel-switch-control input:checked + span::after { background: var(--on-brand); transform: translateX(18px); }
.chat-channel-switch-control input:focus-visible + span { outline: 2px solid var(--brand); outline-offset: 2px; }
/* Плашки панели канала — общая inline-alert со своим тоном (ИН8); здесь только
   место в панели: отступы от её краёв и плотность. */
.chat-settings-notice,
.chat-settings-dependency {
    margin: 18px 24px 0;
    padding: 12px 14px;
    font-size: 12px;
}
.chat-settings-notice { display: grid; gap: 3px; }
.chat-settings-dependency { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.chat-settings-notice strong { font-size: 12px; }
.chat-settings-notice span { color: var(--muted); }
.chat-settings-dependency a { flex: 0 0 auto; font-weight: 700; }
.chat-settings-form-intro { padding: 22px 24px 12px; }
.chat-settings-form-intro h3 { margin: 0 0 3px; color: var(--ink); font-size: 14px; }
.chat-settings-form-intro p { margin: 0; color: var(--muted); font-size: 12px; }
.chat-settings-fields { display: grid; gap: 16px; padding: 0 24px 24px; }
.mango-routing { padding: 0 24px 24px; border-bottom: 1px solid var(--border); }
.mango-routing h3 { font-size: 14px; }
.mango-routing p { color: var(--muted); font-size: 12px; }
.mango-route-row { grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 0 0 16px; margin-bottom: 16px; border-bottom: 1px solid var(--border); }
.mango-route-row > button { grid-column: 1 / -1; justify-self: start; }
/* Поля канала — общий .field (макрос field()); здесь только ширина: на широкой
   панели поле токена во всю строку читается хуже, чем в 620px. */
.chat-settings-fields > .field { max-width: 620px; }
.chat-settings-form-footer {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px 24px;
    border-top: 1px solid var(--border);
    background: var(--surface-2);
}
.chat-settings-form-footer .hui-button--primary { flex: 0 0 auto; white-space: nowrap; }
.chat-settings-form-footer p { margin: 0; color: var(--muted); font-size: 11px; line-height: 1.4; }
.chat-settings-security-note { margin: 16px 0 0; color: var(--muted); font-size: 11px; }
.telegram-user-control { border-top: 1px solid var(--border); }
.telegram-user-control > .chat-settings-notice { margin: 0 24px 16px; }
.telegram-user-action-form { display: flex; align-items: end; flex-wrap: wrap; gap: 12px; padding: 0 24px 22px; }
.telegram-user-action-form .field { flex: 1 1 220px; }
.telegram-user-action-form small { flex: 1 1 100%; color: var(--muted); }
.telegram-user-history { margin: 0 24px 24px; padding: 18px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); }
.telegram-user-first-message { margin: 0 24px 18px; padding: 18px; border: 1px solid var(--border); border-radius: var(--radius-md); }
.telegram-user-first-message h4 { margin: 0 0 12px; }
.telegram-user-first-message .telegram-user-action-form { padding: 0; }
.telegram-user-message-field { flex-basis: 360px; }
.telegram-user-message-field textarea { width: 100%; resize: vertical; }
.telegram-user-history h4 { margin: 0 0 12px; }
.telegram-user-history .telegram-user-action-form { padding: 12px 0 0; }
.telegram-user-progress { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin: 0 0 12px; }
.telegram-user-progress div { padding: 10px; border-radius: var(--radius-sm); background: var(--card); }
.telegram-user-progress dt { color: var(--muted); font-size: 11px; }
.telegram-user-progress dd { margin: 3px 0 0; font-weight: 700; }
.sms-provider-card { display: grid; gap: 12px; min-width: 0; }
.sms-provider-card label { min-width: 0; }
.sms-provider-card input { width: 100%; min-width: 0; box-sizing: border-box; }
.sms-provider-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.sms-provider-card-head .form-section-title { margin: 0; }
.sms-credentials-hint { margin-top: 10px; }
@media (max-width: 820px) {
    .sms-provider-grid,
    .chat-settings-fields { grid-template-columns: 1fr; }
}
@media (max-width: 980px) {
    .chat-settings-workspace { grid-template-columns: minmax(0, 1fr); }
    .chat-settings-nav { display: flex; gap: 8px; overflow-x: auto; padding: 8px; scroll-snap-type: x proximity; }
    .chat-settings-nav-group { flex: 0 0 auto; }
    .chat-settings-nav-group + .chat-settings-nav-group { margin: 0; padding: 0 0 0 8px; border-top: 0; border-left: 1px solid var(--border); }
    .chat-settings-nav-items { display: flex; }
    .chat-settings-nav-item { min-width: 190px; scroll-snap-align: start; }
}
@media (max-width: 640px) {
    .chat-settings-panel-head { flex-direction: column; gap: 18px; padding: 18px; }
    .chat-channel-switch { width: 100%; justify-content: space-between; }
    .chat-channel-switch-copy { text-align: left; }
    .chat-settings-notice,
    .chat-settings-dependency { margin: 14px 18px 0; }
    .chat-settings-dependency { align-items: flex-start; flex-direction: column; }
    .chat-settings-form-intro { padding: 20px 18px 10px; }
    .chat-settings-fields { padding: 0 18px 20px; }
    .chat-settings-form-footer { align-items: stretch; flex-direction: column; padding: 16px 18px; }
    .chat-settings-form-footer .hui-button--primary { width: 100%; }
    .telegram-user-control > .chat-settings-notice,
    .telegram-user-first-message,
    .telegram-user-history { margin-right: 18px; margin-left: 18px; }
    .telegram-user-action-form { align-items: stretch; flex-direction: column; padding-right: 18px; padding-left: 18px; }
    .telegram-user-action-form .field { width: 100%; }
    .telegram-user-progress { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.form-hint { margin: -4px 0 6px; font-size: 12px; }
.ai-channels .checkline { min-width: 130px; }
.ai-preview { margin-top: 12px; padding: 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2); }
.ai-preview p { margin: 6px 0 0; white-space: pre-wrap; line-height: 1.45; }
.ai-preview-ok { border-color: var(--ok-border); background: var(--ok-bg); }
.ai-preview-failed { border-color: var(--danger-border); background: var(--danger-soft); }
.ai-notes { display: grid; gap: 12px; margin-bottom: 18px; }
.ai-note .actions { flex-wrap: wrap; }
/* An automatic answer is not an administrator's reply, so it must not look
   like one — the workspace selector wins over the plain outbound colour. */
.message-bubble.ai,
.communications-workspace .message-bubble.ai { background: var(--ai-bg); border-color: var(--ai-border); }
.ai-tag { display: inline-flex; align-items: center; gap: 4px; padding: 1px 7px; border-radius: 999px; background: var(--ai-tag-bg); color: var(--ai-ink); font-size: 11px; font-weight: 700; }
.ai-tag::before { content: "✦"; }
@media (max-width: 900px) { .ai-status-strip { grid-template-columns: 1fr; } }
.ai-tools { display: grid; gap: 10px; margin-bottom: 12px; }
.ai-tool { align-items: start; gap: 10px; padding: 11px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2); }
.ai-tool span { display: grid; gap: 3px; }
.ai-tool small { color: var(--muted); font-size: 12px; line-height: 1.4; }
.ai-tool-trace { margin-top: 8px; font-size: 12px; color: var(--muted); }
/* Метрики чатов: период, целевое время ответа и разрезы. */
.communications-metrics-header { margin-bottom: 10px; }
.communications-metrics-header p { margin: 2px 0 0; }
.communications-metrics-intro { display: grid; justify-items: start; }
.metrics-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 18px; margin-bottom: 4px; }
.metrics-target { display: flex; align-items: end; gap: 10px; margin-top: 12px; }
.metrics-target input { width: 110px; }
.metrics-target-readonly { margin-top: 10px; }
.metrics-legend { font-size: 12px; }
.metrics-breakdown-head { margin-bottom: 12px; }
.metrics-breakdown-controls { display: flex; align-items: start; justify-content: flex-start; gap: 14px 28px; flex-wrap: wrap; margin-bottom: 14px; }
.metrics-breakdown-control { display: grid; gap: 6px; }
.metrics-breakdown-controls .chat-segments { flex: 0 0 auto; }
.metrics-filters { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.metrics-filters select { min-width: 180px; }
.metrics-breakdown { margin-bottom: 14px; }
.metric-ok { color: var(--ok); }
.metric-warn { color: var(--warn); }
.metric-bad { color: var(--err); }
.metrics-hours { list-style: none; margin: 0; padding: 12px 14px; display: grid; gap: 4px; }
.metrics-hours li { display: grid; grid-template-columns: 52px 1fr 40px; align-items: center; gap: 10px; font-size: 12px; }
.metrics-hours .hour { color: var(--muted); font-variant-numeric: tabular-nums; }
.metrics-hours .bar { height: 10px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
.metrics-hours .bar i { display: block; height: 100%; background: var(--brand); }
.metrics-hours .count { text-align: right; font-variant-numeric: tabular-nums; }
.conversation-history-list { max-height: 320px; overflow-y: auto; }
@media (max-width: 900px) { .metrics-target { margin-left: 0; } }

/* Звонок в переписке — карточка, а не пузырь с технической строкой. */
.message-bubble.call { max-width: min(86%, 560px); }
.communications-workspace .message-bubble.call.inbound { background: var(--surface-raised); border-color: var(--border); }
.communications-workspace .message-bubble.call.outbound { justify-self: end; background: var(--brand-tint); border-color: var(--brand-border); }
.communications-workspace .message-bubble.call.missed { background: var(--danger-soft); border-color: var(--danger-border); }
.call-head { display: flex; align-items: center; gap: 11px; }
.call-icon { display: grid; place-items: center; flex: 0 0 34px; width: 34px; height: 34px; border-radius: 50%; background: var(--surface-2); font-size: 15px; }
.message-bubble.call.missed .call-icon { background: var(--danger-soft); color: var(--err); }
.message-bubble.call.outbound .call-icon { background: var(--brand-strong); color: var(--brand-ink); }
.call-title { display: grid; gap: 2px; min-width: 0; flex: 1 1 auto; }
.call-title b { font-size: 14px; }
.call-meta { color: var(--muted); font-size: 12px; }
.call-back { flex: 0 0 auto; }
.message-bubble.call .message-attachments { margin-top: 10px; }
/* Заголовок раздела и его главный переключатель — в одной строке. */
.form-section-head { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.form-section-head.ai-rules-enabled { justify-content: flex-start; }
.form-section-head .form-section-title { margin-bottom: 10px; }
.form-card .form-section-head ~ .form-section-title,
.form-card .form-section-title ~ .form-section-head .form-section-title { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border); }
.checkline.switch { font-weight: 700; }
/* Отдельная страница «Настройки подписания»: документы — строки, шаги — столбцы,
   флажок стоит на их пересечении. Так состав читается по строке и по столбцу
   сразу, без повторного перечисления всех документов в каждом наборе. */
.signing-matrix { table-layout: fixed; }
.signing-matrix thead th { vertical-align: top; padding-top: 12px; padding-bottom: 12px; }
.signing-matrix th.signing-step { width: 34%; min-width: 200px; text-align: center; text-transform: none; letter-spacing: 0; }
.signing-step-title { display: block; font-size: 13px; color: var(--ink); }
.signing-step-hint { display: block; margin-top: 4px; font-weight: 400; font-size: 11.5px; line-height: 1.45; color: var(--muted); }
.signing-matrix th.signing-document { font-weight: 400; text-transform: none; letter-spacing: 0; background: transparent; vertical-align: middle; }
.signing-document-title { display: block; font-size: 14px; font-weight: 600; color: var(--ink); }
.signing-document-note { display: block; margin-top: 3px; font-size: 12px; color: var(--warn); }
.signing-row-unpublished .signing-document-title { color: var(--muted); font-weight: 500; }
.signing-matrix td.signing-cell { text-align: center; vertical-align: middle; }
/* Ячейка — сама по себе подпись флажка: label растягивается на неё целиком,
   поэтому попасть в него можно кликом по клетке, а не по 13 пикселям. */
.signing-box { justify-content: center; padding: 6px 0; margin: 0; cursor: pointer; }
.signing-box input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--brand); cursor: pointer; }
.signing-box input[type="checkbox"]:disabled { cursor: default; }
/* «обязателен» stacks under the box instead of beside it: set side by side the
   pair centres as a unit and pushes that one checkbox off the column's line. */
.signing-box.is-pinned { flex-direction: column; gap: 3px; cursor: default; }
.signing-box-note { font-size: 11px; color: var(--muted); }
.signing-actions { display: flex; justify-content: flex-end; padding: 14px 0; }
/* Реквизиты и печать. Ширина ограничена: реквизиты — короткие поля, на широком
   мониторе строка ввода во весь экран читается хуже, а не лучше. */
.requisites-form { max-width: 920px; }
.requisites-form label { flex: 0 1 auto; }
/* Повторяет общее правило: селектор выше по специфичности его перебивает, и без
   этой строки адрес получает поле ввода шириной в треть строки. */
.requisites-form label.wide { flex: 1 1 100%; }
.requisites-form label.grow { flex: 1 1 220px; }
.requisites-form label.narrow { flex: 0 0 200px; }
/* ИНН, КПП, ОГРН, БИК — поля известной длины, растягивать их нечем. */
.requisites-form label.code { flex: 0 0 156px; }
.requisites-form input, .requisites-form select { min-width: 0; width: 100%; }
.requisites-form .muted { margin: -2px 0 10px; font-size: 12.5px; line-height: 1.5; }
/* Две карточки загрузки рядом, предпросмотр в натуральном виде — владелец
   должен увидеть ровно то, что ляжет в договор. */
.requisites-images { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; margin-top: 16px; }
.requisites-image-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.requisites-image-head .form-section-title { margin: 0; }
.requisites-image-preview { display: flex; align-items: center; justify-content: center; min-height: 130px; margin: 12px 0; padding: 12px; border: 1px dashed var(--border); border-radius: var(--radius-sm); background: var(--surface-2); }
/* Шахматка проявляет прозрачный фон: белый квадрат вместо печати виден сразу,
   а не в договоре у клиента. */
.requisites-image-preview:has(img) { background-color: var(--card); background-image: linear-gradient(45deg, var(--surface-2) 25%, transparent 25%), linear-gradient(-45deg, var(--surface-2) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--surface-2) 75%), linear-gradient(-45deg, transparent 75%, var(--surface-2) 75%); background-size: 16px 16px; background-position: 0 0, 0 8px, 8px -8px, -8px 0; }
.requisites-image-preview img { max-width: 100%; max-height: 180px; }
.requisites-image-preview .muted { margin: 0; font-size: 13px; line-height: 1.5; text-align: center; }
.requisites-image-form .attachment { min-width: 0; }
/* Журнал подписаний в карточке клиента: внизу вкладки и свёрнут, потому что это
   справка «что и когда», а не то, что выдают на руки. */
.client-signature-log { margin: 18px 0 4px; }
.client-signature-log > summary { cursor: pointer; font-size: 13px; color: var(--muted); padding: 6px 0; }
.client-signature-log > summary:hover { color: var(--ink); }
.client-signature-log[open] > summary { margin-bottom: 6px; }
.client-signature-log-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.client-signature-log-list > li { display: grid; gap: 2px; padding: 8px 0; border-top: 1px solid var(--border); font-size: 13px; }
.client-signature-log-date { font-weight: 600; color: var(--ink); }
.client-signature-log-docs { line-height: 1.5; }
.requisites-form textarea { width: 100%; min-height: 120px; line-height: 1.5; }
.requisites-placeholders { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; align-items: baseline; font-size: 13px; margin-bottom: 4px; }
.requisites-placeholders code { font-size: 12.5px; background: var(--surface-2); padding: 2px 6px; border-radius: 4px; white-space: nowrap; }
.requisites-placeholders span { color: var(--muted); }
/* Предпросмотр набирается как в документе: падежи в нём проверяют глазами. */
.requisites-preamble-preview { margin: 0 0 6px; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2); font-size: 13.5px; line-height: 1.6; }
.requisites-notes { margin-top: 16px; }
.requisites-notes h2 { margin: 0 0 10px; font-size: 16px; }
.requisites-notes ul { margin: 0; padding-left: 18px; display: grid; gap: 6px; font-size: 13px; line-height: 1.55; color: var(--muted); }
.signing-notes { margin-top: 16px; }
.signing-notes h2 { margin: 0 0 10px; font-size: 16px; }
.signing-notes ul { margin: 0; padding-left: 18px; display: grid; gap: 6px; font-size: 13px; line-height: 1.55; color: var(--muted); }
.signing-notes b { color: var(--text); }

/* База знаний. Статью читают и с телефона на смене, и с компьютера у стойки:
   текст крупнее табличного, подсветка совпадений заметна. Все
   блоки страницы статьи — сама статья, «Помогла эта инструкция?», «Ещё в
   разделе» — одной ширины: ширины колонки содержимого. Отдельной узкой меры
   у статьи нет: таблицы в инструкциях шире абзацев, и узкая колонка ломала
   именно их. */
.kb-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 10px; }
.kb-card { display: flex; flex-direction: column; gap: 6px; padding: 14px 16px; border-radius: var(--kb-radius); }
.kb-card h2 { margin: 0; font-size: 16px; }
.kb-card h2 a { color: var(--ink); text-decoration: none; }
.kb-card h2 a:hover { color: var(--brand); }
.kb-card p { margin: 0; font-size: 12.5px; line-height: 1.45; }
.kb-subsections { margin: 0; padding-left: 0; list-style: none; display: grid; gap: 4px; font-size: 12.5px; }
.kb-card-foot { margin-top: auto; display: flex; gap: 8px; align-items: center; font-size: 11.5px; }
.kb-badge { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: 12px;
    border: 1px solid var(--brand-border); background: var(--brand-tint); color: var(--brand-ink); }
.kb-badge.draft { border-color: var(--warn-border, var(--border)); background: var(--warn-soft); color: var(--warn); }
.kb-badge.studio { border-color: var(--border); background: var(--surface-2); color: var(--muted); }
/* Строка пути: мелкая служебная надпись, а не часть заголовка. */
.kb-crumbs { display: flex; flex-wrap: wrap; gap: 4px; font-size: 12px; color: var(--muted); margin-bottom: 8px; }
.kb-crumbs a { color: var(--faint); text-decoration: none; }
.kb-chips { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 12px; }
.kb-article { width: 100%; }
.kb-meta { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 12px; padding-bottom: 12px; margin-bottom: 16px; border-bottom: 1px solid var(--border); }
.kb-body { font-size: 15px; line-height: 1.65; }
.kb-body h2 { font-size: 18px; margin: 26px 0 8px; letter-spacing: -.01em; }
.kb-body h3 { font-size: 15.5px; margin: 20px 0 6px; }
.kb-body h4, .kb-body h5 { font-size: 15px; margin: 18px 0 6px; }
.kb-body p { margin: 0 0 12px; }
.kb-body ul, .kb-body ol { margin: 0 0 12px; padding-left: 22px; display: grid; gap: 6px; }
.kb-body blockquote { margin: 0 0 12px; padding: 10px 14px; border-left: 3px solid var(--brand-border-strong);
    background: var(--surface-2); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.kb-body blockquote p { margin: 0; }
.kb-body pre { margin: 0 0 12px; padding: 12px 14px; overflow-x: auto; background: var(--surface-2);
    border: 1px solid var(--border); border-radius: var(--radius-sm); }
.kb-body code { font-size: 13px; background: var(--surface-2); padding: 2px 5px; border-radius: 4px; }
.kb-body pre code { background: none; padding: 0; }
.kb-body img { max-width: 100%; height: auto; border: 1px solid var(--border); border-radius: var(--radius-sm); }
.kb-body hr { border: 0; border-top: 1px solid var(--border); margin: 20px 0; }
/* Таблица в инструкции шире экрана телефона — прокручивается сама, не страница.
   Оформление — как у table.grid кабинета, чтобы справка не выглядела чужой. */
.kb-table-scroll { overflow-x: auto; margin: 0 0 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); }
.kb-body table { width: 100%; border-collapse: collapse; font-size: 14px; line-height: 1.45; }
.kb-body th, .kb-body td { padding: 8px 10px; border-bottom: 1px solid var(--border); text-align: left; vertical-align: top; }
.kb-body th { background: var(--surface-2); color: var(--muted); font-size: 12.5px; font-weight: 600; white-space: nowrap; }
.kb-body tbody tr:last-child td { border-bottom: 0; }
.kb-body tbody tr:hover td { background: var(--surface-2); }
.kb-keywords { margin-top: 18px; font-size: 12.5px; }
.kb-studio-rule { border-left: 3px solid var(--brand-border-strong); background: var(--brand-tint); }
.kb-studio-rule .kb-body { max-width: 860px; }
.kb-results { list-style: none; margin: 0 0 16px; padding: 0; display: grid; gap: 12px; }
.kb-results > li { padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--card); }
.kb-result-title { font-weight: 600; }
.kb-result-section { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.kb-result-snippet { margin: 6px 0 0; font-size: 13.5px; line-height: 1.55; color: var(--text); }
.kb-result-snippet mark { background: var(--brand-strong); color: inherit; padding: 0 2px; border-radius: 3px; }
.kb-article-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.kb-article-list > li { display: grid; gap: 4px; }
.kb-article-list p { margin: 0; font-size: 13.5px; }
.kb-recent ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; font-size: 14px; }
.kb-recent h2 { margin: 0 0 10px; font-size: 16px; }
.kb-empty, .kb-note { font-size: 13.5px; }
/* Кнопка «?» в шапке: ведёт на инструкцию по открытому разделу, если она есть. */
/* Высота — общий токен шапки, а не своя копия его значения: круглая кнопка
   держит ширину равной высоте, поэтому обе берутся из одного места. */
.topbar-help { display: inline-flex; align-items: center; justify-content: center;
    width: var(--topbar-control-height); height: var(--topbar-control-height);
    border: 1px solid var(--border); border-radius: 50%; background: var(--surface-raised); color: var(--muted); }
.topbar-help svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.7;
    stroke-linecap: round; stroke-linejoin: round; }
.topbar-help:hover { color: var(--brand); border-color: var(--brand-border-strong); }
/* Редактор базы знаний: форма и предпросмотр рядом, на телефоне — друг под другом. */
.kb-editor-layout { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: 16px; align-items: start; }
@media (max-width: 900px) { .kb-editor-layout { grid-template-columns: 1fr; } }
.kb-editor-form { display: grid; gap: 12px; }
.kb-editor-side { display: grid; gap: 12px; }
.kb-editor-side h2 { margin: 0 0 10px; font-size: 16px; }
.kb-roles { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 10px 12px; display: flex;
    flex-wrap: wrap; gap: 10px 16px; }
.kb-roles legend { font-size: 12.5px; color: var(--muted); padding: 0 4px; }
.kb-roles .checkbox { display: inline-flex; align-items: center; gap: 6px; font-size: 13.5px; }
.kb-article-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.kb-article-actions form { margin: 0; }
.kb-attachments, .kb-revisions, .kb-feedback-list { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 10px; font-size: 13px; }
.kb-revisions > li { display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
    padding-bottom: 8px; border-bottom: 1px solid var(--border); }
.kb-attachments form, .kb-revisions form { margin: 0; }
.kb-feedback { width: 100%; }
.kb-feedback-head { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; margin-bottom: 8px; }
.kb-feedback-list > li { display: grid; gap: 2px; }
/* Помощник по базе знаний: ответ, источники и оценка. */
.kb-ask h2 { margin: 0 0 6px; font-size: 16px; }
.kb-ask p { margin: 0 0 10px; }
.kb-answer { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border); }
.kb-answer-sources { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 10px; font-size: 12.5px; }
.kb-answer-rate { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 12px; font-size: 13px; }
.kb-answer-note { margin: 10px 0 0; font-size: 12.5px; }
/* База знаний использует ту же левую панель, что кабинет. Содержимое страницы
   начинается после неё; сам сайдбар всегда примыкает к левому верхнему углу. */
.kb-public-body { background: var(--bg); color: var(--ink); min-height: 100dvh; display: flex; flex-direction: column; }
.kb-public-header {
    position: sticky; top: 0; z-index: var(--z-sticky); margin-left: 250px;
    background: var(--surface-raised); border-bottom: 1px solid var(--border);
    transition: margin-left var(--dur) var(--ease);
}
.kb-public-bar { width: 100%; padding: 10px 28px; display: flex; flex-wrap: wrap;
    gap: 12px; align-items: center; justify-content: space-between; }
.kb-public-brand { font-weight: 600; font-size: 17px; color: var(--ink); text-decoration: none; }
.kb-public-brand:hover { color: var(--brand); }
.kb-public-actions { --topbar-control-height: 34px; display: flex; flex-wrap: nowrap; gap: 8px; align-items: center; margin-left: auto; }
.kb-public-actions > .hui-button { min-height: 34px; padding: 0 10px; }

/* Сайдбар теперь вынесен из сетки и не создаёт вокруг себя внешних отступов.
   В сетке остаются только статья и необязательное оглавление. */
.kb-public-shell:has(> .kb-toc:not([hidden])) {
    grid-template-columns: minmax(0, 1fr) var(--kb-toc-width);
}
.kb-public-shell { flex: 1 1 auto; width: auto; margin-left: 250px; padding: 24px 28px 48px;
    --kb-toc-width: 216px;
    display: grid; grid-template-columns: minmax(0, 1fr); gap: 32px; align-items: start;
    transition: margin-left var(--dur) var(--ease);
    /* Оболочка растягивается на всю высоту экрана, и свободное место
       делилось между строками: на телефоне сорокапиксельное меню занимало
       триста, и статья начиналась ниже середины экрана. */
    align-content: start; }
.kb-public-sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    height: 100dvh;
}
.kb-public-sidebar > .sidebar-account-stack { flex-direction: column; }
/* Левое меню базы знаний.

   Оформление берётся у сайдбара кабинета целиком: классы nav-item, nav-icon,
   nav-label, nav-caret, nav-subitem, nav-section те же самые. Здесь остаётся
   только то, чем меню базы от него отличается.

   Прежние .kb-public-nav-home / -item / -child описывали ту же строку меню
   второй раз и каждый раз чуть иначе: отступ 7 вместо 8, радиус sm вместо md,
   подсветка --green-tint вместо --mint-50, вес 600 вместо 700, и без колонки
   иконок. Рядом с кабинетом это читалось как другой продукт. */
.kb-public-nav {
    /* display здесь не задаётся намеренно: он бы перебил скрытие закрытой
       оболочки на узком экране, и меню оставалось бы развёрнутым всегда. */
    flex-direction: column;
    gap: 2px;
    /* Разделов шестнадцать, и с раскрытой веткой список длиннее экрана. Меню
       липкое, поэтому без собственной прокрутки нижние разделы становятся
       недостижимы: страница уже прокручена до конца, а меню — нет. */
    max-height: calc(100dvh - 96px);
    overflow-y: auto;
    overscroll-behavior: contain;
}
/* Названия разделов длинные — «Смены, расходы, зарплата», «Команда и
   администрирование». В одну строку они не помещались и обрезались
   многоточием, а рядом стояла плашка со счётчиком статей, которая отъедала
   ещё двадцать восемь пикселей. Счётчик убран, название переносится. */
.kb-public-nav .nav-label,
.kb-public-nav .nav-subitem {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    line-height: 1.3;
}
.kb-public-nav .nav-item { align-items: flex-start; }
.kb-public-nav .nav-icon,
.kb-public-nav .nav-caret { margin-top: 1px; }
/* Название занимает свободную ширину, счётчик и шеврон прижаты к правому краю. */
.kb-public-nav .nav-label { flex: 1 1 auto; }
.kb-public-nav-home { margin-bottom: 2px; }

/* Раздел как сворачиваемая группа. Собственный треугольник <details> убран:
   его роль играет тот же шеврон, что и у выпадающих пунктов кабинета. */
.kb-nav-group { display: grid; }
.kb-nav-group > summary { cursor: pointer; list-style: none; }
.kb-nav-group > summary::-webkit-details-marker { display: none; }
.kb-nav-group > summary::marker { content: ""; }
.kb-nav-group[open] > summary .nav-caret svg { transform: rotate(90deg); }
/* Та же лесенка, что у подменю кабинета в узкой раскладке. */
.kb-nav-submenu {
    display: grid;
    gap: 1px;
    margin: 2px 0 4px 20px;
    padding-left: 10px;
    border-left: 1px solid var(--border);
}
.kb-nav-submenu .nav-subitem { display: flex; align-items: center; gap: 8px; }

/* Оболочка меню. На широком экране это не переключатель, а просто список:
   заголовок скрыт, содержимое раскрыто всегда. Родной <details> так не умеет,
   поэтому раскрытие навязывается двумя путями сразу — где браузер знает
   ::details-content, работает он, где нет, хватает display у самого списка.
   Контрольная точка 901px — та же, по которой кабинет меняет сайдбар на
   бургер. */
.kb-nav-shell-summary { cursor: pointer; list-style: none; }
.kb-nav-shell { min-height: 0; flex: 1 1 auto; }
.kb-nav-shell-summary::-webkit-details-marker { display: none; }
.kb-nav-shell-summary::marker { content: ""; }
.kb-nav-shell[open] > .kb-nav-shell-summary .nav-caret svg { transform: rotate(90deg); }
.kb-nav-shell[open] > .kb-public-nav { display: flex; }
@media (min-width: 901px) {
    .kb-nav-shell > .kb-nav-shell-summary { display: none; }
    .kb-nav-shell > .kb-public-nav { display: flex; }
    .kb-nav-shell::details-content { content-visibility: visible; block-size: auto; }
    .kb-public-sidebar .kb-public-nav { max-height: calc(100dvh - 112px); }
    .kb-public-sidebar:has(> .sidebar-account-stack) .kb-public-nav {
        max-height: calc(100dvh - 172px);
    }
    .kb-public-sidebar:has(.kb-cabinet-link) .kb-public-nav {
        max-height: calc(100dvh - 216px);
    }

    html[data-sidebar-collapsed="true"] .kb-public-header,
    html[data-sidebar-collapsed="true"] .kb-public-shell,
    html[data-sidebar-collapsed="true"] .kb-public-footer {
        margin-left: 68px;
    }
    html[data-sidebar-collapsed="true"] .kb-public-sidebar .kb-public-nav .nav-icon {
        margin-top: 0;
    }
    html[data-sidebar-collapsed="true"] .kb-public-sidebar .kb-public-nav {
        max-height: none;
        overflow: visible;
    }
    html[data-sidebar-collapsed="true"] .kb-public-sidebar .kb-nav-group {
        position: relative;
    }
    html[data-sidebar-collapsed="true"] .kb-public-sidebar .kb-nav-group[open]::details-content {
        overflow: visible;
    }
    html[data-sidebar-collapsed="true"] .kb-public-sidebar .kb-nav-submenu {
        position: absolute;
        top: 0;
        left: calc(100% + 12px);
        z-index: var(--z-submenu);
        display: none;
        min-width: 220px;
        margin: 0;
        padding: 6px;
        border: 1px solid var(--border);
        border-radius: var(--radius-md);
        background: var(--card);
        box-shadow: var(--shadow);
    }
    html[data-sidebar-collapsed="true"] .kb-public-sidebar .kb-nav-group[open]:hover > .kb-nav-submenu,
    html[data-sidebar-collapsed="true"] .kb-public-sidebar .kb-nav-group[open]:focus-within > .kb-nav-submenu {
        display: grid;
    }
}

/* Плавное раскрытие там, где браузер умеет интерполировать auto. Где не
   умеет — группа просто раскрывается сразу, как обычный <details>. */
@supports selector(::details-content) {
    .kb-nav-group { interpolate-size: allow-keywords; }
    .kb-nav-group::details-content {
        block-size: 0;
        overflow: hidden;
        transition: block-size var(--dur) var(--ease),
                    content-visibility var(--dur) allow-discrete;
    }
    .kb-nav-group[open]::details-content { block-size: auto; }
}
@media (prefers-reduced-motion: reduce) {
    .kb-nav-group::details-content { transition: none; }
}
.kb-public-content { min-width: 0; display: grid; gap: 16px; align-content: start; }
.kb-public-content .page-header { margin-bottom: 0; }
/* Поисковая строка — элемент управления, а не содержимое: на всю ширину
   экрана она не растягивается. Статья и карточки под ней — на всю колонку. */
.kb-public-footer {
    margin-left: 250px;
    border-top: 1px solid var(--border);
    background: var(--surface-raised);
    font-size: 13px;
    transition: margin-left var(--dur) var(--ease);
}
.kb-public-footer .kb-public-bar { padding: 16px 28px; }

@media (max-width: 900px) {
    .kb-public-header,
    .kb-public-shell,
    .kb-public-footer { margin-left: 0; }
    .kb-public-shell,
    .kb-public-shell:has(> .kb-toc:not([hidden])) {
        grid-template-columns: 1fr;
        gap: 18px;
        padding: 18px 16px 36px;
    }
    /* Была горизонтальная лента разделов, и подразделы в ней скрывались
       совсем — добраться до них с телефона было нельзя. Теперь список прячется
       целиком, как сайдбар кабинета за бургером: шестнадцать разделов над
       статьёй отодвинули бы её на пол-экрана. */
    .kb-nav-shell {
        border: 1px solid var(--border);
        border-radius: var(--radius-md);
        background: var(--card);
    }
    .kb-nav-shell[open] { padding-bottom: 6px; }
    .kb-public-nav {
        position: static;
        max-height: 52vh;
        padding: 0 6px;
    }
    .kb-public-bar { padding: 10px 16px; }
    .kb-public-actions { gap: 6px; }
}

/* ===========================================================================
   Примитивы из shadcn/ui, перенесённые на разметку кабинета.

   Из самого пакета взять нечего: shadcn — это CLI, который раскладывает по
   проекту исходники на React, Tailwind и Radix. Здесь Jinja, htmx и этот
   файл. Поэтому переносится не код, а состав слотов и словарь состояний:
   ровно то, из-за чего в shadcn поле формы или таблица выглядят одинаково
   на всех страницах, а у нас — по-разному на каждой.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   Поле формы — .field   (shadcn: Field)

   Полем в кабинете был голый <label>: он же обёртка, он же подпись. Пока в
   поле только подпись и контрол, этого хватает. Как только понадобилась
   пояснительная строка, каждая страница заводила свою: .chat-settings-field
   с -label и -hint для настроек чата, .field-label для расходов,
   .conversation-assignee label с собственным display: grid. Оттуда же
   пятнадцать правил вида «.expense-page-form .form-row > label», которые
   правят flex-basis голого label под конкретную страницу.

   Слотов четыре — подпись, контрол, пояснение, ошибка:

     <label class="field">
         <span class="field-label">Телефон</span>
         <input type="tel" name="phone">
         <span class="field-hint">Формат +7 900 000-00-00</span>
     </label>

   Невалидное состояние — атрибутом на обёртке, а не отдельным классом: то же
   слово читает aria-invalid на самом контроле, поэтому состояние остаётся
   одно и не может разъехаться.

     <label class="field" data-invalid>
         <span class="field-label">Телефон</span>
         <input type="tel" name="phone" aria-invalid="true">
         <span class="field-error">Такой телефон уже занят</span>
     </label>
   --------------------------------------------------------------------------- */
.field {
    display: grid;
    /* Строки прижаты к верху, а не растянуты по высоте поля. В .field-group
       все поля ряда одной высоты, и без этого поле без пояснения отдавало лишнюю
       высоту своему контролу: рядом с сорокапиксельными соседями стояло поле в 51. */
    align-content: start;
    gap: 5px;
    min-width: 0;
    font-size: 13px;
    font-weight: 400;
    color: var(--muted);
}
.field > input,
.field > select,
.field > textarea { width: 100%; min-width: 0; }
.field-label {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    color: var(--ink);
    font-size: 12px;
    font-weight: 700;
}
.field-label-text {
    display: inline-flex;
    align-items: baseline;
    gap: 3px;
}
/* Необязательность, счётчик символов, единица измерения — всё, что стоит
   справа от подписи и не является самой подписью. */
.field-label small { color: var(--muted); font-size: 10px; font-weight: 500; }
.field-label .field-required {
    color: var(--err);
    font-size: 14px;
    font-weight: 800;
    line-height: 1;
}
[data-form-dirty-status], [data-form-guard-error] {
    grid-column: 1 / -1;
    flex: 1 1 100%;
    width: 100%;
    min-width: 0;
}
.field[data-invalid] .field-label { color: var(--err); }
.field[data-invalid] > input,
.field[data-invalid] > select,
.field[data-invalid] > textarea,
.field[data-invalid] > .input-group { border-color: var(--danger-border); }

/* Галочка: контрол слева, подпись и пояснение — колонкой справа. Это не
   вариант вертикального поля, а другая раскладка, поэтому отдельный класс,
   а не модификатор. Заменяет .checkline там, где к галочке нужно пояснение. */
.field-check {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    gap: 4px 10px;
    color: var(--ink);
}
.field-check > input[type="checkbox"],
.field-check > input[type="radio"] {
    width: auto;
    min-width: 0;
    margin-top: 3px;
}
.field-check > .field-body { display: grid; gap: 2px; min-width: 0; }

/* Группа полей вместо .form-row.

   .form-row — это flex-wrap, и ширину каждого поля страница задавала сама
   через flex-basis: 150px, 190px, 220px, 128px. Здесь ширина задаётся один
   раз минимальной шириной поля, а сколько колонок поместится, считает сам
   grid. Подстроить страницу можно, не заводя правило:

     <div class="field-group" style="--field-min: 260px">

   min(…, 100%) нужен, чтобы на узком телефоне колонка не оказалась шире
   экрана: auto-fit не умеет опускаться ниже minmax-минимума сам. */
.field-group {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(var(--field-min, 200px), 100%), 1fr));
    gap: 12px 16px;
    min-width: 0;
    margin-bottom: 12px;
}
.field-group > .wide { grid-column: 1 / -1; }
.marketing-quiet-hours-range { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* Раздел формы: подпись раздела вместо голого <h3> посреди полей. */
.fieldset {
    display: grid;
    gap: 12px;
    min-width: 0;
    margin: 0 0 18px;
    padding: 0;
    border: 0;
}
.fieldset-legend { padding: 0; color: var(--ink); font-size: 14px; font-weight: 700; }
.fieldset-hint { margin: -6px 0 0; color: var(--muted); font-size: 12px; line-height: 1.45; }

/* Создание клиента: одна рабочая форма, разделённая по смыслу, без карточек
   внутри карточки. Состояния полей повторяют композицию HeroUI TextField:
   label, control, description, field error; React-компоненты здесь не нужны. */
.client-create-form { display: grid; gap: 0; }
.client-create-form .modal-header p {
    max-width: none;
    margin: 4px 0 0;
    line-height: 1.45;
}
.client-create-form .modal-header > div { min-width: 0; }
.client-create-subtitle {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.client-create-section {
    gap: 12px;
    margin: 0;
    padding: 18px 0;
    border-bottom: 1px solid var(--border);
}
.client-create-section:first-of-type { padding-top: 4px; }
.client-create-section--notes { border-bottom: 0; }
.client-create-section .field-group {
    --field-min: 220px;
    margin-bottom: 0;
}
.client-create-identity-fields { --field-min: 280px !important; }
/* Поля окна — общие поля кабинета: своя подпись 13px и серая подложка полей
   «Нового клиента» сняты (ИН9), ошибка над формой — общая плашка alert(). */
.client-create-actions {
    position: sticky;
    bottom: 0;
    z-index: var(--z-raised);
    justify-content: flex-end;
    margin: 0 -16px -16px;
    padding: 14px 16px;
    border-top: 1px solid var(--border);
    background: var(--card);
}
@media (max-width: 640px) {
    .client-create-section .field-group { grid-template-columns: 1fr; }
    .client-create-actions .hui-button { flex: 1 1 0; }
}

/* ---------------------------------------------------------------------------
   Поле с приставкой — .input-group   (shadcn: InputGroup)

   Рубль после суммы, лупа перед поиском, «шт.» после количества, кнопка
   «Найти» вплотную к полю — каждый такой случай верстался заново и каждый раз
   немного иначе: то приставка внутри рамки, то рядом с ней.

   Рамка и подсветка фокуса живут на обёртке, у самого контрола их нет, —
   иначе внутри одной рамки оказывались бы две.

     <div class="input-group">
         <span class="input-group-addon">₽</span>
         <input type="number" name="amount" inputmode="decimal">
     </div>

   Приставка снизу (data-align="block-end") нужна многострочному полю: под
   textarea становится строка со счётчиком символов или кнопками.
   --------------------------------------------------------------------------- */
.input-group {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    min-width: 0;
    min-height: var(--control-h);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card);
    transition: border-color var(--dur) ease, box-shadow var(--dur) ease;
}
.input-group:focus-within {
    border-color: var(--brand-border-strong);
    box-shadow: 0 0 0 3px var(--brand-strong);
}
.input-group > input,
.input-group > select,
.input-group > textarea {
    flex: 1 1 120px;
    min-width: 0;
    /* Высоту здесь задаёт группа, а не поле: со своей height поле распирало бы
       обёртку на две пиксели рамки, и поле с приставкой вставало бы выше
       соседнего обычного в том же ряду. */
    height: auto;
    align-self: stretch;
    border: 0;
    border-radius: inherit;
    background: none;
}
.input-group > input:focus,
.input-group > select:focus,
.input-group > textarea:focus { outline: none; }
.input-group > textarea { flex-basis: 100%; padding-block: 9px; }
.input-group-addon {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 6px;
    padding-inline: 11px;
    color: var(--faint);
    font-size: 12.5px;
    font-weight: 600;
    white-space: nowrap;
}
/* Приставка, у которой есть собственное действие, — не текст, а кнопка:
   отступ у неё свой, иначе цель нажатия оказывается 11-пиксельной полоской. */
.input-group-addon > .hui-button { min-height: 30px; padding: 3px 10px; font-size: 13px; }
.input-group-addon:first-child { padding-inline-end: 0; }
.input-group-addon:last-child { padding-inline-start: 0; }
.input-group-addon[data-align="block-start"],
.input-group-addon[data-align="block-end"] {
    flex: 1 0 100%;
    justify-content: flex-end;
    padding: 6px 9px;
}
.input-group-addon[data-align="block-start"] { order: -1; box-shadow: inset 0 -1px 0 var(--border); }
.input-group-addon[data-align="block-end"] { order: 1; box-shadow: inset 0 1px 0 var(--border); }
.input-group[data-invalid],
[data-invalid] > .input-group { border-color: var(--danger-border); }

/* ---------------------------------------------------------------------------
   Таблица с сортировкой   (shadcn: Data Table)

   Таблиц в кабинете пятьдесят четыре, а заголовок с сортировкой был у восьми
   страниц — и в каждой лежала своя копия одного и того же макроса
   sortable_header, девять копий всего. Отличались они только тем, из какого
   словаря брать ссылки. Копии сведены в webapp/templates/_table.html.

   Здесь остаётся то, чего в макросе не было вовсе: по какой колонке таблица
   отсортирована сейчас, видно только по стрелке в 10 пикселей. Активная
   колонка теперь подсвечена целиком.
   --------------------------------------------------------------------------- */
/* Активная колонка. Раньше её заливали зелёным во всю ячейку — плашка весила
   больше, чем выделение строки под курсором, и глаз цеплялся за шапку вместо
   данных. Теперь состояние несут цвет подписи и стрелка. */
.sortable-th.is-sorted > a { color: var(--ink); font-weight: 600; }
.sortable-th.is-sorted .sort-icon { color: var(--brand); opacity: 1; }

.sort-icon {
    width: 14px; height: 14px; flex: none;
    fill: none; stroke: currentColor; stroke-width: 2;
    stroke-linecap: round; stroke-linejoin: round;
    opacity: 0; transition: opacity var(--dur) ease;
}
/* Двойной шеврон на неотсортированной колонке — подсказка, а не значение: он
   проявляется под курсором и по фокусу с клавиатуры. Показывать его сразу во
   всех колонках значит нарисовать восемь одинаковых стрелок, среди которых не
   видно текущую. */
.sortable-th > a:hover .sort-icon,
.sortable-th > a:focus-visible .sort-icon { opacity: .5; }
.sortable-th.is-sorted > a:hover .sort-icon { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
    .sort-icon { transition: none; }
}

/* Заголовок, который не уезжает при прокрутке длинного списка.

   Два условия, без которых не работает. Первое: у table.grid стоит
   overflow: hidden ради скруглённых углов, а любой предок с overflow, кроме
   visible, отменяет sticky у потомка — поэтому здесь overflow возвращается, а
   углы задаются на самих ячейках. Второе: при border-collapse: collapse
   граница принадлежит таблице, а не ячейке, и уезжает вместе с телом, —
   поэтому нижняя линия шапки рисуется тенью.

     <table class="grid" data-sticky-head>

   Если над таблицей есть собственная липкая панель, её высота передаётся
   через --sticky-head-top, чтобы шапка встала под ней, а не под неё. */
table.grid[data-sticky-head] { overflow: visible; }
table.grid[data-sticky-head] thead th {
    position: sticky;
    top: var(--sticky-head-top, 0);
    z-index: var(--z-sticky);
    box-shadow: inset 0 -1px 0 var(--border);
    /* Подложка здесь больше не задаётся: она есть у шапки всегда. Раньше это
       правило было единственным местом, где липкий заголовок получал плоскость,
       и переопределяло бы её другим цветом. */
}
table.grid[data-sticky-head] thead tr:first-child th:first-child { border-top-left-radius: var(--radius-md); }
table.grid[data-sticky-head] thead tr:first-child th:last-child { border-top-right-radius: var(--radius-md); }

/* ---------------------------------------------------------------------------
   Размер всплывающей карточки — .modal[data-size]

   Ширина каждой карточки задавалась собственным правилом рядом с её именем:
   440 у таблицы реквизитов, 520 у предупреждения смены, 560 у публикации
   расписания, 640 у продажи абонемента, 680 у привязки диалога, 920 у карты
   клиента, 980 по умолчанию, 1120 у боковой карточки. Восемь ширин, ни одна
   не выводится из другой, и добавление девятой карточки означало девятое
   правило.

   Ступеней четыре, отступ от края экрана у всех одинаковый (--dialog-gutter):

     sm   440   подтверждение, одно поле, короткий список
     md   640   форма на несколько полей
     lg   920   форма с таблицей или предпросмотром
     xl  1120   карточка сущности целиком

   Размер стоит у каждого окна кабинета (ИН23), собственных ширин окон
   рядом с их именами не осталось; своя ширина — только у боковых карточек
   (.client-drawer) и у окна по содержимому (fit).
   --------------------------------------------------------------------------- */
.modal[data-size="sm"] { width: min(440px, calc(100vw - var(--dialog-gutter))); }
.modal[data-size="md"] { width: min(640px, calc(100vw - var(--dialog-gutter))); }
.modal[data-size="lg"] { width: min(920px, calc(100vw - var(--dialog-gutter))); }
.modal[data-size="xl"] { width: min(1120px, calc(100vw - var(--dialog-gutter))); }
/* На телефоне окно почти во всю ширину: шестнадцать пикселей на оба края. */
@media (max-width: 560px) {
    :root { --dialog-gutter: 16px; }
}
.event-form .modal-header[data-sticky] { top: -16px; }
/* Липкий ряд действий большой формы в окне: кнопки остаются у нижнего края,
   пока поля прокручиваются. Отрицательные поля равны padding у .form-card
   окна, иначе ряд не дотягивается до краёв и форма просвечивает по бокам.
   Было два одинаковых правила — у окна мероприятия и у объединения дублей. */
.actions--sticky {
    position: sticky;
    bottom: -16px;
    z-index: var(--z-raised);
    margin: 0 -18px -16px;
    padding: 14px 18px;
    background: var(--card);
    border-top: 1px solid var(--border);
    flex-wrap: wrap;
}

/* Шапка карточки, которая остаётся на месте при прокрутке содержимого.
   Раньше липкой умела быть только .client-panel-header — та, что внутри
   боковой карточки; у .modal-header такого варианта не было, и в длинной
   форме кнопка закрытия уезжала вверх вместе с заголовком. */
.modal-header[data-sticky] {
    position: sticky;
    top: 0;
    z-index: var(--z-raised);
    /* Отрицательные поля равны padding у .form-card. Без них шапка
       накрывает только колонку содержимого, и в шестнадцатипиксельных полях
       по краям видно, как форма проезжает под ней. Тот же приём, что у
       .client-panel-header, только шаг отступа здесь свой. */
    margin: -16px -16px 14px;
    padding: 14px 16px;
    background: var(--card);
    border-bottom: 1px solid var(--border);
}

/* Ширина по содержимому — для карточек, которые целиком приходят с сервером.

   Ступени sm/md/lg/xl задают предсказуемую ширину, и для карточек, которые
   догружаются htmx-ом, это правильно: содержимое приезжает после открытия, и
   карточка с плавающей шириной дёргалась бы вбок на каждом ответе. Но
   подтверждение из одной фразы такой ступени не нужно — <dialog> по умолчанию
   ужимается по содержимому, надо только не мешать ему шириной.

     <dialog class="modal" data-size="fit">

   Границы всё равно нужны: без нижней подтверждение из двух слов вышло бы
   уже своих кнопок, без верхней таблица растянула бы карточку на весь экран. */
.modal[data-size="fit"] {
    /* Именно fit-content, а не auto: браузер выставляет модальному <dialog>
       нулевые left и right, и при auto ширина не ужимается по содержимому, а
       наоборот разливается до max-width. */
    width: fit-content;
    min-width: min(340px, calc(100vw - var(--dialog-gutter)));
    max-width: min(920px, calc(100vw - var(--dialog-gutter)));
}

/* Плавный рост вместо скачка, когда содержимое приезжает htmx-ом: карточка
   открывается с заглушкой на 380 пикселей и дорастает до своего размера.
   Интерполяция auto есть не везде — там, где её нет, высота встаёт сразу,
   ровно как до этой правки. Переход не срабатывает на самом открытии:
   <dialog> переключает display, а такие смены анимируются только с
   @starting-style, которого здесь нет намеренно. */
@supports (interpolate-size: allow-keywords) {
    .client-drawer {
        interpolate-size: allow-keywords;
        transition: height var(--dur) var(--ease);
    }
}
@media (prefers-reduced-motion: reduce) {
    .client-drawer { transition: none; }
}

/* ---------------------------------------------------------------------------
   Одноразовый код — .otp   (shadcn: Input OTP)

   Код из SMS вводится в кабинете и в личном кабинете в одиннадцати местах, и
   везде это было обычное текстовое поле с placeholder «123456»: сколько цифр
   ждут, видно только из подсказки, а набранное не пересчитать глазами.

   Клетки нарисованы отдельным слоем и помечены aria-hidden: значение живёт в
   одном настоящем input. Так остаётся работать autocomplete="one-time-code"
   — Android и iOS подставляют код из SMS сами, — и форма отправляется без
   единой строки JavaScript. Разложить цифры по клеткам получается разрядкой:
   каждый символ занимает ровно ширину клетки с просветом.

     <span class="otp" style="--otp-length: 6">
         <span class="otp-slots" aria-hidden="true">...шесть пустых span...</span>
         <input class="otp-input" name="code" inputmode="numeric"
                autocomplete="one-time-code" maxlength="6">
     </span>

   Разрядка считается в ch, поэтому шрифт обязан быть моноширинным: в Manrope
   ширина «1» и «8» разная, и цифры расползлись бы по клеткам.
   --------------------------------------------------------------------------- */
.otp {
    --otp-length: 6;
    --otp-slot: 44px;
    --otp-gap: 8px;
    position: relative;
    display: inline-grid;
    max-width: 100%;
    width: calc(var(--otp-length) * var(--otp-slot) + (var(--otp-length) - 1) * var(--otp-gap));
}
.otp-input {
    position: absolute;
    inset: 0;
    width: 100%;
    min-width: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    color: var(--ink);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
    font-size: 21px;
    font-weight: 700;
    letter-spacing: calc(var(--otp-slot) + var(--otp-gap) - 1ch);
    text-indent: calc((var(--otp-slot) - 1ch) / 2);
}
.otp-input:focus { outline: none; }
.otp-input::placeholder { color: var(--faint); opacity: .5; }
/* Невалидный код: рамка у всех клеток сразу — ошибка относится к коду
   целиком, а не к какой-то одной цифре. */
/* На узком телефоне шесть клеток по 44 пикселя не помещаются в экран. */
@media (max-width: 420px) {
    .otp { --otp-slot: 38px; --otp-gap: 6px; }
    .otp-input { font-size: 19px; }
}

/* ===========================================================================
   База знаний: поиск в шапке, оглавление, помощник и общая плотность.

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

/* Собственный радиус: 12 пикселей кабинета на плотной документации выглядят
   мягче, чем нужно. Меняется одним значением, а не в двадцати правилах. */
.kb-public-body { --kb-radius: 8px; }

/* ---------- Поиск в шапке ---------- */
.kb-topsearch {
    position: relative;
    flex: 1 1 320px;
    min-width: 0;
    max-width: 520px;
    margin: 0 8px;
    display: flex;
    align-items: center;
}
.kb-topsearch-icon {
    position: absolute;
    left: 10px;
    display: inline-flex;
    color: var(--faint);
    pointer-events: none;
}
.kb-topsearch-icon svg {
    width: 16px; height: 16px;
    fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round;
}
.kb-topsearch input[type="search"] {
    width: 100%;
    min-width: 0;
    min-height: 34px;
    padding: 6px 12px 6px 32px;
    border-radius: var(--kb-radius);
    font-size: 14px;
}
.kb-topsearch input[type="search"]:focus-visible {
    border-color: var(--brand-border-strong);
    outline: none;
    box-shadow: 0 0 0 3px var(--brand-strong);
}

/* ---------- Оглавление статьи ---------- */
.kb-toc {
    position: sticky;
    top: 72px;
    display: grid;
    gap: 2px;
    /* Нижние пункты не должны уходить под плавающее окно помощника. */
    padding-bottom: 56px;
    max-height: calc(100dvh - 96px);
    overflow-y: auto;
    overscroll-behavior: contain;
}
.kb-toc-title {
    padding: 0 10px 6px;
    color: var(--faint);
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
}
.kb-toc-list { display: grid; gap: 1px; }
.kb-toc-link {
    padding: 5px 10px;
    border-left: 2px solid transparent;
    color: var(--muted);
    font-size: 13px;
    line-height: 1.35;
    text-decoration: none;
    transition: color var(--dur) ease, border-color var(--dur) ease;
}
.kb-toc-link-deep { padding-left: 22px; font-size: 12.5px; }
.kb-toc-link:hover { color: var(--ink); }
/* Где ты сейчас: без этого оглавление показывает, что где-то есть, но не где
   ты находишься. Подсветку ведёт IntersectionObserver в knowledge.js. */
.kb-toc-link.active { border-left-color: var(--brand); color: var(--brand-ink); font-weight: 600; }

/* ---------- Помощник как плавающее окно ---------- */
.kb-ask-dock {
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: var(--z-menu);
    /* Панель раскрывается вверх: окно прижато к низу экрана, и вниз ей некуда. */
    display: flex;
    flex-direction: column-reverse;
    align-items: flex-end;
    gap: 10px;
}
.kb-ask-dock-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 40px;
    padding: 8px 16px;
    border-radius: 999px;
    background: var(--brand);
    color: var(--on-brand);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    list-style: none;
    box-shadow: var(--shadow);
    transition: background var(--dur) ease, transform var(--dur-fast) ease;
}
.kb-ask-dock-toggle::-webkit-details-marker { display: none; }
.kb-ask-dock-toggle::marker { content: ""; }
.kb-ask-dock-toggle:hover { background: var(--brand-ink); }
.kb-ask-dock-toggle:active { transform: translateY(1px); }
.kb-ask-dock-icon { display: inline-flex; }
.kb-ask-dock-icon svg {
    width: 18px; height: 18px;
    fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round;
}
.kb-ask-dock[open] .kb-ask-dock-label { display: inline; }
.kb-ask-dock-panel {
    width: min(380px, calc(100vw - 40px));
    max-height: min(70dvh, 560px);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 16px;
    border: 1px solid var(--border);
    border-radius: var(--kb-radius);
    background: var(--card);
    box-shadow: var(--shadow);
}
.kb-ask-dock-head { margin-bottom: 12px; }
.kb-ask-dock-head p { margin: 4px 0 0; font-size: 12.5px; line-height: 1.45; }
.kb-ask-form { display: flex; gap: 8px; align-items: center; }
.kb-ask-form input { flex: 1 1 auto; min-width: 0; font-size: 14px; }
.kb-ask-dock-answer:not(:empty) { margin-top: 12px; }

/* ---------- Плотность документации ---------- */
.kb-public-content .card { border-radius: var(--kb-radius); box-shadow: none; }
.kb-public-content .page-header h1 { font-size: 24px; letter-spacing: -.01em; }
.kb-crumbs a:hover { color: var(--brand-ink); text-decoration: underline; }
.kb-crumbs span { color: var(--faint); }
/* Длинная строка утомляет глаз: колонка статьи шире, чем нужно тексту. */
.kb-article .kb-body { max-width: 74ch; }
.kb-article { padding: 22px 24px; }
.kb-body h2:first-child, .kb-body h3:first-child { margin-top: 0; }
/* Прыжок по якорю из оглавления ставит заголовок ровно на верх экрана — то
   есть под липкую шапку, и человек попадает сразу в текст без его названия. */
.kb-body h2, .kb-body h3, .kb-body h4 { scroll-margin-top: 80px; }

/* Карточка раздела на главной: иконка та же, что в меню, — две страницы
   перестают выглядеть как два разных списка. */
.kb-card-head { display: flex; align-items: center; gap: 10px; }
.kb-card-head h2 { font-size: 15px; }
.kb-card-icon {
    width: 28px; height: 28px; flex: 0 0 28px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 7px;
    background: var(--brand-tint);
    color: var(--brand-ink);
}
.kb-card-icon svg {
    width: 17px; height: 17px;
    fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round;
}
.kb-subsections a { color: var(--muted); }
.kb-subsections a:hover { color: var(--brand-ink); }
.kb-article-list > li { padding-bottom: 12px; border-bottom: 1px solid var(--border); }
.kb-article-list > li:last-child { padding-bottom: 0; border-bottom: 0; }

.payroll-corrections { margin-block: 24px; }
.inline-alert.payroll-publication-alert { display: block; overflow-wrap: anywhere; }
.payroll-publication-alert p { margin-block: 8px; }
.payroll-publication-alert summary { cursor: pointer; }
.payroll-corrections summary { cursor: pointer; padding-block: 12px; overflow-wrap: anywhere; }
.payroll-corrections > summary { font-weight: 600; }
.payroll-corrections-table .payroll-correction-comment { overflow-wrap: anywhere; }
.payroll-correction-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap: 16px; padding-block: 8px 16px; }
.payroll-correction-form > label { min-width: 0; }
.payroll-correction-form .payroll-correction-reason { grid-column: 1 / -1; }
.payroll-correction-form .actions { grid-column: 1 / -1; }

@media (max-width: 900px) {
    /* На узком экране оглавление уводит статью вниз: там его роль играет
       сама прокрутка. */
    .kb-toc { display: none; }
    .kb-topsearch { order: 3; flex-basis: 100%; margin: 6px 0 0; max-width: none; }
    .kb-ask-dock { right: 12px; bottom: 12px; }
    .kb-ask-dock-panel { width: calc(100vw - 24px); }
    .kb-article { padding: 16px 14px; }
}

/* Оптимизатор расписания: отсутствия в развёртке. Отличие от шаблона —
   бейджем .tag общего словаря тонов. */
.schedule-row--absent td { background: var(--warn-tint); }
.schedule-teacher-note { font-size: 12px; font-weight: 400; margin-top: 2px; }
.schedule-teachers-grid td { vertical-align: top; }
.schedule-teachers-grid select[multiple] { min-width: 130px; }
.schedule-teachers-grid th, .schedule-teachers-grid td { padding-inline: 8px; }
/* «Стабильность и спрос»: три поля в одну строку, поле занимает 60 % своей колонки —
   подсказки под полями длинные, и без этого каждое поле растягивалось на всю подпись. */
.schedule-inline-row { align-items: flex-start; }
/* Специфичнее .form-row.wrap label, иначе подпись растягивается по своей подсказке и уходит на вторую строку. */
.form-row.wrap.schedule-inline-row > label { flex: 1 1 220px; min-width: 0; }
.form-row.wrap.schedule-inline-row > label > input { width: 60%; min-width: 96px; }

/* Выданные сертификаты: код как главный идентификатор, карточка с действиями. */
.certificate-code { font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; letter-spacing: .06em; }
.certificate-code--large { font-size: 26px; letter-spacing: .14em; padding: 4px 12px; }
.certificate-code-button { background: none; border: 0; padding: 0; cursor: pointer; color: var(--brand-ink); font: inherit; text-align: left; }
.certificate-code-button:hover .certificate-code,
.certificate-code-button:focus-visible .certificate-code { text-decoration: underline; }
.certificate-panel-heading { min-width: 0; flex: 1 1 auto; }
.certificate-panel-title { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 6px 0 10px; }
.certificate-panel .inline-alert { margin-top: 14px; }
.certificate-metrics {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    margin: 16px 0 0;
    padding: 0;
}
.certificate-metrics .client-state-metric strong a { color: inherit; text-decoration: none; }
.certificate-metrics .client-state-metric strong a:hover { text-decoration: underline; }
.certificate-panel-actions {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px 16px;
    flex-wrap: wrap;
    margin: 16px 0 0;
    padding: 12px 0;
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
}
.certificate-panel-actions-main { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.certificate-panel-actions .inline,
.certificate-panel-footer .inline { display: inline-block; }
.certificate-panel-footer {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 24px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
}
.certificate-panel-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 20px 32px;
    margin-top: 20px;
}
.certificate-panel-history { margin-top: 20px; }
.certificate-panel-form .form-row { margin-bottom: 12px; }
.certificate-panel-form-actions { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
.certificate-panel-form-actions .muted { flex: 1 1 240px; min-width: 0; font-size: 12.5px; }
@media (max-width: 900px) {
    .certificate-panel-grid { grid-template-columns: 1fr; }
    .certificate-metrics { grid-template-columns: 1fr; }
}
/* Набор кнопок в строке разный: у списанного сертификата нет «Активировать»
   и «Операции». По правому краю «Открыть» и корзина стоят столбиком во всех
   строках, а необязательные кнопки прибавляются слева. */
.certificates-issued-table th.actions-col,
.certificates-issued-table td.row-actions { text-align: right; white-space: nowrap; }

/* Запись на мероприятие: подбор клиента и кнопка в карточке события. */
.push-broadcast-holdout-note { margin: 10px 0 0; color: var(--muted); font-size: 12px; line-height: 1.45; }

/* Рассылки: второй вариант текста, сохранённые аудитории, лимит (доработки этапа 4 «Маркетинга»). */
.push-broadcast-variant { display: grid; gap: 8px; margin-top: 10px; padding-top: 12px; border-top: 1px dashed var(--border); }
.push-broadcast-link-button { padding: 0; border: 0; background: none; color: var(--brand-ink); font: inherit; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.push-broadcast-saved { display: grid; gap: 6px; margin: 0 0 14px; }
.push-broadcast-saved ul { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.push-broadcast-saved li { display: inline-flex; align-items: center; gap: 2px; padding: 3px 4px 3px 10px; border: 1px solid var(--border); border-radius: 999px; background: var(--surface-raised); font-size: 12.5px; }
.push-broadcast-saved a { color: var(--ink); text-decoration: none; }
.push-broadcast-saved a:hover { text-decoration: underline; }
.push-broadcast-saved button { width: 22px; height: 22px; border: 0; border-radius: 50%; background: none; color: var(--muted); cursor: pointer; }
.push-broadcast-saved button:hover { background: var(--surface-2); color: var(--danger); }
.push-broadcast-save-audience { display: grid; gap: 8px; margin-top: 10px; }

/* Опрос клиентов: список во вкладке «Отзывы и опросы», конструктор в окне
   и страница итогов (она же на классах карточки кампании). */
.survey-table { width: 100%; }
.survey-table td { padding-top: 9px; padding-bottom: 9px; vertical-align: top; }
.survey-period, .survey-nowrap { white-space: nowrap; }
.survey-row-warning { margin-top: 3px; color: var(--warn); font-size: 12px; }

.survey-question-builder { display: grid; gap: 12px; min-width: 0; }
.survey-question-list { display: grid; min-width: 0; }
.survey-question {
    display: grid;
    grid-template-columns: 26px minmax(0, 1fr) auto;
    align-items: start;
    gap: 12px;
    padding: 14px 0;
    border-top: 1px solid var(--border);
}
.survey-question:first-child { padding-top: 0; border-top: 0; }
.survey-question-number {
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    margin-top: 22px;
    border-radius: 50%;
    background: var(--surface-2);
    color: var(--muted);
    font-size: 12px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.survey-form > .promo-form-sections { padding-top: 14px; }
/* Вопросам нужна вся ширина окна: заголовок раздела — сверху, а не слева. */
.promo-form-section.survey-form-section--stacked { grid-template-columns: minmax(0, 1fr); gap: 14px; }
.survey-question-fields {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr);
    gap: 10px 12px;
    min-width: 0;
}
.survey-question-fields > label { min-width: 0; }
.survey-question-fields input,
.survey-question-fields select,
.survey-question-fields textarea { width: 100%; min-width: 0; }
.survey-question-wide { grid-column: 1 / -1; }
.survey-question-tools { display: grid; gap: 6px; padding-top: 22px; }
.survey-question-up svg { transform: rotate(180deg); }
.survey-question-add { justify-self: start; }

.survey-report .survey-freshness { margin: -14px 0 12px; font-size: 12px; }
.survey-report .survey-kpis { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.survey-distribution {
    display: flex;
    gap: 2px;
    min-width: 180px;
    height: 10px;
    overflow: hidden;
    border-radius: 999px;
    background: var(--surface-2);
}
.survey-distribution-part { flex: 1 1 0; min-width: 4px; }
.survey-distribution-part--1 { background: var(--danger); }
.survey-distribution-part--2 { background: color-mix(in oklab, var(--danger) 55%, var(--card)); }
.survey-distribution-part--3 { background: color-mix(in oklab, var(--muted) 35%, var(--card)); }
.survey-distribution-part--4 { background: color-mix(in oklab, var(--ok) 55%, var(--card)); }
.survey-distribution-part--5 { background: var(--ok); }
.survey-distribution-legend { display: flex; flex-wrap: wrap; gap: 4px 14px; margin: 10px 0 0; font-size: 11px; }
.survey-distribution-legend span { display: inline-flex; align-items: center; gap: 5px; }
.survey-distribution-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; }
.survey-average--low, .survey-score--low { color: var(--danger); }
.survey-score { font-weight: 650; font-variant-numeric: tabular-nums; }
.survey-finale-list { display: grid; gap: 0; margin: 0; }
.survey-finale-list > div { display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; border-top: 1px solid var(--border); }
.survey-finale-list > div:first-child { border-top: 0; }
.survey-finale-list dt { color: var(--muted); font-size: 12.5px; }
.survey-finale-list dd { margin: 0; font-weight: 700; font-variant-numeric: tabular-nums; }
.survey-panel-note { margin: 10px 0 0; color: var(--warn); font-size: 12px; line-height: 1.45; }
.survey-choice-list { display: grid; gap: 9px; margin: 0; padding: 0; list-style: none; }
.survey-choice-list li {
    display: grid;
    grid-template-columns: minmax(120px, 190px) minmax(0, 1fr) auto;
    align-items: center;
    gap: 12px;
    font-size: 12.5px;
}
.survey-choice-bar { height: 8px; overflow: hidden; border-radius: 999px; background: var(--surface-2); }
.survey-choice-bar i { display: block; height: 100%; border-radius: inherit; background: var(--brand); }
.survey-choice-value { min-width: 64px; text-align: right; font-weight: 650; font-variant-numeric: tabular-nums; }
.survey-report .survey-nps-breakdown { grid-template-columns: repeat(3, minmax(0, 1fr)); margin-bottom: 0; }
.survey-views { display: flex; flex-wrap: wrap; gap: 6px; }
.survey-report .mk-table.survey-responses-table tbody td,
.survey-report .mk-table.survey-responses-table tbody th { vertical-align: top; }
.survey-responses-table tbody th { white-space: nowrap; }
/* Заголовки критериев переносятся: иначе лента уходит в горизонтальную прокрутку. */
.survey-report .survey-responses-table thead th,
.survey-report .survey-responses-table thead th.num { white-space: normal; }
.survey-report .survey-responses-table thead th.num { width: 84px; }
.survey-responses-table tr:target { background: var(--brand-tint); }
.survey-comment { min-width: 180px; max-width: 380px; overflow-wrap: anywhere; }
.survey-next { display: grid; justify-items: start; gap: 3px; margin-top: 5px; font-size: 12px; font-weight: 400; }
.survey-link-summary { display: flex; flex-wrap: wrap; gap: 8px 28px; margin: 0 0 12px; }
.survey-link-summary dt { color: var(--muted); font-size: 12px; }
.survey-link-summary dd { margin: 2px 0 0; font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; }
.survey-link-sent { margin-top: 3px; font-size: 11.5px; }
.survey-panel-empty { margin: 0; font-size: 13px; }
.survey-question-summary { display: grid; gap: 8px; margin: 0; padding-left: 20px; font-size: 13px; line-height: 1.45; }
@media (max-width: 560px) {
    .survey-question { grid-template-columns: minmax(0, 1fr); }
    .survey-question-number { display: none; }
    .survey-question-fields { grid-template-columns: minmax(0, 1fr); }
    .survey-question-tools { display: flex; padding-top: 0; }
    .survey-choice-list li { grid-template-columns: minmax(0, 1fr) auto; }
    .survey-choice-bar { grid-column: 1 / -1; grid-row: 2; }
}

/* Страница «Настройки»: группы редких экранов, у каждой строки подпись.
   Ширина колонки задаёт число столбцов сама, без своих точек перелома. */
.settings-hub {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
    gap: 14px;
    align-items: start;
}
.settings-hub-group h2 { margin: 0 0 10px; font-size: 15px; font-weight: 600; }
.settings-hub-links { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; }
.settings-hub-links a {
    display: grid; gap: 2px; margin: 0 -10px; padding: 8px 10px;
    border-radius: var(--radius-sm); color: var(--ink); text-decoration: none;
}
.settings-hub-links a:hover { background: var(--surface-2); }
.settings-hub-links strong { color: var(--brand-ink); font-size: 14px; font-weight: 600; }
.settings-hub-links span { color: var(--muted); font-size: 13px; }
.settings-hub-links small { color: var(--faint); font-size: 12px; }

/* «Аналитика → Путь новых клиентов» (модуль newcomer_funnel): шаги пути, потерянные и переходы по каналам. */
/* Фильтры — одной строкой: две даты, канал, филиал и «Показать». */
.newcomer-filters {
    grid-template-columns: repeat(2, minmax(140px, 160px)) minmax(190px, 240px) minmax(170px, 220px) auto;
    width: fit-content;
    max-width: 100%;
}
.newcomer-filters input[type="date"] { width: 100%; min-width: 0; }
/* Воронка: столбцы на общей базовой линии — длины сравниваются честно, в отличие
   от центрированной «трапеции». Штриховка над столбцом — прошлый шаг, то есть
   сколько отсеялось; между столбцами — сколько дошло с прошлого шага. */
.newcomer-panel--full { grid-column: 1 / -1; }
.newcomer-panel--half { grid-column: span 6; }
.newcomer-funnel {
    display: grid;
    grid-template-columns: repeat(5, minmax(96px, 1fr));
    grid-template-rows: repeat(4, auto);
    grid-auto-flow: column;
    gap: 6px 16px;
    margin: 0;
    padding: 0;
    list-style: none;
    overflow-x: auto;
}
/* Подсетка: шапки, столбцы, числа и «остановились» всех шагов стоят на одних линиях. */
.newcomer-stage { display: grid; grid-row: span 4; grid-template-rows: subgrid; min-width: 0; }
.newcomer-stage-head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 2px 8px; }
.newcomer-stage-label { font-weight: 600; }
.newcomer-stage-rate { color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.newcomer-stage-plot {
    position: relative;
    height: 170px;
    border-bottom: 1px solid var(--border);
    outline-offset: 3px;
}
.newcomer-stage-bar,
.newcomer-stage-drop { position: absolute; left: 0; right: 0; }
.newcomer-stage-bar {
    bottom: 0;
    height: max(2px, var(--share));
    border-radius: 4px 4px 0 0;
    background: var(--analytics-0);
}
/* Отсеялись: от верха столбца (с зазором 2px) до высоты прошлого шага. */
.newcomer-stage-drop {
    bottom: calc(var(--share) + 2px);
    height: max(0px, calc(var(--previous-share) - var(--share) - 2px));
    border-radius: 4px 4px 0 0;
    background: repeating-linear-gradient(
        135deg,
        color-mix(in srgb, var(--analytics-0) 28%, transparent) 0 2px,
        transparent 2px 6px
    );
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--analytics-0) 30%, transparent);
}
.newcomer-stage-tip {
    position: absolute;
    top: 6px;
    left: 6px;
    z-index: 2;
    display: grid;
    gap: 2px;
    width: max-content;
    max-width: 240px;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card);
    box-shadow: var(--lift);
    color: var(--ink);
    font-size: 12.5px;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur) ease;
}
.newcomer-stage:last-child .newcomer-stage-tip { left: auto; right: 6px; }
.newcomer-stage-tip span { color: var(--muted); }
.newcomer-stage-plot:hover .newcomer-stage-tip,
.newcomer-stage-plot:focus-visible .newcomer-stage-tip { opacity: 1; }
.newcomer-stage-plot:hover .newcomer-stage-bar { filter: brightness(1.08); }
.newcomer-stage-value { display: flex; align-items: baseline; gap: 8px; }
.newcomer-stage-value strong { font-size: 20px; font-variant-numeric: tabular-nums; }
.newcomer-stage-value span { color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
.newcomer-stage-value > a { margin-left: auto; font-size: 13px; }
.newcomer-stage-lost { display: grid; gap: 2px; margin: 0; color: var(--muted); font-size: 12.5px; }
@media (max-width: 1100px) { .newcomer-panel--half { grid-column: 1 / -1; } }
@media (max-width: 760px) {
    .newcomer-filters { grid-template-columns: repeat(2, minmax(0, 1fr)); width: auto; }
    .newcomer-funnel { display: flex; flex-direction: column; gap: 20px; overflow: visible; }
    .newcomer-stage { grid-template-rows: auto 24px auto auto; gap: 6px; }
    .newcomer-stage-head { align-items: baseline; }
    .newcomer-stage-rate { white-space: normal; }
    .newcomer-stage-plot { height: 24px; border: 0; }
    .newcomer-stage-bar { width: var(--share); height: 100%; right: auto; border-radius: 3px; }
    .newcomer-stage-drop { left: var(--share); right: auto; bottom: 0; width: max(0px, calc(var(--previous-share) - var(--share))); height: 100%; border-radius: 0 3px 3px 0; }
    .newcomer-stage-tip { top: auto; bottom: calc(100% + 6px); max-width: calc(100% - 12px); }
    .newcomer-stage-value > a,
    .newcomer-stage-lost > a { min-height: 36px; display: inline-flex; align-items: center; }
}
@media (prefers-reduced-motion: reduce) { .newcomer-stage-tip { transition: none; } }
.newcomer-note { margin: 14px 0 0; font-size: 13px; }
.newcomer-list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.newcomer-list li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; }
.newcomer-list span { flex: 1 1 auto; }
.newcomer-list a { font-size: 13px; }
.newcomer-table { width: 100%; }
.newcomer-table td.num { padding-top: 6px; padding-bottom: 6px; line-height: 1.25; }
/* Доля — отдельной строкой под числом людей: «211 51 %» читалось как «21151 %». */
.newcomer-table small { display: block; color: var(--muted); font-size: 12px; font-weight: 400; }
.newcomer-table .metric-bad small { color: var(--err); }
.newcomer-total th, .newcomer-total td { font-weight: 600; border-top: 1px solid var(--border); }
.clients-funnel-notice {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 16px;
    margin: 0 0 12px; padding: 10px 14px;
    border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2);
}
.clients-funnel-notice span { flex: 1 1 auto; }
/* Шапка воронки: описание во всю ширину рядом с кнопкой, без узкой колонки. */
.newcomer-heading > div:first-child { flex: 1 1 auto; min-width: 0; max-width: none; }
.newcomer-heading-actions { display: flex; flex: 0 0 auto; align-items: center; gap: 12px; }
.analytics-container .newcomer-panel--full .analytics-panel-heading > div,
.analytics-container .newcomer-panel--half .analytics-panel-heading > div { flex: 1 1 auto; }
.analytics-container .newcomer-panel--full .analytics-panel-heading p,
.analytics-container .newcomer-panel--half .analytics-panel-heading p { max-width: none; }
/* Окно «Сроки потери клиента»: подпись слева, число справа. */
.newcomer-settings-form { display: grid; gap: 10px; margin: 12px 0 0; }
.newcomer-settings-form label { display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 16px; }
.newcomer-settings-form label > span { flex: 1 1 auto; text-align: left; }
.newcomer-settings-form input { width: 90px; }
@media (max-width: 760px) {
    .newcomer-heading-actions { flex-wrap: wrap; }
}
.task-card-sent-list { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; font-size: 13px; }
.task-card-sent-list time { color: var(--muted); }
.financial-newcomers-steps { display: flex; flex-wrap: wrap; gap: 4px 8px; margin: 0; color: var(--muted); }
.financial-newcomers-steps b { color: var(--ink); }
/* Стойка «Приём QR»: раскладка, цвета и формы — токены кабинета. */
.qr-desk-last { display: flex; align-items: baseline; gap: 12px; margin: 0 0 16px; }
.qr-desk-last-time { font-weight: 800; }
.qr-desk-journal h2 { font-size: 16px; margin: 0 0 10px; }
.qr-desk-table .qr-desk-col-time { width: 72px; }
.qr-desk-table .qr-desk-col-client { width: 210px; }
.qr-desk-table .qr-desk-col-class { width: 250px; }
.qr-desk-table .qr-desk-col-actions { position: relative; width: 210px; }
.qr-desk-result { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.qr-desk-result .muted { font-size: 13px; }
.qr-desk { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
.qr-desk > * { margin: 0; }
.qr-desk-devices { margin: 0 0 20px; }
.qr-desk-devices h2 { font-size: 16px; margin: 0 0 10px; }
.qr-desk-pair-result { display: grid; gap: 14px; }
.qr-desk-pair-result p { margin: 0; }
.qr-desk-command { display: grid; gap: 6px; justify-items: start; }
.qr-desk-command h3 { font-size: 14px; margin: 0; }
.qr-desk-command-text {
    display: block;
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    font-size: 12px;
    line-height: 1.5;
    overflow-wrap: anywhere;
    user-select: all;
}

/* Справочник «Папки диалогов». */
.communication-folders-hint { margin: 0 0 12px; }
.folder-row-name { display: inline-flex; align-items: center; gap: 8px; }
.folder-row-name svg { width: 18px; height: 18px; flex: none; fill: none; stroke: var(--muted); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
