/* Chill Hub — лендинг 2.0
   ------------------------------------------------------------------
   Идея оформления: ночь и один фиолетовый — тот самый, которым в
   лаунчере залита кнопка «Играть». Сайт и лаунчер теперь одного цвета:
   человек видит на странице то, что получит, поставив программу.

   Акцент один, но у него две роли. Знак (ссылки, подписи, указатели)
   красится светлым фиолетовым — ему нужен контраст к тёмному фону.
   Заливка кнопки — тёмным, потому что на ней стоит белая подпись.
   Одна краска на обе роли не проходит порог ни там, ни там.

   Отсюда все запреты ниже: ни второго акцента, ни градиента, ни неона.
   Если элементу нужно выделиться, он выделяется поверхностью и рамкой,
   а не свечением. Одно исключение — игровой автомат в «Заявках»: это
   аттракцион, и запреты сняты с него намеренно (см. его раздел).
   ------------------------------------------------------------------ */

/* ---------- Токены ---------- */

:root {
  color-scheme: dark light;

  /* Поверхности — те же, что в лаунчере. Каждая следующая на шаг светлее
     предыдущей: глубина набирается светлотой, а не тенью. */
  --page: #0c0c10;
  --surface: #14141b;
  --surface-2: #1b1b24;
  --surface-3: #20202a;
  --line: #24242f;
  --line-2: #35354a;
  --fg: #e9e9f0;
  --fg-2: #9a9aab;
  --fg-3: #86869f;

  /* Фиолетовый. Знак — светлый: на самом светлом фоне #9a82ff даёт 5,39.
     Заливка — тёмная: белая подпись на #6949e0 даёт 5,79, под курсором 4,94,
     в нажатии 6,96. Приглушённый — только для указателей и рамок. */
  --accent: #9a82ff;
  --accent-hi: #b3a3ff;
  --accent-dim: #7c5cff;
  --accent-fill: #6949e0;
  --accent-fill-hi: #7457e6;
  --accent-fill-lo: #5a3fcc;
  --on-accent: #fff;
  --accent-wash: rgb(124 92 255 / 14%);

  /* Статусы: приглушённые, чтобы не спорить с акцентом. */
  --ok: #6f9d63;
  --warn: #bf9439;
  --bad: #c0564d;
  --shot-frame: #08080b;

  /* Радиус почти отсутствует: скругление здесь ничего не сообщает,
     а «мягкий по умолчанию» — первый признак шаблона. */
  --r: 3px;
  --r-lg: 5px;
  --header-h: 60px;

  /* Модульная шкала отступов, шаг 1.5. Промежуточных значений нет:
     любой отступ на странице — одно из этих шести чисел. */
  --s1: 4px;
  --s2: 8px;
  --s3: 14px;
  --s4: 22px;
  --s5: 36px;
  --s6: 58px;
  --s7: 92px;
  --measure: 64ch;
  --wide: 1180px;
  --sans: "IBM Plex Sans", ui-sans-serif, system-ui, "Segoe UI", sans-serif;
  --display: bitter, ui-serif, georgia, serif;
  --mono: "IBM Plex Mono", ui-monospace, "Cascadia Mono", consolas, monospace;
}

/* Светлая тема — прохладная бумага с лёгкой синевой, а не белый лист:
   на #fff тёмные скриншоты лаунчера выглядят дырами. */
@media (prefers-color-scheme: light) {
  :root {
    --page: #f4f4f8;
    --surface: #fbfbfd;
    --surface-2: #ececf3;
    --surface-3: #e2e2eb;
    --line: #d9d9e3;
    --line-2: #b8b8c8;
    --fg: #17171f;
    --fg-2: #55556a;
    --fg-3: #5f5f73;
    --accent: #5a3fcc;
    --accent-hi: #4a30b8;
    --accent-dim: #6949e0;
    --accent-fill: #6949e0;
    --accent-fill-hi: #5a3fcc;
    --accent-fill-lo: #4a30b8;
    --on-accent: #fff;
    --accent-wash: rgb(105 73 224 / 10%);
    --shot-frame: #d0d0da;
  }
}

/* ---------- Основа ---------- */

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

/* Скрытое обязано быть скрытым.

   Встроенное правило браузера `[hidden] { display: none }` слабее любого
   собственного, задающего `display` элементу, — и скрытая строка
   показывалась подписью без значения: «размер», «собран», «SHA-256» и
   пустота рядом. Пряталось ровно от этого. Правило общее, потому что
   ловить такие места по одному значит пропустить следующее. */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + var(--s4));
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  background: var(--page);
  color: var(--fg);
  font: 400 16px/1.6 var(--sans);
  font-feature-settings: "kern", "liga";
  padding-top: var(--header-h);
  overflow-x: hidden;
}

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

img { height: auto; }

a { color: inherit; }

:where(a, button, input, select, summary):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r);
}

::selection {
  background: var(--accent-fill);
  color: var(--on-accent);
}

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

h1, h2, h3, h4 {
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

h1, h2 { font-family: var(--display); }

h1 {
  font-size: clamp(2rem, 1.3rem + 3vw, 3.4rem);
  line-height: 1.08;
  letter-spacing: -0.025em;
}

h2 {
  font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.1rem);
  line-height: 1.15;
}

h3 { font-size: 1.0625rem; line-height: 1.35; }

p { margin: 0; max-width: var(--measure); }

/* Браузерные поля у figure — 1em сверху и 40px по бокам. Незаметные,
   пока не обнаружишь, что скриншот в первом экране уже 80px, чем
   колонка, в которую он положен. */
figure { margin: 0; }

small { font-size: 0.8125rem; }

code, kbd { font-family: var(--mono); font-size: 0.875em; }

kbd {
  padding: 1px 5px;
  border: 1px solid var(--line-2);
  border-bottom-width: 2px;
  border-radius: var(--r);
  background: var(--surface-2);
  font-size: 0.75rem;
}

.dim { color: var(--fg-2); }
.faint { color: var(--fg-3); }

/* ---------- Раскладка ---------- */

.wrap {
  width: min(100% - var(--s4) * 2, var(--wide));
  margin-inline: auto;
}

.section {
  padding-block: var(--s7);
  border-top: 1px solid var(--line);
  position: relative;
  z-index: 1;
}

.section > .wrap > header {
  margin-bottom: var(--s5);
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  flex-wrap: wrap;
}

.section > .wrap > header p {
  color: var(--fg-2);
  max-width: 46ch;
  font-size: 0.9375rem;
}

.eyebrow {
  font: 500 0.6875rem/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-3);
  display: block;
  margin-bottom: var(--s3);
}

/* ---------- Кнопки ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  padding: 10px 18px;
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  background: var(--surface-2);
  color: var(--fg);
  font: 500 0.9375rem/1.2 var(--sans);
  text-decoration: none;
  cursor: pointer;
  transition: background-color .12s linear, border-color .12s linear;
}

.btn:hover { background: var(--surface-3); border-color: var(--line-2); }
.btn:active { background: var(--surface); }

.btn--primary {
  background: var(--accent-fill);
  border-color: var(--accent-fill);
  color: var(--on-accent);
  font-weight: 600;
}

.btn--primary:hover { background: var(--accent-fill-hi); border-color: var(--accent-fill-hi); }
.btn--primary:active { background: var(--accent-fill-lo); border-color: var(--accent-fill-lo); }



.btn--lg { padding: 14px 26px; font-size: 1rem; }

.btn[disabled] { opacity: 45%; cursor: default; pointer-events: none; }

/* ---------- Шапка ---------- */

/* Непрозрачная, с волосяной линией. Размытое «стекло» поверх скриншотов
   превращает их в кашу и читается как декор ради декора. */
.site-header {
  position: fixed;
  inset: 0 0 auto;
  height: var(--header-h);
  z-index: 50;
  background: var(--page);
  border-bottom: 1px solid var(--line);
}

.site-header .wrap {
  height: 100%;
  display: flex;
  align-items: center;
  gap: var(--s4);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--s2);
  text-decoration: none;
  font-family: var(--display);
  font-weight: 600;
  font-size: 1.0625rem;
  letter-spacing: -0.01em;
  flex: 0 0 auto;
}

.brand img { width: 32px; height: 32px; }

.site-nav {
  display: flex;
  align-items: center;
  gap: var(--s4);
  margin-left: auto;
  font-size: 0.9375rem;
}

.site-nav .nav-link {
  color: var(--fg-2);
  text-decoration: none;
  padding-block: 4px;
  border-bottom: 1px solid transparent;
}

.site-nav .nav-link:hover { color: var(--fg); border-bottom-color: var(--line-2); }

.site-header .wrap > .btn { flex: 0 0 auto; }

/* НА ТЕЛЕФОНЕ РАЗДЕЛЫ ТОЖЕ НУЖНЫ.
   Ссылки просто прятались, и в шапке оставалась одна кнопка «Скачать»:
   попасть в «Игры», «Как это работает» и «Что ставится» с телефона было
   неоткуда — только прокруткой всей страницы или из подвала.

   Шапка становится двухрядной: имя и кнопка сверху, разделы под ними.
   Высота объявлена переменной, поэтому отступ страницы и прокрутка к
   якорям пересчитываются сами. */
@media (width < 720px) {
  :root { --header-h: 104px; }

  .site-header .wrap {
    flex-wrap: wrap;
    align-content: center;
    row-gap: var(--s2);
  }

  .site-header .wrap > .btn { margin-left: auto; }

  .site-nav {
    order: 3;
    width: 100%;
    margin-left: 0;
    font-size: 0.875rem;
  }
}

/* ---------- Фон ---------- */

/* Волновое поле. Осталось от версии 1.0 сознательно: это единственная
   вещь на странице, которая двигается сама по себе, и она задаёт
   «холодную ночь». Но амплитуда и контраст срезаны так, чтобы поле
   читалось как фактура, а не как заставка, и оно больше не закрывает
   старт страницы спиннером — сетка рисуется поверх готового фона. */

/* Имя намеренно не `.field`: этот же класс носят строки формы заявки,
   и на общем имени они получали `position: fixed; inset: 0` — то есть
   раскрывались во весь экран непрозрачной плашкой и закрывали
   страницу. */
.backdrop {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: var(--page);
}

.backdrop canvas {
  width: 100%;
  height: 100%;
  opacity: 0%;
  transition: opacity 1.2s ease;
}

.backdrop.on canvas { opacity: 100%; }

main { position: relative; z-index: 1; }

/* ---------- Герой ---------- */

/* Экран не отдаётся целиком под заголовок: к моменту первого скролла
   посетитель должен уже увидеть, как продукт выглядит. */
.hero {
  padding-block: var(--s6) var(--s7);
  position: relative;
  z-index: 1;
}

.hero .wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: var(--s6);
  align-items: center;
}

@media (width < 900px) {
  .hero .wrap { grid-template-columns: 1fr; gap: var(--s5); }
}

.hero h1 { margin-bottom: var(--s4); }

.hero h1 em {
  font-style: normal;
  color: var(--accent);
}

.hero-lede {
  font-size: 1.0625rem;
  color: var(--fg-2);
  max-width: 44ch;
  margin-bottom: var(--s5);
}

.hero-cta {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
  margin-bottom: var(--s3);
}

/* ---------- Факты о загрузке ---------- */

/* Скачивание неподписанного exe с незнакомого сайта — самый уязвимый
   момент всей воронки. Версия, размер, дата и хеш стоят прямо под
   кнопкой, а не прячутся: это ровно те четыре вещи, которых не хватает,
   чтобы решиться нажать. */
.dl-facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1) var(--s3);
  font: 400 0.8125rem/1.5 var(--mono);
  color: var(--fg-3);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* `display` в правиле для элемента списка сильнее встроенного
   `[hidden] { display: none }` — и факты об установщике, которых нет,
   показывались подписями без значений: «размер», «собран», «SHA-256» и
   пустота. Это ровно то, ради чего их и прятали. */
.dl-facts li { display: flex; gap: 6px; }
.dl-facts li[hidden] { display: none; }
.dl-facts b { color: var(--fg-2); font-weight: 400; }

.dl-facts .copy-hash {
  border: 0;
  background: none;
  padding: 0;
  color: var(--fg-2);
  font: inherit;
  cursor: pointer;
  border-bottom: 1px dotted var(--line-2);
}

.dl-facts .copy-hash:hover { color: var(--accent); }

/* ---------- Снимок в первом экране ---------- */

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

   Светлый контур в пиксель запечён в сам снимок — так его рисует Windows.
   Без него тёмное окно растворялось бы на такой же тёмной странице. Тень
   мягкая и нейтральная: свечения акцентом здесь нет, как и во всём сайте. */
.hero-shot { position: relative; }

.hero-shot img {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 24px 48px rgb(0 0 0 / 45%));
}

/* ---------- Рамка скриншота ---------- */

.shot {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--shot-frame);
  overflow: hidden;
  position: relative;
}

/* Только собственная картинка рамки. Без `>` правило растягивало во всю
   ширину любое изображение внутри — в том числе значки игр в эмуляторе,
   который стоит в такой же рамке. */
.shot > img { width: 100%; }

.shot figcaption {
  padding: var(--s2) var(--s3);
  border-top: 1px solid var(--line);
  background: var(--surface);
  font-size: 0.8125rem;
  color: var(--fg-2);
}

/* Скелет — не украшение: картинки тяжёлые, и без него на месте
   скриншота полсекунды зияет дыра, из-за которой прыгает вся раскладка. */
.skeleton {
  background:
    linear-gradient(90deg, var(--surface) 0%, var(--surface-2) 50%, var(--surface) 100%);
  background-size: 200% 100%;
  animation: sk 1.4s linear infinite;
}

@keyframes sk { to { background-position: -200% 0; } }

img.loaded { animation: none; background: none; }

/* ---------- Игры ---------- */

/* КАТАЛОГ — ЭТО СПИСОК, А НЕ ВОСЕМЬ РАССКАЗОВ.
   ------------------------------------------------------------------
   Карточка была высотой в треть экрана и на три четверти состояла из
   текста, одинакового у всех игр. Восемь таких карточек — это экран, по
   которому нельзя пробежать глазами, хотя пришли сюда ровно за этим:
   посмотреть, есть ли в списке своя игра.

   Плитка отвечает на этот вопрос строкой: значок, название, модпак.
   Общее для всех сказано один раз в подписи раздела. */
.games {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: var(--s2);
}

/* ОДНА КАРТОЧКА НА ВСЮ СТРАНИЦУ.
   ------------------------------------------------------------------
   Блоков было пять, и выглядели они пятью разными способами: плитки
   каталога — рамка и радиус, шаги — строки с разделителями, факты —
   сетка внутри общей рамки без радиуса, врезка — свой радиус и свои
   отступы, автомат — тёмный корпус. Читается это как пять кусков от
   разных страниц, сложенных подряд.

   Рамка, радиус, фон и отступ теперь заданы один раз здесь, и берут их
   все. Отличаются блоки только тем, чем должны: у врезки полоса
   предупреждения, у автомата тёмный корпус прибора. */
.game,
.facts > div,
.warnbox {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  padding: var(--s3);
}

.game {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-width: 0;
}

/* Значок из каталога, а когда его нет — буква на плашке. Пустое место
   на его месте сбивает высоту плиток в ряду. */
.game-ico {
  width: 40px;
  height: 40px;
  flex: 0 0 auto;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface-2);
  object-fit: cover;
}

.game-ico--letter {
  display: grid;
  place-items: center;
  font: 600 1rem/1 var(--display);
  color: var(--fg-3);
}

.game-body { min-width: 0; }

/* Названия игр бывают длинными («Drive Beyond Horizons»), а плитка на
   телефоне — узкой: без переноса слово вылезает за край. */
.game h3,
.facts h3,
.warnbox h3,
.steps h3 {
  margin: 0;
  font: 600 0.9375rem/1.3 var(--sans);
  overflow-wrap: anywhere;
}

.game-pack {
  margin: 2px 0 0;
  font-size: 0.8125rem;
  color: var(--fg-2);
  overflow-wrap: anywhere;
}

/* Каталог кончался тупиком: своей игры человек не нашёл, и дальше ему
   некуда. Пунктир отличает эту плитку от игр — она не игра. */
.game--ask {
  text-decoration: none;
  color: inherit;
  border-style: dashed;
}

.game--ask:hover { border-color: var(--accent); }
.game--ask:hover h3 { color: var(--accent); }

/* ---------- Технические работы ---------- */

/* Полоса, а не всплывающее окно: её нельзя закрыть и забыть, а
   перекрывать ею страницу не за что — читать сайт техработы не мешают. */
.maint {
  border-bottom: 1px solid var(--line-2);
  border-left: 3px solid var(--warn);
  background: var(--surface);
  padding: var(--s3) 0;
  position: relative;
  z-index: 2;
}

.maint .wrap { display: flex; gap: var(--s3); align-items: baseline; flex-wrap: wrap; }
.maint b { font-size: 0.9375rem; }
.maint span { color: var(--fg-2); font-size: 0.9375rem; }

/* ---------- Скелеты карточек ---------- */

/* Разделы приходят из API, и до ответа на их месте должна стоять форма
   будущего содержимого, а не пустота, из-за которой страница прыгает. */
.sk-card {
  min-height: 68px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background:
    linear-gradient(90deg, var(--surface) 0%, var(--surface-2) 50%, var(--surface) 100%);
  background-size: 200% 100%;
  animation: sk 1.4s linear infinite;
}

/* ---------- Шаги ---------- */

/* Раньше здесь было шесть карточек с иконками, три в ряд. Карточка не
   несёт порядка, а порядок тут — весь смысл: это последовательность, и
   она набрана нумерованным списком. */
.steps {
  list-style: none;
  counter-reset: step;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0;
  border-top: 1px solid var(--line);
}

.steps li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 3rem minmax(0, 15rem) minmax(0, 1fr);
  gap: var(--s4);
  align-items: baseline;
  padding: var(--s4) 0;
  border-bottom: 1px solid var(--line);
}

@media (width < 760px) {
  .steps li { grid-template-columns: 2rem minmax(0, 1fr); }
  .steps li p { grid-column: 2; }
}

.steps li::before {
  content: counter(step, decimal-leading-zero);
  font: 400 0.8125rem/1.6 var(--mono);
  color: var(--accent);
}

.steps p { color: var(--fg-2); font-size: 0.875rem; }

/* ---------- Факты ---------- */

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: var(--s2);
}

.facts > div { display: grid; gap: var(--s1); align-content: start; }
.facts p { font-size: 0.875rem; color: var(--fg-2); }
.facts code { color: var(--fg); }

/* Предупреждение SmartScreen: первое, что видит каждый первый
   пользователь после скачивания. Молчать об этом дороже, чем сказать. */
.warnbox {
  border-left: 3px solid var(--warn);
  margin-top: var(--s3);
  display: grid;
  gap: var(--s1);
}

.warnbox p { font-size: 0.875rem; color: var(--fg-2); }

/* ---------- Автомат ---------- */

/* Единственный аттракцион, который оставлен, — и единственное место,
   где запреты из шапки файла не действуют. Автомат обязан выглядеть
   как автомат: лампочки по рамке, свечение, искры на выигрыше. Всё это
   украшение вокруг формы, а не вместо неё: комбинация уходит в заявку,
   заявка — в те же «Обращения», что и из лаунчера. Каждая анимация
   здесь молчит при `prefers-reduced-motion`. */

@property --lever-pull {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

@property --ring {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.slots {
  --glow: 0;
  --item-h: 44px;
  --reel-h: calc(var(--item-h) * 3 + 16px);

  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px minmax(280px, 380px);
  gap: var(--s4);
  align-items: start;
}

@media (width < 960px) {
  .slots { grid-template-columns: minmax(0, 1fr) 44px; }
  .slots .wish { grid-column: 1 / -1; width: 100%; }
}

/* Барабаны крутятся рядом при любой ширине — автомат так выглядит
   везде. На телефоне строки длиннее, чем треть экрана: ряд выше, шрифт
   меньше. Скрипт читает --item-h отсюда же, поэтому позиции сходятся. */
@media (width < 640px) {
  .slots { --item-h: 56px; grid-template-columns: 1fr; }
}

/* Корпус */

.machine {
  position: relative;
  isolation: isolate;
  padding: var(--s4);
  border: 1px solid var(--line-2);
  border-radius: var(--r-lg);
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--surface-3) 70%, transparent), transparent 40%),
    var(--surface);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--fg) 8%, transparent),
    0 24px 60px -30px #000,
    0 0 calc(80px * var(--glow)) calc(-10px + 20px * var(--glow)) color-mix(in srgb, var(--accent-dim) 55%, transparent);
  transition: box-shadow .5s ease;
  display: grid;
  gap: var(--s3);
  overflow: hidden;
}

.slots.busy .machine { --glow: 1; }
.slots.done .machine { --glow: 0.45; }

.slots.thud .machine { animation: thud .5s cubic-bezier(.2, .9, .3, 1.4); }

@keyframes thud {
  0% { transform: translateY(0); }
  30% { transform: translateY(3px) scaleY(.985); }
  60% { transform: translateY(-2px); }
  100% { transform: translateY(0); }
}

/* Лампочки по рамке: точечная сетка, оставленная только на бортике
   через маску. Идут по кругу медленно, при прокрутке — быстро, при
   выпадении — мигают всей рамкой. */
.machine-lights {
  position: absolute;
  inset: 0;
  padding: 7px;
  pointer-events: none;
  z-index: 3;
  background:
    radial-gradient(circle at 50% 50%, var(--accent-hi) 0 2px, color-mix(in srgb, var(--accent-dim) 40%, transparent) 2.5px, transparent 3.5px)
    0 0 / 16px 16px;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: 35%;
  animation: chase 2.4s steps(8) infinite;
  transition: opacity .4s;
}

.slots.busy .machine-lights { opacity: 100%; animation-duration: .6s; }
.slots.done .machine-lights { opacity: 90%; animation: chase 2.4s steps(8) infinite, blink 1.1s ease-in-out 3; }

@keyframes chase { to { background-position: 128px 0; } }

@keyframes blink {
  0%, 100% { opacity: 90%; filter: brightness(1); }
  50% { opacity: 30%; filter: brightness(1.6); }
}

/* Табло */

.machine-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s3);
  flex-wrap: wrap;
  font: 500 0.6875rem/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.machine-brand { color: var(--accent); text-shadow: 0 0 calc(12px * var(--glow)) var(--accent-dim); }
.machine-combo b { color: var(--fg); font-weight: 600; display: inline-block; min-width: 4ch; }
.machine-combo i { font-style: normal; margin-left: 4px; }
.slots.done .machine-combo b { animation: flip .5s cubic-bezier(.2, .9, .3, 1.3); }

@keyframes flip {
  from { transform: rotateX(90deg) translateY(-6px); opacity: 0%; }
  to { transform: none; opacity: 100%; }
}

/* Подписи барабанов */

.machine-head {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  margin-bottom: calc(var(--s3) * -1 + 4px);
  font: 500 0.6875rem/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.machine-head span { text-align: center; }

/* Барабаны */

.reels {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  width: 100%;
  padding: 6px;
  border-radius: var(--r-lg);
  background:
    linear-gradient(180deg, #000 0%, color-mix(in srgb, var(--page) 60%, #000) 100%);
  box-shadow: inset 0 2px 8px #000, inset 0 0 0 1px color-mix(in srgb, var(--fg) 6%, transparent);
}

.reel {
  position: relative;
  height: var(--reel-h);
  overflow: hidden;
  border-radius: var(--r);
  background:
    linear-gradient(180deg, #05050a 0%, var(--surface-2) 22%, var(--surface-3) 50%, var(--surface-2) 78%, #05050a 100%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fg) 8%, transparent);
  transform-origin: 50% 50%;
}

.reel.stopped { animation: reel-stop .45s cubic-bezier(.2, .9, .3, 1.6); }

@keyframes reel-stop {
  0% { transform: scaleY(1); }
  35% { transform: scaleY(.94) translateY(2px); }
  70% { transform: scaleY(1.02); }
  100% { transform: scaleY(1); }
}

.reel-track {
  position: absolute;
  inset-inline: 0;
  top: calc((var(--reel-h) - var(--item-h) * 3) / 2);
  will-change: transform;
  transition: filter .2s;
}

.slots.busy .reel:not(.stopped) .reel-track { filter: blur(1.3px); }

.reel-track div {
  height: var(--item-h);
  display: flex;
  align-items: center;
  justify-content: center;
  padding-inline: var(--s3);
  font: 600 0.875rem/1.2 var(--sans);
  color: var(--fg-2);
  text-align: center;
  text-shadow: 0 1px 0 #000;
  overflow-wrap: anywhere;
  transition: color .3s, transform .3s;
}

@media (width < 640px) {
  .reel-track div { font-size: 0.75rem; padding-inline: 6px; hyphens: auto; }
}

.slots.done .reel-track div.hit {
  color: var(--fg);
  transform: scale(1.08);
  text-shadow: 0 0 10px var(--accent-dim), 0 0 24px color-mix(in srgb, var(--accent-dim) 60%, transparent);
  animation: hit-pop .55s cubic-bezier(.2, .9, .3, 1.5);
}

@keyframes hit-pop {
  0% { transform: scale(.9); filter: brightness(2); }
  100% { transform: scale(1.08); filter: brightness(1); }
}

/* Линия выигрыша: рамка посередине и блик, который проносится по ней,
   когда все три барабана встали. */
.reel-line {
  position: absolute;
  inset-inline: 0;
  top: calc((var(--reel-h) - var(--item-h)) / 2);
  height: var(--item-h);
  border-block: 1px solid color-mix(in srgb, var(--fg) 14%, transparent);
  pointer-events: none;
  z-index: 2;
  overflow: hidden;
  transition: border-color .3s, box-shadow .3s;
}

.reel-line::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 20%, color-mix(in srgb, var(--fg) 22%, transparent) 50%, transparent 80%);
  transform: translateX(-120%);
}

.slots.done .reel-line {
  border-color: var(--accent);
  box-shadow: 0 0 18px color-mix(in srgb, var(--accent-dim) 45%, transparent), inset 0 0 12px color-mix(in srgb, var(--accent-dim) 25%, transparent);
}

.slots.done .reel-line::after { animation: sweep .9s ease-out .15s; }

@keyframes sweep { to { transform: translateX(120%); } }

/* Изгиб барабана: тени сверху и снизу читаются как цилиндр. */
.reel-shade {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background:
    linear-gradient(180deg, #000 0%, transparent 32%, transparent 68%, #000 100%),
    linear-gradient(90deg, color-mix(in srgb, #000 35%, transparent), transparent 12%, transparent 88%, color-mix(in srgb, #000 35%, transparent));
}

/* Стекло: блик, который следует за курсором. Координаты приходят из
   скрипта переменными --mx/--my; без скрипта блик стоит в углу. */
.machine-glass {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  background:
    radial-gradient(240px circle at var(--mx, 20%) var(--my, 0%), color-mix(in srgb, var(--fg) 9%, transparent), transparent 70%);
  opacity: 0%;
  transition: opacity .4s;
}

.machine:hover .machine-glass { opacity: 100%; }

/* Искры при выпадении. Каждая получает свой вектор из скрипта. */
.sparks {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 4;
  overflow: hidden;
}

.sparks i {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--s, 4px);
  height: var(--s, 4px);
  border-radius: 50%;
  background: var(--accent-hi);
  box-shadow: 0 0 8px var(--accent);
  animation: spark var(--d, .9s) cubic-bezier(.1, .8, .4, 1) forwards;
}

@keyframes spark {
  0% { transform: translate(0, 0) scale(1); opacity: 100%; }
  100% { transform: translate(var(--dx), var(--dy)) scale(.2); opacity: 0%; }
}

.slots-out {
  font-size: 0.9375rem;
  color: var(--fg-2);
  min-height: 1.6em;
  position: relative;
  z-index: 2;
}

.slots.done .slots-out { animation: rise .4s ease-out; }

@keyframes rise {
  from { transform: translateY(6px); opacity: 0%; }
  to { transform: none; opacity: 100%; }
}

.slots-actions {
  display: flex;
  gap: var(--s3);
  flex-wrap: wrap;
  align-items: center;
  position: relative;
  z-index: 2;
}

.slots-hint { font-size: 0.8125rem; color: var(--fg-3); }

@media (width < 640px) { .slots-hint { display: none; } }

/* Кнопка «Крутить»: перелистывает надпись, пока крутится, и пускает
   блик по себе при наведении. Подписана акцентом, а не залита: залитая
   кнопка на странице одна — та, что скачивает лаунчер. */
.btn--spin {
  position: relative;
  overflow: hidden;
  border-color: var(--accent-dim);
  color: var(--accent-hi);
  background: color-mix(in srgb, var(--accent-dim) 14%, var(--surface-2));
  font-weight: 600;
  letter-spacing: 0.02em;
  min-width: 9.5em;
}

.btn--spin::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg, transparent 30%, color-mix(in srgb, var(--fg) 20%, transparent) 50%, transparent 70%);
  transform: translateX(-120%);
}

.btn--spin:hover { background: color-mix(in srgb, var(--accent-dim) 24%, var(--surface-2)); }
.btn--spin:hover::after { animation: sweep .7s ease-out; }

.btn-spin-face {
  display: grid;
  height: 1.2em;
  overflow: hidden;
}

.btn-spin-face span {
  grid-area: 1 / 1;
  transition: transform .35s cubic-bezier(.2, .9, .3, 1.2), opacity .35s;
}

.btn-spin-face span + span { transform: translateY(120%); opacity: 0%; }
.slots.busy .btn-spin-face span:first-child { transform: translateY(-120%); opacity: 0%; }
.slots.busy .btn-spin-face span + span { transform: none; opacity: 100%; }

.slots.busy .btn--spin {
  pointer-events: none;
  animation: pulse 1s ease-in-out infinite;
}

@keyframes pulse {
  50% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent-dim) 25%, transparent); }
}

/* Рычаг. Кнопка без табуляции: с клавиатуры крутит «Крутить», а рычаг —
   для тех, кто пришёл мышью. Тянется анимацией переменной --lever-pull:
   0 — вверху, 1 — дёрнут до упора. */
.lever {
  --lever-pull: 0;

  all: unset;
  position: relative;
  height: var(--reel-h);
  width: 44px;
  margin-top: calc(var(--s4) + 1.8em + var(--s3) + 1.2em);
  cursor: grab;
  display: block;
  justify-self: center;
}

.lever:active { cursor: grabbing; }

/* На узком экране барабаны занимают всю ширину, и рычагу не за что
   держаться. Правило ниже основного, иначе его перебивает display выше. */
@media (width < 640px) { .lever { display: none; } }

.lever-base {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 34px;
  border-radius: var(--r) var(--r) 0 0;
  background: linear-gradient(180deg, var(--surface-3), var(--surface));
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--fg) 10%, transparent), 0 10px 20px -12px #000;
  border: 1px solid var(--line-2);
}

.lever-base::after {
  content: "";
  position: absolute;
  left: 50%;
  top: -6px;
  width: 14px;
  height: 14px;
  margin-left: -7px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, var(--line-2), var(--page));
}

.lever-arm {
  position: absolute;
  left: 50%;
  bottom: 30px;
  width: 6px;
  height: calc(var(--reel-h) - 44px);
  margin-left: -3px;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--line-2), var(--surface-3), var(--line));
  transform-origin: 50% 100%;
  transform: rotateX(calc(var(--lever-pull) * 150deg));
  transition: transform .25s cubic-bezier(.2, .9, .3, 1.4);
}

.lever-knob {
  position: absolute;
  left: 50%;
  top: -12px;
  width: 24px;
  height: 24px;
  margin-left: -12px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, var(--accent-hi), var(--accent-dim) 55%, var(--accent-fill-lo));
  box-shadow: 0 0 calc(6px + 14px * var(--glow)) color-mix(in srgb, var(--accent-dim) 70%, transparent), 0 4px 10px -4px #000;
}

.lever:hover .lever-arm { --lever-pull: 0.12; }
.lever.pulled .lever-arm { animation: pull .7s cubic-bezier(.3, .8, .3, 1.3); }

@keyframes pull {
  0% { --lever-pull: 0; }
  35% { --lever-pull: 1; }
  100% { --lever-pull: 0; }
}

/* ---------- Форма заявки ---------- */

/* Рядом с автоматом — билет. Рамка обегает карточку акцентом, пока
   в ней печатают, штамп «Отправлено» ставится по факту доставки. */
.wish {
  --ring: 0deg;

  position: relative;
  display: grid;
  gap: var(--s3);
  width: 100%;
  padding: var(--s4);
  border-radius: var(--r-lg);
  background: var(--surface);
  overflow: hidden;
  transition: box-shadow .4s;
}

.wish::before {
  content: "";
  position: absolute;
  inset: 0;
  padding: 1px;
  border-radius: inherit;
  background:
    conic-gradient(from var(--ring), var(--line-2) 0%, var(--line-2) 70%, var(--accent-hi) 85%, var(--line-2) 100%);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
  opacity: 60%;
  transition: opacity .3s;
}

.wish:focus-within::before { opacity: 100%; animation: ring 3s linear infinite; }
.wish:focus-within { box-shadow: 0 30px 60px -40px color-mix(in srgb, var(--accent-dim) 60%, transparent); }

@keyframes ring { to { --ring: 360deg; } }

.wish-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding-bottom: var(--s3);
  border-bottom: 1px dashed var(--line-2);
  font: 500 0.6875rem/1 var(--mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-3);
}

.wish-ticket { color: var(--accent); }
.wish-no { color: var(--fg-2); transition: color .3s; }
.wish-no.lit { color: var(--fg); animation: flip .5s cubic-bezier(.2, .9, .3, 1.3); }

.wish .field { display: grid; gap: 6px; }

.wish label {
  font-size: 0.8125rem;
  color: var(--fg-2);
  transition: color .2s;
}

.wish .field:focus-within label { color: var(--accent-hi); }

.wish textarea,
.wish input {
  width: 100%;
  padding: 9px 10px;
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  background: var(--page);
  color: var(--fg);
  font: 400 0.9375rem/1.5 var(--sans);
  resize: vertical;
  transition: border-color .2s, box-shadow .25s, background-color .2s;
}

.wish textarea::placeholder,
.wish input::placeholder { color: var(--fg-3); }
.wish textarea:hover, .wish input:hover { border-color: var(--fg-3); }

.wish textarea:focus-visible,
.wish input:focus-visible {
  outline: none;
  border-color: var(--accent-dim);
  box-shadow: 0 0 0 3px var(--accent-wash), 0 0 18px -4px color-mix(in srgb, var(--accent-dim) 60%, transparent);
  background: color-mix(in srgb, var(--page) 85%, var(--surface));
}

/* Автомат печатает свою комбинацию в поле сам — рядом с подписью
   мигает курсор, пока идёт набор. */
.wish.typing .field:first-of-type label::after {
  content: " ▍";
  color: var(--accent);
  animation: caret .6s steps(1) infinite;
}

@keyframes caret { 50% { opacity: 0%; } }

.wish-note { font-size: 0.8125rem; color: var(--fg-2); }

.btn--send { position: relative; overflow: hidden; }

.btn--send::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg, transparent 30%, color-mix(in srgb, #fff 35%, transparent) 50%, transparent 70%);
  transform: translateX(-120%);
}

.btn--send:hover::after { animation: sweep .7s ease-out; }

.wish.sending .btn--send > span { visibility: hidden; }

.wish.sending .btn--send::before {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--on-accent) 40%, transparent);
  border-top-color: var(--on-accent);
  animation: spin .7s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

.wish-stamp {
  position: absolute;
  left: 50%;
  top: 42%;
  padding: 6px 14px;
  border: 3px solid var(--ok);
  border-radius: var(--r);
  color: var(--ok);
  font: 700 1.25rem/1 var(--mono);
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--ok) 70%, transparent));
  letter-spacing: 0.18em;
  text-transform: uppercase;
  transform: translate(-50%, -50%) rotate(-12deg) scale(3);
  opacity: 0%;
  pointer-events: none;
  mix-blend-mode: screen;
}

@media (prefers-color-scheme: light) { .wish-stamp { mix-blend-mode: multiply; } }

.wish.sent .wish-stamp { animation: stamp .5s cubic-bezier(.2, .9, .3, 1.2) forwards; }

@keyframes stamp {
  0% { transform: translate(-50%, -50%) rotate(-12deg) scale(3); opacity: 0%; }
  60% { transform: translate(-50%, -50%) rotate(-12deg) scale(.92); opacity: 100%; }
  100% { transform: translate(-50%, -50%) rotate(-12deg) scale(1); opacity: 100%; }
}

.wish.sent .field { animation: dim .4s ease-out forwards; }

@keyframes dim { to { opacity: 55%; } }

/* Свечение и вспышки — только тем, кто не просил покоя. */
@media (prefers-reduced-motion: reduce) {
  .slots .machine { --glow: 0 !important; }
  .machine-lights { animation: none; opacity: 35%; }
  .slots.busy .reel-track { filter: none; }
  .sparks { display: none; }
  .machine-glass { display: none; }
  .wish::before { animation: none; }
}

/* ---------- Подвал ---------- */

.site-footer {
  border-top: 1px solid var(--line);
  padding-block: var(--s6);
  position: relative;
  z-index: 1;
  background: var(--page);
}

.site-footer .wrap {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, 1fr));
  gap: var(--s5);
}

@media (width < 760px) {
  .site-footer .wrap { grid-template-columns: 1fr; gap: var(--s4); }
}

.site-footer h4 {
  font: 500 0.6875rem/1 var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-3);
  margin-bottom: var(--s3);
}

.site-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); }
.site-footer a { color: var(--fg-2); text-decoration: none; font-size: 0.9375rem; }
.site-footer a:hover { color: var(--accent); }
.site-footer p { font-size: 0.875rem; color: var(--fg-3); }

/* ---------- Правовые страницы ---------- */

.doc { padding-block: var(--s6) var(--s7); }
.doc .wrap { max-width: 72ch; }
.doc h1 { margin-bottom: var(--s3); }
.doc h2 { font-size: 1.25rem; margin-top: var(--s5); margin-bottom: var(--s3); }
.doc p, .doc li { color: var(--fg-2); }
.doc p + p { margin-top: var(--s3); }
.doc ul, .doc ol { padding-left: 1.2em; margin: var(--s3) 0; display: grid; gap: var(--s2); }
.doc dl { margin: var(--s3) 0; display: grid; gap: var(--s3); }
.doc dt { font-weight: 600; color: var(--fg); }
.doc dd { margin: 4px 0 0; color: var(--fg-2); }

.doc-meta {
  font: 400 0.8125rem/1.6 var(--mono);
  color: var(--fg-3);
  padding-bottom: var(--s4);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--s5);
}

/* ---------- Мелочи ---------- */

.skip {
  position: absolute;
  left: -9999px;
}

.skip:focus {
  left: var(--s3);
  top: var(--s2);
  z-index: 100;
  background: var(--surface-2);
  padding: var(--s2) var(--s3);
  border: 1px solid var(--line-2);
  border-radius: var(--r);
}

