/* 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, а не обход файла.

       Тон при этом не менялся: --brand это тот же #2d7d61, вшитый в
       favicon.svg, pwa-icon.svg, манифест и <meta theme-color>.
       ------------------------------------------------------------------ */

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

       Графит, а не зелёный. Зелёный в кабинете означал одновременно «главное
       действие» и «сделано»; на строке, где «Сохранить» стоит рядом с
       «Оплачено», цвет не помогал различить их. Теперь зелёный остался ровно
       значением (--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%);
    --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;

    /* 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;

    /* Направления в расписании: восьмёрка, разведённая по кругу с шагом 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° */

    /* Сегмент и ИИ-агент: две несигнальные идентичности со своим тоном. */
    --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. Поэтому тёмная тема, которая
   переопределяет палитру ниже, получает их без второго набора правил.

   Осторожно с --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; }
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: stretch; flex: 0 0 250px; width: 250px;
    min-height: 100dvh; 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;
}
.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-name { display: block; font-weight: 700; font-size: 20px; line-height: 1; }
.brand-sub { display: block; margin-top: 3px; color: var(--faint); font-size: 11px; }
.brand.big { font-size: 26px; color: var(--logo); }
.sidenav { display: flex; flex-direction: column; gap: 2px; padding-bottom: 12px; }
.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: 0 16px 36px rgb(0 0 0 / 38%);
}
.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 {
        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-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); }
    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;
    align-items: stretch;
    gap: 6px;
    min-width: 0;
    margin-top: auto;
}
.sidebar-account {
    display: flex; flex: 1 1 auto; align-items: center; gap: 9px; 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; flex: 0 0 28px;
    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: grid; min-width: 0; gap: 3px; line-height: 1; }
.sidebar-account-name {
    max-width: 172px; overflow: hidden; text-overflow: ellipsis;
    font-size: 14px; font-weight: 700;
}
.sidebar-account-role { color: var(--nav-section); font-size: 12px; }
/* Бургер и затемнение нужны только на узких экранах. */
.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-popover[hidden] { display: none; }
.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__content[hidden] { display: 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;
    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); }
.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%; }
.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; }
.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; }
.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.leads-container,
.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;
}
.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.teacher-payroll-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-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 — карточки в одном ряду обрывались на трёх разных
   высотах, потому что у «Расходов» есть переключатель разбивки, а у «Прибыли»
   одна строка. Растяжка выравнивает нижнюю кромку ряда; содержимое карточки
   и так прижато к верху. */
.dashboard-cards { grid-template-columns: repeat(3, minmax(360px, 1fr)); }
.dashboard-title-form {
    margin: 0 0 16px;
}
.dashboard-freshness {
    margin: -8px 0 16px;
    font-size: 13px;
}
.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; }
.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-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; cursor: pointer; }
.roster-month-day:hover { background: var(--brand-tint); }
.roster-month-day.empty { cursor: default; background: var(--surface-2); }
.roster-month-day.today { box-shadow: inset 0 0 0 2px var(--marker); }
.roster-month-day.has-shift { background: var(--roster-admin-bg, var(--brand-tint)); box-shadow: inset 4px 0 0 var(--roster-admin-accent, var(--brand)); }
.roster-month-day.has-shift:hover { background: color-mix(in srgb, var(--roster-admin-bg) 86%, var(--ink)); }
.roster-month-day.admin-color-0 { --roster-admin-bg: var(--admin-0-bg); --roster-admin-accent: var(--admin-0-accent); }
.roster-month-day.admin-color-1 { --roster-admin-bg: var(--admin-1-bg); --roster-admin-accent: var(--admin-1-accent); }
.roster-month-day.admin-color-2 { --roster-admin-bg: var(--admin-2-bg); --roster-admin-accent: var(--admin-2-accent); }
.roster-month-day.admin-color-3 { --roster-admin-bg: var(--admin-3-bg); --roster-admin-accent: var(--admin-3-accent); }
.roster-month-day.admin-color-4 { --roster-admin-bg: var(--admin-4-bg); --roster-admin-accent: var(--admin-4-accent); }
.roster-month-day.admin-color-5 { --roster-admin-bg: var(--admin-5-bg); --roster-admin-accent: var(--admin-5-accent); }
.roster-month-day.admin-color-6 { --roster-admin-bg: var(--admin-6-bg); --roster-admin-accent: var(--admin-6-accent); }
.roster-month-day.admin-color-7 { --roster-admin-bg: var(--admin-7-bg); --roster-admin-accent: var(--admin-7-accent); }
.roster-month-day.admin-color-8 { --roster-admin-bg: var(--admin-8-bg); --roster-admin-accent: var(--admin-8-accent); }
.roster-month-day.admin-color-9 { --roster-admin-bg: var(--admin-9-bg); --roster-admin-accent: var(--admin-9-accent); }
.roster-assignment-modal[open] { inset: 88px auto auto 262px; margin: 0; }
.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; }
/* Текст метки — токен, а не литерал white: в тёмной теме сама метка светлая,
   и белая цифра на ней читалась бы как пустой кружок. */
.roster-month-day.today .roster-date-number { background: var(--marker); color: var(--on-marker); }
@media (max-width: 900px) { .roster-assignment-modal[open] { inset: 72px 12px auto 12px; margin: 0; } }
@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(92px,1fr)); } .roster-month-day { min-height: 96px; padding: 7px; } }

.dashboard-title {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin: 0;
}
.dashboard-month-link {
    padding: 2px 0;
    border-bottom: 1px dashed var(--brand);
    color: var(--brand-ink);
    font-size: 22px;
    font-weight: 700;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
}
.dashboard-month-picker {
    position: relative;
    display: inline-flex;
    align-items: center;
}
.dashboard-month-picker:hover .dashboard-month-link { color: var(--brand); }
.dashboard-month-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    opacity: 0;
    cursor: pointer;
}
.dashboard-month-input::-webkit-calendar-picker-indicator {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    cursor: pointer;
}
.dashboard-month-arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: 1px solid var(--border);
    border-radius: 50%;
    background: var(--card);
    color: var(--brand-ink);
    font-size: 24px;
    font-weight: 700;
    line-height: 1;
    text-decoration: none;
}
.dashboard-month-arrow:hover {
    background: var(--hover);
    border-color: var(--border);
}
.dashboard-month-arrow.is-disabled {
    background: var(--surface-2);
    color: var(--faint);
    pointer-events: none;
}
.dashboard-card-revenue { order: 1; }
.dashboard-card-expenses { order: 2; }
.dashboard-card-profit { order: 3; }
.dashboard-card-passes { order: 4; }
.dashboard-card-average { order: 5; }
.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; }
.breakdown-section-label { margin-top: 10px; font-weight: 600; }
.expense-category-details { margin-top: 12px; }
.expense-category-details > summary {
    display: inline-flex; align-items: center; gap: 7px; list-style: none;
    background: var(--card); color: var(--brand-ink); font-weight: 700;
}
.expense-category-details > summary::-webkit-details-marker { display: none; }
.expense-category-details > summary::after {
    content: "\25BE"; font-size: 12px; line-height: 1; transition: transform .16s ease;
}
.expense-category-details[open] > summary::after { transform: rotate(180deg); }
.expense-category-details[open] > summary { background: var(--selected); }
.expense-category-breakdown { margin-top: 10px; }
.expense-category-breakdown .breakdown-row { align-items: flex-start; }
.expense-category-breakdown .breakdown-label {
    overflow: visible; text-overflow: clip; white-space: normal; overflow-wrap: anywhere; line-height: 1.35;
}
.expense-category-breakdown .breakdown-value { flex: 0 0 auto; white-space: nowrap; }
.revenue-forecast { margin-top: -2px; font-weight: 600; }
.card-value-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 6px 0; }
.card-value-row .card-value { margin: 0; }
.revenue-total-row { justify-content: space-between; }
.revenue-total-row .metric-deltas { justify-content: flex-end; }
.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); }
.card-breakdown { margin-top: 10px; display: grid; gap: 6px; }
.revenue-breakdown { padding-top: 8px; border-top: 1px solid var(--border); }
.branch-breakdown-row {
    display: grid; gap: 5px; font-size: 13px; color: var(--muted);
}
.branch-breakdown-row + .branch-breakdown-row { padding-top: 8px; border-top: 1px solid var(--surface-2); }
.branch-breakdown-metrics { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.branch-deltas { justify-content: flex-end; flex-wrap: nowrap; }
.branch-deltas .metric-delta { min-height: 22px; padding: 2px 7px; font-size: 11.5px; white-space: nowrap; }
.breakdown-row {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    font-size: 13px; color: var(--muted);
}
.breakdown-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.breakdown-value { color: var(--ink); font-weight: 700; font-variant-numeric: tabular-nums; }

@media (max-width: 1399px) {
    .dashboard-cards { grid-template-columns: repeat(2, minmax(300px, 1fr)); }
}

@media (max-width: 640px) {
    .dashboard-cards { grid-template-columns: 1fr; }
}

/* Forms */
.form-card, .filterbar {
    background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-md);
    padding: 16px 18px; margin-bottom: 16px; box-shadow: var(--lift);
}
/* Панель фильтров — не форма, а полоса инструментов над списком, и поля у неё
   ниже, чем у карточки формы. */
.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-portal-filter .filter-actions { flex: 0 0 auto; }
.teacher-portal-header { margin-bottom: 10px; }
.teacher-portal-header p { margin: 4px 0 0; }
.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; }

/* Выбор цвета направления. Свободное поле hex заменено палитрой расписания:
   восемь образцов плюс «Авто». Образец берётся из --sched-N-bg, поэтому
   форма и доска не могут разъехаться. */
.direction-color { min-width: 0; margin: 0; padding: 0; border: 0; }
.direction-color > legend {
    padding: 0 0 4px;
    color: var(--muted);
    font-size: 13px;
}
.direction-color-row { display: flex; flex-wrap: wrap; gap: 6px; }
.direction-color-choice { display: inline-flex; cursor: pointer; }
.direction-color-choice input {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px;
    clip-path: inset(50%);
}
.direction-color-swatch {
    display: block;
    width: 30px; height: 30px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
/* «Авто» рисуется диагональю, а не пустотой: пустой квадрат в ряду цветов
   читается как «белый», а не как «цвет назначит система». */
.direction-color-choice--auto .direction-color-swatch {
    background:
        linear-gradient(to top right,
            transparent calc(50% - 1px), var(--border) calc(50% - 1px),
            var(--border) calc(50% + 1px), transparent calc(50% + 1px)),
        var(--surface-2);
}
.direction-color-choice:hover .direction-color-swatch { border-color: var(--brand-border-strong); }
.direction-color-choice input:checked + .direction-color-swatch {
    border-color: var(--brand);
    box-shadow: inset 0 0 0 2px var(--card);
}
.direction-color-choice input:focus-visible + .direction-color-swatch {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
}
/* Подпись держит выбор доступным без наведения мышью и озвучивается
   скринридером; на экране её заменяет сам образец. */
.direction-color-label {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
.direction-color-legacy {
    display: inline-flex; align-items: center; gap: 7px;
    margin-top: 7px;
    color: var(--muted);
    font-size: 12.5px;
}
@media (pointer: coarse) {
    .direction-color-swatch { width: 36px; height: 36px; }
}
.shift-form-section {
    padding: 12px;
    border: 1px solid var(--brand-border);
    border-radius: var(--radius-sm);
    background: var(--brand-tint);
}
.shift-card-break { flex-basis: 100%; height: 0; }
label { display: flex; flex-direction: column; font-size: 13px; color: var(--muted); gap: 4px; }
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; padding: 0 12px; border: 1px solid var(--border);
    border-radius: var(--radius-sm); background: var(--card); color: var(--ink); min-width: 120px;
    font-family: inherit;
}
/* Поиск — отдельная интерактивная поверхность. На серых панелях он остаётся
   белым в светлой теме и приподнятым в тёмной; все модули меняют его одним
   токеном вместо локальных 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 { justify-content: flex-end; 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: 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);
}
.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-modal { width: min(520px, calc(100vw - 36px)); }
.shift-alert-message { margin: 0 0 14px; color: var(--ink); font-weight: 600; }
.shift-alert-modal .actions[hidden] { display: none !important; }
.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 {
    width: min(980px, calc(100vw - 36px)); max-height: calc(100dvh - 48px);
    padding: 0; border: 0; border-radius: var(--radius-md);
    background: var(--card); color: var(--ink);
    box-shadow: 0 24px 70px rgba(30, 42, 35, .22);
}
/* Затемнение вынесено в токен: тот же цвет задавали три подложки — диалога,
   выдвижной карточки и поиска по разделам — тремя разными числами. */
.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-pass-sale-dialog { width: min(640px, calc(100vw - 36px)); }
.client-booking-dialog { width: min(920px, calc(100vw - 36px)); }
.client-balance-dialog { width: min(540px, calc(100vw - 36px)); }
.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 { justify-content: flex-end; 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 { justify-content: flex-end; 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-dialog { width: min(560px, calc(100vw - 36px)); }
.class-booking-form { display: grid; gap: 14px; }
.class-booking-form .modal-header { margin-bottom: 0; }
.class-booking-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 { color: var(--ink); font-size: 16px; font-weight: 650; }
.class-booking-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-picker { display: grid; gap: 7px; min-width: 0; }
.class-booking-picker > label { color: var(--muted); font-size: 13px; }
.class-booking-picker input[type="search"] { width: 100%; min-width: 0; }
/* Список стоит в потоке и раздвигает диалог. Всплывающим он быть не может:
   у .modal стоит overflow: auto, и абсолютно позиционированный список
   обрезается нижней границей окна — видно первые две-три строки из десяти. */
.class-booking-picker .client-search-results button.is-active { background: var(--surface-2); }
.class-booking-actions { justify-content: flex-end; margin-top: 0; }
.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; }
/* 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 { justify-content: flex-end; 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--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); }

.teacher-payroll-summary {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 0 0 18px;
}
.teacher-payroll-summary .stat-card {
    display: inline-flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    min-height: 44px;
    flex: 1 1 190px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
}
.teacher-payroll-summary .stat-card span {
    color: var(--muted);
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
}
.teacher-payroll-summary .stat-card strong {
    font-size: 18px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.teacher-payroll-lines-wrap {
    margin-bottom: 24px;
}
.teacher-payroll-lines {
    min-width: 1180px;
}
.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 > h2 { margin-top: 0; }
.payroll-premium-section > .muted { margin-top: 0; }
.payroll-table .premium-col { width: 220px; min-width: 220px; }
.premium-cell {
    display: flex; align-items: baseline; justify-content: flex-end; gap: 4px;
    white-space: nowrap;
}
.premium-value { font-weight: 500; }
.premium-breakdown { margin: 0; text-align: left; font-weight: 400; }
.premium-breakdown__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 { color: var(--ink); }
.premium-breakdown__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__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 { min-height: 44px; }
}
.payroll-adjustment-modal {
    width: min(760px, calc(100vw - 36px));
}
.teacher-payroll-adjustment-modal {
    width: min(1080px, calc(100vw - 36px));
}
.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) {
    .teacher-payroll-summary .stat-card {
        flex-basis: 100%;
    }
    .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;
    font-size: 11px;
}
.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;
    align-items: center;
    justify-content: center;
    min-height: 48px;
    padding: 8px;
    border-right: 1px solid var(--border);
    background: var(--card);
    color: var(--ink);
    font-size: 12px;
    font-weight: 700;
}
.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-label {
    align-items: flex-start;
    min-height: 72px;
    padding-top: 12px;
    color: var(--muted);
    text-align: center;
}
.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 {
    position: relative;
    height: calc(var(--timeline-duration) * var(--timeline-minute));
    min-height: 84px;
}
.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 в светлой теме и 5,9: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: rgba(0, 0, 0, .08);
    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-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,
        rgba(0, 0, 0, .1) 0,
        rgba(0, 0, 0, .1) 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%; }
.expense-modal { width: min(1120px, calc(100vw - 36px)); }
.expense-modal-form .form-row > label,
.expense-page-form .form-row > label {
    flex: 1 1 150px;
    min-width: 140px;
}
.expense-modal-form .form-row > label.wide,
.expense-page-form .form-row > label.wide {
    flex-basis: 100%;
}
.expense-modal-form input,
.expense-modal-form select,
.expense-page-form input,
.expense-page-form select {
    width: 100%;
    min-width: 0;
}
.expense-money-row {
    flex-wrap: nowrap;
    align-items: flex-end;
}
.expense-money-row > label {
    min-width: 0;
}
.expense-money-row > .expense-category-field {
    flex: 2 1 300px;
}
.expense-money-row > label:not(.expense-category-field) {
    flex: 1 1 150px;
}
.expense-modal-form .field-label,
.expense-page-form .field-label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-height: 20px;
}
@media (max-width: 760px) {
    .expense-money-row {
        flex-wrap: wrap;
    }
}
.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; }
.leads-container .table-scroll { width: 100%; }
.leads-table { min-width: 1160px; table-layout: fixed; }
.leads-table .message-col { margin-top: 4px; white-space: normal; color: var(--muted); font-size: 12px; }
.lead-table-overdue { color: var(--err); font-weight: 700; }
.lead-funnel { display: flex; flex-wrap: wrap; gap: 5px; }
.lead-funnel span {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 2px 6px;
    font-size: 12px;
    color: var(--muted);
    background: var(--card);
}
.lead-funnel span.done { background: var(--ok-bg); border-color: var(--ok-border); color: var(--ok-ink); font-weight: 700; }
.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; max-width: 46ch; }
/* Заливки здесь больше нет. Шапка теперь тоже --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: 18px; margin-top: 20px; }
.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(2, minmax(0, 1fr));
    gap: 8px;
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}
.push-broadcast-options legend {
    grid-column: 1 / -1;
    margin-bottom: 7px;
    color: var(--ink);
    font-weight: 700;
}
.push-broadcast-choice {
    display: grid;
    grid-template-columns: 18px minmax(0, 1fr);
    align-items: start;
    column-gap: 10px;
    min-width: 0;
    padding: 12px;
    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-picker[hidden] { display: none; }
.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-md);
}
.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-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 {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
    font-size: 12px;
}
.push-broadcast-exclusions strong { color: var(--ink); font-variant-numeric: tabular-nums; }
.push-broadcast-recipients-preview li { display: grid; justify-content: stretch; gap: 1px; }
.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-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 > span {
    display: grid;
    width: 44px;
    height: 44px;
    place-items: center;
    border: 1px solid var(--border);
    border-radius: 50%;
    color: var(--faint);
    font-size: 12px;
    font-weight: 800;
}
.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-summary strong { font-size: 18px; }
}
.freeze-summary {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: 10px;
    margin: 8px 0 14px;
}
.freeze-summary-item {
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.two-column-sections { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; align-items: start; }
.communications-layout { display: grid; grid-template-columns: 360px minmax(0, 1fr); gap: 18px; align-items: start; margin-bottom: 22px; }
.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-meta, .conversation-preview, .conversation-time { 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; }
.conversation-links { display: flex; gap: 10px; margin-top: 6px; }
.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; }
.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; }
/* One control row instead of three: search, views, metrics. */
.chat-controls { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 9px 11px; margin-bottom: 10px; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-md); }
.chat-search { flex: 1 1 240px; min-width: 190px; }
.chat-search input { width: 100%; }
.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: 0 1px 2px rgb(28 52 38 / 8%); }
.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-channels { display: flex; gap: 4px; overflow-x: auto; padding-bottom: 2px; margin-bottom: 12px; }
.chat-channels a { display: inline-flex; align-items: center; gap: 7px; padding: 7px 12px; border: 1px solid var(--border); border-radius: 999px; background: var(--card); color: var(--muted); text-decoration: none; font-size: 13px; white-space: nowrap; }
.chat-channels a.active { border-color: var(--brand); background: var(--selected); color: var(--ink); font-weight: 700; }
.chat-channels .glyph { font-size: 14px; line-height: 1; }
.chat-channels .n { font-size: 12px; color: var(--faint); font-variant-numeric: tabular-nums; }
/* Red counts unanswered chats for the studio; blue counts messages this administrator has not read. */
.chat-channels i { min-width: 17px; padding: 1px 5px; border-radius: 999px; background: var(--danger); color: var(--on-brand); font: 700 10px/1.5 inherit; text-align: center; font-variant-numeric: tabular-nums; }
.chat-channels i.unread { background: var(--info); }
.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 section { 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; }
.conversation-list-heading { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 9px 11px; border-bottom: 1px solid var(--border); }
.conversation-list-heading span { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.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-pager[hidden] { display: none; }
.conversation-list-page { min-width: 42px; color: var(--muted); font-size: 12px; font-weight: 700; text-align: center; font-variant-numeric: tabular-nums; }
.chat-status-button { border: 0; background: none; padding: 2px 4px; font-size: 13px; font-weight: 700; color: var(--ink); cursor: pointer; }
.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: 0 12px 28px rgb(28 52 38 / 14%); display: grid; gap: 1px; }
/* `display` here would otherwise beat the browser default for [hidden]. */
.chat-menu[hidden], .composer-templates[hidden] { display: none; }
.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 form { margin: 0; }
.chat-status-picker, .chat-more { position: relative; }
.communications-workspace .conversation-card { grid-template-columns: 38px minmax(0,1fr); padding: 11px 9px; border: 0; border-left: 4px solid transparent; border-radius: 10px; }
.communications-workspace .conversation-card.active { border-left-color: var(--brand); background: var(--brand-tint); }
.communications-workspace .conversation-card.unanswered:not(.active) { background: var(--warn-tint); }
.communications-workspace .conversation-card.unread:not(.active) { background: var(--info-soft); }
.communications-workspace .conversation-card.priority-high { border-left-color: var(--warn); }
.communications-workspace .conversation-card.priority-urgent { border-left-color: var(--danger); }
.conversation-avatar { width: 36px; height: 36px; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; background: var(--brand-strong); color: var(--brand); font-weight: 800; text-transform: uppercase; }
.conversation-avatar.large { width: 44px; height: 44px; font-size: 16px; }
.conversation-card-body { min-width: 0; display: grid; gap: 3px; }
.conversation-card-top { display: flex; justify-content: space-between; gap: 8px; min-width: 0; }
.conversation-card-top b, .conversation-preview { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conversation-card-top time, .conversation-channel { color: var(--muted); font-size: 11px; white-space: nowrap; }
.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; flex-wrap: wrap; gap: 4px; }
.unread-badge { width: fit-content; padding: 3px 8px; border-radius: 7px; background: var(--info-soft); color: var(--info); font-size: 11px; font-weight: 700; }
.snoozed-badge { width: fit-content; padding: 3px 8px; border-radius: 7px; background: var(--surface-2); color: var(--muted); font-size: 11px; font-weight: 700; }
.communications-workspace .conversation-card.snoozed:not(.active) { opacity: .72; }
.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-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 220px; }
.conversation-title > div { min-width: 0; }
.conversation-title h2 { margin: 0; font-size: 17px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conversation-title .muted { font-size: 12px; }
.chat-back { display: none; }
.conversation-header-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.hui-button.mark-closed { border-color: var(--brand-border); background: var(--brand-tint); color: var(--brand-ink); font-weight: 700; }
.hui-button.mark-closed:hover { background: var(--brand-strong); }
/* 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: 18px; margin: 0; 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[hidden] { display: none; }
.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;
}
.thread-jump-count[hidden] { display: none; }
.communications-workspace .message-bubble { width: fit-content; min-width: 0; max-width: min(76%, 680px); height: auto; align-self: start; justify-self: start; box-shadow: 0 1px 2px rgb(28 52 38 / 6%); }
.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 .message-meta b { color: var(--warn); }
.communications-workspace .message-body { overflow-wrap: anywhere; }
.communications-workspace .message-meta { display: flex; justify-content: space-between; gap: 16px; }
.message-time { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.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: 5px; color: var(--muted); font-size: 11px; text-align: right; }
.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-provider-edit { display: inline-block; }
.message-provider-edit > summary { cursor: pointer; color: var(--brand-ink); list-style: none; }
.message-provider-edit > summary::before { content: "·"; margin-right: 5px; color: var(--muted); }
.message-provider-edit > summary::-webkit-details-marker { display: none; }
.message-provider-edit[open] { flex-basis: 100%; width: 100%; margin-top: 4px; }
.message-provider-edit[open] > summary { margin-left: auto; }
.message-provider-edit form { display: grid; justify-items: stretch; gap: 6px; margin-top: 6px; }
.message-provider-edit textarea { width: min(520px, 100%); min-height: 70px; margin-left: auto; resize: vertical; }
.message-provider-edit button { justify-self: end; }
.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.note-mode { background: var(--warn-tint); }
.chat-composer textarea { width: 100%; resize: vertical; min-height: 68px; }
.chat-composer.note-mode textarea { border-color: var(--warn-border); }
.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; padding: 3px; background: var(--surface-2); border-radius: var(--radius-sm); }
.chat-composer.note-mode .composer-mode { background: var(--warn-bg); }
.composer-mode button { padding: 5px 11px; border: 0; border-radius: 6px; background: none; color: var(--muted); font-size: 12.5px; font-weight: 700; cursor: pointer; }
.composer-mode button.active { background: var(--card); color: var(--ink); box-shadow: 0 1px 2px rgb(28 52 38 / 8%); }
.composer-field { position: relative; }
.composer-field textarea { padding-right: 46px; }
.emoji-picker { position: absolute; right: 8px; bottom: 8px; z-index: var(--z-menu); }
.emoji-trigger { display: grid; place-items: center; width: 32px; height: 32px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--muted); font-size: 21px; cursor: pointer; }
.emoji-trigger:hover, .emoji-trigger[aria-expanded="true"] { background: var(--surface-2); color: var(--ink); }
.emoji-menu { position: absolute; right: 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: 0 12px 28px rgb(28 52 38 / 14%); }
.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-footer { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.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); font: 700 10.5px/1.6 inherit; color: var(--muted); }
.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: 0 12px 28px rgb(28 52 38 / 14%); }
.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: 7px; margin: 0; padding: 0; list-style: none; }
.conversation-history { min-width: 0; overflow: hidden; }
.conversation-history li { display: grid; grid-template-columns: 84px 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 .hui-button { padding: 8px 6px; font-size: 12px; white-space: nowrap; }
.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; }
.communication-link-dialog { width: min(680px, calc(100vw - 32px)); }
.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-search input { width: 100%; margin-top: 5px; }
.client-link-results { display: grid; gap: 6px; max-height: 260px; overflow-y: auto; }
.client-link-result { display: grid; gap: 3px; width: 100%; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--card); color: var(--ink); text-align: left; }
.client-link-result:hover, .client-link-result:focus-visible { border-color: var(--brand); background: var(--hover); }
.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[hidden], .client-link-conflicts[hidden] { display: none; }
.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 section { padding: 15px; }
.conversation-assignee form { display: grid; gap: 8px; margin: 0; }
.conversation-assignee label { display: grid; gap: 4px; color: var(--muted); font-size: 12px; }
.conversation-assignee select { width: 100%; }
.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 { max-width: 82ch; margin: -6px 0 18px; font-size: 12.5px; }
.communications-load-table { margin-top: 12px; }
.danger-text { color: var(--danger); font-weight: 700; }
.client-context h3 { margin: 0 0 10px; }
.client-context-person { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.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 b { display: block; line-height: 1.35; }
.client-pass h3 { margin-bottom: 6px; }
.client-pass p { margin: 2px 0 0; font-size: 12px; line-height: 1.35; }
.upcoming-item { display: grid; gap: 2px; padding: 9px 0; border-top: 1px solid var(--border); 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-layout, .two-column-sections { grid-template-columns: 1fr; }
    .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-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-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; }

.app-shell .container.activation-reviews-container { max-width: none; }
.activation-review-table-wrap { width: 100%; }
.activation-review-table { width: 100%; min-width: 1280px; }
.activation-candidates { display: grid; gap: 8px; }
.activation-candidates small { display: block; margin-top: 3px; color: var(--muted); }
.activation-review-actions { display: grid; gap: 10px; }
.activation-review-actions form { display: grid; gap: 7px; }
.activation-review-actions textarea { resize: vertical; }
.groups-table { min-width: 1320px; }
.color-swatch {
    width: 18px;
    height: 18px;
    padding: 0;
    border: 1px solid rgba(31, 42, 38, .18);
    border-radius: 999px;
    background: var(--swatch-color);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .35);
}
.color-swatch.readonly {
    display: inline-block;
    cursor: default;
}
.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; }
.client-pass-client-picker {
    position: relative;
    display: grid;
    flex: 1 1 320px;
    min-width: min(320px, 100%);
    gap: 4px;
}
.client-pass-client-picker > input[type="search"] { width: 100%; min-width: 0; }
.client-pass-client-picker .client-search-results {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    left: 0;
    z-index: var(--z-menu);
}
.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;
    transition: border-color var(--dur) ease, color var(--dur) ease;
}
.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); }
.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; }
.app-communications-tabs { gap: 20px; }
.app-communications-tabs > a { min-height: 38px; padding-top: 7px; padding-bottom: 7px; }
.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: visible;
    overscroll-behavior-inline: contain;
}
.schedule-template-board .crm-schedule-week-grid {
    width: 100%;
    min-width: 0;
}
.schedule-template-board .crm-schedule-week-head,
.schedule-template-board .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-board { overflow-x: auto; }
    .schedule-template-board .crm-schedule-week-grid { min-width: 1050px; }
    .schedule-template-board .crm-schedule-week-head,
    .schedule-template-board .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-end; margin-top: 18px; }
.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 {
    display: flex;
    justify-content: flex-end;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
}
.schedule-template-publish-dialog { width: min(560px, calc(100vw - 36px)); }
.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-actions { justify-content: flex-end; 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-entry-actions,
    .schedule-template-delete-form,
    .schedule-template-publish-actions { align-items: stretch; flex-direction: column-reverse; }
    .schedule-template-entry-actions button,
    .schedule-template-delete-form button,
    .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-section-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 22px;
}
.access-section-nav a {
    display: inline-flex;
    align-items: center;
    min-height: 36px;
    padding: 7px 12px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-raised);
    color: var(--muted);
    font-size: 13px;
    font-weight: 700;
    text-decoration: none;
    transition: background var(--dur) ease, border-color var(--dur) ease, color var(--dur) ease;
}
.access-section-nav a:hover {
    border-color: var(--border);
    background: var(--hover);
    color: var(--ink);
}
.access-settings-form {
    display: grid;
    gap: 28px;
}
.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-actions {
    position: sticky;
    bottom: 12px;
    z-index: 2;
    justify-content: flex-end;
    margin: -4px 0 0;
    padding: 12px;
    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);
}
.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: 1750px; table-layout: auto; }
.passes-table .pass-type-description {
    display: block;
    width: max-content;
    max-width: 320px;
    white-space: normal;
}
.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 {
    max-width: 32ch;
    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,
.promo-renewal-window > label {
    min-width: 0;
}
.promo-form-grid input,
.promo-form-grid select,
.promo-form-grid textarea {
    width: 100%;
    min-width: 0;
}
.promo-form-wide,
.promo-renewal-condition {
    grid-column: 1 / -1;
}
.promo-checkline {
    align-self: end;
    min-height: 42px;
    padding-bottom: 10px;
}
.promo-renewal-condition {
    padding: 16px;
    border-radius: 12px;
    background: var(--surface-2);
}
.promo-renewal-condition > p {
    margin: 6px 0 14px 28px;
    color: var(--muted);
    font-size: 12px;
    line-height: 1.5;
}
.promo-renewal-window {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 190px));
    gap: 12px;
    margin-left: 28px;
}
.promo-card-actions {
    justify-content: flex-end;
    flex-wrap: wrap;
    margin-top: 20px;
}
.promo-card-action {
    width: 120px;
}
.promo-delete-form {
    display: none;
}
@media (max-width: 820px) {
    .promo-form-section {
        grid-template-columns: 1fr;
        gap: 14px;
    }
    .promo-form-section-head p {
        max-width: 65ch;
    }
}
@media (max-width: 560px) {
    .promo-form-grid,
    .promo-renewal-window {
        grid-template-columns: 1fr;
    }
    .promo-renewal-window,
    .promo-renewal-condition > p {
        margin-left: 0;
    }
    .promo-card-actions {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .promo-card-action,
    .promo-card-back {
        width: 100%;
    }
    .promo-delete-action,
    .promo-card-back {
        grid-column: 1 / -1;
    }
}
.certificates-table { width: 100%; min-width: 100%; }
.class-bookings-table { min-width: 1320px; }
.class-queue-table { min-width: 1180px; }
.sales-table { min-width: 1280px; }
.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 { width: 100%; }
.shelf-products-container .filterbar .hui-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
}
.shelf-products-table { width: 100%; min-width: 880px; table-layout: fixed; }
.shelf-products-table td { overflow-wrap: anywhere; vertical-align: top; }
.field-hint {
    display: block;
    margin-top: 4px;
    color: var(--muted);
    font-size: 12px;
}
/* Карточка была центрирована по вертикали. Пока высота была прибита
   числом, это не чувствовалось. Как только высоту стало задавать содержимое,
   центрирование показало себя с худшей стороны: при переключении вкладок
   высота меняется, и у центрированного блока едут оба края сразу — шапка
   уходит из-под курсора вместе с вкладками, по которым только что кликнули.
   Теперь верх прибит к --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: rgba(247, 250, 246, .96);
    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; }
/* Дата, время и место читались 13-м кеглем в --muted и на фоне шапки почти
   пропадали. Это опознавательная строка занятия, а не сноска. */
.class-panel-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0;
    min-width: 0;
    color: var(--ink);
    font-size: 14px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
}
.class-panel-meta > * {
    display: inline-flex;
    align-items: center;
    min-width: 0;
}
.class-panel-meta > * + *::before {
    content: "·";
    flex: 0 0 auto;
    margin: 0 8px;
    color: var(--faint);
}
.class-panel-meta .tag::before { content: none; margin: 0; }
.class-panel-meta .tag { margin-left: 10px; }
.client-edit-form { margin-bottom: 18px; }
.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; }
.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,
.class-edit-form-header h2 {
    margin: 0 0 12px;
    font-size: 18px;
}
.class-edit-form-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 14px;
}
.class-edit-form-header h2 { margin-bottom: 3px; }
.class-edit-form-header p {
    margin: 0;
    color: var(--muted);
    font-size: 12px;
}
.class-form { display: grid; gap: 16px; }
.class-form .plain-fieldset { display: grid; gap: 16px; }
.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-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.05fr .72fr .72fr 1.1fr 1.35fr; }
.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-error[hidden] { display: none; }

/* Ростер занятия: один список вместо «Записано» и «Посетило». Прежняя
   раскладка держала четыре секции с полосами по левому краю и правило 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-person { display: grid; min-width: 0; gap: 1px; }
.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-actions { display: flex; align-items: center; gap: 6px; }
.class-roster-actions form { margin: 0; }
.class-roster-actions button { min-height: 30px; }
.class-roster-actions .class-attendance-delete {
    width: 32px;
    min-width: 32px;
    padding: 0;
}
/* Кнопки отметки стоят в колонке фиксированной ширины: строка с одним
   действием иначе разъезжается относительно строк с двумя, и «Отменить
   запись» перестаёт стоять под собой же на соседней строке. */
.class-roster-mark {
    display: flex;
    justify-content: flex-end;
    gap: 6px;
    min-width: 246px;
}

.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-details {
    margin-top: 4px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--card);
}
.class-edit-details > summary {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 13px 16px;
    color: var(--ink);
    font-size: 15px;
    font-weight: 700;
    cursor: pointer;
    list-style: none;
}
.class-edit-details > summary::-webkit-details-marker { display: none; }
.class-edit-details > summary::before {
    content: "";
    width: 7px;
    height: 7px;
    border-right: 2px solid var(--faint);
    border-bottom: 2px solid var(--faint);
    transform: rotate(-45deg) translate(-1px, 1px);
    transition: transform var(--dur-fast) var(--ease);
}
.class-edit-details[open] > summary::before { transform: rotate(45deg); }
.class-edit-details > summary:focus-visible { outline: 2px solid var(--brand-border-strong); outline-offset: -2px; }
.class-edit-hint { color: var(--muted); font-size: 13px; font-weight: 400; }
.class-edit-body { padding: 0 16px 16px; border-top: 1px solid var(--border); }
.class-edit-details .class-edit-form {
    margin: 0;
    padding: 14px 0 0;
    border: 0;
    background: transparent;
    box-shadow: none;
}
.class-edit-details .class-edit-form-header { display: none; }
@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;
    }
    /* Кнопки уходят на свою строку: раньше ростер был таблицей с
       min-width: 760px и уезжал в горизонтальную прокрутку. */
    .class-roster-row {
        grid-template-columns: minmax(0, 1fr) max-content;
        row-gap: 6px;
    }
    .class-roster-actions { grid-column: 1 / -1; justify-content: flex-start; }
    .class-roster-mark { justify-content: flex-start; min-width: 0; }
    .class-roster-status { min-width: 0; }
    .class-remove-note { text-align: left; }
}
@media (max-width: 560px) {
    .class-form-grid-time,
    .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-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-sticky-note .note-text {
    color: var(--text);
    line-height: 1.5;
    white-space: pre-wrap;
}
.client-delete-form {
    clear: both;
    margin-top: 34px;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}
.client-activity {
    display: block;
    margin-top: 18px;
    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 {
    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; }
#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-title,
.client-profile-contacts,
.client-primary-actions,
.client-consents,
.client-tab-heading {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}
.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-client-actions-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: 0 14px 34px rgb(28 52 38 / 16%);
}
.client-actions-menu[hidden] { display: none; }
.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 { width: min(560px, calc(100vw - 28px)); }
.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 { justify-content: flex-end; 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-tab-panel[hidden],
.client-profile-panel[hidden],
.client-activity[hidden] { display: none !important; }

/* Заметка — единственное на карточке, что написал человек. Тёплая подложка
   остаётся постоянным ориентиром и в заполненном, и в пустом состоянии. */
.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-display[hidden] { display: none; }
.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[hidden] { display: none; }
.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; }
.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);
    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-row div,
.client-task-row > div { display: grid; gap: 3px; }
.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 { display: inline-flex; align-items: center; gap: 6px; }
.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-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-variable-help { padding: 14px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); }
.contract-variable-help h3 { margin: 0 0 6px; }
.contract-variable-list { display: grid; grid-template-columns: max-content minmax(0,1fr); gap: 6px 12px; }
.contract-variable-list code { color: var(--brand-ink); }
.contract-editor-field { display: grid; gap: 7px; min-width: 0; }
.contract-editor-label { color: var(--muted); font-size: 13px; }
.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-table-tools[hidden] { display: none; }
.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-dialog { width: min(440px, calc(100vw - 24px)); }
.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 { margin-top: 0; }
.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-client-actions-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-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: calc(100dvh - 48px); }
.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-details {
    display: grid;
    grid-template-columns: 1.15fr repeat(2, minmax(0, 1fr));
    grid-template-areas:
        "balance start end"
        "freeze-count freeze-days class-type"
        "purchase price price";
    column-gap: 28px;
    margin: 0;
    padding: 2px 0 8px;
}
.client-card-pass-detail {
    min-width: 0;
    padding: 14px 0 13px;
    border-bottom: 1px solid var(--border);
}
.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-detail--balance { grid-area: balance; }
.client-card-pass-detail--balance dd { font-size: 24px; letter-spacing: -.02em; }
.client-card-pass-detail--start { grid-area: start; }
.client-card-pass-detail--end { grid-area: end; }
.client-card-pass-detail--freeze-count { grid-area: freeze-count; }
.client-card-pass-detail--freeze-days { grid-area: freeze-days; }
.client-card-pass-detail--class-type { grid-area: class-type; }
.client-card-pass-detail--purchase { grid-area: purchase; }
.client-card-pass-detail--price { grid-area: price; }
.client-card-pass-actions {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    align-items: stretch;
    gap: 10px;
    margin-top: 10px;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}
.client-card-pass-actions form,
.client-card-pass-actions > button { min-width: 0; margin: 0; }
.client-card-pass-actions form > button,
.client-card-pass-actions > button {
    width: 100%;
    height: 100%;
    min-height: 42px;
    padding-inline: 12px;
    line-height: 1.25;
    white-space: normal;
    text-wrap: balance;
}
.client-card-pass-actions > :only-child {
    justify-self: end;
    width: min(100%, 240px);
}
.client-card-pass-freeze-form {
    margin-top: 18px;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}
.client-card-pass-freeze-form[hidden] { display: none; }
.client-card-pass-freeze-heading {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 14px;
}
.client-card-pass-freeze-heading h2 { margin: 0 0 4px; font-size: 17px; }
.client-card-pass-freeze-heading p { margin: 0; color: var(--muted); font-size: 13px; }
.client-card-pass-freeze-fields {
    display: grid;
    grid-template-columns: minmax(150px, .7fr) minmax(150px, .7fr) minmax(220px, 1.4fr) auto;
    gap: 12px;
    align-items: end;
}
.client-card-pass-freeze-fields label { min-width: 0; }
.client-card-pass-freeze-fields input { width: 100%; min-width: 0; }
.client-card-pass-freeze-fields button { min-height: 42px; white-space: nowrap; }
@media (max-width: 760px) {
    .client-card-pass-details {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-template-areas:
            "balance balance"
            "start end"
            "freeze-count freeze-days"
            "class-type class-type"
            "purchase price";
        column-gap: 18px;
    }
    .client-card-pass-actions {
        grid-auto-flow: row;
        grid-auto-columns: auto;
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .client-card-pass-actions > :only-child { grid-column: 2; }
    .client-card-pass-freeze-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .client-card-pass-freeze-reason,
    .client-card-pass-freeze-fields button { grid-column: 1 / -1; }
}
@media (max-width: 520px) {
    .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; }
.channel-grid { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }
/* Только горизонтальный отступ: высоту строки держит --row-h-sm выше, а
   вертикальный padding поверх height давал ячейку то в 40, то в 54 пикселя
   в зависимости от того, переносится ли текст. */
.compact-grid th, .compact-grid td { padding: 0 12px; }
.external-ids-table { min-width: 820px; }
.external-ids-table code { white-space: nowrap; }
.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-summary { color: var(--muted); font-size: 13px; font-weight: 600; }
.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; }
}
.pager-jump {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0;
}
.pager-jump label {
    flex-direction: row;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    font-weight: 600;
}
.pager-jump input {
    width: 78px;
    min-width: 0;
    padding: 4px 8px;
    font-size: 13px;
}
/* Статусный бейдж.

   Рамки здесь не было, хотя три правила её уже предполагали: .tag.segment и
   тёмные заплатки для .ok и .err задают 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;
}
/* Не var(--ok): зелёный акцент на этой подложке даёт 4,29:1. */
.tag.ok { background: var(--ok-bg); border-color: var(--ok-border); color: var(--ok-ink); }
.tag.warn { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn); }
.tag.err { background: var(--danger-soft); border-color: var(--danger-border); color: var(--err); }
/* Синий тон был только у плашек и подсказок: у бейджа не было способа сказать
   «идёт», не притворяясь предупреждением. */
.tag.info { background: var(--info-soft); border-color: var(--info-border); color: var(--info); }
.hint { cursor: help; color: var(--muted); }
/* Причина недоступного действия. Раньше она жила в title на disabled-кнопке:
   такой элемент не фокусируется, и причина была недостижима и с клавиатуры,
   и скринридером. */
.action-reason { margin: 6px 0 0; color: var(--muted); font-size: 12px; line-height: 1.35; }

.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; align-items: start; }
@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) {
    .two-col { grid-template-columns: 1fr; }
    .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; }
}

/* Постоянное сообщение, которое должно оставаться рядом с данными страницы. */
.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;
}
.inline-alert.success { background: var(--ok-bg); border-color: var(--ok-border); color: var(--ok-ink); }
.inline-alert.danger { background: var(--danger-soft); border-color: var(--danger-border); color: var(--err); }
.inline-alert.warning { background: var(--warn-bg); border-color: var(--warn-border); color: var(--warn); }

/* 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: 0 10px 40px rgb(28 52 38 / 7%);
}
.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: 0 16px 40px rgba(30, 42, 35, .08);
}
.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;
}

/* Embedded BI */
/* The embed fills the whole content column: the main shell becomes a flex
   column pinned to the viewport height, the topbar keeps its natural size and
   the dashboard container grows into the rest. No magic header offset, so the
   iframe always reaches the bottom edge regardless of the topbar height. */
.main-shell:has(.datalens-container) {
    display: flex;
    flex-direction: column;
    height: 100dvh;
    height: 100dvh;
    overflow: hidden;
}
.app-shell .container.datalens-container {
    flex: 1 1 auto;
    width: 100%;
    max-width: none;
    min-height: 0;
    margin: 0;
    padding: 0;
    /* Fallback for browsers without :has() — keeps the embed near full height. */
    height: calc(100dvh - 64px);
    height: calc(100dvh - 64px);
    overflow: hidden;
}
.datalens-shell {
    height: 100%;
    overflow: hidden;
}
.datalens-frame {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
    border-radius: 0;
    /* Дашборд внутри iframe рисует собственную тему; белый холст под ним
       не даёт тёмной вспышке при загрузке. Не тематический цвет. */
    background: #fff;
    overflow: hidden;
}
.code-block {
    overflow-x: auto;
    margin: 10px 0;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.section-block {
    margin-top: 24px;
}
.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;
}

/* Dark theme */
/* .topbar раньше требовала здесь собственный фон — теперь она смешивает
   --surface-2 сама и следует за темой без отдельного правила. */
/* Стрелка списка нарисована в data-URI, а в него не подставляется var().
   Поэтому на тёмной теме тот же рисунок повторяется со своим тоном — иначе
   она осталась бы почти чёрной на тёмном поле. */
/* Бейджи ожидания, опоздания и непрочитанного теперь берут цвет из токенов
   --warn / --danger / --info, у которых есть тёмная пара, поэтому семь
   отдельных заплаток отсюда ушли. Подложке карточки в списке диалогов пара
   всё ещё нужна: светлые тона там подобраны вручную. */
/* На тёмной странице зеленоватое затемнение неразличимо: подложка и фон
   сходятся по светлоте. Отсюда чёрный и заметно плотнее. Переопределяется
   один токен — раньше здесь перечислялись сами подложки, и поиск по разделам
   в этот список не попал, оставаясь на светлом затемнении. */

@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-y: auto;
        overflow-x: hidden;
        overscroll-behavior: contain;
        scrollbar-width: thin;
        transform: translateX(-100%);
        transition: transform .24s var(--ease);
        box-shadow: 0 0 42px rgb(20 32 26 / 22%);
        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: rgb(20 32 26 / 42%);
        opacity: 0;
        pointer-events: none;
        transition: opacity .24s ease;
    }
    .nav-scrim[hidden] { display: block; }
    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; }
    .module-search-trigger span, .module-search-trigger kbd { display: none; }
    .module-search-trigger { width: 38px; padding: 0; justify-content: center; }
    .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; }
    .module-search { margin-top: 6dvh; }
    /* On narrow screens the sidebar stacks on top, so the embed can't own the
       full viewport height — fall back to a fixed share of the screen. */
    .main-shell:has(.datalens-container) {
        display: block;
        height: auto;
        overflow: visible;
    }
    .app-shell .container.datalens-container {
        flex: none;
        height: 78vh;
        height: 78dvh;
        min-height: 520px;
        padding: 0;
    }
}

/* «Мой день» — рабочая очередь задач админа */
.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-sub { color: var(--muted); margin: 4px 0 12px; font-size: 14px; }
.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-filterbar {
    display: flex; align-items: flex-end; flex-wrap: nowrap;
    margin-bottom: 16px; gap: 10px 14px;
}
.myday-filterbar > label:not(.myday-toggle) { flex: 0 1 260px; min-width: 160px; }
.myday-filterbar .filter-actions { flex: 0 0 auto; }
.myday-toggle {
    display: grid; grid-template-columns: 18px minmax(0, 1fr); align-items: center;
    flex: 1 1 430px; min-width: min(100%, 330px); min-height: 40px;
    gap: 8px; padding: 4px 2px; color: var(--ink); cursor: pointer;
}
.myday-toggle input { width: 18px; min-width: 18px; height: 18px; margin: 0; accent-color: var(--brand); }
.myday-toggle-copy { display: flex; min-width: 0; flex-direction: column; gap: 1px; }
.myday-toggle-title { font-size: 13px; font-weight: 700; line-height: 1.35; }
.myday-hint { color: var(--faint); font-size: 12px; line-height: 1.35; }
.myday-pager { margin-bottom: 18px; }

.myday-group { margin-bottom: 26px; }
.myday-group-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; }
.myday-group-head h2 { margin: 0; font-size: 14px; letter-spacing: .04em; text-transform: uppercase; }
.myday-count { font-weight: 700; font-variant-numeric: tabular-nums; }
.myday-overdue .myday-group-head h2, .myday-overdue .myday-count { color: var(--err); }
.myday-today .myday-group-head h2 { color: var(--brand-ink); }
.myday-upcoming .myday-group-head h2, .myday-no_due .myday-group-head h2 { color: var(--muted); }
.myday-note { color: var(--faint); font-size: 12.5px; }

.myday-tasks { display: flex; flex-direction: column; gap: 8px; }
.myday-task {
    display: grid; grid-template-columns: 68px minmax(0, 1fr) auto;
    gap: 4px 14px; align-items: center;
    background: var(--card); border: 1px solid var(--border);
    border-radius: var(--radius-md); padding: 12px 14px;
}
.myday-task:focus { outline: var(--ring-w) solid var(--ring); outline-offset: var(--ring-offset); }
.myday-overdue .myday-task { border-inline-start: 3px solid var(--err); }
.myday-task .t-when { text-align: center; }
.myday-task .t-time { font-weight: 700; font-size: 16px; font-variant-numeric: tabular-nums; }
.myday-task .t-date { color: var(--faint); font-size: 12px; }
.myday-overdue .t-time { color: var(--err); }
.myday-task .t-main { min-width: 0; }
.myday-task .t-title { font-weight: 600; }
.myday-task .t-meta {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    margin-top: 3px; font-size: 13px; color: var(--muted);
}
.myday-task .t-meta a { font-weight: 600; }
.t-tel { text-decoration: none; font-variant-numeric: tabular-nums; white-space: nowrap; }
.t-attempt { font-size: 12px; color: var(--warn); font-weight: 600; }
.myday-chip { font-size: 12px; color: var(--faint); }
.myday-chip.mine { color: var(--brand-ink); font-weight: 600; }
.myday-notes { color: var(--faint); font-size: 12.5px; }
.myday-task .t-actions {
    --myday-action-width: 124px;
    display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: flex-end;
}
.myday-work-form { display: flex; width: var(--myday-action-width); margin: 0; }
.myday-work-action { width: var(--myday-action-width); }
.myday-empty {
    border: 1px dashed var(--border); border-radius: var(--radius-md);
    padding: 16px; text-align: center; color: var(--faint); font-size: 14px;
}

.myday-snooze-group { width: var(--myday-action-width); }
.myday-snooze-default {
    display: flex; flex: 1 1 auto; min-width: 0; margin: 0;
}
.myday-snooze-default > .hui-button {
    width: 100%; min-width: 0;
    border-top-right-radius: 0; border-bottom-right-radius: 0;
}
.myday-snooze-menu { position: relative; flex: 0 0 auto; }
.myday-snooze-menu > summary { list-style: none; cursor: pointer; }
.myday-snooze-menu > summary::-webkit-details-marker { display: none; }
.myday-snooze-menu > summary.hui-button {
    border-left: 0;
    border-top-left-radius: 0; border-bottom-left-radius: 0;
}
.myday-snooze-menu > summary svg { transition: transform var(--dur-fast) var(--ease); }
.myday-snooze-menu[open] > summary svg { transform: rotate(180deg); }
.myday-snooze-menu[open] > summary { background: var(--surface-2); color: var(--ink); }
.myday-snooze-options {
    position: absolute; z-index: var(--z-menu); top: calc(100% + 5px); right: 0;
    min-width: 150px; padding: 4px;
    border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--card);
}
.myday-snooze-options form { margin: 0; }
.myday-snooze-options 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-snooze-options button:hover { background: var(--surface-2); }
.myday-snooze-options button:focus-visible { outline: var(--ring-w) solid var(--ring); outline-offset: -2px; }

.myday-modal-sub { color: var(--muted); font-size: 13px; margin: -6px 0 4px; }
.myday-outcomes { display: flex; flex-direction: column; gap: 6px; }
.myday-outcome {
    display: flex; align-items: center; gap: 10px; cursor: pointer;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    padding: 9px 12px; font-size: 14px;
}
.myday-outcome:hover { background: var(--surface-2); }
.myday-outcome input { accent-color: var(--brand); }
.myday-outcome-hint { margin-left: auto; color: var(--faint); font-size: 12px; text-align: right; }

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

/* Ссылка занимает всю ячейку, а не только надпись: колонка «Статус» шириной в
   сто пикселей давала цель для курсора в двадцать, и промах по ней означал
   клик мимо сортировки. Отрицательные поля возвращают заголовку отступы
   ячейки, съеденные растягиванием. */
.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);
    transition: color var(--dur-fast) ease, background var(--dur-fast) ease;
}
/* Подчёркивание при наведении сдвигало базовую линию подписи на пиксель, и
   шапка «дышала» под курсором. Тон и подложка сообщают то же самое молча. */
.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: 700px) {
    .myday-status-item { flex-basis: 50%; }
    .myday-filterbar { flex-wrap: wrap; }
    .myday-filterbar > label:not(.myday-toggle) { flex: 1 1 100%; }
    .myday-task { grid-template-columns: 56px minmax(0, 1fr); }
    .myday-task .t-actions { grid-column: 1 / -1; justify-content: flex-start; }
}
@media (pointer: coarse) {
    .myday-snooze-options 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,
.client-link-result,
.crm-schedule-modes a,
.roster-month-day,
.modal-close,
.dashboard-month-arrow,
.snooze button,
.myday-outcome,
.sortable-th > a,
.color-swatch,
.lead-kanban-card {
    transition: background var(--dur) ease, border-color var(--dur) ease, color var(--dur) ease, box-shadow var(--dur) ease;
}
.conversation-card:active,
.client-link-result:active,
.roster-month-day:active,
.modal-close:active,
.dashboard-month-arrow: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: 0 6px 18px rgb(28 52 38 / 8%);
}
a.card:active, button.card:active, .card.is-clickable:active { transform: translateY(1px); }

/* HTMX swaps had no feedback whatsoever: the client drawer, the chat badges and
   the activity feed all changed with no sign that anything was loading. */
.htmx-request.htmx-swapping,
.htmx-request:not(form):not(body) {
    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; }

/* Skeletons replace the bare "Загрузка" text while a panel is fetched. */
.skeleton-stack { display: grid; gap: 10px; padding: 18px 20px; }
.skeleton-line {
    height: 13px;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--surface-2) 25%, var(--border) 37%, var(--surface-2) 63%);
    background-size: 400% 100%;
    animation: skeleton-sweep 1.3s ease-in-out infinite;
}
.skeleton-line.wide { width: 100%; }
.skeleton-line.half { width: 52%; }
.skeleton-line.short { width: 30%; }
.skeleton-line.tall { height: 46px; border-radius: var(--radius-md); }
@keyframes skeleton-sweep {
    from { background-position: 100% 50%; }
    to { background-position: 0 50%; }
}

/* ---------------------------------------------------------------------------
   Быстрый переход по разделам.

   Модулей пятьдесят восемь, и единственным способом попасть в нужный был поиск
   глазами по колонке слева. Список берётся из уже отрисованного сайдбара, так
   что права доступа учитываются сами собой.
   --------------------------------------------------------------------------- */
.module-search-trigger {
    display: inline-flex; align-items: center; gap: 8px;
    height: var(--topbar-control-height); padding: 0 10px;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: var(--search-bg); color: var(--muted);
    font: inherit; font-size: 12.5px; font-weight: 700;
    transition: background var(--dur) ease, border-color var(--dur) ease, color var(--dur) ease;
}
.module-search-trigger:hover { background: var(--hover); border-color: var(--border); color: var(--ink); }
.module-search-trigger svg {
    width: 15px; height: 15px; fill: none; stroke: currentColor;
    stroke-width: 2; stroke-linecap: round;
}
.module-search-trigger kbd {
    padding: 1px 5px; border: 1px solid var(--border); border-radius: 4px;
    background: var(--surface-2); color: var(--faint); font: 700 10.5px/1.6 inherit;
}
.module-search {
    width: min(560px, calc(100vw - 32px));
    max-height: min(560px, calc(100dvh - 96px));
    margin: 12dvh auto auto;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--card);
    color: var(--ink);
    box-shadow: 0 28px 74px rgb(20 32 26 / 26%);
    overflow: hidden;
}
.module-search::backdrop { background: var(--scrim); backdrop-filter: blur(2px); }
.module-search-field {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 12px 12px 16px; border-bottom: 1px solid var(--border); background: var(--search-bg);
}
.module-search-field > svg {
    width: 18px; height: 18px; flex: 0 0 18px; fill: none; stroke: var(--faint);
    stroke-width: 2; stroke-linecap: round;
}
.module-search .module-search-field input[type="search"] {
    flex: 1; min-width: 0; border: 0; background: transparent; padding: 4px 0;
    font-size: 16px; color: var(--ink);
}
.module-search .module-search-field input[type="search"]:focus { outline: none; }
/* Свой крестик уже есть — родной от type="search" ставил рядом второй. */
.module-search-field input::-webkit-search-cancel-button { display: none; }
.module-search-results { max-height: 380px; overflow-y: auto; padding: 6px; scrollbar-gutter: stable; }
.module-search-option {
    display: flex; align-items: baseline; gap: 10px; width: 100%;
    padding: 9px 11px; border: 0; border-radius: var(--radius-sm);
    background: none; color: var(--ink); text-align: left; text-decoration: none;
    font: inherit; font-size: 14px;
}
.module-search-option:hover { background: var(--hover); color: var(--ink); }
.module-search-option.active { background: var(--selected); color: var(--ink); font-weight: 700; }
.module-search-option .path { margin-left: auto; color: var(--faint); font-size: 12px; white-space: nowrap; }
.module-search-option .group { color: var(--faint); font-size: 12px; }
.module-search-empty { padding: 22px 14px; color: var(--muted); text-align: center; font-size: 14px; }
.module-search-foot {
    display: flex; gap: 16px; flex-wrap: wrap;
    padding: 9px 16px; border-top: 1px solid var(--border);
    background: var(--surface-2); color: var(--faint); font-size: 11.5px;
}
.module-search-foot kbd {
    margin-right: 3px; padding: 1px 5px; border: 1px solid var(--border);
    border-radius: 4px; background: var(--card); font: 700 10.5px/1.6 inherit;
}

/* Подтверждение паролем заменяет небезопасный window.prompt(). */
.password-confirm, .confirm-dialog { width: min(420px, calc(100vw - 32px)); }
.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: 13px; font-weight: 600; }
.field-error[hidden] { display: none; }

/* 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 стёр бы её.

   Поиск по разделам исключён намеренно: его открывают с клавиатуры по Ctrl+K
   сотни раз в день, и любая задержка там читается как тормоз.
   --------------------------------------------------------------------------- */
dialog:not(.module-search) {
    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:not(.module-search)[open] { opacity: 1; scale: 1; }
@starting-style {
    dialog:not(.module-search)[open] { opacity: 0; scale: .98; }
}
dialog:not(.module-search)::backdrop {
    opacity: 0;
    transition:
        opacity var(--dur) var(--ease),
        overlay var(--dur) var(--ease) allow-discrete,
        display var(--dur) var(--ease) allow-discrete;
}
dialog:not(.module-search)[open]::backdrop { opacity: 1; }
@starting-style {
    dialog:not(.module-search)[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.marketing-automation-container {
    max-width: none;
    width: 100%;
}
.marketing-automation-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%; }

.datalens-settings-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
}
.datalens-settings-card { margin: 0; }
.datalens-private-key { -webkit-text-security: disc; font-family: monospace; }
.lead-telegram-stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
    margin-bottom: 16px;
}
.lead-telegram-stats .card { min-width: 0; }
.lead-telegram-settings-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(300px, .65fr);
    gap: 16px;
    align-items: start;
}
.lead-telegram-settings-grid > .form-card { margin: 0; min-width: 0; }
.lead-telegram-settings-grid .form-row > label:not(.wide) { flex: 1 1 220px; }
.integration-steps { margin: 12px 0 18px; padding-left: 22px; color: var(--muted); }
.integration-steps li + li { margin-top: 8px; }

@media (max-width: 980px) {
    .datalens-settings-grid,
    .lead-telegram-settings-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
    .lead-telegram-stats { grid-template-columns: minmax(0, 1fr); }
}
.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-"] {
    width: min(1040px, calc(100vw - 36px));
    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,
.certificate-client-picker { flex: 1 1 220px; min-width: min(220px, 100%); }
.certificate-client-picker { position: relative; display: grid; gap: 4px; }
.certificate-client-picker > input[type="search"] { width: 100%; min-width: 0; }
.certificate-client-picker .client-search-results {
    position: fixed;
    z-index: 100;
    right: auto;
    max-height: min(320px, 45dvh);
}
.certificate-operation-form { min-width: 320px; margin-top: 8px; }
#certificate-activation-dialog [data-certificate-redemption-fields] { display: grid; gap: 12px; }
#certificate-activation-dialog [data-certificate-redemption-fields][hidden] { display: none; }
.operations-board { display: grid; grid-template-columns: repeat(auto-fill,minmax(260px,1fr)); gap: 14px; margin: 16px 0 28px; }
.operations-panel { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 15px; }
.operations-panel h3,.operations-panel h2 { margin-top: 0; }
.app-shell .container.loyalty-container { max-width: none; width: 100%; margin: 0; padding-left: 18px; padding-right: 18px; }
.loyalty-header { align-items: flex-end; }
.loyalty-header h1 { margin-bottom: 5px; }
.loyalty-header p { margin: 0; }
.loyalty-kpi-alert { border-color: var(--danger-border); background: var(--danger-soft); }
.loyalty-search { margin-bottom: 18px; }
.task-settings-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 18px; flex-wrap: wrap; }
.task-attribution-note { max-width: 78ch; }
.task-rule-stats { display: flex; flex-wrap: wrap; gap: 18px; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border); }
.task-rule-stats div { display: grid; gap: 1px; }
.task-rule-stats span { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
.task-rule-stats strong { font-size: 17px; font-variant-numeric: tabular-nums; }
.task-rule-stats small { color: var(--muted); font-size: 11px; }
.task-rule-revenue strong { color: var(--brand-ink); }
.task-panel { padding-bottom: 24px; }
.task-panel-page .task-panel { padding: 0; }
.task-panel-header h1 {
    max-width: 34ch;
    margin: 4px 0 8px;
    font-size: 25px;
    line-height: 1.2;
    letter-spacing: -.02em;
    text-wrap: pretty;
}
.task-panel-header .client-tags { display: flex; flex-wrap: wrap; gap: 5px; }
.task-panel .form-card { margin: 0; }
.task-card-grid { display: grid; grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr); gap: 16px; align-items: start; }
.task-card-grid .form-card > h2 { margin-top: 0; }
.task-card-main, .task-card-side { display: grid; gap: 16px; min-width: 0; }
.task-card-notes { white-space: pre-wrap; max-width: 70ch; }
.task-card-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin: 14px 0 0; }
.task-card-facts dt { color: var(--muted); font-size: 12px; }
.task-card-facts dd { margin: 2px 0 0; font-weight: 700; }
.task-card-overdue { color: var(--danger); }
.task-card-outcome { margin-top: 14px; 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-card-link { display: grid; gap: 2px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.task-card-link:last-child { border-bottom: 0; }
.task-card-link span { color: var(--muted); font-size: 12px; }
.task-comments { display: grid; gap: 10px; margin: 10px 0 14px; }
.task-comment { padding: 10px 12px; border-radius: var(--radius-sm); background: var(--surface-2); }
.task-comment-head { display: flex; justify-content: space-between; gap: 10px; font-size: 12px; }
.task-comment-head time { color: var(--muted); }
.task-comment p { margin: 4px 0 0; white-space: pre-wrap; }
.task-history { display: grid; gap: 8px; }
.task-history-item { display: grid; grid-template-columns: 118px 1fr; gap: 10px; font-size: 13px; }
.task-history-item time { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.task-history-item span { display: block; color: var(--muted); font-size: 12px; }
@media (max-width: 900px) { .task-card-grid { 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; }
.task-rules { display: grid; gap: 12px; margin-top: 14px; }
.task-rule { padding: 16px 18px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--card); opacity: .72; }
.task-rule.is-active { opacity: 1; border-color: var(--brand-ink); }
.task-rule h3 { margin: 0 0 4px; font-size: 15px; }
.task-rule p { margin: 0 0 8px; max-width: 70ch; }
.task-rule-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 18px; }
.task-rule-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 12px; }
.task-rule-switch { display: flex; align-items: center; gap: 7px; white-space: nowrap; font-weight: 700; }
@media (max-width: 700px) {
  .task-rule-head { flex-direction: column; }
  .task-limit-name { min-width: 0; }
}
.entity-picker { display: grid; gap: 7px; min-width: 0; }
.entity-picker input[type="search"] { width: 100%; }
.loyalty-client-picker { display: grid; gap: 7px; min-width: 0; }
.loyalty-client-picker input[type="search"] { width: 100%; }
.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: 0 10px 24px rgba(30,42,35,.12); }
.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 { padding: 8px 10px; border-radius: 7px; background: var(--selected); color: var(--ink); font-size: 13px; font-weight: 700; }
.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; gap: 8px; }
.loyalty-summary span { padding: 7px 10px; border-radius: 999px; background: var(--surface-2); color: var(--muted); font-size: 13px; white-space: nowrap; }
.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; grid-template-columns: minmax(0,1fr) auto; 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; } .recovery-card form { grid-template-columns: 1fr; } }
.qr-card { text-align: center; }
/* Белое поле вокруг QR обязательно: сканеру нужна светлая тихая зона,
   поэтому этот белый не следует за темой. */
.qr-card img { max-width: 100%; background: #fff; border-radius: 12px; padding: 8px; }
.check-row { display: flex; flex-wrap: wrap; gap: 8px 12px; }
.view-switch { display: flex; gap: 8px; margin: 0 0 16px; }

/* Sales funnel: dense operational workspace with explicit priority queues. */
.lead-workspace-tabs { margin-bottom: 14px; }
.lead-queue-cards { display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: 10px; margin-bottom: 14px; }
.lead-queue-card { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 2px 10px; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--card); color: var(--ink); text-decoration: none; }
.lead-queue-card:hover, .lead-queue-card.active { border-color: var(--brand); background: var(--brand-tint); }
.lead-queue-card.danger strong { color: var(--err); }
.lead-queue-card span { min-width: 0; font-size: 13px; font-weight: 700; }
.lead-queue-card strong { font-size: 22px; line-height: 1; }
.lead-queue-card small { grid-column: 1 / -1; color: var(--muted); font-size: 11px; }
.lead-filter-bar { align-items: end; flex-wrap: nowrap; gap: 8px; margin-bottom: 14px; padding: 10px; overflow-x: auto; }
.lead-filter-bar > label { flex: 1 1 128px; min-width: 120px; }
.lead-filter-bar > label.wide { flex: 1.4 1 190px; min-width: 180px; }
/* Своя высота, а не min-height: базовое правило задаёт height, и минимум
   рядом с ним ничего не решал — панель всё равно вытягивалась до общей. */
.lead-filter-bar input, .lead-filter-bar select { height: 36px; padding: 0 8px; font-size: 13px; }
.lead-filter-bar select { padding-right: 30px; }
.lead-filter-bar .filter-actions { flex: 0 0 auto; flex-wrap: nowrap; gap: 8px; }
.lead-filter-bar .filter-actions > * { min-height: 36px; white-space: nowrap; }
.form-error { min-height: 20px; color: var(--err); font-size: 13px; font-weight: 700; }
.lead-kanban { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(286px,1fr); gap: 12px; overflow-x: auto; padding: 4px 2px 18px; scroll-snap-type: x proximity; }
.lead-kanban-column { min-height: 420px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-md); scroll-snap-align: start; transition: border-color .15s,background .15s; }
.lead-kanban-column.drag-over { border-color: var(--brand); background: var(--brand-tint); }
.lead-kanban-column > header { display: flex; justify-content: space-between; align-items: center; padding: 12px 13px; border-bottom: 1px solid var(--border); }
.lead-kanban-column > header h2 { font-size: 14px; margin: 0; }
.lead-kanban-column > header span { background: var(--card); border-radius: 999px; min-width: 25px; padding: 3px 7px; text-align: center; font-size: 12px; }
.lead-kanban-dropzone { min-height: 360px; display: flex; flex-direction: column; gap: 9px; padding: 10px; }
.lead-kanban-card { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 11px; box-shadow: 0 2px 8px rgba(20,45,35,.05); cursor: pointer; }
.lead-kanban[data-can-edit="1"] .lead-kanban-card { cursor: grab; }
.lead-kanban[data-can-edit="1"] .lead-kanban-card:active,
.lead-kanban[data-can-edit="1"] .lead-kanban-card.dragging { cursor: grabbing; }
.lead-kanban-card:hover { border-color: var(--brand-border); }
.lead-kanban-card.is-overdue { border-left: 3px solid var(--err); }

.lead-kanban-card.dragging { opacity: .45; }
/* Отказ сервера при переносе. Карточка едет обратно (FLIP в app.js), и на
   время возврата подсвечивается сама — тост в углу объясняет причину, но
   взгляд в этот момент на карточке. Переход берётся из общего правила
   .lead-kanban-card ниже, отдельной скорости здесь нет. */
.lead-kanban-card.is-rejected {
    border-color: var(--err);
    box-shadow: 0 0 0 1px var(--err);
}
.lead-kanban-card a { overflow-wrap: anywhere; -webkit-user-drag: none; }
.lead-card-heading { display: flex; align-items: start; justify-content: space-between; gap: 8px; }
.lead-card-heading-main, .lead-table-title { display: flex; align-items: start; gap: 7px; min-width: 0; }
.lead-card-title { color: var(--ink); text-decoration: none; line-height: 1.35; }
.lead-card-title:hover { color: var(--brand); text-decoration: underline; text-underline-offset: 3px; }
.lead-card-meta { display: flex; flex-wrap: wrap; gap: 4px 9px; margin-top: 3px; color: var(--muted); font-size: 11px; }
.lead-card-message { margin: 9px 0; color: var(--ink); font-size: 13px; line-height: 1.4; overflow-wrap: anywhere; }
.lead-card-contact { display: grid; gap: 2px; margin-top: 8px; font-size: 13px; }
.lead-card-ownership { display: grid; gap: 5px; margin: 9px 0 0; }
.lead-card-ownership div { display: grid; grid-template-columns: 92px minmax(0,1fr); gap: 6px; align-items: baseline; }
.lead-card-ownership dt { color: var(--muted); font-size: 11px; }
.lead-card-ownership dd { min-width: 0; margin: 0; font-size: 12px; overflow-wrap: anywhere; }
.lead-missing { color: var(--err); font-weight: 700; }
.lead-card-due { color: var(--muted); font-size: 12px; margin-top: 7px; }
.lead-card-due.overdue { color: var(--err); font-weight: 700; }
.lead-column-empty { display: grid; min-height: 100px; place-items: center; color: var(--muted); font-size: 12px; }
.lead-column-more { display: block; padding: 0 12px 12px; color: var(--brand); font-size: 12px; text-align: center; }
.lead-drawer {
    width: min(1350px, calc(100vw - 32px));
    min-height: min(420px, calc(100dvh - var(--dialog-top) - var(--dialog-bottom)));
}
.lead-panel { display: grid; gap: 14px; min-height: 100%; padding: 18px; }
.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; }
.lead-panel-tags { display: flex; flex-wrap: wrap; gap: 5px; }
.lead-panel-summary { display: grid; grid-template-columns: repeat(auto-fit,minmax(180px,1fr)); gap: 8px; }
.lead-panel-summary-page { grid-column: 1 / -1; }
.lead-panel-summary > div, .lead-panel-readonly > div { display: grid; gap: 3px; min-width: 0; padding: 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2); }
.lead-panel-summary span, .lead-panel-readonly span { color: var(--muted); font-size: 11px; }
.lead-panel-summary strong, .lead-panel-readonly strong { overflow-wrap: anywhere; }
.lead-panel-summary small { color: var(--err); }
.lead-panel-summary small.lead-source-url { color: var(--muted); overflow-wrap: anywhere; }
.lead-panel-form { margin: 0; }
.lead-panel-form .form-row { display: grid; gap: 14px; }
.lead-panel-grid-2 { grid-template-columns: repeat(2,minmax(0,1fr)); }
.lead-panel-grid-3 { grid-template-columns: repeat(3,minmax(0,1fr)); }
.lead-panel-grid-4 { grid-template-columns: repeat(4,minmax(0,1fr)); }
.lead-panel-form .form-row > label { min-width: 0; }
.lead-panel-form input:not([type="hidden"]),
.lead-panel-form select,
.lead-panel-form textarea { box-sizing: border-box; width: 100%; min-width: 0; }
.lead-panel-readonly { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: 8px; }
.lead-panel-readonly p { margin: 2px 0 0; white-space: pre-wrap; }
.lead-panel-actions { display: grid; gap: 10px; padding-top: 12px; border-top: 1px solid var(--border); }
.lead-panel-action-row { display: flex; flex-wrap: nowrap; align-items: stretch; gap: 8px; overflow-x: auto; }
.lead-panel-action-row > a,
.lead-panel-action-row > button,
.lead-panel-action-row > form { flex: 1 1 0; min-width: 170px; margin: 0; }
.lead-panel-action-row > a,
.lead-panel-action-row > button,
.lead-panel-action-row > form > button { display: inline-flex; box-sizing: border-box; width: 100%; min-height: 40px; align-items: center; justify-content: center; white-space: nowrap; }
.lead-panel-lost-form { display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: end; gap: 8px; padding: 10px; border: 1px solid color-mix(in srgb,var(--err) 35%,var(--border)); border-radius: var(--radius-sm); background: var(--surface-2); }
.lead-panel-lost-form[hidden] { display: none; }
.lead-panel-lost-form label { min-width: 0; margin: 0; }
.lead-panel-lost-form textarea { box-sizing: border-box; width: 100%; min-width: 0; }
@media (max-width: 1100px) { .lead-panel-grid-3, .lead-panel-grid-4 { grid-template-columns: repeat(2,minmax(0,1fr)); } }
@media (max-width: 980px) { .lead-queue-cards { grid-template-columns: repeat(2,minmax(0,1fr)); } }
@media (max-width: 760px) { .operations-form-grid { grid-template-columns: 1fr; } .operations-inline-form { grid-template-columns: 1fr; } .lead-kanban { grid-auto-columns: minmax(84vw,1fr); } .lead-drawer { width: calc(100vw - 16px); height: calc(100dvh - 16px); } .lead-panel { padding: 13px; } .lead-panel-summary, .lead-panel-grid-2, .lead-panel-grid-3, .lead-panel-grid-4, .lead-panel-readonly, .lead-panel-lost-form { grid-template-columns: 1fr; } }
@media (max-width: 420px) { .lead-queue-cards { gap: 7px; } .lead-queue-card { padding: 10px; } .lead-queue-card strong { font-size: 19px; } }
@media (prefers-reduced-motion: reduce) { .lead-kanban-column { transition: none; } }

/* Чаты → ИИ-агент: 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 { max-width: 720px; margin: 0; color: var(--muted); }
.chat-settings-migration {
    display: grid;
    max-width: 1068px;
    gap: 3px;
    margin: 0 0 18px;
    padding: 12px 14px;
    border: 1px solid var(--info-border);
    border-radius: var(--radius-sm);
    background: var(--info-soft);
    font-size: 12px;
}
.chat-settings-migration span { 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-legacy,
.chat-channel-status.status-warning { color: var(--warn); }
.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 { max-width: 440px; 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; }
.chat-settings-notice,
.chat-settings-dependency {
    display: grid;
    gap: 3px;
    margin: 18px 24px 0;
    padding: 12px 14px;
    border: 1px solid var(--warn-border);
    border-radius: var(--radius-sm);
    background: var(--warn-tint);
    color: var(--ink);
    font-size: 12px;
}
.chat-settings-notice strong { font-size: 12px; }
.chat-settings-notice span { color: var(--muted); }
.chat-settings-notice.is-error { border-color: var(--danger-border); background: var(--danger-soft); color: var(--err); }
.chat-settings-dependency { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.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; }
.chat-settings-field { display: grid; max-width: 620px; min-width: 0; gap: 6px; }
.chat-settings-field-label { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; color: var(--ink); font-size: 12px; font-weight: 700; }
.chat-settings-field-label small { color: var(--muted); font-size: 10px; font-weight: 500; }
.chat-settings-field input { width: 100%; min-width: 0; }
.chat-settings-field-hint { color: var(--muted); font-size: 11px; line-height: 1.4; }
.chat-settings-check-row { display: flex; align-items: flex-start; gap: 10px; max-width: 620px; }
.chat-settings-check-row > input[type="checkbox"] { width: auto; margin-top: 3px; }
.chat-settings-check-row > span { display: grid; gap: 1px; }
.chat-settings-check-row small { color: var(--muted); }
.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 { max-width: 420px; margin: 0; color: var(--muted); font-size: 11px; line-height: 1.4; }
.chat-settings-security-note { max-width: 900px; 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-state.is-ready { border-color: var(--ok-border); background: var(--ok-bg); }
.telegram-user-action-form { display: flex; align-items: end; flex-wrap: wrap; gap: 12px; padding: 0 24px 22px; }
.telegram-user-action-form .chat-settings-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 .chat-settings-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 label { font-size: 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-control-label { color: var(--muted); font-size: 12px; font-weight: 700; }
.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-columns { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin-bottom: 18px; }
.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 .history-full { margin-top: 8px; }
.conversation-history .history-full > summary { cursor: pointer; font-size: 12px; color: var(--brand-ink); }
.conversation-history .history-full[open] > summary { margin-bottom: 6px; }
/* Тревожная плитка красилась светлой заливкой и в тёмной теме — светлый текст
   на светлом фоне читался хуже, чем совсем без подсветки. */
@media (max-width: 900px) { .metrics-columns { grid-template-columns: 1fr; } .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-search { display: flex; gap: 8px; align-items: center; margin-bottom: 16px; }
.kb-search input[type="search"] { flex: 1 1 auto; min-width: 0; }
.kb-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
.kb-card { display: flex; flex-direction: column; gap: 8px; }
.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: 13.5px; line-height: 1.5; }
.kb-subsections { margin: 0; padding-left: 18px; display: grid; gap: 4px; font-size: 13.5px; }
.kb-card-foot { margin-top: auto; display: flex; gap: 8px; align-items: center; font-size: 12.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: 6px; font-size: 13px; color: var(--muted); margin-bottom: 6px; }
.kb-crumbs a { color: var(--muted); }
.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: 10px; align-items: center; font-size: 12.5px; margin-bottom: 12px; }
.kb-body { font-size: 15px; line-height: 1.65; }
.kb-body h2 { font-size: 19px; margin: 22px 0 8px; }
.kb-body h3 { font-size: 17px; margin: 20px 0 8px; }
.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, .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, .kb-editor-layout { grid-template-columns: 1fr; } }
.kb-editor-form { display: grid; gap: 12px; }
.kb-editor-body { width: 100%; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13.5px; line-height: 1.6; }
.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;
}
/* Левое меню базы знаний.

   Оформление берётся у сайдбара кабинета целиком: классы 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);
    }

    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: 0 16px 36px rgb(30 42 35 / 14%);
    }
    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-content .kb-search { max-width: 720px; }
.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; }
}

/* Команда для сервера в пустом состоянии базы знаний: её копируют целиком. */
.kb-command { margin: 8px 0 0; padding: 10px 12px; overflow-x: auto; font-size: 12.5px;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); }
.kb-command code { background: none; padding: 0; }

/* ===========================================================================
   Примитивы из 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;
    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;
}
.field-hint { color: var(--muted); font-size: 11px; line-height: 1.4; }
.field-error { color: var(--err); font-size: 11px; font-weight: 600; line-height: 1.4; }
.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,
.field-group > .field-wide { grid-column: 1 / -1; }

/* Раздел формы: подпись раздела вместо голого <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; }
.client-create-dialog .field { gap: 6px; }
.client-create-dialog .field-label { font-size: 13px; }
.client-create-dialog .field > :is(input, select, textarea) {
    width: 100%;
    min-width: 0;
    border-color: var(--border);
    background-color: var(--surface-2);
    transition:
        background-color var(--dur-fast) ease,
        border-color var(--dur-fast) ease;
}
.client-create-dialog .field > :is(input, select, textarea):hover:not(:disabled) {
    border-color: var(--brand-border);
}
.client-create-dialog .field > :is(input, select, textarea):focus-visible {
    border-color: var(--brand-border-strong);
    background-color: var(--card);
}
.client-create-dialog .field[data-invalid] > :is(input, select, textarea) {
    border-color: var(--danger-border);
    background-color: var(--danger-soft);
}
.client-create-form-error {
    margin: 0 0 14px;
    padding: 10px 12px;
    border: 1px solid var(--danger-border);
    border-radius: var(--radius-sm);
    background: var(--danger-soft);
    color: var(--danger);
    font-size: 13px;
    font-weight: 650;
}
.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 у боковой карточки. Восемь ширин, ни одна
   не выводится из другой, и добавление девятой карточки означало девятое
   правило.

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

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

   Атрибут выигрывает у прежних именных правил по специфичности, поэтому
   страницы переводятся по одной, а не все сразу.
   --------------------------------------------------------------------------- */
.modal[data-size="sm"] { width: min(440px, calc(100vw - 32px)); }
.modal[data-size="md"] { width: min(640px, calc(100vw - 32px)); }
.modal[data-size="lg"] { width: min(920px, calc(100vw - 36px)); }
.modal[data-size="xl"] { width: min(1120px, calc(100vw - 48px)); }

/* Шапка карточки, которая остаётся на месте при прокрутке содержимого.
   Раньше липкой умела быть только .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 - 32px));
    max-width: min(920px, calc(100vw - 32px));
}

/* Плавный рост вместо скачка, когда содержимое приезжает htmx-ом: карточка
   открывается с заглушкой на 380 пикселей и дорастает до своего размера.
   Интерполяция auto есть не везде — там, где её нет, высота встаёт сразу,
   ровно как до этой правки. Переход не срабатывает на самом открытии:
   <dialog> переключает display, а такие смены анимируются только с
   @starting-style, которого здесь нет намеренно. */
@supports (interpolate-size: allow-keywords) {
    .client-drawer,
    .lead-drawer {
        interpolate-size: allow-keywords;
        transition: height var(--dur) var(--ease);
    }
}
@media (prefers-reduced-motion: reduce) {
    .client-drawer,
    .lead-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-slots {
    display: grid;
    grid-template-columns: repeat(var(--otp-length), var(--otp-slot));
    gap: var(--otp-gap);
}
.otp-slots > span {
    height: calc(var(--otp-slot) * 1.16);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--card);
    transition: border-color var(--dur) ease, box-shadow var(--dur) ease;
}
.otp:focus-within .otp-slots > span {
    border-color: var(--brand-border-strong);
    box-shadow: 0 0 0 3px var(--brand-strong);
}
.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; }
/* Невалидный код: рамка у всех клеток сразу — ошибка относится к коду
   целиком, а не к какой-то одной цифре. */
.otp[data-invalid] .otp-slots > span,
[data-invalid] .otp .otp-slots > span { border-color: var(--danger-border); }
/* На узком телефоне шесть клеток по 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 в app.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: 0 8px 24px -8px rgba(20, 60, 44, .45);
    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: 0 24px 60px -20px rgba(20, 60, 44, .38);
}
.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 { gap: 4px; margin-bottom: 8px; font-size: 12px; }
.kb-crumbs a { color: var(--faint); text-decoration: none; }
.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-meta { gap: 8px; padding-bottom: 12px; margin-bottom: 16px; border-bottom: 1px solid var(--border); font-size: 12px; }
.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 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-grid { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 10px; }
.kb-card { gap: 6px; padding: 14px 16px; border-radius: var(--kb-radius); }
.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-card p { font-size: 12.5px; line-height: 1.45; }
.kb-subsections { padding-left: 0; list-style: none; font-size: 12.5px; }
.kb-subsections a { color: var(--muted); }
.kb-subsections a:hover { color: var(--brand-ink); }
.kb-card-foot { font-size: 11.5px; }
.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; }

@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; }
}
