/* Шрифты названий территорий: имя семейства у каждого правила скопировано
   1:1 из map.svg (font-family, который Inkscape вписал в <tspan> подписей)
   — иначе браузер не свяжет правило с текстом на карте и молча откатится
   на дефолтный шрифт. Добавляешь в Inkscape подписи новым шрифтом — добавь
   сюда ещё один @font-face с тем же именем семейства и файлом из public/fonts. */
@font-face {
  font-family: "CyrillicOld [Edited by me]";
  src: url("/fonts/Old.otf") format("opentype");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Eastern Rhodopes";
  src: url("/fonts/Eastern rhodopes.otf") format("opentype");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Orientir";
  src: url("/fonts/Orientir.otf") format("opentype");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Pravoslavnaya";
  src: url("/fonts/Pravoslavnaya.otf") format("opentype");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Patefon";
  /* Расширение не важно: бросаешь файл "1.woff2"/"1.woff"/"1.otf"/"1.ttf" в
     public/fonts — браузер сам пропускает недостающие src в списке (404) и
     берёт первый рабочий, CSS трогать не нужно. */
  src: url("/fonts/1.woff2") format("woff2"),
       url("/fonts/1.woff") format("woff"),
       url("/fonts/1.otf") format("opentype"),
       url("/fonts/1.ttf") format("truetype");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* Подписи территорий (шрифт Patefon, см. выше) — сглаживание контура и
   лёгкая тень поверх уже имеющегося тёмного обводочного stroke в самой
   разметке map.svg. Тень отдельная от stroke: та даёт читаемость на любом
   фоне, а drop-shadow — глубину/объём самой надписи. Правило в CSS, а не
   в map.svg: 15 подписей x2 (меню + игра) правились бы вручную при каждом
   пересохранении в Inkscape. */
#map text[data-label],
#menu-map text[data-label] {
  text-rendering: optimizeLegibility;
  filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, 0.55)) drop-shadow(0 0 3px rgba(0, 0, 0, 0.3));
}

:root {
  /* Направление "Flat White" (см. дизайн-макеты Coffee Glass): та же
     светлота и приглушённое свечение, что понравились, перенесённые из
     макета в реальные токены игры. */
  --bg: #26190e;
  --bg-soft: #3c2a16;
  --panel: #4c3a1e;
  --panel-2: #2e1f10;
  --text: #f0e0c4;
  --text-dim: #c8a878;
  --accent: #c8964e;
  --accent-2: #e0bc7e;
  --good: #9ecf7a;
  --bad: #e07a5f;
  --radius: 14px;
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html, body {
  height: 100%;
}

body {
  font-family: "Segoe UI", system-ui, -apple-system, Roboto, sans-serif;
  /* Направление Flat White: плоский тёплый градиент вместо фоновой
     фотографии пергамента (см. макеты Coffee Glass). */
  background: radial-gradient(1200px 800px at 20% 10%, var(--bg-soft), var(--bg));
  color: var(--text);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}

#app {
  width: 100%;
  max-width: 720px;
}

body.in-game {
  padding: 0;
  overflow: hidden;
}

body.in-game #app {
  width: 100vw;
  height: 100vh;
  max-width: none;
  overflow: hidden;
  padding: 0;
}

#screen-game {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.screen {
  display: none;
}

.screen.active {
  display: block;
  animation: fadeIn 0.25s ease;
}

/* Только opacity, без transform: у #screen-menu внутри лежит .menu-box--game
   с position:fixed (прижимает плитки к низу экрана поверх живой карты).
   Пока у #screen-menu самого шёл transform этой анимации, он на 0.25с
   становился containing block для fixed-потомков — .menu-box--game на это
   время позиционировался не от вьюпорта, а от рамки #screen-menu (которая
   не на весь экран), и плитки ехали куда-то в середину, а потом
   "прыгали" на настоящий низ, когда анимация заканчивалась и transform
   пропадал. Баг был на каждом возврате в меню после партии — там #screen-menu
   заново получает .active и анимацию проигрывает с нуля. */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.hidden {
  display: none !important;
}

/* ---- menu ---- */

.menu-box, .results-box, .auth-box {
  position: relative;
  z-index: 2;
  /* Современная стеклянная карточка: полупрозрачный фон + блюр вместо
     сплошной деревянной панели. */
  background: linear-gradient(180deg, rgba(35, 22, 12,0.8), rgba(16, 10, 5,0.88));
  backdrop-filter: blur(22px) saturate(140%);
  -webkit-backdrop-filter: blur(22px) saturate(140%);
  border: 1px solid rgba(255, 255, 255,0.09);
  border-radius: 28px;
  padding: 40px 32px;
  text-align: center;
  box-shadow: 0 24px 70px rgba(0, 0, 0,0.45), inset 0 1px 0 rgba(255, 255, 255,0.06);
}

/* Лобби и модалки (Настройки/Профиль используют одну и ту же .modal-box) —
   та же тёмная стеклянная подложка, но чуть плотнее и в языке плиток
   главного меню: тонкая золотая рамка вместо белой, более собранный
   радиус, угловые засечки как у .menu-tile — единый почерк "HUD-панели"
   вместо прежней мягкой скруглённой карточки. */
.lobby-box, .modal-box {
  position: relative;
  z-index: 2;
  /* Та же тонкая золотая полоса сверху и угловые засветки, что у
     .question-box — единый почерк стеклянной панели на все окна игры. */
  background:
    linear-gradient(90deg, transparent, var(--accent-2) 20%, var(--accent-2) 80%, transparent) top / 100% 3px no-repeat,
    radial-gradient(circle at 30% 0%, rgba(224, 188, 126, 0.12), transparent 60%),
    radial-gradient(circle at 80% 100%, rgba(200, 150, 78, 0.15), transparent 55%),
    linear-gradient(180deg, rgba(72, 54, 30, 0.75), rgba(38, 25, 14, 0.85));
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(200, 150, 78,0.35);
  border-radius: 12px;
  padding: 36px 30px;
  text-align: center;
  box-shadow: 0 24px 70px rgba(0, 0, 0,0.5), inset 0 1px 0 rgba(255, 255, 255,0.05);
}

/* Ромб-заклёпка (Вариант C) вместо плоского квадрата — только в левом
   верхнем углу, остальные три убрали везде в игре по этой же схеме (см.
   .menu-tile, .question-box, .boot-loading-box, .conn-box ниже). */
.lobby-box::before, .modal-box::before {
  content: "";
  position: absolute;
  width: 7px;
  height: 7px;
  background: var(--accent-2);
  transform: rotate(45deg);
  border-radius: 1px;
  box-shadow: 0 0 8px 1px rgba(224, 188, 126,0.6), 0 0 2px rgba(224, 188, 126,0.9);
  pointer-events: none;
  top: 9px;
  left: 9px;
}

.menu-box {
  opacity: 0;
}

.menu-logo {
  display: block;
  margin: 0 auto 8px;
  max-height: 56px;
  max-width: 250px;
  width: auto;
  height: auto;
}

.menu-map {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

/* Декоративный "призрак" карты на месте fon_sm.jpg — #bgGhostMap в map.svg:
   те же контуры территорий (продублированные <path>, без подписей),
   увеличенные в 2 раза и отражённые по обеим осям (scale(-2,-2)
   центр-симметрично = зеркало + масштаб за один transform), залиты той же
   terrTex-текстурой, что и настоящие территории, но приглушены через
   opacity на самой группе. В документе группа лежит НИЖЕ настоящих
   территорий, поэтому их непрозрачная заливка перекрывает её сама. Плюс к
   z-order — честная вырезка через SVG-маску #realMapHole: под площадью
   настоящих территорий у призрака физически нет пикселей, поэтому его
   границы не проступают сквозь анимацию захвата. Маска висит на ВНЕШНЕЙ
   обёртке #bgGhostClip, а не на самой группе: маска с userSpaceOnUse
   применяется к элементу вместе с его собственным transform, и на группе
   дырки уезжали и раздувались вместе с масштабом (чёрное заливало почти
   весь холст — фон пропадал целиком). Стили заливки/обводки заданы
   presentation-атрибутами прямо на <g id="bgGhostMap"> в map.svg (не тут).
   Между призраком и настоящей картой лежит #realMapOutline — статичные
   границы территорий (обводка как у настоящих, без заливки). Он нужен из-за
   terrSpread: там территория стартует со scale(0.04) и растёт, то есть на её
   месте на 1.7с образуется пустое окно. Без этого слоя в окне виден голый
   фон, с ним — контур территории остаётся на месте, пока цвет "разливается".
   Геометрия контуров лежит один раз в <defs> (#terrShapes, у путей НЕТ
   атрибутов fill/stroke), а маска и слой контуров тянут её через <use> и
   задают заливку/обводку сами — именно поэтому у shape-путей не должно
   появляться собственных presentation-атрибутов: они бы победили значения,
   унаследованные от <use>, и маска перестала бы вырезать.
   Под ним — только градиент sea (тёплые тона под палитру сайта), БЕЗ
   отдельного текстурного прямоугольника: пробовали класть terrTex вторым
   слоем под группу, но там, где она перекрывалась с призрак-картой, две
   полупрозрачные текстуры складывались и давали заметно более тёмное
   пятно именно по силуэту призрака. Один слой текстуры — либо от
   настоящих территорий, либо от призрака — держит фон ровным. */

/* Тот же рельеф, что у настоящих территорий (.menu-map svg path[data-territory]
   и .map path.terr), но с поправкой на масштаб группы: #bgGhostMap увеличен
   в 1.97 раза по X и 2.52 по Y, а CSS-фильтр считается в локальных координатах
   ДО трансформации — не поделив смещения, получили бы тени вдвое толще, чем
   у настоящей карты. 1.5/1.97 ≈ 0.76, 1.5/2.52 ≈ 0.6, блюр 2/2.23 ≈ 0.9.
   Селектор по id (а не по .menu-map) — карта вставляется и в меню, и в
   игровой #map, правило должно работать в обоих. */
#bgGhostMap path {
  filter: drop-shadow(0 0 2px rgba(200, 150, 90, 0.2));
}

/* Силуэтная тень "побережья" — аналог .menu-map .territories-group. Висит на
   внешней обёртке, у которой нет transform, поэтому значения совпадают с
   настоящей картой один в один, без пересчёта. Фильтр применяется ДО маски,
   так что тень, падающая в вырезы под настоящими территориями, срезается
   вместе с ними и не проступает в анимации захвата. */
#bgGhostClip {
  filter: drop-shadow(0 0 16px rgba(10, 6, 2, 0.4));
}

/* "Объём" поверх настоящих территорий — пара плоских прямоугольников на весь
   холст в map.svg (#terrShade снизу, #terrSheen сверху), оба замаскированы
   под ТОЛЬКО реальные территории через #terrShapeMask (инверсия #realMapHole:
   белые силуэты по чёрному фону вместо чёрных дыр по белому):
     #terrShade — тёмный диагональный градиент снизу-справа, mix-blend-mode:
       multiply — та же сторона, что у тёмной половины emboss-тени ниже.
     #terrSheen — светлый диагональный градиент сверху-слева, mix-blend-mode:
       overlay — та же сторона, что у светлой половины emboss-тени.
   Вместе имитируют один источник света сверху-слева, как и остальной рельеф
   карты, только по всей площади территории, а не только по контуру. Работают
   поверх любого цвета заливки — не трогают FILL/COLOR в game.js и
   menu-sim.js, чисто оптический слой поверх готовой территории, отсюда и
   "объём" без переписывания логики раскраски. Лежат между g3 (территориями)
   и g17 (подписями), чтобы не попадать на текст. Стили заданы прямо в
   map.svg через style= — здесь для них ничего нет. */

.menu-map svg {
  width: 100%;
  height: 100%;
  display: block;
}

.menu-map svg path[data-territory] {
  filter: drop-shadow(0 0 2px rgba(200, 150, 90, 0.25));
}

/* Тот же приём, что и в игровой карте: тень на группе территорий ложится
   только по внешнему силуэту (побережью), стыки между территориями её не
   получают. */
.menu-map .territories-group {
  filter: drop-shadow(0 0 14px rgba(10, 6, 2, 0.45));
}

/* Фоновая "живая" симуляция в меню/лобби (menu-sim.js): случайные захваты
   территорий, летящие мечи, смена цвета — чисто декоративно. */
.menu-sword-fly {
  animation: menuSwordFly 0.9s cubic-bezier(0.25, 0.1, 0.3, 1) forwards;
}

@keyframes menuSwordFly {
  0% { transform: translate(var(--sx), var(--sy)) rotate(0deg) scale(0.4); opacity: 0; }
  15% { opacity: 1; }
  85% { opacity: 1; }
  100% { transform: translate(var(--tx), var(--ty)) rotate(var(--rot)) scale(1); opacity: 0; }
}

.menu-map path.menu-terr-flash {
  animation: menuTerrFlash 0.6s ease-out;
}

@keyframes menuTerrFlash {
  0% {
    filter:
      drop-shadow(-1.5px -1.5px 0 rgba(240, 200, 140, 0.55))
      drop-shadow(1.5px 1.5px 2px rgba(40, 22, 8, 0.6))
      brightness(2.2) saturate(1.4);
  }
  100% {
    filter:
      drop-shadow(-1.5px -1.5px 0 rgba(240, 200, 140, 0.55))
      drop-shadow(1.5px 1.5px 2px rgba(40, 22, 8, 0.6))
      brightness(1) saturate(1);
  }
}

.menu-map text {
  pointer-events: none;
  user-select: none;
  fill: #f0e0c4;
  stroke: #26190e;
  stroke-width: 2;
  opacity: 1;
  paint-order: stroke;
  font-weight: 700;
}

#screen-menu.menu-in .menu-box {
  animation: menuFlyIn 0.55s cubic-bezier(0.2, 0.9, 0.3, 1.12) forwards;
}

@keyframes menuFlyIn {
  from { transform: translateY(90px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

.logo {
  font-family: "Cinzel", serif;
  font-weight: 900;
  font-size: 56px;
  letter-spacing: 2px;
  background: linear-gradient(120deg, var(--accent-2), var(--accent));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  margin-bottom: 28px;
}

.tagline {
  color: var(--text-dim);
  margin-bottom: 28px;
}

/* Крупный титул "Vanquelia" в главном меню: после того как меню загружено
   (класс .menu-in вешает main.js в самом конце загрузки, вместе с появлением
   карты), текст спускается сверху — из-за границы экрана — и останавливается
   у ВЕРХНЕГО края, ниже шапки меню, целиком в кадре (не уходит ни за верх, ни
   за низ). Затем медленно "плавает" по вертикали на несколько пикселей.
   Показывается только в залогиненном меню (#screen-menu.menu-authed, класс
   вешает main.js вместе с .menu-box--game): там центр/верх свободны, а в
   карточке входа/регистрации роль титула играют логотип и заголовок карточки.
   Каждый возврат в меню анимация проигрывается заново: #screen-menu уходит из
   display:none (.screen.active), а вместе с ним перезапускаются CSS-анимации
   потомков.

   Вход и "плавание" разведены на два элемента намеренно: у одного элемента
   нельзя одновременно иметь конечную анимацию входа и бесконечную — они
   конкурировали бы за transform. Внешний .menu-hero держит вход (ends
   forwards), внутренний .menu-hero-text — бесконечное покачивание с задержкой
   равной длительности входа, так что плавание начинается ровно после него. */
.menu-hero {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: flex-start;   /* отдыхает у верхнего края, а не в центре */
  justify-content: center;
  /* Ниже шапки меню (top:24px + иконки ~40px), чтобы не пересекаться с ней */
  padding-top: 60px;
  box-sizing: border-box;
  pointer-events: none;
  user-select: none;
  z-index: 1;
  opacity: 0;
  visibility: hidden;
}

.menu-hero-text {
  font-family: "Cinzel", serif;
  font-weight: 900;
  font-size: clamp(52px, 12vw, 125px);
  line-height: 1;
  letter-spacing: 4px;
  color: #e0bc7e;
  white-space: nowrap;
  text-shadow: 0 10px 34px rgba(0, 0, 0, 0.7), 0 3px 8px rgba(0, 0, 0, 0.6);
}

#screen-menu.menu-in.menu-authed.active .menu-hero {
  visibility: visible;
  animation: heroDrop 1.1s cubic-bezier(0.16, 0.84, 0.3, 1.02) forwards;
}

#screen-menu.menu-in.menu-authed.active .menu-hero-text {
  animation: heroFloat 5.5s ease-in-out 1.1s infinite;
}

@keyframes heroDrop {
  0% { transform: translateY(-135%); opacity: 0; }
  55% { opacity: 1; }
  100% { transform: translateY(0); opacity: 1; }
}

@keyframes heroFloat {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-5px); }
}

.name-row {
  margin-bottom: 22px;
}

.name-row input {
  width: 100%;
  max-width: 320px;
  padding: 12px 16px;
  font-size: 16px;
  color: var(--text);
  background: rgba(255, 255, 255,0.05);
  border: 1px solid rgba(255, 255, 255,0.12);
  border-radius: 14px;
  outline: none;
  text-align: center;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.name-row input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(200, 150, 78,0.2);
}

.menu-buttons {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
}

/* Плитки главного меню (Настройки / Играть / Профиль / Выйти). Играть —
   акцентная, чуть крупнее и со светящейся полоской сверху; остальные три
   визуально ровные, той же высоты. Отступ сверху отделяет ряд от текста
   приветствия — по просьбе "опустить кнопки чуть ниже". */
.menu-tiles {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 14px;
  margin-top: 30px;
}

.menu-tile {
  position: relative;
  width: 116px;
  height: 132px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  border-radius: 12px;
  cursor: pointer;
  color: var(--text-dim);
  background: linear-gradient(180deg, rgba(59, 40, 20,0.72), rgba(14, 9, 4,0.88));
  border: 1px solid rgba(200, 150, 78,0.4);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.3, 1.2), border-color 0.18s ease, background 0.18s ease, color 0.18s ease;
}

.menu-tile::before {
  content: "";
  position: absolute;
  width: 5px; height: 5px;
  background: var(--accent-2);
  transform: rotate(45deg);
  border-radius: 1px;
  box-shadow: 0 0 6px 1px rgba(224, 188, 126,0.55), 0 0 2px rgba(224, 188, 126,0.85);
  top: 8px;
  left: 8px;
}

.menu-tile:hover {
  transform: translateY(-3px);
  border-color: rgba(200, 150, 78,0.6);
  color: var(--text);
  background: linear-gradient(180deg, rgba(70, 48, 24,0.8), rgba(16, 10, 5,0.92));
}

.menu-tile:active {
  transform: translateY(-1px) scale(0.97);
}

.menu-tile-icon {
  width: 30px;
  height: 30px;
}

.menu-tile-icon svg {
  width: 100%;
  height: 100%;
  display: block;
}

.menu-tile-label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
}

/* Имя игрока над иконкой на кнопке "Выйти" — вместо отдельной строки
   "Вы вошли как…" над плитками. Длинное имя обрезается многоточием (сама
   плашка не растягивается), полное — во всплывающей стеклянной подсказке
   при наведении именно на имя; подсказка — чистый CSS (:hover + content:
   attr()), поэтому сама пропадает вместе с курсором, ничего лишнего в JS
   не нужно. */
/* Обрезание многоточием живёт на ВНУТРЕННЕМ .menu-tile-name-text, а не на
   самом .menu-tile-name — раньше overflow:hidden стоял прямо на элементе,
   который тут же хостит ::after-подсказку, и та обрезалась собственным
   overflow хозяина (подсказка технически рисовалась, но почти вся уходила
   под невидимую кромку). Внешний .menu-tile-name теперь ничего не обрезает
   сам — только позиционирует подсказку. */
/* position:absolute — раньше имя стояло ПЕРВЫМ ребёнком в flex-колонке
   .menu-tile вместе со значком и подписью, и на "Выйти" (у которой есть
   ещё и эта строка) значок с подписью центрировались ниже, чем на
   "Играть"/"Профиль" (там всего 2 ребёнка). Вынесли имя из потока —
   значок+подпись теперь везде считаются от одинаковых двух элементов и
   центрируются на одной высоте, а имя просто прижато к низу кнопки. */
.menu-tile-name {
  position: absolute;
  bottom: 8px;
  left: 8px;
  right: 8px;
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.2px;
  color: var(--accent-2);
  text-align: center;
}

.menu-tile-name-text {
  display: block;
  max-width: 88px;
  margin: 0 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menu-tile-name:hover::after {
  content: attr(data-full-name);
  position: absolute;
  /* Имя теперь прижато к низу кнопки — подсказка раскрывается вниз, а не
     вверх (иначе легла бы поверх значка/подписи посередине кнопки). */
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-top: 8px;
  padding: 6px 12px;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.2px;
  color: var(--text);
  background: linear-gradient(180deg, rgba(72, 54, 30,0.94), rgba(38, 25, 14,0.97));
  border: 1px solid rgba(200, 150, 78,0.5);
  border-radius: 8px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 8px 20px rgba(0, 0, 0,0.5);
  z-index: 30;
  pointer-events: none;
}

/* "Играть" раньше отличалась от соседних плиток размером, цветом текста,
   цветом рамки, отдельной полоской сверху и даже непрозрачностью фона —
   на живой карте под backdrop-filter это читалось как отдельно "тёмная"/
   сломанная кнопка, а не акцент. Теперь у .menu-tile-primary нет вообще
   никаких переопределений — она визуально неотличима от соседних плиток,
   акцент только смысловой (это кнопка запуска игры), не визуальный. */

@media (max-width: 480px) {
  .menu-tiles {
    flex-wrap: wrap;
    gap: 12px;
  }
  .menu-tile { width: 42%; }
}

/* Залогиненное меню больше не сидит в стеклянной карточке — только кнопки
   на прозрачном фоне поверх живой карты, герб слева сверху и подпись
   "Главное меню" справа сверху, как в согласованном варианте 5. Карточку
   (.menu-box) убираем только для этого состояния: она делит один и тот же
   .menu-box со входом/регистрацией (#auth-area), которых это не касается —
   поэтому не переопределяем сам .menu-box, а навешиваем модификатор
   .menu-box--game, который main.js включает вместе с #game-area. */
.menu-box.menu-box--game {
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: none;
  box-shadow: none;
  padding: 0;
  /* Раньше карточка стояла в обычном потоке и центрировалась body{display:flex;
     align-items:center}. Приветствие и плитки просили "почти в самый低" —
     этого не добиться внутри центрированного потока, поэтому карточка сама
     становится на весь экран и прижимает содержимое к низу. */
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  padding-bottom: 56px;
}

.menu-box--game .menu-logo,
.menu-box--game .logo,
.menu-box--game .tagline {
  display: none;
}

/* Герб и подпись "Главное меню" — не внутри .menu-box (у неё есть
   transform от анимации menuFlyIn, а transform на предке создаёт свой
   контекст для fixed-потомков, и position:fixed внутри прижался бы к
   границам карточки, а не экрана), а отдельным блоком-соседом, как и
   test-mode-corner ниже. */
.menu-hud-header {
  position: fixed;
  top: 24px;
  left: 24px;
  right: 24px;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: space-between;
  pointer-events: none;
}

.menu-hud-brand {
  display: flex;
  align-items: center;
  gap: 12px;
}

.menu-hud-brand img {
  height: 34px;
  width: auto;
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0,0.5));
}

/* Логотип раз в 15 секунд "переворачивается" по горизонтали (вращение вокруг
   вертикальной оси Y). perspective в самом transform — без него rotateY
   выглядит как плоское сжатие. Переворот занимает ~1с в начале пятнадцати-
   секундного цикла, дальше картинка стоит на месте (360deg визуально = 0).
   Тот же эффект вешаем и на лого в карточке меню (#menu-logo). */
.menu-hud-brand img,
.menu-logo {
  animation: logoFlip 15s ease-in-out infinite;
}

@keyframes logoFlip {
  0% { transform: perspective(500px) rotateY(0deg); }
  7% { transform: perspective(500px) rotateY(360deg); }
  100% { transform: perspective(500px) rotateY(360deg); }
}

.menu-hud-brand span {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 3px;
  background: linear-gradient(120deg, var(--accent-2), var(--accent));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.menu-hud-eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--text-dim);
  border: 1px solid rgba(200, 150, 78,0.4);
  border-radius: 2px;
  padding: 6px 16px;
}

/* Правая половина хедера: подпись "Главное меню" + кнопка настроек рядом —
   у самого .menu-hud-header pointer-events:none (сквозь него кликается
   карта), поэтому интерактивным элементам внутри нужно включать их себе
   обратно явно. */
.menu-hud-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

.menu-hud-gear {
  pointer-events: auto;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  background: linear-gradient(180deg, rgba(59, 40, 20,0.72), rgba(14, 9, 4,0.88));
  border: 1px solid rgba(200, 150, 78,0.4);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  cursor: pointer;
  transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.3, 1.2), border-color 0.18s ease, background 0.18s ease, color 0.18s ease;
}

/* Кнопка "Профиль" показывает выбранную аватарку картинкой вместо иконки
   силуэта — background-image кладёт main.js (updateMenuAvatar). */
.menu-hud-gear.has-avatar {
  background-size: cover;
  background-position: center;
}

.menu-hud-gear.has-avatar svg {
  display: none;
}

.menu-hud-gear svg {
  width: 20px;
  height: 20px;
}

.menu-hud-gear:hover {
  transform: rotate(35deg);
  border-color: rgba(200, 150, 78,0.6);
  color: var(--text);
  background: linear-gradient(180deg, rgba(70, 48, 24,0.8), rgba(16, 10, 5,0.92));
}

.menu-hud-gear:active {
  transform: rotate(35deg) scale(0.93);
}

@media (max-width: 480px) {
  .menu-hud-header {
    top: 16px;
    left: 16px;
    right: 16px;
  }
  .menu-hud-eyebrow {
    display: none;
  }
}

/* Тестовые чекбоксы (боты / сразу в битву) — намеренно вынесены из карточки
   меню в угол экрана и уменьшены, чтобы не спорить за внимание с реальными
   пунктами меню. position:fixed, а не absolute внутри .menu-box: у той
   уже есть transform от анимации появления (menuFlyIn), а transform на
   предке создаёт свой контекст для fixed-потомков — здесь нужен угол
   именно экрана, а не карточки. */
.test-mode-corner {
  position: fixed;
  right: 18px;
  bottom: 14px;
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: flex-end;
  pointer-events: none;
}

.test-mode-corner .test-mode-toggle {
  pointer-events: auto;
}

.test-mode-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  justify-content: flex-end;
  font-size: 11px;
  opacity: 0.45;
  cursor: pointer;
  transition: opacity 0.15s ease;
}

.test-mode-toggle:hover {
  opacity: 0.85;
}

.test-mode-toggle input {
  cursor: pointer;
  width: 12px;
  height: 12px;
}

.btn {
  position: relative;
  overflow: hidden;
  cursor: pointer;
  border: none;
  border-radius: 999px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.2px;
  padding: 13px 30px;
  color: var(--text);
  transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.3, 1.2), box-shadow 0.18s ease, background 0.18s ease, border-color 0.18s ease;
}

.btn:hover {
  transform: translateY(-2px);
}

.btn:active {
  transform: translateY(0) scale(0.96);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}

.btn-primary {
  background: linear-gradient(135deg, var(--accent-2), var(--accent) 65%, #c48a3a);
  color: #221200;
  font-weight: 700;
  box-shadow: 0 10px 26px rgba(200, 150, 78,0.4), inset 0 1px 0 rgba(255, 255, 255,0.35);
}

.btn-primary:hover {
  box-shadow: 0 14px 34px rgba(200, 150, 78,0.55), inset 0 1px 0 rgba(255, 255, 255,0.4);
}

/* Лёгкий блик, пробегающий по кнопке при наведении — современный акцент
   вместо статичного плоского градиента. */
.btn-primary::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 30%, rgba(255, 255, 255,0.5) 46%, transparent 62%);
  transform: translateX(-130%);
  transition: transform 0.65s ease;
  pointer-events: none;
}

.btn-primary:hover::after {
  transform: translateX(130%);
}

.btn-secondary {
  background: rgba(255, 255, 255,0.04);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1.5px solid rgba(255, 255, 255,0.14);
  color: var(--text-dim);
}

.btn-secondary:hover {
  background: rgba(255, 255, 255,0.09);
  border-color: rgba(255, 255, 255,0.3);
  color: var(--text);
}

.btn-danger {
  background: rgba(93, 255, 238,0.12);
  border: 1.5px solid rgba(93, 255, 238,0.5);
  color: var(--bad);
}

.btn-danger:hover {
  background: rgba(93, 255, 238,0.22);
  border-color: var(--bad);
}

.btn-sm {
  padding: 7px 16px;
  font-size: 13px;
}

.btn-lg {
  width: 260px;
  font-size: 18px;
  padding: 14px 28px;
}

.status {
  margin-top: 16px;
  color: var(--text-dim);
  min-height: 20px;
  font-size: 14px;
}

/* Эти два всегда несут только ошибки, в отличие от общего .status (который
   показывает и нейтральные подсказки). Раньше они красились приглушённым
   --text-dim и терялись на фоне — игрок жал "Создать аккаунт", ошибка
   появлялась, но выглядела как обычная серая подпись, и казалось, что
   кнопка просто не работает. */
#login-error:not(:empty),
#register-error:not(:empty) {
  color: var(--bad);
  font-weight: 600;
}

/* ---- auth ---- */

.auth-box {
  max-width: 400px;
  margin: 0 auto;
}

.auth-box h2 {
  margin-bottom: 22px;
  font-size: 26px;
}

.auth-box input {
  width: 100%;
  padding: 12px 16px;
  font-size: 16px;
  color: var(--text);
  background: rgba(255, 255, 255,0.05);
  border: 1px solid rgba(255, 255, 255,0.12);
  border-radius: 14px;
  outline: none;
  margin-bottom: 12px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.auth-box input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(200, 150, 78,0.2);
}

.auth-box .btn {
  width: 100%;
  margin-top: 6px;
}

.btn-google {
  background: #ffffff;
  color: #333333;
  border: 1px solid #d9d9d9;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.btn-google:hover {
  filter: brightness(0.96);
}

.btn-google::before {
  content: "";
  width: 18px;
  height: 18px;
  background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><path fill="%23EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"/><path fill="%234285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"/><path fill="%23FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"/><path fill="%2334A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"/></svg>') center / contain no-repeat;
}

.btn-yandex {
  background: #fc3f1d;
  color: #ffffff;
  border: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-weight: 600;
}

.btn-yandex:hover {
  filter: brightness(1.06);
}

.btn-yandex::before {
  content: "Y";
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #ffffff;
  color: #fc3f1d;
  font-weight: 800;
  font-size: 13px;
  line-height: 18px;
  text-align: center;
  font-family: Arial, sans-serif;
}

.divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 16px 0;
  color: var(--text-dim);
  font-size: 13px;
}

.divider::before,
.divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--panel-2);
}

.auth-switch {
  margin-top: 16px;
  color: var(--text-dim);
  font-size: 14px;
}

.auth-switch a {
  color: var(--accent-2);
  cursor: pointer;
  text-decoration: none;
}

.auth-switch a:hover {
  text-decoration: underline;
}

/* ---- lobby ---- */

.lobby-box h2 {
  margin-bottom: 18px;
  font-size: 26px;
}

.spinner {
  width: 40px;
  height: 40px;
  margin: 0 auto 18px;
  border: 3px solid rgba(255, 255, 255,0.1);
  border-top-color: var(--accent-2);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.lobby-count {
  color: var(--text-dim);
  margin-bottom: 14px;
}

.lobby-list {
  list-style: none;
  margin: 0 auto 22px;
  max-width: 320px;
  text-align: left;
}

.lobby-list li {
  padding: 10px 16px;
  margin-bottom: 8px;
  background: rgba(255, 255, 255,0.05);
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255,0.1);
}

.lobby-list li .me {
  color: var(--accent-2);
  font-weight: 700;
}

/* ---- boot loading ---- */

.boot-loading {
  position: fixed;
  inset: 0;
  z-index: 100;
  /* Тот же плоский градиент Flat White, что и у body/conn-overlay — раньше
     тут была отдельная сплошная заливка, и заставка на миг "перескакивала"
     на неё до появления настоящего фона. */
  background: radial-gradient(1200px 800px at 20% 10%, var(--bg-soft), var(--bg));
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.55s ease;
}

.boot-loading.fade-out {
  opacity: 0;
}

.boot-loading.hidden {
  display: none;
}

/* Та же стеклянная HUD-панель, что у .lobby-box/.modal-box/.question-box —
   раньше у заставки загрузки не было ни заливки, ни блюра, только рамка и
   уголки, и на фоне остальных стеклянных окон игры она смотрелась голо. */
.boot-loading-box {
  text-align: center;
  color: var(--text);
  position: relative;
  padding: 32px 46px;
  background:
    linear-gradient(90deg, transparent, var(--accent-2) 20%, var(--accent-2) 80%, transparent) top / 100% 3px no-repeat,
    radial-gradient(circle at 30% 0%, rgba(224, 188, 126, 0.12), transparent 60%),
    radial-gradient(circle at 80% 100%, rgba(200, 150, 78, 0.15), transparent 55%),
    linear-gradient(180deg, rgba(72, 54, 30, 0.75), rgba(38, 25, 14, 0.85));
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(200, 150, 78, 0.35);
  border-radius: 12px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

.boot-loading-box::before {
  content: "";
  position: absolute;
  width: 7px;
  height: 7px;
  background: var(--accent-2);
  transform: rotate(45deg);
  border-radius: 1px;
  box-shadow: 0 0 8px 1px rgba(224, 188, 126,0.6), 0 0 2px rgba(224, 188, 126,0.9);
  top: 9px;
  left: 9px;
}

.boot-spinner {
  width: 44px;
  height: 44px;
  margin: 0 auto 18px;
  border: 4px solid rgba(240, 224, 196, 0.2);
  border-top-color: var(--text);
  border-radius: 50%;
  animation: bootSpin 0.9s linear infinite;
}

@keyframes bootSpin {
  to { transform: rotate(360deg); }
}

.boot-bar {
  width: 240px;
  height: 8px;
  margin: 14px auto;
  background: rgba(240, 224, 196, 0.15);
  border-radius: 999px;
  overflow: hidden;
}

.boot-bar-fill {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  border-radius: 999px;
  transition: width 0.3s ease;
}

.boot-text {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 2px;
  text-transform: uppercase;
  opacity: 0.85;
}

.boot-count {
  margin-top: 6px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.5px;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

/* ---- game ---- */

.game-top {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 10;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 16px;
  background: linear-gradient(to bottom, rgba(26, 16, 8,0.85), transparent);
}

.round-info {
  font-size: 15px;
  color: var(--text-dim);
}

/* Трекер ходов боя ("C, переработка — вариант 2: мини-точки в раунде") —
   6 ячеек раунда, каждая с 3 мини-точками цветом игроков в порядке хода
   ЭТОГО раунда (посчитан заранее из battle.baseOrder — детерминированный
   rotate, см. renderBattleTurnTracker в game.js), поэтому расклад виден
   на раунды вперёд, а не только на текущий. Снизу — полный порядок ходов
   активного раунда цепочкой со стрелками. Видим только в фазе "битва"
   Левый нижний угол экрана, поверх карты — независимо от шапки. Виден
   только в фазе "битва": появляется влётом снизу ровно в момент начала
   боя и улетает обратно вниз, как только бой заканчивается (класс
   .leaving играет обратную анимацию, .hidden добавляется только когда
   она доиграла — см. renderBattleTurnTracker в game.js, тот же приём,
   что у #answer-reminder). */
.battle-turn-tracker {
  position: absolute;
  left: 16px;
  bottom: 16px;
  z-index: 10;
  animation: bttSlideIn 0.4s cubic-bezier(0.2, 0.8, 0.3, 1);
}

.battle-turn-tracker.leaving {
  animation: bttSlideOut 0.35s cubic-bezier(0.4, 0, 0.6, 1) forwards;
}

@keyframes bttSlideIn {
  from { transform: translateY(48px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

@keyframes bttSlideOut {
  from { transform: translateY(0); opacity: 1; }
  to { transform: translateY(48px); opacity: 0; }
}

/* Все размеры трекера — ×1.5 от исходных (запрошенное увеличение на 50%):
   каждое число ниже кратно шагу исходной версии. */
/* Стиль "Боевой консоли" (тот же язык, что у #question-card.hud-console —
   тёмный var(--bg), тонкие сканлайны + радиальный блик через ::before,
   рамка accent 0.35) — макет собран в Claude Design ("Combat Console HUD",
   2026-09-16), перенесён сюда без шапки по месту (см. .btt-wrap::before). */
.btt-wrap {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7.5px;
  padding: 7.5px 15px 9px;
  background: var(--bg);
  border: 1px solid rgba(200, 150, 78, 0.35);
  border-radius: 15px;
  box-shadow: 0 9px 24px rgba(0, 0, 0, 0.35);
  overflow: hidden;
}

.btt-wrap::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    repeating-linear-gradient(0deg, rgba(224, 188, 126, 0.035) 0px, rgba(224, 188, 126, 0.035) 1px, transparent 1px, transparent 3px),
    radial-gradient(280px 220px at 90% -20%, rgba(200, 150, 78, 0.16), transparent);
}

/* Сканлайн-подложка (::before) — position:absolute без z-index (auto),
   поэтому в порядке отрисовки она попадает в ту же "положительную" группу,
   что и остальные positioned-потомки; без z-index:1 тут она красилась бы
   ПОВЕРХ обычных block-детей ниже (rounds/divider/turnrow), закрывая их
   лёгкой дымкой. */
.btt-rounds, .btt-divider, .btt-turnrow {
  position: relative;
  z-index: 1;
}

.btt-rounds {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 6px;
}

.btt-rcell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4.5px;
  padding: 4.5px 4.5px 3px;
  border-radius: 7.5px;
  background: rgba(46, 31, 16, 0.5);
  border: 1px solid rgba(224, 188, 126, 0.1);
  transition: background 0.3s ease, border-color 0.3s ease, opacity 0.3s ease;
}

.btt-rcell.active {
  background: rgba(200, 150, 78, 0.14);
  border-color: rgba(200, 150, 78, 0.5);
}

.btt-rcell.upcoming { opacity: 0.55; }

.btt-rnum {
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: var(--text-dim);
  opacity: 0.7;
}

.btt-rcell.active .btt-rnum {
  color: var(--accent-2);
  opacity: 1;
}

.btt-dots {
  display: flex;
  align-items: center;
  gap: 3.75px;
}

.btt-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1.5px solid rgba(0, 0, 0, 0.3);
  opacity: 0.85;
  position: relative;
}

.btt-rcell.done .btt-dot { opacity: 0.4; }

.btt-dot.is-done::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: rgba(26, 18, 10, 0.6);
}

.btt-dot.is-now {
  width: 12px;
  height: 12px;
  opacity: 1;
  box-shadow: 0 0 0 2.25px var(--panel-2), 0 0 0 3.75px var(--ring), 0 0 9px 2.25px var(--ring);
  animation: bttDotPulse 1.5s ease-in-out infinite;
}

@keyframes bttDotPulse {
  0%, 100% { box-shadow: 0 0 0 2.25px var(--panel-2), 0 0 0 3.75px var(--ring), 0 0 6px 1.5px var(--ring); }
  50% { box-shadow: 0 0 0 2.25px var(--panel-2), 0 0 0 3.75px var(--ring), 0 0 13.5px 4.5px var(--ring); }
}

.btt-divider {
  width: 100%;
  height: 1.5px;
  background: rgba(224, 188, 126, 0.16);
}

.btt-turnrow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0;
}

.btt-turn {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 6px;
  opacity: 0.65;
  transition: opacity 0.3s ease, transform 0.3s ease;
}

.btt-turn.current { opacity: 1; transform: scale(1.12); }
.btt-turn.past { opacity: 0.45; }

.btt-tdot {
  width: 27px;
  height: 27px;
  border-radius: 50%;
  border: 2px solid rgba(0, 0, 0, 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
}

.btt-tdot svg { width: 12px; height: 12px; }

.btt-turn.current .btt-tdot {
  box-shadow: 0 0 0 2.25px var(--panel-2), 0 0 0 3.75px var(--ring), 0 0 12px 3px var(--ring);
  animation: bttTdotPulse 1.6s ease-in-out infinite;
}

@keyframes bttTdotPulse {
  0%, 100% { box-shadow: 0 0 0 2.25px var(--panel-2), 0 0 0 3.75px var(--ring), 0 0 7.5px 1.5px var(--ring); }
  50% { box-shadow: 0 0 0 2.25px var(--panel-2), 0 0 0 3.75px var(--ring), 0 0 16.5px 5.25px var(--ring); }
}

.btt-tarrow {
  color: var(--text-dim);
  opacity: 0.35;
  font-size: 13.5px;
}

@media (max-width: 760px) {
  .battle-turn-tracker { display: none; }
}

.scoreboard {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

/* Раньше здесь был общий стеклянный док позади всех плашек — теперь у
   каждого игрока своя стеклянная капсула (.score-chip), общая подложка под
   ними стала лишним слоем и просто убрана: .scoreboard-corner остаётся
   только раскладкой (позиционирование внизу экрана + отступы между
   карточками), без фона/блюра/рамки. */
.scoreboard-corner {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 16px;
  z-index: 10;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0;
  padding: 0;
  max-width: 96vw;
}

/* "Оверлап-бейдж": крупный круглый аватар слева (кольцо цвета игрока —
   опора под будущий выбор картинки аватарки: нет картинки — просто заливка
   цветом через .avatar.pX ниже, есть картинка — JS кладёт background-image
   поверх той же заливки, кольцо остаётся тем же индикатором цвета), имя и
   счёт стопкой справа внутри стеклянной капсулы. Фиксированная ширина —
   не потолок: у каждого игрока карточка одного и того же размера всегда,
   длинное имя просто обрезается многоточием внутри .chip-name, а не
   раздувает или сжимает саму карточку. */
/* Цвета — те же, что у окна вопроса ("Боевая консоль"): тёмный var(--bg)
   вместо стеклянной заливки цветом игрока, тонкие сканлайны через ::before
   (тот же рецепт, что и у #question-card.hud-console/.btt-wrap), рамка на
   accent вместо --glow. Форма (пилюля) и раскладка не трогаются — только
   палитра. */
.score-chip {
  position: relative;
  background: var(--bg);
  border: 1px solid rgba(200, 150, 78, 0.35);
  border-radius: 999px;
  padding: 6px 20px 6px 6px;
  font-size: 18px;
  display: inline-flex;
  align-items: center;
  gap: 13px;
  transition: background 0.18s ease, border-color 0.18s ease;
  overflow: hidden;
  width: 300px;
}

.score-chip::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    repeating-linear-gradient(0deg, rgba(224, 188, 126, 0.035) 0px, rgba(224, 188, 126, 0.035) 1px, transparent 1px, transparent 3px),
    radial-gradient(220px 140px at 88% -30%, rgba(200, 150, 78, 0.16), transparent);
}

.score-chip .avatar, .score-chip .chip-text {
  position: relative;
  z-index: 1;
}

.score-chip:hover {
  background: var(--panel-2);
}

.avatar {
  position: relative;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  border: none;
  background-size: cover;
  background-position: center;
  box-shadow: 0 0 0 3px rgba(var(--glow, 255,255,255), 0.9), 0 4px 12px rgba(0,0,0,0.4);
}

/* Кольцо цвета игрока в панели очков — чуть толще базового (3px -> 5px):
   на тёмном фоне карточки (см. .score-chip выше) это единственный явный
   цветовой маркер "чей это счёт", раз сама плашка больше не залита цветом
   игрока. Только здесь — остальные места (шапка дуэли и т.п.) не трогаем. */
.score-chip .avatar {
  box-shadow: 0 0 0 5px rgba(var(--glow, 255,255,255), 0.9), 0 4px 12px rgba(0,0,0,0.4);
}

/* Лёгкий блик сверху-слева поверх сплошного цвета — та же идея объёма, что
   у территорий на карте (terrSheen), только на аватарке. Это то, что видно,
   пока у игрока нет своей картинки — кольцо выше уже готово обвести и
   картинку, когда выбор аватарки появится. */
/* --glow — тот же цвет игрока, что и у .score-chip.pX (см. ниже): без него
   кольцо .avatar.answered/.pending (box-shadow: ...rgba(var(--glow,
   255,255,255)...) в шапке дуэли (.duel-strip-avatar) падало на дефолт
   255,255,255 — белое кольцо вместо цвета игрока, разница атакующий/
   защищающийся была почти не видна. */
.avatar.p0 { --glow: 107,125,143; background: radial-gradient(circle at 32% 28%, rgba(255,255,255,0.4), transparent 45%), #6b7d8f; }
.avatar.p1 { --glow: 127,154,74; background: radial-gradient(circle at 32% 28%, rgba(255,255,255,0.4), transparent 45%), #7f9a4a; }
.avatar.p2 { --glow: 193,91,72; background: radial-gradient(circle at 32% 28%, rgba(255,255,255,0.4), transparent 45%), #c15b48; }

/* Силуэт-иконка поверх заливки цветом — чтобы кружок читался как "аватар
   игрока", а не как нейтральная цветная точка (важно в duel-vs-header, где
   по кружкам определяют, кто атакует, а кто защищается). Если у игрока
   появится своя картинка (background-image на .avatar), силуэт нужно будет
   спрятать через ту же обёртку, что положит картинку — здесь такого случая
   пока нет ни в одном месте кода. */
.avatar::after {
  content: "";
  position: absolute;
  inset: 0;
  background-color: rgba(255, 255, 255, 0.92);
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 12c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm0 2c-3.33 0-10 1.68-10 5.01V21h20v-1.99c0-3.33-6.67-5.01-10-5.01z'/></svg>");
  mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 12c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm0 2c-3.33 0-10 1.68-10 5.01V21h20v-1.99c0-3.33-6.67-5.01-10-5.01z'/></svg>");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: 60%;
  mask-size: 60%;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));
  pointer-events: none;
}

/* Выбранная в профиле аватарка (VanqAvatars, game.js/main.js кладут её
   background-image инлайн-стилем) — силуэт-заглушку прячем, он больше не
   нужен, своя картинка и так уже читается как "аватар". */
.avatar.has-pic::after {
  display: none;
}

.chip-text {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1px;
  /* Растягивается на всё свободное место в фиксированной карточке, сжимается
     вплоть до многоточия у имени, если имени не хватает места. min-width:0
     обязателен — без него flex-элемент не сжимается меньше своего
     содержимого, и text-overflow:ellipsis у .chip-name не сработает. */
  flex: 1 1 auto;
  min-width: 0;
}

.chip-name {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  letter-spacing: 0.1px;
}

.score-chip.me {
  border-color: rgba(224, 188, 126, 0.8);
  box-shadow: 0 0 0 1px rgba(224, 188, 126, 0.25);
}

.score-chip .score-num {
  /* relative обязателен: .score-fly-ring (position:absolute) вкладывается
     сюда же при попадании очков — без этого якоря кольцо позиционируется
     от первого предка с position (обычно .scoreboard-corner/.score-chip
     выше по дереву) и заметно "моргает" не на своём месте. */
  position: relative;
  display: inline-block;
  /* .chip-text — flex-колонка, без этого число растягивалось бы на всю её
     ширину (стандартный stretch у flex-детей) — тогда кольцо-искра
     (.score-fly-ring, inset:-6px от границ этого элемента) обхватывало бы
     пустое место справа от цифры, а не саму цифру. */
  align-self: flex-start;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  font-size: 25px;
  line-height: 1.05;
  color: var(--text);
}

/* "Искра со шлейфом" — летящее +N/-N от территории (или от аватарки) к
   бейджу очков при начислении/списании (game.js: spawnScoreFly). Элементы
   искры/подписи навешиваются на document.body с position:fixed, поэтому
   координаты в JS считаются как есть, без пересчёта под какой-либо
   контейнер. */
.score-fly-spark {
  position: fixed;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 9000;
  box-shadow: 0 0 16px 5px currentColor, 0 0 4px 2px currentColor;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 900;
  /* color наследуется из инлайна (game.js: currentColor и для box-shadow,
     и для самого значка ▲/▼) — тёмная обводка ниже держит контраст даже
     когда значок того же тона, что и заливка. */
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.85);
}

.score-fly-label {
  position: fixed;
  font-weight: 800;
  font-size: 20px;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  z-index: 9000;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.5);
  animation: scoreFlyLabel 0.7s ease-out forwards;
}

@keyframes scoreFlyLabel {
  0% { opacity: 0; transform: translateY(0) scale(0.8); }
  18% { opacity: 1; transform: translateY(-10px) scale(1.05); }
  55% { opacity: 1; transform: translateY(-16px) scale(1); }
  100% { opacity: 0; transform: translateY(-26px) scale(0.9); }
}

.score-fly-impact {
  animation: scoreFlyImpact 0.4s ease-out;
}

@keyframes scoreFlyImpact {
  0% { transform: scale(1.5); filter: brightness(1.8); }
  100% { transform: scale(1); filter: brightness(1); }
}

.score-fly-ring {
  position: absolute;
  inset: -6px;
  border-radius: 999px;
  border: 2px solid currentColor;
  pointer-events: none;
  animation: scoreFlyRing 0.5s ease-out forwards;
}

@keyframes scoreFlyRing {
  0% { opacity: 0.8; transform: scale(0.6); }
  100% { opacity: 0; transform: scale(1.9); }
}

/* Цветная подсветка карточки игрока в момент удара — зелёная/красная, в
   отличие от нейтрально-золотой искры в полёте (см. spawnScoreFly). Через
   box-shadow, а не через background: у .score-chip уже висит
   transition на background (shorthand), и JS-присвоенный inline
   background-color на таком элементе на практике не подхватывался —
   проверено на макете, box-shadow того же бага не имеет. */
.score-chip.score-fly-hit {
  animation: scoreFlyHit 0.9s ease-out;
}

@keyframes scoreFlyHit {
  0% { box-shadow: 0 0 0 3px var(--hit-glow), 0 0 26px 6px var(--hit-glow); }
  100% { box-shadow: 0 0 0 0px transparent, 0 0 0px 0px transparent; }
}

.question-card {
  background: var(--panel);
  border: 1px solid rgba(255, 255, 255,0.06);
  border-radius: var(--radius);
  padding: 28px 24px;
}

.question-category {
  display: inline-block;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--accent-2);
  background: rgba(224, 188, 126,0.1);
  padding: 4px 10px;
  border-radius: 999px;
  margin-bottom: 12px;
}

.question-text {
  font-size: 20px;
  line-height: 1.4;
  margin-bottom: 18px;
}

.timer-wrap {
  height: 8px;
  background: var(--bg-soft);
  border-radius: 999px;
  overflow: hidden;
  margin-bottom: 20px;
}

.timer-row {
  position: absolute;
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  width: 40%;
  min-width: 220px;
  z-index: 30;
  display: flex;
  align-items: center;
  pointer-events: none;
}

/* "Отвечайте!" — напоминание для игрока, пока он реально участвует в
   дуэли (MC или тай-брейк) и ещё не ответил (game.js, updateAnswerReminder).
   Чуть ниже .timer-row (та занимает верхние ~8-16px), тот же язык, что у
   других всплывающих уведомлений игры (золотая пилюля, влёт сверху). */
.answer-reminder {
  position: absolute;
  top: 26px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 31;
  /* ×2 от исходного размера (padding/шрифт/тени) — запрошенное увеличение. */
  padding: 18px 52px;
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(224, 188, 126, 0.95), rgba(200, 150, 78, 0.95));
  color: #2e1f10;
  font-family: "Cinzel", serif;
  font-weight: 800;
  font-size: 32px;
  letter-spacing: 0.03em;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4), 0 0 48px rgba(224, 188, 126, 0.35);
  pointer-events: none;
  animation: answerReminderIn 0.3s cubic-bezier(0.2, 0.8, 0.3, 1);
}

.answer-reminder.leaving {
  animation: answerReminderOut 0.35s cubic-bezier(0.4, 0, 0.6, 1) forwards;
}

@keyframes answerReminderIn {
  from { transform: translateX(-50%) translateY(-52px); opacity: 0; }
  to { transform: translateX(-50%) translateY(0); opacity: 1; }
}

@keyframes answerReminderOut {
  from { transform: translateX(-50%) translateY(0); opacity: 1; }
  to { transform: translateX(-50%) translateY(-68px); opacity: 0; }
}

.timer-label {
  display: none;
}

.timer-row .timer-wrap {
  flex: 1;
  margin-bottom: 0;
}

.timer-bar {
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
  border-radius: 999px;
  transition: width 0.2s linear;
}

/* Как в "Кто хочет стать миллионером": 2 варианта слева, 2 справа, а не
   столбиком друг под другом. Вопросов с другим числом вариантов в игре нет
   (все 20 в questions-data.js — ровно по 4), поэтому колонки не завязаны на
   их количество отдельным условием. */
.options {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

.option {
  text-align: left;
  padding: 14px 18px;
  background: var(--bg-soft);
  border: 1px solid var(--panel-2);
  border-radius: 10px;
  font-size: 16px;
  color: var(--text);
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}

.option:hover:not(:disabled) {
  border-color: var(--accent);
  background: var(--panel-2);
}

.option:disabled {
  cursor: default;
  opacity: 0.7;
}

.option.correct {
  background: rgba(158, 207, 122,0.18);
  border-color: var(--good);
}

.option.wrong {
  background: rgba(224, 122, 95,0.15);
  border-color: var(--bad);
}

.waiting-note {
  margin-top: 16px;
  text-align: center;
  color: var(--text-dim);
  /* Было 20px — хватало для обычного текста, но .duel-result-pill (28px
     шрифт + padding 8px) заметно выше: без запаса появление баннера
     "X захватывает территорию!" ощутимо раздвигало окно вопроса вниз. */
  min-height: 56px;
}

/* "Кто уже ответил" в дуэли (обычный MC-вопрос и тай-брейк) — не счётчик
   "(1/2)" и не "Отвечайте!" в тексте, а рамка-табличка ПОД вариантами
   ответа (не над ними — обычный поточный элемент сразу после #options, не
   position:absolute), с той стороны, где сидит атакующий/защищающийся (те
   же стороны, что у их аватарок в .duel-vs-header — атакующий слева,
   защищающийся справа). Оформление — тот же золотой кант и градиент, что
   у .duel-strip-name (табличка с именем над аватаркой), чтобы читалось
   одним стилем. Каждая половина независима и появляется сама по себе, как
   только этот конкретный игрок ответил (см. renderAnsweredSides в
   game.js); пока не ответил — .hidden, места не занимает. */
/* Оба слота ВСЕГДА участвуют в flex-раскладке (см. .duel-answered-side
   ниже — visibility, не display:none) — иначе, если убрать невидимый из
   потока при единственном видимом, justify-content:space-between с одним
   оставшимся элементом схлопывается до flex-start (так по спеке), и
   бейдж защищающегося уезжал бы налево, на чужую сторону. */
.duel-answered-row {
  display: flex;
  justify-content: space-between;
  margin-top: 14px;
}

.duel-answered-side {
  /* Побольше по горизонтали (padding шире), одна строка — не переносится.
     Без рамки — это просто закрашенный бейдж-пилюля, форму даёт border-
     radius, а не border. */
  padding: 8px 26px;
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(224, 188, 126, 0.22), rgba(46, 31, 16, 0.94));
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4);
  font-size: 28px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--text-dim);
  text-align: center;
  white-space: nowrap;
  pointer-events: none;
  visibility: hidden;
  /* Фикс высоты — не только видимость: пустой (без текста) и заполненный
     ("Бот 1 ответил") варианты иначе давали бы разную высоту строки, и
     появление рамки на деле всё равно двигало бы окно вопроса.
     box-sizing здесь border-box (глобальный ресет), поэтому min-height
     обязан включать вертикальный padding сам — иначе он на деле меньше,
     чем реально нужно строке текста, и бейдж при появлении текста всё
     равно раздувается на высоту паддинга (8px×2 = 16px). */
  min-height: calc(1.3em + 16px);
}

/* Быстрый вылет снизу окна вопроса — общее и для обычной MC-дуэли, и для
   тай-брейка (оба используют один и тот же .duel-answered-side/
   renderAnsweredSides в game.js). */
.duel-answered-side.is-visible {
  visibility: visible;
  animation: duelAnsweredIn 0.25s cubic-bezier(0.2, 0.8, 0.3, 1);
}

/* Уход — не мгновенное visibility:hidden, а такой же быстрый вылет, только
   вниз и наоборот (исчезает туда же, откуда появилось). JS (renderAnswered-
   Sides) сперва вешает этот класс и только СПУСТЯ длительность анимации
   реально прячет элемент — см. DUEL_ANSWERED_EXIT_MS в game.js. */
.duel-answered-side.is-leaving {
  visibility: visible;
  animation: duelAnsweredOut 0.22s cubic-bezier(0.4, 0, 0.6, 1) forwards;
}

@keyframes duelAnsweredIn {
  0% { transform: translateY(22px); opacity: 0; }
  100% { transform: translateY(0); opacity: 1; }
}

@keyframes duelAnsweredOut {
  0% { transform: translateY(0); opacity: 1; }
  100% { transform: translateY(22px); opacity: 0; }
}

/* Итог хода ("X захватывает/отстаивает территорию!", duelWinnerText в
   game.js) — та же рамка и тот же размер шрифта, что у "Имя ответил"
   (.duel-answered-side), но одна, по центру: inline-block, а не отдельный
   слот слева/справа — оборачивается вокруг #waiting-note (у того уже
   text-align:center, это и центрирует пилюлю). */
.duel-result-pill {
  display: inline-block;
  padding: 8px 26px;
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(224, 188, 126, 0.22), rgba(46, 31, 16, 0.94));
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4);
  font-size: 28px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--text-dim);
  white-space: nowrap;
  /* Тот же вылет снизу, что и у "Имя ответил" (duelAnsweredIn) — элемент
     каждый раз создаётся заново (innerHTML), поэтому анимация играет сама,
     без reflow-трюков. */
  animation: duelAnsweredIn 0.3s cubic-bezier(0.2, 0.8, 0.3, 1);
}

.duel-answered-side b {
  font-weight: 800;
}

/* ---- map ---- */

.map {
  width: 100%;
  height: 100%;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: scale(1);
  /* Плавное "приближение камеры" (camera.js) — на #map, а не на
     #map-wrap: там же лежат оверлеи (баннеры, карточка вопроса), которые
     масштабировать вместе с картой не нужно. */
  transition: transform 1.1s cubic-bezier(0.2, 0.7, 0.3, 1);
}

.map.camera-zoomed {
  transform: scale(1.1);
}

.map svg {
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  display: block;
}

/* filter на группе территорий считает тень по силуэту ОБЪЕДИНЁННОЙ фигуры:
   стыки между соседними территориями внутри суши не дают перепада альфы и
   тени не получают, а вот настоящий внешний край карты (побережье) —
   получает, причём один раз, а не дважды на стыке двух путей. Это и есть
   "внешние границы" из задачи — без готового контура берега строить его
   отдельно не нужно, тень сама ляжет только по кромке. */
.map .territories-group {
  filter: drop-shadow(0 0 14px rgba(10, 6, 2, 0.45));
}

/* Базовое (нейтральное) свечение — только запасной вариант до первого
   рендера. Как только territory получает владельца, game.js выставляет
   свой inline style.filter (цвет владельца) прямо на path и полностью
   перекрывает это правило — inline всегда сильнее классового. */
.map path.terr {
  transition: filter 0.12s ease;
  cursor: default;
  filter: drop-shadow(0 0 2px rgba(200, 150, 90, 0.25));
}

/* Узор-сетка поверх закрашенных территорий (game.js/menu-sim.js,
   TERR_GRID_ENABLED) — сам паттерн чёрный и непрозрачный, 50% даёт эта
   прозрачность на клоне территории поверх. */
.terr-grid-overlay {
  opacity: 0.5;
}

.map path.terr.interactive {
  cursor: pointer;
  animation: terrPulse 1.4s ease-in-out infinite;
}

/* Курсоры атаки/ремонта/захвата (cursor_attack/shield/place.png) — не
   статичный CSS cursor:url(), а своя картинка-follower (#game-cursor-icon,
   заведена и позиционируется в game.js), потому что обычный OS-курсор нельзя
   ни анимировать (пульсация), ни дать ему CSS drop-shadow — браузер рисует
   курсор как есть, без фильтров. Системный курсор здесь прячем (cursor:none),
   а сама картинка следует за мышью отдельным position:fixed элементом. */
.map path.terr.interactive.action-attack,
.map path.terr.interactive.action-repair,
.map path.terr.interactive.action-claim {
  cursor: none;
}

#game-cursor-icon {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 9999;
  pointer-events: none;
  transform: translate(-50%, -50%) scale(1);
  filter:
    drop-shadow(0 3px 4px rgba(0, 0, 0, 0.55))
    drop-shadow(0 0 8px rgba(0, 0, 0, 0.35));
  animation: gameCursorPulse 1s ease-in-out infinite;
}

@keyframes gameCursorPulse {
  0%, 100% { transform: translate(-50%, -50%) scale(0.92); }
  50% { transform: translate(-50%, -50%) scale(1.1); }
}

.map path.terr.interactive:hover {
  filter: brightness(1.3);
  animation: terrHoverPulse 0.9s ease-in-out infinite;
  transform-origin: center;
  transform-box: fill-box;
}

.map path.terr.interactive:hover:not(.attack) {
  opacity: 0.5;
}

.map path.terr.interactive.attack {
  animation: terrPulseOwner 1.4s ease-in-out infinite;
}

@keyframes terrPulseOwner {
  0%, 100% { opacity: 0.7; }
  50% { opacity: 1; }
}

.option.selected {
  border-color: rgba(255, 255, 255,0.85);
  background: rgba(255, 255, 255,0.14);
}

@keyframes terrPulse {
  0%, 100% { opacity: 0.2; }
  50% { opacity: 0.6; }
}

@keyframes terrHoverPulse {
  0%, 100% { transform: scale(1.06); }
  50% { transform: scale(1.1); }
}

.map text {
  pointer-events: none;
  user-select: none;
  fill: #f0e0c4;
  stroke: #26190e;
  stroke-width: 2;
  opacity: 1;
  paint-order: stroke;
  font-weight: 700;
}

/* Ценность территории под названием (только бой, updateTerrValueLabel в
   game.js) — своя, более чёткая подпись: без потёртости, золотом, чтобы
   явно читалась как "цена", а не сливалась с именем. */
.map text.terr-value-label {
  font-family: "Segoe UI", system-ui, sans-serif;
  font-size: 15px;
  font-weight: 700;
  fill: #f0c060;
  stroke: #2a1808;
  stroke-width: 2.5;
  opacity: 0.95;
  filter: none;
}

/* Появление ярлыка цены "из пустоты" — и после баннера начала раунда, и в
   момент падения замка (тогда территория только что стала иметь цену). */
.map text.terr-value-label.appear {
  transform-box: fill-box;
  transform-origin: center;
  animation: terrValueAppear 0.6s cubic-bezier(0.2, 0.8, 0.3, 1.1) both;
}

@keyframes terrValueAppear {
  0% { opacity: 0; transform: scale(0.3); }
  100% { opacity: 0.95; transform: scale(1); }
}

.map-wrap {
  position: absolute;
  inset: 0;
}

.overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 5;
  border-radius: 12px;
}

.overlay::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(18, 11, 5, 0.78);
  border-radius: 12px;
}

.overlay-box {
  position: relative;
  z-index: 1;
  width: 92%;
  max-width: 1100px;
  max-height: 94%;
  overflow: hidden;
  background: var(--panel);
  border: 1px solid rgba(255, 255, 255,0.08);
  border-radius: var(--radius);
  padding: 20px 26px;
  box-shadow: 0 12px 40px rgba(0, 0, 0,0.45);
  zoom: 0.65;
}

.question-box {
  position: relative;
  z-index: 1;
  width: 92%;
  max-width: 1100px;
  min-height: 55vh;
  max-height: 94%;
  /* .duel-vs-header — полоса-шапка "атакующий/защищающийся" — специально
     выведена за padding окна (отрицательные margin, см. ниже) до самых его
     краёв, а аватарки в ней приподняты так, что торчат ВЫШЕ верхней границы
     окна (top: -32px у .duel-strip-avatar) — overflow должен быть visible,
     иначе эта часть аватарки просто обрежется рамкой окна. Квадратные углы
     самой полосы при этом скруглены отдельно (см. .duel-strip), чтобы не
     торчать мимо скруглённых углов окна без обрезки. */
  overflow: visible;
  background: var(--panel);
  border: 1px solid rgba(255, 255, 255,0.08);
  border-radius: var(--radius);
  padding: 20px 26px;
  box-shadow: 0 12px 40px rgba(0, 0, 0,0.45);
  /* Окно вопроса/ответов (в т.ч. числовых вопросов — guess-layout внутри
     того же question-box-inner) — 0.85, на 15% меньше исходного размера.
     zoom (а не transform:scale) честно пересчитывает layout в изменённом
     масштабе, поэтому min-height:55vh и вся раскладка внутри (варианты
     ответа, numpad, инпут) остаются пропорциональными. */
  zoom: 0.85;
}

/* Заголовок "атакующий / защищающийся" — полоса-баннер во всю ширину окна,
   вплотную к его верхним углам (отрицательные margin компенсируют padding
   .question-box: 20px сверху/по бокам). Аватарки крупные и приподняты так,
   что торчат ровно наполовину ВЫШЕ верхней границы окна (top:-32px при
   диаметре 64px — центр аватарки лежит точно на линии рамки), а не просто
   свисают внутрь — эффект "герба поединка", закреплённого на краю карточки.
   Обычный flow-элемент (не position:absolute) — когда видим, сам отодвигает
   текст вопроса вниз; когда .hidden (display:none), ничего вручную
   отодвигать/возвращать не нужно. */
.duel-vs-header {
  position: relative;
  /* Имя переехало НАД аватарку — под окном ему больше не нужен запас,
     но золотое кольцо (.duel-strip-ring-gold, inset до -12px) всё ещё
     выступает ниже, чем раньше выступала голая аватарка. */
  margin: -20px -26px 30px;
  z-index: 2;
}

.duel-strip {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  padding: 7px 0 9px;
  background: linear-gradient(180deg, rgba(224, 188, 126, 0.16), rgba(46, 31, 16, 0.92));
  border-bottom: 1px solid rgba(224, 188, 126, 0.4);
  border-radius: var(--radius) var(--radius) 0 0;
}

/* Картинка герба вместо текста "VS" — крупнее самой полосы .duel-strip и
   намеренно вылезает за её пределы (и за пределы .question-box, у той
   overflow:visible — см. выше): абсолютное позиционирование по центру
   верха полосы, а не в потоке (как был текст), чтобы не раздвигать/не
   менять размеры самого окна вопроса. z-index выше аватарок (2) — герб
   должен лежать поверх них, не под. */
.duel-strip-vs {
  position: absolute;
  top: -88px;
  left: 50%;
  /* Родной размер файла (150x146) — не уменьшаем. */
  width: 150px;
  height: auto;
  transform: translateX(-50%);
  z-index: 3;
  pointer-events: none;
  animation: vsGlowPulse 1.8s ease-in-out infinite;
}

/* Свечение пополам: два drop-shadow с противоположным горизонтальным
   сдвигом — левый (отрицательный dx) в цвете атакующего, правый
   (положительный dx) в цвете защищающегося. --atk-glow/--def-glow
   проставляет renderDuelVsHeader() в game.js (rgb-триплет через
   hexToRgb(COLOR[...])), дефолт — нейтральный янтарный, если по какой-то
   причине переменные не пришли. */
@keyframes vsGlowPulse {
  0%, 100% {
    filter:
      drop-shadow(0 4px 10px rgba(0, 0, 0, 0.55))
      drop-shadow(-5px 0 8px rgba(var(--atk-glow, 200,150,78), 0.55))
      drop-shadow(5px 0 8px rgba(var(--def-glow, 200,150,78), 0.55));
  }
  50% {
    filter:
      drop-shadow(0 4px 10px rgba(0, 0, 0, 0.55))
      drop-shadow(-7px 0 16px rgba(var(--atk-glow, 200,150,78), 0.95))
      drop-shadow(7px 0 16px rgba(var(--def-glow, 200,150,78), 0.95));
  }
}

.duel-strip-sub {
  min-height: 13px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-dim);
  letter-spacing: 0.04em;
}

.duel-strip-avatar {
  position: absolute;
  top: -32px;
  width: 64px;
  height: 64px;
  z-index: 2;
}

/* "Поженили" с окном вопроса: обычные аватарки (.avatar, табло/профиль) —
   голая цветная заливка + тонкое кольцо статуса, этого достаточно там, где
   вокруг уже панель того же стиля. Здесь же аватарка торчит НАД самим окном,
   на пустом фоне карты — без рамки она читалась чужеродной цветной точкой.
   Двойное кольцо, как в макете: golderRing/gapRing — ОТДЕЛЬНЫЕ соседние
   элементы внутри .duel-strip-avatar, ПЕРЕД самой аватаркой в DOM, а не
   ::before/::after САМОЙ аватарки. Раньше пробовали именно псевдоэлементы
   аватарки — они всегда красятся ПОСЛЕ собственного фона элемента (даже с
   отрицательным z-index), то есть либо перекрывают картинку/цвет, либо
   (через mask-дырку) дают совсем другую, более широкую геометрию колец, чем
   в макете. Обычные соседние элементы проще: они просто сплошные диски,
   каждый следующий (aватарка — последняя в DOM) рисуется поверх и
   перекрывает центр предыдущего — ровно то, что показано в Option2. */
.duel-strip-ring-gold,
.duel-strip-ring-gap {
  position: absolute;
  inset: 0;
  border-radius: 50%;
}

.duel-strip-ring-gold {
  inset: -12px;
  background: var(--accent);
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.5);
}

/* Свечение цветом игрока СНАРУЖИ золотого кольца — только когда игрок
   ответил (.is-answered на обёртке, см. renderDuelVsHeader в game.js,
   --glow туда же проставляет). Не на самой аватарке (её кольцо/бейдж
   галочки достаточно говорят про статус) — а как ореол вокруг всей рамки. */
.duel-strip-avatar.is-answered .duel-strip-ring-gold {
  box-shadow:
    0 6px 14px rgba(0, 0, 0, 0.5),
    0 0 18px 4px rgba(var(--glow, 200,150,78), 0.65);
}

.duel-strip-ring-gap {
  inset: -8px;
  background: var(--panel-2);
}

.duel-strip-avatar .avatar {
  position: absolute;
  inset: 0;
  width: 64px;
  height: 64px;
}

.duel-strip-avatar-atk { left: 46px; }
.duel-strip-avatar-def { right: 46px; }

/* Галочка "ответил" — отдельный бейдж НАД аватаркой (не подсветка кольца,
   см. .avatar.answered выше), вырастает из нуля пружинящим scale. */
.duel-strip-check {
  position: absolute;
  top: -22px;
  left: 50%;
  transform: translateX(-50%) scale(0);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  /* Молочно-кремовый, без жёлтого оттенка — не var(--good) (зелёный) и не
     var(--accent-2) (в ней есть жёлтая нота). */
  background: #f2ede3;
  color: #2e1f10;
  font-size: 26px;
  font-weight: 800;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.5), 0 0 0 2px var(--panel);
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
  z-index: 3;
  pointer-events: none;
}

.duel-strip-check.is-answered {
  transform: translateX(-50%) scale(1);
}

/* Салют из аватарки за верный ответ (task 1, spawnAvatarSalute() в game.js) —
   одноразовые искры-точки, позиционируются в JS через left/top (центр
   аватарки в момент клика) и --dx/--dy (случайный угол/дистанция разлёта).
   position:fixed — аватарка внутри .duel-strip, которая сама масштабируется
   через zoom на .question-box, а искры добавлены в document.body и с этим
   масштабом не связаны, летят в реальных экранных пикселях. */
.avatar-salute-spark {
  position: fixed;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 60;
  transform: translate(-50%, -50%);
  animation: avatarSaluteFly 0.65s cubic-bezier(0.15, 0.7, 0.3, 1) forwards;
}

@keyframes avatarSaluteFly {
  0% { transform: translate(-50%, -50%) translate(0, 0) scale(1); opacity: 1; }
  70% { opacity: 1; }
  100% { transform: translate(-50%, -50%) translate(var(--dx), var(--dy)) scale(0.3); opacity: 0; }
}

/* Имя — плашка-табличка НАД аватаркой (не строкой под окном, как раньше):
   та же "золотая полоса" стилистика, что у самого .duel-strip (линейный
   градиент + золотой кант), только в виде компактной таблички. Абсолютно
   спозиционирована внутри .duel-strip-avatar — тот же приём, что у
   .duel-strip-check (галочки), просто выше и по центру. */
.duel-strip-name {
  position: absolute;
  /* Плашка выросла (шрифт x2) — выше поднял, чтобы не наезжать на кольцо. */
  top: -70px;
  left: 50%;
  transform: translateX(-50%);
  /* На 20 знаков + "…" (обрезка по числу символов — в game.js, не здесь):
     запас с большим избытком, CSS text-overflow — только страховка. */
  max-width: 480px;
  padding: 8px 22px;
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(224, 188, 126, 0.22), rgba(46, 31, 16, 0.94));
  border: 1px solid rgba(224, 188, 126, 0.55);
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.45);
  font-weight: 700;
  font-size: 30px;
  color: var(--text);
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
  z-index: 3;
  pointer-events: none;
}

/* Статус "ответил" теперь — не цвет на самой аватарке, а отдельная
   галочка-бейдж над ней (.duel-strip-check, см. ниже) — так игрок остаётся
   виден без лишней подсветки. Кольцо аватарки — только цвет игрока,
   pending мягко пульсирует акцентным цветом, пока мы ждём ответ. */
.avatar.answered {
  box-shadow:
    0 0 0 5px rgba(var(--glow, 255,255,255), 1),
    0 4px 12px rgba(0,0,0,0.4);
}

.avatar.pending {
  animation: duelPendingPulse 1.6s ease-in-out infinite;
}

@keyframes duelPendingPulse {
  0%, 100% {
    box-shadow:
      0 0 0 5px rgba(var(--glow, 255,255,255), 1),
      0 0 10px 1px rgba(var(--glow, 255,255,255), 0.6),
      0 0 0 8px rgba(200, 150, 78, 0),
      0 4px 12px rgba(0,0,0,0.4);
  }
  50% {
    box-shadow:
      0 0 0 5px rgba(var(--glow, 255,255,255), 1),
      0 0 16px 3px rgba(var(--glow, 255,255,255), 0.85),
      0 0 0 8px rgba(200, 150, 78, 0.55),
      0 4px 12px rgba(0,0,0,0.4);
  }
}

/* Размеры .question-text и .option задаются ниже по файлу (clamp, рядом с
   остальным оформлением карточки) — здесь их дублировать не нужно, поздние
   правила всё равно перекрывают эти. */
.question-box .guess-input-wrap input {
  font-size: 18px;
}

#intro-overlay {
  inset: auto 0 auto 0;
  top: 14px;
  bottom: auto;
  align-items: flex-start;
  justify-content: center;
  padding: 0 12px;
  z-index: 20;
}

#intro-overlay::before {
  content: none;
}

#intro-text {
  width: auto;
  max-width: none;
  max-height: none;
  overflow: visible;
  padding: 20px 40px;
  text-align: center;
  /* Античный свиток: тёмный коричневый + двойная рамка (бронза снаружи,
     тонкая золотая линия внутри через inset-тень) — и свой акцент, чтобы
     не путаться с боевыми уведомлениями. */
  background: linear-gradient(180deg, rgba(38, 24, 12,0.97), rgba(22, 13, 6,0.97));
  border: 1px solid #8a5a2b;
  box-shadow: 0 8px 24px rgba(0, 0, 0,0.4), inset 0 0 0 3px rgba(200, 150, 78,0.22);
  text-shadow: 0 1px 4px rgba(0, 0, 0,0.6);
}

.intro-stage,
.intro-name,
.intro-castle {
  display: inline;
  margin: 0;
}

.intro-stage {
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 24px;
  margin-right: 16px;
}

.intro-name {
  font-size: 32px;
  font-weight: 700;
}

.intro-castle {
  font-size: 28px;
  color: var(--text-dim);
}

#phase-banner {
  z-index: 19;
  /* Раньше баннер раунда висел по центру экрана; двигаем его туда же,
     где всплывают остальные уведомления боя (draft-bar, attack-banner) —
     почти к самому верху экрана, с небольшим зазором. */
  align-items: flex-start;
  padding-top: 14px;
}

.phase-banner-box {
  position: relative;
  z-index: 1;
  padding: 28px 64px;
  zoom: 0.65;
  /* Тот же стеклянный язык, что у окна вопроса/лобби/заставки — золотая
     полоса сверху и тёплое стекло вместо прежней сплошной непрозрачной
     плашки. Торжественность раунда держит крупный кегль и свечение канта. */
  background:
    linear-gradient(90deg, transparent, var(--accent-2) 20%, var(--accent-2) 80%, transparent) top / 100% 3px no-repeat,
    radial-gradient(circle at 30% 0%, rgba(224, 188, 126, 0.16), transparent 60%),
    radial-gradient(circle at 80% 100%, rgba(200, 150, 78, 0.2), transparent 55%),
    linear-gradient(180deg, rgba(72, 54, 30, 0.82), rgba(38, 25, 14, 0.9));
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(224, 188, 126, 0.5);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0,0.4), inset 0 0 0 3px rgba(200, 150, 78,0.2);
  font-size: 44px;
  font-weight: 700;
  text-align: center;
  color: var(--text);
  text-shadow: 0 1px 4px rgba(0, 0, 0,0.6);
  animation: phaseBannerIn 0.3s ease-out both;
}

@keyframes phaseBannerIn {
  from { opacity: 0; transform: scale(0.9); }
  to { opacity: 1; transform: scale(1); }
}

/* Баннер места — и итоговый (партия закончилась, "Вы захватили весь мир" /
   "Вы заняли N место"), и промежуточный (выбыл, но партия ещё идёт — тогда
   виден дальше .place-banner-btn "Продолжить просмотр"). Карта нарочно
   остаётся видна под тёмной подложкой ("на фоне игры"), а не прячется за
   сплошным .overlay — партия для остальных игроков в это время всё ещё
   может продолжаться. */
.place-banner {
  position: absolute;
  inset: 0;
  z-index: 25;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}

.place-banner::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(18, 11, 5, 0.72);
  border-radius: 12px;
}

.place-banner-box {
  position: relative;
  z-index: 1;
  padding: 36px 56px;
  text-align: center;
  background:
    linear-gradient(90deg, transparent, var(--place-accent, var(--accent-2)) 20%, var(--place-accent, var(--accent-2)) 80%, transparent) top / 100% 3px no-repeat,
    radial-gradient(circle at 30% 0%, rgba(224, 188, 126, 0.16), transparent 60%),
    radial-gradient(circle at 80% 100%, rgba(200, 150, 78, 0.2), transparent 55%),
    linear-gradient(180deg, rgba(72, 54, 30, 0.88), rgba(38, 25, 14, 0.94));
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(224, 188, 126, 0.5);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0,0.4), inset 0 0 0 3px rgba(200, 150, 78,0.2);
  animation: phaseBannerIn 0.4s ease-out both;
}

.place-banner-title {
  font-size: 40px;
  font-weight: 700;
  color: var(--place-accent, var(--text));
  text-shadow: 0 1px 4px rgba(0, 0, 0,0.6);
  max-width: 70vw;
}

/* --place-accent — золото/серебро/бронза по месту, задаётся классом на
   #place-banner из JS (place-1/place-2/place-3). */
.place-banner.place-1 { --place-accent: #e8c869; }
.place-banner.place-2 { --place-accent: #cdd6de; }
.place-banner.place-3 { --place-accent: #d99a63; }

.place-banner-box .btn {
  margin-top: 22px;
}

.draft-bar {
  position: absolute;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  width: auto;
  min-width: 340px;
  max-width: 70%;
  z-index: 18;
  /* Тот же масштаб, что у баннера фазы (.phase-banner-box) — "чей ход" и
     "осталось выбрать" читаются тем же размером, что "Захват территорий". */
  zoom: 0.65;
  /* Постоянная статусная полоса — то же стекло, что у остальных
     уведомлений, но без золотой полосы/угловых засветок: сдержаннее
     "парадных" баннеров, эти на экране всё время. */
  background: linear-gradient(180deg, rgba(72, 54, 30, 0.72), rgba(38, 25, 14, 0.8));
  backdrop-filter: blur(16px) saturate(140%);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  border: 1px solid rgba(200, 150, 78, 0.35);
  border-radius: 24px;
  padding: 24px 40px;
  text-align: center;
  font-size: 34px;
  font-weight: 700;
  color: var(--text);
  text-shadow: 0 1px 4px rgba(0, 0, 0,0.6);
  pointer-events: none;
}

/* Тот же приём, что у .terr.own-pX/.avatar.pX — стекло тонируется цветом
   хода игрока вместо смены на сплошную непрозрачную заливку. */
.draft-bar.act-p0 { background: linear-gradient(180deg, rgba(107,125,143,0.32), rgba(24,54,74,0.75)); border-color: rgba(107,125,143,0.55); }
.draft-bar.act-p1 { background: linear-gradient(180deg, rgba(127,154,74,0.3), rgba(40,52,20,0.75)); border-color: rgba(127,154,74,0.55); }
.draft-bar.act-p2 { background: linear-gradient(180deg, rgba(193,91,72,0.3), rgba(70,30,22,0.75)); border-color: rgba(193,91,72,0.55); }

.game-loading {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  color: var(--text-dim);
}

.terr {
  border-radius: 10px;
  border: 1px solid var(--panel-2);
  background: var(--bg-soft);
  padding: 10px 8px;
  min-height: 74px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 6px;
  cursor: default;
  transition: transform 0.1s ease, border-color 0.1s ease;
}

.terr-empty {
  opacity: 0.15;
}

.terr-name {
  font-size: 12px;
  line-height: 1.25;
  color: var(--text);
  font-weight: 600;
}

.terr-val {
  font-size: 11px;
  color: var(--text-dim);
}

.terr-castle {
  border-width: 2px;
}

.terr-free {
  background: rgba(255, 255, 255,0.04);
}

.own-p0 { background: rgba(107,125,143,0.28); border-color: #6b7d8f; }
.own-p1 { background: rgba(127,154,74,0.24); border-color: #7f9a4a; }
.own-p2 { background: rgba(193,91,72,0.24); border-color: #c15b48; }

.terr.interactive {
  cursor: pointer;
  box-shadow: 0 0 0 2px rgba(200, 150, 78,0.6);
}

.terr.interactive:hover {
  transform-origin: center;
  transform-box: fill-box;
}

.terr.own-me {
  box-shadow: 0 0 0 3px rgba(255, 255, 255,0.35);
}

.legend {
  display: flex;
  gap: 14px;
  justify-content: center;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text-dim);
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--bg-soft);
  border: 1px solid var(--panel-2);
}

.legend-item.legend-me {
  color: var(--text);
  border-color: #ffffff;
  font-weight: 700;
}

.legend-item.legend-act {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px rgba(200, 150, 78,0.5);
  color: var(--text);
  font-weight: 700;
}

.swatch {
  width: 12px;
  height: 12px;
  border-radius: 4px;
  display: inline-block;
}

.swatch.p0 { background: #6b7d8f; }
.swatch.p1 { background: #7f9a4a; }
.swatch.p2 { background: #c15b48; }

.score-chip.p0 { --glow: 107,125,143; }
.score-chip.p1 { --glow: 127,154,74; }
.score-chip.p2 { --glow: 193,91,72; }

.score-chip.act {
  /* --glow приходит от .p0/.p1/.p2 — свечение хода красится цветом самого
     игрока, а не одним общим золотом. */
  border-color: rgba(var(--glow, 200, 150, 78), 0.7);
  animation: actGlowPulse 1.4s ease-in-out infinite;
}

@keyframes actGlowPulse {
  0%, 100% {
    box-shadow: 0 0 0 2px rgba(var(--glow, 200, 150, 78), 0.75), 0 0 16px 3px rgba(var(--glow, 200, 150, 78), 0.5);
  }
  50% {
    box-shadow: 0 0 0 3px rgba(var(--glow, 200, 150, 78), 0.95), 0 0 28px 7px rgba(var(--glow, 200, 150, 78), 0.8);
  }
}

.score-chip.score-dead {
  opacity: 0.45;
  text-decoration: line-through;
}

.guess-input-wrap {
  display: flex;
  gap: 10px;
  margin-top: 4px;
}

.guess-input-wrap input {
  flex: 1;
  padding: 12px 16px;
  font-size: 18px;
  color: var(--text);
  background: var(--bg-soft);
  border: 1px solid var(--panel-2);
  border-radius: 10px;
  outline: none;
  caret-color: transparent;
}

.my-answer {
  margin-top: 14px;
  padding: 14px 18px;
  font-size: 22px;
  font-weight: 700;
  color: var(--accent-2);
  background: var(--bg-soft);
  border: 1px solid var(--panel-2);
  border-radius: 10px;
  text-align: center;
}

.guess-input-wrap input:focus {
  border-color: var(--accent);
}

/* Grid, а не flex: раньше .guess-main было flex-колонкой, а её ширина
   считалась через width:320px внутри shrink-to-fit родителя — на практике
   браузер решал это неоднозначно и получившаяся полоса ввода оказывалась
   ýже, чем нужно, обрезая кнопку "Ответить". Grid считает ширины колонок
   заранее и однозначно, такой проблемы нет. Раскладка: строка ввода на всю
   ширину сверху; numpad и статус "кто ответил" — двумя колонками рядом под
   ней, вместо пустого разрыва между ними раньше. */
.guess-layout {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: center;
  column-gap: 32px;
  row-gap: 14px;
  align-items: start;
}

/* .guess-main в разметке оборачивает input-wrap/numpad/my-answer, но в
   раскладке они должны вести себя как отдельные ячейки грида (numpad — не
   там же, где ввод) — display:contents убирает сам .guess-main из
   раскладки, оставляя только его детей как прямые элементы грида. */
.guess-main {
  display: contents;
}

/* Раньше строка "ввод+кнопка" была ОДНИМ элементом, растянутым по центру
   обеих колонок, — из-за этого numpad (колонка 1) не совпадал по ширине с
   полем ввода внутри этой строки, и визуально они не выравнивались. Теперь
   input-wrap тоже display:contents — сам инпут и кнопка становятся
   отдельными ячейками грида: инпут в колонке 1 (той же, что numpad, и той
   же ширины — 172px, ровно под numpad), кнопка в колонке 2 (той же, что
   статус). */
.guess-input-wrap {
  display: contents;
}

.numpad {
  grid-column: 1 / 2;
  grid-row: 2;
  justify-self: center;
  margin: 0;
}

.my-answer {
  grid-column: 1 / 3;
  grid-row: 3;
  justify-self: center;
  margin-top: 0;
}

.guess-status {
  grid-column: 2 / 3;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  gap: 9px;
  align-self: start;
  width: 250px;
  /* У numpad есть свой margin-top:12px (историческое правило ниже по файлу) —
     без такого же отступа статус стоял на ~10px выше numpad. */
  margin-top: 12px;
}

/* Кнопка "Ответить" — та же колонка (2), что и статус, той же строкой, что
   инпут (1) — визуально она теперь стоит над статусом, зеркально тому, как
   numpad стоит под инпутом. */
.guess-input-wrap button {
  grid-column: 2;
  grid-row: 1;
  justify-self: center;
  align-self: center;
}

/* Скоуп через .guess-status .gstatus-row (а не голый .gstatus-row) —
   тот же класс переиспользуется в результатах боя (gboard) с совсем другими
   отступами/кеглем; без скоупа то, позднее правило по specificity того же
   уровня побеждало бы здесь в зависимости от порядка в файле. */
.guess-status .gstatus-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: var(--bg-soft);
  border: 1px solid var(--panel-2);
  border-radius: 10px;
  font-size: 16px;
}

.guess-status .gstatus-row.me {
  border-color: var(--accent);
}

.gstatus-name {
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.gstatus-ok {
  color: var(--text);
  font-weight: 700;
  white-space: nowrap;
}

.gstatus-wait {
  color: var(--text-dim);
  white-space: nowrap;
}

.guess-results {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.gboard-title {
  font-size: 24px;
  font-weight: 700;
  color: var(--accent-2);
  margin-bottom: 6px;
}

.answer-scale,
.scale-line,
.scale-correct,
.scale-correct-label,
.scale-dot,
.scale-name {
  display: none;
}

/* Подиум результатов числового вопроса — см. renderPodium() в game.js.
   Высота ступени задаётся инлайново (--pcolor и height), тут только форма:
   .win — победитель, залит цветом игрока и светится золотом; остальные —
   только контур того же цвета на тёмной подложке, текст приглушён. */
.podium {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 14px;
  margin: 18px 0 12px;
}

.podium-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1 1 0;
  max-width: 150px;
  min-width: 0;
}

.podium-name {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  color: var(--text-dim);
  margin-bottom: 2px;
}

.podium-col.win .podium-name {
  color: var(--text);
  font-weight: 700;
}

.podium-value {
  font-size: 13px;
  color: var(--text-dim);
  margin-bottom: 10px;
  white-space: nowrap;
}

.podium-col.win .podium-value {
  color: var(--text);
  font-weight: 600;
}

.podium-step {
  /* Высоту (34-130px) задаёт JS в renderPodium() — она и есть точность
     ответа, поэтому тут её быть не должно: min-height конфликтовал бы с
     самой короткой ступенью ("не отвечал", 18px) и обнулял бы разницу. */
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  border-radius: 10px 10px 4px 4px;
  border: 2px solid var(--pcolor);
  background: color-mix(in srgb, var(--pcolor) 12%, transparent);
  transition: height 0.4s ease;
}

.podium-step .podium-answer {
  font-size: 17px;
  font-weight: 800;
  color: var(--pcolor);
  opacity: 0.75;
  white-space: nowrap;
}

.podium-step.win {
  background: color-mix(in srgb, var(--pcolor) 55%, transparent);
  box-shadow: 0 0 24px color-mix(in srgb, var(--pcolor) 55%, transparent),
    0 0 40px rgba(200, 150, 78, 0.35);
  border-color: var(--pcolor);
}

.podium-step.win .podium-answer {
  color: #ffffff;
  opacity: 1;
  text-shadow: 0 0 12px rgba(0, 0, 0, 0.4);
}

/* ---- тай-брейк: дуэльные карточки (замена подиума в окне результата) ----
   Макет выбран из 5 вариантов, собранных в Claude Design ("Duel Cards").
   Раскрывается в стадии по времени (см. TBC_RING_DELAY и таймер в
   renderTieBreakCards(), game.js): карточки с жетоном VS влетают первыми,
   затем — верный ответ, затем у победителя загорается ореол (плюс тряска
   карточки и искры из spawnAvatarSalute), и последним — баннер исхода. */
.tbc-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.tbc-correct {
  font-family: "Cinzel", serif;
  font-weight: 700;
  font-size: 26px;
  color: var(--text-dim);
  text-align: center;
  margin-bottom: 86px;
  opacity: 0;
  animation: tbcFadeUp 0.5s 1.15s ease forwards;
}
.tbc-correct b {
  color: var(--text);
  text-shadow: 0 0 20px rgba(224, 188, 126, 0.45);
}

@keyframes tbcFadeUp {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

.tbc-arena {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 10px;
}

/* Внешний узел карточки держит только форму (фон/рамка/тень) и влёт
   (tbcSlideL/R, opacity+transform, с forwards) — сама раскладка содержимого
   и встряска живут на .tbc-card-inner. Разделены НАРОЧНО: одна и та же
   анимация из двух источников на одном элементе конфликтует по CSS-
   свойству transform/opacity, и позже добавленная (tbcShake) стирала бы
   forwards-состояние влёта — карточка на миг схлопывалась до opacity:0
   (тот самый баг "пропадает во время салюта"). На разных узлах конфликта
   нет: у каждого своё independent-свойство transform. */
/* Поверхность консольная, как у клавиш и панелей окна вопроса:
   полупрозрачная подложка вместо плотного тёплого градиента — сквозь неё
   читаются сканлайны фона, и карточка перестаёт выглядеть накладкой из
   другого набора. Геометрия, Cinzel-цифры, корона и ореолы не тронуты. */
.tbc-card {
  width: 225px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.04);
  /* рамка в цвете игрока — так же, как на карточках захвата */
  border: 1px solid color-mix(in srgb, var(--pcolor) 45%, transparent);
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.4);
  position: relative;
  opacity: 0;
}
.tbc-card.tbc-slide0 {
  transform: translateX(60px) rotate(3deg);
  animation: tbcSlideL 0.6s 0.3s cubic-bezier(0.2, 0.75, 0.3, 1) forwards;
}
.tbc-card.tbc-slide1 {
  transform: translateX(-60px) rotate(-3deg);
  animation: tbcSlideR 0.6s 0.45s cubic-bezier(0.2, 0.75, 0.3, 1) forwards;
  z-index: 2;
}
@keyframes tbcSlideL { to { opacity: 1; transform: translateX(-14px) rotate(-2deg); } }
@keyframes tbcSlideR { to { opacity: 1; transform: translateX(14px) rotate(2deg) scale(1.22); } }

.tbc-card.tbc-win {
  width: 245px;
  border-color: color-mix(in srgb, var(--pcolor) 60%, transparent);
  box-shadow:
    0 24px 48px rgba(0, 0, 0, 0.5),
    0 0 60px color-mix(in srgb, var(--pcolor) 55%, transparent),
    0 0 110px color-mix(in srgb, var(--pcolor) 30%, transparent);
}

.tbc-ring {
  position: absolute;
  inset: -30px;
  border-radius: 40px;
  background: radial-gradient(circle, color-mix(in srgb, var(--pcolor) 48%, transparent), transparent 70%);
  opacity: 0;
  z-index: -1;
  animation: tbcRingIn 0.4s 1.6s ease forwards, tbcRingPulse 2.4s 2s ease-in-out infinite;
}
@keyframes tbcRingIn { to { opacity: 0.5; } }
@keyframes tbcRingPulse {
  0%, 100% { opacity: 0.35; transform: scale(0.96); }
  50% { opacity: 0.7; transform: scale(1.06); }
}

/* Корона победителя — влетает вместе с ореолом/тряской/искрами (та же
   TBC_RING_DELAY = 1.6с в game.js), а не сразу с карточкой: до этого
   момента экран ещё не "объявил" победителя. */
.tbc-crown {
  position: absolute;
  top: -34px;
  left: 50%;
  z-index: 4;
  opacity: 0;
  transform: translateX(-50%) translateY(10px) scale(0.4) rotate(-10deg);
  animation: tbcCrownDrop 0.5s 1.6s cubic-bezier(0.3, 1.6, 0.4, 1) forwards;
  filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.5));
}
@keyframes tbcCrownDrop {
  to { opacity: 1; transform: translateX(-50%) translateY(0) scale(1) rotate(0deg); }
}

.tbc-card-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 23px 17px 19px;
}

/* Встряска — короткая, добавляется/снимается JS-таймером (TBC_RING_DELAY) в
   тот же момент, когда стартует ореол и летят искры (spawnAvatarSalute). */
.tbc-card-inner.tbc-shake {
  animation: tbcShake 0.4s ease;
}
@keyframes tbcShake {
  10%, 90% { transform: translate3d(12px, -1px, 0) rotate(2deg); }
  20%, 80% { transform: translate3d(-10px, 2px, 0) rotate(2deg); }
  30%, 50%, 70% { transform: translate3d(9px, -2px, 0) rotate(2deg); }
  40%, 60% { transform: translate3d(-9px, 1px, 0) rotate(2deg); }
}

.tbc-name {
  font-weight: 800;
  font-size: 15px;
  color: var(--pcolor);
  margin-bottom: 12px;
  text-align: center;
}
.tbc-card.tbc-win .tbc-name { font-size: 16.5px; }

.tbc-answer {
  font-family: "Cinzel", serif;
  font-weight: 900;
  font-size: 34px;
  color: var(--text);
  line-height: 1;
}
.tbc-card.tbc-win .tbc-answer {
  font-size: 41px;
  color: #ffffff;
  text-shadow: 0 0 16px color-mix(in srgb, var(--pcolor) 70%, transparent);
}

.tbc-divider {
  width: 32px;
  height: 1px;
  background: rgba(255, 255, 255, 0.14);
  margin: 12px 0;
}

.tbc-stats {
  display: flex;
  gap: 9px;
}
.tbc-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 7px 11px;
  background: rgba(0, 0, 0, 0.22);
  border-radius: 10px;
  min-width: 52px;
}
.tbc-stat .l {
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.tbc-stat .v {
  font-size: 14px;
  font-weight: 800;
  color: var(--text);
}
.tbc-card.tbc-win .tbc-stat .v { color: #ffffff; }

/* Ничья по отклонению, решило время ответа (см. isTie/tbc-speed в game.js) —
   у победителя именно "Время" крупнее соседнего "Откл.", чтобы глаз сразу
   находил цифру, которая и определила исход. */
.tbc-stat-decisive .v { font-size: 17px; }

.tbc-speed {
  margin-top: 12px;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.6);
  box-shadow: 0 0 12px rgba(255, 255, 255, 0.5), 0 0 3px rgba(255, 255, 255, 0.7);
  font-size: 10.5px;
  font-weight: 700;
  color: #ffffff;
  opacity: 0;
  animation: tbcFadeUp 0.4s 1.75s ease forwards;
}

.tbc-vs {
  width: 68px;
  height: 68px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--accent-2), var(--accent) 72%);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "Cinzel", serif;
  font-weight: 900;
  font-size: 19px;
  color: #2e1f10;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5), 0 0 0 5px var(--panel-2);
  z-index: 3;
  opacity: 0;
  transform: scale(0.3);
  animation: tbcVsPop 0.5s 0.7s cubic-bezier(0.3, 1.6, 0.4, 1) forwards;
}
@keyframes tbcVsPop { to { opacity: 1; transform: scale(1); } }

.tbc-banner {
  margin-top: 19.5px;
  display: flex;
  align-items: center;
  gap: 7.5px;
  padding: 11px 19.5px;
  border-radius: 999px;
  background: linear-gradient(135deg, rgba(200, 150, 78, 0.22), rgba(224, 188, 126, 0.12));
  box-shadow: 0 0 40px rgba(200, 150, 78, 0.3);
  font-family: "Cinzel", serif;
  font-weight: 700;
  font-size: 12.75px;
  color: var(--text);
  text-shadow: 0 0 14px rgba(200, 150, 78, 0.5);
  opacity: 0;
  animation: tbcFadeUp 0.55s 2.2s ease forwards;
}

.gboard-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: var(--bg-soft);
  border: 1px solid var(--panel-2);
  border-radius: 8px;
  font-size: 14px;
}

.gboard-row.first {
  border-color: var(--accent);
  background: linear-gradient(120deg, rgba(200, 150, 78,0.15), var(--bg-soft));
}

.gboard-row.me {
  box-shadow: 0 0 0 1px rgba(255, 255, 255,0.25);
}

.gboard-row .place {
  font-weight: 700;
  color: var(--accent-2);
  width: 20px;
}

.gboard-ans {
  margin-left: auto;
  color: var(--text);
  white-space: nowrap;
}

.gboard-picks {
  color: var(--text-dim);
  font-size: 12px;
  white-space: nowrap;
}

/* ---- results ---- */

/* Оверлей результатов — поверх ЕЩЁ ВИДИМОЙ карты боя (тот же приём, что у
   .place-banner: карта остаётся на фоне, а не прячется целиком за
   отдельным screen — партия могла закончиться, но карта всё равно должна
   быть настоящей картой этой партии, а не декоративной картой меню). Живёт
   внутри #map-wrap, а не отдельным .screen. */
.results-overlay {
  position: absolute;
  inset: 0;
  z-index: 26;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}

.results-overlay::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(18, 11, 5, 0.6);
  border-radius: 12px;
}

.results-close {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 2;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid rgba(224, 188, 126, 0.4);
  background: rgba(46, 31, 16, 0.7);
  color: var(--text);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.results-close:hover {
  border-color: var(--accent-2);
}

/* Крупная кнопка "В меню" — больше не внутри самой панели результатов
   (крестик там закрывает только панель, партия при этом никуда не
   девается), а отдельно, фиксированным углом экрана — доступна и с
   закрытой, и с открытой панелью. */
.results-menu-btn {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 24;
  width: auto;
  padding: 16px 36px;
  font-size: 17px;
}

/* .results-box переиспользует общий .menu-box/.auth-box (см. начало файла),
   но заметно легче: сплошная непрозрачная панель тут не нужна — под
   подиумом с тремя колонками и так остаётся много пустого места, плотная
   подложка только подчёркивала бы это. */
.results-box {
  position: relative;
  z-index: 1;
  zoom: 1.1;
  width: 92%;
  max-width: 460px;
  background: linear-gradient(180deg, rgba(35, 22, 12, 0.4), rgba(16, 10, 5, 0.5));
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
}

.results-title {
  margin-bottom: 22px;
  font-size: 26px;
}

/* Подиум — центральная колонна (1 место) выше и в центре, 2-е слева,
   3-е справа, как на спортивном пьедестале. align-items:flex-end и разная
   высота .podium-step задают ступеньки; сами колонны выстроены по порядку
   мест в разметке (JS кладёт 2-1-3), а не просто по возрастанию. Снизу
   márgin меньше, чем раньше: под подиумом больше нет кнопки "В меню" —
   place отступ отдаёт padding самого .results-box. */
.podium {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 14px;
  margin: 0 auto 4px;
  max-width: 520px;
}

.podium-col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.podium-col .avatar {
  width: 76px;
  height: 76px;
  margin-bottom: 10px;
  box-shadow: 0 0 0 3px rgba(var(--glow, 255,255,255), 0.9), 0 6px 18px rgba(0,0,0,0.5);
}

.podium-name {
  font-weight: 700;
  font-size: 16px;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-bottom: 4px;
}

.podium-score {
  font-size: 14px;
  color: var(--text-dim);
  margin-bottom: 10px;
}

.podium-step {
  width: 100%;
  border-radius: 10px 10px 0 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 10px;
  font-size: 34px;
  font-weight: 700;
  background: linear-gradient(180deg, rgba(200, 150, 78, 0.22), rgba(46, 31, 16, 0.7));
  border: 1px solid rgba(224, 188, 126, 0.4);
  border-bottom: none;
}

.podium-col-1 .podium-step { height: 128px; color: #e8c869; border-color: rgba(232, 200, 105, 0.6); }
.podium-col-2 .podium-step { height: 92px; color: #cdd6de; border-color: rgba(205, 214, 222, 0.55); }
.podium-col-3 .podium-step { height: 66px; color: #d99a63; border-color: rgba(217, 154, 99, 0.55); }

.podium-col-1 .avatar { box-shadow: 0 0 0 3px #e8c869, 0 6px 18px rgba(0,0,0,0.5); }
.podium-col-2 .avatar { box-shadow: 0 0 0 3px #cdd6de, 0 6px 18px rgba(0,0,0,0.5); }
.podium-col-3 .avatar { box-shadow: 0 0 0 3px #d99a63, 0 6px 18px rgba(0,0,0,0.5); }

@media (max-width: 480px) {
  .results-box { zoom: 1.1; }
  .podium-col .avatar { width: 56px; height: 56px; }
  .podium-step { font-size: 26px; }
  .podium-col-1 .podium-step { height: 96px; }
  .podium-col-2 .podium-step { height: 70px; }
  .podium-col-3 .podium-step { height: 50px; }
}

/* ---- modal ---- */

.modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0,0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 16px;
}

.modal-box {
  max-width: 480px;
  width: 100%;
  text-align: left;
  /* "Настройки" теперь совмещает "Как играть" + "Об игре" в одном окне —
     заметно длиннее любого прежнего содержимого модалки, а сама .modal-box
     раньше вообще не умела скроллиться (переполнение просто вылезало бы за
     тёмную подложку на невысоких экранах). max-height + скролл — не
     косметика, а необходимое следствие объединения разделов. */
  max-height: min(80vh, 640px);
  overflow-y: auto;
}

/* Профильные экраны (Профиль / Смена имени / Смена аватара) — окно
   фиксированной высоты. Иначе оно тянулось под содержимое (в хабе профиля
   оно одно, в списке аватарок — другое) и при переходах "прыгало" по
   размеру. Теперь окно одного размера, а сетка аватарок скроллится внутри
   него, а не растягивает его. */
.modal-box.modal-box--profile {
  height: min(72vh, 440px);
  display: flex;
  flex-direction: column;
}

.modal-box--profile .modal-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin-bottom: 0;
}

/* Хаб профиля — по центру окна (иначе контент прилипал бы к верху, а снизу
   оставалась пустота). */
.modal-box--profile .profile-hub {
  flex: 1 1 auto;
  justify-content: center;
}

/* Сетка аватарок занимает всё свободное место и прокручивается сама. */
.modal-box--profile #avatar-grid {
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;
}

/* Крестик закрытия — только на профильных окнах, вместо кнопки "Закрыть"
   (в окне фиксированной высоты она сжималась и выглядела чужеродно).
   Остальные модалки (настройки, "Покинуть партию") закрываются кнопкой как
   и раньше. */
.modal-x {
  display: none;
  position: absolute;
  top: 12px;
  right: 12px;
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(224, 188, 126, 0.3);
  background: rgba(0, 0, 0, 0.25);
  color: var(--text-dim);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  align-items: center;
  justify-content: center;
  transition: color 0.15s ease, border-color 0.15s ease;
  z-index: 3;
}

.modal-x:hover { color: var(--accent-2); border-color: var(--accent-2); }

.modal-box--profile .modal-x { display: flex; }
.modal-box--profile #modal-close { display: none; }
/* Чтобы длинный заголовок не наезжал на крестик. */
.modal-box--profile h3 { padding: 0 34px; }

.modal-box h3 {
  text-align: center;
  margin-bottom: 14px;
}

.modal-body {
  color: var(--text-dim);
  line-height: 1.6;
  margin-bottom: 20px;
}

.modal-body input {
  width: 100%;
  padding: 12px 16px;
  font-size: 16px;
  color: var(--text);
  background: var(--bg-soft);
  border: 1px solid var(--panel-2);
  border-radius: 10px;
  outline: none;
  margin-bottom: 14px;
  text-align: center;
}

.modal-body input:focus {
  border-color: var(--accent);
}

.modal-body .btn {
  width: 100%;
}

/* Профиль: ник и кнопка сохранения в одну строку (компактнее, чем прежние
   подпись + инпут + кнопка на всю ширину каждая отдельной строкой). */
.profile-row {
  display: flex;
  gap: 8px;
  margin-bottom: 18px;
}

.profile-row input {
  flex: 1 1 auto;
  min-width: 0;
  width: auto;
  margin-bottom: 0;
}

.profile-row .btn {
  width: auto;
  flex: 0 0 auto;
  padding-left: 18px;
  padding-right: 18px;
}

.profile-avatar-label {
  font-size: 13px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: 10px;
}

.avatar-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
  /* Окно выбора аватара не должно расти с каждой новой аватаркой: сама сетка
     ограничена по высоте и скроллится внутри. Иначе модалка тянулась под
     число аватарок (10 → 20 → 30...) и на невысоких экранах уезжала в
     скролл целиком, вместе с заголовком и кнопкой "Назад". */
  max-height: min(46vh, 340px);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Отступ под скроллбар и чтобы scale(1.08) при наведении не обрезался
     краем скролл-контейнера. */
  padding: 3px 8px 3px 3px;
  scrollbar-width: thin;
  scrollbar-color: rgba(224, 188, 126, 0.45) transparent;
}

.avatar-grid::-webkit-scrollbar { width: 8px; }
.avatar-grid::-webkit-scrollbar-track { background: transparent; }
.avatar-grid::-webkit-scrollbar-thumb {
  background: rgba(224, 188, 126, 0.35);
  border-radius: 8px;
}
.avatar-grid::-webkit-scrollbar-thumb:hover { background: rgba(224, 188, 126, 0.6); }

.avatar-pick {
  width: 100%;
  aspect-ratio: 1;
  border-radius: 50%;
  border: 2px solid transparent;
  background-size: cover;
  background-position: center;
  cursor: pointer;
  padding: 0;
  transition: transform 0.15s ease, border-color 0.15s ease;
}

.avatar-pick:hover {
  transform: scale(1.08);
}

.avatar-pick.selected {
  border-color: var(--accent-2);
  box-shadow: 0 0 0 2px rgba(224, 188, 126, 0.35);
}

@media (max-width: 480px) {
  .avatar-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* Хаб профиля — крупная аватарка и имя сверху, две отдельные кнопки
   ("Сменить имя"/"Сменить аватар") каждая открывает свой экран внутри той
   же модалки. Заменяет прежнюю форму "всё сразу одним окном". */
.profile-hub {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.profile-hub-avatar-el {
  width: 88px;
  height: 88px;
  margin-bottom: 14px;
}

/* Нет своей аватарки — нейтральная серая заливка вместо цвета игрока: вне
   партии у аккаунта ещё нет назначенного pX-цвета (тот выдаётся только на
   старте конкретной игры). */
.avatar.neutral {
  background: var(--panel-2);
}

.profile-hub-name {
  font-size: 19px;
  font-weight: 700;
  margin-bottom: 22px;
}

.profile-hub-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
}

.profile-hub-actions .btn {
  width: 100%;
}

.profile-modal-actions {
  display: flex;
  gap: 8px;
  margin-top: 4px;
}

.profile-modal-actions .btn {
  flex: 1 1 0;
  width: auto;
}

.profile-error {
  min-height: 18px;
  font-size: 13px;
  color: var(--bad);
  text-align: center;
  margin: 4px 0 10px;
}

.modal-body b {
  color: var(--text);
}

@media (max-width: 520px) {
  .logo { font-size: 42px; }
  .question-text { font-size: 17px; }
  .btn-lg { width: 100%; }
}

/* ==================== QUESTION WINDOW THEME (glassmorphism) ==================== */

/* Радиус — 12px, тот же, что у .modal-box/.lobby-box/.menu-tile (единый
   почерк HUD-панелей вместо прежних calc(var(--radius)*1.6)=22.4px). Угловое
   свечение раньше жило в ::before отдельным слоем — переехало прямо в
   background (доп. radial-gradient поверх обычного), чтобы освободить
   ::before/::after под угловые золотые засечки — тот же мотив, что у модалок,
   лобби и плиток меню. */
.question-box {
  /* Первый слой — тонкая золотая полоса у самого верха карточки (декор, НЕ
     настоящий таймер: реальный #timer-row — общий для карты и карточки
     элемент, используется и в фазе выбора цели атаки, где самой карточки
     ещё нет вообще, — переносить его внутрь .question-box нельзя, он бы
     пропадал именно тогда, когда нужен). Просто визуальный акцент по
     мотиву макета. */
  background:
    linear-gradient(90deg, transparent, var(--accent-2) 20%, var(--accent-2) 80%, transparent) top / 100% 3px no-repeat,
    radial-gradient(circle at 30% 0%, rgba(224, 188, 126, 0.15), transparent 60%),
    radial-gradient(circle at 80% 100%, rgba(200, 150, 78, 0.18), transparent 55%),
    linear-gradient(180deg, rgba(72, 54, 30, 0.75), rgba(38, 25, 14, 0.85));
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(200, 150, 78, 0.4);
  border-radius: 12px;
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.03) inset,
    0 8px 32px rgba(0, 0, 0, 0.55),
    0 0 60px rgba(200, 150, 78, 0.15);
  color: var(--text);
}

/* Угловые засечки — были 8px почти без свечения и терялись на карточке
   шириной под 1100px; увеличены и добавлено свечение, чтобы читались
   так же явно, как на макете. */
.question-box::before {
  content: "";
  position: absolute;
  width: 12px;
  height: 12px;
  background: var(--accent-2);
  transform: rotate(45deg);
  border-radius: 2px;
  box-shadow: 0 0 10px rgba(224, 188, 126, 0.8);
  z-index: 1;
  pointer-events: none;
  top: 14px;
  left: 14px;
}

.question-box > * {
  position: relative;
  z-index: 1;
}

.question-category {
  display: inline-block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-2);
  padding: 5px 14px;
  margin-bottom: 14px;
  background: rgba(224, 188, 126, 0.08);
  border: 1px solid rgba(224, 188, 126, 0.35);
  border-radius: 999px;
  box-shadow: 0 0 14px rgba(224, 188, 126, 0.25);
}

/* Крупный кегль намеренно: в игру смотрят с дивана, издалека, и среди
   игроков бывают люди со слабым зрением — вопрос и варианты должны читаться
   не прищуриваясь.
   Размер привязан к ВЫСОТЕ окна (vh): карточка растягивается вниз до 94%
   экрана (см. .question-box) и упирается именно в вертикаль, а не в ширину.
   Потолки подобраны замером на самом длинном вопросе базы (116 символов)
   при body.in-game — без этого класса #app схлопывается в нулевую высоту, и
   любые замеры вёрстки карточки врут. На 1920x1080 предел, за которым низ
   вариантов начинает обрезаться, — 82px/46px; берём заметно ниже, потому что
   у коротких вопросов такой кегль выглядел бы нелепо. */
.question-box .question-text {
  font-size: clamp(24px, min(3.4vw, 5.4vh), 60px);
  line-height: 1.3;
  font-weight: 600;
  margin: 0 0 16px;
  text-align: center;
  text-shadow: 0 0 18px rgba(200, 150, 78, 0.25);
}

.question-box .option {
  font-size: clamp(18px, min(2vw, 3.1vh), 34px);
}

/* display:contents переопределён выше (рядом с .guess-layout/.numpad) —
   здесь только оставшиеся свойства этого исторического дубля-селектора,
   которые под display:contents всё равно не действуют (gap/margin у
   элемента без своего бокса игнорируются), не удаляю только чтобы не
   плодить более узкий переезд правил без необходимости. */
.guess-input-wrap {
  gap: 10px;
  margin-bottom: 18px;
}

.guess-input-wrap input {
  /* Ширина ровно как у numpad (172px) и та же колонка (1) — инпут встаёт
     точно над numpad, без зазора/сдвига между "строкой ввода" и "цифровым
     блоком" под ней. */
  grid-column: 1;
  grid-row: 1;
  width: 172px;
  box-sizing: border-box;
  padding: 14px 10px;
  font-size: 22px;
  font-weight: 700;
  text-align: center;
  color: var(--text);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(200, 150, 78, 0.4);
  border-radius: var(--radius);
  outline: none;
  caret-color: var(--accent-2);
  transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}

.guess-input-wrap input::placeholder {
  color: var(--text-dim);
  font-weight: 500;
}

.guess-input-wrap input:focus {
  border-color: var(--accent-2);
  background: rgba(224, 188, 126, 0.08);
  box-shadow:
    0 0 0 3px rgba(224, 188, 126, 0.18),
    0 0 22px rgba(224, 188, 126, 0.35);
}

.numpad {
  display: grid;
  /* Раньше колонки были 1fr — на широкой карточке вопроса кнопки-кружки
     "плавали" далеко друг от друга. Фиксированная ширина колонки под
     размер кнопки + justify-content:center держит панель компактной. */
  grid-template-columns: repeat(3, 52px);
  justify-content: center;
  gap: 8px;
  margin: 12px auto 20px;
}

.numpad button {
  position: relative;
  width: 52px;
  height: 52px;
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(154, 163, 199, 0.25);
  border-radius: 50%;
  cursor: pointer;
  user-select: none;
  transition: transform 0.12s ease, background 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

.numpad button:hover {
  background: rgba(200, 150, 78, 0.14);
  border-color: rgba(200, 150, 78, 0.55);
  box-shadow: 0 0 16px rgba(200, 150, 78, 0.35);
}

.numpad button:active {
  transform: scale(0.9);
  background: rgba(200, 150, 78, 0.25);
  box-shadow: 0 0 22px rgba(200, 150, 78, 0.5);
}

.numpad button.numpad-act {
  border-radius: var(--radius);
  font-size: 16px;
  color: var(--accent-2);
  background: rgba(224, 188, 126, 0.07);
  border-color: rgba(224, 188, 126, 0.35);
}

.numpad button.numpad-act:hover {
  background: rgba(224, 188, 126, 0.16);
  border-color: rgba(224, 188, 126, 0.6);
  box-shadow: 0 0 16px rgba(224, 188, 126, 0.4);
}

.numpad button.numpad-act:active {
  transform: scale(0.92);
  color: var(--bad);
  border-color: rgba(255, 107, 107, 0.5);
  box-shadow: 0 0 18px rgba(255, 107, 107, 0.4);
}

.question-box .btn-primary {
  padding: 14px 22px;
  font-size: 16px;
  font-weight: 800;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
  color: #0b0d18;
  background: linear-gradient(135deg, var(--accent-2), var(--accent));
  border: none;
  border-radius: var(--radius);
  box-shadow:
    0 4px 18px rgba(200, 150, 78, 0.45),
    0 0 30px rgba(224, 188, 126, 0.25);
  transition: transform 0.15s ease, box-shadow 0.2s ease, filter 0.2s ease;
}

.question-box .btn-primary:hover {
  filter: brightness(1.08);
  box-shadow:
    0 6px 24px rgba(200, 150, 78, 0.55),
    0 0 40px rgba(224, 188, 126, 0.35);
}

.question-box .btn-primary:active {
  transform: scale(0.97);
}

.question-box .btn-primary:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  filter: grayscale(0.3);
  box-shadow: none;
}

.my-answer {
  margin-top: 16px;
  padding: 12px 16px;
  font-size: 16px;
  font-weight: 700;
  color: var(--accent-2);
  text-align: center;
  background: rgba(255, 255, 255, 0.03);
  border: 1px dashed rgba(154, 163, 199, 0.3);
  border-radius: var(--radius);
  text-shadow: 0 0 10px rgba(224, 188, 126, 0.4);
}

.gstatus-row {
  padding: 13px 18px;
  margin-bottom: 8px;
  background: rgba(59, 40, 20, 0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(200, 150, 78, 0.3);
  border-radius: 12px;
  font-size: 17px;
  color: var(--text-dim);
  transition: border-color 0.2s ease, background 0.2s ease;
}

.gstatus-row.me {
  border-color: rgba(200, 150, 78, 0.5);
}

.option {
  /* margin-bottom раньше отвечал за отступ между вариантами в столбик —
     теперь это делает gap у .options (сетка 2x2), а лишний margin вдобавок
     к gap не даёт кнопкам ровно встать в общую сетку по высоте. */
  text-align: left;
  padding: 14px 18px;
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(154, 163, 199, 0.25);
  border-radius: var(--radius);
  cursor: pointer;
  transition: transform 0.12s ease, background 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}

.option:hover:not(:disabled) {
  background: rgba(200, 150, 78, 0.12);
  border-color: rgba(200, 150, 78, 0.5);
  box-shadow: 0 0 16px rgba(200, 150, 78, 0.3);
  transform: translateX(2px);
}

.option:active:not(:disabled) {
  transform: scale(0.98);
}

.option.correct-glow {
  border: 2px solid #ffffff !important;
  box-shadow: 0 0 18px rgba(255, 255, 255,0.8), 0 0 34px rgba(255, 255, 255,0.45);
  animation: correctPulse 1.2s ease-in-out infinite;
}

@keyframes correctPulse {
  0%, 100% { box-shadow: 0 0 12px rgba(255, 255, 255,0.7), 0 0 24px rgba(255, 255, 255,0.4); }
  50% { box-shadow: 0 0 22px rgba(255, 255, 255,0.95), 0 0 44px rgba(255, 255, 255,0.6); }
}

.option.wrong {
  border-color: var(--bad);
  background: rgba(255, 107, 107, 0.14);
  box-shadow: 0 0 18px rgba(255, 107, 107, 0.4);
  color: var(--bad);
}

.winner-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 18px 20px;
  margin-bottom: 16px;
  font-size: 20px;
  font-weight: 800;
  text-align: center;
  color: var(--text);
  background: linear-gradient(135deg, rgba(200, 150, 78, 0.2), rgba(224, 188, 126, 0.15));
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid rgba(200, 150, 78, 0.4);
  border-radius: calc(var(--radius) * 1.2);
  box-shadow: 0 0 40px rgba(200, 150, 78, 0.35);
  text-shadow: 0 0 16px rgba(200, 150, 78, 0.5);
}

.winner-banner.sub {
  padding: 10px 16px;
  margin-top: -6px;
  font-size: 16px;
  font-weight: 700;
  background: rgba(72, 54, 30, 0.55);
  box-shadow: none;
}

.gboard-row {
  padding: 15px 20px;
  margin-bottom: 8px;
  gap: 14px;
  background: rgba(72, 54, 30, 0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(154, 163, 199, 0.18);
  border-radius: 12px;
  font-size: 19px;
  color: var(--text-dim);
  transition: border-color 0.2s ease, background 0.2s ease;
}

.gboard-row .place {
  font-size: 22px;
  width: 26px;
}

.gboard-ans {
  font-size: 18px;
}

.gboard-picks {
  font-size: 15px;
}

.ans-digit {
  font-size: 26px;
  font-weight: 800;
  margin-right: 4px;
}

.gboard-row:nth-child(odd) {
  background: rgba(59, 40, 20, 0.35);
}

.gboard-row.first {
  border-color: rgba(224, 188, 126, 0.5);
  background: rgba(224, 188, 126, 0.1);
  color: var(--text);
  box-shadow: 0 0 16px rgba(224, 188, 126, 0.25);
}

@media (max-width: 520px) {
  .question-box .question-text { font-size: 17px; }
  .guess-input-wrap input { font-size: 18px; }
  .numpad { grid-template-columns: repeat(3, 48px); }
  .numpad button { width: 48px; height: 48px; }
}

/* ---- question card: drop + flip ---- */

.question-box-inner {
  position: relative;
  display: grid;
  min-height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.55s ease;
  /* Защита от лёгкого копирования вопроса/вариантов ответа в поисковик —
     текст вопроса, категория, варианты и результаты не выделяются мышью.
     Инпут для числового ответа — исключение ниже, туда всё равно нужно
     вводить и видеть свой текст. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

.question-box-inner input,
.question-box-inner textarea {
  user-select: text;
  -webkit-user-select: text;
  -webkit-touch-callout: default;
}

.question-box-inner.flipped {
  transform: rotateX(180deg);
}

/* Флип-вход окна тай-брейка целиком (game.js, TB_FLIP_MS = 460 — держать в
   синхроне с длительностью ниже). Полный оборот 0→90→0: на 90° (ребро, оба
   лица через backface-visibility:hidden не видны) JS подменяет содержимое
   #question-mode со старого вопроса дуэли на тай-брейк, поэтому появление
   всегда читается как переворот карточки, а не как рывок нового текста
   поверх старого. Выход (после показа результата/подиума) — обычный
   cardExit/question-exit (улёт вверх), тот же, что и у всех остальных
   вопросов — см. #question-card.question-exit ниже. */
.question-box-inner.tb-flip-in {
  animation: tbFlipIn 0.46s ease-in-out;
}

@keyframes tbFlipIn {
  0% { transform: rotateX(0deg); }
  50% { transform: rotateX(90deg); }
  100% { transform: rotateX(0deg); }
}

#question-mode,
#question-results {
  grid-area: 1 / 1;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  /* position:absolute выводит элемент из расчёта высоты грид-трека:
     иначе карточки прошлого результата (даже спрятанные backface-
     visibility) продолжали задавать высоту .question-box-inner, и окно
     следующего обычного вопроса оставалось таким же большим, как самый
     высокий результат, который вообще показывался в партии. Пока не
     идёт реальный реведл (#question-card.hud-result ниже возвращает
     position:relative), карточка занимает всю область #question-mode,
     не влияя на общую высоту окна. */
  position: absolute;
  inset: 0;
}

#question-results {
  transform: rotateX(180deg);
}

/* .tb-no-drop — тай-брейк входит/держится/выходит своим флипом (ниже), а не
   обычным падением сверху: пока он активен, карточка помечена этим классом
   (game.js, ветка turn.tieBreak), и cardDrop для неё не переигрывается. */
/* :not(.question-exit) — без него это правило (ID + 2 class-псевдо) было
   специфичнее #question-card.question-exit ниже (ID + 1 класс) и побеждало
   его же: окно результата на выходе вместо улёта вверх (cardExit) заново
   играло cardDrop (translateY(-110%) → none, т.е. просто щёлкало на место)
   и пропадало без анимации ровно в момент скрытия через 500мс. */
#question-card:not(.hidden):not(.tb-no-drop):not(.question-exit) {
  animation: cardDrop 0.5s cubic-bezier(0.2, 0.9, 0.3, 1.12) both;
}

@keyframes cardDrop {
  from { transform: translateY(-110%); }
  to { transform: none; }
}

#question-card.question-exit {
  animation: cardExit 0.5s cubic-bezier(0.5, 0, 0.7, 0.4) forwards;
}

@keyframes cardExit {
  from { transform: none; }
  to { transform: translateY(-110%); }
}

.correct-answer {
  font-size: 36px;
  font-weight: 800;
  text-align: center;
  margin-bottom: 18px;
  animation: answerFadeIn 0.6s ease;
  text-shadow: 0 0 22px currentColor;
}

@keyframes answerFadeIn {
  from { opacity: 0; transform: scale(0.9); }
  to { opacity: 1; transform: scale(1); }
}

/* ---- rotate hint overlay (mobile portrait) ---- */

/* Объявление от админа (admin.js -> /announcement, presence.js слушает и
   показывает) — тонкая полоса поверх всего интерфейса, но НИЖЕ conn-overlay/
   rotate-overlay (9999-10000): потеря связи или просьба повернуть телефон
   всегда важнее текста от администрации. */
.announce-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9998;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 10px 44px 10px 16px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  color: #2e1f10;
  font-weight: 700;
  font-size: 14px;
  text-align: center;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
}

.announce-banner-text {
  max-width: 900px;
}

.announce-banner-close {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  color: #2e1f10;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.75;
  padding: 4px 8px;
}

.announce-banner-close:hover { opacity: 1; }

/* Плашка "доступна новая версия" (см. updater.js) — снизу по центру, чтобы не
   перекрывать шапку/карту. Показывается, если обновление вышло, пока вкладка
   была открыта. */
.update-banner {
  position: fixed;
  left: 50%;
  bottom: 20px;
  transform: translateX(-50%);
  z-index: 9997;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px;
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(59, 40, 20, 0.96), rgba(24, 15, 7, 0.96));
  border: 1px solid rgba(224, 188, 126, 0.4);
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.5);
  color: var(--text);
  font-size: 14px;
}

.update-banner.hidden { display: none; }

.update-banner-text { white-space: nowrap; }

/* Слой "нет связи". z-index выше rotate-overlay: если связь отвалилась, это
   важнее просьбы повернуть телефон. Показывается не сразу — см. connection.js,
   иначе он мигал бы на каждом штатном переподключении Firebase. */
.conn-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 10000;
  align-items: center;
  justify-content: center;
  background: radial-gradient(1200px 800px at 50% 20%, var(--bg-soft), var(--bg));
  text-align: center;
}

.conn-overlay.active {
  display: flex;
}

/* Раньше окно потери связи было просто текстом со спиннером прямо на фоне
   меню, без своей стеклянной панели — единственное такое окно в игре. */
.conn-box {
  position: relative;
  max-width: 380px;
  padding: 28px 24px;
  zoom: 0.65;
  background:
    linear-gradient(90deg, transparent, var(--accent-2) 20%, var(--accent-2) 80%, transparent) top / 100% 3px no-repeat,
    radial-gradient(circle at 30% 0%, rgba(224, 188, 126, 0.12), transparent 60%),
    radial-gradient(circle at 80% 100%, rgba(200, 150, 78, 0.15), transparent 55%),
    linear-gradient(180deg, rgba(72, 54, 30, 0.75), rgba(38, 25, 14, 0.85));
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(200, 150, 78, 0.35);
  border-radius: 12px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

.conn-box::before {
  content: "";
  position: absolute;
  width: 7px;
  height: 7px;
  background: var(--accent-2);
  transform: rotate(45deg);
  border-radius: 1px;
  box-shadow: 0 0 8px 1px rgba(224, 188, 126,0.6), 0 0 2px rgba(224, 188, 126,0.9);
  pointer-events: none;
  top: 9px;
  left: 9px;
}

.conn-spinner {
  width: 40px;
  height: 40px;
  margin: 0 auto 20px;
  border: 3px solid rgba(255, 255, 255, 0.12);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: connSpin 0.9s linear infinite;
}

@keyframes connSpin {
  to { transform: rotate(360deg); }
}

.conn-title {
  margin: 0 0 10px;
  font-size: 20px;
}

.conn-text {
  margin: 0;
  color: var(--text-dim);
  font-size: 15px;
  line-height: 1.5;
}

/* Показывается поверх меню, если проверка сессии Firebase не успела
   ответить к моменту, когда прогрузилась карта и заставка (.boot-loading)
   уже скрылась — без этого окна игрок на секунду-другую видел бы меню в
   виде "гостя", а потом оно резко переключалось на "вы вошли". В отличие
   от .conn-overlay фон не перекрывается сплошной подложкой, а именно
   блюрится (backdrop-filter): меню за окном видно, но нажать на него нельзя. */
.auth-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9997;
  align-items: center;
  justify-content: center;
  text-align: center;
  background: rgba(18, 11, 5, 0.35);
  backdrop-filter: blur(8px) saturate(120%);
  -webkit-backdrop-filter: blur(8px) saturate(120%);
}

.auth-overlay.active {
  display: flex;
}

.rotate-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9999;
  align-items: center;
  justify-content: center;
  background: radial-gradient(1200px 800px at 50% 20%, var(--bg-soft), var(--bg));
  text-align: center;
  cursor: pointer;
}

.rotate-overlay.active {
  display: flex;
}

.rotate-box {
  max-width: 320px;
  padding: 28px 24px;
}

.rotate-icon {
  font-size: 68px;
  line-height: 1;
  margin-bottom: 20px;
  display: inline-block;
  animation: rotateHint 1.6s ease-in-out infinite;
  text-shadow: 0 0 24px rgba(200, 150, 78, 0.5);
}

.rotate-title {
  font-size: 20px;
  font-weight: 800;
  line-height: 1.35;
}

.rotate-sub {
  margin-top: 10px;
  font-size: 14px;
  opacity: 0.7;
}

/* Заглушка спящей вкладки (см. tabs.js): вкладка открыта, но соединение
   Firebase держит другая — эта не подключается, чтобы не тратить лимит
   одновременных соединений. */
.tab-overlay {
  position: fixed;
  inset: 0;
  z-index: 19999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(1200px 800px at 50% 20%, var(--bg-soft), var(--bg));
  text-align: center;
  padding: 24px;
}

.tab-overlay.hidden { display: none; }

.tab-box {
  max-width: 380px;
  padding: 28px 24px;
}

.tab-icon {
  font-size: 56px;
  line-height: 1;
  margin-bottom: 18px;
  color: var(--accent-2);
  text-shadow: 0 0 24px rgba(200, 150, 78, 0.5);
}

.tab-title {
  font-size: 20px;
  font-weight: 800;
  line-height: 1.35;
}

.tab-sub {
  margin: 10px 0 20px;
  font-size: 14px;
  opacity: 0.7;
}

@keyframes rotateHint {
  0%, 100% { transform: rotate(0deg); }
  50% { transform: rotate(90deg); }
}

/* ---- intro castle animations ---- */

/* Специфичность не ниже .map path.terr.interactive, иначе пульсация вытесняет
   terrSpread и та перезапускается, когда подсветка снимается. */
.terr-spread,
.map path.terr.terr-spread {
  transform-box: fill-box;
  transform-origin: 50% 50%;
  animation: terrSpread 1.7s ease-out both;
}

@keyframes terrSpread {
  from { transform: scale(0.04); }
  to { transform: scale(1); }
}

.castle-marker {
  filter:
    drop-shadow(0 8px 10px rgba(0, 0, 0,0.55))
    drop-shadow(0 0 5px rgba(0, 0, 0,0.4));
}

.castle-drop {
  animation: castleDrop 0.9s cubic-bezier(0.3, 0.5, 0.4, 1) both;
}

@keyframes castleDrop {
  0% { transform: translate(var(--cx), calc(var(--cy) - 300px)); }
  62% { transform: translate(var(--cx), var(--cy)); }
  72% { transform: translate(calc(var(--cx) - 6px), calc(var(--cy) - 3px)); }
  80% { transform: translate(calc(var(--cx) + 6px), var(--cy)); }
  88% { transform: translate(calc(var(--cx) - 3px), calc(var(--cy) - 1px)); }
  100% { transform: translate(var(--cx), var(--cy)); }
}

/* "Усадка" маркера замка при смене стадии повреждения (сбита башня, руины)
   — вешается на саму <image> (renderCastleMarker), а не на .castle-marker:
   у той transform занят позиционированием (translate/castleDrop), а тут
   нужен только scale вокруг центра замка. x/y картинки и так симметричны
   вокруг (0,0) локальной системы координат g — scale(1) там же и есть
   центр замка, transform-origin трогать не нужно. */
.castle-marker-img.settle {
  animation: castleSettle 0.45s cubic-bezier(0.2, 0.8, 0.3, 1) both;
}

@keyframes castleSettle {
  0% { transform: scale(1.16); }
  100% { transform: scale(1); }
}

/* ---- battle attack flight + banner ---- */

.sword-fly {
  animation-name: swordFly;
  animation-duration: var(--dur, 0.9s);
  animation-delay: var(--delay, 0s);
  animation-timing-function: cubic-bezier(0.25, 0.1, 0.3, 1);
  animation-fill-mode: both;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0,0.6));
}

@keyframes swordFly {
  0% { transform: translate(var(--sx), var(--sy)) rotate(0deg) scale(0.3); opacity: 0; }
  15% { opacity: 1; }
  100% { transform: translate(var(--tx), var(--ty)) rotate(var(--rot)) scale(1); opacity: 1; }
}

/* Дуэль решилась — мечи не просто пропадают, а истаивают в воздухе на
   месте, куда долетели (тот же приём, что и attack-flyer-evaporate). */
.attack-swords-exit .sword-fly {
  animation: swordEvaporate 0.5s ease-in forwards;
}

@keyframes swordEvaporate {
  0% { transform: translate(var(--tx), var(--ty)) rotate(var(--rot)) scale(1); opacity: 1; }
  100% { transform: translate(var(--tx), calc(var(--ty) - 14px)) rotate(var(--rot)) scale(1.6); opacity: 0; }
}

/* Линза прицела при атаке замка. Сама по себе невидима (opacity:0, без
   анимации) — появление включает createFlyer() добавлением класса
   .attack-sight-lens-in ровно по animationend прицела, то есть в момент,
   когда прицел реально долетел до замка, а не по отдельному таймеру
   (раньше был фиксированный JS-delay, который приходилось вручную
   синхронизировать с длительностью CSS-анимации полёта — см. комментарий
   в createLensView()). */
.attack-sight-lens {
  opacity: 0;
}

.attack-sight-lens.attack-sight-lens-in {
  animation: sightLensIn 0.35s ease-out both;
}

@keyframes sightLensIn {
  0% { opacity: 0; }
  100% { opacity: 1; }
}

.attack-sight-lens-exit {
  animation: none;
  opacity: 0;
  transition: opacity 0.4s ease;
}

/* Ракета на сбитую башню. Сам полёт (позиция, разворот, масштаб) больше не
   описан здесь: @keyframes с фиксированными процентами давали рывки —
   timing-function в CSS применяется к каждому промежутку между кейфреймами
   по отдельности, так что ракета тормозила на каждой путевой точке. Теперь
   траекторию считает и проигрывает launchRocket() через element.animate(),
   размечая кадры по реальной длине дуги.

   Тени здесь тоже больше нет: смаз в движении делается SVG-фильтром
   (направленный feGaussianBlur вдоль корпуса), а свойство filter в CSS
   перекрыло бы атрибут filter на элементе — вдвоём они не живут. Поэтому
   тень уехала в тот же фильтр, в createRocketBlur(). Класс оставлен как
   опознавательный: по нему ракету находят в отладке. */
.rocket-fly { /* оформление — в SVG-фильтре, см. createRocketBlur() */ }

.attack-flyer-in,
.attack-flyer-evaporate,
.attack-flyer-return {
  --glow: 200, 150, 78;
  filter:
    drop-shadow(0 4px 10px rgba(0, 0, 0,0.5))
    drop-shadow(0 0 10px rgba(var(--glow), 0.95))
    drop-shadow(0 0 22px rgba(var(--glow), 0.7));
}

.attack-flyer-in.p0,
.attack-flyer-evaporate.p0,
.attack-flyer-return.p0 { --glow: 107,125,143; }

.attack-flyer-in.p1,
.attack-flyer-evaporate.p1,
.attack-flyer-return.p1 { --glow: 127,154,74; }

.attack-flyer-in.p2,
.attack-flyer-evaporate.p2,
.attack-flyer-return.p2 { --glow: 193,91,72; }

.attack-flyer-in {
  animation: attackFly 0.95s cubic-bezier(0.25, 0.1, 0.3, 1) forwards;
}

@keyframes attackFly {
  0% { transform: translate(var(--sx), var(--sy)) rotate(0deg) scale(0.5); opacity: 0; }
  12% { transform: translate(var(--sx), var(--sy)) rotate(0deg) scale(1); opacity: 1; }
  100% { transform: translate(var(--tx), var(--ty)) rotate(360deg) scale(1); opacity: 1; }
}

/* Territory falls to the attacker: the planted icon dissolves in place,
   right where the terr-spread capture effect plays. */
.attack-flyer-evaporate {
  animation: attackEvaporate 0.5s ease-in forwards;
}

@keyframes attackEvaporate {
  0% { transform: translate(var(--tx), var(--ty)) scale(1); opacity: 1; }
  100% { transform: translate(var(--tx), var(--ty)) scale(1.7); opacity: 0; }
}

/* Defender holds the territory: the icon retreats back to the attacker's
   castle and fades out there. */
.attack-flyer-return {
  animation: attackReturn 0.6s cubic-bezier(0.4, 0, 0.6, 1) forwards;
}

@keyframes attackReturn {
  0% { transform: translate(var(--tx), var(--ty)) scale(1); opacity: 1; }
  100% { transform: translate(var(--sx), var(--sy)) scale(0.5); opacity: 0; }
}

/* Щит ремонта (def.png, см. createRepairShield/updateRepairShield в
   game.js) — три вложенных <g>: позиция (не анимируется, растёт над
   своим замком без полёта), масштаб появления/ухода (transition — не
   keyframes, чтобы истаивание не дёргалось, если случится на полпути
   появления) и вращение (отдельный элемент, не мешает масштабу). */
.repair-shield-scale {
  transform-box: fill-box;
  transform-origin: center;
  transform: scale(0);
  opacity: 0;
  transition: transform 0.5s cubic-bezier(0.2, 0.8, 0.3, 1), opacity 0.3s ease;
  /* Тень заметно глубже (было 0 4px 10px/0.5) + лёгкое размытие самой
     картинки (blur) — вместе читается мягче, "магический" щит, а не
     плоская наклейка поверх замка. */
  filter:
    drop-shadow(0 8px 16px rgba(0, 0, 0, 0.65))
    drop-shadow(0 0 14px rgba(158, 207, 122, 0.8))
    blur(0.6px);
}

.repair-shield-scale.repair-shield-in {
  transform: scale(1);
  opacity: 1;
}

.repair-shield-scale.repair-shield-exit {
  transform: scale(0.3);
  opacity: 0;
  transition: transform 0.6s ease-in, opacity 0.5s ease-in;
}

.repair-shield-spin-el {
  transform-box: fill-box;
  transform-origin: center;
}

/* Против часовой стрелки — отрицательный угол. Несколько полных оборотов
   за 1.5с ("быстро крутится"), не один медленный. */
.repair-shield-spin-el.repair-shield-spinning {
  animation: repairShieldSpin 1.5s linear;
}

@keyframes repairShieldSpin {
  from { transform: rotate(0deg); }
  to { transform: rotate(-1080deg); }
}

.attack-banner {
  position: absolute;
  inset: auto 0 auto 0;
  top: 14px;
  bottom: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 17;
  pointer-events: none;
}

.attack-banner-box {
  position: relative;
  padding: 24px 56px;
  zoom: 0.65;
  /* Та же стеклянная панель, что у остальных уведомлений, но кант и полоса
     сверху — медно-ржавые вместо золота баннера раунда: боевая тревога не
     должна читаться так же "празднично", чтобы их нельзя было спутать
     даже мельком. */
  background:
    linear-gradient(90deg, transparent, #c46a3e 20%, #c46a3e 80%, transparent) top / 100% 3px no-repeat,
    radial-gradient(circle at 30% 0%, rgba(196, 106, 62, 0.18), transparent 60%),
    linear-gradient(180deg, rgba(58, 30, 16, 0.82), rgba(28, 14, 8, 0.9));
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(196, 106, 62, 0.5);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0,0.4), inset 0 0 0 2px rgba(138, 74, 44,0.25);
  font-size: 38px;
  font-weight: 700;
  text-align: center;
  color: var(--text);
  text-shadow: 0 1px 4px rgba(0, 0, 0,0.6);
  animation: phaseBannerIn 0.25s ease-out both;
}

/* Штурм замка визуально выделяется отдельно от атаки рядовой территории —
   тот же крючок (attack-banner-castle/-territory) пригодится и для
   будущей озвучки, которая тоже будет разной для этих двух случаев. */
.attack-banner-castle .attack-banner-box {
  border-color: rgba(224, 188, 126, 0.55);
  box-shadow: 0 8px 24px rgba(0, 0, 0,0.4), 0 0 20px 2px rgba(200, 150, 78,0.45);
}
.attack-banner-castle .attack-banner-box::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: linear-gradient(90deg, transparent, var(--accent-2) 20%, var(--accent-2) 80%, transparent);
}

/* ==== "Боевая консоль" — HUD-оформление окна числового вопроса ====
   Макеты собраны в Claude Design: "Combat Console" для дуэли тай-брейка и
   "Сетка отряда" для фазы захвата. Общая часть — .hud-console на
   #question-card, различия — .hud-duel / .hud-capture.

   ВАЖНО про раскладку. В обычном режиме #guess-layout — это grid 2x2
   (инпут | кнопка / numpad | статус), а .guess-main и .guess-input-wrap
   имеют display:contents, то есть их дети лежат прямо в этом гриде. Любые
   правила на самих обёртках в таком режиме не работают вовсе (у элемента
   с display:contents нет собственного бокса) — именно поэтому первая
   версия консоли разъехалась: numpad оставался в левой колонке, а кнопка
   "Ответить" — в правой. Здесь грид целиком заменён на ОДНУ флекс-колонку,
   а порядок задан через order, потому что перевесить элементы в DOM
   нельзя: разметка общая с обычным (не консольным) режимом. */

/* Макеты консоли нарисованы на полотне 640px с полями 32px — всё внутри
   идёт на ВСЮ ширину контента (ридаут, numpad, сетка отряда). Обычная
   .question-box тянется до 1100px, и на такой ширине те же элементы
   растянулись бы в нечитаемые полосы, поэтому в консольном режиме окно
   ограничено шириной макета. min-height тоже снят: консоль компактнее
   MC-вопроса и при 55vh под ней оставалась бы пустая нижняя треть. */
#question-card.hud-console .question-box {
  overflow: hidden;
  background: var(--bg);
  position: relative;
  padding: 26px 32px 24px;
  width: 100%;
  max-width: 700px;
  min-height: 0;
}

#question-card.hud-console .question-box::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
  background:
    repeating-linear-gradient(0deg, rgba(224, 188, 126, 0.035) 0px, rgba(224, 188, 126, 0.035) 1px, transparent 1px, transparent 3px),
    radial-gradient(700px 500px at 80% -10%, rgba(200, 150, 78, 0.14), transparent);
  pointer-events: none;
  z-index: 0;
}

/* Гербовый баннер с аватарками — не часть консоли (в дуэли его заменяет
   текстовая строка .tbq-duel-row, в захвате он и так не показывается). */
#question-card.hud-console #duel-vs-header {
  display: none;
}

#question-card.hud-console #question-mode {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

/* #question-category в обычном режиме — золотая пилюля-лейбл; в консоли
   становится строкой HUD-заголовка: индикатор + подпись фазы слева,
   номер раунда/вопроса справа. Тот же элемент, без лишнего DOM. */
#question-card.hud-console #question-category {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: 0 0 12px;
  margin: 0 0 20px;
  background: none;
  border: none;
  border-bottom: 1px solid transparent;
  border-image: linear-gradient(90deg, var(--accent) 0%, transparent 100%) 1;
  box-shadow: none;
}

.hud-cat-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent-2);
  box-shadow: 0 0 8px var(--accent-2);
  margin-right: 8px;
  animation: hudDotBlink 1.4s ease-in-out infinite;
}
@keyframes hudDotBlink { 50% { opacity: 0.3; } }

/* Строка дуэли (только тай-брейк) — замена гербовому баннеру. */
.tbq-duel-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-bottom: 10px;
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-weight: 700;
  font-size: 15px;
}
.tbq-fighter { display: flex; align-items: center; gap: 8px; }
.tbq-fighter .tag { font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 4px; color: var(--bg); }
.tbq-fighter.atk { color: var(--fighter-atk, var(--accent-2)); }
.tbq-fighter.atk .tag { background: var(--fighter-atk, var(--accent-2)); }
.tbq-fighter.def { color: var(--fighter-def, var(--accent)); }
.tbq-fighter.def .tag { background: var(--fighter-def, var(--accent)); }
.tbq-vs-label {
  font-family: "Cinzel", serif;
  font-weight: 900;
  font-size: 13px;
  color: var(--text-dim);
  letter-spacing: 0.1em;
}

/* Тот же кегль, что у вопроса с четырьмя вариантами (см. .question-box
   .question-text выше) — формула один-в-один. Место под него освобождено
   тем, что цифровой блок и поле ввода ниже сжаты до компактных размеров:
   на типичном (коротком) вопросе это даёт ~40px чистого выигрыша, на
   самом длинном в базе — примерно ничью, зато текст заметно крупнее. */
#question-card.hud-console .question-text {
  font-size: clamp(24px, min(3.4vw, 5.4vh), 60px);
  margin: 0 0 16px;
}

/* --- ядро раскладки: одна колонка вместо грида 2x2 --- */
#question-card.hud-console #guess-layout {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: 100%;
  margin: 0;
  column-gap: 0;
  row-gap: 0;
}

/* Обёртки остаются display:contents (как и в обычном режиме) — их дети
   становятся прямыми флекс-элементами колонки, порядок задан ниже. */
#question-card.hud-console .guess-main,
#question-card.hud-console .guess-input-wrap {
  display: contents;
}

.hud-readout-label {
  width: 100%;
  text-align: center;
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 6px;
}

/* Поле ввода и цифровой блок ниже — компактные и одной ширины. Раньше оба
   тянулись на всю ширину окна: клавиша под одну цифру выходила 175px, что
   и съедало место, которое теперь отдано тексту вопроса. */
#question-card.hud-console .guess-input-wrap input {
  width: 268px;
  max-width: 100%;
  align-self: center;
  grid-column: auto;
  grid-row: auto;
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 30px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 12px 10px;
  margin-bottom: 12px;
  background: linear-gradient(90deg, var(--panel-2), var(--panel));
  border: 1px solid rgba(224, 188, 126, 0.3);
  border-radius: 14px;
  box-shadow: 0 0 30px rgba(200, 150, 78, 0.12);
  caret-color: var(--accent-2);
}

#question-card.hud-console .guess-input-wrap input:focus {
  background: linear-gradient(90deg, var(--panel-2), var(--panel));
  box-shadow: 0 0 30px rgba(200, 150, 78, 0.12), 0 0 0 3px rgba(224, 188, 126, 0.18);
}

#question-card.hud-console .numpad {
  grid-column: auto;
  grid-row: auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  width: 268px;
  max-width: 100%;
  /* именно align-self: #guess-layout здесь — флекс-КОЛОНКА, поперечная ось
     у неё горизонтальная. justify-self работает только у грид-элементов и
     на флексе игнорируется — из-за этого блок с цифрами прижимался влево,
     хотя поле ввода над ним (у него align-self) стояло по центру. */
  align-self: center;
  gap: 7px;
  margin: 0 0 12px;
}

/* padding подобран так, чтобы клавиша осталась ~44px по высоте на экране:
   ниже этого по ней неудобно попадать пальцем. */
#question-card.hud-console .numpad button {
  width: auto;
  height: auto;
  padding: 13px 0;
  border-radius: 8px;
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 17px;
  background: rgba(255, 255, 255, 0.04);
  border-color: rgba(154, 163, 199, 0.2);
}

#question-card.hud-console .numpad button.numpad-act {
  border-radius: 8px;
  font-size: 15px;
  color: var(--accent-2);
  border-color: rgba(224, 188, 126, 0.35);
  background: rgba(224, 188, 126, 0.06);
}

#question-card.hud-console .guess-input-wrap button {
  grid-column: auto;
  grid-row: auto;
  justify-self: auto;
  /* колонка растягивает детей (align-items:stretch) — кнопке это не нужно,
     она остаётся по своему размеру и по центру, как в макете */
  align-self: center;
  padding: 13px 34px;
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-2);
  background: rgba(224, 188, 126, 0.1);
  border: 1px solid var(--accent-2);
  border-radius: 8px;
  box-shadow: none;
}

#question-card.hud-console .guess-input-wrap button:hover {
  background: rgba(224, 188, 126, 0.18);
}

#question-card.hud-console .my-answer {
  grid-column: auto;
  grid-row: auto;
  align-self: center;
  margin-top: 14px;
  font-family: "JetBrains Mono", "Courier New", monospace;
}

/* Порядок колонки. Дуэль: подпись → ввод → numpad → кнопка.
   Захват: сетка отряда идёт ПЕРВОЙ, остальное так же. */
#question-card.hud-console .guess-status { order: 1; }
#question-card.hud-console .hud-readout-label { order: 2; }
#question-card.hud-console .guess-input-wrap input { order: 3; }
#question-card.hud-console .numpad { order: 4; }
#question-card.hud-console .guess-input-wrap button { order: 5; }
#question-card.hud-console .my-answer { order: 6; }

/* --- Сетка отряда (только фаза захвата) ---
   #guess-status уже рендерит по строке на игрока (renderGuessStatus в
   game.js) — здесь те же данные раскладываются карточками в ряд. */
#question-card.hud-capture .guess-status {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  width: 100%;
  gap: 10px;
  margin: 0 0 20px;
  align-self: stretch;
}

#question-card.hud-capture .guess-status .gstatus-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  padding: 14px 8px;
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.22);
  border: 1px solid rgba(255, 255, 255, 0.07);
  box-shadow: none;
}

#question-card.hud-capture .guess-status .gstatus-row.is-ready {
  border-color: color-mix(in srgb, var(--pcolor) 55%, transparent);
  background: color-mix(in srgb, var(--pcolor) 12%, rgba(0, 0, 0, 0.22));
  box-shadow: 0 0 18px color-mix(in srgb, var(--pcolor) 18%, transparent);
}

.squad-tag {
  display: inline-block;
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 9px;
  font-weight: 700;
  color: var(--bg);
  background: var(--pcolor);
  padding: 2px 6px;
  border-radius: 4px;
}

#question-card.hud-capture .guess-status .gstatus-name {
  font-weight: 700;
  font-size: 13px;
  color: var(--pcolor);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.squad-state {
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-dim);
}
.gstatus-row.is-ready .squad-state { color: var(--pcolor); }

/* Бейджи "X ответил" и подпись — только в консоли дуэли; в захвате их
   роль выполняет сетка отряда. */
#question-card.hud-console .duel-answered-row,
#question-card.hud-console .waiting-note {
  position: relative;
  z-index: 1;
}

#question-card.hud-console .duel-answered-side {
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 18px;
}

#question-card.hud-console .waiting-note {
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 13px;
  min-height: 34px;
}

/* Числовой отсчёт рядом с полоской. #timer-row лежит СНАРУЖИ
   #question-card (сосед, не потомок), поэтому класс зеркалится на него
   отдельно из game.js, а не достаётся по вложенности. */
.hud-timer-num {
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-weight: 700;
  font-size: 14px;
  color: var(--accent-2);
  margin-left: 10px;
  flex: none;
}

.timer-row.hud-console .timer-wrap { height: 8px; }

.timer-row.hud-console .timer-bar {
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
}

/* ==== Захват · результат числового вопроса — "Три карты" ====
   Адаптация "Дуэльных карточек" тай-брейка на трёх игроков (макет Claude
   Design): победитель по центру, крупнее, с короной; проигравшие по бокам,
   карточка последнего места чуть ниже. Главный итог фазы — сколько
   территорий получает каждый — строкой внизу карточки.

   Про свечение и перекрытие. Ореол победителя — box-shadow, он рисуется
   ВНЕ бокса и поэтому никогда не ложится на собственный контент карточки.
   Опасность только в соседях: у победителя transform:scale(), это создаёт
   свой контекст наложения, и при z-index выше соседей его ореол закрасил
   бы их текст. Поэтому здесь наоборот — z-index победителя НИЖЕ соседних
   карточек, а зазор в .capr-arena заведомо больше прироста от scale, так
   что геометрически карточки не пересекаются и ничего не обрезается. */

.capr-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
}

@keyframes caprFadeUp {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* gap заведомо больше прироста победителя от scale(1.1) на 190px
   (≈9.5px с каждой стороны) — карточки не наезжают друг на друга, и
   вопрос "чей z-index выше" перестаёт влиять на читаемость. */
.capr-arena {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  /* запас снизу с учётом сдвига карточки третьего места (translateY),
     чтобы она не подходила вплотную к баннеру под ареной */
  margin-bottom: 58px;
}

.capr-card {
  position: relative;
  z-index: 2;
  width: 168px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid color-mix(in srgb, var(--pcolor) 45%, transparent);
  box-shadow: 0 14px 28px rgba(0, 0, 0, 0.4);
  opacity: 0;
  animation: caprCardIn 0.45s cubic-bezier(0.2, 0.8, 0.3, 1) forwards;
}

/* Второе место — слабое свечение, третье — без свечения вовсе. */
.capr-card.capr-second {
  box-shadow:
    0 14px 28px rgba(0, 0, 0, 0.4),
    0 0 22px color-mix(in srgb, var(--pcolor) 22%, transparent);
}

/* Третье место стоит чуть ниже остальных. Сдвиг зашит в кадры
   собственной анимации входа: отдельным transform его задать нельзя —
   свойство одно, и анимация его перезапишет. */
.capr-card.capr-third {
  animation-name: caprCardInLow;
}

.capr-card.capr-win {
  z-index: 1;
  width: 190px;
  border-color: color-mix(in srgb, var(--pcolor) 65%, transparent);
  box-shadow:
    0 22px 44px rgba(0, 0, 0, 0.5),
    0 0 54px color-mix(in srgb, var(--pcolor) 55%, transparent),
    0 0 104px color-mix(in srgb, var(--pcolor) 30%, transparent);
  animation-name: caprCardInWin;
  animation-delay: 0.1s;
}

@keyframes caprCardIn {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes caprCardInLow {
  from { opacity: 0; transform: translateY(34px); }
  to { opacity: 1; transform: translateY(16px); }
}
@keyframes caprCardInWin {
  from { opacity: 0; transform: translateY(18px) scale(1.1); }
  to { opacity: 1; transform: translateY(0) scale(1.1); }
}

.capr-card-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px 12px 16px;
}

/* Корона: обёртка играет падение, сама иконка — тряску. Разделены
   намеренно: одна и та же анимация из двух источников на одном элементе
   конфликтует по transform, и позже добавленная стёрла бы удержанное
   forwards-состояние падения (та же грабля, что уже ловили на карточках
   тай-брейка). */
.capr-crown-wrap {
  position: absolute;
  top: -26px;
  left: 50%;
  z-index: 3;
  opacity: 0;
  transform: translateX(-50%) translateY(10px) scale(0.4) rotate(-10deg);
  animation: caprCrownDrop 0.5s 0.45s cubic-bezier(0.3, 1.6, 0.4, 1) forwards;
  filter: drop-shadow(0 5px 8px rgba(0, 0, 0, 0.5));
}
@keyframes caprCrownDrop {
  to { opacity: 1; transform: translateX(-50%) translateY(0) scale(1) rotate(0deg); }
}

.capr-crown.capr-shake {
  animation: caprCrownShake 0.45s ease;
}
@keyframes caprCrownShake {
  10%, 90% { transform: translate3d(3px, -1px, 0) rotate(-7deg); }
  20%, 80% { transform: translate3d(-3px, 1px, 0) rotate(7deg); }
  30%, 50%, 70% { transform: translate3d(2px, -2px, 0) rotate(-5deg); }
  40%, 60% { transform: translate3d(-2px, 1px, 0) rotate(5deg); }
}

.capr-place {
  position: absolute;
  top: 10px;
  left: 10px;
  font-family: "Cinzel", serif;
  font-weight: 900;
  font-size: 13px;
  color: var(--text-dim);
  opacity: 0.7;
}

.capr-name {
  font-weight: 800;
  font-size: 14px;
  color: var(--pcolor);
  margin-bottom: 12px;
  text-align: center;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.capr-card.capr-win .capr-name { font-size: 16px; }

.capr-answer {
  font-family: "Cinzel", serif;
  font-weight: 900;
  font-size: 30px;
  color: var(--text);
  line-height: 1;
}
.capr-card.capr-win .capr-answer {
  font-size: 36px;
  color: #ffffff;
  text-shadow: 0 0 16px color-mix(in srgb, var(--pcolor) 70%, transparent);
}
.capr-answer.capr-none {
  font-family: "Segoe UI", system-ui, sans-serif;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-dim);
}

.capr-divider {
  width: 32px;
  height: 1px;
  background: rgba(255, 255, 255, 0.14);
  margin: 12px 0;
}

.capr-stats { display: flex; gap: 8px; }
.capr-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 7px 10px;
  background: rgba(0, 0, 0, 0.22);
  border-radius: 9px;
  min-width: 52px;
}
.capr-stat .l {
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.capr-stat .v { font-size: 14px; font-weight: 800; color: var(--text); }
.capr-card.capr-win .capr-stat .v { color: #ffffff; }

/* Награда — главный итог фазы захвата. */
.capr-reward {
  width: 100%;
  margin-top: 14px;
  padding: 9px 6px;
  text-align: center;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  font-weight: 800;
  font-size: 13px;
  color: var(--pcolor);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.capr-reward svg { width: 14px; height: 14px; flex: none; }
.capr-reward.capr-none {
  color: var(--text-dim);
  opacity: 0.55;
  font-weight: 700;
}

.capr-banner {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 15px 28px;
  border-radius: 999px;
  background: linear-gradient(135deg, rgba(200, 150, 78, 0.22), rgba(224, 188, 126, 0.12));
  box-shadow: 0 0 40px rgba(200, 150, 78, 0.3);
  font-family: "Cinzel", serif;
  font-weight: 700;
  font-size: 17px;
  color: var(--text);
  text-shadow: 0 0 14px rgba(200, 150, 78, 0.5);
  opacity: 0;
  animation: caprFadeUp 0.55s 0.75s ease forwards;
}
.capr-banner svg { width: 20px; height: 20px; flex: none; }

/* ==== Экран результата тай-брейка: консольная оправа вокруг карточек ====
   Сами карточки (.tbc-card и всё внутри) НЕ меняются — тёплый градиент,
   Cinzel, корона, ореол. Консольным становится только окно вокруг них:
   тёмный фон со сканлайнами, шапка с индикатором, «ридаут» для верного
   ответа и отсек со скобками по углам вокруг арены.
   Медальон VS убран по решению (.tbc-vs больше не рендерится в game.js).

   .hud-result НЕ включает раскладочные правила .hud-console: те жмут окно
   до 700px, а арене карточек (260 + 280×1.22) нужно заметно больше. */

#question-card.hud-result .question-box {
  position: relative;
  background: var(--bg);
}

/* Окно результата захвата — под свою арену (2 карточки 168px + 1 победная
   190px + зазоры = ~590px), а не общую ширину hud-result.question-box
   (до 1100px, под более широкую арену тай-брейка) — та оставляла пустоту
   по бокам, которой карточкам захвата взяться неоткуда. */
#question-card.hud-result.hud-capr .question-box {
  width: auto;
  max-width: 660px;
}

/* Окно результата тай-брейка — тоже под свою арену, не под общий потолок
   1100px: тот был рассчитан на прежний (более крупный) размер карточек
   .tbc-card, с тех пор карточки уменьшили, а окно осталось прежней
   ширины — с обеих сторон набегала пустота. Арена сейчас ~967px (225 +
   136 + 245 + 136 + 225), плюс поля отсека (с запасом под scale(1.22)
   карточки победителя — см. .tbc-bay) и самого окна. */
#question-card.hud-result:not(.hud-capr) .question-box {
  width: auto;
  max-width: 1160px;
}

#question-card.hud-result .question-box::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
  background:
    repeating-linear-gradient(0deg, rgba(224, 188, 126, 0.035) 0px, rgba(224, 188, 126, 0.035) 1px, transparent 1px, transparent 3px),
    radial-gradient(700px 500px at 80% -10%, rgba(200, 150, 78, 0.14), transparent);
  pointer-events: none;
  z-index: 0;
}

/* Всё содержимое результата — поверх сканлайнов. */
#question-card.hud-result #question-results {
  position: relative;
  z-index: 1;
}

/* Шапка — копия строки из окна вопроса. */
.hud-res-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: 0 0 12px;
  margin-bottom: 26px;
  border-bottom: 1px solid transparent;
  border-image: linear-gradient(90deg, var(--accent) 0%, transparent 100%) 1;
  opacity: 0;
  animation: tbcFadeUp 0.45s 0.05s ease forwards;
}

/* Верный ответ — та же панель, что поле ввода в окне вопроса. */
.hud-res-readout {
  align-self: center;
  width: 300px;
  max-width: 100%;
  background: linear-gradient(90deg, var(--panel-2), var(--panel));
  border: 1px solid rgba(224, 188, 126, 0.3);
  border-radius: 14px;
  box-shadow: 0 0 30px rgba(200, 150, 78, 0.12);
  padding: 16px 12px;
  text-align: center;
  margin-bottom: 26px;
  opacity: 0;
  animation: tbcFadeUp 0.5s 1.15s ease forwards;
}
.hud-res-readout .l {
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 6px;
}
.hud-res-readout .v {
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 38px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text);
}

/* Отсек: скобки по углам вокруг арены. Подписи у отсека нет — убрана по
   решению вместе с медальоном VS. Отступы сверху/снизу с запасом: корона
   торчит на 34px выше карточки, ореол — на 30px во все стороны. */
.tbc-bay {
  position: relative;
  /* по содержимому, а не во всю ширину окна: окно бывает заметно шире
     арены, и растянутый отсек оставлял бы по ~190px пустоты по бокам.
     Боковые поля (2-е число) — НЕ просто отступ: карточка победителя
     (.tbc-slide1) растёт до scale(1.22) уже ПОСЛЕ раскладки (transform,
     в layout/ширину бокса не считается), и при плотно сжатом окне
     (width:auto под содержимое) этот прирост высовывался за реальную
     границу окна, читаясь как "карточка вываливается". Запас здесь —
     это и есть та ширина, в которую окно вырастает под сам разъезд. */
  align-self: center;
  padding: 40.5px 45px 25.5px;
  margin-bottom: 6px;
}

/* Шапка/ридаут окна результата тай-брейка — на 25% меньше базового
   .hud-res-head/.hud-res-readout (те же классы делит окно результата
   захвата, .capr-stage — поэтому переопределяем именно через .tbc-stage,
   не трогая базовые правила). */
.tbc-stage .hud-res-head {
  font-size: 9px;
  padding: 0 0 9px;
  margin-bottom: 19.5px;
}
.tbc-stage .hud-res-readout {
  width: 225px;
  padding: 12px 9px;
  margin-bottom: 19.5px;
}
.tbc-stage .hud-res-readout .l { font-size: 8.25px; }
/* Тот же размер, что у числа в карточке победителя (.tbc-card.tbc-win
   .tbc-answer, 41px) — по просьбе, чтобы обе цифры на экране результата
   читались одним весом. */
.tbc-stage .hud-res-readout .v { font-size: 41px; }

/* Медальон VS раньше служил распоркой между карточками (68px плюс
   притяжка translateX(±14px) у обеих). Его убрали — без зазора карточки
   налезают друг на друга на ~112px. Зазор великоват на вид именно
   потому, что scale(1.22) у карточки победителя НЕ занимает места в
   раскладке: визуально она шире своего бокса примерно на 30px с каждой
   стороны, и это тоже нужно компенсировать. 160px дают 24px чистого
   просвета между карточками — проверено замером. */
#question-card.hud-result .tbc-arena {
  gap: 136px;
}


/* Итог хода — прямоугольная строка-статус, как кнопка «Отправить». */
#question-card.hud-result .tbc-banner,
#question-card.hud-result .capr-banner {
  align-self: center;
  justify-content: center;
  margin-top: 22px;
  padding: 14px 28px;
  border-radius: 8px;
  border: 1px solid var(--accent-2);
  background: rgba(224, 188, 126, 0.1);
  box-shadow: none;
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-2);
  text-shadow: none;
}

/* Тай-брейк — на 25% меньше общего .tbc-banner/.capr-banner (тот делит
   размер с результатом захвата, трогать его нельзя). */
#question-card.hud-result .tbc-stage .tbc-banner {
  margin-top: 16.5px;
  padding: 10.5px 21px;
  font-size: 10.5px;
}

/* ==== Вопрос с четырьмя вариантами (бой) — консольная оправа ====
   Макет "Аватары и скобки" (Claude Design). Кегли вопроса и вариантов
   НЕ трогаем — боевые clamp-формулы остаются как есть. Меняется оправа:
   тёмный фон со сканлайнами, шапка с индикатором, у вариантов вместо
   сплошной рамки скобки по углам, а гербовый баннер с VS.png становится
   горизонтальной полосой со скобками — аватарки игроков сохранены.

   Всё ниже заскоуплено под #question-card.hud-mc: обычный вид того же
   окна (вне боя консоль не включается) не затрагивается. */

#question-card.hud-mc .question-box {
  position: relative;
  background: var(--bg);
  /* visible, не hidden: аватарки в .duel-vs-header специально торчат за
     верхнюю границу окна (см. ниже) — hidden их обрезал бы пополам. */
  overflow: visible;
  /* Без большой мин-высоты числового вопроса (55vh, под numpad) — окно
     дуэли из 4 вариантов короче и должно облегать свой контент, а не
     оставлять пустоту под ним. */
  min-height: 0;
}

/* Кегль на 25% меньше базового (clamp тот же, все числа × 0.75) — под
   окно дуэли из 4 вариантов, чтобы не читалось "на весь экран". */
#question-card.hud-mc .question-text {
  font-size: clamp(18px, min(2.55vw, 4.05vh), 45px);
}
#question-card.hud-mc .option {
  font-size: clamp(13.5px, min(1.5vw, 2.325vh), 25.5px);
}

#question-card.hud-mc .question-box::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
  background:
    repeating-linear-gradient(0deg, rgba(224, 188, 126, 0.035) 0px, rgba(224, 188, 126, 0.035) 1px, transparent 1px, transparent 3px),
    radial-gradient(700px 500px at 80% -10%, rgba(200, 150, 78, 0.14), transparent);
  pointer-events: none;
  z-index: 0;
}

#question-card.hud-mc #question-mode {
  position: relative;
  z-index: 1;
}

/* Шапка — та же строка, что в числовых вопросах. */
#question-card.hud-mc #question-category {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: 0 0 12px;
  margin: 0 0 18px;
  background: none;
  border: none;
  border-bottom: 1px solid transparent;
  border-image: linear-gradient(90deg, var(--accent) 0%, transparent 100%) 1;
  box-shadow: none;
}

/* --- Без отдельной панели: аватарки просто сидят по краям окна, ---
   наполовину высовываясь за его верхнюю границу (тот же приём, что у
   обычного .duel-vs-header, без промежуточного бара-фона). */
#question-card.hud-mc .duel-vs-header {
  position: relative;
  display: block;
  height: 0;
  margin: -20px -26px 30px;
  padding: 0;
  background: none;
  border: none;
  border-radius: 0;
  z-index: 2;
}

#question-card.hud-mc .duel-strip { display: none; }

/* .avatar внутри остаётся как есть — цвет/картинка игрока не трогаем. */
#question-card.hud-mc .duel-strip-avatar {
  position: absolute;
  top: -22px;
  width: 44px;
  height: 44px;
}
#question-card.hud-mc .duel-strip-avatar-atk { left: 16px; }
#question-card.hud-mc .duel-strip-avatar-def { right: 16px; left: auto; }
#question-card.hud-mc .duel-strip-avatar .avatar { width: 44px; height: 44px; }

/* Кольца: вместо золотого канта — тонкий ободок цветом игрока
   (--glow проставляет renderDuelVsHeader в game.js). */
#question-card.hud-mc .duel-strip-ring-gold {
  inset: -3px;
  background: rgba(var(--glow, 200, 150, 78), 0.55);
  box-shadow: none;
}
#question-card.hud-mc .duel-strip-avatar.is-answered .duel-strip-ring-gold {
  background: rgba(var(--glow, 200, 150, 78), 0.9);
  box-shadow: 0 0 14px 2px rgba(var(--glow, 200, 150, 78), 0.5);
}
#question-card.hud-mc .duel-strip-ring-gap { inset: -1px; background: var(--bg); }

/* Имя — моно-подпись НАД аватаркой (снизу упиралась в строку категории
   "ДУЭЛЬ ЗА ТЕРРИТОРИЮ/РАУНД X" сразу под аватаркой и налезала на неё).
   Сверху всё ещё вырастает из 44-пиксельной обёртки, но там уже пусто —
   фон карты, а не текст карточки. */
#question-card.hud-mc .duel-strip-name {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-bottom: 2px;
  max-width: 150px;
  padding: 0;
  border: none;
  border-radius: 0;
  background: none;
  box-shadow: none;
  text-shadow: none;
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 13px;
  font-weight: 700;
  text-align: center;
}

/* Галочка «ответил» — маленький моно-бейдж в углу аватарки. Кремово-
   бежевая (--accent-2), не зелёная (--good): зелёный тут читался как
   "верно", хотя означает только сам факт ответа, ещё до раскрытия. */
#question-card.hud-mc .duel-strip-check {
  top: -6px;
  left: auto;
  right: -8px;
  width: 20px;
  height: 20px;
  font-size: 13px;
  background: var(--accent-2);
  color: var(--bg);
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
  transform: scale(0);
}
#question-card.hud-mc .duel-strip-check.is-answered { transform: scale(1); }

/* Эмблема сверху окна — общая для трёх боевых карточек (MC-дуэль, вопрос
   тай-брейка, результат тай-брейка): наполовину торчит за верхнюю
   границу, 50% от исходного размера файла. ::after, а не ::before — тот
   занят фоном-сканлайнами (.question-box::before выше). :not(.hud-capr)
   у hud-result исключает результат ЗАХВАТА (та же .hud-result оправа, но
   своя "тройка карточек" без герба поединка).
   По умолчанию — VS.png (150×146 → 75×73, обычная территория); когда
   #question-card помечена .vs-castle (see setVsCastle() в game.js — сама
   атака на замок/башню, а не просто дуэль) — castle_attack.png (150×116
   → 75×58, другие пропорции файла, поэтому своя высота и свой top). */
#question-card.hud-mc .question-box::after,
#question-card.hud-duel .question-box::after,
#question-card.hud-result:not(.hud-capr) .question-box::after {
  content: "";
  position: absolute;
  top: -37px;
  left: 50%;
  transform: translateX(-50%);
  width: 75px;
  height: 73px;
  background: url('../window_quest/VS.png') center / contain no-repeat;
  pointer-events: none;
  z-index: 5;
}
#question-card.hud-mc.vs-castle .question-box::after,
#question-card.hud-duel.vs-castle .question-box::after,
#question-card.hud-result.vs-castle:not(.hud-capr) .question-box::after {
  /* 75×58 (50% исходника) × 1.3 = 97.5×75.4 */
  top: -37.7px;
  width: 97.5px;
  height: 75.4px;
  /* ?v= — держать в синхроне с CASTLE_ATTACK_ICON в game.js (см. комментарий
     там): /window_quest/ кэшируется на неделю (vercel.json), при замене
     файла нужен новый номер в ОБОИХ местах, иначе покажет старую картинку. */
  background-image: url('../window_quest/castle_attack.png?v=2');
}

/* Окно вопроса тай-брейка (.hud-console.hud-duel) — overflow:hidden от
   общей консольной оправы обрезал бы герб ровно по границе, вместо
   ожидаемого "наполовину наружу". */
#question-card.hud-duel .question-box { overflow: visible; }

/* --- Варианты ответа: скобки вместо сплошной рамки --- */
#question-card.hud-mc .options { gap: 12px; }

#question-card.hud-mc .option {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 18px;
  /* скобки убраны — границу даёт обычная рамка, как у клавиш numpad */
  border: 1px solid rgba(154, 163, 199, 0.2);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.04);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
}


#question-card.hud-mc .opt-idx { display: block;
  flex: none;
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 13px;
  font-weight: 700;
  color: var(--accent-2);
}

#question-card.hud-mc .option:hover:not(:disabled) {
  background: rgba(200, 150, 78, 0.1);
  border-color: rgba(200, 150, 78, 0.55);
}

/* Состояния: цвет уходит в скобки и подложку, рамки по-прежнему нет. */
#question-card.hud-mc .option.correct {
  border-color: var(--good);
  background: rgba(158, 207, 122, 0.14);
  box-shadow: 0 0 22px rgba(158, 207, 122, 0.3);
}
#question-card.hud-mc .option.correct .opt-idx { color: var(--good); }
#question-card.hud-mc .option.wrong {
  border-color: var(--bad);
  background: rgba(224, 122, 95, 0.12);
  color: var(--bad);
  box-shadow: none;
}
#question-card.hud-mc .option.wrong .opt-idx { color: var(--bad); }
#question-card.hud-mc .option.selected { border-color: var(--accent-2); }

/* Бейджи «X ответил» и строка исхода — в моно, как в числовых вопросах. */
#question-card.hud-mc .duel-answered-side {
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 15px;
  border-radius: 8px;
  padding: 7px 16px;
  /* Не 0: пустой (текста ещё нет) и заполненный ("X ответил") бейдж
     должны совпадать по высоте — иначе окно вопроса чуть подрастает и
     садится обратно в момент появления/исчезновения бейджа. Формула та
     же, что у базового .duel-answered-side (1.3em + вертикальный
     padding), просто под свой paddiing (7px×2=14px) и кегль (15px). */
  min-height: calc(1.3em + 14px);
  background: rgba(0, 0, 0, 0.3);
  box-shadow: none;
}

#question-card.hud-mc .duel-result-pill {
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-2);
  background: rgba(224, 188, 126, 0.1);
  border: 1px solid var(--accent-2);
  border-radius: 8px;
  padding: 13px 26px;
  box-shadow: none;
}

#question-card.hud-mc .waiting-note {
  font-family: "JetBrains Mono", "Courier New", monospace;
  font-size: 13px;
}

/* .opt-idx скрыт вне консоли (см. .hud-mc выше), а .opt-text — просто
   обёртка текста варианта: нужна, чтобы скобки-спаны не влияли на
   выравнивание строки в обычном режиме. */
.opt-idx { display: none; }
.option .opt-text { display: inline; }

/* ==== Масштаб окон по высоте экрана ====
   .question-box целиком масштабируется через zoom (базовое правило выше) —
   меняются и окно, и содержимое пропорционально.

   Лестницы РАЗНЫЕ, потому что запас по высоте у окон разный. Замер на
   длинном вопросе базы и трёх карточках результата дал предельный zoom,
   при котором ничего не обрезается (высота игровой области → предел):

       игровая область   вопросы   результаты и бой
            560px          0.59          0.81
            700px          0.74          1.01
            900px          0.96          1.31

   Держит всегда окно ВОПРОСА захвата — самое высокое из пяти (крупный
   текст + сетка отряда + поле ввода + цифровой блок + кнопка). Привязывать
   к его пределу ещё и результаты значило бы держать карточки мелкими без
   причины, поэтому у них своя, более щедрая лестница.

   Пороги ниже — по высоте ОКНА БРАУЗЕРА; игровая область примерно на 90px
   меньше (верхняя панель). Значения взяты как ~92% от предела на нижней
   границе каждой ступени — запас на имена и вопросы длиннее тестового. */

/* --- окна числовых вопросов --- */
#question-card.hud-console .question-box { zoom: 0.52; }
@media (min-height: 650px) { #question-card.hud-console .question-box { zoom: 0.55; } }
@media (min-height: 790px) { #question-card.hud-console .question-box { zoom: 0.68; } }
@media (min-height: 890px) { #question-card.hud-console .question-box { zoom: 0.79; } }
@media (min-height: 990px) { #question-card.hud-console .question-box { zoom: 0.88; } }

/* --- окна результатов и вопроса боя: крупнее, запас позволяет --- */
#question-card.hud-result .question-box,
#question-card.hud-mc .question-box { zoom: 0.72; }
@media (min-height: 650px) {
  #question-card.hud-result .question-box,
  #question-card.hud-mc .question-box { zoom: 0.76; }
}
@media (min-height: 790px) {
  #question-card.hud-result .question-box,
  #question-card.hud-mc .question-box { zoom: 0.93; }
}
@media (min-height: 890px) {
  #question-card.hud-result .question-box,
  #question-card.hud-mc .question-box { zoom: 1.07; }
}
@media (min-height: 990px) {
  #question-card.hud-result .question-box,
  #question-card.hud-mc .question-box { zoom: 1.20; }
}
@media (min-height: 1090px) {
  #question-card.hud-result .question-box,
  #question-card.hud-mc .question-box { zoom: 1.34; }
}
