/* Страница MISSU (/missu/) — изолированный модуль, не подключается на главной. */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body.missu-page {
    margin: 0;
    min-height: 100dvh;
    background-color: #eef1f5;
    color: #16233d;
    font-family: 'Unbounded', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
    /* Одностраничный экран-постер: выделение текста не имеет смысла. */
    -webkit-user-select: none;
    user-select: none;
}

/* --- Фон и виньетка ------------------------------------------------- */

.missu-page__bg {
    position: fixed;
    inset: 0;
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
    z-index: -2;
}

.missu-page__veil {
    position: fixed;
    inset: 0;
    z-index: -1;
    background:
        radial-gradient(ellipse 70% 60% at 50% 45%, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 60%),
        linear-gradient(180deg, rgba(198, 210, 226, 0.26) 0%, rgba(198, 210, 226, 0) 35%, rgba(163, 181, 205, 0.4) 100%);
    pointer-events: none;
}

/* --- Раскладка: логотип слева, счётчик справа ----------------------- */

.missu {
    position: relative;
    z-index: 1;
    display: grid;
    place-items: center;
    min-height: 100dvh;
    /* Горизонталь — общий стандарт проекта: на мобильных responsive.css
       даёт clamp(14px, 3.6vw, 24px), на десктопе --spacing-md (32px). */
    padding: clamp(1.5rem, 5vh, 3rem) clamp(14px, 3.6vw, 32px);
}

.missu__inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(1rem, 3vh, 1.6rem);
    width: 100%;
    /* Общая колонка для логотипа и панели: оба сжимаются вместе,
       поэтому их края остаются на одной вертикали. */
    max-width: 16.5rem;
    text-align: center;
}

/* Появление по элементам: каждый блок приходит со своей задержкой,
   а не одним куском — ощущается как последовательный «всплытие». */
.missu__brand {
    margin: 0;
    line-height: 0;
    position: relative;
}

/* Невидимая зона вокруг логотипа. Само изображение при наклоне меняет свой
   контур попадания (перспектива выпускает ближний край за габариты), и
   курсор у края многократно «выходит-входит» — отсюда дёргания. Обёртка не
   трансформируется, а с запасом покрывает наклоненный лого, поэтому
   pointer-события остаются стабильными на всём диапазоне углов. */
.missu__brand::after {
    content: "";
    position: absolute;
    inset: -16px;
}

.missu__logo {
    display: block;
    /* Ровно та же ширина, что и у панели счётчика: в колонке логотип и
       прогресс-бар совпадают по краям (в файле логотипа почти нет полей). */
    width: min(100%, 28rem);
    height: auto;
    filter:
        drop-shadow(0 0.75rem 2rem rgba(23, 54, 96, 0.26))
        drop-shadow(0 0.125rem 0.25rem rgba(23, 54, 96, 0.2));
    /* 3D под курсором: perspective живёт прямо в transform, поэтому
       элемент остаётся один — отдельная 3D-обёртка не нужна.
       JS двигает только --rx/--ry/--logo-scale и сглаживает их в кадровом
       цикле; CSS-transition здесь намеренно нет, иначе получилось бы
       двойное сглаживание и отставание от курсора.
       Больший радиус перспективы (1100 вместо 900) меньше «выпускает»
       ближний край за габариты — это важно для стабильности hover. */
    transform: perspective(1100px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale(var(--logo-scale, 1));
}

.missu__panel {
    width: min(100%, 28rem);
}

.missu__caption {
    /* inline-block, а не block: иначе box тянется на всю ширину панели,
       и hover срабатывал бы на пустоте по бокам от текста. */
    display: inline-block;
    position: relative;
    /* Приоритет hit-test: область попадания по тексту цифр считается по
       глифу и выходит на ~18px выше их border-box, перекрывая подпись.
       z-index возвращает подписи попадание в этой зоне. */
    z-index: 1;
    /* Явный line-height: без него высота строки бралась из метрик
       подключаемого шрифта, и при swap-подключении Unbounded подпись
       «подпрыгивала» вверх на ~17px. */
    line-height: 1.3;
    margin: 0 0 clamp(0.3rem, 1vh, 0.7rem);
    font-size: clamp(0.62rem, 1.4vw, 0.85rem);
    font-weight: 600;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    color: #46587a;
    text-indent: 0.28em;
    transition: color 0.3s ease, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

.missu__caption:hover {
    color: #16233d;
    transform: translateY(-0.12em);
}

.missu__value {
    margin: 0;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    font-weight: 800;
    line-height: 0.9;
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
}

.missu__number {
    display: inline-block;
    min-width: 2ch;
    color: #16233d;
    font-size: clamp(3rem, 12.5vw, 6.75rem);
}

/* Градиент висит на каждой цифре, а не на общей обёртке: цифры анимируются
   собственным transform, и при общем фоне глиф просто съехал бы со своей
   «вырезки» в background-clip: text. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
    .missu__digit {
        background-image: linear-gradient(155deg, #16233d 0%, #24497a 55%, #3c73ad 100%);
        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
        color: transparent;
    }
}

/* Каждая цифра и знак процента — отдельный символ со своей задержкой:
   подъём идёт посимвольно, а не одним блоком.

   fill-mode именно backwards, а не both: анимационные значения всегда
   приоритетнее обычных правил, и с both hover-трансформ ниже был бы молча
   проигнорирован. backwards держит from только до старта, а после
   завершения возвращает обычные стили — тогда :hover начинает работать. */
.missu__digit,
.missu__unit {
    /* Обязателен: transform не применяется к display:inline, поэтому
       цифра оставалась неподвижной, а её rect (133px вместо 97px line-height)
       захватывал чужую область и перекрывал подпись сверху. */
    display: inline-block;
    /* Hit-test только по ::after: у текста область попадания считается по
       метрикам шрифта (ascent+descent ≈ 133px) и выходит за border-box,
       из-за чего ниже цифр оставалась «фантомная» зона с той же анимацией.
       Сам элемент в hit-test не участвует. */
    position: relative;
    pointer-events: none;
    /* Форма входного появления: цифры всплывают мельче и заметнее блоков.
       Значения по умолчанию заданы в keyframes missu-in. */
    --reveal-y: 0.5em;
    --reveal-scale: 0.6;
    transition: transform 0.34s cubic-bezier(0.22, 1, 0.36, 1);
    transition-delay: calc(var(--i, 0) * 0.07s);
}

.missu__digit::after,
.missu__unit::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: auto;
}

/* Зона разделяется: цифры оживают только от наведения на цифры,
   знак процента — только от наведения на него самого. */
.missu__number:hover .missu__digit {
    transform: translateY(-0.07em) scale(1.07);
}

.missu__unit {
    margin-left: 0.06em;
    font-size: clamp(1.2rem, 4.2vw, 2.3rem);
    font-weight: 600;
    color: #3c73ad;
    line-height: 1;
    padding-top: 0.14em;
    /* Личный hover без волны: свойство задержки берётся из --i выше,
       поэтому для самостоятельного срабатывания гасим её. */
    transition-delay: 0s;
}

.missu__unit:hover {
    transform: translateY(-0.07em) scale(1.07);
}

/* --- Прогресс-бар ---------------------------------------------------- */

.missu__bar {
    position: relative;
    height: 0.72rem;
    margin-top: clamp(0.8rem, 2.2vh, 1.4rem);
    border-radius: 999px;
    background: rgba(22, 35, 61, 0.11);
    box-shadow: inset 0 1px 3px rgba(22, 35, 61, 0.16);
    overflow: hidden;
    transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Наведение утолщает полосу: transform не трогает layout, поэтому
   соседние блоки не дёргаются. */
.missu__bar:hover {
    transform: scaleY(1.4);
}

.missu__bar-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: 0;
    border-radius: 999px;
    background: linear-gradient(90deg, #16233d 0%, #245589 55%, #3f86cf 100%);
    box-shadow: 0 0 12px rgba(63, 134, 207, 0.55);
}

/* Величина задаётся инлайном (--p) из модели, поэтому значение видно и без JS. */
@keyframes missu-bar-fill {
    to {
        width: calc(var(--p) * 1%);
    }
}

.missu__scale {
    display: flex;
    justify-content: space-between;
    margin: 0.4rem 0 0;
    font-size: clamp(0.58rem, 1.2vw, 0.7rem);
    font-weight: 600;
    letter-spacing: 0.18em;
    line-height: 1.3;
    color: #6b7c99;
}

/* Hover висит на самих подписях, а не на всю ширину растянутом контейнере:
   иначе между «0» и «100%» оживал бы весь блок сразу. */
.missu__scale span {
    display: inline-block;
    transition: color 0.3s ease, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

.missu__scale span:hover {
    color: #46587a;
    transform: translateY(-0.1em);
}

/* --- Появление после раскрытия загрузочного экрана ---------------------
   Пока висит loader и идёт его fade-out, контент скрыт: чёрный экран его
   всё равно не показывает, но «хвост» анимации под уходящей маской читается
   как глюк — подпись ползёт на глазах в момент, когда экран тускнеет.
   Поэтому анимации запускает класс missu-ready, который ставит JS после
   фактического скрытия loader'а: контент проявляется уже на чистой
   странице, целиком и в заданном порядке.
   --------------------------------------------------------------------- */
/* Единая шина появления. Участник отмечается в разметке атрибутом
   data-reveal; отличие одного элемента от другого (форма, задержка)
   выражается переменными --reveal-*, а не отдельным правилом. Добавить
   новый анимируемый блок — значит проставить атрибут и, при необходимости,
   задержку в списке ниже. Скрытие, запуск и reduced-motion смотрят на один
   и тот же селектор, поэтому не могут разойтись между собой. */
body:not(.missu-ready) [data-reveal] {
    opacity: 0;
}

body.missu-ready [data-reveal] {
    animation: missu-in 0.85s var(--reveal-delay, 0s) cubic-bezier(0.22, 1, 0.36, 1) backwards;
}

/* Единый таймлайн: задержки всех участников собраны в одном месте, поэтому
   порядок появления читается как список, а не собирается по разным правилам.
   Цифры и «%» берут индекс символа из --i. */
.missu__brand   { --reveal-delay: 0.05s; }
.missu__caption { --reveal-delay: 0.16s; }
.missu__digit,
.missu__unit    { --reveal-delay: calc(var(--i, 0) * 0.11s + 0.3s); }
.missu__bar     { --reveal-delay: 0.55s; }
.missu__scale   { --reveal-delay: 0.7s; }

/* Единая форма входа: «всплытие + раскрытие». Разница между блоками и
   цифрами — только в --reveal-y/--reveal-scale (у цифр меньше стартовый
   масштаб), поэтому отдельные keyframes не нужны. */
@keyframes missu-in {
    from {
        opacity: 0;
        transform: translateY(var(--reveal-y, 1.1rem)) scale(var(--reveal-scale, 0.94));
    }
    to {
        opacity: 1;
        transform: none;
    }
}

/* Заполнение полосы тоже ждёт раскрытия, иначе к этому моменту оно уже
   проиграно под loader'ом и полоса показалась бы сразу готовой. */
body.missu-ready .missu__bar-fill {
    animation: missu-bar-fill 1.4s 0.35s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

/* --- Снег ------------------------------------------------------------
   Только CSS-анимации через translate3d: браузер отдаёт их GPU
   (композитинг), не пересчитывая layout и paint. JS создаёт частицы
   один раз при загрузке и дальше не работает вовсе.
   --------------------------------------------------------------------- */

.missu-snow {
    position: fixed;
    inset: 0;
    z-index: 5;
    overflow: hidden;
    pointer-events: none;
}

/* Общий порыв ветра: слой со всеми хлопьями медленно сносит вбок,
   периодически меняя направление — «как будто подул». */
.missu-snow__field {
    position: absolute;
    inset: -8% -12%;
    animation: missu-wind 17s ease-in-out infinite;
}

.missu-flake {
    position: absolute;
    top: -8%;
    left: var(--x);
    width: var(--s);
    height: var(--s);
    border-radius: 50%;
    /* Мягкость даёт сам градиент (край растворяется в прозрачность), а не
       filter: blur — blur пересчитывается каждый кадр для движущихся
       частиц и заметно тормозит анимации страницы. Глубина достигается
       разницей размера, длительности и прозрачности. */
    background: radial-gradient(circle at 32% 30%, #ffffff 0%, rgba(255, 255, 255, 0.85) 40%, rgba(255, 255, 255, 0.35) 68%, rgba(255, 255, 255, 0) 100%);
    opacity: var(--o);
    animation: missu-fall var(--d) linear var(--dl) infinite;
}

@keyframes missu-fall {
    0% {
        transform: translate3d(0, -12vh, 0);
        opacity: 0;
    }
    12% {
        opacity: var(--o);
    }
    /* Плавный боковой дрейф каждого хлопья в собственной фазе. */
    55% {
        transform: translate3d(var(--drift-b), 52vh, 0);
    }
    88% {
        opacity: var(--o);
    }
    100% {
        transform: translate3d(var(--drift-a), 116vh, 0);
        opacity: 0;
    }
}

@keyframes missu-wind {
    0%, 100% {
        transform: translate3d(0, 0, 0);
    }
    18% {
        transform: translate3d(-2.6vw, 0, 0);
    }
    46% {
        transform: translate3d(3.4vw, 0, 0);
    }
    72% {
        transform: translate3d(-1.4vw, 0, 0);
    }
}

/* --- Адаптив ---------------------------------------------------------- */

/* Планшеты в портретной ориентации: колонка остаётся, но шире, чем на телефоне. */
@media (min-width: 34rem) and (max-width: 54.99rem) {
    .missu__inner {
        max-width: 22rem;
    }
}

/* Планшеты и десктоп в альбомной ориентации: логотип слева, счётчик справа. */
@media (min-width: 55rem) {
    .missu__inner {
        flex-direction: row;
        justify-content: center;
        align-items: center;
        gap: clamp(2.5rem, 6vw, 5rem);
        text-align: left;
        max-width: 62rem;
    }

    .missu__logo {
        width: min(36vw, 26rem);
    }

    .missu__panel {
        width: min(40vw, 26rem);
        flex: 0 1 auto;
    }

    .missu__value {
        justify-content: flex-start;
    }

    .missu__scale {
        justify-content: space-between;
    }
}

@media (max-width: 30rem) {
    /* На самых узких экранах только чуть сжимаем шрифт, ширина логотипа
       остаётся равной панели, чтобы края совпадали. */
    .missu__caption {
        letter-spacing: 0.24em;
        text-indent: 0.24em;
    }
}

@media (prefers-reduced-motion: reduce) {
    [data-reveal],
    .missu__bar-fill,
    .missu-snow__field,
    .missu-flake {
        animation: none;
    }

    /* Гасим не только вход, но и hover-движение текста: при reduce
       ни подъём, ни масштабирование под курсором происходить не должно. */
    .missu__caption,
    .missu__digit,
    .missu__unit,
    .missu__scale span,
    .missu__bar {
        transition: none;
    }

    .missu__caption:hover,
    .missu__digit:hover,
    .missu__unit:hover,
    .missu__scale span:hover,
    .missu__bar:hover {
        transform: none;
    }

    /* Без анимации полоса сразу занимает положенное место. */
    .missu__bar-fill {
        width: calc(var(--p) * 1%);
    }

    /* 3D под курсором выключается вместе с прочим движением. */
    .missu__logo {
        transform: none;
    }

    .missu-snow {
        display: none;
    }
}
