/* Главная страница.
   Фолбэк первого экрана — статичный: сетка, свечение и виньетка на CSS.
   Он же остаётся у всех, у кого WebGL2 нет или выключен, поэтому должен
   выглядеть законченно сам по себе, а не как дырка под сцену. */
@layer components {

/* Художественные блоки закреплены за тёмной схемой в обеих темах.

   Это решение, а не недоделка. Огонь, угли и блик по знаку построены на
   `mix-blend-mode:screen` поверх тёмного — то есть на том, что светлое
   проявляется на тёмном. На белом фоне тот же приём даёт белое по
   белому, и подбирать «светлый огонь» значило бы рисовать другой
   эффект, а не тот же.

   `color-scheme:dark` на самом блоке переключает ВСЕ токены внутри него
   на тёмные значения — проверено замером: снаружи `light-dark()` отдаёт
   светлое, внутри тёмное. Поэтому ни одного цвета здесь дублировать не
   нужно. */
.hero{
  color-scheme: dark;
  /* Свой тёмный фон, а не прозрачность.
     Герой — художественный блок, закреплённый за тёмной схемой: весь
     текст в нём светлый. Пока фона не было, на светлой схеме он
     показывал фон страницы, и заголовок первого экрана оказывался
     светлым по светлому. Под тёмным холстом фон снимается — см.
     `.has-site-gl .hero` в tokens.css. */
  background: var(--art-bg);
  position:relative; overflow:hidden;
  border-bottom:1px solid var(--stroke);
  padding-block:clamp(var(--sp-9),12vh,140px);
}
.hero__art{ position:absolute; inset:0; z-index:0; pointer-events:none }
/* Топография намёком: две сетки под углом дают ощущение среза, а не обоев. */
.hero__grid{
  position:absolute; inset:-20% -10%;
  background-image:
    linear-gradient(var(--stroke) 1px, transparent 1px),
    linear-gradient(90deg, var(--stroke) 1px, transparent 1px);
  background-size:64px 64px;
  transform:perspective(700px) rotateX(58deg) translateY(18%);
  transform-origin:50% 100%;
  opacity:.5;
  mask-image:radial-gradient(120% 80% at 50% 100%, #000 20%, transparent 72%);
  -webkit-mask-image:radial-gradient(120% 80% at 50% 100%, #000 20%, transparent 72%);
}
.hero__glow{
  position:absolute; inset:0;
  background:
    radial-gradient(70% 55% at 22% 12%, rgba(255,176,32,.10), transparent 62%),
    radial-gradient(60% 50% at 82% 30%, rgba(61,224,180,.05), transparent 60%),
    linear-gradient(180deg, transparent 40%, var(--bg-void));
}
.hero__inner{ position:relative; z-index:1 }
/* Знак во весь первый экран.

   Заголовок заходит на нижний край знака — это не случайность, а приём:
   так два слоя читаются как один блок, а не как картинка и подпись под
   ней. Наезд небольшой и только на пустую часть знака, буквы не задевает.

   Появление: расфокус собирается в резкость, знак подаётся вперёд, по
   металлу проходит блик, снизу разгорается отсвет. Это самая дорогая
   анимация на сайте, и она одна: один элемент, один раз за визит. */
/* Наезд считаем от низа знака: у заголовка свой верхний отступ, и без его
   вычитания «минус 24» превращались в восемь. */
/* Сдвиг к центру, но не в центр: знак уходит вправо ровно настолько,
   чтобы перестать упираться в край, и всё ещё держал общий левый край с
   заголовком. На узком экране сдвиг обнуляется сам. */
.hero__logo-wrap{ position:relative; width:max-content; max-width:100%;
                  margin-bottom:calc(var(--sp-8) * -1 - var(--sp-4)) }
/* Сдвиг включаем только там, где под знаком есть свободное место. Задать
   его сразу нельзя: на средних ширинах знак занимает почти всю строку, и
   отступ вытолкнул бы его за край — страница поехала бы вбок. */
@media (min-width:1024px){
  .hero__logo-wrap{ margin-left:clamp(0px, 6vw, 150px) }
}
.hero__logo{
  width:min(760px,94vw); height:auto; display:block;
  animation:logo-in 1.15s var(--ease-out) both;
  animation-delay:60ms;
}
@keyframes logo-in{
  from{ opacity:0; transform:translateY(26px) scale(.94);
        filter:blur(18px) brightness(1.6) saturate(.6) }
  55% { opacity:1 }
  to  { opacity:1; transform:none;
        filter:blur(0) brightness(1) saturate(1) }
}

/* Блик по металлу: узкая полоса света проходит слева направо один раз.
   Маской вырезаем её по силуэту самого знака, иначе светился бы воздух. */
.hero__logo-wrap::before{
  content:""; position:absolute; inset:0; z-index:2; pointer-events:none;
  background:linear-gradient(105deg, transparent 38%,
             rgba(255,255,255,.55) 47%, rgba(255,226,160,.35) 52%,
             transparent 60%);
  background-size:260% 100%; background-position:180% 0;
  -webkit-mask:url(/static/brand/logo-hero.webp) no-repeat center/contain;
  mask:url(/static/brand/logo-hero.webp) no-repeat center/contain;
  animation:logo-sheen 1.3s var(--ease-out) both; animation-delay:700ms;
  mix-blend-mode:var(--blend-fx);
}
@keyframes logo-sheen{
  from{ background-position:180% 0; opacity:0 }
  20% { opacity:1 }
  to  { background-position:-60% 0; opacity:0 }
}

/* Тёплый отсвет под знаком — разгорается следом и остаётся. */
.hero__logo-wrap::after{
  content:""; position:absolute; left:8%; right:8%; bottom:8%;
  height:54px; border-radius:50%; z-index:-1;
  background:radial-gradient(50% 100% at 50% 100%,
             rgba(255,176,32,.34), transparent 70%);
  filter:blur(22px);
  animation:glow-in 1s var(--ease-out) both; animation-delay:640ms;
}
@keyframes glow-in{ from{ opacity:0 } }

/* Огонь по знаку.

   Слой живёт постоянно, поэтому вырезан маской по силуэту самого знака —
   иначе тлел бы воздух вокруг. Две независимые анимации: тёплая волна
   поднимается снизу вверх с постоянной скоростью, а яркость дрожит по
   собственному, некратному ей ритму. Из-за разных периодов повтор на глаз
   не ловится, хотя обе анимации короткие.

   mix-blend-mode:var(--blend-fx) — чтобы огонь ложился светом на металл, а не
   закрашивал его: тёмные участки знака остаются тёмными. */
.hero__fire{
  position:absolute; inset:0; z-index:1; pointer-events:none;
  background:linear-gradient(0deg,
    rgba(255,64,0,.62) 0%, rgba(255,120,10,.46) 16%,
    rgba(255,176,32,.30) 34%, rgba(255,228,150,.13) 52%,
    transparent 70%);
  background-size:100% 240%;
  -webkit-mask:url(/static/brand/logo-hero.webp) no-repeat center/contain;
  mask:url(/static/brand/logo-hero.webp) no-repeat center/contain;
  mix-blend-mode:var(--blend-fx);
  animation:fire-rise 5.2s linear infinite,
            fire-flicker 2.9s var(--ease-in-out) infinite,
            glow-in 1.2s var(--ease-out) both;
  animation-delay:0s, 0s, 900ms;
}
@keyframes fire-rise{
  from{ background-position:50% 100% }
  to  { background-position:50% -55% }
}
@keyframes fire-flicker{
  0%,100%{ opacity:.88 } 11%{ opacity:.62 } 26%{ opacity:1 }
  43%{ opacity:.71 } 59%{ opacity:.96 } 74%{ opacity:.66 } 87%{ opacity:.92 }
}

/* Угли под знаком: дышат медленнее огня, поэтому низ кадра не мигает
   в такт, а живёт своей жизнью. */
.hero__embers{
  position:absolute; left:6%; right:6%; bottom:4%; height:72px; z-index:0;
  pointer-events:none;
  background:radial-gradient(58% 100% at 50% 100%,
             rgba(255,116,0,.42), rgba(255,176,32,.16) 46%, transparent 72%);
  filter:blur(26px);
  animation:ember-breathe 3.7s var(--ease-in-out) infinite;
}
@keyframes ember-breathe{
  0%,100%{ opacity:.5;  transform:scaleY(1) }
  50%    { opacity:1;   transform:scaleY(1.16) }
}

@media (max-width:720px){
  .hero__logo{ width:min(420px,92vw) }
  .hero__logo-wrap{ margin-left:0;
                    margin-bottom:calc(var(--sp-6) * -1 - var(--sp-4)) }
  .hero__embers{ height:44px; filter:blur(18px) }
}
.hero__title{
  font-size:clamp(var(--fs-2xl), 6.4vw, var(--fs-3xl));
  margin:var(--sp-4) 0 var(--sp-5); max-width:16ch;
}
.hero__lede{ color:var(--text-muted); max-width:52ch; font-size:var(--fs-md) }

/* align-items:start обязателен. Без него столбцы растягиваются по самому
   высокому, строки внутри grid тянутся вместе с ними, и подписи оказываются
   на разной высоте — ровно то, что и было видно: «игроков сейчас» выше,
   «серверов онлайн» ниже. */
.hero__meta{ display:flex; align-items:start; gap:var(--sp-8);
             margin-top:var(--sp-7); flex-wrap:wrap }
.hero__stat{ display:grid; gap:var(--sp-2); align-content:start }

/* Крупные цифры набираем витринным шрифтом, а не моноширинным: здесь они
   часть первого экрана, а не измеренная величина в таблице. Внутри
   карточек и таблиц правило прежнее — моноширинный. */
.hero__num{
  font-family:var(--font-display); font-weight:700;
  font-size:clamp(var(--fs-xl), 4vw, var(--fs-2xl));
  letter-spacing:var(--tracking-head);
  font-variant-numeric:tabular-nums;
  color:var(--text); line-height:1;
}
.hero__stat--wide .hero__spark{ width:140px; height:28px }
.hero__spark{ width:140px; height:28px }

.hero__cta{ display:flex; flex-wrap:wrap; gap:var(--sp-3);
            margin-top:var(--sp-8) }
.hero__fine{ margin-top:var(--sp-4); max-width:52ch; font-size:var(--fs-sm) }

/* ------------------------------------------------------------- эпохи */

.epoch{
  position:relative; overflow:hidden;
  /* Высота — по строке сетки, а не по содержимому. У карточек разный
     объём текста (у одной эпохи подпись длиннее), и при display:block
     они получались разной высоты: та, что короче, не доставала до низа
     строки. Подгонять отступами бессмысленно — текст меняется вместе с
     данными; тянем карточку на всю ячейку и распускаем её тело. */
  display:flex; flex-direction:column; height:100%;
  border:1px solid var(--stroke); border-radius:var(--r-lg);
  background:var(--bg-panel); color:inherit;
  transition:border-color var(--dur-2) var(--ease-out),
             transform var(--dur-2) var(--ease-out);
}
.epoch:hover{ border-color:var(--stroke-strong); transform:translateY(-2px) }
/* Раньше здесь стоял кадр карты, и он об эпохе ничего не сообщал: Mirage в
   2015 и в 2023 выглядит одинаково. Теперь фоном идёт короткая петля из
   игры той эпохи, а поверх — её знак. Кадр остаётся фактурой: приглушён и
   затемнён, чтобы знак читался при любом кадре. */
.epoch__art{ color-scheme:dark;
  position:relative; aspect-ratio:16/7; background:var(--art-bg);
             overflow:hidden; display:grid }
.epoch__art > img:not(.epoch__logo),
.epoch__art > video{
  grid-area:1/1; width:100%; height:100%; object-fit:cover;
  object-position:center 42%;
  opacity:.38; filter:grayscale(.4) contrast(1.05);
  transition:opacity var(--dur-3) var(--ease-out),
             filter var(--dur-3) var(--ease-out);
}
.epoch:hover .epoch__art > img:not(.epoch__logo),
.epoch:hover .epoch__art > video{ opacity:.55; filter:grayscale(.15) contrast(1.05) }
.epoch__art::after{ content:""; grid-area:1/1; z-index:1;
  background:linear-gradient(180deg, var(--art-fade-1) 30%, var(--art-fade-2) 78%,
                             var(--bg-panel)) }

/* Знак эпохи — вместо крупного года: год в нём уже есть. */
.epoch__logo{
  grid-area:1/1; z-index:2; place-self:center;
  /* Высота, а не ширина: знаки эпох нарисованы в разных пропорциях, и по
     ширине они выравнивались бы только по бумаге, а не на глаз. */
  height:min(62%, 128px); width:min(70%, 260px); object-fit:contain;
  filter:drop-shadow(0 8px 24px var(--shadow-color));
  transition:transform var(--dur-3) var(--ease-out);
}
.epoch:hover .epoch__logo{ transform:scale(1.04) }

/* Год остаётся для эпох, у которых знака пока нет. */
.epoch__year{
  grid-area:1/1; z-index:2; align-self:end; justify-self:start;
  margin:0 0 var(--sp-3) var(--sp-5);
  font-family:var(--font-display); font-size:var(--fs-2xl); font-weight:700;
  color:var(--text); line-height:1; letter-spacing:-.03em;
}
.epoch__badge{ grid-area:1/1; z-index:3; align-self:start; justify-self:start;
               margin:var(--sp-3) 0 0 var(--sp-3) }
.epoch__lock{ grid-area:1/1; z-index:3; align-self:start; justify-self:end;
              margin:var(--sp-3) var(--sp-3) 0 0 }
/* Тело забирает остаток высоты, а строка с цифрами прижимается к низу:
   тогда у обеих карточек «Игроки / Серверы / Режимы» стоят на одной
   линии независимо от длины подписи выше. */
/* Колонка на flex, а не на grid: в grid-контейнере `margin-top:auto`
   у элемента не прижимает его к низу — строку двигает align-content, и
   цифры оставались на разной высоте у карточек с подписями разной
   длины. */
.epoch__body{ padding:var(--sp-5); display:flex; flex-direction:column;
              gap:var(--sp-3); flex:1 }
.epoch__body > .epoch__facts{ margin-top:auto }
.epoch__title{ font-size:var(--fs-lg) }
.epoch__facts{ display:flex; gap:var(--sp-5); flex-wrap:wrap;
               font-size:var(--fs-sm) }
.epoch__facts div{ display:grid; gap:2px }
.epoch__facts .k{ font-size:var(--fs-2xs); font-weight:600;
  letter-spacing:var(--tracking-caps); text-transform:uppercase;
  color:var(--text-faint) }

/* --------------------------------------------------------------- шаги */

/* Номер был абсолютом поверх карточки — и лёг прямо на заголовок: у
   .panel__pad свой padding, он перебивал padding-top у li, и место под
   номер исчезало. Ставим номер в поток: тогда он не может ни на что
   наехать, какой бы длины ни оказался заголовок. */
.steps{ list-style:none; margin:0; padding:0 }
.steps li{ display:grid; gap:var(--sp-2); align-content:start }
.steps__n{
  font-family:var(--font-display); font-size:var(--fs-lg); font-weight:700;
  color:var(--accent-ink); line-height:1; margin-bottom:var(--sp-1);
}
.steps h3{ margin:0 }

/* -------------------------------------------------------- честная игра */

.fair{ display:grid; grid-template-columns:auto 1fr; gap:var(--sp-5);
       align-items:start; max-width:820px }
.fair__icon{ width:32px; height:32px; stroke:var(--accent-ink); fill:none;
             stroke-width:1.6; margin-top:var(--sp-1) }
@media (max-width:640px){ .fair{ grid-template-columns:1fr } }

} /* @layer components */

/* ------------------------------------------------- страница эпохи
   Открыта поисковикам, поэтому живого состояния здесь нет: только то, что
   не меняется от минуты к минуте. */
@layer components {
  .crumbs{ color:var(--text-faint); font-size:var(--fs-sm) }
  .crumbs a:hover{ color:var(--accent-ink) }
  .crumbs span[aria-hidden]{ margin-inline:var(--sp-2) }

  .ep-head{ display:grid; grid-template-columns:minmax(0,5fr) minmax(0,7fr);
            overflow:hidden }

  /* Ролик — фон, а не содержимое: приглушён и затемнён снизу, чтобы знак
     поверх читался при любом кадре. Без этого светлый кадр съедал бы знак. */
  .ep-head__art{ position:relative; min-height:260px; overflow:hidden;
                 background:var(--bg-sunken); display:grid }
  .ep-head__art > video,
  .ep-head__art > img:not(.ep-head__logo){
    grid-area:1/1; width:100%; height:100%; object-fit:cover;
    opacity:.55; filter:grayscale(.2) contrast(1.05);
  }
  .ep-head__art::after{
    content:""; grid-area:1/1; z-index:1;
    background:radial-gradient(120% 90% at 50% 40%, transparent 30%,
               var(--art-fade-2) 100%);
  }
  .ep-head__logo{
    grid-area:1/1; z-index:2; place-self:center;
    height:min(58%, 190px); width:min(78%, 340px); object-fit:contain;
    filter:drop-shadow(0 10px 30px var(--shadow-color));
    animation:ep-logo-in .8s var(--ease-out) both; animation-delay:120ms;
  }
  @keyframes ep-logo-in{
    from{ opacity:0; transform:translateY(10px) scale(.96) }
  }

  .ep-head__body{ padding:var(--sp-7) }
  @media (max-width:820px){
    .ep-head{ grid-template-columns:1fr }
    .ep-head__art{ min-height:200px }
    .ep-head__logo{ height:min(52%, 130px); width:min(70%, 240px) }
    .ep-head__body{ padding:var(--sp-5) }
  }

  /* Карточка соседней эпохи: знак слева, текст справа. */
  .ep-other{ display:flex; align-items:center; gap:var(--sp-4) }
  .ep-other__logo{ height:60px; width:96px; object-fit:contain; flex:none }
  .ep-other__title{ display:block; color:var(--text);
                    font-size:var(--fs-lg); font-weight:600 }
  @media (max-width:520px){ .ep-other__logo{ height:44px; width:64px } }
}

/* ================================================= карты эпохи

   Порядок задаёт страница: первая карточка помечена как главная. Снимка
   может не быть — тогда рисуем подложку с именем файла, а не битую
   ссылку: поломка и «снимка пока нет» должны выглядеть по-разному. */

.emap{ overflow:hidden; display:flex; flex-direction:column }
.emap__img{
  width:100%; aspect-ratio:16/9; object-fit:cover; display:block;
  border-bottom:1px solid var(--stroke);
}
.emap__blank{
  display:grid; place-items:center;
  width:100%; aspect-ratio:16/9;
  background:linear-gradient(160deg, var(--bg-elevated), var(--bg-sunken));
  border-bottom:1px solid var(--stroke);
  color:var(--muted); font-family:var(--font-mono, monospace);
  font-size:var(--fs-sm); letter-spacing:.02em;
}
.emap__body{
  display:flex; align-items:center; justify-content:space-between;
  gap:var(--sp-2); padding:var(--sp-3);
}
.emap__name{ font-weight:600; color:var(--text) }

/* ============================================ холст первого экрана

   Лежит поверх нарисованных градиента и сетки, но под содержимым. Если
   холст не завёлся, ничего не меняется: под ним всё то же, что было
   раньше, — поэтому «нет WebGL» выглядит как прежний первый экран, а не
   как дырка.

   Проявляется плавно: сам шейдер тоже разгорается, но холст добавляется в
   разметку раньше первого кадра, и без этого была бы вспышка чёрным. */
.hero__gl{
  position:absolute; inset:0;
  width:100%; height:100%;
  display:block;
  opacity:0;
  animation:gl-in 1.2s var(--ease-out) .1s forwards;
  /* Холст ничего не ловит: все нажатия принадлежат содержимому над ним. */
  pointer-events:none;
}
@keyframes gl-in{ to{ opacity:1 } }

/* Когда холст есть, нарисованные слои приглушаем — иначе сетка спорит с
   металлом. Совсем убирать нельзя: они держат низ экрана. */
.hero__art.has-gl .hero__grid{ opacity:.18 }
.hero__art.has-gl .hero__glow{ opacity:.45; animation:none }

@media (prefers-reduced-motion:reduce){
  .hero__gl{ display:none }
}
