/* ==============================================================================
   app/static/css/design-system.css

   Единый источник истины для токенов и компонентов кабинета (сайдбар,
   шапка, подвал, кнопки, поля форм, таблицы, карточки дашборда) — вместо
   точечных переопределений темы BootstrapDash на каждой странице отдельно
   (три предыдущих патча так и делали, и раз за разом натыкались на одни и
   те же ловушки этой темы: --bs-btn-border-radius не читается там, где тема
   задаёт border-radius напрямую; .table .btn{background} задевал элементы,
   для которых не предназначался; дублированные литералы высоты шапки
   (97px) расходились друг с другом при правке в одном месте и не в другом).

   Подключается ПОСЛЕ style.css/vendor.bundle.base.css темы. Публичный сайт
   и гостевой layout (auth_layout.html) НЕ используют .content-wrapper —
   компоненты ниже, где это важно, явно ограничены этим селектором, чтобы
   не задеть сознательно другую типографику публичных страниц (например,
   крупный герой-заголовок на главной).

   custom.css остаётся ТОЛЬКО для того, что не является токеном/компонентом
   в смысле этого файла: @font-face подключение шрифта (см. ниже — на самом
   деле тоже здесь, а не в custom.css, т.к. это часть типографической
   системы), круглая область кадрирования Cropper.js, скрытие нативного
   input[type=file]. Всё остальное, что раньше жило в custom.css
   (типографика, кнопки, поля форм, таблицы, сайдбар/шапка/подвал, баннер),
   перенесено сюда и удалено оттуда — не должно быть двух источников,
   спорящих за одно и то же свойство.
   ============================================================================== */

/* ------------------------------------------------------------------------
   ТОКЕНЫ
   ------------------------------------------------------------------------ */
:root {
    /* Цвета — палитра, уже принятая в предыдущих патчах, собрана в одном месте */
    --wod-color-primary: #1c5fc4;
    --wod-color-secondary: #495057;
    --wod-color-success: #198754;
    --wod-color-danger: #dc3545;
    --wod-color-warning: #a17700;  /* тёмно-жёлтый — чистый жёлтый текст на белом нечитаем */
    --wod-color-info: #087990;
    --wod-color-white: #ffffff;
    --wod-color-body-text: #212529;
    --wod-color-muted: #6c757d;
    --wod-color-border: #dee2e6;
    --wod-color-footer-bg: #666666;      /* 60% серого по ТЗ */
    --wod-color-sidebar-bg: #ffffff;
    /* Round 9, item 8 — фон страницы кабинета/гостевых страниц (тема
       задаёт это напрямую на body/html, style.css — здесь как токен, чтобы
       другие компоненты (напр. disabled-кнопки, Round 10 item 3) могли
       ссылаться на то же значение осознанно, а не задавать литерал заново). */
    --wod-color-page-bg: #f4f5f7;

    /* Типографика */
    --wod-font-family: 'Roboto Slab', Georgia, 'Times New Roman', serif;
    --wod-font-weight-base: 300;
    --wod-font-weight-emphasis: 600;
    --wod-font-size-base: 0.95rem;   /* тело/UI: сайдбар, карточки, таблицы, лейблы форм, кнопки */
    --wod-font-size-h1: 1.75rem;     /* заголовок страницы кабинета (один везде, где <h1>) */
    /* Round 9 (Item 4) — заголовки карточек/панелей ("Участники", "Расписание
       по дням недели", "Профиль" -> "Личные данные"/"Роли" и т.п.) раньше
       намеренно сводились к БАЗОВОМУ размеру текста (см. правило ниже до
       этого раунда) — только жирнее, без реального шага по кеглю. Продукт-
       оунер попросил обратное: реальный шаг вверх, не просто насыщенность.
       1.2rem — заметно крупнее базовых 0.95rem, но явно меньше заголовка
       страницы (--wod-font-size-h1, 1.75rem), не конкурирует с ним. */
    --wod-font-size-card-heading: 1.2rem;

    /* Шкала отступов (4/8/12/16/24/32) */
    --wod-space-1: 4px;
    --wod-space-2: 8px;
    --wod-space-3: 12px;
    --wod-space-4: 16px;
    --wod-space-6: 24px;
    --wod-space-8: 32px;
    /* Round 9 (Item 5) — буквально "1см" (не подобранный пиксель): физическая
       единица CSS, конвертируется в px предсказуемо одинаково при любом DPI/
       масштабе браузера — та же причина, по которой это ТЗ просило именно
       эту единицу, а не число из шкалы выше. */
    --wod-space-1cm: 1cm;

    /* Форма компонентов */
    --wod-radius: 4px;
    --wod-border-width: 1px;

    /* Геометрия сайдбара/шапки — темы завязывает ширину сайдбара сразу в
       нескольких местах (.navbar-brand-wrapper, .main-panel,
       .navbar-menu-wrapper, мобильный .sidebar-offcanvas) — одна переменная
       вместо повторяющегося литерала в каждом месте. */
    /* Round 4, п.3 — сужено с прежних 280px: правый отступ после самого
       длинного пункта меню ("На сайт клуба", правый край текста на x=174 при
       старой ширине 280 — измерено) должен визуально равняться левому
       отступу до колонки иконок (20px). 174+20=194 — измерено и посчитано,
       не подобрано на глаз. */
    /* Round 5, п.4 — снова увеличено. Меряется по ТЕКСТУ, не по колонке
       иконок: левый "воздух" теперь = расстояние от края страницы до
       начала САМОГО ТЕКСТА (не иконки) — измерено 68px (20 отступ + 28
       иконка + 20 отступ иконка->текст), не изменилось.
       Round 7, п.1 — самый длинный пункт сократился: "На сайт клуба" ->
       "Сайт клуба" (переименован в этом же раунде), а "Участники"
       (правый край 151) больше не самый длинный — теперь это "Сайт клуба"
       (правый край текста x=153, измерено заново, не по аналогии). Правый
       "воздух" должен совпадать с левым: 153+68=221. */
    --wod-sidebar-width: 221px;
    --wod-sidebar-width-collapsed: 70px;
    /* Round 5, п.2 — уменьшено со 112 до 104: шапка должна заканчиваться
       ровно по нижнему краю логотипа (96px), без "мёртвого" пространства
       под ним. padding-top логотипа остаётся 8px (--wod-space-2),
       padding-bottom убран (см. .navbar-brand-wrapper ниже) — 8+96+0=104. */
    --wod-navbar-height: 104px;
    --wod-menu-icon-size: 28px;
    /* Round 6, п.1: ОДИН токен вместо двух — раньше раздельная калибровка
       под flex/block-раскладку (0px развёрнуто / 2px свёрнуто) была именно
       тем источником дрейфа, который просили прекратить. Теперь оба
       состояния — один и тот же режим раскладки (.nav-link всегда flex, см.
       .menu-icon/.nav-link ниже), поэтому один и тот же отступ подходит
       обоим по построению, а не по совпадению. Значение — эталон "свёрнутое
       состояние" (было верным по отзыву продукт-оунера), 2px. */
    --wod-sidebar-nav-top-offset: 2px;
}

/* ------------------------------------------------------------------------
   ШРИФТ: Roboto Slab 300, самостоятельный хостинг (app/static/fonts/RobotoSlab/,
   4 unicode-range подмножества — полный набор кириллицы), без обращения к
   Google Fonts CDN в рантайме.
   ------------------------------------------------------------------------ */
@font-face {
    font-family: 'Roboto Slab';
    font-style: normal;
    font-weight: 300;
    font-display: swap;
    src: url('../fonts/RobotoSlab/roboto-slab-v36-cyrillic-ext-300.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: 'Roboto Slab';
    font-style: normal;
    font-weight: 300;
    font-display: swap;
    src: url('../fonts/RobotoSlab/roboto-slab-v36-cyrillic-300.woff2') format('woff2');
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-family: 'Roboto Slab';
    font-style: normal;
    font-weight: 300;
    font-display: swap;
    src: url('../fonts/RobotoSlab/roboto-slab-v36-latin-ext-300.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;
}
@font-face {
    font-family: 'Roboto Slab';
    font-style: normal;
    font-weight: 300;
    font-display: swap;
    src: url('../fonts/RobotoSlab/roboto-slab-v36-latin-300.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;
}

/* ------------------------------------------------------------------------
   ТИПОГРАФИКА
   ------------------------------------------------------------------------ */
/* Round 5 — сведение к универсальному правилу вместо перечня селекторов.
   Три предыдущих раунда чинили один и тот же класс бага точечно (таблица,
   <p>, теперь ещё и .footer с прямым font-family:"Manrope" в теме,
   style.css:21455 — обнаружено этим раундом полным граппом по font-family
   во всём style.css, не точечной проверкой) — у темы то тут, то там есть
   прямое свойство на КОНКРЕТНОМ элементе, и список "давайте перечислим все
   такие элементы" каждый раз оказывается неполным. Универсальный селектор
   `*` внутри .container-scroller гарантированно перекрывает вообще любой
   такой элемент разом, включая ещё не найденные. Безопасно для MDI-иконок:
   их шрифт задаётся темой на псевдоэлементе ::before (см.
   vendors/mdi/css/materialdesignicons.min.css), `*` его не затрагивает. */
html, body,
.container-scroller, .container-scroller * {
    font-family: var(--wod-font-family) !important;
}
body {
    font-size: var(--wod-font-size-base);
    font-weight: var(--wod-font-weight-base);
}
/* Round 7, п.5/7 — реальный баг, найден граппом по style.css: тема задаёт
   `body, html { background: #F4F5F7 }` (style.css:21301-21306) БЕЗ привязки
   к кабинету — этот же файл подключён и на гостевом layout (вход, выбор
   роли), поэтому обе страницы получали фирменный серый фон темы вместо
   собственного чистого/светлого фона, отсюда и ощущение "совсем без
   стилей". auth_layout.html теперь ставит класс auth-guest на html/body
   специально для этого переопределения. */
html.auth-guest, body.auth-guest {
    background: #f8f9fa !important;
}
h1, h2, h3, h4, h5, h6 {
    font-weight: var(--wod-font-weight-base);
}
/* Один размер заголовка страницы кабинета — независимо от того, какой
   Bootstrap-класс размера (h3/h4/h6) ещё висит на теге в конкретном
   шаблоне; используйте семантический <h1>, класс размера не имеет значения. */
.content-wrapper h1, .content-wrapper .h1 {
    font-size: var(--wod-font-size-h1) !important;
}
/* Round 9 (Item 4) — заголовки внутри карточек/разделов: реальный шаг вверх
   по кеглю (--wod-font-size-card-heading), не только насыщенность (было
   сведено к БАЗОВОМУ размеру — обратный порядок, см. комментарий у токена
   в :root).
   .wod-panel-heading — тот же визуал, но КЛАССОМ, не тегом+контекстом — для
   мест, где заголовок должен выглядеть так же, но структурно не является
   <h2..h6> внутри .card (напр. имя атлета на его дашборде, athlete/dashboard.html). */
.content-wrapper .card h2, .content-wrapper .card h3, .content-wrapper .card h4,
.content-wrapper .card h5, .content-wrapper .card h6,
.content-wrapper > h2, .content-wrapper > h3,
.content-wrapper .wod-panel-heading {
    font-size: var(--wod-font-size-card-heading) !important;
    font-weight: var(--wod-font-weight-emphasis) !important;
}
/* Item 5 — отступ СНИЗУ (1см) между заголовком и контентом сразу под ним:
   только настоящие заголовки-над-контентом (h2..h6 внутри .card). НЕ на
   .wod-panel-heading — там заголовок стоит РЯДОМ с элементом (статус-точка
   атлета в одной строке), а не НАД контентом; margin-bottom сдвинул бы его
   текст вверх относительно соседа при align-items:center на общем flex-ряду. */
.content-wrapper .card h2, .content-wrapper .card h3, .content-wrapper .card h4,
.content-wrapper .card h5, .content-wrapper .card h6,
.content-wrapper > h2, .content-wrapper > h3 {
    margin-bottom: var(--wod-space-1cm) !important;
}
/* Round 9 (Item 5) — "дыхание" вокруг САМОСТОЯТЕЛЬНОЙ кнопки-действия на
   карточке (напр. "+ Добавить день", "Сгенерировать" — кнопка как последний
   смысловой элемент карточки, а не кнопка в строке тулбара/формы рядом с
   другими полями, см. применение класса в шаблонах — там же объяснение,
   почему НЕ все кнопки в карточках получили этот класс). */
.wod-card-action-btn {
    display: inline-block;
    margin-top: var(--wod-space-1cm) !important;
    margin-bottom: var(--wod-space-1cm) !important;
}
.sidebar .nav .nav-item .nav-link .menu-title,
.table, .form-label, .form-control, .form-select, .btn {
    font-size: var(--wod-font-size-base) !important;
}
/* Тема задаёт голому <p> font-size:0.812rem НАПРЯМУЮ (style.css:21074) — тот
   же класс бага, что и у .table th/td выше: явное правило на самом элементе
   не даёт унаследовать размер от body, сколько бы !important на body ни
   было. Round 4, п.9 — обнаружено измерением (карточка участника, карточка
   "Отсутствие" и т.д. везде оказывались мельче базового токена). Только
   .content-wrapper (кабинет) — паблик-сайт использует свою типографику. */
.content-wrapper p {
    font-size: var(--wod-font-size-base) !important;
}
/* font-size на .table (элемент <table>) не наследуется сквозь !important —
   тема задаёт СВОЙ явный font-size прямо на .table thead th (0.875rem) и
   .table td (0.812rem), явное правило на потомке всегда побеждает
   унаследованное значение родителя независимо от !important на родителе.
   Обнаружено измерением (Playwright): th/td оставались 14px/12.99px вместо
   ожидаемых 15.2px. Нужно явное правило на самих th/td. */
.table th, .table td {
    font-size: var(--wod-font-size-base) !important;
}

/* ------------------------------------------------------------------------
   КНОПКИ — единственный путь стилизации кнопок в приложении. Стандартные
   Bootstrap-классы (btn btn-primary, btn btn-outline-danger, btn-sm и т.д.)
   остаются разметкой — здесь переопределяется, как ИМЕННО они выглядят,
   в одном месте, а не по одной кнопке на каждой странице.

   Контур (прозрачный/белый фон, рамка+текст цветом семантики), прямоугольник
   со скруглением var(--wod-radius) — НЕ через переменную --bs-btn-border-radius
   (тема задаёт border-radius НАПРЯМУЮ на .btn.btn-sm, минуя эту переменную
   полностью — единственный рабочий способ здесь — прямое свойство с
   !important; см. ARCHITECTURE.md, раздел про эту ловушку).
   ------------------------------------------------------------------------ */
/* :not(.absence-status-dot) — иначе этот блок (в частности padding и
   border-radius) бьёт по кружку статуса отсутствия в таблице участников:
   он тоже .btn (см. users_list.html), но должен остаться маленьким цветным
   кругом (inline style border-radius:50%, 16x16), а не обычной прямоугольной
   кнопкой с паддингами. Найдено скриншотом headless-браузера — кружки
   рендерились скруглёнными прямоугольниками вместо кругов. */
/* Round 5 — реальный (и серьёзный) баг: --wod-btn-color по умолчанию раньше
   жил ВНУТРИ .btn:not(.absence-status-dot) — а :not() поднимает
   специфичность блока выше, чем у одного класса (0,2,0 против 0,1,0),
   поэтому этот "дефолт на синий" побеждал .btn-outline-danger/-secondary/
   -success и т.д. ВЕЗДЕ в приложении (не только в баннере — измерено:
   "Деактивировать", "Изменить", "Отмена", кнопка баннера — вообще ЛЮБАЯ
   кнопка не btn-primary рендерилась синей). Вынесено в отдельное правило
   БЕЗ :not() — та же специфичность (0,1,0), что у .btn-outline-danger и
   остальных вариантов ниже, поэтому побеждает уже порядок в файле (variant-
   правила идут ниже) — как и было задумано изначально. */
.btn {
    --wod-btn-color: var(--wod-color-primary);
}
.btn:not(.absence-status-dot) {
    font-family: var(--wod-font-family) !important;
    font-size: var(--wod-font-size-base) !important;
    font-weight: 400 !important;
    padding: var(--wod-space-1) var(--wod-space-3) !important;
    border-radius: var(--wod-radius) !important;
    border-width: var(--wod-border-width) !important;
    line-height: 1.5 !important;
}
.btn-primary, .btn-outline-primary, .btn-wod { --wod-btn-color: var(--wod-color-primary); }
.btn-secondary, .btn-outline-secondary { --wod-btn-color: var(--wod-color-secondary); }
.btn-success, .btn-outline-success { --wod-btn-color: var(--wod-color-success); }
.btn-danger, .btn-outline-danger { --wod-btn-color: var(--wod-color-danger); }
.btn-warning, .btn-outline-warning { --wod-btn-color: var(--wod-color-warning); }
.btn-info, .btn-outline-info { --wod-btn-color: var(--wod-color-info); }

.btn-primary, .btn-secondary, .btn-success, .btn-danger, .btn-warning, .btn-info, .btn-wod,
.btn-outline-primary, .btn-outline-secondary, .btn-outline-success, .btn-outline-danger,
.btn-outline-warning, .btn-outline-info {
    background-color: transparent !important;
    border-color: var(--wod-btn-color) !important;
    color: var(--wod-btn-color) !important;
}
.btn-primary:hover, .btn-secondary:hover, .btn-success:hover, .btn-danger:hover,
.btn-warning:hover, .btn-info:hover, .btn-wod:hover,
.btn-outline-primary:hover, .btn-outline-secondary:hover, .btn-outline-success:hover,
.btn-outline-danger:hover, .btn-outline-warning:hover, .btn-outline-info:hover {
    background-color: var(--wod-btn-color) !important;
    color: var(--wod-color-white) !important;
}
/* Кнопки на белых/светлых поверхностях (таблицы/карточки/toast/модалки) —
   фон именно белый, не "transparent" (иначе просвечивает table-striped).
   Кружок статуса отсутствия (.absence-status-dot) — тоже .btn внутри
   .table, но это цветной индикатор (зелёный/жёлтый/красный), не обычная
   кнопка — исключён отовсюду, где это правило задавало бы ему белый фон
   или прямоугольное скругление вместо круга.
   Round 5, п.9 — РЕАЛЬНЫЙ баг: :not(:hover) добавлен, т.к. это правило и
   hover-инверт выше (строка ~264) имели РАВНУЮ специфичность (оба 0,2,0) —
   при равной специфичности побеждает то, что позже в файле, а это правило
   идёт позже. В результате при наведении текст белел (hover-правило для
   color сработало), а фон оставался белым (это правило продолжало
   принудительно держать white) — белый текст на белом фоне, невидимо.
   Измерено: kнопка "Выбрать" (аватар) — color:255,255,255 bg:255,255,255
   одновременно на hover. :not(:hover) убирает конфликт: во время hover
   это правило больше не участвует, фон свободно берёт цвет из инверт-правила.

   Шаг 5, Часть 3 — РЕАЛЬНЫЙ баг, найден при добавлении "чёрного" статуса:
   ветка .card .btn:not(:hover) НЕ имела исключения :not(.absence-status-dot)
   (в отличие от соседней .table-ветки, у которой оно есть) — на странице
   секции (admin/_athlete_roster.html) точка статуса живёт ВНУТРИ .card
   ("Участники секции"), поэтому !important здесь ПЕРЕБИВАЛ инлайновый
   background цветного кружка через .card-ветку, даже когда .table-ветка его
   корректно исключала — кружок был белым (невидимым) на белой карточке
   всегда, только на этой странице (на users_list.html, где таблица не
   обёрнута в .card, баг не проявлялся). Добавлено то же исключение сюда. */
.table .btn:not(.absence-status-dot):not(:hover), .card .btn:not(.absence-status-dot):not(:hover),
.toast .btn:not(:hover), .modal .btn:not(:hover) {
    background-color: var(--wod-color-white) !important;
}
/* Round 10, item 3 — единый стиль disabled-кнопки на весь сайт: раньше не
   было вообще никакого явного правила, кнопка просто тускнела через
   стандартный Bootstrap opacity:0.65 поверх своего обычного цвета
   семантики (напр. "Вставить" при пустом буфере — синяя, но полупрозрачная).
   ТЗ: фон = фон страницы (не белый), текст/рамка — тёмно-серые (не цвет
   семантики кнопки притушенный). Побеждает варианты выше по специфичности
   (0,2,0, как и они) и по порядку (идёт позже в файле). opacity:1 явно —
   иначе Bootstrap-дефолт (0.65) продолжает притушивать уже заданные здесь
   цвета поверх этого правила. */
/* Специфичность (0,2,0) правила .btn:disabled ниже, чем у .card .btn:not(:hover)
   и аналогичных выше (0,3,0, см. их комментарий про :not(:hover)) — без
   явного повтора тех же контекстов здесь белый фон "карточки"/"таблицы"
   победил бы (найдено живой проверкой: disabled-кнопка оставалась белой,
   не серо-фоновой). Те же контексты, что и там, + сам .btn:disabled общим
   случаем. */
.table .btn:disabled, .table .btn.disabled,
.card .btn:disabled, .card .btn.disabled,
.toast .btn:disabled, .toast .btn.disabled,
.modal .btn:disabled, .modal .btn.disabled,
.btn:disabled, .btn.disabled {
    background-color: var(--wod-color-page-bg) !important;
    border-color: var(--wod-color-secondary) !important;
    color: var(--wod-color-secondary) !important;
    opacity: 1 !important;
}
/* Round 4, п.10 — вертикальное совпадение с cap-height заглавной буквы
   подписи (не просто "на глаз по центру бокса кнопки"). Измерено Range API
   (реальный прямоугольник буквы "С" в "Список" против bbox иконки): при
   -0.15em иконка была на 1.89px ниже центра буквы; -0.03em — 0.03px
   расхождения (де-факто точное совпадение), см. отчёт коммита. */
.btn i, .btn .mdi {
    font-size: 1rem;
    vertical-align: -0.03em;
    /* Round 4, п.11 — БЕЗ этого кнопки с иконкой (Список/Выйти/фильтры)
       рендерились на 1.2px выше кнопок без иконки, при абсолютно ОДИНАКОВЫХ
       computed padding/line-height/border-width на самой кнопке — у
       шрифта иконки (MDI) свои внутренние метрики line-height, "протекающие"
       в высоту строчного бокса вокруг него, даже когда line-height задан на
       родителе. line-height:1 на самой иконке убирает этот вклад. */
    line-height: 1;
}

/* ------------------------------------------------------------------------
   ПОЛЯ ФОРМ — единый размер/паддинг/скругление + принудительно светлый select
   (тема местами протекает тёмной палитрой в стандартный <select> — было
   отдельным переопределением, теперь часть той же системы).
   ------------------------------------------------------------------------ */
.form-control, .form-select {
    border-radius: var(--wod-radius) !important;
    border-width: var(--wod-border-width) !important;
    padding: var(--wod-space-1) var(--wod-space-2) !important;
    font-size: var(--wod-font-size-base) !important;
    /* Round 5, п.10 — реальный баг, тот же паттерн задвоенного правила темы,
       что и у .form-check/.footer/<p> ранее: у темы есть СВОЙ .form-select
       (style.css:25950) с явным height:2.75rem (44px) — раньше это правило
       ничем не перекрывалось (только min-height, а явный height всегда
       побеждает min-height, если он больше). Из-за этого select оказывался
       на 11.2px выше соседней инлайн-кнопки ("+" рядом с "Ответственное
       лицо" на Площадках) — измерено: 44px против 32.8px у кнопки. Теперь
       явный height (не min-height) той же формулой, что даёт 32.8px у
       кнопок (см. .btn) — гарантированно совпадает. */
    height: calc(1.5em + var(--wod-space-2) + 2px) !important;
}
select,
select.form-select,
select.form-control {
    background-color: var(--wod-color-white) !important;
    color: var(--wod-color-body-text) !important;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e") !important;
    background-repeat: no-repeat;
    background-position: right var(--wod-space-2) center;
    background-size: 16px 12px;
}
select option {
    background-color: var(--wod-color-white);
    color: var(--wod-color-body-text);
}
/* Round 5, п.6 — реальный баг: у темы есть СВОЙ, полностью отдельный от
   Bootstrap .form-check (style.css:25468, изначально под "todo list"
   виджет) с padding-left:0 (у Bootstrap — 1.5em) и font-size:0.812rem на
   .form-check-label — оба правила позже в файле, чем оригинальные
   Bootstrap-версии, поэтому побеждают. padding-left:0 без соответствующего
   отступа ломает checkbox: инпут (margin-left:-1.5em от Bootstrap,
   рассчитан на то, что контейнер даёт эти 1.5em отступа) вылезает на 22.8px
   левее границы контейнера — в модалке это заезжает за левый край. */
.form-check {
    padding-left: 1.5em !important;
}
.form-check .form-check-input {
    margin-left: -1.5em !important;
}
/* Round 7, п.2 — ещё один остаток того же "todo list"-виджета темы (см.
   комментарий выше): .form-check .form-check-label { margin-left: 1.75rem }
   (style.css:25476) — рассчитан на СВОЮ разметку (input ВНУТРИ label,
   позиционирован absolute), а не на стандартную Bootstrap-структуру
   (input и label — соседние элементы). У нас уже есть компенсирующий
   padding-left на .form-check (см. выше) — этот margin-left поверх него
   просто задваивал отступ (замерено: 35.6px между чекбоксом и текстом
   вместо ожидаемых ~8px). */
.form-check-label {
    font-size: var(--wod-font-size-base) !important;
    margin-left: 0 !important;
}

/* Round 5, п.7 — точка статуса отсутствия для ролей, которым это не
   отслеживается (не athlete/coach): то же место в таблице, тот же диаметр
   (16px), но контур вместо заливки — визуально отличимо от "в строю"
   (зелёная заливка), не кликабельно (не .btn, не absence-status-dot). */
/* Round 9 (rollback) — атлет больше не меняет свой статус сам: точка на его
   собственном дашборде теперь простой <span>, не <button> (см.
   athlete/dashboard.html). display:inline-block нужен явно — иначе inline
   <span> игнорирует width/height из инлайн-style. У версии-<button>
   (админские таблицы) то же самое уже даёт .btn, здесь дублировать не
   вредно — одно и то же значение. */
.absence-status-dot {
    display: inline-block;
}
.absence-status-ring {
    display: inline-block;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: transparent;
    border: 2px solid var(--wod-color-success);
    box-sizing: border-box;
}

/* ------------------------------------------------------------------------
   ТАБЛИЦЫ — единый размер текста заголовков/ячеек (тот же токен, что и
   сайдбар — раньше таблицы были намеренно чуть меньше, явно убрано).
   ------------------------------------------------------------------------ */
.table > :not(caption) > * > * {
    padding: var(--wod-space-1) var(--wod-space-2);
}
.badge.text-bg-success {
    color: var(--wod-color-white) !important;
}
/* Round 9 (Part D) — тема (style.css) задаёт .badge{font-size:12px}, тогда
   как всё остальное в строке (кнопки, лейблы, ячейки таблиц) уже приведено
   к единому базовому токену — бейджи оставались заметно мельче соседей
   (измерено: пилюля "Тренеров Т." 12px/27px против кнопки "Добавить"
   15.2px/32.8px в той же строке). Тот же приём, что и везде в этом файле. */
.badge {
    font-size: var(--wod-font-size-base) !important;
}
/* Тот же баг класса, что уже был найден и пофикшен выше для .text-bg-success:
   тема прибивает .text-bg-secondary к чёрному тексту. Важно для кликабельного
   бейджа "Отменена" (восстановление тренировки, Part D) — обязан быть
   читаемым на сером фоне secondary. */
.badge.text-bg-secondary {
    color: var(--wod-color-white) !important;
}
/* Кликабельный бейдж как <button> (напр. "Отменена" -> восстановление) —
   снимает нативный хром кнопки (рамка/фон браузера), badge-классы уже дают
   весь визуал; курсор явно, раз это интерактивный элемент. */
button.badge {
    border: none;
    cursor: pointer;
}
/* Пилюли бейдж-пикера (badge_picker.js — "Тренеры секции" и другие инстансы)
   — паддинг/line-height подогнаны под соседний .btn-sm в той же строке
   (space-1/space-3, line-height 1.5 — те же значения, что у .btn выше),
   чтобы высота совпадала, а не просто шрифт. */
.badge-picker-pill {
    padding: var(--wod-space-1) var(--wod-space-3) !important;
    line-height: 1.5 !important;
}
/* Round 10, item 6 — поле бейдж-пикера ("Тренеры секции" и другие инстансы,
   см. badge_picker.js) раньше было просто <div> без рамки/фона — на карточке
   выглядело как "плавающий" контент, не как поле ввода. Та же рамка/фон/
   радиус, что у .form-control/.form-select (design-system.css выше) — не
   высота (у неё динамическое содержимое — пилюли переносятся на несколько
   строк), только видимая "оболочка" поля. */
.badge-picker-field {
    background-color: var(--wod-color-white) !important;
    border: var(--wod-border-width) solid var(--wod-color-border) !important;
    border-radius: var(--wod-radius) !important;
    padding: var(--wod-space-2) !important;
}
/* Round 10, item 4 — выбранная строка таблицы участников (чекбокс отмечен)
   подсвечивается серым, пока не завершится действие (cut/copy -> paste,
   remove) — тот же токен рамки (--wod-color-border), уже используемый как
   "нейтральный серый" по всему дизайн-системе. */
.athlete-row.is-selected {
    background-color: var(--wod-color-border) !important;
}
/* Round 9 (Part D) — убрана горизонтальная линия под заголовками колонок
   "Расписание по дням недели" (тема задаёт border-bottom на .table thead th
   независимо от общих правил .table выше). */
#scheduleTable thead th {
    border-bottom: none !important;
}
.table .text-success {
    font-size: 1.3rem;
    font-weight: 700;
    line-height: 1;
}
.table td.avatar-cell {
    padding-top: 0 !important;
    padding-bottom: 0 !important;
}
.table td.avatar-cell img {
    width: 40px !important;
    height: 40px !important;
}
/* Round 7, п.3 — на table-striped+table-hover перекрашивались при наведении
   только БЕЛЫЕ строки полосы (серые от Bootstrap-переменной прятались под
   уже применённым фоном table-striped) — визуально мерцание/непоследовательно.
   Полосатость сама по себе достаточна как визуальный ориентир — весь
   hover-эффект отключён на таких таблицах через переменную Bootstrap
   (--bs-table-hover-bg), а не борьбой за специфичность. */
.table-striped.table-hover {
    --bs-table-hover-bg: transparent;
}

/* ------------------------------------------------------------------------
   САЙДБАР И ШАПКА
   ------------------------------------------------------------------------ */
.navbar .navbar-brand-wrapper,
.sidebar {
    width: var(--wod-sidebar-width) !important;
}
.main-panel,
.navbar .navbar-menu-wrapper {
    width: calc(100% - var(--wod-sidebar-width)) !important;
    /* Round 5, п.3 — гамбургер живёт внутри .navbar-menu-wrapper и раньше
       (Round 4) был вынесен в position:fixed на один жёстко заданный x,
       чтобы не прыгать при сворачивании — по новому ТЗ он ДОЛЖЕН ехать
       вместе с границей контента (левым краем этого блока), просто плавно,
       а не мгновенным прыжком. Возврат к обычному потоку (без
       position:fixed, см. .navbar-toggler ниже) + переход по width здесь —
       даёт ровно это: гамбургер снова обычный flex-child, а его видимое
       движение синхронно со сворачиванием сайдбара (та же длительность,
       что и у .sidebar/.navbar-brand-wrapper). */
    transition: width 0.25s ease !important;
}
@media (min-width: 992px) {
    .sidebar-icon-only .navbar .navbar-brand-wrapper,
    .sidebar-icon-only .sidebar {
        width: var(--wod-sidebar-width-collapsed) !important;
    }
    .sidebar-icon-only .main-panel,
    .sidebar-icon-only .navbar .navbar-menu-wrapper {
        width: calc(100% - var(--wod-sidebar-width-collapsed)) !important;
    }
}
@media (max-width: 991px) {
    .sidebar-offcanvas {
        right: calc(-1 * var(--wod-sidebar-width)) !important;
    }
}

/* Логотип — реальные 96px (тема задаёт .navbar-brand img: height:34px
   напрямую, той же длины селектор + !important побеждает гарантированно). */
.navbar .navbar-brand-wrapper .navbar-brand.brand-logo img {
    height: 96px !important;
    width: auto !important;
    max-width: none !important;
}
.navbar .navbar-brand-wrapper {
    height: var(--wod-navbar-height) !important;
    padding-top: var(--wod-space-2) !important;
    /* Round 5, п.2 — было var(--wod-space-2) (8px), теперь 0: шапка должна
       заканчиваться ровно по нижнему краю логотипа, без "воздуха" под ним.
       8(top) + 96(лого) + 0(bottom) = 104 = --wod-navbar-height. */
    padding-bottom: 0 !important;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Round 5 — реальный баг, найденный полным граппом по фону, не
       догадкой: тема задаёт .navbar-brand-wrapper { background: #F4F5F7 }
       (серый) напрямую (style.css:28819), а override на белый фон был
       раньше только внутри @media(min-width:992px) .sidebar-icon-only —
       то есть работал ТОЛЬКО в свёрнутом состоянии. В развёрнутом
       состоянии этого правила не было вообще — серый блок под логотипом
       был не визуальным глюком, а буквально недостающим правилом. */
    background: var(--wod-color-sidebar-bg) !important;
    /* Round 5, п.3 — было `transition: background` (БЕЗ width) — тогда
       ширина .navbar-brand-wrapper менялась мгновенно, а не плавно.
       Изначально (до появления двух отдельных файлов лого) это делалось
       намеренно: единственный логотип масштабировался пропорционально
       ширине контейнера и "плющился" при плавном сужении. Сейчас — два
       отдельных <img>, каждый со своим фиксированным px-размером
       (.brand-logo/.brand-logo-mini, дискретное display:none/flex
       переключение) — ни один из них больше не завязан на ширину
       контейнера, плющить нечего. Мгновенная ширина контейнера, однако,
       была и причиной того, что гамбургер (flex-сосед .navbar-menu-wrapper,
       чья левая граница = правая граница этого блока) прыгал вместо того
       чтобы плавно ехать вместе с сайдбаром (п.3 ТЗ) — возвращаем width в
       transition, теперь безопасно. */
    transition: width 0.25s ease, background 0.25s ease !important;
}
.navbar .navbar-menu-wrapper {
    height: var(--wod-navbar-height) !important;
    padding-top: 0 !important;
    padding-bottom: 0 !important;
}

/* Логотип свёрнутого состояния — Round 4, п.1: раньше был по высоте (1.5x
   иконки меню = 42px), что оставляло колонку сильно недозаполненной по
   ширине (сама картинка занимала только 33px из доступных 70px). Теперь
   МАКСИМУМ по ширине — измерено: колонка 70px, оставляем по 8px (токен
   --wod-space-2) с каждой стороны -> 54px. Высота считается пропорционально
   (естественное соотношение сторон файла logo_v.png — 390x494), auto. */
.navbar .navbar-brand-wrapper .brand-logo-mini img {
    width: calc(var(--wod-sidebar-width-collapsed) - (var(--wod-space-2) * 2)) !important;
    height: auto !important;
    max-width: none !important;
}

.sidebar {
    background: var(--wod-color-sidebar-bg) !important;
    /* min-height:100% (не calc(100vh - Npx)) — сайдбар растягивается на
       реальную высоту страницы через flex-stretch родителя
       .page-body-wrapper, а не на высоту вьюпорта: на любой странице
       длиннее экрана белый фон раньше обрывался на границе экрана. */
    min-height: 100%;
}
.page-body-wrapper {
    min-height: calc(100vh - var(--wod-navbar-height)) !important;
    padding-top: var(--wod-navbar-height) !important;
}
.main-panel {
    min-height: calc(100vh - var(--wod-navbar-height)) !important;
}
@media (max-width: 991px) {
    .sidebar-offcanvas {
        max-height: calc(100vh - var(--wod-navbar-height)) !important;
        top: var(--wod-navbar-height) !important;
    }
}

/* Иконки меню — Round 6, п.1: СТРУКТУРНАЯ переделка, не очередная калибровка
   чисел. Раньше по свёрнутому/развёрнутому состоянию у иконки был РАЗНЫЙ
   режим раскладки — тема переключает .nav-link display:flex (развёрнуто) на
   display:block + text-align:center (свёрнуто, .sidebar-icon-only), а
   .menu-title — display:none. У flex и block разная метрика "естественной
   надбавки" глифа MDI (измерено в Round 5: 28.19px зазор между иконками при
   одном padding в flex, ~22.5px при том же padding в block) — именно
   поэтому три раунда подряд калибровка "уезжала": считали два РАЗНЫХ числа
   для двух РАЗНЫХ режимов раскладки одного и того же визуального элемента.

   Фикс — не число, а раскладка: .nav-link ВСЕГДА display:flex (отменяем
   переключение темы на block/center в свёрнутом состоянии), иконка — flex-
   item с фиксированной шириной (flex:0 0 28px) и фиксированным padding-left
   у .nav-link (20px в обоих состояниях) — раз оба состояния теперь один и
   тот же режим раскладки (flex) с одним и тем же отступом слева, позиция
   иконки (и по X, и по Y — паддинг-формула теперь тоже одна) идентична и
   статична в обоих состояниях, её вообще не нужно калибровать раздельно.
   .menu-title — flex-item, который сжимается до width:0/opacity:0 в
   свёрнутом состоянии (см. ниже) вместо мгновенного display:none — именно
   ЭТА часть анимируется при сворачивании, не позиция иконки. */
.sidebar .nav .nav-item .nav-link {
    display: flex !important;
    align-items: center !important;
    padding-left: 20px !important;
    padding-right: 20px !important;
    /* Единая формула (была рассчитана отдельно для flex/block — теперь один
       режим раскладки, одно число): 12.5+12.5 паддинга + ~3.19px
       "естественной надбавки" глифа MDI (line-height:1 её не убирает, это
       не эффект line-height, а метрики контура символа) = зазор между
       соседними иконками 28.19px ≈ 28px (высота иконки, п.1 ТЗ). */
    padding-top: 12.5px !important;
    padding-bottom: 12.5px !important;
}
.sidebar .nav .nav-item .nav-link i.menu-icon {
    font-size: var(--wod-menu-icon-size) !important;
    line-height: 1;
    /* Фиксированная колонка — icon.left = sidebarLeft(0) + padding-left(20),
       не зависит от того, свёрнут сайдбар или нет, и не зависит от того,
       есть ли рядом видимый .menu-title (иконка идёт в разметке ПЕРЕД
       текстом, flex не сдвигает более ранний элемент из-за состояния
       более позднего). */
    flex: 0 0 var(--wod-menu-icon-size);
    width: var(--wod-menu-icon-size);
    text-align: center;
    margin-right: 20px !important;
    /* Round 7, п.1 — та же природа бага, что чинили в Round 6 для позиции
       иконки: тема задаёт РАЗНЫЙ цвет иконки на разных селекторах для
       развёрнутого (.menu-icon{color:#484848}, style.css:28526 — тёмно-серый)
       и свёрнутого состояния (.sidebar-icon-only ...menu-icon{color:rgba(31,
       59,179,.7)}, style.css:30146 — синий) — ровно поэтому иконка казалась
       синей свёрнутой и чёрной развёрнутой. Один явный цвет, без привязки к
       состоянию, тем же принципом "не тюнить два числа для одного элемента". */
    color: var(--wod-color-primary) !important;
}
.sidebar .nav .nav-item .nav-link .menu-title {
    font-size: var(--wod-font-size-base) !important;
    white-space: nowrap;
    overflow: hidden;
    flex: 1 1 auto;
    opacity: 1;
    transition: opacity 0.15s ease, width 0.15s ease;
    /* Round 7, п.1 — подпись пункта меню теперь того же синего цвета и
       насыщенности, что и иконка рядом. */
    color: var(--wod-color-primary) !important;
    font-weight: var(--wod-font-weight-emphasis) !important;
}
@media (min-width: 992px) {
    /* Тема переключает .nav-link на block/center и .menu-title на
       display:none в этом же брейкпоинте — display:none мгновенный (не
       анимируется), поэтому отменяем оба и заменяем на width/opacity-переход
       у .menu-title (см. transition выше) — это и есть "анимируется ТОЛЬКО
       текстовая часть", а не иконка (п.1 ТЗ). */
    .sidebar-icon-only .sidebar .nav .nav-item .nav-link {
        display: flex !important;
        text-align: left !important;
        padding-left: 20px !important;
        padding-right: 20px !important;
    }
    .sidebar-icon-only .sidebar .nav .nav-item .nav-link .menu-title {
        display: block !important;
        width: 0 !important;
        opacity: 0 !important;
        margin: 0 !important;
        padding: 0 !important;
    }
}
/* Отступ сверху перед первым пунктом меню — Round 6, п.1: один токен, одно
   и то же значение в обоих состояниях (см. --wod-sidebar-nav-top-offset,
   раньше было раздельно откалибровано под flex/block-раскладку — теперь
   раскладка одна и та же в обоих состояниях, отдельного медиа-правила для
   свёрнутого состояния больше не нужно). */
.sidebar .nav {
    padding-top: var(--wod-sidebar-nav-top-offset);
}
@media (min-width: 992px) {
    .sidebar-icon-only .navbar .navbar-brand-wrapper {
        background: var(--wod-color-sidebar-bg) !important;
    }
    .sidebar-icon-only .sidebar {
        background: var(--wod-color-sidebar-bg) !important;
    }
}

/* Кнопка "гамбургер" — БЕЗ рамки/фона.
   Round 5, п.3 — ЯВНАЯ смена направления от Round 4: там кнопку намеренно
   зафиксировали `position: fixed` на одном x, чтобы контейнер вообще не
   двигался при сворачивании (крутилась только иконка). По новому ТЗ это
   неверно — кнопка ДОЛЖНА ехать вместе с границей контента (левым краем
   .navbar-menu-wrapper) в обоих направлениях, просто ПЛАВНО, а не прыжком.
   Возврат к обычному потоку (без position) — кнопка снова обычный
   flex-child .navbar-menu-wrapper, значит автоматически "прижата к текущей
   границе контента" в любом состоянии. Причина прежнего прыжка была не в
   самом потоковом позиционировании, а в том, что width родителя менялась
   МГНОВЕННО (класс sidebar-icon-only переключается сразу по клику, transition
   на width не было) — исправлено добавлением transition на width самого
   .navbar-menu-wrapper (см. блок "САЙДБАР И ШАПКА" выше), не убиранием
   кнопки из потока. */
.navbar .navbar-menu-wrapper .navbar-toggler {
    font-size: var(--wod-menu-icon-size) !important;
    border: 0 !important;
    background: transparent !important;
    color: var(--wod-color-secondary) !important;
    padding: 0 !important;
}
/* Bootstrap показывает свой стандартный box-shadow-"кольцо" фокуса на
   .navbar-toggler:focus (0 0 0 4px) — реальный клик мышью его тоже
   показывает (не только клавиатурная навигация), обнаружено скриншотом
   headless-браузера сразу после клика. Убираем — просили "без рамки" в
   любом состоянии, включая момент клика. */
.navbar .navbar-menu-wrapper .navbar-toggler:focus {
    box-shadow: none !important;
    outline: none !important;
}

/* Кнопка "Выйти" — чёткий контраст (контур, семантический красный), не
   сливается с остальной навигацией. */
.navbar-nav-right .nav-item form .btn.nav-link {
    color: var(--wod-color-danger) !important;
    background: transparent !important;
    border: var(--wod-border-width) solid var(--wod-color-danger) !important;
    border-radius: var(--wod-radius) !important;
    padding: var(--wod-space-1) var(--wod-space-3) !important;
    opacity: 1;
}
.navbar-nav-right .nav-item form .btn.nav-link:hover {
    background: var(--wod-color-danger) !important;
    color: var(--wod-color-white) !important;
}

/* ------------------------------------------------------------------------
   ПОДВАЛ
   ------------------------------------------------------------------------ */
.footer {
    background: var(--wod-color-footer-bg) !important;
    color: var(--wod-color-white) !important;
}
.footer span {
    color: var(--wod-color-white) !important;
    font-size: var(--wod-font-size-base) !important;
}

/* ------------------------------------------------------------------------
   БАННЕРЫ (alert-danger/warning/info/...) — тоньше, бледнее фон. Кнопка
   внутри баннера — ТА ЖЕ единая .btn-система, что и везде (контур, цвет по
   семантике), без отдельного размера/веса под баннер — иначе именно баннерная
   кнопка расходится по высоте с остальными (Round 4, п.11: высота кнопки не
   должна плавать по контексту). Раньше здесь было отдельное правило
   `.alert-danger .btn-danger` с ЗАЛИТЫМ фоном — оно било только по классу
   btn-danger (баннер на dashboard.html использовал btn-outline-danger и под
   него не попадал), из-за чего одна и та же по смыслу баннерная кнопка
   визуально расходилась между страницами (залитая на sections_list.html,
   контурная на dashboard.html) — уже сам факт двух разных классов на
   одинаковых по смыслу кнопках было ошибкой шаблона, а точечное правило под
   один из них её маскировало вместо того чтобы унифицировать. Оба шаблона
   теперь используют btn-outline-danger — точечное правило больше не нужно.
   ------------------------------------------------------------------------ */
.alert-danger {
    padding: var(--wod-space-2) var(--wod-space-4) !important;
    background-color: #fdf2f1 !important;
    border-color: #f5c6c2 !important;
}

/* ------------------------------------------------------------------------
   Item 6 (Round 9) — действия над таблицами (вырезать/скопировать/вставить/
   исключить в ростере секции, отмена/восстановление тренировки, отметка
   отсутствия) редиректят обратно на ЯКОРЬ нужной карточки/таблицы (см.
   _anchor= в app/blueprints/admin/routes.py), а не просто на URL страницы —
   иначе браузер прыгает к САМОМУ верху страницы, теряя место пользователя
   в длинной форме/списке. scroll-margin-top нужен явно: фиксированная шапка
   (.navbar, fixed-top) иначе перекрывает верх карточки при переходе по якорю.
   ------------------------------------------------------------------------ */
[id].wod-scroll-anchor {
    scroll-margin-top: calc(var(--wod-navbar-height) + var(--wod-space-4));
}

/* ------------------------------------------------------------------------
   Обратные ссылки ("Назад в кабинет...", "К списку ...") — отступ сверху
   ~1.5x высоты самой кнопки (кнопка ~32px общей высотой с текущими
   паддингами/шрифтом -> ~48px отступ).
   ------------------------------------------------------------------------ */
.wod-back-link {
    margin-top: 48px;
}
