/*
 * Общие правки панели поверх стилей Filament.
 *
 * Поля ввода без оранжевой обводки при фокусе мышью (решение пользователя 17.09.2026:
 * «убери везде»): рамка остаётся такой же, как в покое. Исключения как у Filament: поле с
 * ошибкой валидации (красное кольцо .fi-invalid не трогаем), отключённое поле, фокус на
 * кнопке-действии внутри поля (стрелки периода). Для клавиатуры (:focus-visible) остаётся
 * нейтральное серое кольцо — иначе фокус в панели не виден вовсе.
 */
.fi-input-wrp:not(.fi-invalid):not(.fi-disabled):not(:has(.fi-ac-action:focus)):focus-within {
    box-shadow: 0 0 0 1px rgba(128, 128, 128, 0.35) !important;
}
/* Те же условия, что у правила выше, плюс :has(…:focus-visible): иначе у этого правила специфичность ниже
   (0,4,1 против 0,6,0), и с клавиатуры оставалось бледное кольцо 1px (найдено 24.10.2026). */
.fi-input-wrp:not(.fi-invalid):not(.fi-disabled):not(:has(.fi-ac-action:focus)):focus-within:has(input:focus-visible, select:focus-visible, textarea:focus-visible) {
    box-shadow: 0 0 0 2px rgba(128, 128, 128, 0.6) !important;
}
.fi-input-wrp input:focus:not(:focus-visible),
.fi-input-wrp select:focus:not(:focus-visible),
.fi-input-wrp textarea:focus:not(:focus-visible) {
    outline: none;
    box-shadow: none;
}

/*
 * Окно «Настроить отчёт» (resources/views/filament/pages/partials/report-columns-panel.blade.php): поле поиска,
 * название отчёта и флажки — компоненты Filament (x-filament::input.*), здесь только раскладка и подписи.
 * Флажок с подписью .o-check — по виду как пункт списка флажков Filament.
 */
.o-cols-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
}
.o-cols-counter,
.o-cols-save-label {
    font-size: 0.875rem;
    color: var(--gray-500);
}
.o-cols-save-hint {
    font-size: 0.75rem;
    color: var(--gray-500);
}
.dark .o-cols-counter,
.dark .o-cols-save-label,
.dark .o-cols-save-hint {
    color: var(--gray-400);
}
.o-cols-search {
    flex: none;
    width: 14rem;
}
.o-cols-grid {
    display: grid;
    gap: 0.75rem 1.25rem;
}
.o-cols-col {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.o-cols-group {
    margin-bottom: 0.375rem;
    font-size: 0.875rem;
    font-weight: 600;
}
.o-check {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.125rem 0;
    font-size: 0.875rem;
    line-height: 1.5rem;
    cursor: pointer;
}
.o-check .fi-checkbox-input {
    flex: none;
}
.o-cols-save {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid rgba(128, 128, 128, 0.25);
}
.o-cols-name {
    flex: none;
    width: 16rem;
}

/*
 * Меню пользователя в шапке (просьба пользователя 18.09.2026): «Выйти» — в одной строке с именем,
 * справа; переключатель темы — второй строкой на всю ширину. Панель меню телепортируется в body,
 * поэтому цепляемся за неё саму: переключатель темы есть только в этом меню. Правила — в слое
 * components, как у Filament: их max-width стоит с !important, а для !important слой без имени
 * проигрывает именованному.
 *
 * x-float открывает и закрывает панель инлайновым style: «display: block» / «display: none».
 * Перебить block можно только через !important, но тогда перебьётся и none — панель перестанет
 * закрываться (ошибка 18.09.2026). Поэтому сетка включается только у открытой панели, по
 * атрибуту style; остальные правила от display не зависят.
 */
@layer components {
    .fi-dropdown-panel.fi-dropdown-panel:has(.fi-theme-switcher) { /* класс дважды: перебить «:scope .fi-dropdown-panel» Filament */
        width: max-content !important; /* имя целиком, без обрезки */
        min-width: 13rem;
        max-width: 22rem !important;
    }
    .fi-dropdown-panel:has(.fi-theme-switcher)[style*="display: block"] {
        display: grid !important;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: center;
    }
    .fi-dropdown-panel:has(.fi-theme-switcher) > .fi-dropdown-header {
        grid-row: 1;
        grid-column: 1;
        border-bottom-width: 0;
    }
    .fi-dropdown-panel:has(.fi-theme-switcher) > .fi-dropdown-list:last-child {
        grid-row: 1;
        grid-column: 2;
        padding-inline-start: 0;
    }
    .fi-dropdown-panel:has(.fi-theme-switcher) > .fi-dropdown-list:has(.fi-theme-switcher) {
        grid-row: 2;
        grid-column: 1 / -1;
        border-bottom-width: 0;
        border-top-width: 1px;
    }
}

/*
 * «Проверить подключение» в строке списка источников (SourcesTable::healthCheckBlinkAttributes):
 * иконка сигнала мигает зелёным (успех) или красным (неудача) — три вспышки по 0,5 с, всего 1,5 с,
 * затем остаётся обычного цвета. Класс на кнопку ставит Alpine после ответа сервера и снимает
 * через 1,6 с. Кнопка при этом остаётся обычной: pointer-events не трогаем, повторное нажатие
 * запускает мигание заново. В кадрах задана только вспышка (50 %): крайние кадры браузер берёт
 * из текущего цвета иконки (у Filament он серый, в тёмной теме темнее), поэтому его здесь не
 * повторяем. Спиннер загрузки (.fi-loading-indicator) не трогаем.
 */
.o-health-blink-ok { --o-blink-color: var(--success-600); }
.o-health-blink-fail { --o-blink-color: var(--danger-600); }
.dark .o-health-blink-ok { --o-blink-color: var(--success-400); }
.dark .o-health-blink-fail { --o-blink-color: var(--danger-400); }
.o-health-blink-ok > .fi-icon:not(.fi-loading-indicator),
.o-health-blink-fail > .fi-icon:not(.fi-loading-indicator) {
    animation: o-health-blink 0.5s linear 3;
}
@keyframes o-health-blink {
    50% { color: var(--o-blink-color); }
}
/* Без движения: цвет просто держится те же 1,5 с. */
@media (prefers-reduced-motion: reduce) {
    .o-health-blink-ok > .fi-icon:not(.fi-loading-indicator),
    .o-health-blink-fail > .fi-icon:not(.fi-loading-indicator) {
        animation: o-health-hold 1.5s step-end;
    }
    @keyframes o-health-hold {
        0%, 100% { color: var(--o-blink-color); }
    }
}

/* Результат «Проверить подключение» в описании секции «Доступы» (SourceForm::credentialsSectionDescription). */
.o-health-ok { color: var(--success-600); }
.o-health-fail { color: var(--danger-600); }
.dark .o-health-ok { color: var(--success-400); }
.dark .o-health-fail { color: var(--danger-400); }

/*
 * Ширина страниц (решение пользователя 29.09.2026): панель на всю ширину экрана
 * (maxContentWidth Full в AdminPanelProvider), чтобы таблицы и отчёты помещались целиком,
 * а страницы с формами — создание, правка, карточка записи, настройки бота — не шире 80rem
 * (как 7xl Filament по умолчанию): растянутые поля читать неудобно.
 * Одна левая граница (решение пользователя 20.10.2026): формы встают от того же левого края,
 * что списки и отчёты, и не центрируются — иначе при переходе между разделами контент «прыгает».
 */
.fi-resource-create-record-page,
.fi-resource-edit-record-page,
.fi-resource-view-record-page,
.oika-form-page {
    width: 100%;
    max-width: 80rem;
}

/*
 * Полоса кнопок формы «Сохранить / Отмена» (решение пользователя 20.10.2026). Page::stickyFormActions()
 * прижимает кнопки к низу экрана на длинных формах; штатный вид Filament — белая плавающая карточка в
 * 1rem над нижним краем, и в зазоре под ней и вокруг неё просвечивал текст секций. Здесь полоса — на
 * всю ширину формы, вплотную к низу, фоном страницы (непрозрачная), с верхней границей и мягкой тенью
 * вверх; сама форма остаётся от левой границы, поэтому поля выровнены с краем секций. Отступ
 * слева-справа обнулён: ширину полосе считает скрипт Filament (ширина формы + её отрицательные поля),
 * без полей она точно равна форме. Класс .fi-sticky появляется, только пока кнопки ушли за нижний край
 * экрана, — в конце формы они стоят обычной строкой. Селектор усилен вторым .fi-ac: правила Filament
 * лежат в том же слое components.
 */
@layer components {
    .fi-sc-actions.fi-sticky .fi-ac.fi-ac {
        bottom: 0;
        margin-inline: 0;
        padding: 0.75rem 0;
        border-radius: 0;
        border-top: 1px solid var(--gray-200);
        background-color: var(--gray-50);
        box-shadow: 0 -0.5rem 1rem -0.5rem rgba(0, 0, 0, 0.12);
    }
    .dark .fi-sc-actions.fi-sticky .fi-ac.fi-ac {
        border-top-color: rgba(255, 255, 255, 0.1);
        background-color: var(--gray-950);
        box-shadow: 0 -0.5rem 1rem -0.5rem rgba(0, 0, 0, 0.6);
    }
}

/*
 * Поле периода «21.09.2026 - 20.10.2026» со стрелками на дашборде, в отчётах и в «Аналитике»
 * (решение пользователя 20.10.2026: одна ширина везде). При 17rem дата обрезалась на 3px
 * (clientWidth 182, scrollWidth 185) — 18rem даёт запас на другой шрифт и масштаб. Раньше ширина
 * стояла инлайном в каждой из трёх страниц; класс o-period-range ставится через
 * extraFieldWrapperAttributes() у DateRangePicker «range».
 */
.o-period-range {
    width: 18rem;
}

/*
 * Плитка фильтров дашборда, «Отчёта» и «Аналитики» (решение пользователя 20.10.2026: один вид).
 * Внутри строки по смыслу — что смотрим (отчёт, «Настроить», фильтры), разрез (проект, режим,
 * группировка), период (пресеты, даты, «Сравнить»). Строки собирает ReportFilters::row(), в Blade-страницах
 * отчётов стопкой их выстраивает .o-filter-card. Элементы по содержимому; не помещаются — переносятся.
 * Одинаковые элементы одной ширины: проект — 13rem, выбор отчёта — 22rem (с многоточием у длинного
 * названия), период — 18rem (выше).
 */
.o-filter-card {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}
.o-filter-row {
    flex-wrap: wrap;
}
/* То же для строки, собранной вручную в Blade (отчёт, «Настроить», чипы фильтров). */
.o-filter-line {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
}
.o-filter-project {
    width: 13rem;
}
.o-report-select {
    width: 22rem;
    max-width: 100%;
}
.o-report-select .fi-select-input-value-label {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/*
 * Ширина таблиц списков — штатная Filament (решение пользователя 20.10.2026): карточка на всю область страницы
 * и не меняется от поиска, фильтров и страниц. Свободное место забирает одна колонка с ->grow() — новой таблице
 * тоже пометить одну такую колонку (тест TableWidthTest следит).
 */

/*
 * Заголовки столбцов в своих HTML-таблицах («Отчёт», «Аналитика»; тот же вид у «Сверки») — как у таблиц
 * Filament (решение пользователя 20.10.2026): размер .875rem, жирность 600, цвет основного текста,
 * без заглавных букв и разрядки. Общие стили o-table-styles (разрядка, верхний регистр, прозрачность .7)
 * подключены и другими простыми таблицами панели, поэтому правило включается классом на таблице.
 */
.o-table-plain-head .o-th,
.o-table-plain-head .o-th-left {
    font-size: 0.875rem;
    font-weight: 600;
    letter-spacing: normal;
    text-transform: none;
    color: inherit;
    opacity: 1;
}

/*
 * Таблица «Сверки» (вместе с o-table-plain-head): не уже своего содержимого — на узкой области она
 * прокручивается, а не обрезает значок статуса; чуть меньшие боковые отступы, чтобы на обычном
 * экране (1440) она помещалась целиком.
 */
.o-recon {
    min-width: max-content;
}
.o-recon .o-th,
.o-recon .o-th-left,
.o-recon .o-td,
.o-recon .o-td-left {
    padding-inline: 0.625rem;
}

/*
 * Список источников данных: кнопки строки всегда на виду (решение пользователя 20.10.2026). Таблица широкая
 * (десять колонок), и на узком экране её правый край с кнопками уходил за границу прокрутки. Последняя
 * ячейка (кнопки) прилипает к правому краю области: при прокрутке остальные колонки уезжают под неё, сами
 * кнопки остаются. Ячейка непрозрачная (иначе сквозь неё видны уехавшие колонки), поэтому её фон повторяет
 * фон строки во всех состояниях: обычная — цвет карточки таблицы (белый / gray-900), строка при наведении,
 * выбранная и полосатая — как у строки Filament (row.css: gray-50 / белый 5 %). Полупрозрачный белый 5 %
 * тёмной темы переведён в непрозрачный эквивалент поверх gray-900 (color-mix), так же, как у строки заголовков.
 * Подсветка строки при наведении есть только у кликабельной строки (.fi-clickable).
 */
.fi-resource-sources .fi-ta-table td:last-child,
.fi-resource-sources .fi-ta-table th:last-child {
    position: sticky;
    right: 0;
    z-index: 1;
    background-color: #fff;
    transition-property: background-color;
    transition-duration: 75ms;
}
.fi-resource-sources .fi-ta-table th:last-child,
.fi-resource-sources .fi-ta-row.fi-selected > td:last-child,
.fi-resource-sources .fi-ta-row.fi-striped > td:last-child {
    background-color: var(--gray-50);
}
.dark .fi-resource-sources .fi-ta-table td:last-child {
    background-color: var(--gray-900);
}
.dark .fi-resource-sources .fi-ta-table th:last-child,
.dark .fi-resource-sources .fi-ta-row.fi-selected > td:last-child,
.dark .fi-resource-sources .fi-ta-row.fi-striped > td:last-child {
    background-color: color-mix(in srgb, #fff 5%, var(--gray-900));
}
/* Наведение — как у строки Filament: только на устройствах с мышью. */
@media (hover: hover) {
    .fi-resource-sources .fi-ta-row.fi-clickable:hover > td:last-child {
        background-color: var(--gray-50);
    }
    .dark .fi-resource-sources .fi-ta-row.fi-clickable:hover > td:last-child {
        background-color: color-mix(in srgb, #fff 5%, var(--gray-900));
    }
}

/* Поля интервала обновления источника (дн / ч / мин): без стрелок числового поля — в узком
   поле они закрывали само число. */
.oika-interval-field input[type="number"] {
    -moz-appearance: textfield;
    appearance: textfield;
}
.oika-interval-field input[type="number"]::-webkit-inner-spin-button,
.oika-interval-field input[type="number"]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
/* Подписи «дн» / «ч» / «мин» одной ширины — чтобы сами поля ввода были одинаковыми. */
.oika-interval-field .fi-input-wrp-suffix {
    width: 3rem;
    justify-content: center;
    padding-inline: 0;
}

/* Часовой пояс проекта: смещение «(UTC+5)» видно в выпадающем списке, а в выбранном значении
   поля — только город, в одну строку. */
.fi-select-input-value-label .oika-tz-offset {
    display: none;
}
.fi-select-input-value-label:has(.oika-tz-offset) {
    white-space: nowrap;
}

/*
 * Импорт идёт долго, и в панели должно быть видно, что он идёт (решение пользователя 05.10.2026).
 * Три места: подпись под датой в списке источников (SourcesTable::importStateDescription),
 * значок-крутилка на неактивной кнопке «Идёт импорт…» и значок «Импорт» в шапке
 * (App\Livewire\ImportActivityIndicator). Цвета — переменные Filament, в тёмной теме — светлее.
 */
.o-import-state {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}
/*
 * У зависшего запуска подпись длиннее (прогресс и «нет движения N мин — возможно, завис»): в одну строку она растягивала бы
 * колонку списка почти вдвое. Переносим на две строки в блоке фиксированной ширины — колонку не раздувает и не сжимает в узкую полоску.
 */
.o-import-state--stalled > span:last-child {
    white-space: normal;
    width: 18rem;
}
/*
 * Точка — «живой» признак импорта (запрос пользователя 24.10.2026: видно, что он идёт, а не завис).
 * Состояние выбирает сервер по движению запуска (ImportRun::isStalled(), App\Livewire\ImportActivityIndicator):
 *  --running — идёт и двигается: точка бьётся (размер и яркость) и пускает расходящуюся «волну»;
 *  --stalled — идёт, но дольше порога нет движения: не пульсирует, полое колечко предупреждающего цвета
 *              (warning панели — тот же янтарь, что и primary, поэтому отличаем ещё и формой);
 *  --queued  — ждёт очереди: серая, медленно «дышит» яркостью, без волны.
 * Цвет задаёт color, точка и «волна» его берут; в тёмной теме светлее.
 * «Волна» — копия точки (::after), которая растёт и гаснет: transform и opacity анимируются в любом браузере.
 * Прежняя волна была тенью с color-mix(currentColor): Chrome не плавит такие значения, а переключает их
 * скачком на середине цикла — кольцо нулевой ширины сменялось прозрачным, и точка выглядела статичной.
 */
.o-import-dot {
    position: relative;
    display: inline-block;
    flex: none;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 9999px;
    color: var(--primary-600);
    background: currentColor;
}
.dark .o-import-dot { color: var(--primary-400); }
.o-import-dot--running { animation: o-import-beat 1.4s ease-in-out infinite; }
.o-import-dot--running::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: currentColor;
    animation: o-import-wave 1.4s ease-out infinite;
}
.o-import-dot--queued {
    --o-import-fade-min: 0.45;
    color: var(--gray-400);
    animation: o-import-fade 3.2s ease-in-out infinite;
}
.dark .o-import-dot--queued { color: var(--gray-500); }
.o-import-dot--stalled {
    color: var(--warning-600);
    background: transparent;
    box-shadow: inset 0 0 0 2px currentColor;
}
.dark .o-import-dot--stalled { color: var(--warning-400); }
@keyframes o-import-beat {
    0%, 100% { transform: scale(1); opacity: 1; }
    50% { transform: scale(1.25); opacity: 0.65; }
}
@keyframes o-import-wave {
    0% { transform: scale(1); opacity: 0.75; }
    100% { transform: scale(2.8); opacity: 0; }
}
/* Мягкое мигание одной яркостью: «дыхание» в очереди и замена движению при prefers-reduced-motion. */
@keyframes o-import-fade {
    0%, 100% { opacity: 1; }
    50% { opacity: var(--o-import-fade-min, 0.35); }
}
/* Подпись зависшего запуска под датой в списке источников и строка в подсказке значка — предупреждающим цветом. */
.o-import-state--stalled,
.o-import-popup-item--stalled { color: var(--warning-700); }
.dark .o-import-state--stalled,
.dark .o-import-popup-item--stalled { color: var(--warning-400); }

/* Кнопка «Идёт импорт…» / «В очереди…»: значок вращается (иконку Filament кладёт прямо в кнопку). */
.o-import-busy > .fi-icon:not(.fi-loading-indicator) {
    animation: o-import-spin 1.2s linear infinite;
}
@keyframes o-import-spin {
    to { transform: rotate(360deg); }
}

/* На узком экране оставляем иконку и счётчик, чтобы ссылка поместилась рядом с часами. */
@media (max-width: 40rem) {
    .o-import-indicator-link > .fi-link-label { display: none; }
}

/*
 * «Уменьшить движение» в системе: ни биения, ни расходящейся «волны», ни вращения — вместо них мягкое мигание
 * яркостью (по образцу o-health-hold выше), чтобы живой импорт всё равно был виден, а не выглядел статичным.
 * Очередь уже дышит одной яркостью, зависший не двигается вовсе — их это правило не трогает.
 */
@media (prefers-reduced-motion: reduce) {
    .o-import-dot--running,
    .o-import-busy > .fi-icon:not(.fi-loading-indicator) { animation: o-import-fade 2s ease-in-out infinite; }
    .o-import-dot--running::after { display: none; }
}

/*
 * Сообщения в углу экрана: «вышла новая версия» (livewire/new-version-notice.blade.php, карточка внизу справа)
 * и «запрос не прошёл» (filament/partials/request-failure-notice.blade.php, карточка сверху по центру,
 * строится скриптом). Не мешают работе: ничего не закрывают, кроме угла, и не перезагружают страницу сами.
 * Версионная — над прилипающей панелью «Сохранить/Отмена» (у неё z-index не задан), но под боковым меню на
 * телефоне (z-index 30) и под окнами Filament (40); сбой — выше всего. Кнопка «Обновить страницу» — настоящая
 * кнопка Filament (.fi-btn), своих цветов у неё нет.
 */
.o-notice {
    position: fixed;
    z-index: 20;
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    box-sizing: border-box;
    width: min(26rem, calc(100vw - 2rem));
    padding: 0.75rem 0.75rem 0.75rem 1rem;
    border-radius: 0.75rem;
    border: 1px solid rgba(128, 128, 128, 0.3);
    border-left: 4px solid var(--primary-500);
    font-size: 0.875rem;
    line-height: 1.4;
    color: var(--gray-700);
    background: var(--color-white, #fff);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}
.dark .o-notice {
    color: var(--gray-200);
    background: var(--gray-900);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
}
.o-notice--version { right: 1rem; bottom: 1rem; }
/* Прилипающая полоса кнопок формы (.fi-sc-actions.fi-sticky: высота около 3,8rem, вплотную к низу экрана, см. блок «Полоса кнопок формы» выше) — карточка выше неё. */
body:has(.fi-sc-actions.fi-sticky) .o-notice--version { bottom: 5rem; }
.o-notice--failure {
    z-index: 60;
    top: 1rem;
    left: 50%;
    transform: translateX(-50%);
    border-left-color: var(--danger-500);
}
.o-notice-body { flex: 1 1 auto; min-width: 0; }
.o-notice-text,
.o-notice-paragraph { margin: 0; }
.o-notice-title { font-weight: 600; }
.o-notice-code { font-size: 0.75rem; opacity: 0.65; }
.o-notice-code:empty { display: none; }
.o-notice-actions { margin-top: 0.5rem; }
.o-notice-close {
    flex: none;
    width: 1.5rem;
    height: 1.5rem;
    padding: 0;
    border: 0;
    border-radius: 0.375rem;
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
    color: inherit;
    background: transparent;
    opacity: 0.6;
}
.o-notice-close:hover,
.o-notice-close:focus-visible { opacity: 1; background: rgba(128, 128, 128, 0.15); }

/*
 * Диаграммы ApexCharts (дашборд, «Аналитика», «Отчёт»). ApexCharts v6 для доступности ставит на SVG
 * диаграммы tabindex="0" (dist/apexcharts.js: setAttribute("tabindex","0")), и браузер рисует голубую
 * рамку фокуса вокруг всей диаграммы после клика. Решение пользователя 17.09.2026 про поля («без цветной
 * обводки при фокусе мышью») распространено на диаграммы: мышью — рамки нет; с клавиатуры (:focus-visible,
 * стрелки Apex переходят по точкам) — нейтральное серое кольцо. Кольцо нарисовано внутрь (outline-offset
 * отрицательный), чтобы его не обрезали контейнеры с overflow:hidden, например у колец «Топ каналов».
 */
.apexcharts-canvas .apexcharts-svg:focus {
    outline: none;
}
.apexcharts-canvas .apexcharts-svg:focus-visible {
    outline: 2px solid rgba(128, 128, 128, 0.6);
    outline-offset: -2px;
    border-radius: 0.5rem;
}
.apexcharts-canvas .apexcharts-legend-series:focus {
    outline: none;
}
.apexcharts-canvas .apexcharts-legend-series:focus-visible {
    outline: 2px solid rgba(128, 128, 128, 0.6);
    border-radius: 0.375rem;
}

/*
 * Текст в центре колец «Топ каналов по выручке» (plotOptions.pie.donut.labels, тексты задаёт
 * App\Filament\Widgets\TopChannelsWidget::centerLabelsJs()). Apex красит его своим цветом — на тёмной теме
 * он сливается с фоном, поэтому цвет — как у текста панели (currentColor) в обеих темах; название канала
 * приглушено, сумма — основным цветом. !important нужен, потому что при наведении Apex кладёт цвет
 * сегмента в style="fill" названия.
 */
.apexcharts-pie .apexcharts-datalabel-value {
    fill: currentColor !important;
}
.apexcharts-pie .apexcharts-datalabel-label {
    fill: var(--gray-500) !important;
}
.dark .apexcharts-pie .apexcharts-datalabel-label {
    fill: var(--gray-400) !important;
}
.apexcharts-pie .apexcharts-datalabels-group {
    pointer-events: none;
}

/*
 * «Топ каналов по выручке» по Парето (resources/views/filament/widgets/top-channels.blade.php): два блока рядом —
 * «Основные» и «Остальные», каждый с заголовком, кольцом и полным списком под ним. На экране уже 768px блоки идут друг под другом;
 * хвост пуст — один блок на всю ширину (--single). Колонки minmax(0, 1fr): кольцо ApexCharts не растягивает колонку.
 */
.o-channel-blocks {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2rem;
    align-items: start;
}
.o-channel-blocks--single {
    grid-template-columns: minmax(0, 1fr);
}
@media (max-width: 767px) {
    .o-channel-blocks {
        grid-template-columns: minmax(0, 1fr);
    }
}
.o-channel-block {
    min-width: 0;
}
.o-channel-heading {
    margin: 0 0 0.5rem;
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.5rem;
}

/*
 * Список каналов под кольцом: кружок цвета сегмента, название, сумма, доля. Список полный, без ограничения высоты.
 * Правые края сумм и долей выровнены: доля — колонка фиксированной ширины, сумма прижата к ней вправо.
 * Наведение на строку подсвечивает сегмент кольца своего блока.
 */
.o-channel-list {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    max-width: 36rem;
    margin: 0.75rem auto 0;
}
.o-channel-row {
    display: grid;
    grid-template-columns: 0.625rem minmax(0, 1fr) auto 3.75rem;
    align-items: center;
    column-gap: 0.625rem;
    padding: 0.375rem 0.5rem;
    border-radius: 0.5rem;
    font-size: 0.875rem;
    line-height: 1.25rem;
}
.o-channel-row:hover {
    background-color: rgba(128, 128, 128, 0.12);
}
.o-channel-dot {
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 9999px;
}
.o-channel-amount,
.o-channel-share {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.o-channel-share {
    opacity: 0.6;
}

/*
 * Страница «Эффективность кабинетов» (resources/views/filament/pages/cabinet-efficiency.blade.php): три сводные
 * плитки, сетка карточек кабинетов, таблица и диаграмма. Блоки — плитки Filament section от одной левой границы,
 * цвета только через currentColor, прозрачность и переменные Filament — одинаково в светлой и тёмной теме.
 */
.o-cab-tiles,
.o-cab-cards {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
}
.o-cab-tiles > *,
.o-cab-cards > * {
    min-width: 0;
}
/* Уже 1280: плиток по две в ряд (третья плитка — во всю ширину, дыр нет), на телефоне — по одной. */
@media (max-width: 1279px) {
    .o-cab-tiles,
    .o-cab-cards {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .o-cab-tiles > :last-child:nth-child(odd) {
        grid-column: 1 / -1;
    }
}
@media (max-width: 639px) {
    .o-cab-tiles,
    .o-cab-cards {
        grid-template-columns: minmax(0, 1fr);
    }
}
.o-cab-value {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.25rem 0.5rem;
    min-width: 0;
}
.o-cab-value-text {
    min-width: 0;
    overflow-wrap: anywhere;
    font-size: 1.25rem;
    line-height: 1.75rem;
    font-weight: 600;
}
.o-cab-line {
    margin-top: 0.375rem;
    font-size: 0.875rem;
    line-height: 1.25rem;
}
.o-cab-caption {
    margin-top: 0.25rem;
    font-size: 0.8125rem;
    line-height: 1.125rem;
    opacity: 0.7;
}
.o-cab-hint {
    font-size: 0.8125rem;
    font-weight: 400;
    opacity: 0.65;
    white-space: nowrap;
}
.o-cab-block {
    display: block;
}
.o-cab-text {
    font-size: 0.875rem;
    line-height: 1.375rem;
    max-width: 80ch;
}
.o-cab-label {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    opacity: 0.6;
}
.o-cab-muted-text {
    opacity: 0.65;
}
.o-cab-card-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem 0.5rem;
    min-width: 0;
}
/* Название кабинета не растягивает карточку и ячейку таблицы: длинное обрезается многоточием (полное — в подсказке). */
.o-cab-name {
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
}
.o-cab-card-head .o-cab-name {
    flex: 0 1 auto;
    font-size: 1rem;
}
.o-cab-row-name {
    display: flex;
    align-items: center;
    gap: 0.375rem;
}
.o-cab-row-name .o-cab-name {
    min-width: 9rem;
    max-width: 18rem;
    font-weight: 500;
}
.o-cab-row-name > .fi-badge,
.o-cab-row-flags > .fi-badge {
    flex-shrink: 0;
}
/* Значки «эталон», «лидер», «мало данных» — второй строкой под названием, чтобы колонка названия не раздувала таблицу. */
.o-cab-row-flags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    margin-top: 0.25rem;
}
.o-cab-balance,
.o-cab-spend {
    margin-top: 0.875rem;
    padding-top: 0.75rem;
    border-top: 1px solid rgba(128, 128, 128, 0.2);
}
.o-cab-balance-value {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.125rem 0.5rem;
    margin-top: 0.125rem;
}
.o-cab-money {
    font-size: 1.25rem;
    line-height: 1.75rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.o-cab-spend-row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 0.25rem;
    font-size: 0.875rem;
    line-height: 1.25rem;
}
.o-cab-num {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.o-cab-change {
    opacity: 0.75;
}
.o-cab-good {
    color: var(--success-600);
}
.dark .o-cab-good {
    color: var(--success-400);
}
.o-cab-warn {
    color: var(--warning-600);
}
.dark .o-cab-warn {
    color: var(--warning-400);
}
/* Таблица: длинные заголовки переносятся на вторую строку, чтобы таблица помещалась на экране 1440; не помещается — .o-wrap прокручивает. */
.o-cab-table .o-th,
.o-cab-table .o-th-left {
    white-space: normal;
    vertical-align: bottom;
}
.o-cab-table .o-th,
.o-cab-table .o-th-left,
.o-cab-table .o-td,
.o-cab-table .o-td-left {
    padding-inline: 0.625rem;
}
.o-cab-table .o-td-left {
    vertical-align: middle;
}
.o-cab-table tbody tr.o-cab-weak > td {
    opacity: 0.55;
}
/* Значок «?» с подсказкой. */
.o-tip {
    display: inline-flex;
    vertical-align: middle;
    margin-left: 0.25rem;
    cursor: help;
    opacity: 0.6;
}
.o-tip:hover,
.o-tip:focus-visible {
    opacity: 1;
}
.o-tip-icon {
    width: 1rem;
    height: 1rem;
}
.o-cab-chart {
    width: 100%;
    max-width: 100%;
}
.o-cab-help {
    display: grid;
    gap: 0.5rem;
    max-width: 90ch;
    padding-left: 1.25rem;
    list-style: disc;
    font-size: 0.875rem;
    line-height: 1.375rem;
}

/* Текст только для программ экранного доступа и для разметки: на экране не виден (в сборку темы Filament sr-only не попал). */
.o-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/*
 * Выпадающий список с флажками (App\Filament\Schemas\Components\CheckboxDropdown, вид —
 * resources/views/filament/components/checkbox-dropdown.blade.php, решение пользователя 24.10.2026).
 * Кнопка со сводкой, стрелка, рамка и панель с поиском — штатные классы Select (fi-select-input-*, fi-dropdown-panel);
 * здесь только то, чего у Select нет: панель шириной с поле и прокручиваемый список флажков.
 */
.fi-fo-checkbox-dropdown .fi-dropdown {
    position: relative;
}
.fi-fo-checkbox-dropdown .fi-dropdown-trigger {
    display: block;
}
.fi-fo-checkbox-dropdown .fi-dropdown-panel.o-cd-panel {
    width: 100%;
    max-height: none;
}
.fi-fo-checkbox-dropdown .fi-select-input-btn:not(.fi-disabled) {
    cursor: pointer;
}
/* Кольцо при фокусе с клавиатуры на кнопке списка (как правило выше для input/select/textarea, но с большей
   специфичностью: то правило перебивается рамкой focus-within в начале файла). Касается и кнопки штатного Select. */
.fi-input-wrp:not(.fi-invalid):not(.fi-disabled):not(:has(.fi-ac-action:focus)):has(.fi-select-input-btn:focus-visible) {
    box-shadow: 0 0 0 2px rgba(128, 128, 128, 0.6) !important;
}
.fi-fo-checkbox-dropdown .fi-select-input-search-ctn {
    position: static;
}
.o-cd-actions {
    display: flex;
    justify-content: flex-end;
    padding: 0.375rem 0.75rem;
}
.o-cd-list {
    max-height: 20rem;
    overflow-y: auto;
    padding: 0.25rem;
}
.o-cd-option {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.375rem 0.5rem;
    border-radius: 0.375rem;
    font-size: 0.875rem;
    line-height: 1.5rem;
    cursor: pointer;
}
.o-cd-option:hover,
.o-cd-option:has(input:focus-visible) {
    background-color: var(--gray-50);
}
.dark .o-cd-option:hover,
.dark .o-cd-option:has(input:focus-visible) {
    background-color: rgba(255, 255, 255, 0.05);
}
.o-cd-option .fi-checkbox-input {
    flex: none;
    margin-top: 0.25rem;
}
.o-cd-option-text {
    display: grid;
    min-width: 0;
}
.o-cd-option-label {
    overflow-wrap: anywhere;
    color: var(--gray-950);
}
.dark .o-cd-option-label {
    color: #fff;
}
.o-cd-option-description {
    color: var(--gray-500);
}
.dark .o-cd-option-description {
    color: var(--gray-400);
}
.o-cd-option:has(input:disabled) {
    cursor: default;
    opacity: 0.7;
}
