/*
  «Буферная зона» — стили главного экрана (шаг 27).
  Палитра и типографика — ТОЧНО из docs/GAME_DESIGN.md, Часть I, п.2 и п.6.
  Без фреймворков/препроцессоров — обычный CSS, переменные в :root.
*/

:root {
  /* Базовые цвета (GAME_DESIGN.md, Часть I, п.2) */
  --color-graphite: #1B1F23;   /* почти чёрный графит — контуры, тени, текстовая плашка карточки */
  --color-blue-grey: #2E3A46;  /* холодный синевато-серый — основной фон карточек */
  --color-muted-grey: #5C6B73; /* приглушённый серо-голубой — фон-трек полос шкал */
  --color-paper: #C9CDC7;      /* пыльный светло-серый — "бумага", текст на тёмном */

  /* Акценты (роли/шкалы) */
  --color-red: #B23A2E;   /* Союз, тревога */
  --color-blue: #3A6B8A;  /* Альянс, "демократия" как бренд */
  --color-gold: #E0A93C;  /* ордена/звёзды — оба полюса */
  --color-olive: #7A8C5A; /* буферные страны, нейтралитет */

  /*
    Цвет заполнения шкалы = "акцентный цвет соответствующей шкалы"
    (GAME_DESIGN.md, п.6) — но документ не закрепляет ОДИН цвет за КАЖДОЙ
    из 4 шкал явно (акценты в п.2 описаны как цвета РОЛЕЙ, не шкал).
    Решение шага 27 (флагаю, не тихо): по одному цвету на шкалу, используя
    все 4 акцента без повторов. "Силовики → золото" — единственное, что
    подтверждено текстом самой иконки (п.3: "звезда меняет насыщенность
    золотого в зависимости от уровня"), остальные 3 — обоснованный, но
    самостоятельный выбор (см. CHANGELOG, шаг 27).
  */
  --stat-people-color: var(--color-red);
  --stat-loyalists-color: var(--color-gold);
  --stat-economy-color: var(--color-blue);
  --stat-front-color: var(--color-olive);

  --font-main: "PT Mono", "Courier New", monospace;

  /*
    Шаг 27.1: сколько вертикального места вокруг карточки резервируем на
    "хром" интерфейса, чтобы вычислить ширину карточки от РЕАЛЬНОЙ высоты
    экрана, а не только от ширины (см. CHANGELOG, шаг 27.1, о причине
    скролла на мобильных). Шаг 27.5: шапка вынесена из потока (position:
    fixed) — больше не складывается в бюджет построчно, но нужен зазор
    сверху, чтобы карточка не подъезжала под неё на низких экранах.
    Оценка: верхний зазор под шапку ~64px + отступы страницы 2*~24px +
    gap'ы 2*~16px + ряд кнопок ~64px + запас ~30px ≈ 220px.
  */
  --card-chrome-reserve: 220px;
}

/*
  Шаг 33: у vs-ai матчей над шкалами игрока появляется панель состояния
  оппонентов (.opponent-panel) — занимает дополнительное вертикальное
  место, которого не было в бюджете шага 27.1. Класс переключается из
  game.js (applyState) по факту наличия state.countries — только тогда,
  когда эта панель реально на экране, не всегда (иначе одиночная игра
  без реальной необходимости получила бы карточку чуть меньше, чем могла
  бы). Оценка добавки: 2 пилюли-индикатора ~34px + сворачиваемая лента
  (заголовок ~22px, раскрытая не влияет — max-height со скроллом
  внутри) + gap ~8px ≈ +70px к прежним 220px.
*/
body.vs-ai-mode {
  --card-chrome-reserve: 290px;
}

* {
  box-sizing: border-box;
}

html, body {
  height: 100%;
}

body {
  margin: 0;
  /*
    Шаг 27.1, фикс переполнения на мобильных: 100vh на мобильных браузерах
    считается от САМОГО БОЛЬШОГО возможного viewport'а (когда адресная
    строка свёрнута), а не от реально видимой сейчас области — если
    строка показана, реальная видимая высота МЕНЬШЕ, чем 100vh, и контент,
    "точно помещающийся в 100vh" по факту вылезает за экран. 100svh
    (small viewport height, строка точно показана) и 100dvh (dynamic,
    следует за реальным состоянием строки) решают это — но поддерживаются
    не всеми браузерами, поэтому 3 объявления подряд: неподдерживаемая
    единица игнорируется браузером целиком, а не даёт 0 — последнее
    ПОДДЕРЖИВАЕМОЕ побеждает. 100vh — рабочий fallback для старых браузеров.
  */
  min-height: 100vh;
  min-height: 100svh;
  min-height: 100dvh;
  background: var(--color-graphite);
  color: var(--color-paper);
  font-family: var(--font-main);
  /* На широких экранах вокруг карточки — не пустота, а лёгкий двухцветный
     фон из палитры (не однотонная заливка) */
  background-image:
    radial-gradient(circle at 50% 0%, var(--color-blue-grey) 0%, var(--color-graphite) 70%);
}

.page {
  min-height: 100vh;
  min-height: 100svh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: clamp(0.75rem, 3vw, 2rem);
  /*
    Шаг 27.5: шапка и правый верхний угол (меню/помощь) вынесены из потока
    (position:fixed, см. .brand-header/.top-right-controls ниже) — .page
    больше не делит место с ними построчно, но на низких экранах
    карточка/шкалы могли бы всё равно наехать ПОД них, поэтому верхний
    отступ увеличен отдельно.
  */
  padding-top: clamp(3.25rem, 11vw, 4.25rem);
  gap: clamp(0.75rem, 2.5vw, 1.5rem);
}

/* ===== Шапка с брендом (шаг 27.5: фиксированный левый верхний угол) ===== */

.brand-header {
  /*
    Раньше — обычная строка внутри .page, "отжимала" карточку вниз
    (см. историю правок в CHANGELOG, шаг 27.1). Пользователь попросил
    перенести в угол, чтобы карточка/шкалы/кнопки могли расположиться
    выше — вынесена из потока полностью, поверх контента.
  */
  position: fixed;
  top: clamp(0.75rem, 3vw, 1.25rem);
  left: clamp(0.75rem, 3vw, 1.25rem);
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.brand-header__logo {
  width: clamp(28px, 6vw, 40px);
  height: clamp(28px, 6vw, 40px);
  flex-shrink: 0;
  /*
    logo.png сгенерирован с непрозрачным сплошным фоном (промпт шага 26:
    "centered composition on a solid graphite black background") — на
    размере ~40px это читается как жёсткий плавающий прямоугольник, а не
    иконка/знак. border-radius смягчает угол без перегенерации файла.
  */
  border-radius: 8px;
}

.brand-header__title {
  font-size: clamp(1rem, 3vw, 1.3rem);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--color-paper);
}

/*
  Шаг 27.5, по прямому запросу: на мобильном (тот же брейкпоинт 700px,
  что и ниже у .page) название рядом с логотипом не нужно — экономим
  место в углу, оставляем только сам знак. На широких экранах — показываем
  оба, как раньше.
*/
@media (max-width: 699px) {
  .brand-header__title {
    display: none;
  }
}

/* ===== Кнопки в правом верхнем углу — меню + помощь (шаг 27.5, шаг 28.1:
   симметрично шапке слева) ===== */

.top-right-controls {
  position: fixed;
  top: clamp(0.75rem, 3vw, 1.25rem);
  right: clamp(0.75rem, 3vw, 1.25rem);
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.icon-button {
  width: clamp(28px, 6vw, 40px);
  height: clamp(28px, 6vw, 40px);
  border-radius: 50%;
  border: 2px solid var(--color-paper);
  background: transparent;
  color: var(--color-paper);
  font-family: var(--font-main);
  font-size: clamp(0.9rem, 3vw, 1.1rem);
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.icon-button:hover,
.icon-button:focus-visible {
  background: var(--color-paper);
  color: var(--color-graphite);
}

/*
  Шаг 29: mute-button — SVG внутри .icon-button, stroke/fill: currentColor
  подхватывает и обычный, и hover-цвет кнопки автоматически, без
  дублирования палитры в SVG. Две группы путей переключаются по
  aria-pressed (true = звук выключен) — JS (audio.js/main.js) только
  меняет атрибут, видимость путей — чистый CSS.
*/
.mute-button__muted-line {
  display: none;
}

#mute-button[aria-pressed="true"] .mute-button__waves {
  display: none;
}

#mute-button[aria-pressed="true"] .mute-button__muted-line {
  display: block;
}

/*
  Шаг 28.1 (уточнение): стрелка "←" как единственный глиф в круглой
  кнопке была не по центру и слишком тонкой на части устройств/шрифтов —
  замена на явный текст "В меню" в кнопке-пилюле (не круг — текст не
  вписывается в квадратную область без обрезки/сжатия).
*/
.menu-button {
  height: clamp(28px, 6vw, 40px);
  padding: 0 clamp(0.7rem, 3vw, 1rem);
  border-radius: 999px;
  border: 2px solid var(--color-paper);
  background: transparent;
  color: var(--color-paper);
  font-family: var(--font-main);
  font-size: clamp(0.7rem, 2.3vw, 0.85rem);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.menu-button:hover,
.menu-button:focus-visible {
  background: var(--color-paper);
  color: var(--color-graphite);
}

/*
  Шаг 27.5: попап помощи — пока пустой (только крестик), содержимое
  (инструкция для игрока) добавится отдельным шагом. Открытие/закрытие —
  client/js/helpModal.js.
*/
.help-modal {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
}

.help-modal.is-hidden {
  display: none;
}

.help-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(27, 31, 35, 0.72);
}

.help-modal__panel {
  position: relative;
  width: min(90vw, 420px);
  max-height: 80vh;
  overflow-y: auto;
  border-radius: 14px;
  border: 3px solid var(--color-paper);
  background: var(--color-blue-grey);
  padding: clamp(1rem, 4vw, 1.5rem);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
}

.help-modal__close {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 2px solid var(--color-paper);
  background: transparent;
  color: var(--color-paper);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
}

.help-modal__close:hover,
.help-modal__close:focus-visible {
  background: var(--color-paper);
  color: var(--color-graphite);
}

.help-modal__body {
  min-height: 2rem;
  color: var(--color-paper);
  font-size: clamp(0.85rem, 2.6vw, 1rem);
  line-height: 1.5;
}

/* ===== Контейнер приложения ===== */

.app {
  width: 100%;
  max-width: 480px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(0.75rem, 2.5vw, 1.25rem);
  flex: 1;
  justify-content: center;
  /*
    Классический flexbox-фикс: без min-height:0 flex-элемент по умолчанию
    не может сжаться меньше своего содержимого внутри flex-колонки (.page)
    — если карточка+кнопки в сумме выше доступного места, .app раздувает
    .page вместо того, чтобы позволить карточке ужаться под реальную
    высоту (см. также height-aware .card ниже).
  */
  min-height: 0;

  /*
    Единая переменная ширины "колонки контента" — раньше формула
    min(94vw, 420px, calc(...)) была продублирована в .card и .choices по
    отдельности (шаг 27.1). Шаг 27.3 добавляет третьего потребителя
    (.stat-bars, шкалы вынесены НАД карточку) — дублировать трёхстрочный
    vh/svh/dvh-каскад в третьем месте уже неоправданно, считаем один раз.
  */
  --content-width: min(94vw, 420px, calc((100vh - var(--card-chrome-reserve)) * 3 / 4));
  --content-width: min(94vw, 420px, calc((100svh - var(--card-chrome-reserve)) * 3 / 4));
  --content-width: min(94vw, 420px, calc((100dvh - var(--card-chrome-reserve)) * 3 / 4));

  /* Якорь для .decision-toast (шаг 27.4) — попап позиционируется
     абсолютно по центру .app, поверх карточки. */
  position: relative;
}

.app__loading-fallback,
.app__message {
  text-align: center;
  color: var(--color-paper);
  font-size: clamp(0.9rem, 2.5vw, 1.1rem);
}

.app__error {
  color: var(--color-red);
  text-align: center;
  font-size: clamp(0.85rem, 2.3vw, 1rem);
}

/* ===== Лобби (шаг 28: выбор режима + опционально фигуры) ===== */

.lobby {
  width: var(--content-width);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1rem, 4vw, 1.75rem);
}

.lobby__logo {
  width: clamp(56px, 14vw, 84px);
  height: clamp(56px, 14vw, 84px);
  /* Тот же приём, что и у .brand-header__logo (шаг 27.1) — logo.png со
     сплошным фоном, border-radius смягчает жёсткий угол. Крупнее, чем в
     фиксированной шапке — здесь это "титульный" момент лобби, не просто
     опознавательный знак. */
  border-radius: 12px;
}

.lobby__title {
  margin: 0;
  font-size: clamp(1.3rem, 5vw, 1.8rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-align: center;
  color: var(--color-paper);
  font-weight: normal;
}

.lobby__subtitle {
  margin: 0;
  font-size: clamp(1.05rem, 3.5vw, 1.3rem);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-align: center;
  color: var(--color-paper);
  font-weight: normal;
}

.mode-select,
.figure-select {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: clamp(0.6rem, 3vw, 1rem);
}

/*
  Кнопки-карточки режима/фигуры — стилизованы под тему (двойная рамка,
  как у .card, не дефолтная HTML-кнопка), но НЕ под штампы (.stamp) —
  тут выбор режима игры, а не решение по карточке-событию, разная
  семантика заслуживает разного визуального языка при общей палитре.
*/
.mode-card,
.figure-card {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.35rem;
  text-align: left;
  font-family: var(--font-main);
  padding: clamp(0.85rem, 3vw, 1.25rem);
  border-radius: 10px;
  border: 3px solid var(--color-paper);
  outline: 2px solid var(--color-graphite);
  outline-offset: -6px;
  background: var(--color-blue-grey);
  color: var(--color-paper);
  cursor: pointer;
  transition: transform 0.15s ease, border-color 0.15s ease;
}

.mode-card:hover,
.mode-card:focus-visible,
.figure-card:not(:disabled):hover,
.figure-card:not(:disabled):focus-visible {
  border-color: var(--color-gold);
  transform: scale(1.015);
}

.mode-card:active,
.figure-card:not(:disabled):active {
  transform: scale(0.98);
}

.mode-card__title,
.figure-card__name {
  font-size: clamp(1rem, 3.2vw, 1.2rem);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--color-gold);
}

.mode-card__hint,
.figure-card__mods {
  font-size: clamp(0.8rem, 2.4vw, 0.95rem);
  line-height: 1.4;
  color: var(--color-paper);
  opacity: 0.85;
}

.figure-card--locked {
  cursor: default;
  opacity: 0.5;
}

.figure-card__lock {
  font-size: clamp(0.7rem, 2.2vw, 0.8rem);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-red);
}

.figure-select__skip {
  align-self: center;
  margin-top: 0.25rem;
  background: transparent;
  border: none;
  color: var(--color-paper);
  font-family: var(--font-main);
  font-size: clamp(0.85rem, 2.6vw, 1rem);
  text-decoration: underline;
  cursor: pointer;
}

.figure-select__skip:hover,
.figure-select__skip:focus-visible {
  color: var(--color-gold);
}

/* ===== Карточка (GAME_DESIGN.md, Часть I, п.6) ===== */

.card {
  /*
    Шаг 27.1: ширина карточки ограничена одновременно и шириной, и высотой
    экрана — см. --content-width в .app (три vh/svh/dvh-варианта каскадом,
    неподдерживаемая единица отбрасывает ВСЁ объявление целиком, новые
    поддерживаемые просто перекрывают старые).
  */
  width: var(--content-width);
  aspect-ratio: 3 / 4;
  display: grid;
  /*
    Шаг 27.3: было 3 ряда (60/25/15 — иллюстрация/текст/шкалы, спецификация
    арт-директора). Шкалы вынесены НАД карточку отдельным блоком
    (.stat-bars ниже, см. CHANGELOG) — остались 2 ряда, пропорция
    иллюстрация:текст сохранена (60:25 -> 70:30 после нормализации без
    третьей зоны).
  */
  grid-template-rows: 70fr 30fr;
  border-radius: 14px;
  overflow: hidden;
  /* Двойная рамка по периметру: внешняя #C9CDC7 + внутренняя #1B1F23 */
  border: 3px solid var(--color-paper);
  outline: 2px solid var(--color-graphite);
  outline-offset: -6px;
  background: var(--color-blue-grey);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
  /* Шаг 31: якорь для .card__swipe-stamp (position:absolute внутри). */
  position: relative;
  /*
    Шаг 31, п.6 задания: без этого драг пальцем по карточке на мобильном
    конфликтует с браузерными жестами (pull-to-refresh, попытка
    проскроллить страницу) — touch-action:none на самой перетаскиваемой
    области полностью отдаёт обработку жеста нашему JS (cardSwipe.js),
    браузер не пытается интерпретировать его по-своему.
  */
  touch-action: none;
  cursor: grab;
}

/*
  Шаг 31: печати-подсказки направления свайпа — GAME_DESIGN.md, Часть I,
  п.6: "слева — красная печать «ОТКАЗАТЬ», справа — золотая «ОДОБРИТЬ»".
  Текст — РЕАЛЬНАЯ подпись варианта этой карточки (та же, что на кнопке
  ниже), не буквально "ОТКАЗАТЬ"/"ОДОБРИТЬ" — спецификация даёт это как
  иллюстративный пример через "например", а не как требование к тексту.
  Видимость (opacity) управляется инлайн-стилем из cardSwipe.js во время
  драга, здесь только базовое состояние (0 = не видно, пока не тянут).
*/
.card__swipe-stamp {
  position: absolute;
  top: 50%;
  max-width: 55%;
  padding: clamp(0.4rem, 2vw, 0.7rem) clamp(0.6rem, 2.5vw, 1rem);
  border: 4px solid currentColor;
  border-radius: 8px;
  font-family: var(--font-main);
  font-size: clamp(0.85rem, 3vw, 1.15rem);
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  line-height: 1.2;
  text-align: center;
  background: rgba(27, 31, 35, 0.55);
  opacity: 0;
  pointer-events: none;
  z-index: 5;
}

.card__swipe-stamp--a {
  left: clamp(0.5rem, 4vw, 1rem);
  color: var(--color-red);
  transform: translateY(-50%) rotate(-10deg);
}

.card__swipe-stamp--b {
  right: clamp(0.5rem, 4vw, 1rem);
  color: var(--color-gold);
  transform: translateY(-50%) rotate(10deg);
}

.card__illustration {
  background-color: var(--color-blue-grey);
  /*
    Шаг 27.3, подтверждённая причина обрезки иллюстраций: сгенерированные
    файлы (шаг 23-24) — 896×1200px, то есть соотношение ~0.747:1 (портрет,
    почти как сама карточка целиком, 3:4=0.75:1). Зона иллюстрации внутри
    карточки — куда более "широкая" форма (при 70% высоты 3:4-карточки
    соотношение зоны ≈1.07:1, раньше при 60% было ≈1.25:1) — с
    background-size:cover браузер масштабирует узкое высокое изображение
    по ширине зоны, из-за чего оно становится значительно выше зоны и
    обрезается сверху/снизу (в кадре пользователя было видно обрезанную
    руку/монету у самого верхнего края). contain показывает изображение
    ЦЕЛИКОМ без обрезки — ценой узких полей по бокам (letterbox, залиты
    тем же --color-blue-grey, что и рамка карточки, поэтому не читаются
    как "пустота"). background-repeat:no-repeat обязателен при contain —
    иначе браузер замостит пустые поля повторами картинки.
  */
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

.card__text {
  background: var(--color-graphite);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(0.5rem, 2vw, 1rem);
  text-align: center;
}

.card__text p {
  margin: 0;
  color: var(--color-paper);
  font-size: clamp(0.95rem, 3.2vw, 1.35rem);
  line-height: 1.35;
}

/*
  Шаг 33: панель состояния union-ai/alliance-ai (только vs-ai матчи) —
  НАД шкалами игрока, компактная: агрегированный "индикатор здоровья" на
  роль (не второй набор из 4 полосок каждая, см. GAME_DESIGN.md), плюс
  сворачиваемая (<details>, без JS на сам toggle) лента нейтральных
  сводок по ходам. Стилистика — телеграфная сводка, приглушённые тона,
  не яркие игровые уведомления (п.4 задания).
*/
.opponent-panel {
  width: var(--content-width);
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.opponent-pills {
  display: flex;
  gap: 0.5rem;
}

.opponent-pill {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.6rem;
  border-radius: 999px;
  border: 1.5px solid var(--color-muted-grey);
  background: rgba(0, 0, 0, 0.15);
  font-size: clamp(0.68rem, 2.1vw, 0.8rem);
  min-width: 0;
}

.opponent-pill__name {
  color: var(--color-paper);
  font-weight: bold;
  text-transform: uppercase;
  white-space: nowrap;
}

.opponent-pill__status {
  flex: 1;
  color: currentColor;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.opponent-pill__bar {
  width: 26px;
  height: 5px;
  flex-shrink: 0;
  border-radius: 999px;
  background: var(--color-muted-grey);
  overflow: hidden;
}

.opponent-pill__bar-fill {
  height: 100%;
  background: currentColor;
}

.opponent-pill--up {
  color: var(--color-olive);
}

.opponent-pill--neutral {
  color: var(--color-gold);
}

.opponent-pill--down {
  color: var(--color-red);
}

.opponent-feed {
  font-size: clamp(0.68rem, 2.1vw, 0.78rem);
}

.opponent-feed__summary {
  cursor: pointer;
  color: var(--color-muted-grey);
  list-style: none;
}

.opponent-feed__summary::-webkit-details-marker {
  display: none;
}

.opponent-feed__summary::before {
  content: "▸ ";
}

.opponent-feed[open] > .opponent-feed__summary::before {
  content: "▾ ";
}

.opponent-feed__list {
  margin: 0.35rem 0 0;
  padding: 0 0 0 0.6rem;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  max-height: 110px;
  overflow-y: auto;
}

.opponent-feed__item {
  color: var(--color-paper);
  opacity: 0.8;
}

.opponent-feed__item--up {
  color: var(--color-olive);
}

.opponent-feed__item--down {
  color: var(--color-red);
}

/*
  Шаг 27.3: шкалы вынесены НАД карточку отдельным блоком (раньше —
  .card__stats, нижняя зона внутри самой карточки, см. историю в
  CHANGELOG). Явный флаг: это отход от исходной спецификации арт-директора
  (GAME_DESIGN.md, Часть I, п.6 — "3 зоны внутри карточки, нижняя ≈15% —
  шкалы") по прямому запросу пользователя, с референсом-скриншотом другой
  Reigns-подобной игры: горизонтальный ряд иконок в отдельной полосе НАД
  карточкой. Задокументировано как решение, а не тихая правка (см.
  GAME_DESIGN.md).
*/
.stat-bars {
  width: var(--content-width);
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  gap: clamp(0.5rem, 2.5vw, 1rem);
}

.stat-bar {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(0.3rem, 1.2vw, 0.5rem);
  flex: 1;
  min-width: 0;
  /* Якорь для .stat-bar__delta (шаг 27.2) — всплывающая дельта
     позиционируется абсолютно относительно всей колонки шкалы. */
  position: relative;
}

.stat-bar__icon {
  /*
    Шаг 27.3: иконки укрупнены (24-30px -> 32-44px) — это теперь отдельная
    полоса над карточкой, а не стеснённая нижняя зона внутри неё.
  */
  width: clamp(32px, 8vw, 44px);
  height: clamp(32px, 8vw, 44px);
  flex-shrink: 0;
  /*
    Шаг 27.1 диагностировал причину "невидимых" иконок (файлы — ЧЁРНАЯ
    линия на НЕПРОЗРАЧНОМ БЕЛОМ фоне, filter:invert(1) инвертировал и фон
    тоже) и чинил её светлым "бейджем"-подложкой под иконкой. Шаг 27.3:
    пользователь попросил вместо badge-подложки настоящий прозрачный фон
    у самих иконок. Файлы пересозданы (Pillow, порогом по яркости:
    альфа = 255 − luminance, RGB залит --color-paper) — теперь это
    RGBA-PNG, линия сама по себе светлая и прозрачная за пределами линии,
    контраст с тёмным фоном страницы обеспечивается ЦВЕТОМ линии, а не
    отдельной подложкой. background/padding/border-radius больше не нужны.
  */
}

.stat-bar__track {
  width: 100%;
  height: clamp(8px, 2vw, 12px);
  background: var(--color-muted-grey);
  border-radius: 999px;
  overflow: hidden;
}

.stat-bar__fill {
  height: 100%;
  border-radius: 999px;
  /* Эта transition уже существовала с шага 27, но реально проигрывалась
     только в теории — раньше вся карточка (включая шкалы) уничтожалась и
     пересоздавалась заново между решением и показом новой карточки
     (renderWaiting → applyState), так что браузер никогда не видел
     "старое" значение перед "новым" — переход был мгновенным скачком, не
     анимацией. Шаг 27.2 (game.js: playDecisionReaction) специально
     оставляет ЭТИ ЖЕ DOM-элементы на месте и меняет им width на
     следующем кадре — только тогда transition реально видна. */
  transition: width 0.3s ease;
}

/* Шаг 27.2: всплывающая "печать"-дельта (+10/−5) рядом со шкалой,
   которая изменилась этим решением. Создаётся/удаляется из JS
   (game.js: playDecisionReaction) — сам элемент живёт ровно один ход,
   следующий renderCard() пересоздаёт всю карточку заново. */
.stat-bar__delta {
  position: absolute;
  /* Шаг 27.3: .stat-bar теперь колонка (иконка сверху, трек снизу), а не
     строка — дельта якорится по ГОРИЗОНТАЛЬНОМУ центру колонки (было:
     left:0, под старую раскладку "иконка слева"). left:50% скомпенсирован
     через translateX(-50%) прямо в keyframes ниже (нельзя одновременно
     задать статичный transform здесь и анимировать transform в
     @keyframes — вторая перезапишет первую, поэтому центрирование внесено
     в каждый шаг анимации). */
  left: 50%;
  top: -8px;
  font-size: clamp(0.7rem, 2.2vw, 0.85rem);
  font-weight: bold;
  padding: 1px 5px;
  border-radius: 4px;
  border: 1.5px solid currentColor;
  background: var(--color-graphite);
  pointer-events: none;
  /*
    Шаг 27.4: длительность задаётся ОТДЕЛЬНЫМ свойством (не в shorthand),
    чтобы game.js мог переопределить её инлайн-стилем и держать РОВНО
    синхронной с REACTION_DURATION_MS (сейчас 3с, по прямому запросу
    пользователя — было 0.9с, оказалось мало, чтобы прочитать цифру).
    Значение здесь — просто дефолт на случай, если инлайн-стиль почему-то
    не применился.
  */
  animation-name: stat-delta-pop;
  animation-timing-function: ease;
  animation-fill-mode: forwards;
  animation-duration: 5s;
}

.stat-bar__delta--up {
  color: var(--color-olive);
}

.stat-bar__delta--down {
  color: var(--color-red);
}

@keyframes stat-delta-pop {
  0% {
    opacity: 0;
    transform: translate(-50%, 4px) rotate(-6deg) scale(0.85);
  }
  20% {
    opacity: 1;
    transform: translate(-50%, -6px) rotate(-6deg) scale(1.05);
  }
  75% {
    opacity: 1;
    transform: translate(-50%, -10px) rotate(-6deg) scale(1);
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -16px) rotate(-6deg) scale(0.95);
  }
}

/*
  Шаг 27.4: попап с текстовым резюме последствий решения ("Экономика −10 ·
  Народ +5"), поверх карточки, поверх .app (см. .app { position:relative }
  выше). Отдельно от поштучных .stat-bar__delta у шкал — тот же результат,
  но текстом и крупнее, чтобы читалось с одного взгляда, без необходимости
  разглядывать 4 маленьких значка. Создаётся/удаляется из JS
  (game.js: playDecisionReaction), сам гаснет — без ручного закрытия.
*/
.decision-toast {
  position: absolute;
  top: 50%;
  left: 50%;
  max-width: 88%;
  padding: clamp(0.5rem, 2vw, 0.8rem) clamp(0.75rem, 3vw, 1.1rem);
  border-radius: 10px;
  border: 2px solid var(--color-paper);
  background: var(--color-graphite);
  color: var(--color-paper);
  font-size: clamp(0.85rem, 2.6vw, 1rem);
  line-height: 1.4;
  text-align: center;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.5);
  z-index: 10;
  pointer-events: none;
  animation-name: decision-toast-pop;
  animation-timing-function: ease;
  animation-fill-mode: forwards;
  /* Дефолт-длительность — реально задаётся инлайн из game.js, синхронно с
     REACTION_DURATION_MS (см. комментарий у .stat-bar__delta выше). */
  animation-duration: 5s;
}

@keyframes decision-toast-pop {
  0% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.92);
  }
  10% {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
  85% {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.96);
  }
}

/* ===== Кнопки-штампы вместо свайпа (шаг 27; свайп — отдельным шагом позже) ===== */

.choices {
  width: var(--content-width);
  display: flex;
  gap: clamp(0.6rem, 3vw, 1rem);
}

.stamp {
  flex: 1;
  font-family: var(--font-main);
  font-size: clamp(0.75rem, 2.6vw, 0.95rem);
  line-height: 1.25;
  padding: clamp(0.6rem, 2.2vw, 0.9rem) clamp(0.5rem, 2vw, 0.75rem);
  border-radius: 6px;
  border: 3px solid currentColor;
  background: transparent;
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  transition: transform 0.15s ease, background-color 0.15s ease;
}

.stamp:hover:not(:disabled),
.stamp:focus-visible:not(:disabled) {
  background-color: currentColor;
}

.stamp:hover:not(:disabled) .stamp__label,
.stamp:focus-visible:not(:disabled) .stamp__label {
  color: var(--color-graphite);
}

.stamp:active:not(:disabled) {
  transform: rotate(-2deg) scale(0.97);
}

.stamp:disabled {
  opacity: 0.4;
  cursor: default;
}

/*
  Шаг 27.2: визуальное "утверждение" нажатой кнопки — эффект оттиска
  печати (вспышка рамки наружу + лёгкий приссановный поворот/сжатие,
  перекликается с существующим .stamp:active). Специально НЕ через
  :disabled — нажатая кнопка не гаснет (opacity не падает), приглушается
  только вторая, непринятая (см. .stamp:disabled выше) — так разница
  "что выбрано / что нет" читается явно, а не обе кнопки одинаково тускнеют.
  pointer-events:none — повторный клик по уже подтверждённой кнопке
  игнорируется, не полагаемся только на несуществующий disabled-атрибут.
*/
.stamp--confirmed {
  pointer-events: none;
  animation: stamp-confirm 0.45s ease;
}

@keyframes stamp-confirm {
  0% {
    box-shadow: 0 0 0 0 currentColor;
    transform: scale(1) rotate(0deg);
  }
  35% {
    box-shadow: 0 0 0 6px currentColor;
    transform: scale(0.95) rotate(-2deg);
  }
  100% {
    box-shadow: 0 0 0 0 transparent;
    transform: scale(1) rotate(0deg);
  }
}

.stamp--a {
  color: var(--color-red);
}

.stamp--b {
  color: var(--color-gold);
}

.stamp__label {
  color: currentColor;
}

/* ===== Экран ожидания решения ===== */

.waiting {
  text-align: center;
  color: var(--color-paper);
  font-size: clamp(0.9rem, 2.8vw, 1.1rem);
  padding: clamp(1rem, 4vw, 1.5rem);
}

.waiting::after {
  content: "";
  display: block;
  margin: 0.75rem auto 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 3px solid var(--color-muted-grey);
  border-top-color: var(--color-gold);
  animation: spin 0.9s linear infinite;
}

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

/* ===== Экран конца партии (шаг 30: "Досье закрыто", полноценный экран) ===== */

.game-over {
  /* Совпадает с шириной карточки/лобби (шаг 27.1/27.3) — раньше здесь был
     отдельный min(94vw, 420px), не связанный с общей переменной. */
  width: var(--content-width);
  max-height: 82dvh; /* длинное досье на маленьком экране скроллится внутри, не выходит за viewport */
  overflow-y: auto;
  border: 3px solid var(--color-paper);
  border-radius: 14px;
  background: var(--color-blue-grey);
  padding: clamp(1.25rem, 5vw, 2rem);
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: clamp(0.65rem, 3vw, 1rem);
  /* Шаг 30, п.5: кульминационный момент партии — плавное появление, не
     резкий скачок. Keyframes проигрываются автоматически на только что
     вставленном элементе, форсировать reflow (как для .stat-bar__fill,
     шаг 27.2) не нужно — это анимация "с нуля", а не переход между двумя
     существующими состояниями. */
  animation: game-over-reveal 0.6s ease;
}

@keyframes game-over-reveal {
  0% {
    opacity: 0;
    transform: translateY(14px) scale(0.97);
  }
  100% {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.game-over h2 {
  margin: 0;
  font-size: clamp(1.1rem, 3.5vw, 1.4rem);
  color: var(--color-red);
  text-transform: uppercase;
}

.game-over__death-reason {
  margin: 0;
  font-size: clamp(1rem, 3.2vw, 1.2rem);
  font-weight: bold;
  line-height: 1.45;
}

/* flavorText — "летописная запись" от LLM (шаг 21), курсивом, приглушённым
   тоном — отличается от основного death-reason визуально, не дублирует
   его вес. Отсутствует в разметке целиком, если flavorText === null
   (LLM не ответила) — не показываем плейсхолдер на его месте. */
.game-over__flavor {
  margin: 0;
  padding: 0 clamp(0.25rem, 2vw, 0.75rem);
  font-style: italic;
  font-size: clamp(0.85rem, 2.6vw, 1rem);
  line-height: 1.45;
  color: var(--color-paper);
  opacity: 0.85;
}

/* "Пережил эпоху мира" — редкое достижение, золотой акцент палитры
   (GAME_DESIGN.md, Часть I, п.2: золото — "ордена/звёзды"), должно
   ощущаться особенным, не рядовой строкой статистики. */
.game-over__era-badge {
  margin: 0.15rem 0;
  padding: clamp(0.5rem, 2vw, 0.75rem);
  border: 2px solid var(--color-gold);
  border-radius: 8px;
  background: rgba(224, 169, 60, 0.12);
  color: var(--color-gold);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: clamp(0.85rem, 2.6vw, 1rem);
  font-weight: bold;
}

.game-over__stats {
  display: flex;
  justify-content: center;
  gap: clamp(1.25rem, 6vw, 2rem);
  margin: 0.15rem 0;
}

.game-over__stat {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--color-paper);
  font-size: clamp(0.85rem, 2.6vw, 1rem);
}

.game-over__stat svg {
  flex-shrink: 0;
  color: var(--color-gold);
}

/* Досье (шаг 30, п.3) — полный статичный список dossier, самая свежая
   запись первой (см. game.js: .reverse()). Обычный текстовый список,
   не карточки — это вторичная, "архивная" информация, не должна
   конкурировать по весу с самим deathReason. */
.game-over__dossier {
  margin-top: 0.35rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--color-muted-grey);
  text-align: left;
}

.game-over__dossier h3 {
  margin: 0 0 0.5rem;
  font-size: clamp(0.85rem, 2.6vw, 1rem);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  text-align: center;
  color: var(--color-paper);
}

.game-over__dossier ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.game-over__dossier li {
  font-size: clamp(0.78rem, 2.3vw, 0.9rem);
  line-height: 1.4;
  color: var(--color-paper);
  opacity: 0.85;
  padding: 0.4rem 0.55rem;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.15);
}

.game-over button {
  margin-top: 0.5rem;
  font-family: var(--font-main);
  font-size: clamp(0.85rem, 2.6vw, 1rem);
  padding: 0.6rem 1rem;
  border-radius: 6px;
  border: 3px solid var(--color-gold);
  background: transparent;
  color: var(--color-gold);
  text-transform: uppercase;
  cursor: pointer;
}

.game-over button:hover {
  background: var(--color-gold);
  color: var(--color-graphite);
}

/* ===== Экран загрузки (шаг 27.1, п.4 — предзагрузка ресурсов) ===== */

/*
  Показывается сразу при открытии страницы (разметка в index.html, не
  создаётся через JS — чтобы быть видимым даже пока js/main.js ещё не
  выполнился) и скрывается из bootLoader.js, когда критичный набор
  ресурсов готов (см. CHANGELOG, шаг 27.1). Не дефолтный браузерный
  спиннер — вращающаяся "печать" (переиспользуем существующую иконку
  scale-front-pressure.png, штамп по смыслу самой иконки, см.
  index.html) + фраза в тон сеттингу.
*/
.boot-screen {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
  background: var(--color-graphite);
  background-image:
    radial-gradient(circle at 50% 0%, var(--color-blue-grey) 0%, var(--color-graphite) 70%);
  transition: opacity 0.4s ease;
}

.boot-screen.is-hidden {
  opacity: 0;
  pointer-events: none;
}

.boot-screen__stamp {
  width: clamp(56px, 14vw, 84px);
  height: clamp(56px, 14vw, 84px);
  /*
    Шаг 27.3: раньше здесь была светлая badge-подложка под иконкой
    (--color-paper, как и на .stat-bar__icon) — сама иконка scale-front-
    pressure.png была непрозрачной чёрно-белой. Теперь файл пересоздан с
    прозрачным фоном и заливкой линии в --color-paper (см. .stat-bar__icon
    выше) — подложка больше не нужна, иконка сама по себе светлая и видна
    прямо на градиентном фоне загрузочного экрана.
  */
  animation: boot-stamp-spin 1.6s linear infinite;
}

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

.boot-screen__text {
  font-size: clamp(0.9rem, 2.8vw, 1.05rem);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--color-paper);
  text-align: center;
}

/* ===== Планшет/десктоп: чуть просторнее, но карточка не растягивается ===== */
@media (min-width: 700px) {
  .page {
    padding: 2.5rem;
  }
}
