/* ==========================================================================
   ui.css — слой темы ВВГУ поверх Bootstrap 5.
   Подключается ПОСЛЕДНИМ (после bootstrap.css, css/site.css, css/vvsu.css),
   поэтому может перекрывать всё перечисленное. Исторические файлы не
   переписываются: правки только здесь, чтобы откат был одним движением.

   Правила слоя:
     * цвет — из токенов и палитры разделов (--tone / --tone-light);
       ни одного style="color:..." в разметке;
     * геометрия — по шкале 4 px, радиусов не больше пяти;
     * контраст считается по худшему участку фона (самый светлый стоп
       градиента), а не по «основному» цвету.
   Проверка:
     python ui_audit.py public/css/ui.css --hints _tools/ui-audit.hints.json
   Подсказки нужны для вложенности, которую по одному файлу не вывести:
   .hero-lead лежит на .hero, .service-card > div — на .service-card.
   ========================================================================== */

/* --- 1. Токены ---------------------------------------------------------- */
:root {
    /* фирменный синий: три ступени, светлее #1668b8 не поднимаем —
       на более светлом стопе белый текст падает ниже 4.5 */
    --vvsu-blue: #0a56a4;
    --vvsu-blue-dark: #0b2f57;
    --vvsu-blue-mid: #1668b8;
    --vvsu-link: #1a6bbd;          /* 5.41 на белом, 5.03 на фоне страницы */

    /* поверхности */
    --vvsu-surface: #ffffff;
    --vvsu-page: #f4f7fb;
    --vvsu-bg-soft: #e6eef6;
    --vvsu-bg-softer: #eef3f9;
    --vvsu-border: #e2e8f0;
    --vvsu-border-strong: #8593a5; /* 3.13 на белом — для границ управления */

    /* текст */
    --vvsu-text: #212529;
    --vvsu-text-soft: #4a5c70;     /* 6.87 на белом, 6.40 на фоне страницы */
    --vvsu-muted: #526273;         /* 6.26 на белом, 5.83 на фоне страницы */
    --vvsu-danger-ink: #8c2b33;    /* 8.37 на белом, 6.96 на #ffe4e4 */

    /* геометрия: четыре радиуса на весь портал */
    --vvsu-radius: 4px;
    --vvsu-radius-tile: 8px;
    --vvsu-radius-card: 12px;
    --vvsu-radius-pill: 999px;

    /* тени: у карточки и у подъёма под курсором */
    --vvsu-shadow-card: 0 1px 2px rgba(11, 47, 87, 0.06),
                        0 12px 24px -20px rgba(11, 47, 87, 0.45);
    --vvsu-shadow-hover: 0 2px 4px rgba(11, 47, 87, 0.08),
                         0 18px 32px -22px rgba(11, 47, 87, 0.6);
}

/* --- 2. Палитра разделов ------------------------------------------------
   Шесть тонов — предел, дальше человек перестаёт их различать.
   --tone        заливка иконок, полоса-акцент, текст на светлой подложке
   --tone-alt    только заливки (под белым текстом не годится: 3.8–5.7)
   --tone-light  светлая подложка под текстом тона (>= 5.2 на всех тонах)
   ---------------------------------------------------------------------- */
.tone-1 { --tone: #0a56a4; --tone-alt: #2f6bb0; --tone-light: #e7effa; }
.tone-2 { --tone: #0f6f66; --tone-alt: #14907f; --tone-light: #ddf3ef; }
.tone-3 { --tone: #5b21b6; --tone-alt: #7c3aed; --tone-light: #ece7fb; }
.tone-4 { --tone: #8f4300; --tone-alt: #c96a00; --tone-light: #fbeedb; }
.tone-5 { --tone: #a3123c; --tone-alt: #d61f4a; --tone-light: #fbe4ea; }
.tone-6 { --tone: #14663a; --tone-alt: #1a8f4c; --tone-light: #ddf3e4; }

/* --- 3. Базовая типографика и поверхность ------------------------------- */
html {
    /* было 14px в site.css; для BS5 оставляем как было, но через токен */
    font-size: 14px;
}

body {
    color: var(--vvsu-text);
    background-color: var(--vvsu-page);
    /* В vvsu.css объявлены @font-face RobotoRegular/Medium/Light, но самих
       файлов в public/fonts нет (есть только RobotoBlack и RobotoBold) —
       каждая страница ловила 404 на шрифт. Берём системный стек: он есть
       везде и не даёт сетевых ошибок. Заголовки и кнопки по-прежнему
       используют RobotoBold из vvsu.css. */
    font-family: "Segoe UI", Tahoma, "Helvetica Neue", Arial, sans-serif;
}

body a {
    color: var(--vvsu-link);
    text-underline-offset: 2px;
}

body a:hover {
    color: var(--vvsu-blue);
}

/* site.css держит у контейнера страницы padding 15px, а BS5-сетка считает
   поля от --bs-gutter-x (1.5rem = 21px при корне 14px, то есть 10.5px на
   сторону). Из-за разницы в 4.5px герой и разделы стояли левее шапки.
   Берём половину гаттера — тогда логотип, герой, заголовок раздела и
   карточки начинаются на одной вертикали. */
.wrap > .container {
    padding-left: calc(var(--bs-gutter-x, 1.5rem) * 0.5);
    padding-right: calc(var(--bs-gutter-x, 1.5rem) * 0.5);
}

h1 {
    font-size: 2rem !important;
    font-weight: 700;
    color: var(--vvsu-blue-dark);
}

h3 {
    font-size: 1.5rem !important;
}

/* --- 4. Герой-блок: первое впечатление ---------------------------------
   Светлейший стоп градиента — #1668b8 (белый текст 5.67). Радиальные
   блики — прозрачные, малой площади и с альфой не выше .10: в худшей
   точке (блик поверх светлого стопа) белый текст остаётся 5.03.
   ---------------------------------------------------------------------- */
.hero {
    position: relative;
    overflow: hidden;
    margin-bottom: 24px;
    padding: 32px;
    border-radius: var(--vvsu-radius-card);
    color: #fff;
    background:
        radial-gradient(520px 240px at 6% -30%, rgba(120, 190, 255, 0.10), transparent 70%),
        radial-gradient(420px 220px at 98% 130%, rgba(120, 190, 255, 0.08), transparent 70%),
        linear-gradient(112deg, var(--vvsu-blue-dark) 0%, var(--vvsu-blue) 54%, var(--vvsu-blue-mid) 100%);
    box-shadow: 0 20px 40px -30px rgba(11, 47, 87, 0.9);
}

/* точечный узор поверх градиента: доли процента площади, текст не осветляет */
.hero::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: radial-gradient(rgba(255, 255, 255, 0.16) 1px, transparent 1px);
    background-size: 18px 18px;
    opacity: 0.5;
    pointer-events: none;
}

.hero > * {
    position: relative;
    z-index: 1;
}

.hero h1 {
    margin: 0 0 8px;
    color: #fff;
}

.hero-eyebrow {
    margin: 0 0 8px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #fff;
}

.hero-lead {
    max-width: 62ch;
    margin: 0 0 24px;
    font-size: 14px;
    line-height: 1.5;
    color: #fff;
}

.hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

.hero-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border: 1px solid transparent;
    border-radius: var(--vvsu-radius-pill);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
}

.hero-btn-primary {
    background: #fff;
    border-color: #fff;
    color: var(--vvsu-blue-dark);
}

.hero-btn-primary:hover {
    background: var(--vvsu-bg-softer);
    border-color: var(--vvsu-bg-softer);
    color: var(--vvsu-blue-dark);
}

.hero-btn-ghost {
    background: transparent;
    border-color: rgba(255, 255, 255, 0.7);
    color: #fff;
}

/* Подсветка «стеклянной» кнопки — затемняющий слой, а не белый: белая
   заливка поверх светлого стопа #1668b8 уронила бы текст до 4.48. */
.hero-btn-ghost:hover {
    background: rgba(3, 26, 50, 0.18);
    border-color: #fff;
    color: #fff;
}

@media (max-width: 575.98px) {
    .hero {
        padding: 24px 16px;
        border-radius: var(--vvsu-radius-tile);
    }
}

/* --- 5. Раздел с сервисами --------------------------------------------- */
.service-section {
    margin-bottom: 32px;
}

/* у последнего раздела отступ снизу не нужен: подвал и так отделён
   полосой, а вместе с отступом подвала это давало 150 px пустоты */
.service-section:last-of-type {
    margin-bottom: 0;
}

.section-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
}

.section-icon {
    flex: 0 0 auto;
    display: inline-grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: var(--vvsu-radius-tile);
    background: var(--tone, var(--vvsu-blue));
    color: #fff;
}

.section-icon svg {
    width: 20px;
    height: 20px;
    fill: currentColor;
}

.section-head h2 {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.3;
    color: var(--vvsu-blue-dark);
}

.section-sub {
    margin: 4px 0 0;
    font-size: 13px;
    color: var(--vvsu-muted);
}

/* мягкий бейдж «тон на тон» */
.badge-soft {
    background: var(--tone-light, var(--vvsu-bg-softer));
    color: var(--tone, var(--vvsu-blue));
    border-radius: var(--vvsu-radius-pill);
}

/* --- 6. Сетка сервисов --------------------------------------------------
   Раньше .service-card был col-md-2 внутри обычного div (не .row) — колонка
   получала ширину 16.6 %, но блокировалась, и пятнадцать карточек вставали
   в столбик шириной 726 px. Теперь раскладку задаёт CSS Grid, а утилиты
   col-* на карточке сохраняются только как запасной вариант.
   ---------------------------------------------------------------------- */
.service-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}

@media (min-width: 576px) {
    .service-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 992px) {
    .service-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* 13 карточек в первом разделе: пятёрками остаётся ровный последний ряд
   (5 + 5 + 3), шестёрками — одна карточка в пустой строке */
@media (min-width: 1200px) {
    .service-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

.service-grid > .service-card {
    width: 100%;
    max-width: 100%;
    flex: none;
}

.card.service-panel {
    border: 1px solid var(--vvsu-border) !important;
    /* site.css объявляет .card { border: none !important } — без !important
       полоса-акцент и рамка не применяются вовсе */
    border-top: 3px solid var(--tone, var(--vvsu-blue)) !important;
    border-radius: var(--vvsu-radius-card);
    background: var(--vvsu-surface);
    box-shadow: var(--vvsu-shadow-card);
}

.service-panel .card-body {
    padding: 16px;
}

/* --- 7. Карточка сервиса: иконка в квадратике + подпись ----------------- */
.service-card {
    display: flex;
    align-items: stretch;
    min-height: 152px;
    padding: 0 !important;
    border: 1px solid var(--vvsu-border);
    border-radius: var(--vvsu-radius-card);
    background: var(--vvsu-surface);
    text-decoration: none !important;
    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}

.service-card > div {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 12px;
    width: 100%;
    height: auto;
    padding: 16px 12px;
    border-radius: inherit;
    color: var(--vvsu-text-soft);
    text-align: center;
}

/* Квадратик под иконкой — это сам <svg>: padding + background дают плитку,
   а необъявленный fill у путей наследуется от svg. */
.service-card svg {
    flex: 0 0 auto;
    box-sizing: content-box;
    width: 40px;
    height: 40px;
    padding: 12px;
    margin: 0;
    border-radius: var(--vvsu-radius-tile);
    background: var(--vvsu-bg-softer);
    fill: var(--tone, var(--vvsu-blue));
    transition: background 0.18s ease, fill 0.18s ease;
}

.service-card > div span {
    height: auto;
    margin-top: 0;
    font-size: 13px;
    line-height: 1.35;
    color: inherit;
}

.service-card:hover,
.service-card:focus-visible {
    border-color: var(--tone, var(--vvsu-blue));
    box-shadow: var(--vvsu-shadow-hover);
    transform: translateY(-2px);
}

/* site.css красил при наведении всю карточку в синий; здесь подсвечивается
   только иконка, а подпись получает цвет тона (>= 5.6 на белом) */
.service-card:hover > div,
.service-card:focus-visible > div {
    background: transparent;
    color: var(--tone, var(--vvsu-blue));
}

.service-card:hover svg,
.service-card:focus-visible svg {
    background: var(--tone, var(--vvsu-blue));
    fill: #fff;
}

/* --- 8. Кнопки: фирменные цвета поверх BS5 ------------------------------ */
.btn.btn-success,
.btn.btn-success:focus,
.btn.btn-success:disabled {
    border: 2px solid var(--vvsu-blue);
    border-radius: var(--vvsu-radius);
    color: #fff;
    padding: 8px 16px;
    background: var(--vvsu-blue);
    font-size: 13px;
    font-family: "RobotoBold", Tahoma, sans-serif;
    transition: all 0.24s ease-out;
}

.btn.btn-success:hover:not(:disabled),
.btn.btn-success:active:not(:disabled) {
    background: transparent;
    color: var(--vvsu-blue);
    border: 2px solid var(--vvsu-blue);
}

/* было #999 на белом (2.85) — серый текст кнопки не читался */
.btn.btn-info {
    border: 2px solid var(--vvsu-border-strong);
    border-radius: var(--vvsu-radius);
    color: var(--vvsu-text-soft);
    background: transparent;
    font-size: 13px;
    font-family: "RobotoBold", Tahoma, sans-serif;
    transition: all 0.24s ease-out;
}

.btn.btn-info:hover:not(:disabled),
.btn.btn-info:active:not(:disabled) {
    background: var(--vvsu-text-soft);
    border-color: var(--vvsu-text-soft);
    color: #fff;
}

.btn.btn-warning {
    border: 2px solid #d02d2d;
    border-radius: var(--vvsu-radius);
    color: #fff;
    background: #d02d2d;
    font-size: 13px;
    font-family: "RobotoBold", Tahoma, sans-serif;
    transition: all 0.24s ease-out;
}

.btn.btn-warning:hover:not(:disabled) {
    background: transparent;
    color: #d02d2d;
}

/* BS5 по умолчанию даёт белый текст на #0d6efd — это 4.02, ниже нормы.
   Кнопка «Согласиться» в плашке cookie — как раз .btn-primary. */
.btn.btn-primary {
    --bs-btn-bg: var(--vvsu-blue);
    --bs-btn-border-color: var(--vvsu-blue);
    --bs-btn-hover-bg: #084584;
    --bs-btn-hover-border-color: #084584;
    --bs-btn-active-bg: var(--vvsu-blue-dark);
    --bs-btn-active-border-color: var(--vvsu-blue-dark);
    --bs-btn-font-size: 13px;
    border-radius: var(--vvsu-radius);
}

/* BS5 переименовал btn-default в btn-outline-secondary; в разметке он
   встречается как «второстепенная» кнопка — даём ему вид BS4-кнопки */
.btn-outline-secondary {
    border-radius: var(--vvsu-radius);
}

/* --- 9. Формы: BS5 сделал form-label / form-text / mb-3 ---------------- */
.form-label {
    margin-bottom: 0.25rem;
    font-weight: 400;
}

.form-control,
.form-select {
    border-radius: var(--vvsu-radius);
}

/* «Валидация» в этом проекте исторически через .is-invalid на span/обёртке */
.is-invalid .form-control,
.is-invalid .form-select,
.form-control.is-invalid,
.form-select.is-invalid {
    border-color: #dc3545 !important;
}

.invalid-feedback {
    display: block !important;
    font-size: 12px !important;
}

/* --- 10. Навбар и шапка ------------------------------------------------ */
/* BS3-имена остались в site.css/vvsu.css, даём совместимость */
/* Светлее #0a56a4 стоп не поднимаем: #bad5f1 на #1668b8 даёт 3.74.
   Навбар — 8-пиксельная полоса без ссылок, но правило должно быть честным. */
.navbar-inverse {
    background: linear-gradient(90deg, var(--vvsu-blue-dark), var(--vvsu-blue));
    border-color: transparent;
}

.navbar-inverse .navbar-brand,
.navbar-inverse .navbar-nav .nav-link {
    color: #bad5f1;
}

.navbar-inverse .navbar-nav .nav-link:hover,
.navbar-inverse .navbar-nav .nav-link:focus {
    color: #fff;
}

/* BS4 .navbar-nav > li > a, в BS5 — .nav-link */
.navbar-inverse .navbar-nav > li > a {
    color: #bad5f1;
}

/* высоту 8px из vvsu.css сохраняем, но BS5-навбар иначе раскладывает
   внутренний контейнер */
.navbar > .container,
.navbar > .container-fluid {
    min-height: 0;
}

.header {
    background: var(--vvsu-surface);
    border-bottom: 1px solid var(--vvsu-border);
    box-shadow: none;
}

/* --- 10a. Шапка как в ADMIN --------------------------------------------
   Нижняя полоса-навбар (8 px, vvsu.css) остаётся сверху как акцент, а вся
   шапка — один синий градиент с логотипом, названием страницы, «пилюлей»
   пользователя и кнопкой выхода. Так в ADMIN (app-navbar + .user-pill), и
   это же убирает главную проблему прежней шапки: пользователь и выход
   жили в подвале, то есть их не было видно без прокрутки до конца.
   Светлейший стоп #1668b8: белый текст на нём — 5.67, на полупрозрачной
   пилюле (rgba(255,255,255,.16) поверх #1668b8) — 4.72. Ниже 4.5 не уходит.
   ---------------------------------------------------------------------- */
.header {
    padding: 0;
    border-bottom: none;
    background:
        radial-gradient(520px 200px at 4% -60%, rgba(120, 190, 255, 0.14), transparent 70%),
        linear-gradient(100deg, var(--vvsu-blue-dark) 0%, var(--vvsu-blue) 46%, var(--vvsu-blue-mid) 100%);
    box-shadow: 0 8px 22px -16px rgba(11, 47, 87, 0.85);
}

.header .container {
    padding-top: 8px;
    padding-bottom: 8px;
}

.app-head {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    min-height: 40px;
}

.app-head-brand {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    color: #fff;
    text-decoration: none;
}

.app-head-brand:hover,
.app-head-brand:focus {
    color: #fff;
    text-decoration: none;
}

/* Логотип в шапке — белая версия (logo.svg): на синем фоне синий
   logo_blue.svg давал контраст 1.9 и был почти невидим.
   Теперь это инлайновый SVG с fill="currentColor" (см.
   views/layouts/logoMark.php): цвет берётся из color контейнера, поэтому
   в версии для слабовидящих логотип автоматически становится того цвета,
   который выбрал плагин, — без инверсии фильтром и без своих !important. */
.app-logo {
    display: block;
    width: 92px;
    height: auto;
    color: #fff;
}

.app-logo-link {
    display: inline-flex;
    color: inherit;
    text-decoration: none;
}

.app-logo-link:hover,
.app-logo-link:focus {
    color: inherit;
    text-decoration: none;
}

.app-head-title {
    font-size: 13px;
    line-height: 1.35;
    color: #dbe8f6;
    padding-left: 12px;
    border-left: 1px solid rgba(255, 255, 255, 0.32);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-head-tools {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
}

/* «Пилюля» пользователя: аватар с инициалами + ФИО/логин. Как .user-pill
   в ADMIN. Имя на телефоне скрыто — остаются инициалы, иначе на 390 px
   шапка расползается. */
.user-pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    max-width: 260px;
    padding: 3px 12px 3px 3px;
    border-radius: var(--vvsu-radius-pill);
    background: rgba(255, 255, 255, 0.16);
    border: 1px solid rgba(255, 255, 255, 0.26);
    color: #fff;
}

.user-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    border-radius: var(--vvsu-radius-pill);
    background: linear-gradient(140deg, #ffffff, #dce7f6);
    color: var(--vvsu-blue-dark);
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.02em;
}

.user-name {
    font-size: 13px;
    line-height: 1.2;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Кнопка выхода: контурная, как btn-outline-light в ADMIN */
.btn-exit {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border: 1px solid rgba(255, 255, 255, 0.55);
    border-radius: var(--vvsu-radius-pill);
    background: transparent;
    color: #fff;
    font-size: 13px;
    line-height: 1.2;
    text-decoration: none;
    white-space: nowrap;
}

.btn-exit:hover,
.btn-exit:focus {
    border-color: #fff;
    background: rgba(255, 255, 255, 0.16);
    color: #fff;
    text-decoration: none;
}

.btn-exit-icon {
    flex: 0 0 auto;
}

/* Иконки языка и меню — в полупрозрачных «чипах», чтобы не висли в воздухе */
.app-head-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: var(--vvsu-radius-tile);
    background: rgba(255, 255, 255, 0.14);
    border: 1px solid rgba(255, 255, 255, 0.22);
}

.app-head-chip img {
    display: block;
    width: 20px;
    height: 20px;
    object-fit: contain;
}

.app-head-chip a {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    border-radius: inherit;
}

.app-head-chip:hover,
.app-head-chip:focus-within {
    background: rgba(255, 255, 255, 0.24);
    border-color: rgba(255, 255, 255, 0.45);
}

/* --- 10b. Кнопка «Версия для слабовидящих» -----------------------------
   Требование доступности: вход в версию для слабовидящих должен быть
   виден с любой страницы. Кнопка — такой же «чип» в шапке, как язык и
   меню, но в отличие от них это ссылка (a.bvi-open), поэтому ей нужен
   собственный hover/focus и белая заливка иконки: на синем градиенте
   контраст иконки 5.6.

   В шапке только иконка глаза (Bootstrap bi-eye, инлайновый SVG) —
   подпись не занимает места и не ломает шапку на 390 px. Текст вплывает
   подсказкой при наведении и при фокусе с клавиатуры: transition по
   opacity + transform, pointer-events: none, чтобы подсказка не ловила
   клик вместо кнопки. Позиционирование absolute внутри <a>, у которого
   position: relative; шапка не обрезает (у .app-head нет overflow), но
   z-index задан явно — иначе подсказку перекрывает блок пользователя.
   ---------------------------------------------------------------------- */
.bvi-launch {
    position: relative;
    color: #fff;
    text-decoration: none;
    width: auto;
    min-width: 34px;
    padding: 0 8px;
    gap: 8px;
}

.bvi-launch:hover,
.bvi-launch:focus {
    color: #fff;
    text-decoration: none;
}

.bvi-launch svg {
    display: block;
    flex: 0 0 auto;
}

/* Подсказка: невидима, пока на кнопку не навели или не встали с клавиатуры.
   translateY(-2px) даёт «вплывание» снизу; nothing не кликается. */
.bvi-launch-tip {
    position: absolute;
    top: calc(100% + 8px);
    left: 50%;
    z-index: 1080;
    padding: 6px 10px;
    border-radius: 8px;
    background: #0b2b4a;
    color: #fff;
    font-size: 12px;
    line-height: 1.25;
    font-weight: 600;
    white-space: nowrap;
    box-shadow: 0 6px 18px rgba(9, 30, 66, 0.28);
    opacity: 0;
    transform: translate(-50%, -2px);
    transition: opacity 0.15s ease, transform 0.15s ease;
    pointer-events: none;
}

/* Стрелка вверх — подсказка читается как привязанная к кнопке */
.bvi-launch-tip::before {
    content: "";
    position: absolute;
    bottom: 100%;
    left: 50%;
    width: 0;
    height: 0;
    margin-left: -5px;
    border: 5px solid transparent;
    border-bottom-color: #0b2b4a;
}

.bvi-launch:hover .bvi-launch-tip,
.bvi-launch:focus .bvi-launch-tip,
.bvi-launch:focus-visible .bvi-launch-tip {
    opacity: 1;
    transform: translate(-50%, 0);
}

/* Уважаем системную настройку «уменьшить движение» */
@media (prefers-reduced-motion: reduce) {
    .bvi-launch-tip {
        transition: none;
    }
}

/* На узких экранах кнопка стоит близко к правому краю, и центрированная
   подсказка вылезала за вьюпорт (scrollWidth 404 при 390 — горизонтальная
   прокрутка). Прижимаем её к правому краю кнопки: растёт влево, остаётся
   внутри экрана. Стрелка при этом тоже смещается вправо. */
@media (max-width: 1199.98px) {
    .bvi-launch-tip {
        left: auto;
        right: 0;
        transform: translateY(-2px);
        max-width: calc(100vw - 24px);
        white-space: normal;
        text-align: right;
    }

    .bvi-launch-tip::before {
        left: auto;
        right: 13px;
        margin-left: 0;
    }

    .bvi-launch:hover .bvi-launch-tip,
    .bvi-launch:focus .bvi-launch-tip,
    .bvi-launch:focus-visible .bvi-launch-tip {
        transform: translateY(0);
    }
}

/* Панель плагина фиксируется сверху (panelFixed) с z-index 999999 и
   перекрыла бы нашу шапку. Плагин сам ставит html.bvi-active и
   --bvi-panel-offset; сдвигаем содержимое вниз, чтобы шапка и кнопка
   «Обычная версия» остались доступны. */
html.bvi-active body {
    padding-top: var(--bvi-panel-offset, 0px);
}

/* В режиме для слабовидящих плагин перекрашивает страницу своими
   правилами (в том числе `fill: var(--bvi-site-color) !important`).
   Это правильное поведение — именно оно делает тему читаемой, и
   перебивать его нельзя. Наша задача — не мешать: логотип объявлен
   инлайновым SVG с fill="currentColor" (views/layouts/logoMark.php),
   поэтому он получает цвет плагина сам. Своих правил на цвет шапки
   в этом режиме нет намеренно. */

@media (max-width: 575.98px) {
    .app-logo {
        width: 76px;
    }

    .user-pill {
        max-width: 44px;
        padding: 3px;
        gap: 0;
    }

    .user-name {
        display: none;
    }

    .btn-exit {
        padding: 6px;
        gap: 0;
    }

    .btn-exit .d-none {
        display: none !important;
    }
}

/* было 11px #859fb9 (2.74 на белом) — подпись рядом с логотипом не читалась,
   а width: 266px из vvsu.css рвал строку на две */
.heading {
    width: auto;
    max-width: 420px;
    font-size: 12px;
    line-height: 1.4;
    color: var(--vvsu-muted);
}

/* заголовок в шапке — ссылка на себя; подчёркивание у него лишнее */
.heading a,
.heading a:hover {
    color: var(--vvsu-muted);
    text-decoration: none;
}

.m-label {
    color: var(--vvsu-muted);
}

/* --- 11. Карточки, тени, отступы --------------------------------------- */
.card {
    border: 1px solid var(--vvsu-border);
    box-shadow: var(--vvsu-shadow-card);
}

.card-header {
    border-bottom: 1px solid var(--vvsu-border);
}

/* --- 11a. Заголовок формы: полоса-шапка карточки ----------------------
   Требование «заголовкиформ интереснее, чем просто жирный текст»; образец —
   ADMIN .card-header (градиент от светлого тона к белому + цвет тона).
   Заголовок формы переезжает ИЗ тела карточки в .card-header: он получает
   подложку, левую полосу-акцент и отделён от полей линией. Кегль 18 px —
   на шаг больше подписей формы, но меньше h1 страницы, чтобы не спорить
   с заголовком страницы.
   ---------------------------------------------------------------------- */
.card-header.form-card-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--vvsu-border);
    border-left: 4px solid var(--vvsu-blue);
    border-radius: var(--vvsu-radius-card) var(--vvsu-radius-card) 0 0;
    background: linear-gradient(90deg, #eef5fc 0%, #f7fbff 62%, #ffffff 100%);
    color: var(--vvsu-blue-dark);
}

.form-card-title {
    margin: 0;
    font-size: 18px !important;
    font-weight: 700;
    line-height: 1.25;
    color: var(--vvsu-blue-dark);
}

.form-card-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    border-radius: var(--vvsu-radius-tile);
    background: var(--vvsu-blue);
    color: #fff;
}

.form-card-icon svg {
    display: block;
    width: 16px;
    height: 16px;
}

/* Действия формы: справа на десктопе, в полную ширину на телефоне.
   Кнопки не разъезжаются по краям родителя, как было с col-*-6. */
.form-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--vvsu-border);
}

.form-actions-start,
.form-actions-end {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.form-actions-end {
    margin-left: auto;
}

@media (max-width: 575.98px) {
    .form-actions {
        justify-content: stretch;
    }

    .form-actions-start,
    .form-actions-end {
        width: 100%;
        margin-left: 0;
    }

    .form-actions-end > .btn,
    .form-actions-start > .btn {
        flex: 1 1 auto;
    }
}

/* В BS5 .card-deck удалён — разметка переведена на d-flex flex-wrap gap-3,
   но на случай старых мест оставляем эквивалент */
.card-deck {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}

.card-deck > .card {
    flex: 1 1 0;
    min-width: 0;
}

/* --- 12. Бейджи: BS4 badge-* -> BS5 text-bg-* -------------------------- */
.badge {
    font-weight: 600;
    font-size: 12px;
    padding: 4px 8px;
}

/* --- 13. Таблицы ------------------------------------------------------- */
.table > :not(caption) > * > * {
    padding: 0.5rem;
}

/* --- 14. Модальные окна ------------------------------------------------ */
.modal-header {
    border-bottom: 1px solid var(--vvsu-border);
}

.modal-footer {
    border-top: 1px solid var(--vvsu-border);
}

/* --- 15. Дропдауны и select2 (krajee) ---------------------------------- */
.dropdown-menu {
    border: 1px solid var(--vvsu-border);
    box-shadow: 0 4px 16px rgba(11, 47, 87, 0.12);
}

a.dropdown-item {
    color: var(--vvsu-blue);
    display: flex;
    align-items: center;
}

a.dropdown-item:hover,
a.dropdown-item:focus {
    color: var(--vvsu-blue);
    background-color: var(--vvsu-bg-softer);
}

/* В BS5 тема select2 называется krajee-bs5; старые правила в vvsu.css
   написаны на krajee (BS3). Дублируем нужное на bs5-класс. */
.select2-container--krajee-bs5 .select2-results__option--highlighted[aria-selected] {
    background-color: var(--vvsu-blue);
}

.select2-container--krajee-bs5 .select2-results__option[aria-selected=true] {
    background: var(--vvsu-bg-softer);
    color: var(--vvsu-blue);
}

.select2-container--krajee-bs5 li.select2-results__option {
    background-color: var(--vvsu-bg-softer);
    color: var(--vvsu-blue);
}

.select2-container--krajee-bs5.select2-container--open .select2-selection,
.select2-container--krajee-bs5 .select2-selection:focus {
    outline: 0;
    box-shadow: 0 0 0 0.2rem rgba(10, 86, 164, 0.25);
}

.select2-container--krajee-bs5 .select2-selection--single .select2-selection__clear {
    right: 32px;
    top: 3px;
}

/* --- 16. Алерты ------------------------------------------------------- */
.alert-info {
    color: var(--vvsu-blue-dark);
    background-color: #f2f7fd;
    border-color: #d6e4f3;
}

.alert-danger {
    color: #721c24;
    background-color: #ffe4e4;
    border-color: #ffd2d2;
}

.alert-danger a {
    color: #721c24;
    text-decoration: underline;
}

/* было #b94c54 на #ffe4e4 (4.14) */
.alert-danger a:hover {
    color: var(--vvsu-danger-ink);
}

/* --- 17. Служебный текст: цвета из site.css ниже нормы ----------------- */
.hint-block {
    color: var(--vvsu-muted);
}

.password-text {
    color: var(--vvsu-muted);
}

/* --- 17a. Требования к паролю: блок с подложкой ------------------------
   Требование «требования к паролю выделить фоном». Голый серый текст в
   потоке формы не читался, а провалидировать его на глаз нельзя.
   Подложка --tone-light (5.2+ на тексте тона), слева полоса-акцент: блок
   видно, но он не спорит с полями ввода. Заголовок — 13 px, пункты — 13 px
   с маркерами: это тот же кегль, что у подсказок формы, но на фоне.
   ---------------------------------------------------------------------- */
.password-rules {
    margin: 4px 0 16px;
    padding: 12px 16px 12px 16px;
    border: 1px solid #cfe0f3;
    border-left: 4px solid var(--vvsu-blue);
    border-radius: var(--vvsu-radius);
    background: #eef5fc;
    color: var(--vvsu-blue-dark);
}

.password-rules-title {
    margin: 0 0 8px;
    font-size: 13px;
    font-weight: 700;
    line-height: 1.3;
    color: var(--vvsu-blue-dark);
}

.password-rules-list {
    margin: 0;
    padding-left: 20px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--vvsu-text-soft);
}

.password-rules-list li {
    margin-bottom: 4px;
}

.password-rules-list li:last-child {
    margin-bottom: 0;
}

.password-rules code {
    padding: 1px 5px;
    border-radius: var(--vvsu-radius);
    background: rgba(10, 86, 164, 0.1);
    color: var(--vvsu-blue-dark);
    font-size: 13px;
}

.not-set {
    color: var(--vvsu-danger-ink);
}

.error-summary {
    color: var(--vvsu-danger-ink);
    background: #fdf3f4;
    border-left: 3px solid #e9b6bb;
}

/* --- 17b. Ссылки регистрации на форме входа --------------------------
   Раньше это был dropdown: три пункта прятались за одним словом и на
   телефоне открывались вбок. Теперь три видимые ссылки-плитки в ряд —
   их видно сразу, и они не конфликтуют с кнопкой «Войти».
   ---------------------------------------------------------------------- */
.app-register-links {
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--vvsu-border);
}

.app-register-label {
    display: block;
    margin-bottom: 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--vvsu-text-soft);
}

.app-register-list {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.app-register-item {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border: 1px solid var(--vvsu-border);
    border-radius: var(--vvsu-radius);
    background: var(--vvsu-bg-softer);
    color: var(--vvsu-link);
    font-size: 13px;
    line-height: 1.3;
    text-decoration: none;
}

.app-register-item:hover,
.app-register-item:focus {
    border-color: var(--vvsu-blue);
    background: #e6eef6;
    color: var(--vvsu-blue);
    text-decoration: none;
}

.app-register-item img {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
}

@media (max-width: 575.98px) {
    .app-register-item {
        flex: 1 1 100%;
    }
}

/* --- 18. Хлебные крошки: BS5 сменил разделитель и паддинги ------------ */
.breadcrumb {
    margin-bottom: 16px;
    font-size: 13px;
}

/* --- 19. Подвал: тёмная полоса с читаемым текстом ----------------------
   В vvsu.css правило записано как footer.footer (специфичность выше), а в
   site.css стоит height: 60px; поэтому здесь тоже footer.footer и height:auto.
   ---------------------------------------------------------------------- */
footer.footer {
    height: auto;
    min-height: 60px;
    margin-top: 32px;
    padding: 16px 0;
    border-top: none;
    color: #fff;
    background: linear-gradient(100deg, var(--vvsu-blue-dark), var(--vvsu-blue) 70%, var(--vvsu-blue-mid));
}

footer.footer p {
    margin: 0;
    font-size: 13px;
    color: #fff;
}

/* --- 19a. Подвал как в ADMIN: две стороны в одну строку ---------------
   Слева организация и название сервиса, справа год. В ADMIN это
   .app-footer с flex и justify-content: space-between; на узком экране
   строки переносятся (flex-wrap), а не наезжают друг на друга.
   ---------------------------------------------------------------------- */
.app-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 16px;
    font-size: 13px;
    color: #fff;
}

.app-foot-org {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.app-foot-icon {
    flex: 0 0 auto;
    opacity: 0.9;
}

.app-foot-copy {
    color: #dbe8f6;
}

footer.footer a,
footer.footer a:hover {
    color: #fff;
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* Плашка cookie стоит вплотную над подвалом, и её синяя полоса с тенью уже
   отделяет её от контента — отступ подвала сверху в этом случае лишний,
   иначе между ними висела полоса фона в 32 px. Без плашки отступ остаётся.
   :has() понимают все актуальные браузеры; там, где его нет, просто
   сохранится прежний отступ. */
body:has(.cookie-bar) footer.footer {
    margin-top: 0;
}

/* --- 20. Утилиты, которые были в site.css как «BS4-хвост» -------------
   В BS5 они есть, дубли не нужны, но .pl-0 остался только в site.css —
   оставляем работоспособным через логический аналог */
.pl-0 {
    padding-left: 0 !important;
}

/* --- 21. Мобильное меню (собственный виджет, не BS) ------------------- */
.fixed-menu {
    width: 390px;
    /* выше плашки cookie (10300), иначе меню уходит под неё;
       ниже модалок Bootstrap по смыслу, но выше — по числу */
    z-index: 10400;
    transition: right 0.5s cubic-bezier(0.25, 0.1, 0, 0.99), visibility 0s linear 0s;
}

/* Закрытое меню уезжает вправо, но остаётся в потоке фокуса: клавиатура
   проходила пятнадцать невидимых ссылок до первой карточки страницы.
   visibility убирает их из обхода, transition-delay сохраняет выезд. */
.fixed-menu.hidden-right {
    visibility: hidden;
    transition: right 0.5s cubic-bezier(0.25, 0.1, 0, 0.99), visibility 0s linear 0.5s;
}

.overlay-menu {
    z-index: 10390;
}

.m-content ul li a:hover {
    background: var(--vvsu-bg-softer);
}

@media (max-width: 390px) {
    .fixed-menu {
        width: 100%;
    }
}

/* --- 22. Плашка cookie: прибита к низу экрана ------------------------
   Раньше здесь был position: sticky. Sticky «прилипает» только пока виден
   его родитель и пока страница не доскроллена до конца блока: у короткой
   страницы плашка уезжала вместе с прокруткой, у длинной оставалась в
   потоке внизу документа, то есть её можно было упустить. Требование —
   плашка всегда накрывает низ экрана и не пропадает при прокрутке, поэтому
   position: fixed.
   Место под неё резервирует body.cookie-open (класс ставит
   views/layouts/main.php): иначе fixed-плашка накрыла бы подвал и ссылки в
   нём стали бы недоступны. Высота плашки считается в main.php через
   --cookie-h, потому что на 390 px она выше, чем на десктопе.
   ---------------------------------------------------------------------- */
.cookie-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 10300;
    background: var(--vvsu-surface);
    border-top: 3px solid var(--vvsu-blue);
    box-shadow: 0 -8px 24px -18px rgba(11, 47, 87, 0.8);
}

/* Запас под плашку, чтобы подвал не оказался под ней. */
body.cookie-open {
    padding-bottom: var(--cookie-h, 0px);
}

.cookie-bar .cookie-text {
    font-size: 13px;
    line-height: 1.45;
    color: var(--vvsu-text-soft);
}

.cookie-bar .btn {
    white-space: nowrap;
}

/* Внутри плашки прокрутка не нужна, но на очень низком экране (ландшафт
   телефона) текст не должен вываливаться за её пределы. */
.cookie-bar {
    max-height: 60vh;
    overflow-y: auto;
}

/* --- 23. Печать ------------------------------------------------------- */
@media print {
    .navbar,
    .header,
    .fixed-menu,
    .overlay-menu,
    .footer,
    .cookie-bar,
    .hero-actions {
        display: none !important;
    }

    .hero {
        color: #000;
        background: none !important;
        box-shadow: none;
    }

    .hero h1,
    .hero-lead,
    .hero-eyebrow {
        color: #000;
    }
}

/* --- 24. Доступность: видимый фокус -----------------------------------
   site.css объявляет a, button { transition: 0.2s ease } — а это переход
   по ВСЕМ свойствам. Из-за него кольцо фокуса не появляется, а плавно
   «доползает» от прозрачного: 0.2 с видно кольцо чужого цвета. Перечисляем
   свойства явно, outline в список не входит и срабатывает сразу.
   ---------------------------------------------------------------------- */
a,
button,
.heading a,
.m-content ul li a {
    transition-property: color, background-color, border-color, box-shadow, transform;
}

a:focus-visible,
button:focus-visible,
.btn:focus-visible,
.form-control:focus-visible,
.form-select:focus-visible {
    outline: 2px solid var(--vvsu-blue);
    outline-offset: 2px;
}

.hero a:focus-visible,
.hero button:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

.hero-btn {
    transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

/* --- 25. Уважение к prefers-reduced-motion ---------------------------- */
@media (prefers-reduced-motion: reduce) {
    a,
    button,
    .btn,
    .service-card,
    .service-card svg,
    .hero-btn {
        transition: none !important;
    }

    .service-card:hover,
    .service-card:focus-visible {
        transform: none;
    }
}

/* BS5 убрал .hidden — на всякий случай, если где-то осталось */
.hidden {
    display: none !important;
}
