/**
 * assets/css/battle.css — сцена поля боя (движок v2, этап 15).
 *
 * Отвечает за место и слои: где стоит лунка, что перед целью, что за ней,
 * какая у цели зона нажатия и что видно на экране во время боя. Цвета,
 * отступы и тени берутся из ui-tokens.css — своих значений здесь нет.
 *
 * Старое поле (game.css) не трогается: оно ещё живёт на арене PvP.
 */

/* ─────────────── Сцена ─────────────── */

.tam-battle {
  position: fixed;
  inset: 0;
  z-index: 2;
  overflow: hidden;
  /* Касание по полю не должно прокручивать WebView (§52). */
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}

/*
 * Фон поля.
 *
 * Картинку задаёт переменная --tam-field-bg: её ставит выбранная игроком
 * поляна и забег по локации карты. Лунки в неё не вшиты — их расставляет
 * сцена (§136), поэтому один и тот же фон работает с любым набором лунок.
 */
.tam-battle__bg {
  position: absolute;
  inset: 0;
  background-image: var(--tam-field-bg, url('../battle/bg_training.webp?26090901'));
  background-size: cover;
  background-position: center 46%;
  background-repeat: no-repeat;
}

/* Лёгкое затемнение краёв: цель в центре читается лучше, чем на плоском фоне. */
.tam-battle__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 50% 46%,
              rgba(0, 0, 0, 0) 46%, rgba(0, 0, 0, .34) 100%);
  pointer-events: none;
}

/*
 * Игровая зона.
 *
 * §52: верхняя часть экрана отдана боевому интерфейсу, нижняя — усилениям,
 * поле занимает середину. Отступы считаются от безопасных зон Telegram
 * (--tam-inset-*, их приносит mvp/services/telegram.js), иначе верхний ряд
 * уезжает под полосу управления Telegram в полноэкранном режиме.
 *
 * Ширина зоны ограничена её же высотой.
 *
 * Раньше зона занимала 92 % ширины экрана при любых пропорциях, а лунка —
 * 30 % этой ширины. На узком телефоне это совпадало с рисунком, но стоило
 * экрану стать шире и ниже — планшет, разложенный складной, повёрнутый
 * телефон, — как лунки вырастали втрое и налезали друг на друга рядами:
 * расстояние между рядами считается от высоты, а размер лунки — от ширины.
 * Поэтому ширина зоны берётся не больше высоты, умноженной на пропорцию
 * рисунка поляны: поле остаётся тем же самым, просто перестаёт растягиваться
 * туда, где для него нет высоты. Высота считается по видимой части окна
 * (--tam-viewport-h), а не по 100vh: в мини-приложении это разные величины.
 */
.tam-battle__field {
  --tam-field-space: calc(var(--tam-viewport-h, 100vh) * 0.69
                          - var(--tam-inset-top, 0px) - var(--tam-inset-bottom, 0px));
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: min(92%, calc(var(--tam-field-space) * 0.68));
  top: calc(16% + var(--tam-inset-top, 0px));
  bottom: calc(15% + var(--tam-inset-bottom, 0px));
}

/* ─────────────── Лунка ─────────────── */

/*
 * Позиция лунки — якорь в долях сцены, а не ячейка сетки (§138).
 * Числа приходят из battle-scene.js: --tam-hole-x, --tam-hole-y и масштаб
 * ряда --tam-hole-scale.
 */
.tam-hole {
  position: absolute;
  left: var(--tam-hole-x, 50%);
  top: var(--tam-hole-y, 50%);
  width: 30%;
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  /* Нажатие ловит зона, а не декоративные слои. */
  pointer-events: none;
}

/*
 * Перспектива рядов (§139).
 *
 * Масштабируется только рисунок: точка опоры внизу, чтобы лунка «стояла»
 * на земле, а не всплывала при уменьшении. Зона нажатия остаётся снаружи
 * этого преобразования — см. .tam-hole__zone.
 */
.tam-hole__art {
  position: absolute;
  inset: 0;
  transform: scale(var(--tam-hole-scale, 1));
  transform-origin: 50% 72%;
}

/*
 * Задняя и передняя кромка — один файл, показанный дважды.
 *
 * Верхняя часть картинки уходит за спину цели, нижняя ложится перед ней.
 * Крот поднимается между ними — это и есть 2.5D из §132. Разрез идёт по
 * ближнему краю лунки: выше него рисунок относится к дальней кромке.
 */
.tam-hole__back,
.tam-hole__front {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
  -webkit-user-drag: none;
}

.tam-hole__back {
  z-index: 1;
  clip-path: inset(0 0 38% 0);
}

.tam-hole__front {
  z-index: 3;
  clip-path: inset(62% 0 0 0);
  filter: drop-shadow(var(--ui-art-shadow-card));
}

/* Тьма внутри норы: цель выходит из глубины, а не из плоского пятна. */
.tam-hole__pit {
  position: absolute;
  left: 22%;
  right: 22%;
  top: 30%;
  height: 34%;
  z-index: 2;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 40%,
              rgba(0, 0, 0, .82) 30%, rgba(0, 0, 0, .5) 62%, rgba(0, 0, 0, 0) 100%);
  pointer-events: none;
}

/* Контактная тень — лунка прилипает к земле, а не парит над ней. */
.tam-hole__art::after {
  content: "";
  position: absolute;
  left: 12%;
  right: 12%;
  bottom: 6%;
  height: 16%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(0, 0, 0, .5), rgba(0, 0, 0, 0));
  z-index: 0;
  pointer-events: none;
}

/* ─────────────── Цель ─────────────── */

/*
 * Слой цели обрезан по ближней кромке лунки.
 *
 * Всё, что ниже этой линии, не видно: там крот прячется в норе. Сверху
 * слой, наоборот, выше самой лунки — поднявшийся крот не должен упираться
 * головой в невидимый потолок. Обрезка обычным overflow, а не clip-path:
 * отрицательные значения clip-path ведут себя в разных движках по-разному.
 */
.tam-hole__target {
  position: absolute;
  left: 0;
  right: 0;
  top: -45%;
  bottom: 38%;
  z-index: 2;
  overflow: hidden;
  pointer-events: none;
}

/*
 * Выход цели.
 *
 * §72 требует физического подъёма через translate и лёгкий перелёт, а не
 * появления по display. В покое крот стоит ровно под линией обрезки — его
 * не видно вовсе; поднимаясь, он выходит из-за передней кромки.
 */
/*
 * Ширина цели — 78 % лунки, а не 62 %.
 *
 * Замер по кадру боя (as/4.png): голова крота почти во всю ширину лунки,
 * а над ближней кромкой торчит голова целиком с плечами. При 62 % крот
 * сидел в норе по глаза и на площадке читался значком, а не целью, по
 * которой надо попасть пальцем.
 */
.tam-hole__mole {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 78%;
  transform: translate(-50%, 100%) scaleY(.94);
  transform-origin: 50% 100%;
  transition: transform var(--tam-b-mole) cubic-bezier(.22, .9, .22, 1);
  will-change: transform;
}

.tam-hole.is-up .tam-hole__mole {
  animation: tamMoleRise var(--tam-b-rise) cubic-bezier(.2, 1.5, .4, 1) forwards;
}

.tam-hole.is-down .tam-hole__mole {
  animation: none;
  transform: translate(-50%, 100%) scaleY(.9);
  transition: transform var(--tam-b-hide) ease-in;
}

/* Удар: цель сплющивается, а не просто исчезает (§74). */
.tam-hole.hit .tam-hole__mole {
  animation: tamMoleSquash var(--tam-b-mole) ease-out forwards;
}

/*
 * Картинка крота.
 *
 * В game.css у `.moleImg` стоит абсолютное положение с `width: 70% !important`
 * — правило не привязано к старому полю и достаёт сюда. Абсолютная картинка
 * обнуляет высоту родителя, а вместе с ней и подъём в процентах: крот
 * оставался сидеть в лунке. Поэтому здесь положение возвращается в поток.
 */
.tam-hole__mole .moleImg {
  position: static;
  display: block;
  width: 100% !important;
  height: auto;
  bottom: auto;
  left: auto;
  transform: none;
  filter: drop-shadow(var(--ui-art-shadow-md));
  -webkit-user-drag: none;
}

@keyframes tamMoleRise {
  0%   { transform: translate(-50%, 100%) scaleY(.94); }
  70%  { transform: translate(-50%, -2%) scaleY(1.04); }
  100% { transform: translate(-50%, 6%) scaleY(1); }
}

@keyframes tamMoleSquash {
  0%   { transform: translate(-50%, 18%) scaleY(1) scaleX(1); }
  45%  { transform: translate(-50%, 30%) scaleY(.72) scaleX(1.18); }
  100% { transform: translate(-50%, 52%) scaleY(.86) scaleX(1.06); }
}

/* ─────────────── Эффекты попадания ─────────────── */

/*
 * Сами частицы описаны в game.css классами без привязки к полю, поэтому
 * повторять их незачем — здесь только слой и правила запуска для новой
 * лунки. Ключевые кадры (dirtBurst, sparkBurst, dustPuff, wave, debrisFly)
 * тоже общие.
 *
 * Времена ниже стоят числами законно — оговорка 3 лестницы движения
 * (`game-ui.css`): доли разлёта обязаны гаснуть вразнобой, иначе вместо
 * летящей земли получится одна мигнувшая клякса.
 */
.tam-hole__fx {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
}

.tam-hole.pop .ruffle { opacity: 1; }
.tam-hole.pop .ruffle i { animation: dirtBurst .4s ease-out forwards; }
.tam-hole.pop .sparks { opacity: 1; }
.tam-hole.pop .sparks b { animation: sparkBurst .55s ease-out forwards; }
.tam-hole.pop .debris { opacity: 1; }
.tam-hole.pop .debris s { animation: debrisFly .44s ease-out forwards; }
.tam-hole.hit .dust { opacity: 1; animation: dustPuff .32s ease-out 1; }
.tam-hole.hit .shockwave { opacity: 1; animation: wave .28s ease-out 1; }

/* Кромка отзывается на удар — короткая отдача, без тряски всего экрана (§87). */
.tam-hole.hit .tam-hole__front { animation: tamRimHit var(--tam-t-state) ease-in-out 1; }

@keyframes tamRimHit {
  0%, 100% { transform: translateY(0); }
  40%      { transform: translateY(3px); }
}

/*
 * Вспышка попадания.
 *
 * Короткий тёплый всполох из кромки лунки: он держит взгляд на месте удара
 * ровно те 200 мс, пока летят частицы. Цвет — золото палитры, своих
 * значений здесь нет.
 */
.tam-hole.is-flash .tam-hole__fx::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 46%;
  width: 78%;
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  /* Было набрано числами прежней тёплой палитры (#f5d65a, #e9b84e) —
     комментарий выше обещал золото словаря, а всполох шёл своим. */
  background: radial-gradient(closest-side,
              color-mix(in srgb, var(--ui-gold-light) 85%, transparent),
              color-mix(in srgb, var(--ui-gold) 35%, transparent) 55%,
              color-mix(in srgb, var(--ui-gold) 0%, transparent) 100%);
  animation: tamHitFlash var(--tam-b-flash) ease-out forwards;
  pointer-events: none;
}

@keyframes tamHitFlash {
  0%   { opacity: .95; transform: translate(-50%, -50%) scale(.55); }
  100% { opacity: 0;   transform: translate(-50%, -50%) scale(1.25); }
}

/* ─────────────── Молот ─────────────── */

/*
 * Слой удара (§81-82).
 *
 * Молот появляется в точке касания, бьёт и исчезает; за пальцем он не
 * ходит. Ввод не перехватывает вовсе — иначе следующий тап пришёлся бы по
 * картинке молота, а не по лунке.
 */
/*
 * Молот стоит на точке касания бойком, а не углом картинки.
 *
 * Узел ставится левым верхним углом в точку удара, а сдвиг translate
 * подобран так, чтобы в кадре контакта (поворот 6°) центр бойка пришёлся
 * на эту точку и чуть выше — туда, где голова цели. Точка вращения — конец
 * рукояти (62% 95% картинки): молот проворачивается вокруг кисти, а не
 * вокруг своего центра, иначе замах читается как вращение колеса.
 */
.tam-hammer {
  position: absolute;
  width: 36%;
  max-width: 180px;
  z-index: 6;
  pointer-events: none;
  opacity: 0;
  transform-origin: 62% 95%;
  transform: translate(-65%, -38%) rotate(72deg) scale(.9);
  filter: drop-shadow(var(--ui-art-shadow-md));
  -webkit-user-drag: none;
}

.tam-hammer.is-strike { animation: tamHammerStrike var(--tam-b-strike) cubic-bezier(.3, .9, .35, 1) forwards; }

/*
 * След молота — косметика этапа 36 (§488).
 *
 * Отдельный узел, а не псевдоэлемент молота: у картинки (`img`)
 * псевдоэлементов не бывает. Цвет и толщину задаёт надетый предмет, всё
 * остальное общее — след живёт ровно столько же, сколько замах, и ввод не
 * перехватывает.
 */
.tam-hammer-trail {
  position: absolute;
  width: 34%;
  max-width: 170px;
  aspect-ratio: 1 / 1;
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  transform: translate(-62%, -46%) rotate(-18deg);
  border-radius: var(--ui-radius-pill);
  border: var(--tam-trail-width, 8px) solid transparent;
  border-top-color: var(--tam-trail-color, var(--ui-gold));
  border-right-color: var(--tam-trail-color, var(--ui-gold));
  filter: blur(1px) drop-shadow(0 0 var(--ui-glow-md) var(--tam-trail-color, var(--ui-gold)));
}

.tam-hammer-trail.is-strike { animation: tamHammerTrail var(--tam-b-strike) ease-out forwards; }

@keyframes tamHammerTrail {
  0%   { opacity: 0; transform: translate(-62%, -46%) rotate(-42deg) scale(.86); }
  30%  { opacity: .85; transform: translate(-62%, -46%) rotate(-6deg) scale(1); }
  100% { opacity: 0; transform: translate(-62%, -46%) rotate(18deg) scale(1.08); }
}

/*
 * Замах короткий: боёк касается цели на 23% анимации, то есть через 60 мс
 * после нажатия (§82). Ровно столько же ждёт презентер, прежде чем
 * показать сплющивание и частицы, — удар и его последствия совпадают.
 * Всё, что дольше, на телефоне читается как задержка ввода, а не размах.
 */
@keyframes tamHammerStrike {
  0%   { opacity: 0; transform: translate(-65%, -38%) rotate(72deg) scale(.9); }
  10%  { opacity: 1; transform: translate(-65%, -38%) rotate(52deg) scale(1); }
  23%  { opacity: 1; transform: translate(-65%, -38%) rotate(6deg) scale(1.04); }
  40%  { opacity: 1; transform: translate(-65%, -38%) rotate(18deg) scale(1); }
  100% { opacity: 0; transform: translate(-65%, -38%) rotate(40deg) scale(.94); }
}

/* ─────────────── Пустой удар ─────────────── */

/*
 * Тап по земле мимо цели.
 *
 * Отклик обязателен: без него игрок решит, что нажатие не сработало, и
 * начнёт бить чаще. Но это пыль под молотом, а не праздник — пустой тап
 * ничего не стоит и ничего не даёт (§96).
 */
.tam-battle__dud {
  position: absolute;
  width: 54px;
  height: 54px;
  margin: -27px 0 0 -27px;
  z-index: 5;
  border-radius: 50%;
  pointer-events: none;
  /* Пыль из-под молота: светлое пятно с примесью земли, а не серый дым.
     Прежде стояло два числа кремового мира (#dcd1c2, #b9aa96). */
  background: radial-gradient(closest-side,
              color-mix(in srgb,
                        color-mix(in srgb, var(--ui-ivory) 62%, var(--ui-earth-light))
                        50%, transparent),
              color-mix(in srgb, var(--ui-earth-light) 22%, transparent) 60%,
              color-mix(in srgb, var(--ui-earth-light) 0%, transparent) 100%);
  animation: tamDudPuff var(--tam-b-burst) ease-out forwards;
}

@keyframes tamDudPuff {
  0%   { opacity: .9; transform: scale(.4); }
  100% { opacity: 0;  transform: scale(1.35); }
}

/* ─────────────── Отдача сцены ─────────────── */

/*
 * Тряска и микро-остановка (§87).
 *
 * Двигается только сцена: HUD, окна и уведомления остаются на месте, иначе
 * от каждого удара дёргался бы весь интерфейс. Амплитуда мала намеренно —
 * это отдача, а не землетрясение.
 */
.tam-battle.is-shake .tam-battle__field { animation: tamSceneShake var(--tam-b-shake) ease-out; }

/* Поле центрировано translateX(-50%): кадры обязаны его повторять,
 * иначе на время тряски сцена прыгает вправо на полширины. */
@keyframes tamSceneShake {
  0%, 100% { transform: translateX(-50%) translate(0, 0); }
  30%      { transform: translateX(-50%) translate(calc(var(--tam-shake, 1) * -2px), calc(var(--tam-shake, 1) * 2px)); }
  65%      { transform: translateX(-50%) translate(calc(var(--tam-shake, 1) * 2px), calc(var(--tam-shake, 1) * -1px)); }
}

/* Хитстоп: на несколько кадров поле замирает, и удар «весит». */
.tam-battle.is-hitstop .tam-hole * { animation-play-state: paused !important; }

/* ─────────────── Зона нажатия ─────────────── */

/*
 * Зона отдельная и не масштабируется вместе с рисунком (§140).
 *
 * Дальний ряд рисуется мельче, но нажимать по нему должно быть так же
 * удобно: минимальный размер — общий тап проекта (--tap, 56px). Аудит
 * этапа 14 (дефект B15) нашёл ровно обратное: зоной служил прямоугольник
 * картинки лунки.
 */
.tam-hole__zone {
  position: absolute;
  left: 50%;
  top: 52%;
  transform: translate(-50%, -50%);
  width: max(var(--ui-tap), 82%);
  height: max(var(--ui-tap), 72%);
  z-index: 5;
  border-radius: 50%;
  pointer-events: auto;
  cursor: pointer;
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
}

/* Отклик на нажатие — короткий, без сдвига лунки с якоря. */
.tam-hole.is-pressed .tam-hole__art { transform: scale(calc(var(--tam-hole-scale, 1) * .96)); }

.tam-hole.is-denied .tam-hole__art { animation: tamHoleDeny calc(var(--tam-t-sheet) - var(--tam-t-tap)) ease; }

@keyframes tamHoleDeny {
  0%, 100% { transform: scale(var(--tam-hole-scale, 1)) translateX(0); }
  25%      { transform: scale(var(--tam-hole-scale, 1)) translateX(-5px); }
  50%      { transform: scale(var(--tam-hole-scale, 1)) translateX(5px); }
  75%      { transform: scale(var(--tam-hole-scale, 1)) translateX(-2px); }
}

/* ─────────────── Боевой интерфейс ─────────────── */

/*
 * Минимальная полоса боя: выход, жизни и счёт забега (§144 — на экране боя
 * только нужное). Полный HUD с таймером, целью и комбо приходит этапами
 * 17-18; здесь ровно то, без чего бой нельзя вести, — сколько осталось
 * жизней и чем закончить.
 */
/*
 * Раскладка боя целиком повторяет шестой кадр as/4.png.
 *
 * Прежде HUD был одной строкой поверху: жизни, промахи, серия, часы, счёт
 * — пять чипов в ряд, которые на 360px наезжали друг на друга. На кадре
 * же интерфейс боя разнесён по двум краям экрана и середина поля пустая,
 * потому что именно там лунки:
 *
 *   верх   пауза слева · «УРОВЕНЬ 45» и окно таймера по центру · счёт справа
 *   низ    плашка сердец и кружок серии · под ними ряд усилений
 *
 * Корень растянут на весь экран и раздаёт клики сквозь себя: между
 * верхом и низом лежит поле, и перехватывать удары по кротам HUD не
 * должен ни одним пикселем.
 */
.tam-battle-hud {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  /* Выше страницы (z-index 10 у .page), но ниже окон и уведомлений (1000+). */
  z-index: 30;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: calc(var(--tam-inset-top, 0px) + var(--ui-space-3))
           var(--ui-space-2)
           calc(var(--ui-space-3) + var(--safe-bottom, 0px));
  font-family: var(--ui-font-main);
  pointer-events: none;
}

/*
 * Клики принимают только сами контролы, а не их контейнеры: строка и
 * колонка растянуты во всю ширину, и с `pointer-events: auto` на них
 * половина поля перестала бы отзываться на удар.
 */
.tam-battle-hud__pause,
.tam-battle-hud__stat,
.tam-battle-hud__combo,
.tam-battle-hud__boost,
.tam-battle-hud__goal { pointer-events: auto; }

.tam-battle-hud__top {
  display: grid;
  /* Бока равной ширины: иначе окно таймера уезжает от середины, как
     только счёт вырастает до пяти знаков. */
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
  gap: var(--ui-space-2);
}

.tam-battle-hud__side {
  display: flex;
  align-items: center;
  gap: var(--ui-space-1);
  min-width: 0;
}

.tam-battle-hud__side--right { justify-content: flex-end; }

.tam-battle-hud__mid {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.tam-battle-hud__bottom {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--ui-space-2);
}

/* ─────────────── Пауза ─────────────── */

/*
 * Единственное золотое пятно на кадре боя: квадрат со скруглением md,
 * толстой тёмной кромкой и двумя кремовыми брусками внутри. Рисованный
 * знак, а не значок из набора: две полосы читаются паузой при любом
 * размере, а «две вертикальные линии» в SVG-наборе не размечены.
 *
 * Материал у неё общий — §9.1 рамы: здесь она держала СВОЙ золотой
 * градиент в четыре ступени (#f0c95a → #a86c16) и свою тёмную грань
 * (#7e4a0a), то есть главная кнопка боя была золотом, которого нет
 * больше нигде в игре. В разделе осталась геометрия и нажатие.
 */
.tam-battle-hud__pause {
  width: 46px;
  height: 46px;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 0;
  border-radius: var(--ui-radius-md);
  cursor: pointer;
  transition: transform var(--tam-t-tap) ease, box-shadow var(--tam-t-tap) ease;
}

.tam-battle-hud__pause i {
  width: 6px;
  height: 20px;
  border-radius: 2px;
  background: var(--ui-ivory-light);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--ui-gold-deep) 60%, transparent);
}

.tam-battle-hud__pause:active { transform: translateY(3px); }

/* ─────────────── Уровень и окно таймера ─────────────── */

.tam-battle-hud__level {
  font-family: var(--ui-font-condensed);
  font-weight: 900;
  font-size: var(--ui-size-section);
  line-height: 1.1;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--ui-gold-light);
  text-shadow:
    -1px -1px 0 color-mix(in srgb, var(--ui-text-outline) 92%, transparent), 1px -1px 0 color-mix(in srgb, var(--ui-text-outline) 92%, transparent),
    -1px  1px 0 color-mix(in srgb, var(--ui-text-outline) 92%, transparent), 1px  1px 0 color-mix(in srgb, var(--ui-text-outline) 92%, transparent),
     0    2px 0 color-mix(in srgb, var(--ui-text-outline) 60%, transparent);
}

.tam-battle-hud__level.is-hidden { display: none; }

/*
 * Плашка боя — тёмный чип, а не кремовая плитка.
 *
 * Кремовые плашки читались на поле как вырезанные из другого макета:
 * поле нарисованное и светлое, и четыре белых прямоугольника поверх него
 * забирали взгляд у лунок. На кадре боя референса (as/4.png, кадр 6) весь
 * HUD тёмный со светлым текстом — единственное золотое пятно там кнопка
 * паузы, единственное кремовое — окно таймера. Тёмный чип работает и на
 * газоне, и на земле, а кремовый терялся на первом.
 */
.tam-battle-hud__stat {
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-1);
  height: 42px;
  flex: 0 0 auto;
  white-space: nowrap;
  /* Поля ровно --ui-space-2: четыре чипа с большими полями не влезают в
     390px и крайний уезжает за экран. */
  padding: 0 var(--ui-space-2);
  border-radius: var(--ui-radius-pill);
  background: linear-gradient(180deg,
              color-mix(in srgb, var(--ui-panel-main) 94%, transparent),
              color-mix(in srgb, var(--ui-bg-deep) 94%, transparent));
  border: var(--ui-border) solid rgba(0, 0, 0, 0.55);
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.45), var(--ui-shadow-soft),
              inset 0 1px 0 color-mix(in srgb, var(--ui-gold-hi) 16%, transparent);
  color: var(--ui-text-main);
  font-weight: var(--ui-weight-value);
  font-size: var(--ui-size-value);
  text-shadow: var(--ui-text-shadow-sm);
}

.tam-battle-hud__stat svg {
  width: 20px;
  height: 20px;
  display: block;
}

/* На тёмном чипе тёмные значки пропадали: каждому — свой светлый тон. */
.tam-battle-hud__lives svg { color: var(--ui-red-light); }
.tam-battle-hud__lives.is-empty { animation: tamBattlePulse 1.6s ease-in-out infinite; }

.tam-battle-hud__score svg { color: var(--ui-gold-light); }
.tam-battle-hud__score .tam-battle-hud__value { font-size: var(--ui-size-section); }

/* ─────────────── Сердца ─────────────── */

/*
 * Плашка жизней с кадра: тёмный прямоугольник со скруглением md, внутри
 * ряд сердец. Полное сердце красное с бликом, потраченное — тёмное
 * пятно того же силуэта. Цифра остаётся в разметке для диктора, но с
 * экрана убрана: в бою считают силуэты, а не читают дробь.
 */
.tam-battle-hud__lives--hearts {
  height: 48px;
  border-radius: var(--ui-radius-md);
  padding: 0 var(--ui-space-2);
}

.tam-battle-hud__lives--hearts svg { display: none; }

.tam-battle-hud__value--sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.tam-battle-hud__hearts {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

/*
 * Сердце нарисовано двумя кругами и повёрнутым квадратом — исключение из
 * шкалы скруглений наравне с огоньками башни: это рисунок, а не панель.
 */
/*
 * Потраченное сердце — светлый силуэт, а не чёрное пятно.
 *
 * Стояло `#0d0925` на плашке того же тона: погашенные сердца пропадали
 * с экрана целиком, и ряд «3 из 5» читался как «всего три жизни». Игрок
 * терял единственный способ понять, сколько уже потерял. Тон взят на
 * ступень светлее подложки — силуэт виден, но за живое не выдаёт себя.
 */
.tam-battle-hud__heart {
  position: relative;
  width: 22px;
  height: 20px;
  background: color-mix(in srgb, var(--ui-ivory-deep) 62%, var(--ui-panel-edge));
  clip-path: path('M11 19.4C11 19.4 0.8 13.2 0.8 6.6C0.8 3.2 3.4 0.8 6.4 0.8C8.4 0.8 10.2 1.9 11 3.6C11.8 1.9 13.6 0.8 15.6 0.8C18.6 0.8 21.2 3.2 21.2 6.6C21.2 13.2 11 19.4 11 19.4Z');
  transition: background var(--tam-t-state) ease, filter var(--tam-t-state) ease;
}

.tam-battle-hud__heart.is-on {
  background: radial-gradient(60% 46% at 38% 26%,
              color-mix(in srgb, var(--ui-red-light) 62%, var(--ui-ivory-light)) 0%,
              var(--ui-red-light) 52%, var(--ui-red) 100%);
  filter: drop-shadow(var(--ui-art-shadow-pin));
}

/* Больше девяти жизней — сердцами не показать: значок и число. */
.tam-battle-hud__hearts.is-numeric svg { display: block; color: var(--ui-red-light); }
.tam-battle-hud__hearts.is-numeric {
  gap: var(--ui-space-1);
  font-weight: var(--ui-weight-value);
  font-size: var(--ui-size-value);
  color: var(--ui-text-main);
}

/* ─────────────── Ряд усилений ─────────────── */

/*
 * Четыре плитки внизу кадра: рыжая с молотом, тёмно-синяя с молнией,
 * зелёная с секундомером, тёмно-синяя с ракетой. Цвет отвечает за род
 * усиления (`data-theme`), а не за доступность: недоступного усиления в
 * ряду просто нет — там стоит только купленное.
 *
 * Счётчик — золотой кружок в правом нижнем углу плитки, как на кадре.
 */
.tam-battle-hud__boosts {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--ui-space-2);
}

.tam-battle-hud__boosts.is-empty { display: none; }

.tam-battle-hud__boost {
  position: relative;
  width: 62px;
  height: 62px;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: var(--ui-border-thick) solid var(--ui-panel-edge);
  border-radius: var(--ui-radius-md);
  /* Заливки здесь нет: цвет плитки раздаёт рама по `data-theme` (§22),
     и все пять тем она уже знает. Раздел держал свой серо-стальной корпус
     (#55575e → #3a3c42) и четыре своих цвета мимо словаря — рама
     подключена последней и перекрывала их все, то есть эти правила
     ничего не красили с самого своего появления. */
  box-shadow: 0 4px 0 rgba(0, 0, 0, .5), var(--ui-shadow-soft),
              inset 0 2px 0 rgba(255, 255, 255, .18);
  color: var(--ui-ivory-light);
  cursor: pointer;
  transition: transform var(--tam-t-tap) ease, box-shadow var(--tam-t-tap) ease, filter var(--tam-t-state) ease;
}

.tam-battle-hud__boost svg {
  width: 32px;
  height: 32px;
  display: block;
  filter: drop-shadow(var(--ui-art-shadow-pin));
}

/* Набор значков пока контурный (68 обводок против 19 заливок), а на
   цветной плитке тонкий контур в 1.8px исчезает. Утолщаем штрих здесь,
   пока значки не перерисованы заливкой. */
.tam-battle-hud__boost svg * { stroke-width: 2.4; }

/* Материал кружка — §23.1 рамы (счётчик запаса, золотой). Здесь только
   размеры и вылет за угол плитки: у счётчика на кнопке шапки и у этого
   они разные, а материал обязан быть один. */
.tam-battle-hud__boost-count {
  position: absolute;
  right: -5px;
  bottom: -5px;
  min-width: 24px;
  height: 24px;
  padding: 0 5px;
  font-size: var(--ui-size-body);
  line-height: 1;
}

.tam-battle-hud__boost:active {
  transform: translateY(3px);
  box-shadow: 0 1px 0 rgba(0, 0, 0, .5), inset 0 2px 0 rgba(255, 255, 255, .14);
}

/* Пока сервер отвечает, плитка погашена: второй тап потратил бы вторую
   штуку из ящика, а игрок в бою жмёт быстро. */
.tam-battle-hud__boost.is-busy {
  filter: grayscale(.5) brightness(.8);
  pointer-events: none;
}

/* ─────────────── Часы и запас промахов задания ─────────────── */

/*
 * Обе плашки принадлежат заданию обычной игры (§8 списка владельца) и в
 * бою по уровню не показываются. Прячутся через `display`, а не
 * прозрачностью: в отличие от капсулы серии, они не мигают по ходу
 * забега, и резервировать под них место в бесконечном режиме незачем.
 */
.tam-battle-hud__timer.is-hidden,
.tam-battle-hud__misses.is-hidden { display: none; }

.tam-battle-hud__misses svg { color: var(--ui-earth-light); }

/*
 * Часы — не чип, а ОКНО: крупный прямоугольник со скруглением md, тёмной
 * заливкой, толстой светло-коричневой кромкой и большими кремовыми
 * цифрами. На кадре это самый заметный элемент верха, и по нему игрок
 * решает, гнаться ли за последним кротом.
 *
 * Значок часов из него убран (`display: none` на svg): в окне стоят
 * только цифры, значок отнимал у них половину ширины.
 */
.tam-battle-hud__timer {
  height: 52px;
  min-width: 128px;
  justify-content: center;
  padding: 0 var(--ui-space-3);
  border-radius: var(--ui-radius-md);
  border: var(--ui-border-thick) solid var(--ui-wood-light);
  background: linear-gradient(180deg,
              color-mix(in srgb, var(--ui-wood) 96%, transparent),
              color-mix(in srgb, var(--ui-bg-dark) 96%, transparent));
  box-shadow: 0 4px 0 rgba(0, 0, 0, .45), var(--ui-shadow-soft),
              inset 0 2px 0 color-mix(in srgb, var(--ui-gold-hi) 14%, transparent);
}

.tam-battle-hud__timer svg { display: none; }

.tam-battle-hud__timer .tam-battle-hud__value {
  font-family: var(--ui-font-condensed);
  font-weight: 900;
  font-size: 30px;
  line-height: 1;
  letter-spacing: .01em;
  color: var(--ui-ivory-light);
  text-shadow: 0 2px 0 color-mix(in srgb, var(--ui-text-outline) 70%, transparent);
}

/*
 * Тревога: меньше десяти секунд или последний промах.
 *
 * Плашка перекрашивается целиком, а не подсвечивает цифру: игрок в этот
 * момент смотрит на лунки, и заметить он может только пятно на краю
 * зрения.
 */
.tam-battle-hud__timer.is-alarm,
.tam-battle-hud__misses.is-alarm {
  background: linear-gradient(180deg, var(--ui-red-light), var(--ui-red));
  border-color: var(--ui-panel-edge);
  color: var(--ui-text-main);
  animation: tamBattlePulse 1.1s ease-in-out infinite;
}

.tam-battle-hud__timer.is-alarm svg,
.tam-battle-hud__misses.is-alarm svg { color: var(--ui-text-main); }

@keyframes tamBattlePulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: .55; }
}

/* ─────────────── Серия ─────────────── */

/*
 * Золотая капсула в середине полосы (§96: сдержанный UI).
 *
 * Прячется прозрачностью и масштабом, а не `display`: место под неё
 * зарезервировано всегда, иначе жизни и счёт разъезжались бы вбок на
 * каждой третьей цели. Ступени серии меняют насыщенность золота — от
 * спокойного к горячему, — но не размер: растущая капсула перекрывала бы
 * дальний ряд лунок.
 */
/*
 * На кадре серия — тёмный деревянный КРУЖОК с золотой надписью «x2»,
 * стоящий справа от плашки сердец. Золотая капсула прежней версии
 * спорила с кнопкой паузы: два золотых пятна на поле вместо одного.
 */
.tam-battle-hud__combo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  flex: 0 0 auto;
  padding: 0;
  border-radius: 50%;
  background: radial-gradient(70% 70% at 42% 30%,
              var(--ui-purple) 0%, var(--ui-panel-main) 62%, var(--ui-panel-dark) 100%);
  border: var(--ui-border-thick) solid var(--ui-panel-edge);
  box-shadow: var(--ui-shadow-soft), inset 0 2px 0 color-mix(in srgb, var(--ui-gold-hi) 18%, transparent);
  color: var(--ui-gold-light);
  font-family: var(--ui-font-condensed);
  font-weight: 900;
  font-size: var(--ui-size-title);
  letter-spacing: .02em;
  text-shadow:
    -1px -1px 0 color-mix(in srgb, var(--ui-text-outline) 90%, transparent), 1px -1px 0 color-mix(in srgb, var(--ui-text-outline) 90%, transparent),
    -1px  1px 0 color-mix(in srgb, var(--ui-text-outline) 90%, transparent), 1px  1px 0 color-mix(in srgb, var(--ui-text-outline) 90%, transparent);
  opacity: 0;
  transform: scale(.86);
  transition: opacity var(--tam-t-state) ease, transform var(--tam-t-state) ease;
  pointer-events: none;
}

.tam-battle-hud__combo.is-visible {
  opacity: 1;
  transform: scale(1);
}

.tam-battle-hud__combo[data-tier="3"] { filter: saturate(1.12); }
.tam-battle-hud__combo[data-tier="4"] { filter: saturate(1.24) brightness(1.04); }
.tam-battle-hud__combo[data-tier="5"] { filter: saturate(1.36) brightness(1.08); }

/* Точный удар: одна вспышка капсулы, без прыжка соседей. */
.tam-battle-hud__combo.is-perfect { animation: tamComboPerfect calc(var(--tam-t-sheet) + var(--tam-t-state)) ease-out; }

@keyframes tamComboPerfect {
  0%   { box-shadow: var(--ui-shadow-soft), inset 0 2px 0 color-mix(in srgb, var(--ui-gold-hi) 18%, transparent); }
  35%  { box-shadow: 0 0 0 6px color-mix(in srgb, var(--ui-gold-light) 34%, transparent),
                     inset 0 2px 0 color-mix(in srgb, var(--ui-gold-hi) 18%, transparent); }
  100% { box-shadow: var(--ui-shadow-soft), inset 0 2px 0 color-mix(in srgb, var(--ui-gold-hi) 18%, transparent); }
}

/*
 * Кольцо точного удара на самой лунке.
 *
 * Форма, а не оттенок: точный удар случается посреди обычных, и различать
 * их по цвету на солнце невозможно. Кольцо расходится из центра лунки и
 * гаснет за полсекунды — ровно столько, сколько нужно, чтобы заметить, но
 * не столько, чтобы мешать следующей цели.
 */
.tam-hole.is-perfect .tam-hole__fx::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 52%;
  width: 42%;
  height: 42%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border: 3px solid var(--ui-gold);
  animation: tamHolePerfect calc(var(--tam-t-sheet) + var(--tam-t-tap)) ease-out forwards;
  pointer-events: none;
}

@keyframes tamHolePerfect {
  0%   { opacity: .95; transform: translate(-50%, -50%) scale(.5); }
  100% { opacity: 0;   transform: translate(-50%, -50%) scale(1.9); }
}

/*
 * Окно точного удара на цели.
 *
 * Пока оно открыто, у самой цели тёплый контур: игрок видит, что ещё
 * успевает. Подсвечивается крот, а не лунка, — свет от земли читался бы
 * как ещё одна вспышка попадания. Границы окна называет сервер (поле `p`
 * расписания), клиент их не выдумывает и на решение не влияет.
 */
.tam-hole.is-prime .tam-hole__mole {
  filter: drop-shadow(0 0 var(--ui-glow-sm) color-mix(in srgb, var(--ui-gold-light) 55%, transparent));
}

/* ─────────────── Цель уровня ─────────────── */

/*
 * Строка цели под полосой боя (§267: компактно, «18 / 25»).
 *
 * Стоит отдельной строкой, а не в ряду со счётом: цель читают между
 * ударами, и втискивать её в тот же ряд значило бы либо сжать счёт, либо
 * увести цель за край на 360 px. Прогресс считает сервер — здесь только
 * подпись, числа и полоса.
 */
.tam-battle-hud__goal {
  position: absolute;
  left: 50%;
  top: calc(100% + var(--ui-space-2));
  transform: translateX(-50%) translateY(-6px);
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-2);
  max-width: 78vw;
  padding: 6px var(--ui-space-3);
  border-radius: var(--ui-radius-md);
  /* Фиолетовая панель, а не земля: на кадре «BATTLEFIELD» коричневым
     осталось только поле, а полоса цели над ним идёт корпусным тоном. */
  background: linear-gradient(180deg,
              color-mix(in srgb, var(--ui-wood) 94%, transparent),
              color-mix(in srgb, var(--ui-bg-dark) 94%, transparent));
  border: var(--ui-border) solid var(--ui-border-dark);
  box-shadow: var(--ui-shadow-soft);
  /* Подложка тёмная — текст кремовый: --ui-text-ivory это текст ПО крему. */
  color: var(--ui-text-main);
  font-family: var(--ui-font-condensed);
  font-size: var(--ui-size-small);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--tam-t-panel) ease, transform var(--tam-t-panel) ease;
}

.tam-battle-hud__goal.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.tam-battle-hud__goal-label { color: var(--ui-text-muted); }

.tam-battle-hud__goal-value {
  font-weight: var(--ui-weight-value);
  color: var(--ui-gold);
}

/* Полоска цели: материал общий (§14 рамы), своими остаются размеры —
   она самая тонкая шкала игры и стоит внутри HUD боя. Светлая дорожка
   `rgba(255,246,230,.18)` делала её накладкой поверх поля, а не канавкой
   в панели. */
.tam-battle-hud__goal-bar {
  display: block;
  width: 68px;
  height: var(--ui-bar-h-thin);
}

.tam-battle-hud__goal-bar i {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 0;
  transition: width var(--tam-t-modal) ease;
}

/*
 * Цель «никого не упусти» на исходе: полоса и число становятся тревожными.
 * Полоса меняет только цвет заливки (§14 рамы), а не всю подложку:
 * собственный `background` стирал бы вместе с золотом блик и фактуру, и
 * тревожная шкала оказывалась бы плоской там, где на неё как раз смотрят.
 */
.tam-battle-hud__goal.is-alarm .tam-battle-hud__goal-value { color: var(--ui-red-light); }
.tam-battle-hud__goal.is-alarm .tam-battle-hud__goal-bar i {
  --bar-hi:  var(--ui-red-light);
  --bar-top: var(--ui-red);
  --bar-mid: var(--ui-red);
  --bar-low: var(--ui-red-deep);
}

.tam-battle-hud__goal.is-done .tam-battle-hud__goal-value { color: var(--ui-gold); }
.tam-battle-hud__goal.is-failed { filter: grayscale(.4); }

/* ─────────────── Типы целей и предупреждение ─────────────── */

/*
 * Земля дрожит перед подъёмом (§68: 80-220 мс сигнала).
 *
 * Это единственная честная подсказка о быстрой цели: без неё крот,
 * который живёт девятьсот миллисекунд, читается как несправедливость.
 * Хитбокс в это время выключен — ранний тап не наказывает и не
 * засчитывается, поэтому подсказка ничего не ломает.
 */
.tam-hole.is-warning .tam-hole__art {
  animation: tamHoleWarn var(--tam-b-shake) ease-in-out 2;
}

.tam-hole.is-warning .tam-hole__pit {
  box-shadow: inset 0 0 var(--ui-glow-md) color-mix(in srgb, var(--ui-gold) 50%, transparent);
}

@keyframes tamHoleWarn {
  0%, 100% { transform: scale(var(--tam-hole-scale, 1)) translateY(0); }
  50%      { transform: scale(var(--tam-hole-scale, 1)) translateY(2px); }
}

/*
 * Золотая цель: сияние по контуру.
 *
 * Свет — добавка к форме, а не замена ей: сам облик золотого крота
 * приходит картинкой из `enemy_types` (§263 — тип не должен отличаться
 * только цветом).
 */
.tam-hole[data-enemy="golden"] .tam-hole__mole {
  filter: drop-shadow(0 0 var(--ui-glow-md) color-mix(in srgb, var(--ui-gold-light) 62%, transparent));
}

/* Быстрая цель: короткий след движения на подъёме. */
.tam-hole[data-enemy="fast"].is-up .tam-hole__mole {
  animation-duration: var(--tam-t-tap);
}

/*
 * Бронированная цель.
 *
 * Каска держит первый удар: цель остаётся на поле, а игрок должен это
 * увидеть — иначе решит, что промахнулся. Тряска и вспышка кромки короче
 * попадания, чтобы два состояния не путались.
 */
.tam-hole[data-armor] .tam-hole__mole {
  filter: drop-shadow(var(--ui-art-shadow-pin));
}

.tam-hole.is-cracked .tam-hole__mole {
  animation: tamArmorCrack var(--tam-b-strike) ease-out 1;
}

@keyframes tamArmorCrack {
  0%   { transform: translateX(0) rotate(0); }
  30%  { transform: translateX(-4px) rotate(-3deg); }
  60%  { transform: translateX(4px) rotate(3deg); }
  100% { transform: translateX(0) rotate(0); }
}

/*
 * Закрытая лунка на ступенях обучения.
 *
 * Первый бой идёт на одной лунке, второй — на трёх (§272). Лунки не
 * удаляются, а гасятся: те же узлы вернутся на следующем уровне без
 * пересборки сцены. Зона касания уходит вместе с ними — бить по месту,
 * где никто не появится, игрок не должен.
 */
.tam-hole.is-off {
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
}

/* ─────────────── Фокус-режим ─────────────── */

/*
 * Бой — отдельный иммерсивный режим (§143-147): шапка, плашки валют и
 * нижнее меню на время боя уходят. Скрываются прозрачностью, а не
 * display: none — измеритель безопасных зон в mvp/services/telegram.js
 * читает их высоты, и обнулять их нельзя.
 */
body[data-route="game"] .trumpamole__topbar,
body[data-route="game"] .trumpamole__resources-inset,
body[data-route="game"] .trumpamole__bottom-nav {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--tam-t-panel) ease, visibility var(--tam-t-panel) ease;
}

/* Экран боя зафиксирован: вертикальной прокрутки во время боя нет (§52). */
body[data-route="game"] {
  overflow: hidden;
}

/*
 * Числа над лункой.
 *
 * Слой опыта лежит на body с z-index 2, а страница раздела — с z-index 10:
 * на поле числа выходили под сценой и не были видны вовсе. В бою поднимаем
 * слой над полем, но оставляем ниже окон и уведомлений.
 */
body[data-route="game"] .xpLayer {
  z-index: 25;
}

body[data-route="game"] .page[data-page="game"],
body[data-route="game"] .game-page {
  padding: 0;
  overflow: hidden;
  touch-action: none;
}

/* ─────────────── Ступени качества ─────────────── */

/*
 * §24: телефон греется в бою.
 *
 * Ступень называет сторож качества (`modules/battle/perf-controller.js`) —
 * он меряет настоящее время кадра и понижает её, пока кадр не начнёт
 * укладываться в срок. Здесь описано, что именно исчезает на каждой ступени.
 *
 * Дороже всего обходятся три вещи: частицы (двадцать две штуки на удар,
 * каждая со своей анимацией), тени-размытия под картинками лунок и
 * полупрозрачная виньетка поверх фона во весь экран. Подъём цели, её лицо,
 * вспышка попадания и числа опыта не трогаются ни на какой ступени: это
 * правила игры, а не украшение, и играть без них нельзя.
 */

[data-quality="mid"] .tam-hole .ruffle i:nth-child(n+7),
[data-quality="mid"] .tam-hole .sparks b:nth-child(n+4),
[data-quality="mid"] .tam-hole .debris s:nth-child(n+4) {
  display: none;
}

[data-quality="low"] .tam-hole .ruffle i:nth-child(n+4),
[data-quality="low"] .tam-hole .sparks b:nth-child(n+3),
[data-quality="low"] .tam-hole .debris {
  display: none;
}

/*
 * Тени картинок на слабой ступени.
 *
 * drop-shadow считается по прозрачности картинки на каждый кадр, а лунок на
 * экране девять и все они с передней кромкой. Плоская тень под лункой уже
 * нарисована псевдоэлементом `.tam-hole__art::after` — она и остаётся,
 * поэтому лунка не начинает «парить».
 */
[data-quality="low"] .tam-hole__front,
[data-quality="low"] .tam-hole__mole .moleImg {
  filter: none;
}

/* Виньетка во весь экран: полупрозрачный слой поверх фона стоит целого кадра. */
[data-quality="low"] .tam-battle__bg::after { display: none; }

/* Пыль и волна от удара — обратная связь есть и без них, остаётся вспышка. */
[data-quality="low"] .tam-hole.hit .dust,
[data-quality="low"] .tam-hole.hit .shockwave {
  display: none;
}

/*
 * will-change заставляет браузер держать отдельный слой на каждую цель.
 * На флагмане это выигрыш, на слабом устройстве — девять лишних слоёв в
 * видеопамяти, которой там и так нет.
 */
[data-quality="low"] .tam-hole__mole { will-change: auto; }

/* ─────────────── Уважение к системным настройкам ─────────────── */

/*
 * §163: тряску и частицы уменьшаем, движение цели сохраняем — иначе игра
 * перестаёт быть играбельной. В старом поле этого правила не было вовсе
 * (дефект B35).
 */
@media (prefers-reduced-motion: reduce) {

  .tam-hole.pop .ruffle i,
  .tam-hole.pop .sparks b,
  .tam-hole.pop .debris s,
  .tam-hole.hit .dust,
  .tam-hole.hit .shockwave,
  .tam-hole.hit .tam-hole__front,
  .tam-hole.is-denied .tam-hole__art {
    animation: none !important;
  }

  .tam-hole.is-up .tam-hole__mole {
    animation: none;
    transform: translate(-50%, 18%) scaleY(1);
  }

  /*
   * Тряска, хитстоп и пыль выключены, а молот остаётся: без него удар
   * перестаёт читаться как удар. Замах при этом короче и без отскока.
   */
  .tam-battle.is-shake .tam-battle__field,
  .tam-battle__dud,
  .tam-hole.is-flash .tam-hole__fx::after {
    animation: none !important;
  }

  .tam-hammer.is-strike { animation-duration: calc(var(--tam-b-strike) - var(--tam-t-tap)); }

  /*
   * Серия и точный удар остаются видимыми, но перестают мигать: это
   * сведения, а не праздник, и читаются они с самой капсулы.
   */
  .tam-battle-hud__combo.is-perfect,
  .tam-hole.is-perfect .tam-hole__fx::before {
    animation: none !important;
  }

  .tam-battle-hud__combo { transition: none; }
}

/* ─────────────── Узкий и низкий экран ─────────────── */

@media (max-width: 360px) {
  .tam-battle__field { width: min(94%, calc(var(--tam-field-space) * 0.68)); }
  .tam-hole { width: 33%; }
}

/*
 * Низкий экран: поле поджимается сверху и снизу, но не сжимается по
 * горизонтали — иначе соседние лунки сходятся, и промахнуться по нужной
 * становится слишком легко.
 */
@media (max-height: 680px) {
  .tam-battle__field {
    --tam-field-space: calc(var(--tam-viewport-h, 100vh) * 0.78
                            - var(--tam-inset-top, 0px) - var(--tam-inset-bottom, 0px));
    top: calc(13% + var(--tam-inset-top, 0px));
    bottom: calc(9% + var(--tam-inset-bottom, 0px));
  }
  .tam-battle-hud__stat { height: 38px; font-size: var(--ui-size-body); }
}

/*
 * Экран повёрнут.
 *
 * Игра вертикальная, но телефон в руках поворачивается сам, и Telegram
 * поворот не запрещает. Раньше поле в этом положении растягивалось на всю
 * ширину, а лунки — вместе с ним: три ряда сходились в один столбик из
 * налезающих друг на друга лунок, и бить было некуда. Теперь от высоты
 * остаётся почти всё, что есть, а ширину держит та же пропорция — поле
 * просто становится узкой полосой посреди экрана, зато играбельной.
 */
@media (orientation: landscape) and (max-height: 560px) {
  .tam-battle__field {
    --tam-field-space: calc(var(--tam-viewport-h, 100vh) * 0.86
                            - var(--tam-inset-top, 0px) - var(--tam-inset-bottom, 0px));
    /*
     * Вширь поле здесь пускают охотнее, чем стоя: горизонталь — это всё,
     * что осталось. Но тогда лунка, заданная долей ширины, снова выросла бы
     * выше расстояния между рядами, поэтому доля уменьшена ровно во столько
     * же раз, во сколько выросла ширина.
     */
    width: min(92%, calc(var(--tam-field-space) * 1.15));
    top: calc(9% + var(--tam-inset-top, 0px));
    bottom: calc(5% + var(--tam-inset-bottom, 0px));
  }
  .tam-hole { width: 19%; }
  /* Шапка боя прижимается к самому краю: высоты и так нет. */
  .tam-battle-hud { top: calc(var(--tam-inset-top, 0px) + var(--ui-space-1)); }
  .tam-battle-hud__stat { height: 34px; }
}

/*
 * Узкий экран: окно таймера ужимается вместе с боками.
 *
 * Шапка боя разложена сеткой `1fr auto 1fr`, и середина брала своё
 * первой: при `min-width: 128px` плюс поля и кромка окно таймера
 * занимало 160px из 280 доступных на 320px экране. Бокам оставалось по
 * 60px — меньше, чем занимают кнопка паузы (46px) и чип промахов рядом,
 * — и таймер ложился прямо на них: счётчик «×17» на снимке обрезан
 * посередине. Здесь окно и чипы уменьшены ровно настолько, чтобы ряд
 * снова сошёлся, а сами кнопки остались не мельче 44px (§49).
 */
@media (max-width: 360px) {
  .tam-battle-hud__timer {
    height: 46px;
    min-width: 96px;
    padding: 0 var(--ui-space-2);
  }

  .tam-battle-hud__timer .tam-battle-hud__value { font-size: 25px; }

  .tam-battle-hud__pause { width: 44px; height: 44px; }

  /* Чип уступает место первым: цифра в нём короткая и без полей читается. */
  .tam-battle-hud__stat {
    height: 38px;
    min-width: 0;
    flex: 0 1 auto;
    padding: 0 6px;
    gap: 3px;
  }

  .tam-battle-hud__stat svg { width: 17px; height: 17px; }

  .tam-battle-hud__level { font-size: 15px; }
}

/* ─────────────── Экран результата боя ─────────────── */

/*
 * Итог боя (§150-156). Живёт внутри окна `hero`/`reward` фреймворка, поэтому
 * подложку, панель и кнопки рисует не этот файл — здесь только начинка:
 * счёт, звёзды, сводка и награда.
 */

.tam-result {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--ui-space-4);
  width: 100%;
}

/*
 * Счёт итога — тёмная выемка со светлой цифрой, и материал ей даёт рама
 * (§22.2): кремовой плитки с коричневой цифрой нет ни в одном окне
 * референса. Раздел продолжал красить её кремом (`--ui-ivory-light` →
 * `--ui-ivory-dark` с кромкой `--ui-edge-ivory`) и подписывать тёмным
 * `--ui-text-ivory` — рама подключена последней и перекрывала всё это.
 * Здесь остались размеры и кегль.
 */
.tam-result__score {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--ui-space-1);
  min-width: 148px;
  padding: var(--ui-space-3) var(--ui-space-5);
  border-radius: var(--ui-radius-md);
}

.tam-result__score-label {
  font-family: var(--ui-font-condensed);
  font-size: var(--ui-size-small);
  letter-spacing: .08em;
  text-transform: uppercase;
}

.tam-result__score-value {
  font-size: 34px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.tam-result__slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--ui-space-3);
  width: 100%;
  /* Начинка не имеет права быть шире окна: ниже стоит картинка позы,
     и без этого она растягивала само окно за край экрана. */
  min-width: 0;
}

/*
 * Победная поза (§492) больше не живёт отдельной плашкой внизу сводки:
 * с §66 она стала САМИМ героем итога и показывается картинкой окна, на
 * месте общего ликующего Тональда. Своё описание ей больше не нужно —
 * её ведёт `.tam-modal__art` фреймворка (§87: мёртвого CSS не держим).
 */

/* ─── Звёзды ─── */

.tam-result__stars {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--ui-space-3);
}

/*
 * Незажжённая звезда остаётся на месте: три силуэта сразу показывают, что
 * у уровня есть куда расти. Зажигается каждая отдельно (§154).
 */
.tam-result__star {
  display: inline-flex;
  color: rgba(0, 0, 0, .34);
  filter: drop-shadow(0 2px 0 rgba(0, 0, 0, .3));
  transform: scale(.82);
  transition: transform var(--tam-t-panel) cubic-bezier(.2, 1.5, .4, 1), color var(--tam-t-panel) ease;
}

.tam-result__star.is-lit {
  color: var(--ui-gold);
  transform: scale(1.12);
  filter: drop-shadow(0 3px 0 var(--ui-gold-deep)) drop-shadow(0 0 var(--ui-glow-md) color-mix(in srgb, var(--ui-gold-light) 55%, transparent));
  animation: tamResultStar var(--tam-t-modal) ease-out 1;
}

@keyframes tamResultStar {
  0%   { transform: scale(.6) rotate(-16deg); }
  60%  { transform: scale(1.28) rotate(4deg); }
  100% { transform: scale(1.12) rotate(0); }
}

/* ─── Рекорд и цель ─── */

.tam-result__record,
.tam-result__goal {
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-2);
  padding: var(--ui-space-2) var(--ui-space-4);
  border-radius: var(--ui-radius-md);
  font-family: var(--ui-font-main);
  font-size: var(--ui-size-body);
  font-weight: 700;
}

.tam-result__record {
  color: var(--ui-text-dark);
  background: linear-gradient(180deg, var(--ui-gold-light) 0%, var(--ui-gold) 46%, var(--ui-gold-mid) 100%);
  box-shadow: 0 3px 0 var(--ui-gold-deep), var(--ui-shadow-soft);
}

/* Выемку под целью держит рама (§8), здесь только цвет строки: «цель
   взята» и «цель провалена» — состояния раздела, а не материал. */
.tam-result__goal {
  color: var(--ui-text-main);
}

.tam-result__goal.is-done   { color: var(--ui-green-light); }
.tam-result__goal.is-failed { color: var(--ui-red-light); }

/* ─── Сводка боя ─── */

.tam-result__stats {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  border-radius: var(--ui-radius-md);
  overflow: hidden;
  box-shadow: var(--ui-inner-well);
}

.tam-result__stat {
  display: flex;
  align-items: center;
  gap: var(--ui-space-3);
  padding: var(--ui-space-2) var(--ui-space-4);
  background: var(--ui-row-a);
  font-family: var(--ui-font-main);
  font-size: var(--ui-size-body);
  color: var(--ui-text-muted);
}

.tam-result__stat:nth-child(even) { background: var(--ui-row-b); }

.tam-result__stat-icon {
  display: inline-flex;
  color: var(--ui-gold-mid);
}

.tam-result__stat-label { flex: 1; }

.tam-result__stat-value {
  font-weight: 800;
  color: var(--ui-text-main);
  font-variant-numeric: tabular-nums;
}

/* ─── Награда ─── */

/*
 * Своих плиток у итога боя больше нет (§64, §25 рамы).
 *
 * Здесь стояла пара чипов «значок — число» ростом со строку статистики,
 * и «+180» за победу выглядело так же, как «Точность 78 %» ниже. Награда
 * во всей игре показывается одним компонентом — `.ui-reward` из рамы, —
 * а разделу остаётся только место вокруг него.
 */
.tam-result__slot .ui-reward-row {
  margin: var(--ui-space-2) 0 var(--ui-space-3);
}

/* ─── Ожидание ответа сервера ─── */

/*
 * §151 прямо запрещает замерший экран: пока сервер считает, игрок видит
 * бегущий счёт, а эта строка появляется только при настоящей задержке.
 */
.tam-result__checking {
  font-family: var(--ui-font-main);
  font-size: var(--ui-size-body);
  color: var(--ui-text-muted);
  text-align: center;
  animation: tamResultBreath 1.6s ease-in-out infinite;
}

@keyframes tamResultBreath {
  0%, 100% { opacity: .55; }
  50%      { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .tam-result__star,
  .tam-result__star.is-lit,
  .tam-result__checking {
    animation: none !important;
    transition: none;
  }
}

/* Низкий экран: сводка ужимается, чтобы итог помещался без прокрутки. */
@media (max-height: 680px) {
  .tam-result { gap: var(--ui-space-3); }
  .tam-result__score-value { font-size: 28px; }
  .tam-result__star svg { width: 34px; height: 34px; }
  .tam-result__stat { padding: var(--ui-space-1) var(--ui-space-3); }
}
