/*
 * ЕДИНЫЙ ИСТОЧНИК ПРАВДЫ для стекла и цветовой темы UnitVR.
 * Все компоненты используют ТОЛЬКО эти CSS-переменные — никогда не хардкодят свои
 * rgba/blur/box-shadow значения локально. Правка стиля стекла = правка ЭТОГО файла,
 * изменение расходится по всему приложению автоматически (прямое требование Михаила, С151).
 *
 * История: рецепт менялся дважды за ночь С151 (см. reference-glass-canon-2026 в памяти
 * агента) — сначала окантовка/просвечивание были неверными, затем плотность 0.42 давала
 * либо тусклость, либо жёсткую окантовку при попытке компенсировать. Текущие значения —
 * финальные, подтверждённые Михаилом визуально на попапе поддержки.
 */

:root[data-theme="dark"] {
  --fg: #eceef2;
  --fg-dim: #a8abbc;
  --fg-mute: #7c8096;

  --scene:
    radial-gradient(circle at 78% -8%, rgba(255, 154, 77, .32), transparent 46%),
    radial-gradient(circle at 15% 108%, rgba(90, 140, 255, .24), transparent 46%),
    linear-gradient(160deg, #1c1408 0%, #0d0e14 55%, #08090e 100%);

  /* ===== ГЛАВНЫЕ ТОКЕНЫ СТЕКЛА (менять ТОЛЬКО здесь) ===== */
  --glass-bg: rgba(18, 18, 21, .72);
  --glass-img: linear-gradient(160deg, rgba(255, 255, 255, .05) 0%, rgba(255, 255, 255, .015) 40%, rgba(255, 255, 255, 0) 100%);
  --glass-blur: blur(30px) saturate(140%) brightness(1.0);
  --glass-shadow: inset 0 1px 0 rgba(255, 255, 255, .08), 0 8px 24px rgba(0, 0, 0, .32);
  --glass-radius: 18px;

  /* плотнее вариант для мелких элементов (тайлы игр, карточки шлемов) */
  --glass-tile-bg: rgba(20, 20, 24, .5);
  --glass-tile-blur: blur(18px) saturate(150%) brightness(1.02);
  /* С152 (3-й проход): раньше только верхний блик 1px — окантовка "исчезала" книзу
     карточки. inset 0 0 0 1px даёт РАВНОМЕРНЫЙ тонкий контур по всему периметру. */
  --glass-tile-shadow: inset 0 0 0 1px rgba(255, 255, 255, .1), 0 5px 14px rgba(0, 0, 0, .24);
  --gfoot-gradient: linear-gradient(90deg, rgba(255,255,255,.14) 0%, rgba(255,255,255,.26) 50%, rgba(255,255,255,.14) 100%);

  --glass-helm-bg: rgba(20, 20, 24, .48);
  --glass-helm-active-bg: rgba(38, 32, 26, .62);
  /* С152: контур 1.5px (было 1px — слишком тонко, читалось как "срезанное" рядом с
     несимметричной внешней тенью 0 5px). Внешняя тень заменена на симметричную
     0 0 14px, чтобы не создавать ложное ощущение перекоса выделенной карточки. */
  --glass-helm-active-shadow: inset 0 1px 0 rgba(255, 255, 255, .12), 0 0 0 1.5px rgba(255, 154, 77, .55), 0 0 14px rgba(0, 0, 0, .22);

  /* окантовка попап-окон (поддержка/тариф/трансляция), С152 (3-й проход). История:
     0.86+blur(6px на оверлее) убило матовость (двойной конфликт backdrop-filter);
     откат на 0.45 оказался СЛИШКОМ слабым — "плохо видно саму рамку стекла и текст на
     ней" (Михаил). Средний баланс: плотность 0.62 (между крайностями), blur чуть выше,
     чтобы текст лучше читался поверх стекла, окантовка (нижняя тень) усилена — теперь
     рамка визуально отделяется от фона сама по себе, не полагаясь только на оверлей. */
  --glass-sup-bg: rgba(16, 16, 20, .62);
  --glass-sup-blur: blur(22px) saturate(160%) brightness(1.05);
  --glass-sup-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), 0 12px 32px rgba(0, 0, 0, .5);
  --sup-panel-bg: rgba(255, 255, 255, .96);
  --sup-panel-fg: #16171c;
  --sup-panel-fg-dim: #6b6d78;

  /* контейнер-обёртка правой колонки (KPI+таймер+библиотека) — один большой кусок
     тёмного стекла, внутри которого лежат светло-серые вставки (см. --inset-*) */
  --main-panel-bg: rgba(16, 16, 20, .58);
  --main-panel-blur: blur(28px) saturate(150%) brightness(1.0);
  --main-panel-shadow: inset 0 1px 0 rgba(255, 255, 255, .07), 0 8px 24px rgba(0, 0, 0, .3);
  --inset-bg: rgba(255, 255, 255, .045);
  --inset-border: rgba(255, 255, 255, .09);

  /* капсула подписи под обложкой игры (С152) — заметно светлее .inset-bg, ближе к
     референсу Stardog: явная светлая плашка, а не тонкая подложка того же тона */
  --gfoot-bg: rgba(255, 255, 255, .12);
  --gfoot-border: rgba(255, 255, 255, .16);

  /* С152: оверлей под модалками слегка размывает сцену за окном (Михаил — «попап теряется
     на фоне большого числа обложек игр»). ⚠️ Первая попытка (0.32 + blur 6px) в СУММЕ с
     поднятой плотностью самой панели убила матовость целиком — стекло перестало
     просвечивать. Плотность панели вернул к 0.72 (см. --glass-sup-bg), поэтому здесь
     оставляю МЯГКИЙ вариант: blur всего 3px, затемнение чуть выше исходного 0.18 — этого
     достаточно, чтобы окно отделялось от фона, но сцена всё ещё видна сквозь стекло. */
  --overlay-bg: rgba(8, 9, 16, .24);
  --overlay-blur: blur(3px);

  --chip: rgba(10, 10, 14, .45);
  --accent: #ff9a4d;
  --accent2: #e8834a;
  --accent-fg: #1a1410;
  --ok: #7ee6a0;
  --warn: #ffd180;
  --bad: #ff9fac;
}

:root[data-theme="light"] {
  --fg: #eef0f4;
  --fg-dim: #c2c7d2;
  --fg-mute: #9aa0ad;

  --scene:
    radial-gradient(circle at 72% 18%, rgba(210, 160, 110, .16), transparent 34%),
    radial-gradient(circle at 24% 30%, rgba(150, 175, 205, .14), transparent 40%),
    radial-gradient(circle at 88% 78%, rgba(120, 140, 170, .12), transparent 42%),
    radial-gradient(circle at 40% 95%, rgba(190, 150, 110, .10), transparent 38%),
    linear-gradient(155deg, #2a2e36 0%, #1c1f26 45%, #14161c 100%);

  --glass-bg: rgba(50, 54, 62, .58);
  --glass-img: linear-gradient(150deg, rgba(255, 255, 255, .09) 0%, rgba(255, 255, 255, .02) 42%, rgba(0, 0, 0, .03) 100%);
  --glass-blur: blur(26px) saturate(110%) brightness(1.0);
  --glass-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 10px 28px rgba(0, 0, 0, .22);
  --glass-radius: 18px;

  --glass-tile-bg: rgba(46, 50, 58, .5);
  --glass-tile-blur: blur(18px) saturate(105%) brightness(1.0);
  --glass-tile-shadow: inset 0 0 0 1px rgba(255, 255, 255, .12), 0 6px 18px rgba(0, 0, 0, .18);
  --gfoot-gradient: linear-gradient(90deg, rgba(255,255,255,.18) 0%, rgba(255,255,255,.3) 50%, rgba(255,255,255,.18) 100%);

  --glass-helm-bg: rgba(46, 50, 58, .46);
  --glass-helm-active-bg: rgba(58, 62, 72, .6);
  --glass-helm-active-shadow: inset 0 1px 0 rgba(255, 255, 255, .16), 0 0 0 1.5px rgba(255, 255, 255, .2), 0 0 16px rgba(0, 0, 0, .16);

  --glass-sup-bg: rgba(50, 54, 62, .58);
  --glass-sup-blur: blur(20px) saturate(130%) brightness(1.05);
  --glass-sup-shadow: inset 0 1px 0 rgba(255, 255, 255, .12), 0 10px 28px rgba(0, 0, 0, .3);
  --sup-panel-bg: rgba(255, 255, 255, .97);
  --sup-panel-fg: #16171c;
  --sup-panel-fg-dim: #6b6d78;

  --main-panel-bg: rgba(40, 44, 52, .5);
  --main-panel-blur: blur(26px) saturate(120%) brightness(1.0);
  --main-panel-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 8px 22px rgba(0, 0, 0, .22);
  --inset-bg: rgba(255, 255, 255, .06);
  --inset-border: rgba(255, 255, 255, .12);
  --gfoot-bg: rgba(255, 255, 255, .16);
  --gfoot-border: rgba(255, 255, 255, .2);

  --overlay-bg: rgba(8, 9, 16, .24);
  --overlay-blur: blur(3px);

  --chip: rgba(10, 10, 14, .35);
  --accent: #ff9a4d;
  --accent2: #e8834a;
  --accent-fg: #1a1410;
  --ok: #7ee6a0;
  --warn: #ffd180;
  --bad: #ff9fac;
}

/* ===== БАЗОВЫЙ КЛАСС СТЕКЛА (используется всеми .glass-панелями) ===== */
.glass {
  position: relative;
  border-radius: var(--glass-radius);
  background-color: var(--glass-bg);
  background-image: var(--glass-img);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid transparent;
  background-clip: padding-box;
  box-shadow: var(--glass-shadow);
}

.glass-tile {
  background-color: var(--glass-tile-bg);
  backdrop-filter: var(--glass-tile-blur);
  -webkit-backdrop-filter: var(--glass-tile-blur);
  box-shadow: var(--glass-tile-shadow);
}

/* стекло попапа техподдержки — плотнее .glass (см. --glass-sup-* выше) */
.glass-sup {
  position: relative;
  border-radius: var(--glass-radius);
  background-color: var(--glass-sup-bg);
  backdrop-filter: var(--glass-sup-blur);
  -webkit-backdrop-filter: var(--glass-sup-blur);
  border: 1px solid transparent;
  background-clip: padding-box;
  box-shadow: var(--glass-sup-shadow);
}

/* контейнер-обёртка правой колонки — один большой кусок тёмного стекла (С152) */
.main-panel {
  position: relative;
  border-radius: var(--glass-radius);
  background-color: var(--main-panel-bg);
  backdrop-filter: var(--main-panel-blur);
  -webkit-backdrop-filter: var(--main-panel-blur);
  box-shadow: var(--main-panel-shadow);
}

/* С152: светло-серые вставки внутри тёмного стекла (по образцу референса Stardog —
   большая тёмная стеклянная область, внутри которой лежат светлые под-панели с мягкой
   серой окантовкой). Используется для таймера/библиотеки игр внутри .main-panel. */
.inset-panel {
  border-radius: 16px;
  background: var(--inset-bg);
  border: 1px solid var(--inset-border);
}
/* компактные чипы-теги (по образцу «Seekingalpha/CNBC» на референсе) для KPI */
.chip-tag {
  border-radius: 100px;
  background: var(--inset-bg);
  border: 1px solid var(--inset-border);
}

/* grain — то, что отличает матовое стекло от чистого (см. reference-glass-canon-2026) */
.grain::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: .025;
  mix-blend-mode: overlay;
  z-index: 3;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.75' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body, #root { height: 100%; margin: 0; overflow: hidden; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-weight: 300;
  color: var(--fg);
  background: var(--scene);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
}
.hidden { display: none !important; }

/* ================= LOGIN ================= */
/* С152: медленный "дышащий" перелив фоновой сцены на экране логина (Михаил — "чтобы
   градиент медленно перетекал, не так быстро, как надпись"). Только .login-screen — общий
   .scene в приложении не трогаем, чтобы не анимировать фон везде. Два радиальных пятна
   плавно меняют позицию через отдельный слой поверх статичного --scene. */
.login-screen { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; background: var(--scene); overflow: hidden; }
.login-screen::before {
  content: ""; position: absolute; inset: -35%; z-index: 0; pointer-events: none;
  background:
    radial-gradient(circle at 78% -8%, rgba(255, 154, 77, .38), transparent 40%),
    radial-gradient(circle at 15% 108%, rgba(90, 140, 255, .3), transparent 40%);
  animation: login-scene-drift 14s ease-in-out infinite alternate;
}
.login-screen .login-card { position: relative; z-index: 1; }
@keyframes login-scene-drift {
  0% { transform: translate(-10%, -8%) scale(1); }
  50% { transform: translate(8%, 10%) scale(1.15); }
  100% { transform: translate(-6%, 12%) scale(1.08); }
}
/* Карточка логина НЕ использует общий .glass — тот честно просвечивает сцену, а на экране
   входа сцена анимированная и асимметричная (тёплое пятно сверху-справа, холодное снизу-слева,
   плюс тёмный линейный градиент к низу), из-за чего полупрозрачная карточка получала бы
   разную яркость по углам и визуально "таяла" книзу. Михаил явно попросил вместо этого ровную
   матовую поверхность без просвечивания — плотность почти непрозрачная (.97), матовость только
   через зерно и лёгкий верхний блик, не через backdrop-filter по сцене. */
.login-card {
  width: min(320px, 90vw); padding: 28px 26px; display: flex; flex-direction: column; gap: 12px;
  position: relative;
  border-radius: var(--glass-radius);
  background-color: rgba(20, 20, 24, .97);
  background-image: linear-gradient(160deg, rgba(255, 255, 255, .05) 0%, rgba(255, 255, 255, .015) 40%, rgba(255, 255, 255, 0) 100%);
  border: 1px solid transparent;
  background-clip: padding-box;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .06), inset 0 1px 0 rgba(255, 255, 255, .08), 0 20px 50px rgba(0, 0, 0, .45);
}

/* С152 (3-й проход): фоновая петля убрана совсем — на карточке такого размера крупная
   петля не помещалась и наезжала на поля логина/пароля (Михаил проверил вживую). Осталась
   только надпись UnitVR по центру, "VR" жирнее "Unit". Направление перелива слева→направо
   (было наоборот — background-position рос в ту же сторону, что и сам градиент, из-за
   чего визуально цвет "приезжал" с противоположной стороны). */
.login-brand { display: flex; align-items: center; justify-content: center; margin-bottom: 22px; }
.login-title {
  font-size: 30px; font-weight: 500; letter-spacing: -.01em;
  background: linear-gradient(90deg, #ff9a4d 0%, #e8834a 25%, #5a8cff 50%, #ff9a4d 75%, #e8834a 100%);
  background-size: 300% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: login-shine 5s linear infinite;
}
.login-title b { font-weight: 800; }
@keyframes login-shine {
  0% { background-position: 300% 50%; }
  100% { background-position: 0% 50%; }
}
.login-input {
  background: var(--chip); border: 1px solid rgba(255, 255, 255, .08); border-radius: 10px; padding: 12px 14px; font-size: 14px;
  color: var(--fg); outline: none; font-family: inherit; font-weight: 300; width: 100%;
  transition: border-color .2s;
}
.login-input:focus { border-color: rgba(255, 154, 77, .4); }
.login-error { color: var(--bad); font-size: 12px; min-height: 16px; }

.login-password-field { position: relative; }
.login-password-field .login-input { padding-right: 40px; }
.login-password-toggle {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;
  background: none; border: none; border-radius: 8px; font-size: 15px; cursor: pointer;
  opacity: .65; transition: opacity .15s, background .15s;
}
.login-password-toggle:hover { opacity: 1; background: rgba(255, 255, 255, .06); }

/* ================= LAYOUT ================= */
#app {
  position: fixed; inset: 0; display: grid; grid-template-columns: 292px 1fr; gap: 14px; padding: 14px;
  padding-top: max(14px, env(safe-area-inset-top)); padding-bottom: max(14px, env(safe-area-inset-bottom));
  padding-left: max(14px, env(safe-area-inset-left)); padding-right: max(14px, env(safe-area-inset-right));
  transition: grid-template-columns .3s cubic-bezier(.4, 0, .2, 1);
}
#app.collapsed { grid-template-columns: 0px 1fr; }
.col-l { display: flex; flex-direction: column; gap: 10px; min-height: 0; overflow: hidden; }
.col-r { display: flex; flex-direction: column; gap: 12px; min-height: 0; min-width: 0; }
/* С152: левая колонка — тот же приём, что .main-panel справа: ОДИН большой кусок тёмного
   стекла (Михаил — "справа явно единый крупный блок с текстурой, слева карточки как будто
   сливаются со сценой без разделения"), внутри него карточки шлемов теперь светлые вставки. */
.main-panel-l { flex: 1; min-height: 0; padding: 8px; display: flex; flex-direction: column; gap: 8px; }
/* С152: кнопка добавления шлема — ВСЕГДА закреплена сверху, вне скролла карточек
   (Михаил — "чтобы не искать её среди уже добавленных шлемов"), заметная пунктирная
   рамка отличает её от обычных карточек/кнопок. */
.add-helmet-btn {
  flex-shrink: 0; padding: 11px; border-radius: 12px; border: 1.5px dashed var(--inset-border);
  background: transparent; color: var(--fg-dim); font-size: 13px; font-weight: 600;
  cursor: pointer; transition: border-color .2s, color .2s, background .2s;
}
.add-helmet-btn:hover, .add-helmet-btn:active { border-color: var(--accent); color: var(--accent); background: rgba(255, 154, 77, .06); }

/* С152 (2-й проход): реальный отступ до ТЕКСТА внутри карточки шлема — это СУММА всех
   вложенных padding: .main-panel-l (8px) + #helmScroll (2px) + .helm (13px) = 23px,
   а не только последний. Первая попытка (11px) выравнивала по краю .helm, а не по тексту
   внутри неё — логотип оказался левее, чем нужно. */
.brandbar { display: flex; align-items: center; gap: 9px; padding: 2px 4px 2px 23px; flex-shrink: 0; }
.brand { font-size: 15px; font-weight: 400; display: flex; align-items: center; gap: 8px; }
/* С152 (2-й проход): индикатор связи с сервером переехал в правую панель, рядом с
   Обновить/Поддержка/Запчасти (Михаил — "не загромождать левую панель"), явным текстовым
   бейджем вместо голой точки. */
.conn-badge {
  display: inline-flex; align-items: center; gap: 6px; padding: 9px 14px; border-radius: 100px;
  font-size: 11px; font-weight: 500; white-space: nowrap;
}
.conn-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.conn-online { background: rgba(126, 230, 160, .12); border: 1px solid rgba(126, 230, 160, .3); color: var(--ok); }
.conn-online .conn-dot { background: var(--ok); box-shadow: 0 0 6px var(--ok); }
.conn-offline { background: rgba(255, 159, 172, .12); border: 1px solid rgba(255, 159, 172, .3); color: var(--bad); }
.conn-offline .conn-dot { background: var(--bad); box-shadow: 0 0 6px var(--bad); }
/* С152: фирменный лого в шапке приложения — тот же градиентный перелив, что на экране
   логина, но МЯГЧЕ и МЕДЛЕННЕЕ (Михаил: "не такой быстрый, пусть потихонечку переливается"). */
.brand-title {
  font-size: 15px; font-weight: 500; letter-spacing: -.005em;
  background: linear-gradient(90deg, #ff9a4d 0%, #e8834a 25%, #5a8cff 50%, #ff9a4d 75%, #e8834a 100%);
  background-size: 300% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: login-shine 14s linear infinite;
}
.brand-title b { font-weight: 800; }
.icon-btn {
  width: 30px; height: 30px; border-radius: 10px; border: none; background: var(--chip); color: var(--fg-dim);
  font-size: 13px; display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0;
  transition: background .2s, color .2s;
}
.icon-btn:active { transform: scale(.94); }

/* С152: меню режима (Клуб/Выезды) переехало из топбара в шестерёнку слева — временный
   переключатель на период разработки, не должен быть виден в "финальном" виде клубной
   версии, пока Михаил смотрит именно её дизайн. */
.dev-menu { position: absolute; top: 38px; right: 0; z-index: 30; padding: 10px; width: 180px; display: flex; flex-direction: column; gap: 8px; }
.dev-menu-label { font-size: 9.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--fg-dim); margin-top: 4px; }
.dev-menu .mode-switcher { display: flex; flex-direction: column; gap: 6px; }
.dev-menu-theme { width: 100%; height: auto; border-radius: 8px; padding: 7px 10px; font-size: 12px; gap: 6px; justify-content: flex-start; }

/* кнопка "Обновить" видна ТОЛЬКО когда обновление реально готово — сама её видимость уже
   индикатор, отдельная точка избыточна (Михаил заметил) */
.pill-update-ready {
  background: rgba(126, 230, 160, .12);
  color: var(--ok);
  border: 1px solid rgba(126, 230, 160, .3);
}
.bell-shake { display: inline-block; animation: bell-shake 1.6s ease-in-out infinite; transform-origin: 50% 0; }
@keyframes bell-shake {
  0%, 74%, 100% { transform: rotate(0); }
  76% { transform: rotate(-14deg); }
  78% { transform: rotate(11deg); }
  80% { transform: rotate(-8deg); }
  82% { transform: rotate(5deg); }
  84% { transform: rotate(-3deg); }
  86% { transform: rotate(0); }
}
@media (prefers-reduced-motion: reduce) { .bell-shake { animation: none; } }

/* С152: .col-l родитель имеет overflow:hidden (нужен для анимации схлопывания боковой
   панели) — он обрезал 1.5px-контур выделенной карточки слева и сверху у первой карточки
   в списке (некому перекрыть тень изнутри, обрезает именно внешний контейнер). Небольшой
   padding по всем сторонам даёт контуру место, не задевая сам скролл списка. Теперь этот
   запас даёт .main-panel-l (padding 8px) — здесь оставлен небольшой добавочный отступ. */
/* С152: #helmScroll оборачивает карточки в ДОПОЛНИТЕЛЬНЫЙ <div> (нужен Lenis-скроллу) —
   gap на #helmScroll ни на что не действовал, т.к. его единственный flex-ребёнок — этот
   wrapper-div, а не сами карточки. gap перенесён на wrapper, где реальные .helm — прямые
   дети (отсюда карточки визуально были "впритык" друг к другу без зазора). */
#helmScroll {
  flex: 1; min-height: 0; overflow-y: auto; padding: 2px;
  -webkit-overflow-scrolling: touch; scrollbar-width: none;
}
#helmScroll > div { display: flex; flex-direction: column; gap: 8px; }
#helmScroll::-webkit-scrollbar { display: none; }
/* С152: карточка шлема теперь светлая ВСТАВКА внутри общего тёмного .main-panel-l (было —
   собственное тёмное стекло того же тона, что фон сцены за панелью, отсюда "сливаются"). */
.helm {
  position: relative; border-radius: 14px; padding: 11px 13px; background: var(--inset-bg);
  border: 1px solid var(--inset-border);
  cursor: pointer; flex-shrink: 0; transition: background-color .25s, box-shadow .25s, transform .15s;
}
.helm:active { transform: scale(.985); }
/* С152: z-index — иначе следующая карточка в DOM-порядке рисуется ПОВЕРХ предыдущей
   (все .helm имеют position:relative, z-index:auto) и обрезает верхний/нижний край
   контура выделенной карточки на стыке — баг воспроизведён на скриншотах Михаила
   (окантовка "срезалась" то сверху, то снизу в зависимости от того, какая карточка
   выделена относительно соседей). */
.helm.sel { position: relative; z-index: 1; background-color: var(--glass-helm-active-bg); box-shadow: var(--glass-helm-active-shadow); }
.helm.mass-sel { position: relative; z-index: 1; background-color: var(--glass-helm-active-bg); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 0 0 1.5px var(--accent), 0 5px 14px rgba(0, 0, 0, .22); }
.helm-top { display: flex; align-items: center; gap: 8px; }
.mass-check { width: 16px; height: 16px; accent-color: var(--accent); flex-shrink: 0; }
/* С152: заголовок и статы (батарея/wifi/L/R) увеличены и утяжелены по прямой просьбе
   Михаила — на планшете в клубе мелкий текст плохо читается издалека. */
.helm-name { font-size: 15px; font-weight: 600; }
.helm-status { margin-left: auto; font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em; }
/* С152 (2-й проход): 4 иконки в ряд сливались визуально — wifi вынесен отдельным
   индикатором в правый верхний угол карточки (не про батарею, другая природа данных),
   батарея гарнитуры + оба контроллера остались одним рядом, иконки чуть крупнее. */
.helm-stats { display: flex; gap: 12px; margin-top: 8px; font-size: 12px; font-weight: 600; color: var(--fg-mute); }
.helm-stats span { display: inline-flex; align-items: center; gap: 4px; }
.helm-stats .w { color: var(--bad); }
/* С152 (3-й проход): абсолютное позиционирование накладывало wifi то на статус (верхний
   угол), то на таймер (нижний угол, где .helm-timer тоже margin-left:auto). Возврат в
   обычный поток — отдельная строка под .helm-top, выровненная по правому краю через
   margin-left:auto на самом span, ничего не перекрывает. */
.helm-wifi-row { display: flex; margin-top: 5px; }
.helm-wifi {
  margin-left: auto; display: inline-flex; align-items: center; gap: 3px;
  font-size: 10.5px; font-weight: 600; color: var(--fg-mute);
}
/* по образцу референса Fuselab — тонкие нарисованные line-icon вместо эмодзи для
   батареи гарнитуры/wifi/контроллеров (см. StatIcons.jsx). currentColor подхватывает и
   обычный приглушённый тон, и предупреждающий красный (.w) при низком заряде. */
.stat-icon { width: 13px; height: 13px; flex-shrink: 0; opacity: .85; }
.stat-icon-lg { width: 15px; height: 15px; }
.helm-bot { display: flex; align-items: center; margin-top: 8px; font-size: 10.5px; color: var(--fg-dim); gap: 6px; }
.helm-game { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.helm-timer { margin-left: auto; font-family: ui-monospace, monospace; font-size: 12px; color: var(--fg); font-variant-numeric: tabular-nums; }
/* С152: таймер краснеет в последние 5 минут сессии — администратор видит на глаз, что
   время клиента подходит к концу, не открывая карточку/не считая вручную. */
.helm-timer.low { color: var(--bad); font-weight: 700; }

.mass-bar { display: flex; align-items: center; gap: 8px; padding: 10px 4px 2px; flex-shrink: 0; }
.mass-bar span { font-size: 11px; color: var(--fg-dim); }

/* С152: правая колонка — один большой кусок тёмного стекла (.main-panel), внутри
   которого лежат светлые вставки (.inset-panel/.chip-tag) — образец референса Stardog */
.main-panel { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 12px; padding: 16px; }

.topbar { display: flex; align-items: center; gap: 10px; flex-shrink: 0; flex-wrap: wrap; }
.kpis { display: flex; gap: 8px; flex-wrap: wrap; }
.kpi.chip-tag { padding: 8px 16px; display: flex; align-items: baseline; gap: 7px; }
.kpi .l { font-size: 10px; color: var(--fg-dim); text-transform: uppercase; letter-spacing: .04em; }
.kpi .v { font-size: 14px; font-weight: 500; font-variant-numeric: tabular-nums; }
.topacts { display: flex; gap: 8px; flex-shrink: 0; margin-left: auto; }

.offline-badge {
  font-size: 11px; padding: 8px 14px; border-radius: 12px; background: rgba(255, 209, 128, .12);
  color: var(--warn); border: 1px solid rgba(255, 209, 128, .25); flex-shrink: 0;
}

.timer.inset-panel { padding: 16px 20px; display: flex; align-items: center; gap: 18px; flex-shrink: 0; }
.timer .t { font-family: ui-monospace, monospace; font-size: 36px; font-weight: 300; font-variant-numeric: tabular-nums; min-width: 130px; transition: color .3s; }
.timer .t.low { color: var(--bad); }
.timer .meta { font-size: 11.5px; color: var(--fg-dim); line-height: 1.5; }
.timer .sp { flex: 1; }
.timer .acts { display: flex; gap: 8px; }
.pill {
  font-size: 11px; padding: 9px 15px; border-radius: 100px; display: inline-flex; align-items: center; gap: 5px;
  white-space: nowrap; border: none; cursor: pointer; font-family: inherit; font-weight: 300; transition: transform .12s, filter .2s;
}
.pill:active { transform: scale(.95); }
.pill-dark { background: var(--chip); color: var(--fg); }
.pill-accent { background: linear-gradient(135deg, var(--accent), var(--accent2)); color: var(--accent-fg); font-weight: 500; }
/* С152: opacity на градиентной кнопке давал "полупрозрачный оранжевый, будто верстка
   сломалась" (Михаил). Явный серый фон вместо приглушённого акцента — понятнее читается
   как "неактивно", не как визуальный баг. */
.pill:disabled { background: var(--chip); color: var(--fg-mute); opacity: 1; cursor: default; }

.games.inset-panel { flex: 1; min-height: 0; padding: 14px 16px; display: flex; flex-direction: column; }
.games-head { display: flex; align-items: center; gap: 9px; margin-bottom: 11px; flex-wrap: wrap; flex-shrink: 0; }
.games-head h4 { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--fg-dim); margin: 0; white-space: nowrap; font-weight: 300; }
/* С152 (2-й проход): нативный <select> заменён на свой Dropdown — на Safari/WebKit
   внутренний текст select добавлял собственный отступ перед стрелкой независимо от CSS,
   зазор оставался неконтролируемо большим для длинных списков (жанры). Полностью свой
   рендер даёт точный контроль над отступами на всех браузерах одинаково. */
.dropdown { position: relative; }
.dropdown-btn {
  display: flex; align-items: center; gap: 8px; background: var(--chip); border: none; border-radius: 10px;
  padding: 7px 10px; font-size: 11.5px; color: var(--fg); cursor: pointer; font-family: inherit; font-weight: 300;
}
.dropdown-genre .dropdown-btn { width: 108px; }
.dropdown-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; text-align: left; }
.dropdown-arrow { width: 10px; height: 6px; flex-shrink: 0; color: var(--fg-mute); }
.dropdown-menu {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 40; min-width: 100%;
  padding: 6px; display: flex; flex-direction: column; gap: 2px; max-height: 240px; overflow-y: auto;
}
.dropdown-item {
  background: none; border: none; text-align: left; padding: 7px 10px; border-radius: 7px; font-size: 11.5px;
  color: var(--fg); cursor: pointer; font-family: inherit; font-weight: 300; white-space: nowrap;
}
.dropdown-item:hover { background: rgba(255, 255, 255, .06); }
.dropdown-item.active { color: var(--accent); font-weight: 600; }
.search { position: relative; margin-left: auto; width: 190px; }
.search input { width: 100%; background: var(--chip); border: none; border-radius: 10px; padding: 8px 10px 8px 29px; font-size: 11.5px; color: var(--fg); outline: none; font-family: inherit; font-weight: 300; }
.search .si { position: absolute; left: 9px; top: 50%; transform: translateY(-50%); font-size: 11px; opacity: .5; }

#gamesScroll { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; padding-right: 2px; }
#gamesScroll::-webkit-scrollbar { display: none; }
#ggrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(152px, 1fr)); gap: 16px; padding: 2px 2px 6px; }
/* С152: по образцу референса Stardog — карточка ЦЕЛИКОМ матовое стекло (padding даёт
   видимую окантовку вокруг картинки), обложка не размазана в край, подпись — отдельная
   светлая плашка внутри того же padding, не полоска во всю ширину. */
.gtile {
  position: relative; border-radius: 18px; background-color: var(--glass-tile-bg);
  backdrop-filter: var(--glass-tile-blur); -webkit-backdrop-filter: var(--glass-tile-blur); box-shadow: var(--glass-tile-shadow);
  cursor: pointer; transition: transform .15s, box-shadow .25s; padding: 8px; display: flex; flex-direction: column; gap: 8px;
}
.gtile:active { transform: scale(.96); }
.gtile.playing { box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 0 0 1.5px var(--ok), 0 5px 14px rgba(0, 0, 0, .24); }
.gtile.paused { box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 0 0 1.5px var(--warn), 0 5px 14px rgba(0, 0, 0, .24); }
.gcover { position: relative; aspect-ratio: 1 / 1; overflow: hidden; border-radius: 12px; background: var(--chip); }
.gcover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ggenre {
  position: absolute; top: 0; left: 0; z-index: 2; font-size: 8.5px; text-transform: uppercase; letter-spacing: .03em;
  color: #eef1ff; padding: 4px 8px; background: rgba(15, 15, 20, .55); backdrop-filter: blur(8px) saturate(160%); border-radius: 12px 0 10px 0;
}
.gbadge {
  position: absolute; top: 6px; right: 6px; z-index: 2; width: 22px; height: 22px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-size: 9px; background: rgba(15, 15, 20, .6);
  backdrop-filter: blur(8px); border: 1.5px solid transparent;
}
.gtile.playing .gbadge { border-color: var(--ok); color: var(--ok); }
.gtile.paused .gbadge { border-color: var(--warn); color: var(--warn); }
/* С152 (3-й проход): горизонтальный градиент тёмный→светлый→тёмный (блик по центру,
   как на референсе — не плоский цвет), без border. Низ скруглён сильнее верха. */
/* С152: название всегда по центру плашки, независимо от длины (было — короткие названия
   визуально "прижаты" влево из-за flex:1 на .gname рядом с точкой-индикатором). */
.gfoot { padding: 7px 10px; display: flex; align-items: center; justify-content: center; gap: 6px; border-radius: 6px 6px 14px 14px; background: var(--gfoot-gradient); }
.gname { font-size: 11px; color: var(--fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; }
.gdot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; background: transparent; }
.gtile.playing .gdot { background: var(--ok); box-shadow: 0 0 6px var(--ok); }
.gtile.paused .gdot { background: var(--warn); box-shadow: 0 0 6px var(--warn); }
.gempty { grid-column: 1 / -1; text-align: center; color: var(--fg-mute); font-size: 12px; padding: 30px 0; }

/* ================= MODALS ================= */
/* С152 (2-й проход): раньше blur на .ov убирали из-за конфликта вложенных backdrop-filter —
   тогда причина оказалась в БАГЕ СБОРКИ (Vite/Lightning CSS резал backdrop-filter, см.
   project-unitvr-vite-backdropfilter-bug-s152), а не в самом наложении фильтров. После
   фикса сборки пробуем снова — Михаил прямо просит фон ЗА попапом заметно размывать, чтобы
   попап визуально отделялся от библиотеки игр позади. */
.ov { position: fixed; inset: 0; background: var(--overlay-bg); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); display: none; align-items: center; justify-content: center; z-index: 50; padding: 20px; }
.ov.open { display: flex; }
.modal { width: min(340px, 100%); border-radius: 20px; padding: 20px 22px; }
.modal-h { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; position: relative; z-index: 1; }
.modal-h b { font-size: 15px; font-weight: 400; }
.modal-h .x { margin-left: auto; width: 26px; height: 26px; border-radius: 9px; border: none; background: var(--chip); color: var(--fg-dim); cursor: pointer; }
.tariff-list { display: flex; gap: 8px; }
.tariff-btn { flex: 1; justify-content: center; padding: 12px; }

/* С152: доработка модалки тарифа по запросу Михаила — крупная плашка с числом минут и
   ручной корректировкой (+/- 5 мин), явная кнопка "Начать" вместо мгновенного запуска
   по клику на пресет (пресет теперь только ВЫДЕЛЯЕТ тариф, не запускает игру). */
.tariff-custom {
  margin-top: 14px; padding: 18px; display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
.tariff-step {
  width: 44px; height: 44px; border-radius: 14px; border: none; background: var(--chip); color: var(--fg);
  font-size: 22px; font-weight: 300; cursor: pointer; flex-shrink: 0; transition: transform .12s, background .2s;
}
.tariff-step:active:not(:disabled) { transform: scale(.92); }
.tariff-step:disabled { opacity: .3; cursor: default; }
.tariff-value { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; }
.tariff-num { font-size: 40px; font-weight: 300; font-variant-numeric: tabular-nums; line-height: 1; color: var(--fg); }
.tariff-unit { font-size: 11px; color: var(--fg-dim); text-transform: uppercase; letter-spacing: .04em; }
.tariff-start { width: 100%; justify-content: center; padding: 14px; margin-top: 16px; font-size: 14px; }

/* С152: экран с кодом привязки нового шлема — крупная моноширинная строка, легко
   считывается с расстояния при вводе через VR-контроллер (медленный процесс). */
.pairing-result { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 8px 0; }
.pairing-code {
  font-family: ui-monospace, monospace; font-size: 40px; font-weight: 600; letter-spacing: 6px;
  color: var(--accent); background: var(--inset-bg); border: 1px solid var(--inset-border);
  border-radius: 12px; padding: 16px 24px; width: 100%; text-align: center;
}
.pairing-hint { font-size: 12.5px; color: var(--fg-dim); line-height: 1.5; text-align: center; }

.cast { width: min(720px, 94vw); border-radius: 20px; overflow: hidden; display: flex; flex-direction: column; }
.cast-h { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid rgba(255, 255, 255, .06); position: relative; z-index: 1; }
.cast-h b { font-size: 14px; font-weight: 400; }
.cast-status { font-size: 11px; color: var(--fg-dim); margin-left: 6px; }
.cast-h .x { margin-left: auto; width: 26px; height: 26px; border-radius: 9px; border: none; background: var(--chip); color: var(--fg-dim); cursor: pointer; }
.cast-body { aspect-ratio: 16 / 9; background: #000; display: flex; align-items: center; justify-content: center; }
.cast-body video { width: 100%; height: 100%; object-fit: contain; background: #000; }

/* С152: попап поддержки по образцу референса Stardog — плотная стеклянная окантовка
   снаружи (шапка+низ на стекле), белая панель в центре под сам чат. Окантовка = padding
   стеклянного контейнера, белая панель — отдельный внутренний блок со своим скруглением. */
.sup { width: min(360px, 100%); height: min(440px, 80vh); border-radius: 22px; display: flex; flex-direction: column; overflow: hidden; padding: 10px; gap: 8px; }
.sup-h { display: flex; align-items: center; gap: 10px; padding: 10px 12px; position: relative; z-index: 1; flex-shrink: 0; }
.sup-h b, .sup-h div { color: var(--fg) !important; }
.sup-panel { flex: 1; min-height: 0; display: flex; flex-direction: column; border-radius: 14px; background: var(--sup-panel-bg); overflow: hidden; }
.sup-b { flex: 1; overflow-y: auto; padding: 14px 16px; display: flex; flex-direction: column; gap: 9px; }
.msg { max-width: 82%; padding: 9px 12px; border-radius: 13px; font-size: 12px; line-height: 1.5; }
.msg.bot { background: var(--sup-panel-fg-dim); background: rgba(0, 0, 0, .06); color: var(--sup-panel-fg); align-self: flex-start; border-bottom-left-radius: 4px; }
.msg.usr { background: linear-gradient(135deg, var(--accent), var(--accent2)); color: var(--accent-fg); align-self: flex-end; border-bottom-right-radius: 4px; }
.sup-q { padding: 10px 16px 12px; display: flex; flex-wrap: wrap; gap: 6px; border-top: 1px solid rgba(0, 0, 0, .07); }
.qb { font-size: 10.5px; background: rgba(0, 0, 0, .05); color: var(--sup-panel-fg-dim); border: none; border-radius: 100px; padding: 7px 12px; cursor: pointer; font-family: inherit; font-weight: 300; }
.sup-i { display: flex; gap: 8px; padding: 10px 12px 2px; position: relative; z-index: 1; flex-shrink: 0; }
.sup-i input { flex: 1; background: var(--sup-panel-bg); border: none; border-radius: 10px; padding: 9px 12px; font-size: 12px; color: var(--sup-panel-fg); outline: none; font-family: inherit; font-weight: 300; }
.sup-i button { border: none; border-radius: 10px; background: linear-gradient(135deg, var(--accent), var(--accent2)); color: var(--accent-fg); padding: 9px 14px; font-size: 12px; cursor: pointer; font-family: inherit; font-weight: 500; }

.toast {
  position: fixed; left: 50%; bottom: 24px; transform: translate(-50%, 20px); background: rgba(20, 20, 30, .94);
  backdrop-filter: blur(9px); color: #eaeaf2; padding: 11px 20px; border-radius: 100px; font-size: 12px;
  opacity: 0; transition: all .3s; z-index: 60; pointer-events: none; box-shadow: 0 12px 30px -10px rgba(0, 0, 0, .5);
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }

.expand {
  position: fixed; top: max(16px, env(safe-area-inset-top)); left: 12px; width: 32px; height: 32px; border-radius: 10px;
  border: none; background: var(--chip); backdrop-filter: blur(10px); color: var(--fg); font-size: 14px; z-index: 20;
  display: flex; align-items: center; justify-content: center; opacity: 0; pointer-events: none; transition: opacity .25s; cursor: pointer;
}
#app.collapsed ~ .expand { opacity: 1; pointer-events: auto; }

@media (max-width: 820px) {
  #app { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .col-l { max-height: 34vh; }
  #helmScroll { overflow-x: auto; overflow-y: hidden; }
  #helmScroll > div { flex-direction: row; }
  .helm { min-width: 215px; }
  .search { width: 100%; margin-left: 0; }
}
.mode-switcher { display: flex; gap: 6px; margin-right: 4px; }
