/*
 * shared-ui/tokens.css — дизайн-токены Chrysolite, тема «Янтарный терминал»
 * (спека docs/superpowers/specs/2026-07-02-portal-redesign-amber-terminal-design.md).
 *
 * Идея: приборная честность. Сервис, где вся суть — точные цифры (мс, ₽, fps),
 * поэтому главный голос бренда — моноширинный шрифт (дисплей, деньги, лейблы,
 * кнопки), тёплый янтарь ЭЛТ — единственный акцент. Гуманистический sans —
 * второй, «человеческий» слой для связного текста. Сигнатурные приёмы
 * ([лейблы-регистры], мигающий курсор, скан-линии, телеметрия) — дозированно,
 * не более 1–2 на экран.
 */

/* --- шрифты: self-hosted (fonts/fetch-fonts.sh), без CDN --- */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('./fonts/jetbrains-mono-400-cyr.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('./fonts/jetbrains-mono-400-lat.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2212, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('./fonts/jetbrains-mono-700-cyr.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('./fonts/jetbrains-mono-700-lat.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2212, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('./fonts/ibm-plex-sans-400-cyr.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('./fonts/ibm-plex-sans-400-lat.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2212, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('./fonts/ibm-plex-sans-600-cyr.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('./fonts/ibm-plex-sans-600-lat.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2212, U+FEFF, U+FFFD;
}

/* --- микро-сабсет ₽/→ (U+20BD, U+2192) — этих глифов нет в cyr/lat-сабсетах
   Google; без этого блока знак рубля рендерится фолбэком (M-1 финал-ревью). --- */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('./fonts/jetbrains-mono-400-sym.woff2') format('woff2');
  unicode-range: U+20BD, U+2192;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('./fonts/jetbrains-mono-700-sym.woff2') format('woff2');
  unicode-range: U+20BD, U+2192;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('./fonts/ibm-plex-sans-400-sym.woff2') format('woff2');
  unicode-range: U+20BD, U+2192;
}

:root {
  /* --- цвет: поверхности (тёплый почти-чёрный, без чистого чёрного) --- */
  --bg: #17130c;
  --surface: #211a10;
  --surface-2: #2a2114;
  --border: #453718;
  --border-strong: #5c4a20;

  /* --- цвет: текст (тёплая бумага) --- */
  --text: #efe6d2;
  --muted: #9a8c6e;
  --muted-2: #6b6046;

  /* --- цвет: акцент (янтарь ЭЛТ; единственный брендовый огонь) --- */
  --accent: #ffb000;
  --accent-hover: #ffd24d;
  --accent-press: #e09a00;
  --accent-soft: rgba(255, 176, 0, 0.12);
  --on-accent: #1a1406;

  /* --- цвет: скан-линии (тот же янтарь, что и акцент, — но своим токеном:
     альтернативные темы перекрашивают текстуру вместе с акцентом) --- */
  --scanline: rgba(255, 176, 0, 0.03);

  /* --- цвет: семантика (отдельно от акцента) --- */
  --success: #86c232;
  --success-soft: rgba(134, 194, 50, 0.16);
  --danger: #ff5340;
  --danger-soft: rgba(255, 83, 64, 0.16);
  --warning: #ff8a3d;
  --warning-soft: rgba(255, 138, 61, 0.16);
  --neutral: #9a8c6e;
  --neutral-soft: rgba(154, 140, 110, 0.16);

  /* --- текст ПОВЕРХ soft-подложек: обычные danger/neutral на *-soft дают
     4.2–4.4:1 при мелком кегле — ниже AA; эти оттенки светлее ровно настолько,
     чтобы пилюли читались (финал-ревью этапа 2) --- */
  --danger-on-soft: #ff8577;
  --neutral-on-soft: #b8ab8a;

  /* --- типографика: mono — голос бренда, sans — связный текст --- */
  --font: 'IBM Plex Sans', ui-sans-serif, system-ui, 'Segoe UI', Roboto, Arial, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'Cascadia Code', 'Roboto Mono', Consolas, monospace;

  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.25rem;
  --text-xl: 1.75rem;
  --text-2xl: 2.25rem;
  --text-3xl: 3rem; /* хиро лендинга */

  --leading-tight: 1.15;
  --leading-normal: 1.55;

  /* --- пространство (кратно 4px) --- */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-8: 3rem;
  --gap: var(--space-4);

  /* --- минимумы колонок auto-fit (2026-09-17): раньше каждая сетка несла свой
     магический пиксель (190/240/260/300), и «Качество» с минимумом 190px давало
     пять узких колонок на ЛЮБОЙ ширине — заголовки карточек рвались посреди слова.
     Две ступени на все текстовые сетки лендинга: sm — карточка-абзац, md — колонка
     с иллюстрацией. tile — обложка каталога (портрет 3/4, своя мерка). --- */
  --grid-min-sm: 240px;
  --grid-min-md: 300px;
  --grid-min-tile: 200px;

  /* --- форма: жёстче прежней (терминал, не «пилюли») --- */
  --radius-sm: 3px;
  --radius: 4px;
  --radius-lg: 8px;
  --radius-full: 999px;

  /* --- движение --- */
  --ease: cubic-bezier(0.4, 0, 0.2, 1); /* @kind other */
  --dur-fast: 100ms; /* @kind other */
  --dur-base: 180ms; /* @kind other */

  /* --- фокус/доступность --- */
  --focus-ring: 0 0 0 3px var(--accent-soft), 0 0 0 1px var(--accent);
}

/*
 * --- альтернативные темы (кандидаты на выбор владельца; дефолт — янтарь) ---
 * Каждая тема — ТОЛЬКО переопределение цветовых токенов на data-theme:
 * без атрибута ничего не меняется, типографика/пространство/движение общие.
 * Семантика (success/danger/warning) тоже общая — контраст на новых фонах
 * проверен расчётом (≥ 4.5:1); нейтраль перекрашивается под температуру темы,
 * потому что дефолтная (#9a8c6e) — тёплая и на холодных фонах грязнится.
 */

/* --- тема «Изумрудный фосфор»: зелёный ЭЛТ на холодном графите.
   Идея: монитор ранних терминалов — люминофор P1; графит чуть зеленится,
   как стекло выключенной трубки. Акцент ярче фона на 10.6:1, текст 14.9:1. --- */
[data-theme='phosphor'] {
  --bg: #0c1210;
  --surface: #131b17;
  --surface-2: #1a2420;
  --border: #26362d;
  --border-strong: #38503f;

  --text: #d8e8dc;
  --muted: #7fa08a;
  --muted-2: #4f6a5b;

  --accent: #3ddc84;
  --accent-hover: #6ef2a8;
  --accent-press: #2bbd6d;
  --accent-soft: rgba(61, 220, 132, 0.12);
  --on-accent: #08130c;

  --scanline: rgba(61, 220, 132, 0.04);

  --neutral: #7fa08a;
  --neutral-soft: rgba(127, 160, 138, 0.16);
  --neutral-on-soft: #9fbfab;
}

/* --- тема «Ледяной сигнал»: глубокий сине-чёрный, циановый акцент.
   Идея: индикатор связи в ночи — холодный сигнал на почти-чёрном небе;
   синий у поверхностей глубокий, не «корпоративный». Акцент 10.0:1, текст 15.3:1. --- */
[data-theme='ice'] {
  --bg: #0a0e16;
  --surface: #101624;
  --surface-2: #161f31;
  --border: #243149;
  --border-strong: #364763;

  --text: #dce6f2;
  --muted: #7c8ba3;
  --muted-2: #526078;

  --accent: #4cc9f0;
  --accent-hover: #7fdcf7;
  --accent-press: #2fb3dc;
  --accent-soft: rgba(76, 201, 240, 0.12);
  --on-accent: #081019;

  --scanline: rgba(76, 201, 240, 0.04);

  --neutral: #7c8ba3;
  --neutral-soft: rgba(124, 139, 163, 0.16);
  --neutral-on-soft: #a5b4cc;
}

html,
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  margin: 0;
}

* {
  box-sizing: border-box;
}

/* --- политика переносов в заголовках (2026-09-17) ---
 * Заголовок НИКОГДА не рвётся посреди слова по собственной воле: break-word
 * разрешает разрыв только слову, которое не помещается в строку целиком, и, в
 * отличие от `anywhere`, не участвует в расчёте min-content — сетка не «схлопывает»
 * колонку под самый узкий слог. `hyphens: manual` оставляет решение за текстом
 * (мягкий перенос U+00AD), автоматическую расстановку браузером не включаем:
 * русские правила у движков разные, и заголовок бренда — не место для лотереи.
 * `overflow-wrap: anywhere` допустим только там, где в тексте живёт настоящий
 * URL (см. friends/page.tsx).
 */
h1,
h2,
h3,
h4 {
  overflow-wrap: break-word;
  hyphens: manual;
}

a {
  color: var(--accent);
}

:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}

/* --- кнопки: mono-голос, жёсткий радиус --- */
.cg-btn {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-weight: 700;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  padding: var(--space-3) var(--space-5);
  cursor: pointer;
  transition:
    background-color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease);
}
.cg-btn:active:not(:disabled) {
  transform: scale(0.98);
}
.cg-btn:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}
.cg-btn--primary {
  background: var(--accent);
  color: var(--on-accent);
}
.cg-btn--primary:hover:not(:disabled) {
  background: var(--accent-hover);
}
.cg-btn--primary:active:not(:disabled) {
  background: var(--accent-press);
}
.cg-btn--ghost,
.cg-btn--secondary {
  background: transparent;
  border-color: var(--border-strong);
  color: var(--text);
}
.cg-btn--ghost:hover:not(:disabled),
.cg-btn--secondary:hover:not(:disabled) {
  background: var(--surface-2);
  border-color: var(--accent);
}
.cg-btn--danger {
  background: transparent;
  border-color: var(--danger);
  color: var(--danger);
}
.cg-btn--danger:hover:not(:disabled) {
  background: var(--danger-soft);
}

/* --- пульс статуса «онлайн» (имя и контракт прежние — StatusDot) --- */
@keyframes cg-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 var(--dot-color, var(--success));
    opacity: 1;
  }
  50% {
    box-shadow: 0 0 0 4px transparent;
    opacity: 0.7;
  }
}
.cg-pulse-dot {
  animation: cg-pulse 2s var(--ease) infinite;
}

/* --- сигнатура: лейбл-«регистр» в квадратных скобках --- */
.cg-label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  white-space: nowrap;
}
.cg-label::before {
  content: '[';
  color: var(--muted-2);
}
.cg-label::after {
  content: ']';
  color: var(--muted-2);
}

/* --- сигнатура: мигающий курсор в хиро --- */
@keyframes cg-blink {
  50% {
    opacity: 0;
  }
}
.cg-blink {
  display: inline-block;
  width: 0.55em;
  height: 1em;
  background: var(--accent);
  vertical-align: text-bottom;
  animation: cg-blink 1.1s steps(1) infinite;
}

/* --- сигнатура: скан-линии (текстура; накладывать max на 1–2 поверхности) --- */
.cg-scanlines {
  background-image: repeating-linear-gradient(
    0deg,
    var(--scanline) 0 1px,
    transparent 1px 3px
  );
}

/*
 * --- хиро лендинга: стена обложек + вуаль + скан-линии с мерцанием ---
 * Слои по z: 0 — стена (HeroWall), 1 — вуаль и скан-оверлей, 2 — контент.
 * Всё движение — transform/opacity; вуаль на color-mix от --bg, чтобы
 * альтернативные темы гасили стену своим фоном без правки вёрстки.
 */
.cg-hero {
  position: relative;
  overflow: hidden;
  padding: var(--space-8) var(--space-6);
  min-height: 520px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.cg-hero__content {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-5);
}
/* скан-линии хиро — оверлеем ПОВЕРХ стены, с лёгким «дыханием» яркости */
.cg-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background-image: repeating-linear-gradient(0deg, var(--scanline) 0 1px, transparent 1px 3px);
  animation: cg-scan-flicker 7s linear infinite;
}
@keyframes cg-scan-flicker {
  0%,
  44%,
  58%,
  100% {
    opacity: 1;
  }
  47% {
    opacity: 0.55;
  }
  50% {
    opacity: 0.9;
  }
  53% {
    opacity: 0.6;
  }
  82% {
    opacity: 0.75;
  }
}
/* вуаль: центр темнее под текстом, края уходят в чистый --bg */
.cg-hero__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(
      ellipse 58% 62% at 50% 46%,
      color-mix(in srgb, var(--bg) 82%, transparent),
      color-mix(in srgb, var(--bg) 55%, transparent) 68%,
      transparent
    ),
    linear-gradient(
      180deg,
      var(--bg),
      color-mix(in srgb, var(--bg) 30%, transparent) 26%,
      color-mix(in srgb, var(--bg) 30%, transparent) 72%,
      var(--bg)
    ),
    linear-gradient(
      90deg,
      color-mix(in srgb, var(--bg) 85%, transparent),
      transparent 22%,
      transparent 78%,
      color-mix(in srgb, var(--bg) 85%, transparent)
    );
}

/* --- хиро-стена: 3 ряда-маркизы обложек под наклоном (HeroWall) --- */
.cg-wall {
  position: absolute;
  inset: -24% -10%;
  z-index: 0;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-5);
  transform: rotate(-7deg);
}
.cg-wall__row {
  display: flex;
}
/* дорожка задублирована в разметке — цикл -50% бесшовный (как у телеметрии) */
.cg-wall__track {
  display: flex;
  flex: none;
  gap: var(--space-5);
  padding-right: var(--space-5);
  animation: cg-wall-scroll var(--wall-dur, 64s) linear infinite;
  will-change: transform;
}
.cg-wall__row--reverse .cg-wall__track {
  animation-direction: reverse;
}
@keyframes cg-wall-scroll {
  to {
    transform: translateX(-50%);
  }
}
.cg-wall__tile {
  flex: none;
  width: clamp(104px, 11vw, 148px);
  aspect-ratio: 3 / 4;
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-lg);
  border: 1px solid rgba(255, 255, 255, 0.07);
  animation: cg-wall-float 8s ease-in-out infinite alternate;
}
/* «дыхание» плитки: только transform, длительность/фаза — инлайном из HeroWall */
@keyframes cg-wall-float {
  from {
    transform: translateY(-5px);
  }
  to {
    transform: translateY(5px);
  }
}
/* настоящая обложка плитки: абсолютом поверх градиента (тот остаётся фоном
   загрузки/прозрачности и целиком — фолбэком при ошибке). Приглушение и лёгкая
   десатурация — локальная «вуаль» плитки: пёстрые постеры не спорят с текстом
   хиро; фильтр статичен (не анимируется) — движение остаётся transform-only */
.cg-wall__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.78) brightness(0.86) contrast(0.95);
}
.cg-wall__letter {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 2.6rem;
  opacity: 0.5;
  user-select: none;
}
.cg-wall__title {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.3;
  color: rgba(255, 244, 222, 0.85);
  background: linear-gradient(0deg, rgba(0, 0, 0, 0.55), transparent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* reduced-motion: маркиза и «дыхание» гаснут — остаётся статичная сетка */
@media (prefers-reduced-motion: reduce) {
  .cg-wall__track,
  .cg-wall__tile {
    animation: none;
  }
}

/* --- каталог-тизер: лента игровых плиток в одну строку (GameStrip) ---
   Контентная маркиза, в отличие от декоративной cg-wall: ровная (без наклона),
   плитки крупнее, лента интерактивна — ховер ставит дорожку на паузу, плитка
   поднимается и зовёт «Играть». Фулл-блид из контейнера 1080px: margin 50% +
   translateX(-50%) центрируют полосу шириной 100vw по вьюпорту; возможный
   хвост в ширину скроллбара гасит overflow-x у корня лендинга (page.tsx). */
.cg-strip {
  position: relative;
  width: 100vw;
  margin-left: 50%;
  transform: translateX(-50%);
  overflow: hidden;
  /* края растворяются, а не обрезаются: лента «выныривает» из фона */
  mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
}
/* дорожка задублирована в разметке — цикл -50% бесшовный (гэп = padding-right,
   как у cg-wall); вертикальный padding — воздух под ховер-подъём плитки,
   иначе overflow: hidden срезал бы lift и тень */
.cg-strip__track {
  display: flex;
  width: max-content;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  padding-right: var(--space-4);
  animation: cg-strip-scroll var(--strip-dur, 80s) linear infinite;
  will-change: transform;
}
@keyframes cg-strip-scroll {
  to {
    transform: translateX(-50%);
  }
}
/* интерактив ленты: курсор над лентой — маркиза замирает,
   плитки можно разглядеть и накликать */
.cg-strip:hover .cg-strip__track {
  animation-play-state: paused;
}
/* клавиатурный фокус: НЕ paused, а полный сброс анимации. Пауза замораживала
   бы трек в текущей фазе цикла — фокусируемые плитки (первые вхождения игр)
   через ~5–20 с уже за левой кромкой, и фокус-кольцо оказывалось вне видимой
   области (overflow clip; transform не создаёт scrollable overflow — доскроллить
   к нему нельзя). animation: none мгновенно возвращает трек в исходное
   положение, где фокусируемые плитки видны. Визуальный скачок — только при
   Tab-навигации внутрь ленты: приемлемый трейд-офф ради видимого фокуса.
   Именно :has(:focus-visible), НЕ :focus-within: Chromium фокусирует <a> уже
   на mousedown, и focus-within снапал бы трек под зажатой кнопкой — mouseup
   ловил соседнюю плитку, click уходил в предка, навигация терялась. Мышиный
   фокус :focus-visible не матчит, клавиатурный — матчит (:has — baseline 2023). */
.cg-strip:has(:focus-visible) .cg-strip__track {
  animation: none;
}
/* плитка — портрет 2:3, 264–321px высоты: контентная секция, крупнее фоновой
   стены; ссылка целиком (accessible name — «Играть в <название>») */
.cg-strip__tile {
  flex: none;
  display: block;
  position: relative;
  width: clamp(176px, 17vw, 214px);
  aspect-ratio: 2 / 3;
  overflow: hidden;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border-strong);
  text-decoration: none;
  color: inherit;
  transition:
    transform var(--dur-base) var(--ease),
    box-shadow var(--dur-base) var(--ease);
}
.cg-strip__tile:hover,
.cg-strip__tile:focus-visible {
  transform: translateY(-6px);
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.45);
}
/* фокус-кольцо живёт в box-shadow (глобальный :focus-visible гасит outline),
   и lift-тень выше его перекрывала бы — на фокусе компонуем кольцо с тенью */
.cg-strip__tile:focus-visible {
  box-shadow:
    var(--focus-ring),
    0 12px 28px rgba(0, 0, 0, 0.45);
}
.cg-strip__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* литера генеративного фолбэка — по центру, полупрозрачно (как у стены) */
.cg-strip__letter {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 3.2rem;
  opacity: 0.55;
  user-select: none;
}
/* подпись: на градиент-фолбэке — всегда, поверх постера — выезжает по ховеру
   (постер говорит сам, но имя по запросу); движение — transform/opacity */
.cg-strip__name {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: var(--space-4) var(--space-4) var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1.35;
  color: rgba(255, 246, 228, 0.94);
  background: linear-gradient(0deg, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0.38) 60%, transparent);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.cg-strip__tile--cover .cg-strip__name {
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity var(--dur-base) var(--ease),
    transform var(--dur-base) var(--ease);
}
.cg-strip__tile--cover:hover .cg-strip__name,
.cg-strip__tile--cover:focus-visible .cg-strip__name {
  opacity: 1;
  transform: none;
}
/* аффорданс «Подробнее» — как у GameCard v5: подсказка сверху справа на ховер/фокус */
.cg-strip__more {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px 8px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  color: var(--text-muted);
  background: rgba(23, 19, 12, 0.85);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  pointer-events: none;
  opacity: 0;
  transform: translateY(-2px);
  transition:
    opacity var(--dur-base) var(--ease),
    transform var(--dur-base) var(--ease);
}
.cg-strip__tile:hover .cg-strip__more,
.cg-strip__tile:focus-visible .cg-strip__more {
  opacity: 1;
  transform: translateY(0);
  color: var(--accent);
  border-color: var(--border-strong);
}
@media (hover: none) {
  .cg-strip__more {
    display: none;
  }
}
/* обратная совместимость: оверлей «Играть» больше не используется */
.cg-strip__cta {
  display: none;
}
/* reduced-motion: лента — не фон, контент обязан остаться доступным. Маркиза
   гаснет, повторы/дубль-трек прячутся (иначе скролл — сплошные дубли), лента
   превращается в обычный горизонтальный скролл без масок по краям */
@media (prefers-reduced-motion: reduce) {
  .cg-strip {
    overflow-x: auto;
    mask-image: none;
  }
  .cg-strip__track {
    animation: none;
    /* первая плитка — в створ заголовка секции (контейнер 1080px), а не к
       кромке вьюпорта: без моушна лента читается как обычный ряд контента */
    padding-inline: max(var(--space-6), calc((100vw - 1080px) / 2 + var(--space-6)));
  }
  .cg-strip__tile[aria-hidden='true'] {
    display: none;
  }
}

/* --- сигнатура: CRT-«вспышка» заголовка хиро при загрузке (однократно) --- */
@keyframes cg-crt-in {
  0% {
    opacity: 0;
    transform: scaleY(0.92);
  }
  30% {
    opacity: 1;
    transform: scaleY(1);
  }
  45% {
    opacity: 0.45;
  }
  60% {
    opacity: 1;
  }
  75% {
    opacity: 0.8;
  }
  100% {
    opacity: 1;
  }
}
.cg-crt-in {
  animation: cg-crt-in 340ms var(--ease) 1 both;
}

/* --- шапка лендинга: блок якорей (LandingHeader) --- */
/* Раскладка — классом, не инлайном: медиа-скрытие ниже должно побеждать. */
.cg-landing-nav {
  display: flex;
  gap: var(--space-4);
  flex: 1;
}
.cg-landing-nav a {
  font-size: var(--text-sm);
}
/* Мобильная шапка (2026-08-20, жалоба владельца «ебут кнопки шапки»): якоря в ОДНОЙ
   строке с логотипом и CTA физически не помещались — «Как это работает» обрезалось на
   полуслове, а ссылки уезжали за правый край (замер на 390px: right=398 и 435 при vw=390).
   Решение — ДВЕ строки: логотип + CTA сверху (главное действие всегда целиком видно),
   якоря — отдельной строкой во всю ширину с горизонтальным скроллом. Бургер по-прежнему
   не заводим: две строки честнее прячущего меню и не требуют состояния. */
@media (max-width: 640px) {
  .cg-landing-nav {
    /* order 3 + width 100% — перенос на вторую строку (шапка flex-wrap). */
    order: 3;
    width: 100%;
    flex: 0 0 100%;
    gap: var(--space-4);
    overflow-x: auto;
    scrollbar-width: none;
    /* Край второй строки затухает, если якоря не влезли — видно, что есть скролл. */
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 24px), transparent 100%);
    mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 24px), transparent 100%);
    /* Хвост дорожки обязан ВЫХОДИТЬ из зоны затухания при прокрутке до конца — иначе
       последний якорь (и его фокус-кольцо) навсегда полупрозрачны (финдинг ревью). */
    padding-inline-end: 24px;
    scroll-padding-inline-end: 24px;
  }
  .cg-landing-nav::-webkit-scrollbar {
    display: none;
  }
  .cg-landing-nav a {
    white-space: nowrap;
    font-size: var(--text-sm);
    /* Вертикальные поля увеличивают зону тапа до ~30px — на второй строке шапки
       якоря стоят свободно, промахнуться мимо соседнего сложно. */
    padding: var(--space-1) 0;
  }
}

/* --- шапка ЛК (AppShell): та же болезнь, что у лендинга ------------------------------
   Логотип, 4 пункта навигации и правый блок (остаток времени + профиль) в один
   flex-wrap рвались на три ряда вразнобой: пункты прыгали по строкам, чип с профилем
   уезжал в третий ряд. На мобиле раскладываем явно: строка 1 — логотип и правый блок,
   строка 2 — навигация горизонтальным скроллом. */
.cg-app-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-5);
  padding: calc(var(--space-4) + env(safe-area-inset-top, 0px)) calc(var(--space-6) + env(safe-area-inset-right, 0px)) var(--space-4) calc(var(--space-6) + env(safe-area-inset-left, 0px));
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.cg-app-header > a:first-child {
  font-size: var(--text-lg);
}
/* Чип остатка времени (TimeChip): поля и кегль — здесь, чтобы мобильные правила могли
   их ужать (инлайн-стиль победил бы медиа-запрос). */
.cg-chip {
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
}
.cg-app-nav-wrap {
  position: relative;
  display: flex;
  flex: 1;
  min-width: 0;
  align-items: center;
}
.cg-nav-scroll-hint {
  display: none;
}
.cg-app-nav {
  display: flex;
  gap: var(--space-2) var(--space-4);
  flex: 1;
  align-items: center;
  flex-wrap: wrap;
}
@media (max-width: 640px) {
  .cg-app-nav-wrap {
    order: 3;
    width: 100%;
    flex: 0 0 100%;
  }
  .cg-nav-scroll-hint {
    display: block;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 32px;
    background: linear-gradient(90deg, rgba(23, 19, 12, 0) 0%, #17130C 100%);
    pointer-events: none;
    z-index: 2;
  }
  .cg-app-nav {
    order: 3;
    width: 100%;
    flex: 0 0 100%;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    gap: var(--space-4);
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 24px), transparent 100%);
    mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 24px), transparent 100%);
    padding-inline-end: 24px;
    scroll-padding-inline-end: 24px;
  }
  .cg-app-nav::-webkit-scrollbar {
    display: none;
  }
  .cg-app-nav > * {
    white-space: nowrap;
    padding-bottom: 2px;
  }
  /* Правый блок (остаток времени + профиль) остаётся В ОДНОЙ строке с логотипом:
     без этого шапка занимала три ряда — бренд, чип с профилем, навигация. */
  .cg-app-right {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
  }
  /* Узкий горизонтальный gap + компактный вордмарк: логотип и правый блок (остаток
     времени + профиль) обязаны уместиться в ОДНУ строку — иначе шапка снова уезжает
     в три ряда. Кегль вордмарка тут декоративный, читаемость не страдает. */
  .cg-app-header {
    gap: var(--space-3) var(--space-2);
    padding: calc(var(--space-3) + env(safe-area-inset-top, 0px)) calc(var(--space-4) + env(safe-area-inset-right, 0px)) var(--space-3) calc(var(--space-4) + env(safe-area-inset-left, 0px));
  }
  .cg-app-header > a:first-child {
    font-size: var(--text-base);
  }
}
/* Экраны ≤360px (iPhone SE/mini): вордмарк + «остаток времени» + профиль в сумме шире
   строки — на 320px шапка снова разъезжалась на три ряда (финдинг ревью 2026-08-20).
   Ужимаем сам чип и убираем его внутренние поля: смысл («сколько осталось») остаётся. */
@media (max-width: 360px) {
  .cg-app-header > a:first-child {
    font-size: var(--text-sm);
  }
  .cg-app-right .cg-chip {
    font-size: var(--text-xs);
    padding: 2px var(--space-2);
  }
}

/* --- таблица → карточки на мобиле (.cg-table-cards) ----------------------------------
   Журнал сессий — шесть колонок с nowrap: на 390px он жил в горизонтальном скролле,
   и игрок видел ровно первые две колонки. На ≤640px каждая строка становится карточкой
   «подпись — значение» (подпись берётся из data-label ячейки). Семантику таблицы это
   меняет (display:block снимает роли), поэтому переключение — ТОЛЬКО по ширине экрана:
   на десктопе остаётся настоящая таблица. */
@media (max-width: 640px) {
  .cg-table-cards thead {
    display: none;
  }
  .cg-table-cards,
  .cg-table-cards tbody,
  .cg-table-cards tr,
  .cg-table-cards td {
    display: block;
    width: 100%;
  }
  .cg-table-cards tr {
    padding: var(--space-3) var(--space-4);
  }
  .cg-table-cards td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-1) 0 !important;
    text-align: right;
  }
  .cg-table-cards td::before {
    content: attr(data-label);
    flex: none;
    color: var(--muted);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    text-align: left;
  }
  /* Ячейка без подписи (действия) — на всю ширину, без пустой колонки лейбла. */
  .cg-table-cards td:not([data-label])::before {
    content: none;
  }
}

/*
 * --- угловой значок карточки (.cg-art, хендофф 2026-08-18) ---
 * Инлайн-SVG data-URI работает МАСКОЙ поверх заливки var(--accent) (тот же
 * приём, что у gameEtching): значок перекрашивается темами вместе с акцентом.
 * ::before — сам значок в правом верхнем углу, ::after — слабая радиальная
 * засветка угла (z-index -1 под контентом, isolation на карточке). Размер,
 * непрозрачность и силу засветки задают --art-size/--art-opacity/--art-wash.
 * Вариант --plus (карточки «Качество»): значок крупнее и ярче, рамка
 * border-strong, ховер зажигает рамку акцентом и значок до полной яркости.
 */
.cg-art {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  /* Ширина «занятого» углом коридора. Была зашита в правило `> :first-child`
     (2026-09-17): резерв доставался тому, кто оказался первым в разметке —
     в StepCard это лейбл «шаг 01», а не заголовок, а в «Качестве» он резал
     заголовок до 68px и тот рвался посреди слова. Теперь резерв — переменная,
     и его просит ТОТ элемент, который реально доходит до угла. */
  --art-reserve: 64px;
}
/* Место под значок уступают только заголовок карточки и элементы, помеченные
   явно: остальные дети (абзацы, лейблы) идут во всю ширину — значок висит
   в ВЕРХНЕМ углу и нижним строкам не мешает. */
.cg-art > .cg-card-title,
.cg-art > .cg-art-reserve {
  margin-right: var(--art-reserve);
}
.cg-art::before {
  content: '';
  position: absolute;
  z-index: 1;
  pointer-events: none;
  top: var(--art-top, 16px);
  right: var(--art-right, 16px);
  width: var(--art-size, 40px);
  aspect-ratio: 1 / 1;
  background: var(--accent);
  opacity: var(--art-opacity, 0.55);
  -webkit-mask-image: var(--art);
  mask-image: var(--art);
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  transition: opacity var(--dur-base) var(--ease);
}
.cg-art::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    140px 110px at calc(100% - 30px) 34px,
    color-mix(in srgb, var(--accent) var(--art-wash, 6%), transparent),
    transparent
  );
}
.cg-art--plus {
  border-color: var(--border-strong) !important;
  --art-size: 42px;
  --art-opacity: 0.75;
  --art-wash: 10%;
  --art-reserve: 72px;
}
.cg-art--plus:hover {
  border-color: var(--accent) !important;
}
.cg-art--plus:hover::before {
  opacity: 1;
}
.cg-art--mail { --art: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' fill='none' stroke='%23fff' stroke-width='4'%3E%3Crect x='16' y='28' width='68' height='46' rx='3'/%3E%3Cpath d='M16 32 L50 56 L84 32'/%3E%3C/svg%3E"); }
.cg-art--clock { --art: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' fill='none' stroke='%23fff' stroke-width='4'%3E%3Ccircle cx='50' cy='50' r='30'/%3E%3Cpath d='M50 30 L50 50 L66 58'/%3E%3C/svg%3E"); }
.cg-art--play { --art: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='30' fill='none' stroke='%23fff' stroke-width='4'/%3E%3Cpath d='M42 36 L70 50 L42 64 Z' fill='%23fff'/%3E%3C/svg%3E"); }
/* steam — шаг «заведи Steam и добавь игру» на лендинге: библиотека-полка с диском.
   Рисуем СВОЙ знак, а не логотип Steam: чужая марка в нашей палитре — это уже не
   цитата, а присвоение. */
.cg-art--steam { --art: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' fill='none' stroke='%23fff' stroke-width='4'%3E%3Crect x='14' y='20' width='72' height='60' rx='4'/%3E%3Cpath d='M14 66h72'/%3E%3Ccircle cx='38' cy='44' r='11'/%3E%3Cpath d='M49 44h22'/%3E%3C/svg%3E"); }
.cg-art--res { --art: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' fill='none' stroke='%23fff' stroke-width='4'%3E%3Crect x='10' y='22' width='80' height='56' rx='3'/%3E%3Crect x='26' y='34' width='48' height='32'/%3E%3Crect x='40' y='44' width='20' height='12' opacity='.6'/%3E%3C/svg%3E"); }
.cg-art--fps { --art: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cg fill='%23fff'%3E%3Crect x='16' y='58' width='12' height='22'/%3E%3Crect x='34' y='46' width='12' height='34'/%3E%3Crect x='52' y='34' width='12' height='46'/%3E%3Crect x='70' y='22' width='12' height='58'/%3E%3C/g%3E%3C/svg%3E"); }
.cg-art--wide { --art: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' fill='none' stroke='%23fff' stroke-width='4'%3E%3Crect x='6' y='36' width='88' height='30' rx='3'/%3E%3Cpath d='M22 51 L34 42 M22 51 L34 60 M78 51 L66 42 M78 51 L66 60'/%3E%3C/svg%3E"); }
.cg-art--codec { --art: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cg fill='%23fff'%3E%3Crect x='18' y='18' width='20' height='20'/%3E%3Crect x='42' y='18' width='20' height='20' opacity='.45'/%3E%3Crect x='66' y='18' width='16' height='20' opacity='.7'/%3E%3Crect x='18' y='42' width='20' height='20' opacity='.55'/%3E%3Crect x='42' y='42' width='20' height='20'/%3E%3Crect x='66' y='42' width='16' height='20' opacity='.35'/%3E%3Crect x='18' y='66' width='20' height='16' opacity='.7'/%3E%3Crect x='42' y='66' width='20' height='16' opacity='.4'/%3E%3Crect x='66' y='66' width='16' height='16'/%3E%3C/g%3E%3C/svg%3E"); }
.cg-art--station { --art: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect x='18' y='16' width='64' height='68' rx='4' fill='none' stroke='%23fff' stroke-width='4'/%3E%3Cg fill='%23fff'%3E%3Crect x='28' y='28' width='44' height='6'/%3E%3Crect x='28' y='44' width='44' height='6' opacity='.6'/%3E%3Crect x='28' y='60' width='30' height='6' opacity='.4'/%3E%3Ccircle cx='68' cy='63' r='4'/%3E%3C/g%3E%3C/svg%3E"); }

/*
 * --- заголовок карточки (.cg-card-title, 2026-09-17) ---
 * Один голос для всех карточек-терминов: моно 700, плотный интерлиньяж.
 * Кегль растёт от ширины экрана, но потолок — --text-lg: прежние 4.5vw давали
 * на планшете скачок кегля выше соседних заголовков секции. Слова НЕ рвём
 * (overflow-wrap: normal перебивает страховку h1..h4 выше — здесь за ширину
 * отвечает сетка, а не перенос), переносим только по пробелу, а `balance`
 * делит две строки поровну, а не «длинная + хвост».
 * Страховка от переполнения — min-width: 0 на самой карточке (.cg-quality-grid > *).
 */
.cg-card-title {
  margin: 0;
  font-family: var(--font-mono);
  font-size: clamp(var(--text-base), 2.2vw, var(--text-lg));
  font-weight: 700;
  line-height: var(--leading-tight);
  text-wrap: balance;
  overflow-wrap: normal;
  word-break: normal;
  hyphens: manual;
}

/*
 * --- сетка секции «Качество» (.cg-quality-grid, 2026-09-17) ---
 * Пять карточек-терминов. auto-fit с минимумом 190px держал пять колонок по
 * 190px на ЛЮБОЙ десктопной ширине (main упёрт в 1080px), под заголовок
 * оставалось ~68px — пять моно-знаков, и «Ультравайд» ломался на «Ультр/авайд».
 * Раскладка теперь заданная, а не вычисленная:
 *   ≥ 960px — шесть колонок: три карточки по span 2 (ряд 1) и две по span 3
 *             (ряд 2). Ряды полные, дыр и сирот нет, а длинные термины
 *             («Современные кодеки», «Проверенные станции») попадают именно
 *             в широкие плитки и встают в одну строку.
 *   641–959 — две колонки, пятая во всю ширину.
 *   ≤ 640   — одна колонка.
 */
.cg-quality-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--space-4);
}
.cg-quality-grid > * {
  min-width: 0;
}
.cg-quality-grid > :nth-child(-n + 3) {
  grid-column: span 2;
}
.cg-quality-grid > :nth-child(n + 4) {
  grid-column: span 3;
}
@media (max-width: 959px) {
  .cg-quality-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .cg-quality-grid > :nth-child(-n + 3),
  .cg-quality-grid > :nth-child(n + 4) {
    grid-column: auto;
  }
  /* Пятая — во всю ширину: иначе она сирота в половину ряда. */
  .cg-quality-grid > :nth-child(5) {
    grid-column: span 2;
  }
}
@media (max-width: 640px) {
  .cg-quality-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .cg-quality-grid > :nth-child(5) {
    grid-column: auto;
  }
}

/* --- тумблер автопродления (.cg-switch, хендофф 2026-08-18): нативный чекбокс
   поверх нарисованного трека — role=switch остаётся у input, фокус-кольцо на треке. --- */
.cg-switch {
  position: relative;
  display: inline-flex;
  flex: none;
  width: 40px;
  height: 22px;
}
.cg-switch input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
  /* Поверх нарисованного трека <i>: невидимый input и есть кликаемая поверхность —
     иначе клики (и Playwright-хиты) перехватывал бы декоративный слой. */
  z-index: 1;
}
.cg-switch i {
  position: absolute;
  inset: 0;
  border-radius: var(--radius-full);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  transition:
    background-color var(--dur-base) var(--ease),
    border-color var(--dur-base) var(--ease);
}
.cg-switch i::before {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--muted);
  transition:
    transform var(--dur-base) var(--ease),
    background-color var(--dur-base) var(--ease);
}
.cg-switch input:checked + i {
  background: var(--accent-soft);
  border-color: var(--accent);
}
.cg-switch input:checked + i::before {
  transform: translateX(18px);
  background: var(--accent);
}
.cg-switch input:focus-visible + i {
  box-shadow: var(--focus-ring);
}

/* --- «?»-подсказка на details (.cg-help): кружок-маркер + поповер над ним --- */
.cg-help summary::-webkit-details-marker {
  display: none;
}
.cg-help summary:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* --- оценка сессии (/sessions, хендофф 2026-08-18): звёзды 1..3 + кнопка отзыва.
   Ховер подсвечивает звезду и все ЛЕВЕЕ неё (селектор :has(~ :hover)) — превью
   будущей оценки; выбранные горят акцентом (.is-on). --- */
.cg-star {
  background: none;
  border: none;
  cursor: pointer;
  padding: 0 2px;
  font-size: 1.1rem;
  line-height: 1;
  color: var(--muted-2);
  transition:
    color var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease);
}
.cg-star:hover {
  transform: scale(1.15);
}
.cg-star.is-on {
  color: var(--accent);
}
.cg-stars:hover .cg-star {
  color: var(--muted-2);
}
.cg-stars .cg-star:hover,
.cg-stars .cg-star:has(~ .cg-star:hover) {
  color: var(--accent-hover);
}
.cg-review-btn {
  background: none;
  border: none;
  cursor: pointer;
  padding: var(--space-1) 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--muted);
  transition: color var(--dur-fast) var(--ease);
}
.cg-review-btn:hover {
  color: var(--accent-hover);
}
.cg-review-btn.is-done {
  color: var(--success);
}
#cg-review-dialog::backdrop {
  background: rgba(0, 0, 0, 0.55);
}

/* --- декор: бегущая строка телеметрии (TelemetryBar) --- */
@keyframes cg-ticker {
  to {
    transform: translateX(-50%);
  }
}
.cg-telemetry {
  overflow: hidden;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  padding: var(--space-2) 0;
  white-space: nowrap;
}
.cg-telemetry__track {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted);
  animation: cg-ticker 40s linear infinite;
}

/* --- декор: анимированный пунктир схемы пиров (PeerSchema) --- */
@keyframes cg-dash {
  to {
    stroke-dashoffset: -13;
  }
}
.cg-dash-line {
  stroke: var(--accent);
  stroke-width: 1.5;
  fill: none;
  stroke-dasharray: 6 7;
  animation: cg-dash 1.6s linear infinite;
}

/* --- FAQ на нативных details/summary (редизайн хендоффа 2026-08-18) ---
   Сетка 5+5 в две колонки (мобайл — одна); margin-bottom вместо соседского
   `+`-селектора, потому что вопросы разложены по КОЛОНКАМ-обёрткам. Открытый
   вопрос подсвечен: рамка accent со свечением, 2px акцентная кромка слева
   (::before), номер-регистр загорается акцентом, ответ въезжает 240ms. */
.cg-faq-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 var(--space-4);
  align-items: start;
}
.cg-faq-grid > div {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
@media (max-width: 767px) {
  .cg-faq-grid {
    grid-template-columns: 1fr;
  }
}
.cg-faq {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  margin-bottom: var(--space-4);
  position: relative;
  overflow: hidden;
  transition:
    border-color var(--dur-base) var(--ease),
    box-shadow var(--dur-base) var(--ease);
}
.cg-faq::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--accent);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease);
}
.cg-faq:hover {
  border-color: var(--border-strong);
}
.cg-faq[open] {
  border-color: var(--accent);
  box-shadow:
    0 0 28px -14px var(--accent),
    0 8px 24px rgba(0, 0, 0, 0.3);
}
.cg-faq[open]::before {
  opacity: 1;
}
.cg-faq summary {
  cursor: pointer;
  list-style: none;
  padding: var(--space-4) var(--space-5);
  font-weight: 600;
  display: flex;
  gap: var(--space-3);
  align-items: baseline;
}
.cg-faq summary::-webkit-details-marker {
  display: none;
}
.cg-faq summary:hover {
  color: var(--accent-hover);
}
.cg-faq__num {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted-2);
  flex: none;
}
.cg-faq[open] .cg-faq__num {
  color: var(--accent);
}
/* маркер-регистр вместо стрелки: закрыт «[+]», открыт «[–]» */
.cg-faq summary::after {
  content: '[+]';
  font-family: var(--font-mono);
  color: var(--muted);
  font-size: var(--text-sm);
  margin-left: auto;
  transition: color var(--dur-fast) var(--ease);
}
.cg-faq[open] summary::after {
  content: '[–]';
  color: var(--accent);
}
@keyframes cg-faq-in {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.cg-faq > div {
  padding: 0 var(--space-5) var(--space-5);
  color: var(--muted);
  font-size: var(--text-sm);
}
.cg-faq[open] > div {
  animation: cg-faq-in 240ms var(--ease) both;
}

/* --- scroll-reveal лендинга (каскад, хендофф 2026-08-18) ---
 * .cg-reveal сам по себе НИЧЕГО не прячет (SSG-разметка и no-JS видимы как
 * есть); прячет только --armed, который вешает useReveal с JS — теперь на
 * ДЕТЕЙ секций, карточки гридов получают каскадную задержку через --rd
 * (см. useReveal.ts). --in идёт в стилях ПОСЛЕ --armed и потому побеждает
 * при равной специфичности. Заголовок появившегося блока мигает
 * «ЭЛТ-включением» (cg-crt-in — та же сигнатура, что у хиро). */
.cg-reveal--armed {
  opacity: 0;
  transform: translateY(16px);
}
.cg-reveal--in {
  opacity: 1;
  transform: none;
  transition:
    opacity 520ms var(--ease) var(--rd, 0ms),
    transform 520ms var(--ease) var(--rd, 0ms);
}
.cg-reveal--in h2 {
  animation: cg-crt-in 340ms var(--ease) both;
}

/* --- сигнатура: полоса развёртки (хендофф 2026-08-18) — слабый градиент в 4%
   акцента проходит по экрану сверху вниз каждые ~17 с; последняя часть цикла —
   пауза за верхней кромкой, чтобы полоса не мелькала непрерывно. --- */
.cg-sweep {
  position: fixed;
  left: 0;
  right: 0;
  top: -30vh;
  height: 26vh;
  z-index: 6;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    transparent,
    var(--scanline) 45%,
    color-mix(in srgb, var(--accent) 4%, transparent) 50%,
    var(--scanline) 55%,
    transparent
  );
  animation: cg-sweep 17s linear infinite;
}
@keyframes cg-sweep {
  0% {
    transform: translateY(0);
  }
  78% {
    transform: translateY(160vh);
  }
  100% {
    transform: translateY(160vh);
  }
}

/* --- featured-плитка витрины («популярный» пакет): рамка акцентом со
   свечением; ховер чуть ярче. !important — поверх инлайновой рамки Card. --- */
.cg-feature {
  border-color: var(--accent) !important;
  box-shadow:
    0 0 0 1px var(--accent),
    0 12px 32px rgba(0, 0, 0, 0.45),
    0 0 44px -14px var(--accent);
}
.cg-feature:hover {
  border-color: var(--accent-hover) !important;
  box-shadow:
    0 0 0 1px var(--accent-hover),
    0 14px 36px rgba(0, 0, 0, 0.5),
    0 0 52px -12px var(--accent);
}

/* --- CTA плитки пакета: «кнопка»-span внутри карточки-ссылки (лендинг) и
   настоящая кнопка «Купить» (ЛК) делят компактную геометрию. --- */
.cg-bundle-cta {
  display: inline-flex;
  justify-content: center;
  text-align: center;
  padding: var(--space-2) var(--space-3);
  margin-top: var(--space-2);
}

/* --- навигация ЛК: вес у всех пунктов ОДИНАКОВЫЙ (600) всегда — актив
   кодируется цветом и «кареткой» (янтарная полоса 2px, терминальный курсор),
   а не жирностью: пункты не смещаются ни при переходе, ни при ховере. --- */
.cg-nav-link {
  color: var(--muted);
  font-weight: 600;
  font-size: var(--text-sm);
  text-decoration: none;
  white-space: nowrap; /* пункт переносится целиком, а не по словам */
  padding: var(--space-1) 0;
  border-bottom: 2px solid transparent;
  transition: color var(--dur-fast) var(--ease);
}
.cg-nav-link:hover {
  color: var(--text);
}
.cg-nav-link--active {
  color: var(--text);
  border-bottom-color: var(--accent);
}

/* --- витрина пакетов: ВСЕ плитки в одну строку (требование владельца). Флекс с
   flex:1 1 0 делит ширину поровну при любом числе пакетов из API — хардкода
   «5 колонок» нет. На узких экранах — перенос в 2 колонки: горизонтальный скролл
   на мобиле сознательно не делаем (гайдлайн ui-ux-pro-max: High severity). --- */
.cg-bundle-row {
  display: flex;
  gap: var(--space-3);
  align-items: stretch;
}
.cg-bundle-row > * {
  flex: 1 1 0;
  min-width: 0;
  /* Плитка — контейнер: кегли внутри BundleCard считаются в cqw от её ширины,
     а не от viewport (в узкой колонке /time vw-кегль вылезал за плитку). */
  container-type: inline-size;
}
/* Перенос в 2 колонки поднят с 719px до 900px (2026-09-17): между ними пять плиток
   ужимались до ~122px, и контейнерные кегли падали до 10px («Купить» не читалась).
   Ряд становится СЕТКОЙ, а не флексом с переносом: при флексе последняя плитка
   оставалась одна в строке и растягивалась на всю ширину — её кегли подскакивали
   вдвое против соседей, и она читалась как чужая. В сетке все плитки одной ширины. */
@media (max-width: 900px) {
  .cg-bundle-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* --- ряд действий ОДНОЙ ширины и высоты (страница «Друзья»): четыре кнопки в сетке,
   на телефоне — 2×2. grid-auto-rows: 1fr держит рядам одинаковую высоту, даже если
   подпись одной кнопки перенеслась на две строки; ссылка (<a>) в этой сетке выглядит
   как кнопка — display и text-decoration задаются здесь, а не инлайном, чтобы
   мобильное правило их не проигрывало. --- */
.cg-btn-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: 1fr;
  gap: var(--space-3);
}
.cg-btn-grid > .cg-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  line-height: var(--leading-tight);
  text-decoration: none;
  white-space: normal;
  min-width: 0;
}
@media (max-width: 640px) {
  .cg-btn-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* --- строка приглашённого (страница «Друзья»): контакт | статус | дата на десктопе;
   на телефоне дата уходит к контакту в первую строку, статус — во вторую, подсказка — в
   третью. Сетка, а не флекс с переносом: колонки статуса и даты обязаны стоять на одной
   вертикали во всех строках списка. --- */
.cg-invite-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  column-gap: var(--space-4);
  row-gap: var(--space-1);
  align-items: center;
  padding: var(--space-3) var(--space-5);
  border-top: 1px solid var(--border);
}
.cg-invite-row__contact {
  grid-column: 1;
  grid-row: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
}
.cg-invite-row__badge {
  grid-column: 2;
  grid-row: 1;
  justify-self: start;
}
.cg-invite-row__date {
  grid-column: 3;
  grid-row: 1;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted);
  white-space: nowrap;
}
.cg-invite-row__hint {
  grid-column: 1 / -1;
  grid-row: 2;
  font-size: var(--text-xs);
  color: var(--muted);
  line-height: var(--leading-normal);
}
@media (max-width: 640px) {
  .cg-invite-row {
    grid-template-columns: minmax(0, 1fr) auto;
    padding: var(--space-3) var(--space-4);
  }
  .cg-invite-row__badge {
    grid-column: 1 / -1;
    grid-row: 2;
  }
  .cg-invite-row__date {
    grid-column: 2;
    grid-row: 1;
  }
  .cg-invite-row__hint {
    grid-row: 3;
  }
}

/* --- карточка игры v5: вся карточка — ссылка на страницу игры (/game),
   а «Играть» — компактная кнопка-пилюля внизу обложки.
   На десктопе кнопка появляется по ховеру/фокусу, на таче видна всегда. --- */
.cg-game-card {
  position: relative;
}

.cg-game-badge {
  position: absolute;
  top: var(--space-2);
  left: var(--space-2);
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.05em;
  padding: 3px 8px;
  line-height: 1.2;
  border-radius: var(--radius-sm);
  pointer-events: none;
  text-transform: uppercase;
  max-width: calc(100% - var(--space-4));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.cg-game-badge--f2p {
  background: rgba(46, 204, 113, 0.22);
  color: #4ade80;
  border: 1px solid rgba(46, 204, 113, 0.55);
  box-shadow: 0 0 10px rgba(46, 204, 113, 0.25);
}

.cg-game-badge--steam {
  background: rgba(23, 19, 12, 0.75);
  color: var(--accent);
  border: 1px solid rgba(255, 176, 0, 0.45);
  box-shadow: 0 0 10px rgba(255, 176, 0, 0.2);
}

.cg-game-card__more {
  position: absolute;
  bottom: calc(var(--space-2) + 4px);
  right: var(--space-2);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 36px;
  padding: 0 var(--space-3);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  background: rgba(23, 19, 12, 0.75);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  pointer-events: none;
  opacity: 0;
  transform: translateY(4px);
  transition:
    opacity var(--dur-base) var(--ease),
    transform var(--dur-base) var(--ease),
    background var(--dur-base) var(--ease),
    border-color var(--dur-base) var(--ease),
    color var(--dur-base) var(--ease);
}

.cg-game-card__play-btn {
  position: absolute;
  bottom: var(--space-2);
  left: var(--space-2);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 44px;
  min-width: 44px;
  padding: var(--space-2) var(--space-4);
  background: var(--accent);
  color: var(--on-accent);
  border: 0;
  border-radius: var(--radius-full);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
  transition:
    opacity var(--dur-base) var(--ease),
    transform var(--dur-base) var(--ease),
    background var(--dur-base) var(--ease);
}

.cg-game-card__play-btn:hover:not(:disabled) {
  background: var(--accent-hover);
}

.cg-game-card__play-btn:disabled {
  opacity: 0.75;
  cursor: default;
}

@media (hover: hover) {
  .cg-game-card__play-btn {
    opacity: 0;
    transform: translateY(4px);
    pointer-events: none;
  }
  .cg-game-card:hover .cg-game-card__play-btn,
  .cg-game-card:focus-within .cg-game-card__play-btn,
  .cg-game-card__play-btn--visible,
  .cg-game-card__play-btn--touch {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
  .cg-game-card:hover .cg-game-card__more,
  .cg-game-card:focus-within .cg-game-card__more {
    opacity: 1;
    transform: translateY(0);
    color: var(--accent);
    border-color: var(--accent);
    background: rgba(23, 19, 12, 0.88);
  }
}

@media (hover: none) {
  .cg-game-card__play-btn {
    opacity: 1;
    pointer-events: auto;
  }
  .cg-game-card__more {
    display: none;
  }
}

@media (max-width: 480px) {
  .cg-game-card__more {
    display: none;
  }
}

/* Обратная совместимость для старых классов оверлея v4 */
.cg-game-card__cta {
  display: none;
}
.cg-game-card__cta-label {
  display: none;
}
.cg-game-card__cta-play {
  display: none;
}

/* --- ховер-подъём интерактивных карточек (каталог, тизер лендинга) --- */
.cg-lift {
  transition:
    transform var(--dur-base) var(--ease),
    border-color var(--dur-base) var(--ease),
    box-shadow var(--dur-base) var(--ease);
}
.cg-lift:hover {
  transform: translateY(-3px);
  border-color: var(--border-strong);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}

/* --- страница-карточка игры (/game): раскладка и рамка активного скриншота --- */
.cg-game-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: var(--space-6);
  align-items: start;
}
@media (max-width: 860px) {
  .cg-game-layout {
    grid-template-columns: 1fr;
  }
  /* обложка с кнопкой «Играть» — первой: на телефоне действие важнее галереи */
  .cg-game-layout > aside {
    order: -1;
  }
}
/* скобки-уголки «[ ]» на активном кадре галереи — та же сигнатура, что у .cg-label
   и спотлайта бонуса (.cg-spot-frame), только без анимации: рамка, а не призыв */
.cg-shot-frame {
  position: relative;
}
.cg-shot-frame::before,
.cg-shot-frame::after {
  content: '';
  position: absolute;
  top: -6px;
  bottom: -6px;
  width: 10px;
  border: 2px solid var(--accent);
  pointer-events: none;
}
.cg-shot-frame::before {
  left: -10px;
  border-right: none;
}
.cg-shot-frame::after {
  right: -10px;
  border-left: none;
}
#cg-shot-dialog::backdrop {
  background: rgba(0, 0, 0, 0.82);
}

/* --- спотлайт бонуса (/catalog): затемнение всего экрана и «прицел» на карточке
   подтверждения номера. Слои: дим 80, цель 81 — с запасом выше остального ЛК
   (максимум прочих слоёв — 10). Логика показа — в OnboardingCard.tsx. --- */
@keyframes cg-spot-fade {
  from {
    opacity: 0;
  }
}
.cg-spot-dim {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(0, 0, 0, 0.72);
  animation: cg-spot-fade var(--dur-base) var(--ease) both;
}
.cg-spot-frame {
  position: relative;
  z-index: 81;
  box-shadow: 0 0 64px color-mix(in srgb, var(--accent) 22%, transparent);
}
/* гигантские «[ ]» по бокам цели — те же скобки, что у .cg-label; дышат */
.cg-spot-frame::before,
.cg-spot-frame::after {
  content: '';
  position: absolute;
  top: -8px;
  bottom: -8px;
  width: 12px;
  border: 2px solid var(--accent);
  pointer-events: none;
  animation: cg-spot-breathe 2.4s var(--ease) infinite;
}
.cg-spot-frame::before {
  left: -14px;
  border-right: none;
}
.cg-spot-frame::after {
  right: -14px;
  border-left: none;
}
@keyframes cg-spot-breathe {
  50% {
    opacity: 0.55;
  }
}
/* каллаут с шевронами снят 2026-09-16: подсказку, которую объясняет вторая подсказка,
   владелец справедливо назвал навязчивой — «прицела» из скобок довольно. */

/* --- помощник запуска (/start) --------------------------------------------------------
   Две подачи одного шага, переключаются ЧИСТО МЕДИАЗАПРОСОМ на 720px, без JS:
   > 720px  — «смотри → нажми»: кадр Steam с янтарными маркерами слева, нумерованный
              список действий справа (.cg-onb-look + .cg-onb-marks + .cg-onb-nlist);
   <= 720px — «лента кадров»: 2–3 узких зум-окна вертикально (.cg-onb-ribbon).
   Оба варианта живут в разметке одновременно и прячутся друг другом: measure по
   matchMedia дал бы вспышку чужого варианта до гидрации (страница клиентская).
   Общее — шапка-точки, заголовок, плашки и кнопки — рендерится ОДИН раз. --- */

.cg-onb-look {
  display: grid;
  grid-template-columns: 1.3fr minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
}
/* высокий кадр (форма регистрации) не должен раздавливать колонку с текстом */
.cg-onb-look--tall {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

/* кадр Steam: наша рамка и шапка с номером шага; сам снимок без разметки поверх */
.cg-onb-shot {
  margin: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: #0b0906;
  overflow: hidden;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.38);
  min-width: 0;
}
.cg-onb-shot__cap {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text);
}
.cg-onb-shot__cap b {
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: var(--radius-full);
  background: var(--accent);
  color: var(--on-accent);
  display: grid;
  place-items: center;
  /* Было 0.7rem (11.2px) — ниже порога читаемости; --text-xs = 12px (аудит 2026-09-17). */
  font-size: var(--text-xs);
  line-height: 1;
}
.cg-onb-shot__cap span {
  margin-left: auto;
  color: var(--muted-2);
  flex: none;
}
.cg-onb-shot__frame {
  position: relative;
  line-height: 0;
}
.cg-onb-shot__frame img {
  display: block;
  width: 100%;
  height: auto;
}
/* пара кадров: шаг «игра в библиотеке», когда игра ещё не выбрана — версию выбрать не из
   чего, поэтому показываем оба пути сразу (бесплатную добавляют, платную покупают).
   Кадры узкие и низкие, так что в колонку они встают без ущерба читаемости. */
.cg-onb-pair {
  display: grid;
  gap: var(--space-3);
}
/* на телефоне пару заменяет лента (.cg-onb-ribbon), как и одиночный кадр */
@media (max-width: 720px) {
  .cg-onb-pair {
    display: none;
  }
}

/* --- живая панель шага 1: подтверждение номера прямо в помощнике (см. TelegramPanel).
   Стоит на месте кадра Steam и НЕ прячется на телефоне: ленты для неё нет, да и прятать
   единственное действие шага нельзя. --- */
.cg-onb-tg {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: var(--space-5);
}
/* подарок крупно — единственная «цифра-герой» помощника, поэтому моно */
.cg-onb-tg__gift {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.cg-onb-tg__gift b {
  font-family: var(--font-mono);
  font-size: var(--text-2xl);
  line-height: var(--leading-tight);
  color: var(--accent);
}
.cg-onb-tg__gift span {
  font-size: var(--text-sm);
  color: var(--muted);
}
.cg-onb-tg__hint {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--muted);
}
.cg-onb-tg__acts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}
/* «Показать QR-код» — дверь для десктопа: на телефоне сканировать себя нечем */
@media (max-width: 720px) {
  .cg-onb-tg__qr {
    display: none;
  }
}
/* ожидание: мягкий пульс вместо спиннера — ждём человека, а не сервер */
.cg-onb-tg__wait {
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-base);
}
.cg-onb-tg__wait i {
  width: 10px;
  height: 10px;
  flex: none;
  border-radius: var(--radius-full);
  background: var(--accent);
  animation: cg-onb-pulse 1.6s var(--ease) infinite;
}
@keyframes cg-onb-pulse {
  50% {
    opacity: 0.25;
    transform: scale(0.8);
  }
}
/* подтверждено: зелёная плашка той же семантики, что финал ленты кадров */
.cg-onb-tg__ok {
  margin: 0;
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  border: 1px solid rgba(134, 194, 50, 0.45);
  background: rgba(134, 194, 50, 0.08);
  border-radius: var(--radius);
  padding: var(--space-4);
}
.cg-onb-tg__ok b {
  color: var(--success);
  font-size: var(--text-lg);
  line-height: 1;
}
.cg-onb-tg__ok strong {
  display: block;
  font-size: var(--text-base);
  font-weight: 600;
}
.cg-onb-tg__ok small {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: var(--text-sm);
}

/* нумерованный маркер поверх кадра; координаты — инлайновые left/top в процентах */
.cg-onb-mark {
  position: absolute;
  width: 30px;
  height: 30px;
  border-radius: var(--radius-full);
  transform: translate(-50%, -50%);
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: var(--text-sm);
  display: grid;
  place-items: center;
  box-shadow: 0 0 0 4px rgba(255, 176, 0, 0.2), 0 8px 16px rgba(0, 0, 0, 0.6);
}

/* список «1-2-3»: те же цифры, что на кадре, — глазами искать не нужно */
.cg-onb-nlist {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-3);
  align-content: start;
}
.cg-onb-nlist li {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  min-width: 0;
}
.cg-onb-nlist li > b {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: var(--radius-full);
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  display: grid;
  place-items: center;
  box-shadow: 0 0 0 3px rgba(255, 176, 0, 0.14);
}
.cg-onb-nlist small {
  display: block;
  color: var(--muted);
  font-size: var(--text-xs);
  margin-top: 2px;
}

/* лента кадров: зум-окна одной высоты со стрелками между ними */
.cg-onb-ribbon {
  display: none;
  gap: var(--space-3);
  align-items: flex-start;
}
.cg-onb-ribbon > div {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 0;
}
.cg-onb-ribbon__arrow {
  flex: none;
  align-self: center;
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  line-height: 1;
  transform: rotate(90deg);
}
/* окно зума: показывает кусок кадра; --zw/--zl/--zt считает страница по долям снимка */
.cg-onb-zoom {
  position: relative;
  overflow: hidden;
  width: 100%;
  aspect-ratio: var(--ar, 2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: #0b0906;
}
.cg-onb-zoom img {
  position: absolute;
  max-width: none;
  height: auto;
  width: var(--zw);
  left: var(--zl);
  top: var(--zt);
}
.cg-onb-zoom__cap {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted);
  text-align: center;
  margin-top: var(--space-1);
}
/* финальный кадр ленты — результат: «в библиотеке» / «ты вошёл» */
.cg-onb-done {
  width: 100%;
  border: 1px solid rgba(134, 194, 50, 0.45);
  border-radius: var(--radius);
  background: rgba(134, 194, 50, 0.06);
  display: grid;
  place-items: center;
  align-content: center;
  gap: var(--space-1);
  padding: var(--space-4);
  text-align: center;
}

@media (max-width: 720px) {
  /* одна колонка: сначала картинка, потом текст и кнопки — как в макете «лента кадров» */
  .cg-onb-look,
  .cg-onb-look--tall {
    grid-template-columns: minmax(0, 1fr);
  }
  /* кадр с маркерами и список «1-2-3» уступают место ленте: на 390px маркеры налезают
     друг на друга, а мелкие детали экрана Steam всё равно не читаются */
  .cg-onb-shot,
  .cg-onb-nlist {
    display: none;
  }
  .cg-onb-ribbon {
    display: flex;
    flex-direction: column;
  }
}

/* плашка про деньги: единственная красная в помощнике — шаг «игра в библиотеке» */
.cg-onb-warn {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  border: 1px solid rgba(255, 83, 64, 0.42);
  background: rgba(255, 83, 64, 0.06);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
}
.cg-onb-warn > b {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: var(--radius-full);
  background: var(--danger-soft);
  color: var(--danger-on-soft);
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
}

/* запасной путь (Steam Guard по почте, приложение на телефон) — строка, а не плашка */
.cg-onb-guard {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  font-size: var(--text-sm);
  color: var(--neutral-on-soft);
  background: var(--surface-2);
  border-left: 2px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: var(--space-2) var(--space-3);
}
.cg-onb-guard > b {
  color: var(--accent);
  flex: none;
  font-family: var(--font-mono);
}

/* сегмент «аккаунта нет / аккаунт есть» — переключатель ветки шага 2 */
.cg-onb-seg {
  display: inline-flex;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.cg-onb-seg button {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  padding: var(--space-2) var(--space-3);
  color: var(--muted);
  background: transparent;
  border: 0;
  cursor: pointer;
}
.cg-onb-seg button[aria-pressed='true'] {
  background: var(--accent-soft);
  color: var(--accent);
}

/* точки прогресса в шапке шага — КНОПКИ: по ним листают помощника прыжком.
   Цель клика 24px (девятипиксельная точка на телефоне непопадаема), сама точка — ::before */
.cg-onb-dots {
  display: flex;
  gap: var(--space-1);
  align-items: center;
}
.cg-onb-dots button {
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  display: grid;
  place-items: center;
  border-radius: var(--radius-full);
}
.cg-onb-dots button::before {
  content: '';
  width: 9px;
  height: 9px;
  border-radius: var(--radius-full);
  background: var(--border-strong);
  transition: background-color var(--dur-fast) var(--ease);
}
.cg-onb-dots button:hover::before {
  background: var(--accent-hover);
}
.cg-onb-dots button[data-state='done']::before {
  background: var(--success);
}
.cg-onb-dots button[data-state='now']::before {
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* --- шапка помощника: обещание слева, выход из него справа --- */
.cg-onb-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}

/* --- нижняя навигация шага: «назад» слева, движение вперёд справа --- */
.cg-onb-nav {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}

/* --- чеклист помощника на /catalog: четыре шага одной строкой чипов.
   Раньше это были четыре карточки в сетке плюс полоса прогресса — блок занимал полэкрана
   и спорил с обложками игр за роль героя (замечание владельца 2026-09-16). Чипы несут то
   же самое: что закрыто, что сейчас, сколько осталось. На телефоне — две колонки. --- */
.cg-onb-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.cg-onb-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: var(--surface-2);
  color: var(--muted);
  font-size: var(--text-sm);
  padding: var(--space-1) var(--space-3);
}
.cg-onb-chip > i {
  font-style: normal;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted-2);
}
.cg-onb-chip[data-state='done'] {
  border-color: rgba(134, 194, 50, 0.4);
  color: var(--neutral-on-soft);
}
.cg-onb-chip[data-state='done'] > i {
  color: var(--success);
}
.cg-onb-chip[data-state='now'] {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--text);
}
.cg-onb-chip[data-state='now'] > i {
  color: var(--accent);
}
/* Телефонная подпись чипа скрыта на десктопе и наоборот (см. STEP_TITLES_SHORT). */
.cg-onb-chip__short {
  display: none;
}
@media (max-width: 520px) {
  /* на 390px четыре чипа в строку не читаются — раскладываем сеткой в две колонки */
  .cg-onb-chips {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    /* Ряды одной высоты: даже если одна подпись однажды перенесётся, ступеньки не будет. */
    grid-auto-rows: 1fr;
  }
  /* Половина ряда на 390px — это ~135px. Кегль --text-xs и запрет переноса держат
     подпись в одну строку; то, что не помещается и так, укорочено в STEP_TITLES_SHORT
     (аудит 2026-09-17: «Игра в библиотеке» и «Вход по QR» ломались надвое). */
  .cg-onb-chip {
    font-size: var(--text-xs);
    white-space: nowrap;
    padding: var(--space-1) var(--space-2);
    gap: var(--space-1);
  }
  .cg-onb-chip__full {
    display: none;
  }
  .cg-onb-chip__short {
    display: inline;
  }
}

/* --- чип-ответ «платить или нет» в шапке блока «Перед запуском» (карточка игры) --- */
.cg-onb-badge {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 3px 8px;
}
.cg-onb-badge[data-tone='success'] {
  background: var(--success-soft);
  border-color: rgba(134, 194, 50, 0.35);
  color: var(--success);
}
.cg-onb-badge[data-tone='accent'] {
  background: var(--accent-soft);
  border-color: rgba(255, 176, 0, 0.35);
  color: var(--accent);
}
.cg-onb-badge[data-tone='neutral'] {
  background: var(--neutral-soft);
  border-color: var(--border);
  color: var(--neutral-on-soft);
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
