/* ==========================================================================
   ВЛИЯНИЕ РОССИИ — слой 1 из 3
   Токены дизайна, сброс, типографика, утилиты, доступность.
   Подключается первым: остальные слои опираются на переменные отсюда.
   ========================================================================== */

:root {
    /* --- Палитра ---
       Взята из материала, а не выбрана на глаз: образец народного орнамента
       даёт ткань #570b0b / #681313 и шитьё #ecd6ca. Отсюда тёплый тёмный фон,
       один активный цвет и тёплый песок для мелких подписей.
       Сине-фиолетово-неоновая тройка убрана: она и была главным признаком
       шаблонного «дизайна от нейросети». */
    /* Значения подобраны так, чтобы тёплая гамма не оказалась темнее прежней
       холодной: у красного канала вклад в воспринимаемую яркость вдвое меньше,
       чем у синего, поэтому те же по коду числа давали бы более тёмную
       страницу. */
    --bg-black: #261c1e;
    --bg-alt: #332224;
    /* Полупрозрачная заливка чётных секций: сквозь неё видно живой фон,
       который иначе был бы перекрыт сплошным цветом */
    --bg-alt-soft: rgba(66, 36, 39, 0.62);

    /* Один активный цвет. --accent — только для действий и акцентов;
       --accent-deep — материал для крупных заливок; --accent-soft — тёплый
       песок для подписей и мелких деталей. */
    --accent: #c81e28;
    --accent-deep: #5a0c0c;
    --accent-soft: #d9b49c;

    /* Текст на акцентной заливке. Два разных токена, а не один: на малиновой
       кнопке нужен кремовый (5.28:1), а на песочной плашке — тёмный (9.99:1).
       Пока оба места брали цвет из фона страницы, осветление палитры уронило
       контраст главной кнопки с 5.28:1 до 4.38:1, ниже AA. */
    --on-accent: #faf5ef;
    --on-accent-soft: #200d0e;

    /* --- Текст --- */
    --text-white: #faf5ef;
    --text-gray: #eddfd6;
    /* Приглушённый текст: 9.16:1 на #171011 */
    --text-muted: #c3b2a7;

    /* --- Поверхности и границы ---
       Тёплые, а не белые: холодноватый белый на тёплом фоне читается как
       случайная наклейка. */
    --surface-glass: rgba(236, 214, 202, 0.09);
    --surface-card: rgba(236, 214, 202, 0.07);
    --surface-raised: rgba(236, 214, 202, 0.12);
    /* Непрозрачная поверхность для карточек спикеров: они лежат на сетке
       портретов, и полупрозрачность там читается как грязь под фото. */
    --surface-solid: #3d2627;
    --border-subtle: rgba(236, 214, 202, 0.18);
    --border-strong: rgba(236, 214, 202, 0.34);

    /* --- Шрифты --- */
    --font-display: 'Unbounded', system-ui, sans-serif;
    --font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

    /* --- Ритм --- */
    --container-max: 1400px;
    --gutter: 24px;
    --section-y: clamp(72px, 9vw, 120px);
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;
    --space-7: 40px;
    --space-8: 60px;
    --radius: 4px;
    /* Обновляется в js/ui.js по реальной высоте шапки (шапка переносится на мобильных) */
    --header-h: 72px;
    /* Минимальная высота шапки. Отдельный токен, а не --header-h: иначе
       получается обратная связь «высота шапки → min-height → высота шапки». */
    --header-min-h: 72px;

    /* --- Анимация --- */
    --ease: cubic-bezier(0.165, 0.84, 0.44, 1);
    --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
    --dur-fast: 0.2s;
    --dur: 0.3s;
    --dur-slow: 0.8s;

    /* --- Слои --- */
    --z-glow: 1;
    --z-content: 2;
    --z-header: 100;
    --z-dialog: 1000;
    --z-cursor: 9999;

    --focus-ring: 2px solid var(--accent-soft);

    color-scheme: dark;
}

/* --------------------------------------------------------------------------
   Сброс
   -------------------------------------------------------------------------- */

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

html {
    /* clip вместо hidden: не создаёт скролл-контейнер и не ломает position: sticky */
    overflow-x: clip;
    -webkit-text-size-adjust: 100%;
}

@media (prefers-reduced-motion: no-preference) {
    html {
        scroll-behavior: smooth;
    }
}

body {
    background-color: var(--bg-black);
    color: var(--text-white);
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.6;
    overflow-x: clip;
    -webkit-font-smoothing: antialiased;
}

img,
svg,
video {
    display: block;
    max-width: 100%;
}

button,
input,
select,
textarea {
    font: inherit;
    color: inherit;
}

ul,
ol {
    list-style: none;
}

/* --------------------------------------------------------------------------
   Типографика
   -------------------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
    font-family: var(--font-display);
    font-weight: 700;
    text-transform: uppercase;
    line-height: 1.1;
    text-wrap: balance;
    /* anywhere, а не break-word: break-word переносит длинное слово, но НЕ
       уменьшает min-content ширину элемента, поэтому флекс/грид-элемент
       с таким заголовком всё равно распирало контейнер (на 320px карточка
       приза вылезала на 33px). anywhere участвует в расчёте min-content. */
    overflow-wrap: anywhere;
}

p {
    text-wrap: pretty;
}

a {
    color: inherit;
}

.mono {
    font-family: var(--font-mono);
}

/* --------------------------------------------------------------------------
   Утилиты
   -------------------------------------------------------------------------- */

.container {
    width: 100%;
    max-width: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

.section {
    position: relative;
    padding-block: var(--section-y);
}

.section--alt {
    /* Полупрозрачная заливка вместо сплошной: сквозь чётные секции видно
       живой фон, страница перестаёт быть набором непроницаемых полос */
    background: var(--bg-alt-soft);
}

/* Хранилище SVG-иконок: не занимает места, но <use> по нему работает */
.svg-sprite {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

/* --------------------------------------------------------------------------
   Доступность: фокус и навигация с клавиатуры
   -------------------------------------------------------------------------- */

/* Исходная страница прятала системный курсор и не давала ни одного
   индикатора фокуса — с клавиатуры было невозможно понять, где ты. */
:focus-visible {
    outline: var(--focus-ring);
    outline-offset: 3px;
    border-radius: 2px;
}

/* Навигационный обход: первая ссылка на странице.
   Текст тёмный (--on-accent-soft): на песочной плашке кремовый --on-accent
   давал 1.77:1 — ссылка, которую видно только с клавиатуры, была нечитаема. */
.skip-link {
    position: absolute;
    top: 0;
    left: var(--gutter);
    z-index: calc(var(--z-header) + 1);
    padding: 12px 20px;
    background: var(--accent-soft);
    color: var(--on-accent-soft);
    font-weight: 700;
    text-decoration: none;
    border-radius: 0 0 var(--radius) var(--radius);
    transform: translateY(-120%);
    transition: transform var(--dur) var(--ease);
}

.skip-link:focus-visible {
    transform: translateY(0);
    outline-offset: -4px;
}

/* Якорные переходы не должны уезжать под липкую шапку */
[id] {
    scroll-margin-top: calc(var(--header-h) + 16px);
}

/* --------------------------------------------------------------------------
   Появление при скролле.
   Скрытие работает только при классе .js (его ставит инлайн-скрипт в <head>),
   иначе без JavaScript контент остаётся видимым.
   -------------------------------------------------------------------------- */

.js .reveal {
    opacity: 0;
    transform: translateY(50px);
    transition:
        opacity var(--dur-slow) var(--ease) calc(var(--i, 0) * 90ms),
        transform var(--dur-slow) var(--ease) calc(var(--i, 0) * 90ms);
}

.js .reveal.is-visible {
    opacity: 1;
    transform: none;
}

/* --------------------------------------------------------------------------
   Появление изображений.

   Анимируем только opacity ключевого кадра, без финального значения: после
   окончания анимации элемент возвращается к собственному opacity из CSS
   (например, 0.8 у фото спикеров), поэтому подмешивать ничего не нужно.
   -------------------------------------------------------------------------- */

@keyframes img-in {
    from {
        opacity: 0;
    }
}

.img-fade img.is-loaded:not(.speaker-card__img) {
    animation: img-in 0.7s var(--ease);
}

/* Портреты спикеров исключены намеренно: у них своя анимация opacity по
   наведению (0.8 → 1), а анимация всегда перебивает транзишен. Из-за этого
   при наведении в первые 0,7 с после загрузки карточка не подсвечивалась —
   вместо этого портрет «проявлялся из чёрного». Сама карточка и так
   появляется по каскаду .reveal. */

/* Не отрисовалась даже заглушка (например, заблокированы data:-URI).
   Прячем картинку целиком: под ней остаётся фон карточки или градиент,
   а значок «битого» изображения не появляется. */
img.is-broken {
    visibility: hidden;
}

/* --------------------------------------------------------------------------
   Появление первого экрана: короткий каскад при загрузке.
   Только CSS — если анимации не будет, текст всё равно виден.
   -------------------------------------------------------------------------- */

@keyframes hero-in {
    from {
        opacity: 0;
        transform: translateY(28px);
    }
}

.hero__content > * {
    animation: hero-in 0.85s var(--ease) backwards;
}

.hero__content > *:nth-child(1) {
    animation-delay: 0s;
}

.hero__content > *:nth-child(2) {
    animation-delay: 60ms;
}

.hero__content > *:nth-child(3) {
    animation-delay: 120ms;
}

.hero__content > *:nth-child(4) {
    animation-delay: 180ms;
}

/* --------------------------------------------------------------------------
   Индикатор прочтения страницы.
   По умолчанию скрыт: показывает его js/motion.js, когда появляется прокрутка.
   -------------------------------------------------------------------------- */

.scroll-progress {
    position: fixed;
    top: 0;
    left: 0;
    z-index: calc(var(--z-header) + 1);
    width: 100%;
    /* Полоса 2px, а высота дорожки 14px — это запас, чтобы свечение полосы
       было видно и при этом обрезалось по краям дорожки */
    height: 14px;
    overflow: hidden;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur) var(--ease);
}

.scroll-progress.is-visible {
    opacity: 1;
}

.scroll-progress__bar {
    display: block;
    width: 100%;
    height: 2px;
    background: linear-gradient(90deg, var(--accent-deep), var(--accent), var(--accent-soft));
    box-shadow: 0 0 12px rgba(200, 30, 40, 0.45);
    /* Сдвиг, а не масштаб: scaleX сжимал и градиент, и свечение — правый край
       всегда оставался фиолетовым независимо от прогресса, а тень
       превращалась в сплюснутый эллипс. */
    transform: translateX(-100%);
}

/* --------------------------------------------------------------------------
   Уважение к системной настройке «меньше движения»
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    .reveal {
        opacity: 1 !important;
        transform: none !important;
    }

    /* Бесконечные анимации выключаем явно, а не «сжимаем до 0,01 мс».
       Сжатие оставляет элемент в состоянии после последнего кадра, и если
       свойство задавалось только кадрами, элемент исчезал: у свечения
       финального призыва фон был прописан лишь в keyframes, и при
       reduced-motion оно пропадало целиком. Теперь у всех этих элементов
       фон/тень заданы в базовых правилах. */
    .btn--primary,
    .cta__glow,
    .marquee__track,
    .tabpanel.is-active {
        animation: none !important;
    }

    /* Каскад первого экрана и бегущая подсветка — чистый декор.
       Свечения (.hero__glow, .cta__glow) здесь не трогаем: у них opacity
       задаёт яркость самого эффекта, а не видимость элемента. */
    .hero__content > *,
    .hero__cue-line {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
    }

    /* Элементы, которые прячутся до появления блока, при отключённом движении
       показываем сразу: ждать каскада нечего, а невидимыми они быть не должны. */
    .js .prize__num {
        opacity: 0.5 !important;
        transform: none !important;
    }
}
