/* Волны 9-10: редизайн, мета, геймфил, доступность.
   Часть общего каскада, файл 11-redesign.css. ПОРЯДОК ФАЙЛОВ ЗНАЧИМ:
   поздние правила перекрывают ранние порядком, а не !important,
   поэтому index.html подключает их строго по номеру. */

/* ==========================================================================
   ВОЛНА 9. РЕДИЗАЙН + МОБИЛЬНАЯ ИГРАБЕЛЬНОСТЬ.
   Единый визуальный язык: тёмный «неоновый сад» — изумрудный бренд-акцент
   (--brand) + циановый вторичный (--brand2). Красный остаётся ТОЛЬКО
   опасности/смерти (--accent). Блок идёт последним и перекрывает ранние
   правила порядком, а не !important.
   ========================================================================== */

/* Единственная и финальная точка правды для перечисленных ниже токенов:
   раньше их дублировали ещё html[data-theme]/html[data-theme="light"] —
   селекторы для несуществующей светлой темы (см. комментарий в 01-base.css),
   убраны как мёртвый код, значение не менялось.
   --panel/--panel2 отвечают одновременно за контраст текста (волна 8,
   AA-порог 4.5:1 для --muted2 поверх --panel, см. комментарий в
   10-ux-waves.css) и за визуальный стиль волны 9 — сохраняем текущую
   непрозрачность (0.80/0.58 не ниже волны-8 0.76/0.56), чтобы не откатить
   AA-фикс задним числом. */
:root {
  --bg: #060a12;
  --brand: #2ee6a0;
  --brand2: #4cc9f0;
  /* --accent2 и --focus отсюда убраны: они повторяли значения из :root
     01-base.css символ в символ. */
  --panel: rgba(9, 14, 22, 0.80);
  --panel2: rgba(6, 11, 19, 0.58);
  --border: rgba(148, 163, 184, 0.18);
  --border2: rgba(148, 163, 184, 0.13);
  --btn: rgba(148, 163, 184, 0.10);
  --btn2: rgba(148, 163, 184, 0.17);
  --grid: rgba(255, 255, 255, 0.045);
  --r-lg: 18px;
  /* .btnPlay крупнее и ярче остальных кнопок нарочно — свой радиус и своя,
     акцентная тень поверх base-токенов --r-* / --shadow-float. */
  --btn-play-radius: 16px;
  --btn-play-shadow: 0 12px 36px color-mix(in srgb, var(--brand) 30%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.35);
  --btn-play-shadow-hover: 0 16px 44px color-mix(in srgb, var(--brand) 40%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.4);
  /* .btnPrimary/.btnSecondary/.btnGhost/.iconBtn делят один и тот же фокус-ring
     (см. 02-cosmetics.css) — было 4 буквальных копии одного значения. */
  --btn-focus-shadow: 0 0 0 3px color-mix(in srgb, var(--focus) 25%, transparent);
  /* Тот же градиент .btnPrimary был буквально продублирован в 02-cosmetics.css
     (мёртвое правило, перекрытое этим же файлом порядком каскада) — один
     источник вместо двух копий одного хардкода. Значение не менялось. */
  --btn-primary-grad: linear-gradient(135deg, #2bd694, #3fb9dd);
}

/* --- Мобильные свайпы: без touch-action браузер сам съедает pointermove ----
   Главная причина «на телефоне змейка не слушается свайпов»: жест уходил в
   пан/pull-to-refresh, и canvas получал pointercancel вместо движения. */
#game {
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* --- Индикатор свайпа: видимая точка отсчёта и порог срабатывания -------- */
#swipeIndicator {
  position: fixed;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  pointer-events: none;
  z-index: 500;
  opacity: 0;
  transition: opacity 0.08s ease-out;
}
#swipeIndicator.isOn {
  opacity: 1;
}
.swipeIndicator-deadzone {
  position: absolute;
  left: 0;
  top: 0;
  width: 44px;
  height: 44px;
  margin-left: -22px;
  margin-top: -22px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.55);
  background: rgba(255, 255, 255, 0.08);
  box-sizing: border-box;
}
.swipeIndicator-dot {
  position: absolute;
  left: 0;
  top: 0;
  width: 14px;
  height: 14px;
  margin-left: -7px;
  margin-top: -7px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.85);
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.4);
  transition: transform 0.02s linear;
}

/* --- Оверлеи: глубина вместо красной засветки ------------------------------ */
.overlay,
.endOverlay {
  background:
    radial-gradient(1000px 620px at 18% 12%, rgba(46, 230, 160, 0.10), transparent 55%),
    radial-gradient(900px 560px at 84% 88%, rgba(124, 92, 255, 0.10), transparent 55%),
    rgba(3, 6, 12, 0.66);
  backdrop-filter: blur(14px);
}

.overlay .card {
  background: linear-gradient(180deg, rgba(15, 23, 36, 0.94), rgba(8, 13, 21, 0.96));
  border: 1px solid rgba(148, 163, 184, 0.15);
  border-radius: 20px;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

.overlayTitle,
.overlay .card .overlayTitle {
  background: linear-gradient(120deg, #f8fafc 0%, var(--brand) 55%, var(--brand2) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  letter-spacing: -1px;
}

.overlayKicker {
  border-color: color-mix(in srgb, var(--brand) 35%, var(--border2));
  background: color-mix(in srgb, var(--brand) 10%, rgba(0, 0, 0, 0.25));
  color: color-mix(in srgb, var(--brand) 60%, var(--text));
  font-weight: 800;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

/* --- Панели ---------------------------------------------------------------- */
.menuPanel {
  background: rgba(255, 255, 255, 0.025);
  border: 1px solid rgba(148, 163, 184, 0.12);
  border-radius: 16px;
}

.menuPanelPrimary {
  border-color: color-mix(in srgb, var(--brand) 32%, var(--border2));
  background:
    radial-gradient(120% 160% at 0% 0%, color-mix(in srgb, var(--brand) 9%, transparent), transparent 62%),
    rgba(255, 255, 255, 0.02);
}

.menuHowTo {
  border-color: color-mix(in srgb, var(--brand2) 24%, var(--border2));
  background: linear-gradient(180deg, rgba(76, 201, 240, 0.07), rgba(0, 0, 0, 0.18));
}

.menuHowToStep::before {
  border-color: color-mix(in srgb, var(--brand) 50%, var(--border2));
  background: color-mix(in srgb, var(--brand) 16%, rgba(0, 0, 0, 0.3));
}

.menuSkinPreviewWrap,
.cosmeticsPreviewWrap {
  border-color: color-mix(in srgb, var(--brand2) 22%, var(--border2));
  background: radial-gradient(520px 260px at 50% 30%, rgba(76, 201, 240, 0.08), rgba(0, 0, 0, 0.30));
}

/* --- Кнопки ---------------------------------------------------------------- */
.btnPrimary {
  border: 1px solid color-mix(in srgb, var(--brand) 55%, transparent);
  background: var(--btn-primary-grad);
  color: #04170f;
  text-shadow: none;
}

.btnPrimary:hover {
  filter: brightness(1.07) saturate(1.05);
}

.btnPrimary:disabled {
  opacity: 0.45;
  filter: saturate(0.4);
}

.btnPlay,
.menuActions .btnPlay,
.overlay .card .btnPlay {
  min-height: 58px;
  border-radius: var(--btn-play-radius);
  border: 1px solid color-mix(in srgb, var(--brand) 65%, transparent);
  background: linear-gradient(135deg, var(--brand), var(--brand2));
  color: #03130c;
  font-weight: 900;
  letter-spacing: 0.4px;
  box-shadow: var(--btn-play-shadow);
}

.btnPlay:hover {
  box-shadow: var(--btn-play-shadow-hover);
}

/* Спиннер isLoading на ярком фоне — тёмный, а не белый */
.btnPrimary.isLoading::before,
.btnPlay.isLoading::before {
  border-color: rgba(4, 23, 15, 0.35);
  border-top-color: rgba(4, 23, 15, 0.95);
}

.btnSecondary,
.btnGhost,
.iconBtn {
  background: rgba(148, 163, 184, 0.08);
  border-color: rgba(148, 163, 184, 0.18);
}

.btnSecondary:hover,
.btnGhost:hover,
.iconBtn:hover {
  background: rgba(148, 163, 184, 0.16);
  border-color: rgba(148, 163, 184, 0.28);
}

/* --- Поля ввода ------------------------------------------------------------ */
.menuPanelBody input,
.menuPanelBody select,
.roomsControls input,
.roomsControls select,
#nameInput {
  background: rgba(3, 8, 16, 0.55);
  border-color: rgba(148, 163, 184, 0.20);
  border-radius: 12px;
}

/* --- Комнаты --------------------------------------------------------------- */
.roomRow {
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.025);
}

.roomRow.selected {
  border-color: color-mix(in srgb, var(--brand2) 60%, transparent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand2) 14%, transparent);
}

/* --- Игровой HUD: нейтральное стекло вместо красного градиента ------------- */
body.inGame #hud:not(.lbPinned):hover,
body.inGame #hud:not(.lbPinned):focus-within {
  background: linear-gradient(160deg, rgba(17, 26, 40, 0.82), rgba(7, 11, 19, 0.88));
}

.topHudBarFill {
  background: linear-gradient(90deg, var(--brand), var(--brand2));
}

#topHud,
#rightInfo .rightDetails,
#rightSidebar #minimap,
#rightSidebar #teamHud,
#rightSidebar #perf,
#rightSidebar #killfeed,
#chat {
  border-radius: 14px;
}

/* --- Чат ------------------------------------------------------------------- */
.chatLine {
  background: rgba(255, 255, 255, 0.03);
  border-color: rgba(255, 255, 255, 0.05);
}

.chatLine.me {
  border-color: color-mix(in srgb, var(--brand) 26%, rgba(255, 255, 255, 0.06));
  background: linear-gradient(135deg, color-mix(in srgb, var(--brand) 8%, transparent), rgba(0, 0, 0, 0.14));
}

/* --- Экран итогов матча: бренд, а не сине-красная пара --------------------- */
.matchCard {
  border-color: color-mix(in srgb, var(--brand2) 35%, var(--border2));
  background: linear-gradient(150deg, rgba(76, 201, 240, 0.10), rgba(5, 9, 16, 0.92));
}

.matchResultWin {
  border-color: color-mix(in srgb, var(--brand) 60%, rgba(255, 255, 255, 0.12));
  box-shadow: inset 0 0 0 999px color-mix(in srgb, var(--brand) 12%, transparent);
}

.eventToastBig {
  border-color: color-mix(in srgb, var(--brand) 45%, var(--border2));
  background: linear-gradient(135deg, color-mix(in srgb, var(--brand) 14%, transparent), rgba(0, 0, 0, 0.45));
}

/* Экран смерти остаётся в опасно-красном — это его смысл. */

/* --- Скроллбары ------------------------------------------------------------ */
.overlay .card::-webkit-scrollbar,
.cosmeticsItems::-webkit-scrollbar,
#roomsList::-webkit-scrollbar,
#chatLog::-webkit-scrollbar,
#rightInfo::-webkit-scrollbar,
.matchTableWrap::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

.overlay .card::-webkit-scrollbar-thumb,
.cosmeticsItems::-webkit-scrollbar-thumb,
#roomsList::-webkit-scrollbar-thumb,
#chatLog::-webkit-scrollbar-thumb,
#rightInfo::-webkit-scrollbar-thumb,
.matchTableWrap::-webkit-scrollbar-thumb {
  border-radius: 999px;
  background: rgba(148, 163, 184, 0.25);
}

.overlay .card::-webkit-scrollbar-track,
.cosmeticsItems::-webkit-scrollbar-track,
#roomsList::-webkit-scrollbar-track,
#chatLog::-webkit-scrollbar-track,
#rightInfo::-webkit-scrollbar-track,
.matchTableWrap::-webkit-scrollbar-track {
  background: transparent;
}

/* --- Мобильное упрощение интерфейса ----------------------------------------
   В матче на телефоне остаются только три иконки: карта, настройки, выход.
   Лидерборд-пин бессмыслен (панель #stats на телефоне скрыта), косметика и
   язык доступны из меню — им не место над игровым полем. */
@media (max-width: 720px) {
  body.inGame #lbBtn,
  body.inGame #cosmeticsBtn,
  body.inGame #langToggle {
    display: none;
  }

  /* Правило «скрыть #help на узком экране» удалено вместе со своей причиной:
     подсказка раздувала ряд иконок, только пока лежала внутри #hud. Сейчас
     это отдельный fixed-элемент у нижнего края шириной min(46vw, 340px) — на
     раскладку HUD он не влияет, а на телефоне его и так гасит правило
     (pointer: coarse) ниже. Селектор `#hud #help` всё равно не совпадал. */

  body.inGame #hud:not(.lbPinned) .hudActions {
    gap: 8px;
  }

  /* Кнопка «Играть» на телефоне — главная тач-цель */
  .btnPlay,
  .menuActions .btnPlay {
    min-height: 60px;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Волна 9 новых анимаций не вводит. */
  .btnPlay,
  .btnPrimary {
    transition: none;
  }
}

/* ==========================================================================
   ВОЛНА 10. Мета, геймфил и доступность.
   Блок идёт последним в файле: перекрывает ранние правила порядком.
   ========================================================================== */

/* --- Личный рекорд на экране смерти ----------------------------------------
   Карточка в .matchMiniGrid (та же сетка, что и в итогах матча). Обычное
   состояние — нейтральное, «Новый рекорд» подсвечивается золотом: это
   единственная хорошая новость на экране проигрыша, и она обязана читаться
   первой после места. */
.matchMini.deathRecord {
  border-color: color-mix(in srgb, var(--gold) 55%, transparent);
  background: linear-gradient(135deg, color-mix(in srgb, var(--gold) 16%, transparent), rgba(0, 0, 0, 0.2));
  animation: recordPop 420ms cubic-bezier(0.16, 1.5, 0.3, 1) both;
}

.matchMini.deathRecord .matchMiniLabel {
  color: var(--gold);
}

.matchMini.deathRecord .matchMiniValue {
  color: var(--gold);
  text-shadow: 0 0 14px color-mix(in srgb, var(--gold) 45%, transparent);
}

@keyframes recordPop {
  0% {
    opacity: 0;
    transform: scale(0.86);
  }
  60% {
    transform: scale(1.05);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

/* --- Мета на экране меню ---------------------------------------------------
   Дейлики и прогресс до первого скина жили только в правой панели матча —
   то есть были не видны ровно там, где принимается решение «зайти ещё раз». */
.menuMeta {
  display: grid;
  gap: var(--pad-sm);
  margin-top: var(--pad-md);
}

.menuMeta:empty {
  display: none;
}

.menuMetaRow {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border-radius: var(--r-md);
  border: 1px solid var(--border2);
  background: rgba(255, 255, 255, 0.025);
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--muted);
}

.menuMetaIcon {
  font-size: var(--fs-body);
  line-height: 1;
  flex: 0 0 auto;
}

.menuMetaText {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menuMetaValue {
  flex: 0 0 auto;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--brand) 70%, var(--text));
}

.menuMetaRow.isDone .menuMetaValue {
  color: var(--brand);
}

.menuMetaBar {
  grid-column: 1 / -1;
  height: 5px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(0, 0, 0, 0.32);
  overflow: hidden;
}

.menuMetaBarFill {
  display: block;
  height: 100%;
  width: 0%;
  max-width: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--brand), var(--brand2));
  transition: width 420ms cubic-bezier(0.2, 0.8, 0.3, 1);
}

@media (prefers-reduced-motion: reduce) {
  .matchMini.deathRecord,
  .menuMetaBarFill {
    animation: none;
    transition: none;
  }
}

/* --- Подсказка управления переехала из #hud наружу -------------------------
   Причина — замеренное наложение: строка «Управление: стрелки / WASD…»
   шириной 320px раздувала плавающую панель до 340px, и та перекрывала
   центрированный #topHud (на 1076px они делили полосу 258..352).
   Теперь подсказка живёт отдельным фиксированным элементом у нижнего края и
   на ширину HUD не влияет вовсе. Тач-вариант (#helpTouch) уже жил так же —
   правила ниже приводят мышиный вариант к тому же виду. */
#help {
  position: fixed;
  left: calc(12px + var(--sa-left));
  bottom: calc(12px + var(--sa-bottom));
  z-index: var(--z-hud);
  max-width: min(46vw, 340px);
  padding: 6px 12px;
  border: 1px solid var(--border2);
  border-top: 1px solid var(--border2);
  border-radius: 999px;
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  backdrop-filter: blur(10px);
  font-size: var(--fs-meta);
  font-weight: 600;
  line-height: 1.25;
  color: var(--muted);
  pointer-events: none;
  transition: opacity 600ms ease;
  /* Вне матча подсказка не нужна: показываем её только в игре (см. ниже). */
  display: none;
}

/* В матче — показываем, но не поверх развёрнутого чата и не под оверлеями. */
body.inGame #help {
  display: block;
}

body.overlayActive #help,
body:has(#chat:not(.collapsed)) #help {
  display: none;
}

/* Стек тостов делит с подсказкой левый нижний угол — поднимаем его над ней.
   Только для мыши: на телефоне #help скрыт (там #helpTouch), а мобильное
   правило уже поднимает тосты на 52px под свёрнутый чат. Без ограничения по
   ширине это правило опускало их обратно и тосты налезали на чат. */
@media (min-width: 721px) {
  body.inGame #eventToasts {
    bottom: calc(12px + var(--sa-bottom) + 40px);
  }
}

/* На тач-устройстве вместо неё — #helpTouch: «WASD/Enter/Esc/M» там бессмысленны. */
@media (pointer: coarse) {
  body.inGame #help {
    display: none;
  }
}

/* Резервы под боковые панели. Саму раскладку #topHud задаёт 03-game.css —
   здесь только числа, от которых она считается.
   Слева: 12 + фактическая ширина ряда иконок (247) + запас; справа: 12 +
   потолок #rightSidebar (320) + 12. */
:root {
  --hud-left-reserve: 276px;
  --hud-right-reserve: 344px;
}

/* Между 721 и 900px правая колонка уже уехала вниз (её собственное правило),
   поэтому резерв справа не нужен и полоса забирает освободившееся место. */
@media (min-width: 721px) and (max-width: 900px) {
  :root {
    --hud-right-reserve: 12px;
  }
}

/* Раскладка верхней полосы (.topHudRow/.topHudRight/.topHudContract и отмена
   grid-растяжки у таймера) переехала в 04-game-hud.css — к остальным правилам
   #topHud. Здесь она стояла ПОСЛЕ мобильных медиазапросов 08/10 и молча их
   перекрывала: на телефоне не действовали ни `align-items: center`, ни
   уплотнённые row-gap, ни `margin-top` полосы прогресса. */

/* --- Ряд иконок в матче: только то, что нужно ПО ХОДУ матча ----------------
   Косметика и переключатель языка мид-матчем бесполезны: экипировка
   применяется со следующего возрождения, а язык меняют один раз в жизни.
   Обе кнопки остаются в меню, в настройках и на экранах смерти/итогов.
   Здесь они стоили ширины: шесть кнопок держали #hud на 340px, из-за чего
   верхней полосе оставалось всего 368px и она переносилась в три строки. */
body.inGame #hud:not(.lbPinned) #cosmeticsBtn,
body.inGame #hud:not(.lbPinned) #langToggle {
  display: none;
}

/* --- Тосты и чат не делят нижний край на узком десктопе --------------------
   Замер 768x1024: стек тостов (слева, 420px) доставал до x=432, а чат
   (справа, 420px) начинался с x=336 — наложение 96px. На 1076px его нет,
   потому что чат начинается с 644. Порог: 12 + 420 + 420 + 12 = 864px.

   Ниже порога тосты уезжают ВЫШЕ чата, а не сужаются: узкий тост с обрезанным
   текстом бесполезен, а вертикального места внизу хватает.
   Высота свёрнутого чата ~67px, развёрнутого — до 264px (это уже посчитано
   в --right-bottom-reserve, который держит правую колонку). */
@media (min-width: 721px) and (max-width: 880px) {
  body.inGame #eventToasts {
    bottom: calc(12px + var(--sa-bottom) + var(--right-bottom-reserve, 80px));
  }
}

/* Правая колонка на 721..900px уходит ПОД верхнюю полосу, и её смещение было
   зашито константой 104px, рассчитанной на прежнюю высоту полосы. Полоса
   перестроена и на 768px занимает 107px — колонка налезала на неё на 3px.
   Берём запас: 120px покрывает полосу и в две строки. */
@media (max-width: 900px) {
  :root {
    --right-top: calc(12px + var(--sa-top) + 128px);
  }

  #rightSidebar {
    top: var(--right-top);
  }
}

/* --- Магазин на широком экране: разделители тиров и двойная прокрутка ------
   Замер 1920x1080. Лента предметов переключается в две колонки с 1180px, и
   разделители тиров («База», «Обычный», «Редкий»…) оказывались обычными
   ячейками сетки наравне с карточками. Порядок ломался так:

       [База]      [Заливка]
       [Обычный]   [Штриховка]
       [Соты]      [Редкий]     <- карточка слева, разделитель СПРАВА
       [Прилив]    [Схема]

   «Редкий» стоял рядом с «Сотами» обычного тира и не разделял ничего.
   Разделитель обязан занимать всю строку — тогда он снова заголовок группы. */
.cosmeticsItems > .cosmeticsTierSep {
  grid-column: 1 / -1;
}

/* Вторая половина: на 1080p скроллилась и карточка оверлея, и лента внутри
   неё — два вложенных скроллбара на одном экране. Причина — у ленты стоял
   свой потолок высоты, не связанный с высотой карточки, и сумма частей
   вылезала за неё на 36px.
   Делаем карточку и левую панель флекс-колонками: лента забирает ровно
   остаток и скроллится ОДНА, а фильтры и вкладки категорий остаются на
   месте — ради этого потолок и вводился. */
@media (min-width: 1180px) {
  #cosmeticsOverlay .card {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    /* height:auto делает главный размер флекс-контейнера неопределённым —
       flex-grow тогда считается от содержимого, а не от остатка места, и
       .cosmeticsItems сжимается до пары карточек вместо того, чтобы забрать
       остаток колонки. Фиксируем ту же высоту, что даёт max-height выше,
       чтобы flex: 1 1 auto у ленты считался от реального остатка. */
    height: calc(100dvh - 24px - var(--sa-top) - var(--sa-bottom));
  }

  #cosmeticsOverlay .cosmeticsGrid {
    flex: 1 1 auto;
    min-height: 0;
    /* Базовое правило ставит align-items: start — колонки прижимались к
       верху и не получали высоту, поэтому ограничить ленту было нечем и
       переполнялась сама карточка. Растягиваем колонки на всю высоту. */
    align-items: stretch;
  }

  #cosmeticsOverlay .cosmeticsGrid > .menuPanel {
    display: flex;
    flex-direction: column;
    min-height: 0;
  }

  #cosmeticsOverlay .cosmeticsItems {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
    overflow-y: auto;
  }

  /* На минимальном десктопном вьюпорте (1280x720) пять статичных блоков
     над лентой (шапка, статус-баннер, полоса «Стиль», подсказка ✨, вкладки
     редкости и категорий) съедают почти весь бюджет высоты левой панели —
     ленте оставалось ~110px, меньше одной карточки товара. Сокращаем
     вертикальные отступы между блоками и внутри баннеров: свободного места
     это не прибавляет, но отдаёт его ленте вместо межблочных зазоров. */
  #cosmeticsOverlay .cosmeticsStatus,
  #cosmeticsOverlay .cosmeticsStoreBar,
  #cosmeticsOverlay .cosmeticsEarnStyle,
  #cosmeticsOverlay .cosmeticsTabs,
  #cosmeticsOverlay .cosmeticsWhere {
    margin-top: 6px;
  }

  #cosmeticsOverlay .cosmeticsStatus {
    padding: 6px 10px;
  }

  #cosmeticsOverlay .cosmeticsEarnStyle {
    padding: 6px 10px;
  }

  /* Превью прижато к верху своей колонки: растягивать канвас на всю высоту
     незачем, у него фиксированная пропорция. */
  #cosmeticsOverlay .cosmeticsGrid > .menuPanel:last-child {
    align-self: start;
  }
}

/* iter-10 (docs/reviews/iter-10.md, #5): на 1280×720 сокращения отступов выше
   отдавали ленте 110px -> 138px — меньше двух рядов карточек. Дальше
   резервов у межблочных зазоров нет, дело в самой высоте вьюпорта: на более
   высоких десктопных окнах той же ширины (>760px) блок выше уже не нужен —
   вертикального места хватает и без него. Отдельный брейкпоинт по высоте, а
   не по ширине: снимаем рамку/фон у баннера «Стиль» (оставляем текст) —
   это тот статичный блок, что несёт наименьшую функциональную нагрузку
   (прогресс уже дублирован полосой «Стиль: N» в шапке), поэтому именно его
   схлопываем первым, а не режем реальные элементы управления. */
@media (min-width: 1180px) and (max-height: 760px) {
  #cosmeticsOverlay .cosmeticsEarnStyle {
    padding: 2px 0;
    border: none;
    background: none;
  }

  #cosmeticsOverlay .cosmeticsStatus:empty {
    margin-top: 0;
  }
}

/* --- Экран смерти: парный к экрану итогов ----------------------------------
   Красный здесь по правилу волны 9 (он остаётся только опасности и смерти).
   Разметка теперь буквально .matchCard (см. public/index.html) — экран
   смерти использует те же компоненты, что и итоги матча (.matchKpiGrid,
   .matchMiniGrid, .matchTable), просто на опасном цвете вместо бренда. */
.deathOverlay.matchCard {
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border2));
  background: linear-gradient(150deg, color-mix(in srgb, var(--accent) 12%, transparent), rgba(5, 9, 16, 0.92));
}

/* Липкий ряд действий стоял на своей тёмной подложке, не связанной с
   карточкой, — на новом фоне он выглядел вставкой. */
.deathOverlay .matchActions {
  background: rgba(5, 9, 16, 0.94);
}

/* ==========================================================================
   ВОЛНА 11. Полноценный редизайн экрана итогов матча.
   Прошлый заход свёл ровно один токен рамки .matchCard без визуальных
   изменений — намеренно консервативно. Здесь — настоящий редизайн: бейдж
   результата становится героем экрана, KPI/мини-карточки получают глубину
   в духе .cosmeticsItem, таблица топ-игроков — собранный контейнер.
   ========================================================================== */

/* --- Бейдж результата: было — мелкая плоская таблетка вверху блока,
   стало — крупный акцентный заголовок экрана, как у .btnPlay для победы. */
.matchSummaryTop {
  justify-content: center;
  margin-bottom: var(--pad-lg);
}

.matchResultPill {
  padding: 10px 28px;
  border-radius: var(--r-lg);
  font-size: var(--fs-title);
  letter-spacing: 0.6px;
  border: 1px solid color-mix(in srgb, var(--brand) 65%, transparent);
  background: rgba(0, 0, 0, 0.22);
}

.matchResultWin {
  background: linear-gradient(135deg, var(--brand), var(--brand2));
  color: #03130c;
  box-shadow: var(--btn-play-shadow);
}

/* Поражение — та же героика, что у победы (типографика, радиус, сила тени),
   но исключительно на --accent: это единственный экран, где красный вообще
   уместен по правилу волны 9 (см. комментарий вверху файла), и он обязан
   читаться так же уверенно, как изумрудный градиент .matchResultWin, а не
   тускнеть до нейтральной таблетки. */
.matchResultLose {
  border-color: color-mix(in srgb, var(--accent) 70%, transparent);
  background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #1a0510));
  color: #fff;
  box-shadow: 0 12px 36px color-mix(in srgb, var(--accent) 35%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.25);
}

/* --- KPI-карточки (место, очки): главные цифры экрана — приподнимаем их
   над остальными мини-карточками градиентной подложкой и бренд-рамкой,
   тем же приёмом, что и .cosmeticsItem.isSelected/.menuPanelPrimary. */
.matchKpi {
  position: relative;
  border-color: color-mix(in srgb, var(--brand2) 30%, var(--border2));
  background:
    radial-gradient(140% 160% at 0% 0%, color-mix(in srgb, var(--brand2) 12%, transparent), transparent 65%),
    rgba(255, 255, 255, 0.02);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}

.matchKpiValue {
  color: var(--text);
}

/* --- Мини-карточки статистики: та же плотная сетка, что у карточек
   магазина, но приглушённее KPI — вторичная информация, не героика. */
.matchMini {
  border-color: rgba(255, 255, 255, 0.08);
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.03), rgba(0, 0, 0, 0.18));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

.matchMiniReward {
  border-color: color-mix(in srgb, var(--gold) 45%, var(--border2));
  background: linear-gradient(160deg, color-mix(in srgb, var(--gold) 14%, transparent), rgba(0, 0, 0, 0.18));
}

/* --- Таблица топ-игроков: собранный контейнер со своей глубиной,
   парный к .matchSummary, а не отдельная плоская врезка. */
.matchTableWrap {
  border-color: rgba(255, 255, 255, 0.08);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(0, 0, 0, 0.22));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
}

.matchTable thead th {
  background: rgba(5, 9, 16, 0.55);
}

/* ==========================================================================
   ВОЛНА 12. Фокус игрового экрана.
   Ревью живого матча (1920×1080): восемь панелей одинаковой яркости — глазу
   не за что зацепиться. Иерархия задана явно: одна акцентная сущность —
   верхняя полоса (место, время, текущая миссия), всё остальное на ступень
   тише. Блок идёт последним и перекрывает ранние правила порядком.
   ========================================================================== */

/* --- Верхняя полоса: миссия — акцентный чип ---------------------------------
   Контракт — единственная «что делать прямо сейчас» сущность на экране, а
   стоял серым текстом в конце строки. Теперь это бренд-чип с собственной
   рамкой; фаза матча рядом, наоборот, приглушена — она информирует, а не
   зовёт к действию. */
.topHudContract .topHudChip {
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--brand) 55%, transparent);
  background: linear-gradient(135deg, color-mix(in srgb, var(--brand) 22%, transparent), color-mix(in srgb, var(--brand2) 12%, transparent));
  color: #f4fffb;
  font-weight: 800;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--brand) 12%, transparent), 0 6px 18px color-mix(in srgb, var(--brand) 18%, transparent);
}

.topHudContract .topHudChip.hidden {
  display: none;
}

#topHudPhase.topHudChip {
  opacity: 0.72;
}

#topHudPhase.topHudChip.isFinal {
  opacity: 1;
}

/* --- Правая колонка: вторичный слой ---------------------------------------
   Шапки панелей (цвет — в 08-game-sidebar.css) и лента событий тише полосы:
   ниже непрозрачность чужих строк. Свои события остаются полными — это единственное,
   на что здесь стоит смотреть боковым зрением. */
#rightInfo #killfeed .killLine.killLineOther,
#rightInfo #killfeed .killLine:not(.killLineMine) {
  opacity: 0.78;
}

#rightInfo #killfeed .killLine.killLineMine {
  opacity: 1;
}

/* Лента — четыре последних строки: пятая-шестая уже история, а не события. */
#rightInfo #killfeed {
  max-height: var(--killfeed-max, 132px);
}

/* Технический счётчик FPS/пинга — самый тихий текст экрана. */
#rightSidebar #perf {
  opacity: 0.6;
}

#rightSidebar #perf:hover {
  opacity: 1;
}

/* Ряд действий на экранах смерти и итогов: настройки — иконка справа от
   основных кнопок, а не третья равноправная кнопка. */
.matchActions > .iconBtn {
  flex: 0 0 auto;
  margin-left: auto;
}

/* Футер меню: настройки и язык стоят рядом у правого края, а не по разным
   углам (margin-left: auto у языка задан в 02-cosmetics.css для футера
   настроек, где он один). */
.menuFooterActions > .langToggle {
  margin-left: 0;
}

/* --- Подсказка управления гаснет через 25 с матча (client_hud.js) --------- */
body.inGame #help.helpFade {
  opacity: 0;
  pointer-events: none;
}

/* Комбо-чип «⚔ N ×M» делил левый нижний угол с подсказкой и наезжал на неё:
   поднимаем чип над строкой подсказки. */
body.inGame #hudCombo {
  bottom: calc(12px + var(--sa-bottom) + 40px);
}

/* Легенда миникарты лежала ПОВЕРХ карты и закрывала её левый нижний угол —
   теперь стоит строкой под канвасом. */
#minimapPanel {
  display: grid;
  gap: 6px;
}

#minimapPanel .minimapLegend {
  position: static;
  grid-template-columns: repeat(3, auto);
  justify-content: start;
  gap: 4px 12px;
  padding: 4px 8px;
  border: none;
  background: transparent;
  backdrop-filter: none;
}

/* Полоса состояния читается поверх любой территории: подложка темнее и
   непрозрачнее общей панели — на розовой/жёлтой заливке белый текст падал
   ниже AA. */
#topHud {
  background: rgba(6, 10, 18, 0.9);
}

/* Один язык карточек. Строки ленты, чипы и тосты сводятся к одной форме:
   радиус --r-md, тонкая рамка --border2, без декоративной скобки слева у
   событий. Свои события отмечает только цвет фона, а не отдельная полоса. */
.killLine {
  border-left-width: 1px;
  border-left-color: var(--border2);
}

.killLine.killLineMine {
  border-color: color-mix(in srgb, var(--brand) 40%, var(--border2));
}

.killLine.killLineOther {
  border-left-color: var(--border2);
}

/* Меньше капса, крупнее подписи: шапки правой колонки и заголовки таблиц —
   обычный регистр и кегль тела; колонки таблицы лидеров — 13px вместо 11. */
.metaGoalsTitle,
.metaWalletLabel {
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--fs-meta-lg);
}

#stats,
#stats td,
#stats th,
.teamTable td,
.teamTable th {
  font-size: var(--fs-meta-lg);
}

/* На высоком экране правая колонка обрывалась на ~60% высоты — лента событий
   не растёт под контент. Отдаём ей остаток колонки: до 12 строк по высоте. */
@media (min-height: 1000px) {
  #rightInfo > #rightEventsDetails {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  #rightInfo #killfeed {
    max-height: min(40dvh, 420px);
  }
}

/* --- Тач-устройства: HUD не размывает поле -------------------------------
   backdrop-filter поверх канваса, который перерисовывается каждый кадр, —
   худшее, что можно попросить у мобильного GPU: слой под панелью объявляется
   грязным на каждом кадре игры, и размытие считается заново 60 раз в секунду.
   Во время матча над полем постоянно висят шесть таких панелей (#topHud,
   #chat, #metaHud, .rightDetails, четыре-пять .iconBtn, #helpTouch), и ни
   один медиазапрос их не гасил: мобильные блоки снимали размытие только с
   #hud, а на тач-устройствах 10-ux-waves.css его ещё и ДОБАВЛЯЛ кнопкам.

   Признак — pointer: coarse, а не ширина экрана: дело в классе устройства, а
   не в вьюпорте, и в ландшафте телефон шире 720px, оставаясь телефоном.
   Панели становятся непрозрачными: размытие держало читаемость текста над
   пёстрым полем, и без замены подложки её терять нельзя. */
@media (pointer: coarse) {
  body.inGame #topHud,
  body.inGame #chat,
  body.inGame #metaHud,
  body.inGame #rightInfo .rightDetails,
  body.inGame #helpTouch,
  body.inGame .hudActions .iconBtn,
  body.inGame #hud:not(.lbPinned) .hudActions .iconBtn {
    background: var(--panel-solid);
    backdrop-filter: none;
  }

  /* Тень с радиусом 28px по краю каждой панели — второй слой композитинга
     поверх того же движущегося канваса. На неподвижном фоне она бесплатна, над
     полем — нет, а её роль (отделить панель от фона) уже выполняет
     непрозрачная подложка. */
  body.inGame #topHud,
  body.inGame #chat,
  body.inGame #rightInfo .rightDetails,
  body.inGame .hudActions .iconBtn,
  body.inGame #hud:not(.lbPinned) .hudActions .iconBtn {
    box-shadow: none;
  }
}
