/* ============================================
   Оболочка кабинета: «Глубокая бирюза»
   ============================================
   Тёмная сине-бирюзовая шапка и холодный нейтральный фон. Включается классом
   `qq-cab` на <body> (base.html ставит его всем страницам с обычной шапкой —
   лендинги `navbar-landing` и страницы входа `d-none` оболочку не получают).

   Файл намеренно отдельный и подключается после style.css: оболочка
   откатывается одним удалением <link>, а style.css (14 тыс. строк) не
   трогается. Все правила под `body.qq-cab`, поэтому публичные страницы не
   задеваются.

   Заголовок-«герой» (`qq-hero`) включается страницей явно через
   `{% block body_class %}`: у остальных страниц своя разметка заголовка с тёмным
   текстом, и тёмная полоса под шапкой сделала бы его нечитаемым. */

body.qq-cab {
    /* Заголовок страницы — один компонент в двух плотностях: стандартная
       (страницы участника, hub программы) и компактная (админка). Радиус и
       поля берутся отсюда, а не из каждого селектора. */
    --hero-radius: var(--r-lg);
    --hero-pad: 1.2rem 1.75rem;
    --hero-pad-compact: 0.8rem 1.25rem;
    --shell-band: #0b3c47;
    --shell-band-2: #0e4a56;
    --shell-mint: #8fe3d6;
}

/* ───────── Холст: «меш» ─────────
   Фон рисуется на <html>, а не на <body>. У html в style.css задан свой
   background-color (для резиновой прокрутки iOS), поэтому фон body не
   растягивается на окно, а красится поверх слоёв с отрицательным z-index:
   всё, что клалось «под контент» (сетка, зерно, дрейф), пряталось под ним.
   На html эти слои лежат над холстом и под содержимым.
   Градиенты fixed: пятна стоят на месте при прокрутке, а не уезжают со
   страницей. */
html:has(body.qq-cab) {
    --shell-mesh:
        radial-gradient(900px 700px at 0% 10%, rgba(38, 166, 154, 0.34), transparent 65%),
        radial-gradient(900px 700px at 100% 0%, rgba(20, 160, 200, 0.30), transparent 65%),
        radial-gradient(1000px 800px at 60% 110%, rgba(139, 124, 246, 0.20), transparent 65%);
    background: var(--shell-mesh), #eaf1f4;
    background-attachment: fixed;
}

body.qq-cab {
    background: transparent;
}

/* Водяной знак (плитка логотипа) на меше лишний: узор спорил бы с пятнами. */
body.qq-cab .global-watermark {
    display: none;
}

/* Дрейф: те же цвета, что у меша, но живым слоем — пятна медленно плывут.
   Отдельный элемент, а не body::before: тот уже занят полосой под вырезом
   iOS (style.css). Только transform — анимация идёт на GPU. */
body.qq-cab .shell-aurora {
    position: fixed;
    inset: -25%;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(34% 34% at 18% 22%, rgba(38, 166, 154, 0.26), transparent 70%),
        radial-gradient(34% 34% at 82% 14%, rgba(20, 160, 200, 0.24), transparent 70%),
        radial-gradient(38% 38% at 66% 86%, rgba(139, 124, 246, 0.16), transparent 70%);
    animation: shellDrift 42s ease-in-out infinite alternate;
    will-change: transform;
}

@keyframes shellDrift {
    0%   { transform: translate3d(0, 0, 0) rotate(0) scale(1); }
    50%  { transform: translate3d(4%, 3%, 0) rotate(6deg) scale(1.08); }
    100% { transform: translate3d(-3%, 5%, 0) rotate(-4deg) scale(1.04); }
}

/* Зерно: тонкая плёночная текстура, убирает полосы градиента. */
body.qq-cab::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    opacity: 0.07;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .05 0 0 0 0 .24 0 0 0 0 .28 0 0 0 .9 0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}

@media (prefers-reduced-motion: reduce) {
    body.qq-cab .shell-aurora {
        animation: none;
    }
}

/* ───────── Шапка ───────── */

body.qq-cab .navbar {
    background:
        radial-gradient(120% 220% at 100% -40%, #14606b 0, rgba(20, 96, 107, 0) 55%),
        var(--shell-band);
    border-bottom: 0;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

body.qq-cab .nav-brand-text {
    background: linear-gradient(90deg, #ffffff 0%, #c8f3ea 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

@media (min-width: 1201px) {
    body.qq-cab .nav-brand-text {
        font-size: 1.6rem;
        letter-spacing: var(--ls-tight);
    }
}

/* Кнопки справа: «i» и бургер. Светлые плашки на тёмном фоне слепили. */
body.qq-cab .app-info-trigger {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.22);
    color: #ffffff;
}

body.qq-cab .app-info-trigger:hover {
    background: rgba(255, 255, 255, 0.16);
    border-color: rgba(255, 255, 255, 0.42);
    color: #ffffff;
}

body.qq-cab .mobile-nav-toggle {
    border-color: rgba(255, 255, 255, 0.22);
    background: rgba(255, 255, 255, 0.08);
}

body.qq-cab .mobile-nav-toggle span {
    background: #ffffff;
}

/* Публичная навигация у гостя на странице с обычной шапкой. */
body.qq-cab .nav-link-custom {
    color: rgba(255, 255, 255, 0.78);
}

body.qq-cab .nav-link-custom:hover {
    color: #ffffff;
}

/* Пункты меню и аккаунт — только на десктопе. До 1024px меню уходит в
   светлую шторку, и белый текст в ней пропал бы. */
@media (min-width: 1025px) {
    body.qq-cab .nav-menu,
    body.qq-cab #authLinks {
        align-self: stretch;
    }

    /* Пункт тянется на всю высоту шапки: подчёркивание активного встаёт
       ровно на её нижнюю кромку, а не «висит» под текстом. */
    body.qq-cab #authLinks > .nav-link,
    body.qq-cab #authLinks .nav-dropdown-trigger {
        color: rgba(255, 255, 255, 0.72);
        background: none;
        border: 0;
        border-radius: 0;
        box-shadow: none;
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        margin: 0;
        align-self: stretch;
        display: inline-flex;
        align-items: center;
        transform: none;
    }

    /* app.js ставит ссылкам inline `display: inline-block`, и он перебивает
       flex выше: текст прижимался к верху шапки. Центрируем строкой, а не
       выравниванием: line-height работает при любом display. */
    body.qq-cab #authLinks > .nav-link {
        padding-top: 0;
        padding-bottom: 0;
        line-height: calc(var(--nav-height) - 1px);
    }

    body.qq-cab #authLinks .nav-dropdown-trigger {
        height: calc(var(--nav-height) - 1px);
        padding-top: 0;
        padding-bottom: 0;
    }

    /* Бейджи в пунктах: светло-розовая заливка на тёмном читалась как дыра.
       line-height сбрасываем — иначе бейдж унаследует высоту строки меню. */
    body.qq-cab #authLinks .badge {
        line-height: var(--lh-base);
        vertical-align: middle;
        border: 0;
        min-width: 1.35rem;
        padding: 0.1rem 0.4rem;
        font-size: 0.7rem;
    }

    body.qq-cab #authLinks .badge-danger {
        background: #e5534b;
        color: #ffffff;
    }

    body.qq-cab #authLinks .badge-warning {
        background: #f2b24c;
        color: #3a2400;
    }

    body.qq-cab #authLinks .nav-dropdown {
        align-self: stretch;
        margin: 0;
    }

    body.qq-cab #authLinks > .nav-link:hover,
    body.qq-cab #authLinks .nav-dropdown:hover .nav-dropdown-trigger,
    body.qq-cab #authLinks .nav-dropdown.open .nav-dropdown-trigger {
        color: #ffffff;
        background: rgba(255, 255, 255, 0.06);
        box-shadow: none;
        transform: none;
    }

    body.qq-cab #authLinks > .nav-link.active,
    body.qq-cab #authLinks > .nav-link.active:hover,
    body.qq-cab #authLinks .nav-dropdown-trigger.active,
    body.qq-cab #authLinks .nav-dropdown:hover .nav-dropdown-trigger.active,
    body.qq-cab #authLinks .nav-dropdown.open .nav-dropdown-trigger.active {
        color: #ffffff;
        background: none;
        border: 0;
        box-shadow: none;
    }

    body.qq-cab #authLinks > .nav-link.active::after,
    body.qq-cab #authLinks .nav-dropdown-trigger.active::after {
        content: '';
        position: absolute;
        left: 0.6rem;
        right: 0.6rem;
        bottom: -1px;
        height: 2px;
        border-radius: 2px;
        background: var(--shell-mint);
    }

    body.qq-cab .nav-user {
        border-left-color: rgba(255, 255, 255, 0.14);
    }

    body.qq-cab .nav-profile-btn {
        color: #ffffff;
    }

    body.qq-cab .nav-profile-btn:hover,
    body.qq-cab .nav-account.open .nav-profile-btn {
        background: rgba(255, 255, 255, 0.10);
    }

    body.qq-cab .nav-user-avatar {
        background: var(--shell-mint);
        border-color: transparent;
        color: var(--shell-band);
    }
}

/* Режим просмотра (имперсонация) на тёмном: приглушённая янтарная плашка
   вместо оранжевой заливки. */
body.qq-cab .impersonating-badge {
    background: rgba(255, 196, 99, 0.16);
    color: #fcd34d;
    border: 1px solid rgba(255, 196, 99, 0.32);
}

body.qq-cab .exit-impersonation-btn {
    background: rgba(255, 255, 255, 0.10);
    color: #fca5a5;
}

body.qq-cab .exit-impersonation-btn:hover {
    background: var(--danger);
    color: #ffffff;
}

/* В шторке бургера плашка и кнопка лежат на светлом фоне — вернуть как было. */
@media (max-width: 1024px) {
    body.qq-cab .impersonating-badge {
        background: #FFF3E0;
        color: #EF6C00;
        border-color: transparent;
    }

    body.qq-cab .exit-impersonation-btn {
        background: #FFEBEE;
        color: var(--danger);
    }
}

/* ───────── Герой дашборда ─────────
   Заголовок лаборатории и метрики лежат в тёмной плавающей панели по ширине
   колонки (общий вид панелей — ниже, «Заголовки страниц»). */

body.qq-hero .ud-head {
    /* Те же размеры, что у er-page-hero на других вкладках: заголовок
       дашборда не должен выделяться ни высотой, ни радиусом. */
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 1rem;
    padding: 1.2rem 1.75rem;
    border-radius: var(--hero-radius);
    margin-bottom: 2rem;
}

body.qq-hero .ud-head-icon {
    flex: none;
    width: 48px;
    height: 48px;
    border-radius: var(--r-md);
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.10);
    border: 1px solid rgba(255, 255, 255, 0.18);
    color: var(--shell-mint);
}

/* Строки «Результаты, требующие внимания»: вид задаёт my_problems.css (плотные
   строки с цветной точкой). Здесь только цвет текста — глобальный a:hover
   перекрашивал его в цвет бренда. Заливки и кромки слева больше нет: точка
   уже несёт цвет, а кромка обрезалась скруглением карточки. */
body.qq-cab .mp-tile,
body.qq-cab .mp-tile:hover,
body.qq-cab .mp-tile:focus,
body.qq-cab .mp-tile:visited {
    color: #1e293b;
}

body.qq-cab .mp-tile__label {
    color: var(--t-ink);
}

body.qq-hero .ud-head-kicker {
    color: rgba(255, 255, 255, 0.58);
    margin-bottom: 0.35rem;
}

body.qq-hero .ud-head-name {
    color: #ffffff;
    font-size: 1.55rem;
    line-height: 1.2;
    letter-spacing: -0.02em;
}

body.qq-hero .ud-head-sub {
    color: rgba(255, 255, 255, 0.78);
}

/* Метрики — «пилюли» в строку справа от названия, а не вложенная плашка:
   число и подпись рядом, как у чипов на других вкладках. */
body.qq-hero .ud-head-metrics {
    align-items: center;
    flex: 0 1 auto;
    justify-content: flex-end;
    gap: 0.5rem;
    padding: 0;
    background: none;
    border: 0;
    border-radius: 0;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

body.qq-hero .ud-head-metric,
body.qq-hero .ud-head-metric:first-child,
body.qq-hero .ud-head-metric:last-child {
    display: inline-flex;
    align-items: baseline;
    gap: 0.45rem;
    padding: 0.38rem 0.8rem;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.08);
}

body.qq-hero .ud-head-metric-value {
    color: #ffffff;
    font-size: 1rem;
}

body.qq-hero .ud-head-metric-value--warning {
    color: #ffc766;
}

body.qq-hero .ud-head-metric-value--urgent,
body.qq-hero .ud-head-metric-value--overdue {
    color: #fca5a5;
}

body.qq-hero .ud-head-metric-label {
    margin-top: 0;
    color: rgba(255, 255, 255, 0.78);
    white-space: nowrap;
}

body.qq-hero .ud-head-status {
    align-self: center;
    padding: 0.38rem 0.8rem;
    border-radius: 999px;
    background: rgba(126, 224, 168, 0.12);
    border: 1px solid rgba(126, 224, 168, 0.28);
    color: #7ee0a8;
    font-size: var(--fs-xs);
    white-space: nowrap;
}

body.qq-hero .ud-head-status + .ud-head-metric {
    margin-left: 0;
}

@media (max-width: 760px) {
    body.qq-hero .ud-head-metrics {
        flex: 1 1 100%;
        justify-content: flex-start;
        gap: 0.5rem;
    }

    body.qq-hero .ud-head-metric,
    body.qq-hero .ud-head-metric:first-child,
    body.qq-hero .ud-head-metric:last-child {
        min-width: 0;
        padding: 0.38rem 0.8rem;
    }
}

/* ───────── Заголовки страниц ─────────
   Два общих компонента: `er-page-hero` (страницы участника: ввод результатов,
   отчёты, успешность, сертификаты, настройки) и `admin-page-header` (админка).
   Оба переоформлены один раз здесь — шаблоны не трогаются. Это тёмная панель
   с кольцами логотипа, а не полноширинная полоса, как на дашборде: у этих
   страниц под заголовком сразу рабочие таблицы и фильтры, и растворение в
   фон только отнимало бы высоту. */

body.qq-cab {
    --shell-rings: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='700' height='700' fill='none' stroke='%2362b9b1' stroke-width='1.2'%3E%3Ccircle cx='350' cy='350' r='340' stroke-opacity='.30'/%3E%3Ccircle cx='350' cy='350' r='260' stroke-opacity='.24'/%3E%3Ccircle cx='350' cy='350' r='180' stroke-opacity='.20'/%3E%3Ccircle cx='350' cy='350' r='100' stroke-opacity='.16'/%3E%3C/svg%3E");
}

/* Общий вид тёмной панели: заголовок страницы участника, герой дашборда и
   заголовок админки. Кольца логотипа — слой фона, а не псевдоэлемент: так у
   панели нет лишних слоёв, и её снимок в View Transitions чистый. */
body.qq-cab .er-page-hero,
body.qq-hero .ud-head,
body.qq-cab .admin-page-header,
body.qq-cab .hub-header-stacked {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    color: #ffffff;
    background:
        var(--shell-rings) no-repeat right -130px top -240px / 700px 700px,
        radial-gradient(90% 220% at 100% 0%, #14606b 0, rgba(20, 96, 107, 0) 60%),
        var(--shell-band);
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 14px 34px -18px rgba(11, 60, 71, 0.6);
}

/* Страница участника */
body.qq-cab .er-page-hero {
    padding: var(--hero-pad);
    border-radius: var(--hero-radius);
    margin-bottom: 2rem;
}

/* Hub программы: заголовок, бейджи и панель действий в одной тёмной панели,
   как у остальных страниц; хлебные крошки остаются над ней. */
body.qq-cab .hub-header-stacked {
    padding: var(--hero-pad);
    border-radius: var(--hero-radius);
    margin-bottom: 1.5rem;
}

body.qq-cab .hub-header-title h1 {
    color: #ffffff;
    font-size: var(--fs-xl);
    font-weight: 700;
    letter-spacing: var(--ls-tight);
}

/* Цветные свечения вариантов (indigo, plum, gold…) на тёмном не нужны:
   единая палитра важнее различия страниц, различает их иконка. */
body.qq-cab .er-page-hero-bg {
    display: none;
}

body.qq-cab .er-page-hero-icon {
    background: rgba(255, 255, 255, 0.10);
    border: 1px solid rgba(255, 255, 255, 0.18);
    color: var(--shell-mint);
}

body.qq-cab .er-page-hero-title {
    color: #ffffff;
}

/* Админка: панель компактнее — под ней сразу тулбар и таблица. */
body.qq-cab .admin-page-header {
    margin: 0.85rem 0 0.65rem;
    padding: var(--hero-pad-compact);
    border-radius: var(--hero-radius);
}

body.qq-cab .admin-page-header h1 {
    background: none;
    -webkit-text-fill-color: #ffffff;
    color: #ffffff;
}

body.qq-cab .admin-page-subtitle {
    color: rgba(255, 255, 255, 0.72);
    -webkit-text-fill-color: rgba(255, 255, 255, 0.72);
}

/* Липкая обёртка админки (заголовок + фильтры): под ней едет контент, но она
   не должна быть видна прямоугольником, особенно в углах скруглённой панели.
   Своего фона у неё нет: статичный меш не совпадал с живым слоем дрейфа
   (.shell-aurora) и зерном, и в углах читались полупрозрачные квадраты.
   Едущий снизу контент скрывает блюр заднего плана; на гладком фоне самого
   кабинета он ничего не меняет, поэтому края обёртки не видны. */
body.qq-cab .admin-sticky-top {
    background: transparent;
    -webkit-backdrop-filter: blur(24px);
    backdrop-filter: blur(24px);
    border-bottom: 0;
}

/* Элементы внутри тёмной панели админки: кнопки без заливки, счётчик и
   подписи были рассчитаны на светлый фон и на тёмном пропадали. */
body.qq-cab .admin-page-header .admin-toolbar-count,
body.qq-cab .admin-page-header .dash-subtitle {
    color: rgba(255, 255, 255, 0.78);
    -webkit-text-fill-color: rgba(255, 255, 255, 0.78);
}

body.qq-cab .admin-page-header .btn:not(.btn-primary):not(.btn-danger):not(.btn-success) {
    background: rgba(255, 255, 255, 0.10);
    border: 1px solid rgba(255, 255, 255, 0.30);
    color: #ffffff;
}

body.qq-cab .admin-page-header .btn:not(.btn-primary):not(.btn-danger):not(.btn-success):hover:not(:disabled) {
    background: rgba(255, 255, 255, 0.20);
    border-color: rgba(255, 255, 255, 0.5);
    color: #ffffff;
}

body.qq-cab .admin-page-header .btn:disabled {
    opacity: 0.55;
}

/* Футер в тон шапке: прежний зелёный #00332C рядом с сине-бирюзовой шапкой
   читался как другой бренд. */
body.qq-cab .footer-custom {
    background: linear-gradient(180deg, #0b3c47 0%, #072a32 100%);
}

@media (max-width: 640px) {
    body.qq-cab .er-page-hero {
        padding: 1rem 1.1rem;
    }

    body.qq-hero .ud-head {
        padding: 1.2rem 1.1rem;
    }

    body.qq-cab .admin-page-header {
        padding: 0.8rem 1rem;
    }
}

/* ───────── Переходы между страницами ─────────
   Панель заголовка страницы (er-page-hero на вкладках участника, ud-head на
   дашборде) и шапка имеют собственные имена в View Transitions: браузер
   плавно перетекает панель из одного размера и положения в другое, а шапка
   стоит неподвижно. Раньше полоса была отдельным элементом и въезжала вместе
   с <main> (lkPageIn), из-за чего на переходе появлялась светлая щель.
   Имя у панели одно на странице (на странице один такой заголовок), поэтому
   конфликта имён нет; у админских заголовков имени нет намеренно — на части
   страниц их несколько, а повторяющееся имя отменило бы весь переход. */
body.qq-cab .er-page-hero,
body.qq-hero .ud-head {
    view-transition-name: shell-panel;
}

/* Шапка в переходе неподвижна: старый снимок скрыт, новый без анимации,
   и она поверх всего — иначе прокрученный старый контент заезжал бы на неё. */
body.qq-cab .navbar {
    view-transition-name: shell-nav;
}

::view-transition-old(shell-nav) {
    display: none;
}

::view-transition-new(shell-nav) {
    animation: none;
}

::view-transition-group(shell-nav) {
    z-index: 10;
}

::view-transition-group(shell-panel) {
    animation-duration: 0.45s;
    animation-timing-function: cubic-bezier(0.22, 0.8, 0.3, 1);
}

/* Карточка дашборда, раскрывающаяся в панель (shell-motion.js): снимки старой
   и новой панели разного размера, поэтому им нужна заливка по размеру группы и
   взаимное наложение вместо исчезновения одного перед появлением другого —
   иначе посреди раскрытия мелькает пустота. */
::view-transition-old(shell-panel),
::view-transition-new(shell-panel) {
    height: 100%;
    width: 100%;
    object-fit: cover;
    overflow: clip;
    mix-blend-mode: normal;
}

/* Переход по ссылке меню (тип qq-from-menu ставит shell-motion.js): у новой
   панели нет карточки-источника, из которой она могла бы вырасти, поэтому она
   раскрывается со стороны вкладки — вправо по меню справа налево, влево слева
   направо, как карточка дашборда. Это обрезка (clip-path), а не растяжение
   снимка: панель всё время резкая, а в конце совпадает с живой без скачка.
   Без направления (вкладка вне меню) — мягкое опускание из-под шапки.
   Отдельными блоками — по правилу для списка типов. */
html:active-view-transition-type(qq-from-menu)::view-transition-new(shell-panel) {
    height: auto;
    object-fit: fill;
    transform-origin: 50% 0;
    animation: shellPanelDrop 0.5s cubic-bezier(0.22, 0.8, 0.3, 1) both;
}

html:active-view-transition-type(qq-from-menu):active-view-transition-type(qq-forward)::view-transition-new(shell-panel) {
    animation: shellPanelFromRight 0.55s cubic-bezier(0.22, 0.8, 0.3, 1) both;
}

html:active-view-transition-type(qq-from-menu):active-view-transition-type(qq-back)::view-transition-new(shell-panel) {
    animation: shellPanelFromLeft 0.55s cubic-bezier(0.22, 0.8, 0.3, 1) both;
}

@keyframes shellPanelDrop {
    from { opacity: 0; transform: translateY(-14px) scale(0.985); }
    to   { opacity: 1; transform: none; }
}

@keyframes shellPanelFromRight {
    from { opacity: 0.2; clip-path: inset(0 0 0 78% round 18px); }
    40%  { opacity: 1; }
    to   { opacity: 1; clip-path: inset(0 0 0 0 round 18px); }
}

@keyframes shellPanelFromLeft {
    from { opacity: 0.2; clip-path: inset(0 78% 0 0 round 18px); }
    40%  { opacity: 1; }
    to   { opacity: 1; clip-path: inset(0 0 0 0 round 18px); }
}

/* ── Контент и направление ──
   По умолчанию контент мягко проявляется. Если известно направление
   (shell-motion.js ставит тип qq-forward / qq-back по порядку вкладок меню),
   старая страница уходит в сторону, откуда ушёл пользователь, а новая
   приходит с противоположной: переход читается как движение по ряду вкладок,
   а не как случайная подмена. Сдвиг небольшой (14px) — это подсказка
   направления, а не слайдер. Без поддержки типов браузер просто пропускает
   правила и остаётся на мягком появлении. */
::view-transition-new(lk-main) {
    animation: shellPageIn 0.38s cubic-bezier(0.22, 0.8, 0.3, 1) both;
}

html:active-view-transition-type(qq-forward)::view-transition-old(lk-main) {
    animation: shellOutLeft 0.2s cubic-bezier(0.4, 0, 1, 1) both;
}

html:active-view-transition-type(qq-forward)::view-transition-new(lk-main) {
    animation: shellInFromRight 0.4s cubic-bezier(0.22, 0.8, 0.3, 1) both;
}

html:active-view-transition-type(qq-back)::view-transition-old(lk-main) {
    animation: shellOutRight 0.2s cubic-bezier(0.4, 0, 1, 1) both;
}

html:active-view-transition-type(qq-back)::view-transition-new(lk-main) {
    animation: shellInFromLeft 0.4s cubic-bezier(0.22, 0.8, 0.3, 1) both;
}

/* Всё остальное (фон-меш) в переходе одинаково и не должно мерцать. */
::view-transition-group(root) {
    animation-duration: 0.25s;
}

@keyframes shellPageIn {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}

@keyframes shellOutLeft {
    to { opacity: 0; transform: translateX(-14px); }
}

@keyframes shellOutRight {
    to { opacity: 0; transform: translateX(14px); }
}

@keyframes shellInFromRight {
    from { opacity: 0; transform: translateX(14px); }
    to   { opacity: 1; transform: translateX(0); }
}

@keyframes shellInFromLeft {
    from { opacity: 0; transform: translateX(-14px); }
    to   { opacity: 1; transform: translateX(0); }
}

/* ── Проявление блоков с данными ──
   Класс qq-reveal ставит shell-motion.js один раз, когда контейнер впервые
   получил настоящее содержимое вместо скелетона/«Загрузка…». backwards, а не
   both: после анимации у блока не остаётся ни прозрачности, ни transform —
   иначе он навсегда становился бы отдельным слоем и подсказки (z-index)
   внутри него оказывались бы под соседями. Каскад — небольшой задержкой по
   порядку блоков сверху вниз. */
@keyframes shellReveal {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

body.qq-cab .qq-reveal {
    animation: shellReveal 0.42s cubic-bezier(0.22, 0.8, 0.3, 1) backwards;
}

body.qq-cab #timelineHost.qq-reveal { animation-delay: 0.04s; }
body.qq-cab #deadlinesContainer.qq-reveal { animation-delay: 0.08s; }
body.qq-cab #reportsContainer.qq-reveal { animation-delay: 0.12s; }
body.qq-cab #successContainer.qq-reveal { animation-delay: 0.16s; }

@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(shell-panel) {
        animation: none;
    }

    ::view-transition-new(lk-main) {
        animation: none;
    }

    /* Отдельными правилами: браузер без :active-view-transition-type отбросил
       бы весь список целиком, а с ним и правило выше. */
    html:active-view-transition-type(qq-forward)::view-transition-old(lk-main) {
        animation: none;
    }

    html:active-view-transition-type(qq-forward)::view-transition-new(lk-main) {
        animation: none;
    }

    html:active-view-transition-type(qq-back)::view-transition-old(lk-main) {
        animation: none;
    }

    html:active-view-transition-type(qq-back)::view-transition-new(lk-main) {
        animation: none;
    }

    html:active-view-transition-type(qq-from-menu)::view-transition-new(shell-panel) {
        animation: none;
    }

    html:active-view-transition-type(qq-from-menu):active-view-transition-type(qq-forward)::view-transition-new(shell-panel) {
        animation: none;
    }

    html:active-view-transition-type(qq-from-menu):active-view-transition-type(qq-back)::view-transition-new(shell-panel) {
        animation: none;
    }

    body.qq-cab .qq-reveal {
        animation: none;
    }
}

@media print {
    body.qq-cab {
        background: #ffffff;
    }

    /* Фоновые слои кабинета в печати не нужны, а вредят: `fixed`-слой
       повторяется на каждой странице, и зерно (SVG feTurbulence) Chromium
       растеризует в полноразмерное растровое изображение с альфа-каналом —
       около 2 МБ на страницу. PDF-отчёт из 8 страниц разрастался с ~1,4 до
       ~16 МБ и рендерился в разы дольше. */
    body.qq-cab::after,
    body.qq-cab .shell-aurora {
        display: none !important;
    }

    html {
        background: #ffffff !important;
    }
}
