/* lvl up × PTJ — слой эффектов.
 *
 * Владелец прислал набор приёмов (бегущий блик по тексту, градиентный текст,
 * мерцающая решётка, лучи, кольцо прогресса, матрица глифов, сияющая рамка,
 * размытие к краю, появление списка, печать по букве). Здесь они переведены
 * на наш язык: одна бирюза Системы, срезанные углы, тёмное стекло окна
 * Системы. Никаких новых цветов — только токены app.css.
 *
 * Слой независим от app.js: классы вешает fx.js по разметке, которая уже
 * есть. Убрать всё разом — снять два тега в index.html.
 *
 * ПЛАВНОСТЬ (20.09.2026). Замер под CPU ×6 на 360×740: с эффектами как были —
 * 40 к/с в прокрутке и 26 длинных кадров за три секунды, без них — 59 и 2.
 * Дорого стоило не количество эффектов, а их природа: анимации box-shadow,
 * filter и background-position перерисовывают элемент каждый кадр, а холсты
 * перерисовывались целиком. Теперь всё, что движется вечно, движется через
 * transform и opacity (это телефон делает без перерисовки), холсты
 * перерисовывают только изменившиеся клетки, а размытие «за стеклом»
 * осталось только на шапке и вкладках — и то лишь в полном режиме.
 *
 * Три режима на <html data-fx>: full — всё; lite — без холстов, лучей,
 * бликов и стекла (слабые телефоны, выбирается само); off — только
 * необходимые переходы. Выбор — в Настройках, автоматика — в fx.js.
 *
 * Что где:
 *   .fx-grid        мерцающая решётка на весь фон (холст, fx.js)      full
 *   .fx-rays-top    лучи света из-под шапки                             full
 *   .fx-frame       сияющая рамка (вращается transform-ом)             full
 *   .fx-shine       бегущий блик: имя в шапке, ярлык «Сейчас»          full
 *   .fx-gradient    градиентный текст: редкость, имя карты             full/lite
 *   .fx-in          появление: только opacity и transform              full/lite
 *   .fx-beam        огонёк по кромке шапки и вкладок (transform)       full
 *   .fx-ripple      рябь от нажатия                                     full/lite
 *   .fx-typing      печать по букве в окне Системы                     все
 *   .fx-canvas      матрица глифов: загрузка, разговор, бой            full
 *   .fx-rays        лучи на «Глава закрыта», рождении, вскрытии карты  full
 *   .fx-fade-bottom туман над вкладками — градиент, без размытия       full/lite
 */

/* Старая статичная сетка уступает место мерцающей решётке. */
body::before { display: none; }

/* --- Мерцающая решётка: подложка всего приложения ------------------------ */
.fx-grid {
  position: fixed; inset: 0;
  width: 100%; height: 100%;
  z-index: -1;
  pointer-events: none;
  opacity: 0.7;
}

/* Экран рождения и «Привязка не выполнена» пускают решётку и лучи под панель. */
#birth.screen, #gate.gate { background: transparent; }
html[data-fx="lite"] #birth.screen, html[data-fx="off"] #birth.screen,
html[data-fx="lite"] #gate.gate, html[data-fx="off"] #gate.gate { background: var(--void); }

/* --- Лучи из-под шапки: один слой, движется только transform и opacity --- */
.fx-rays-top {
  position: fixed;
  top: 0; left: -25%; right: -25%;
  height: 58vh;
  z-index: -1;
  pointer-events: none;
  background:
    conic-gradient(from 180deg at 50% -6%,
      transparent 0deg,   rgba(79, 227, 216, 0.22) 5deg,  transparent 11deg,
      transparent 28deg,  rgba(79, 227, 216, 0.16) 33deg, transparent 40deg,
      transparent 58deg,  rgba(79, 227, 216, 0.26) 63deg, transparent 70deg,
      transparent 96deg,  rgba(79, 227, 216, 0.18) 100deg, transparent 108deg,
      transparent 130deg, rgba(79, 227, 216, 0.24) 136deg, transparent 144deg,
      transparent 160deg, rgba(79, 227, 216, 0.16) 166deg, transparent 174deg);
  -webkit-mask: linear-gradient(to bottom, #000 10%, transparent 92%);
          mask: linear-gradient(to bottom, #000 10%, transparent 92%);
  transform-origin: 50% 0;
  will-change: transform, opacity;
  animation: fx-rays-top 11s ease-in-out infinite alternate;
}
/* Экран боя закрывает игру целиком и не пускает решётку — лучи ему свои,
   тем же рисунком, через собственный слой. */
.fight > .fx-rays-top { position: absolute; z-index: 0; }
.fight > :not(.fx-rays-top) { position: relative; z-index: 1; }
@keyframes fx-rays-top {
  from { transform: rotate(-5deg) scaleX(1);    opacity: 0.4; }
  50%  { transform: rotate(0deg)  scaleX(1.08); opacity: 0.6; }
  to   { transform: rotate(5deg)  scaleX(1);    opacity: 0.45; }
}

/* --- Бегущий блик по тексту --------------------------------------------- */
/* Единственная анимация с перерисовкой, которая осталась: текст короткий,
   элементов один-два на экран, и замер её не заметил. */
.fx-shine {
  background: linear-gradient(110deg,
    var(--sys) 0%, var(--sys) 38%, #FFFFFF 50%, var(--sys) 62%, var(--sys) 100%);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: fx-shine 4s linear infinite;
  opacity: 1;
}
@keyframes fx-shine { from { background-position: 110% 0; } to { background-position: -110% 0; } }

/* --- Градиентный текст: статичный, красится один раз ----------------------- */
.fx-gradient {
  background: linear-gradient(90deg, var(--sys), var(--upgrade), var(--gold));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* --- Сияющая рамка --------------------------------------------------------
   fx.js кладёт в панель <i class="fx-frame"><i></i></i>. Внешний — кольцо
   толщиной 2 px по контуру панели (маска «рамка минус середина», тот же
   срез угла через clip-path: inherit). Внутренний — квадрат вдвое больше
   панели с коническим градиентом, который ВРАЩАЕТСЯ transform-ом: телефон
   крутит его на видеокарте, не перерисовывая градиент. Прежняя версия
   анимировала угол градиента через @property и перерисовывала рамку каждый
   кадр. */
.fx-border { position: relative; isolation: isolate; }
.fx-frame {
  position: absolute; inset: 0;
  padding: 2px;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
  clip-path: inherit;
  overflow: hidden;
  pointer-events: none;
  z-index: 1;
}
.fx-frame > i {
  position: absolute;
  left: 50%; top: 50%;
  width: 300%; padding-top: 300%;
  margin: -150% 0 0 -150%;
  background: conic-gradient(from 0deg,
    transparent 0deg,
    var(--fx-color, var(--sys)) 30deg, #FFFFFF 55deg, var(--fx-color, var(--sys)) 80deg,
    transparent 120deg,
    transparent 180deg,
    var(--fx-color, var(--sys)) 210deg, #FFFFFF 235deg, var(--fx-color, var(--sys)) 260deg,
    transparent 300deg);
  will-change: transform;
  animation: fx-spin 4.5s linear infinite;
}
@keyframes fx-spin { to { transform: rotate(360deg); } }

/* Панель «Сейчас» дышит: свечение — отдельный слой, меняется только его
   прозрачность. Прежде анимировался box-shadow самой панели. */
.panel-sys.fx-border { border-color: var(--sys); }
.fx-glow {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 0;
  box-shadow: inset 0 0 44px -14px var(--sys);
  clip-path: inherit;
  will-change: opacity;
  animation: fx-breathe 2.8s ease-in-out infinite alternate;
}
@keyframes fx-breathe { from { opacity: 0.35; } to { opacity: 1; } }

/* --- Появление: только opacity и transform --------------------------------- */
.fx-in { animation: fx-in 0.36s cubic-bezier(0.22, 1, 0.36, 1) both; }
.fx-in:nth-child(2)  { animation-delay: 0.04s; }
.fx-in:nth-child(3)  { animation-delay: 0.08s; }
.fx-in:nth-child(4)  { animation-delay: 0.12s; }
.fx-in:nth-child(5)  { animation-delay: 0.16s; }
.fx-in:nth-child(6)  { animation-delay: 0.20s; }
.fx-in:nth-child(7)  { animation-delay: 0.24s; }
.fx-in:nth-child(8)  { animation-delay: 0.28s; }
.fx-in:nth-child(n+9) { animation-delay: 0.32s; }
@keyframes fx-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* --- Кнопка действия: пульс свечения и пробегающий блик ------------------ */
.btn, .tile, .tab { position: relative; overflow: hidden; }
/* Пульс — отдельный слой с готовой тенью, дышит прозрачностью. */
.btn-primary::before {
  content: "";
  position: absolute; inset: 0;
  box-shadow: inset 0 0 14px 0 rgba(79, 227, 216, 0.35);
  pointer-events: none;
  will-change: opacity;
  animation: fx-breathe 3s ease-in-out infinite alternate;
}
/* Блик — узкая полоса, бежит transform-ом слева направо и ждёт паузу. */
.btn-primary::after {
  content: "";
  position: absolute; top: 0; bottom: 0; left: 0;
  width: 45%;
  background: linear-gradient(105deg,
    transparent 0%, rgba(255, 255, 255, 0.28) 40%, rgba(255, 255, 255, 0.55) 50%,
    rgba(255, 255, 255, 0.28) 60%, transparent 100%);
  transform: translateX(-120%);
  pointer-events: none;
  will-change: transform;
  animation: fx-sweep 6s ease-in-out infinite;
}
@keyframes fx-sweep {
  0%   { transform: translateX(-120%); }
  25%  { transform: translateX(340%); }
  100% { transform: translateX(340%); }
}

/* Текущий шаг главы дышит рамкой — слоем, а не тенью самого шага. */
.step-now { position: relative; }
.step-now::after {
  content: "";
  position: absolute; inset: 0;
  box-shadow: inset 0 0 14px -4px rgba(79, 227, 216, 0.5);
  pointer-events: none;
  will-change: opacity;
  animation: fx-breathe 2.4s ease-in-out infinite alternate;
}

/* --- Рябь от нажатия ------------------------------------------------------- */
.fx-ripple {
  position: absolute;
  width: 12px; height: 12px;
  margin: -6px 0 0 -6px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(79, 227, 216, 0.65), rgba(79, 227, 216, 0.15) 60%, transparent 70%);
  pointer-events: none;
  will-change: transform, opacity;
  animation: fx-ripple 0.65s ease-out forwards;
  z-index: 2;
}
@keyframes fx-ripple {
  from { transform: scale(1); opacity: 1; }
  to   { transform: scale(28); opacity: 0; }
}

/* --- Огонёк по кромке шапки и вкладок: узкая полоса едет transform-ом ---- */
.fx-beam {
  position: absolute;
  left: 0;
  width: 34%;
  height: 2px;
  pointer-events: none;
  background: linear-gradient(90deg,
    transparent, var(--sys) 35%, #FFFFFF 50%, var(--sys) 65%, transparent);
  transform: translateX(-100%);
  will-change: transform;
  animation: fx-beam 5s linear infinite;
  z-index: 3;
}
.hud > .fx-beam  { bottom: 0; }
.tabs > .fx-beam { top: 0; }
@keyframes fx-beam { from { transform: translateX(-100%); } to { transform: translateX(300%); } }

/* --- Полосы здоровья и сил: блик пробегает по заполненной части ----------- */
.meter-fill::after {
  content: "";
  position: absolute; top: 0; bottom: 0; left: 0;
  width: 40%;
  background: linear-gradient(100deg,
    transparent 0%, rgba(255, 255, 255, 0.3) 50%, transparent 100%);
  transform: translateX(-120%);
  will-change: transform;
  animation: fx-sweep 6s ease-in-out infinite;
}

/* --- Активная вкладка светится: статично, без анимации фильтра ------------ */
.tab.is-active .tab-icon {
  filter: drop-shadow(0 0 5px var(--sys)) drop-shadow(0 0 10px rgba(79, 227, 216, 0.45));
}

/* --- Туман над вкладками: градиент, без размытия --------------------------
   Размытие «за стеклом» здесь пересчитывалось на каждый кадр прокрутки и
   было самой дорогой вещью на экране, а глазу давало почти ничего. */
.fx-fade-bottom {
  position: fixed;
  left: 0; right: 0;
  bottom: calc(var(--tabs-h) + var(--safe-bottom));
  height: 72px;
  pointer-events: none;
  z-index: 5;
  background: linear-gradient(to bottom, rgba(11, 18, 25, 0), rgba(11, 18, 25, 0.9));
}

/* --- Печать по букве: реплики Системы --------------------------------------- */
.fx-typing::after {
  content: "▍";
  color: var(--sys);
  animation: fx-caret 0.8s steps(1) infinite;
  margin-left: 1px;
}
@keyframes fx-caret { 50% { opacity: 0; } }

/* --- Холст матрицы глифов: подложка загрузки и окна Системы --------------- */
.fx-canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  z-index: 0;
  opacity: 0.6;
}
.fight-scene .fx-canvas { opacity: 0.4; }
#scene .scene-body { position: relative; z-index: 1; }

/* --- Лучи: «Глава закрыта», рождение, вскрытие карты ----------------------- */
/* #reveal уже fixed на весь экран — ему только overflow; лист карточки
   становится опорой для лучей сам. */
.sheet-body.fx-rays { position: relative; }
.fx-rays { overflow: hidden; }
.fx-rays::before {
  content: "";
  position: absolute; inset: -40% -20% auto -20%;
  height: 160%;
  background:
    conic-gradient(from 180deg at 50% 0%,
      transparent 0deg,   rgba(79, 227, 216, 0.30) 5deg,   transparent 11deg,
      transparent 28deg,  rgba(79, 227, 216, 0.24) 33deg,  transparent 40deg,
      transparent 58deg,  rgba(79, 227, 216, 0.32) 63deg,  transparent 70deg,
      transparent 96deg,  rgba(79, 227, 216, 0.26) 100deg, transparent 108deg,
      transparent 130deg, rgba(79, 227, 216, 0.30) 136deg, transparent 144deg,
      transparent 160deg, rgba(79, 227, 216, 0.22) 166deg, transparent 174deg);
  -webkit-mask: linear-gradient(to bottom, #000, transparent 88%);
          mask: linear-gradient(to bottom, #000, transparent 88%);
  pointer-events: none;
  will-change: transform, opacity;
  animation: fx-rays 7s ease-in-out infinite alternate;
  z-index: 0;
}
.fx-rays > :not(.reveal-burst) { position: relative; z-index: 1; }
@keyframes fx-rays { from { transform: rotate(-4deg); opacity: 0.5; } to { transform: rotate(4deg); opacity: 0.8; } }

/* Вскрытая карта парит и покачивается после выезда. */
#reveal:not([hidden]) .reveal-card {
  animation:
    card-in 0.62s cubic-bezier(0.2, 0.9, 0.25, 1) both,
    fx-float 4.5s 0.7s ease-in-out infinite alternate;
}
@keyframes fx-float {
  from { translate: 0 0;    rotate: y -7deg; }
  to   { translate: 0 -10px; rotate: y 7deg; }
}
#reveal:not([hidden]) .reveal-burst { animation: burst 0.7s ease-out both, fx-burst-breathe 3s 0.7s ease-in-out infinite alternate; }
@keyframes fx-burst-breathe { from { opacity: 0.55; scale: 1; } to { opacity: 0.95; scale: 1.15; } }

/* --- Кольцо прогресса: доля здоровья на карточке, глава в шапке ---------- */
.fx-ring { width: 44px; height: 44px; transform: rotate(-90deg); }
.fx-ring circle { fill: none; stroke-width: 4; }
.fx-ring .track { stroke: var(--line-soft); }
.fx-ring .bar { stroke: var(--sys); stroke-linecap: butt;
  transition: stroke-dashoffset 0.7s cubic-bezier(0.2, 0.8, 0.2, 1); }

/* --- Счётчик чисел: пока число бежит, оно чуть подсвечено ----------------- */
.fx-ticking { color: var(--sys); text-shadow: 0 0 10px rgba(79, 227, 216, 0.6); transition: color 0.3s, text-shadow 0.3s; }

/* --- Лёгкий режим: слабые телефоны и выбор в Настройках --------------------
   Ничего вечного: без холстов, лучей, бликов, рамок и пульса. Появление и
   рябь остаются — они короткие и на transform/opacity. */
html[data-fx="lite"] .fx-grid, html[data-fx="lite"] .fx-canvas, html[data-fx="lite"] .fx-rays-top,
html[data-fx="lite"] .fx-beam, html[data-fx="lite"] .fx-frame, html[data-fx="lite"] .fx-glow,
html[data-fx="lite"] .fx-rays::before, html[data-fx="lite"] .btn-primary::before,
html[data-fx="lite"] .btn-primary::after, html[data-fx="lite"] .meter-fill::after,
html[data-fx="lite"] .step-now::after {
  display: none !important;
}
html[data-fx="lite"] .fx-shine {
  animation: none; background: none; color: var(--sys); -webkit-text-fill-color: initial;
}
html[data-fx="lite"] .tab.is-active .tab-icon { filter: none; }
html[data-fx="lite"] #reveal:not([hidden]) .reveal-card { animation: card-in 0.62s cubic-bezier(0.2, 0.9, 0.25, 1) both; }
html[data-fx="lite"] #reveal:not([hidden]) .reveal-burst { animation: burst 0.7s ease-out both; }

/* --- Выключено: как lite, и без появления с рябью --------------------------- */
html[data-fx="off"] .fx-grid, html[data-fx="off"] .fx-canvas, html[data-fx="off"] .fx-rays-top,
html[data-fx="off"] .fx-beam, html[data-fx="off"] .fx-frame, html[data-fx="off"] .fx-glow,
html[data-fx="off"] .fx-rays::before, html[data-fx="off"] .btn-primary::before,
html[data-fx="off"] .btn-primary::after, html[data-fx="off"] .meter-fill::after,
html[data-fx="off"] .step-now::after, html[data-fx="off"] .fx-ripple, html[data-fx="off"] .fx-fade-bottom {
  display: none !important;
}
html[data-fx="off"] .fx-shine {
  animation: none; background: none; color: var(--sys); -webkit-text-fill-color: initial;
}
html[data-fx="off"] .fx-in { animation: none; }
html[data-fx="off"] .tab.is-active .tab-icon { filter: none; }
html[data-fx="off"] #reveal:not([hidden]) .reveal-card { animation: card-in 0.4s ease-out both; }
html[data-fx="off"] #reveal:not([hidden]) .reveal-burst { animation: none; opacity: 0.55; }

@media (prefers-reduced-motion: reduce) {
  .fx-shine, .fx-in, .fx-rays::before, .fx-typing::after, .fx-rays-top,
  .fx-frame > i, .fx-glow, .btn-primary::before, .btn-primary::after, .step-now::after,
  .fx-beam, .meter-fill::after, #reveal:not([hidden]) .reveal-card,
  #reveal:not([hidden]) .reveal-burst {
    animation: none !important;
  }
  .fx-grid, .fx-canvas { display: none; }
}

/* ПЕРЕХОДЫ МЕЖДУ ЭКРАНАМИ (14.10.2026, владелец: «добавь больше плавности
   и анимаций»). Только opacity и transform — телефон делает их без
   перерисовки. Выключено при «меньше движения» и в режиме эффектов off. */
@media (prefers-reduced-motion: no-preference) {
  html:not([data-fx="off"]) #view.view-enter > *,
  html:not([data-fx="off"]) .wiki.wk-enter .wk-pad > * {
    animation: screen-in 0.38s cubic-bezier(0.22, 1, 0.36, 1) both;
  }
  html:not([data-fx="off"]) #view.view-enter > :nth-child(2),
  html:not([data-fx="off"]) .wiki.wk-enter .wk-pad > :nth-child(2) { animation-delay: 0.05s; }
  html:not([data-fx="off"]) #view.view-enter > :nth-child(3),
  html:not([data-fx="off"]) .wiki.wk-enter .wk-pad > :nth-child(3) { animation-delay: 0.1s; }
  html:not([data-fx="off"]) #view.view-enter > :nth-child(4),
  html:not([data-fx="off"]) .wiki.wk-enter .wk-pad > :nth-child(4) { animation-delay: 0.15s; }
  html:not([data-fx="off"]) #view.view-enter > :nth-child(n+5),
  html:not([data-fx="off"]) .wiki.wk-enter .wk-pad > :nth-child(n+5) { animation-delay: 0.2s; }
  html:not([data-fx="off"]) .wiki.wk-enter .wk-head { animation: head-in 0.3s ease-out both; }
  /* Чипы и строки списков — тот же отклик на нажатие, что у кнопок. */
  html:not([data-fx="off"]) .chip:active, html:not([data-fx="off"]) .wk-line:active,
  html:not([data-fx="off"]) .pick-row:active { transform: scale(0.98); transition: transform 0.08s; }
  /* Полосы здоровья и сил едут, а не прыгают. */
  html:not([data-fx="off"]) .bar-fill, html:not([data-fx="off"]) .meter-fill { transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1); }
}
@keyframes screen-in { from { opacity: 0; transform: translateY(12px); } }
@keyframes head-in { from { opacity: 0; transform: translateY(-6px); } }

/* ==========================================================================
   ОКНО СИСТЕМЫ ИЗ МАНХВЫ (17.10.2026, владелец: «больше анимаций и
   плавности, больше свечения, чтобы всё было понятно интуитивно и похоже на
   систему из манхв»).

   Каждая панель Lvl Up — голографическое окно: тёмное стекло, светящаяся
   бирюзовая кромка, уголки-скобы, строки развёртки. Окно ОТКРЫВАЕТСЯ, как в
   манхве: сначала вспыхивает линия, потом окно раскрывается по высоте.
   Свечение статичное (box-shadow, text-shadow) — оно есть в любом режиме,
   в том числе lite; вечное движение — только transform и opacity, и только
   в full. При «меньше движения» и data-fx="off" окна просто стоят.
   ========================================================================== */
#app, #sheet, #toast {
  --win-edge: rgba(79, 227, 216, 0.62);
  --win-glow: rgba(79, 227, 216, 0.24);
  --win-bg: linear-gradient(180deg, rgba(14, 40, 56, 0.94), rgba(5, 15, 24, 0.95));
}

/* Окно */
#view .panel {
  clip-path: none;
  background: linear-gradient(180deg, rgba(79, 227, 216, 0.08), transparent 26%), var(--win-bg) !important;
  border: 1px solid var(--win-edge);
  box-shadow: 0 0 0 1px rgba(79, 227, 216, 0.06), 0 0 18px var(--win-glow), 0 10px 28px rgba(0, 0, 0, 0.45),
    inset 0 0 26px rgba(79, 227, 216, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.09);
}
/* Уголки-скобы: четыре «Г» по углам, светятся. */
#view .panel::before {
  content: ""; position: absolute; inset: -3px; pointer-events: none; z-index: 2;
  background:
    linear-gradient(var(--sys), var(--sys)) left top / 16px 2px no-repeat,
    linear-gradient(var(--sys), var(--sys)) left top / 2px 16px no-repeat,
    linear-gradient(var(--sys), var(--sys)) right top / 16px 2px no-repeat,
    linear-gradient(var(--sys), var(--sys)) right top / 2px 16px no-repeat,
    linear-gradient(var(--sys), var(--sys)) left bottom / 16px 2px no-repeat,
    linear-gradient(var(--sys), var(--sys)) left bottom / 2px 16px no-repeat,
    linear-gradient(var(--sys), var(--sys)) right bottom / 16px 2px no-repeat,
    linear-gradient(var(--sys), var(--sys)) right bottom / 2px 16px no-repeat;
  filter: drop-shadow(0 0 4px var(--sys));
}
/* Строки развёртки поверх стекла — вместо старой засечки. */
#view .panel { isolation: isolate; }
#view .panel::after {
  inset: 0; top: 0; left: 0; width: auto; height: auto; translate: none; transform: none; opacity: 1; z-index: -1;
  background: repeating-linear-gradient(0deg, rgba(79, 227, 216, 0.035) 0 1px, transparent 1px 4px);
}
/* Главное окно («Сейчас», общий бой) светится ярче остальных. */
#view .panel.panel-sys, #view .panel.lv-now, #view .panel.lv-boss { --win-edge: var(--sys);
  box-shadow: 0 0 0 1px rgba(79, 227, 216, 0.2), 0 0 28px rgba(79, 227, 216, 0.38), 0 10px 28px rgba(0, 0, 0, 0.45),
    inset 0 0 34px rgba(79, 227, 216, 0.14), inset 0 1px 0 rgba(255, 255, 255, 0.12); }
#view .panel.lv-boss { --win-edge: rgba(255, 77, 77, 0.75);
  box-shadow: 0 0 28px rgba(255, 77, 77, 0.3), 0 10px 28px rgba(0, 0, 0, 0.45), inset 0 0 34px rgba(255, 77, 77, 0.12); }
#view .panel.is-hot { --win-edge: rgba(255, 77, 77, 0.65); }
#view .panel.subbar::before, #view .panel.subbar::after { display: none; }
#view .panel.subbar { box-shadow: 0 0 12px rgba(79, 227, 216, 0.12), inset 0 0 18px rgba(79, 227, 216, 0.05); }

/* Заголовки окна светятся, как надписи Системы. */
#view .sys-label { color: var(--sys); text-shadow: 0 0 8px rgba(79, 227, 216, 0.75), 0 0 18px rgba(79, 227, 216, 0.35); }
#view .panel h1, #view .panel h2, #view .panel h3 { text-shadow: 0 0 14px rgba(150, 245, 238, 0.35); }
#view .lv-tile b, #view .lv-quest-bar b, #view .data { text-shadow: 0 0 8px rgba(79, 227, 216, 0.45); }
#view .lv-tile.is-gold b { text-shadow: 0 0 10px rgba(255, 198, 92, 0.55); }
#view .lv-tile.is-hot b { text-shadow: 0 0 10px rgba(255, 77, 77, 0.55); }
#view .lv-head-ic, #view .lv-tile .ic, #view .lv-rows li > .ic { filter: drop-shadow(0 0 4px rgba(79, 227, 216, 0.7)); }

/* Плитки и строки — маленькие окна внутри окна. */
#view .lv-tile {
  clip-path: none; border: 1px solid rgba(79, 227, 216, 0.35);
  background: radial-gradient(120% 100% at 50% 0%, rgba(79, 227, 216, 0.14), transparent 70%), rgba(4, 14, 22, 0.7);
  box-shadow: inset 0 0 14px rgba(79, 227, 216, 0.08), 0 0 10px rgba(79, 227, 216, 0.1);
}
#view .lv-rows li { background: linear-gradient(90deg, rgba(79, 227, 216, 0.07), rgba(4, 14, 22, 0.6) 40%); border-left-color: rgba(79, 227, 216, 0.4); }
#view .lv-rows li.is-now { border-left-color: var(--sys); box-shadow: inset 3px 0 12px -4px var(--sys), 0 0 12px rgba(79, 227, 216, 0.15); }
#view .lv-rows li.is-done { border-left-color: var(--good); }
#view .lv-rows li.is-hot { border-left-color: var(--blood); background: linear-gradient(90deg, rgba(255, 77, 77, 0.1), rgba(4, 14, 22, 0.6) 40%); }

/* Кнопки — светящиеся клавиши Системы. */
#app .btn { clip-path: none; border-color: rgba(79, 227, 216, 0.4); background: rgba(8, 26, 38, 0.78);
  box-shadow: inset 0 0 12px rgba(79, 227, 216, 0.08); transition: transform 0.12s, box-shadow 0.2s, border-color 0.2s, background 0.2s; }
#app .btn:hover:not(:disabled) { border-color: var(--sys); box-shadow: inset 0 0 16px rgba(79, 227, 216, 0.18), 0 0 12px rgba(79, 227, 216, 0.25); }
#app .btn:active:not(:disabled) { transform: scale(0.96); translate: none;
  box-shadow: inset 0 0 22px rgba(79, 227, 216, 0.35), 0 0 18px rgba(79, 227, 216, 0.45); }
#app .btn-primary { position: relative; overflow: hidden; color: #effffe; border-color: var(--sys);
  background: linear-gradient(180deg, rgba(79, 227, 216, 0.42), rgba(30, 120, 118, 0.35));
  text-shadow: 0 0 8px rgba(79, 227, 216, 0.9);
  box-shadow: 0 0 16px rgba(79, 227, 216, 0.42), inset 0 0 16px rgba(79, 227, 216, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.3); }
#app .btn-ghost { background: rgba(4, 14, 22, 0.4); }
#app .btn-danger { border-color: rgba(255, 77, 77, 0.6); box-shadow: inset 0 0 12px rgba(255, 77, 77, 0.12), 0 0 10px rgba(255, 77, 77, 0.15); }
#app .btn:disabled { box-shadow: none; filter: saturate(0.3); }

/* Полосы: светятся, по ним бежит отблеск. */
#view .lv-bar { overflow: hidden; }
#view .lv-bar i, #view .meter-fill { box-shadow: 0 0 10px var(--sys-glow), 0 0 2px var(--sys); }
#view .lv-bar i::after {
  content: ""; position: absolute; inset: 0; width: 40%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.55), transparent);
  transform: translateX(-120%);
}

/* Вкладки снизу и шапка: свечение активного. */
.tab.is-active .tab-icon { filter: drop-shadow(0 0 6px var(--sys)) drop-shadow(0 0 12px rgba(79, 227, 216, 0.5)); }
.tab.is-active .tab-text { text-shadow: 0 0 8px var(--sys); }
.tabs { box-shadow: 0 -1px 0 rgba(79, 227, 216, 0.5), 0 -10px 24px rgba(79, 227, 216, 0.1); }
.hud { box-shadow: 0 1px 0 rgba(79, 227, 216, 0.5), 0 10px 24px rgba(79, 227, 216, 0.08); }

/* Уведомление — окно Системы со своей шапкой. */
#toast.toast:not(.toast-wl):not(.toast-wk):not(.toast-rt) {
  padding: 30px 16px 12px; border: 1px solid var(--win-edge); background: var(--win-bg); font-size: 14px;
  box-shadow: 0 0 22px var(--win-glow), 0 10px 30px rgba(0, 0, 0, 0.6), inset 0 0 22px rgba(79, 227, 216, 0.1);
  clip-path: none; text-align: center;
}
#toast.toast:not(.toast-wl):not(.toast-wk):not(.toast-rt)::before {
  content: "◆ УВЕДОМЛЕНИЕ"; position: absolute; top: 8px; left: 0; right: 0; text-align: center;
  font-family: var(--font-data); font-size: 10px; letter-spacing: 0.3em; color: var(--sys);
  text-shadow: 0 0 8px var(--sys);
}
#toast.toast.bad:not(.toast-wl):not(.toast-wk):not(.toast-rt) { --win-edge: rgba(255, 77, 77, 0.7); --win-glow: rgba(255, 77, 77, 0.3); }
#toast.toast.bad:not(.toast-wl):not(.toast-wk):not(.toast-rt)::before { content: "◆ ОТКАЗ"; color: var(--blood); text-shadow: 0 0 8px var(--blood); }

/* Лист (окно поверх экрана) — тоже окно Системы, если у него нет своей темы. */
#sheet .sheet-body[class="sheet-body"] {
  border: 1px solid var(--win-edge); background: var(--win-bg);
  box-shadow: 0 0 26px var(--win-glow), inset 0 0 30px rgba(79, 227, 216, 0.08);
}

/* Дымка за окнами: два мягких пятна света медленно плывут (только full). */
#app::after {
  content: ""; position: fixed; inset: -20%; pointer-events: none; z-index: -1;
  background: radial-gradient(40% 30% at 25% 30%, rgba(79, 227, 216, 0.1), transparent 70%),
    radial-gradient(35% 28% at 75% 70%, rgba(80, 140, 255, 0.08), transparent 70%);
}

@media (prefers-reduced-motion: no-preference) {
  /* Окно открывается: вспышка линии → раскрытие по высоте. */
  html:not([data-fx="off"]) #view.view-enter > .panel,
  html:not([data-fx="off"]) #view.view-enter > section.panel,
  html:not([data-fx="off"]) #view.view-enter > div.panel {
    animation: sys-open 0.62s cubic-bezier(0.2, 0.9, 0.25, 1) both; transform-origin: 50% 50%;
  }
  html:not([data-fx="off"]) #view.view-enter > .panel::before { animation: sys-corners 0.9s ease-out both; }
  html:not([data-fx="off"]) #view.view-enter > .panel > * { animation: sys-content 0.5s ease-out 0.28s both; }
  html:not([data-fx="off"]) #view.view-enter > :nth-child(2) { animation-delay: 0.07s; }
  html:not([data-fx="off"]) #view.view-enter > :nth-child(3) { animation-delay: 0.14s; }
  html:not([data-fx="off"]) #view.view-enter > :nth-child(4) { animation-delay: 0.21s; }
  html:not([data-fx="off"]) #view.view-enter > :nth-child(n+5) { animation-delay: 0.28s; }
  html:not([data-fx="off"]) #view.view-enter > :nth-child(2) > * { animation-delay: 0.35s; }
  html:not([data-fx="off"]) #view.view-enter > :nth-child(3) > * { animation-delay: 0.42s; }
  html:not([data-fx="off"]) #view.view-enter > :nth-child(n+4) > * { animation-delay: 0.5s; }
  /* Уведомление и лист открываются так же. */
  html:not([data-fx="off"]) #toast.toast:not(.toast-wl):not(.toast-wk):not(.toast-rt) { animation: sys-open 0.45s cubic-bezier(0.2, 0.9, 0.25, 1) both; }
  html:not([data-fx="off"]) #sheet:not([hidden]) .sheet-body[class="sheet-body"] { animation: sys-open 0.5s cubic-bezier(0.2, 0.9, 0.25, 1) both; }
  /* Нажатие — вспышка. */
  html:not([data-fx="off"]) #view .lv-tile:active, html:not([data-fx="off"]) #view .lv-route:active,
  html:not([data-fx="off"]) #view .lv-crow:active { transform: scale(0.97); }
  /* Вечное движение — только full: отблеск по полосам, дымка, дыхание главной кнопки. */
  html[data-fx="full"] #view .lv-bar i::after { animation: sys-sweep 2.8s ease-in-out 1s infinite; }
  html[data-fx="full"] #app::after { animation: sys-drift 26s ease-in-out infinite alternate; }
  html[data-fx="full"] #view .lv-now .btn-primary,
  html[data-fx="full"] #view .lv-boss .btn-primary { animation: sys-call 2.4s ease-in-out infinite; }
  html[data-fx="full"] #view .lv-head-ic { animation: sys-blink 4.5s ease-in-out infinite; }
}
@keyframes sys-open {
  0% { opacity: 0; transform: scale(0.4, 0.015); }
  35% { opacity: 1; transform: scale(1, 0.015); }
  100% { opacity: 1; transform: none; }
}
@keyframes sys-corners { 0%, 30% { opacity: 0; } 50% { opacity: 1; } 65% { opacity: 0.4; } 100% { opacity: 1; } }
@keyframes sys-content { from { opacity: 0; transform: translateY(6px); } }
@keyframes sys-sweep { 0% { transform: translateX(-120%); } 60%, 100% { transform: translateX(300%); } }
@keyframes sys-drift { from { transform: translate3d(-3%, -2%, 0); } to { transform: translate3d(4%, 3%, 0); } }
@keyframes sys-call { 50% { transform: scale(1.02); } }
@keyframes sys-blink { 0%, 86%, 100% { opacity: 1; } 90% { opacity: 0.35; } 94% { opacity: 1; } }

html[data-fx="off"] #view .panel::after { display: none; }

/* Заголовок окна отчёркнут светящейся линией, гаснущей к краям. */
#view .lv-sec > .lv-head, #view .lv-now > .lv-now-top { position: relative; padding-bottom: 9px; }
#view .lv-sec > .lv-head::after, #view .lv-now > .lv-now-top::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--sys) 20%, var(--sys) 80%, transparent);
  box-shadow: 0 0 8px var(--sys); opacity: 0.55;
}
/* Раскрывашки «Игрока» и справка — тоже окна. */
#view .codex-head {
  border-color: rgba(79, 227, 216, 0.45); background: var(--win-bg);
  box-shadow: 0 0 12px rgba(79, 227, 216, 0.14), inset 0 0 16px rgba(79, 227, 216, 0.06);
}
#view .hero-fold.is-open .codex-head { border-color: var(--sys); box-shadow: 0 0 18px rgba(79, 227, 216, 0.3), inset 0 0 18px rgba(79, 227, 216, 0.1); }
#view .codex-name { text-shadow: 0 0 8px rgba(79, 227, 216, 0.4); }
/* Полосы в шапке: здоровье, силы, сытость, дух — светятся своим цветом. */
.hud .meter { box-shadow: 0 0 8px rgba(79, 227, 216, 0.2); }
.hud .meter-hp .meter-fill { box-shadow: 0 0 10px rgba(255, 77, 77, 0.6); }
.hud .meter-sta .meter-fill { box-shadow: 0 0 10px rgba(79, 227, 216, 0.6); }

/* Смена экрана: Система «сканирует» — светящаяся полоса проходит сверху вниз. */
@media (prefers-reduced-motion: no-preference) {
  html:not([data-fx="off"]) #view.view-enter::after {
    content: ""; position: fixed; left: 0; right: 0; top: 0; height: 140px; z-index: 30; pointer-events: none;
    background: linear-gradient(180deg, transparent, rgba(79, 227, 216, 0.16) 45%, rgba(170, 255, 248, 0.32) 50%, rgba(79, 227, 216, 0.16) 55%, transparent);
    animation: sys-scan 0.85s cubic-bezier(0.4, 0, 0.2, 1) both;
  }
  html:not([data-fx="off"]) #view .lv-rows li { transition: background 0.2s, box-shadow 0.2s; }
}
@keyframes sys-scan { from { transform: translateY(-140px); opacity: 1; } 85% { opacity: 1; } to { transform: translateY(100vh); opacity: 0; } }

/* ==========================================================================
   Большие окна Системы: «Уровень повышен», «Задание выполнено» (app.js
   sysShow). Затемнение, лучи, окно раскрывается из линии; число уровня
   вспыхивает. Свечение статичное, движение — transform/opacity.
   ========================================================================== */
.sys-modal {
  position: fixed; inset: 0; z-index: 120; display: grid; place-items: center; padding: 20px;
  background: radial-gradient(circle at 50% 45%, rgba(10, 40, 52, 0.75), rgba(2, 6, 10, 0.92));
  --win-edge: var(--sys); --win-bg: linear-gradient(180deg, rgba(14, 44, 60, 0.96), rgba(4, 14, 22, 0.97));
}
.sys-modal-rays {
  position: absolute; inset: -30%; pointer-events: none; opacity: 0.55;
  background: repeating-conic-gradient(from 0deg at 50% 50%, rgba(79, 227, 216, 0.12) 0 6deg, transparent 6deg 18deg);
  -webkit-mask-image: radial-gradient(circle, #000 0 25%, transparent 60%); mask-image: radial-gradient(circle, #000 0 25%, transparent 60%);
}
.sys-win {
  position: relative; width: min(100%, 380px); padding: 22px 18px 18px; display: grid; gap: 12px; text-align: center;
  border: 1px solid var(--win-edge); background: var(--win-bg);
  box-shadow: 0 0 0 1px rgba(79, 227, 216, 0.2), 0 0 40px rgba(79, 227, 216, 0.45), inset 0 0 40px rgba(79, 227, 216, 0.15);
}
.sys-win::before {
  content: ""; position: absolute; inset: -4px; pointer-events: none;
  background:
    linear-gradient(var(--sys), var(--sys)) left top / 22px 2px no-repeat, linear-gradient(var(--sys), var(--sys)) left top / 2px 22px no-repeat,
    linear-gradient(var(--sys), var(--sys)) right top / 22px 2px no-repeat, linear-gradient(var(--sys), var(--sys)) right top / 2px 22px no-repeat,
    linear-gradient(var(--sys), var(--sys)) left bottom / 22px 2px no-repeat, linear-gradient(var(--sys), var(--sys)) left bottom / 2px 22px no-repeat,
    linear-gradient(var(--sys), var(--sys)) right bottom / 22px 2px no-repeat, linear-gradient(var(--sys), var(--sys)) right bottom / 2px 22px no-repeat;
  filter: drop-shadow(0 0 6px var(--sys));
}
.sys-win-kicker { margin: 0; font-family: var(--font-data); font-size: 11px; letter-spacing: 0.35em; color: var(--sys);
  text-transform: uppercase; text-shadow: 0 0 8px var(--sys); }
.sys-win-title { margin: 0; font-size: 20px; font-weight: 900; letter-spacing: 0.08em; text-transform: uppercase; color: #effffe;
  text-shadow: 0 0 10px var(--sys), 0 0 26px rgba(79, 227, 216, 0.6); }
.sys-win-title::before, .sys-win-title::after { content: " ⟦ "; color: var(--sys); font-weight: 400; }
.sys-win-title::after { content: " ⟧ "; }
.sys-win-big { display: flex; align-items: baseline; justify-content: center; gap: 8px; color: var(--sys); }
.sys-win-big span { font-family: var(--font-data); font-size: 16px; text-transform: uppercase; letter-spacing: 0.2em; }
.sys-win-big b { font-family: var(--font-data); font-size: 72px; line-height: 1; color: #f2fffe;
  text-shadow: 0 0 12px var(--sys), 0 0 34px var(--sys), 0 0 60px rgba(79, 227, 216, 0.5); }
.sys-win-big.is-check .ic { width: 64px; height: 64px; color: var(--sys); filter: drop-shadow(0 0 10px var(--sys)) drop-shadow(0 0 24px var(--sys)); }
.sys-win-text { font-size: 15px; line-height: 1.5; text-align: left; padding: 10px 12px; border-left: 2px solid var(--sys);
  background: rgba(79, 227, 216, 0.06); }
.sys-win .lv-rows { text-align: left; }
.sys-win .btn-row { display: flex; gap: 8px; }
.sys-win .btn { flex: 1; clip-path: none; border: 1px solid rgba(79, 227, 216, 0.5); background: rgba(8, 26, 38, 0.8); color: var(--ink); }
.sys-win .btn-primary { border-color: var(--sys); color: #effffe; background: linear-gradient(180deg, rgba(79, 227, 216, 0.45), rgba(30, 120, 118, 0.35));
  box-shadow: 0 0 18px rgba(79, 227, 216, 0.5), inset 0 0 16px rgba(79, 227, 216, 0.3); text-shadow: 0 0 8px var(--sys); }
.sys-modal.is-quest .sys-win-title { font-size: 19px; }
.sys-modal.is-closing { opacity: 0; transition: opacity 0.25s; }

@media (prefers-reduced-motion: no-preference) {
  html:not([data-fx="off"]) .sys-modal { animation: sys-fade 0.3s ease-out both; }
  html:not([data-fx="off"]) .sys-win { animation: sys-open 0.7s cubic-bezier(0.2, 0.9, 0.25, 1) 0.1s both; }
  html:not([data-fx="off"]) .sys-win::before { animation: sys-corners 1s ease-out 0.1s both; }
  html:not([data-fx="off"]) .sys-win > * { animation: sys-content 0.45s ease-out both; }
  html:not([data-fx="off"]) .sys-win > :nth-child(1) { animation-delay: 0.4s; }
  html:not([data-fx="off"]) .sys-win > :nth-child(2) { animation-delay: 0.5s; }
  html:not([data-fx="off"]) .sys-win > :nth-child(3) { animation-delay: 0.62s; }
  html:not([data-fx="off"]) .sys-win > :nth-child(n+4) { animation-delay: 0.75s; }
  html:not([data-fx="off"]) .sys-win-big b, html:not([data-fx="off"]) .sys-win-big.is-check .ic { animation: sys-burst 0.9s cubic-bezier(0.2, 0.9, 0.25, 1.4) 0.55s both; }
  html[data-fx="full"] .sys-modal-rays { animation: sys-spin 30s linear infinite; }
}
@keyframes sys-fade { from { opacity: 0; } }
@keyframes sys-burst { 0% { opacity: 0; transform: scale(2.4); } 60% { opacity: 1; transform: scale(0.92); } 100% { transform: none; } }
@keyframes sys-spin { to { transform: rotate(360deg); } }

/* ==========================================================================
   Бой — окно Системы: бойцы, лог и кнопки светятся; на старте — заставка
   «Бой» и выход бойцов с краёв; итог — окно с большим заголовком.
   Высоту не трогаем: на 360×640 каждый пиксель у лога.
   ========================================================================== */
#fight .fight-top { border-bottom: 1px solid rgba(79, 227, 216, 0.55); box-shadow: 0 1px 14px rgba(79, 227, 216, 0.2);
  background: linear-gradient(180deg, rgba(79, 227, 216, 0.08), transparent); }
#fight .combatant { padding-left: 8px; border-left: 2px solid var(--sys); }
#fight #cmb-foe { border-left-color: var(--blood); }
#fight #cmb-you { box-shadow: -4px 0 12px -6px var(--sys); }
#fight #cmb-foe { box-shadow: -4px 0 12px -6px var(--blood); }
#fight .combatant-name { text-shadow: 0 0 10px rgba(150, 245, 238, 0.45); }
#fight #cmb-foe .combatant-name { text-shadow: 0 0 10px rgba(255, 77, 77, 0.5); }
#fight .meter-hp .meter-fill { box-shadow: 0 0 10px rgba(255, 77, 77, 0.6); }
#fight .meter-sta .meter-fill { box-shadow: 0 0 10px rgba(79, 227, 216, 0.6); }
#fight .fight-log { background: repeating-linear-gradient(0deg, rgba(79, 227, 216, 0.03) 0 1px, transparent 1px 4px); }
#fight .btn { clip-path: none; border-color: rgba(79, 227, 216, 0.45); background: rgba(8, 26, 38, 0.82);
  box-shadow: inset 0 0 12px rgba(79, 227, 216, 0.1); transition: transform 0.1s, box-shadow 0.2s; }
#fight .btn:active:not(:disabled) { transform: scale(0.95); translate: none;
  box-shadow: inset 0 0 22px rgba(79, 227, 216, 0.4), 0 0 20px rgba(79, 227, 216, 0.5); }
#fight .btn-primary { color: #effffe; border-color: var(--sys); background: linear-gradient(180deg, rgba(79, 227, 216, 0.45), rgba(30, 120, 118, 0.35));
  text-shadow: 0 0 8px var(--sys); box-shadow: 0 0 16px rgba(79, 227, 216, 0.45), inset 0 0 14px rgba(79, 227, 216, 0.3); }
#fight .btn-danger { border-color: rgba(255, 77, 77, 0.7); box-shadow: 0 0 12px rgba(255, 77, 77, 0.3), inset 0 0 12px rgba(255, 77, 77, 0.15); }

/* Итог боя */
#fight .fight-result { text-align: center; display: grid; gap: 8px; clip-path: none; border: 1px solid var(--sys);
  background: linear-gradient(180deg, rgba(14, 44, 60, 0.95), rgba(4, 14, 22, 0.96));
  box-shadow: 0 0 34px rgba(79, 227, 216, 0.4), inset 0 0 30px rgba(79, 227, 216, 0.12); }
#fight .fight-result > div { text-align: left; }
#fight .fight-result-title { font-size: 30px; font-weight: 900; letter-spacing: 0.2em; margin: 0; color: #effffe;
  text-shadow: 0 0 12px var(--sys), 0 0 30px rgba(79, 227, 216, 0.6); }
#fight .fight-result.is-won .fight-result-title { color: #fff7e0; text-shadow: 0 0 12px var(--gold), 0 0 30px rgba(255, 198, 92, 0.6); }
#fight .fight-result.is-won { border-color: var(--gold); box-shadow: 0 0 34px rgba(255, 198, 92, 0.35), inset 0 0 30px rgba(255, 198, 92, 0.1); }
#fight .fight-result.is-lost { border-color: var(--blood); box-shadow: 0 0 34px rgba(255, 77, 77, 0.35), inset 0 0 30px rgba(255, 77, 77, 0.1); }
#fight .fight-result.is-lost .fight-result-title { text-shadow: 0 0 12px var(--blood), 0 0 30px rgba(255, 77, 77, 0.6); }

@media (prefers-reduced-motion: no-preference) {
  html:not([data-fx="off"]) #fight.fight-enter .fight-actions { animation: sys-content 0.5s ease-out 0.7s both; }
  html:not([data-fx="off"]) #fight.fight-enter::after {
    content: "БОЙ"; position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none; z-index: 50;
    font-family: var(--font-data); font-size: 64px; font-weight: 900; letter-spacing: 0.4em; color: #effffe;
    text-shadow: 0 0 14px var(--blood), 0 0 40px rgba(255, 77, 77, 0.7);
    background: linear-gradient(180deg, transparent 40%, rgba(255, 77, 77, 0.12) 50%, transparent 60%);
    animation: fight-title 1.2s ease-out both;
  }
  html:not([data-fx="off"]) #fight .fight-result { animation: sys-open 0.7s cubic-bezier(0.2, 0.9, 0.25, 1) both; }
  html:not([data-fx="off"]) #fight .fight-result-title { animation: sys-burst 0.8s cubic-bezier(0.2, 0.9, 0.25, 1.4) 0.4s both; }
}
@keyframes fight-from-left { from { opacity: 0; transform: translateX(-40px); } }
@keyframes fight-from-right { from { opacity: 0; transform: translateX(40px); } }
@keyframes fight-title {
  0% { opacity: 0; transform: scale(1.8); }
  25% { opacity: 1; transform: scale(1); }
  70% { opacity: 1; transform: scale(1.02); }
  100% { opacity: 0; transform: scale(0.9); }
}

/* ==========================================================================
   Бой: арена (17.10.2026, «улучши вид боя, чтобы всё было красиво и
   видно»). Портреты лицом к лицу в светящихся рамках, под каждым имя и
   полосы; посередине — номер раунда и VS. Сцена остаётся тем же гибким
   блоком (.fight > .fight-scene), что ужимается первым на низком экране.
   ========================================================================== */
#fight .fight-arena {
  display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: stretch; gap: 8px;
  padding: 8px 12px 8px; min-height: 150px; max-height: 300px; flex: 1 3 190px;
  background:
    radial-gradient(60% 80% at 20% 40%, rgba(79, 227, 216, 0.12), transparent 70%),
    radial-gradient(60% 80% at 80% 40%, rgba(255, 77, 77, 0.12), transparent 70%),
    linear-gradient(180deg, rgba(79, 227, 216, 0.06), transparent 60%);
  border-bottom: 1px solid rgba(79, 227, 216, 0.5); box-shadow: 0 1px 16px rgba(79, 227, 216, 0.18);
}
#fight:has(.hand-fan) > .fight-arena { flex: 1 4 210px; min-height: 140px; max-height: 290px; }
.arena-side { display: flex; flex-direction: column; gap: 6px; min-width: 0; min-height: 0; }
/* Портреты одной высоты, даже если имя врага в две строки: стороны делят
   строки арены (subgrid). Без subgrid — прежняя колонка, просто вразнобой. */
@supports (grid-template-rows: subgrid) {
  #fight .fight-arena { grid-template-rows: minmax(0, 1fr) auto; row-gap: 6px; }
  #fight .fight-arena .arena-side { display: grid; grid-row: span 2; grid-template-rows: subgrid; }
  #fight .fight-arena .arena-side .fighter { min-height: 0; }
  #fight .fight-arena .scene-mid { grid-row: span 2; }
  #fight .fight-arena .arena-side .combatant { align-self: start; }
}
.arena-side .fighter {
  flex: 1 1 auto; height: auto; min-height: 56px; max-height: none; position: relative; overflow: hidden;
  border: 1px solid rgba(79, 227, 216, 0.55);
  background: radial-gradient(80% 90% at 50% 100%, rgba(79, 227, 216, 0.25), transparent 70%), rgba(4, 14, 22, 0.7);
  box-shadow: 0 0 16px rgba(79, 227, 216, 0.25), inset 0 0 18px rgba(79, 227, 216, 0.12);
}
.arena-side.is-foe .fighter {
  border-color: rgba(255, 77, 77, 0.6);
  background: radial-gradient(80% 90% at 50% 100%, rgba(255, 77, 77, 0.22), transparent 70%), rgba(14, 4, 6, 0.7);
  box-shadow: 0 0 16px rgba(255, 77, 77, 0.25), inset 0 0 18px rgba(255, 77, 77, 0.12);
}
.arena-side .fighter img { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; }
/* Кадр целиком: вписан, а не обрезан; поля — размытая копия того же кадра. */
.arena-side .fighter .fig-main { object-fit: contain; object-position: 50% 100%; z-index: 1; }
.arena-side .fighter .fig-bg { object-fit: cover; filter: blur(9px) brightness(0.45) saturate(1.2); transform: scale(1.18); opacity: 0.9; }
.arena-side .fighter.is-hurt .fig-bg { filter: blur(9px) brightness(0.35) saturate(0.6); }
.arena-side .fighter::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 2;
  background: linear-gradient(180deg, transparent 72%, rgba(2, 8, 12, 0.6)),
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.03) 0 1px, transparent 1px 3px);
}
.arena-side .fighter.is-hurt { border-color: var(--blood); }
.arena-side .combatant { grid-template-columns: minmax(0, 1fr); min-width: 0; padding-left: 0 !important; border-left: 0 !important; box-shadow: none !important; gap: 4px; }
.arena-side .combatant-head { gap: 4px; flex-wrap: nowrap; }
.arena-side .combatant-name { font-size: 13px; line-height: 1.15; overflow: hidden; white-space: normal; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; min-width: 0; flex: 1 1 auto; }
.arena-side.is-foe .combatant-head { flex-direction: row-reverse; text-align: right; }
.arena-side .combatant-school { display: none; }
/* Состояния («Открылся», «Пробуждение») — плашкой на нижнем краю портрета:
   в строке с именем они обрезали его до «Чои Чхан…» на узком экране. */
.arena-side .combatant-tags { position: absolute; bottom: calc(100% + 10px); left: 4px; right: 4px; z-index: 6;
  display: flex; gap: 3px; flex-wrap: wrap; pointer-events: none; }
.arena-side.is-foe .combatant-tags { justify-content: flex-end; }
.arena-side .combatant-tags .tag { background: rgba(4, 10, 16, 0.85); font-size: 10px; padding: 1px 5px; }
.arena-side .combatant-tags:empty { display: none; }
.arena-side .meter { height: 16px; }
.arena-side .meter-sta { height: 12px; }
.arena-side .meter-text { font-size: 11px; }
.arena-side .aura-marks { position: absolute; top: 4px; left: 4px; z-index: 2; }
.arena-side.is-foe .aura-marks { left: auto; right: 4px; }
.arena-side .pop { top: -28px; font-size: 24px; right: 50%; translate: 50% 0; }
.fight-arena .scene-mid { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; padding: 0 2px; }
.fight-arena .scene-round { font-size: 9px; letter-spacing: 0.25em; color: var(--sys); text-shadow: 0 0 6px var(--sys); }
.fight-arena .scene-num { font-size: 30px; line-height: 1; color: #effffe; text-shadow: 0 0 10px var(--sys), 0 0 24px rgba(79, 227, 216, 0.6); }
.fight-arena .scene-vs { font-style: normal; font-weight: 900; font-size: 16px; letter-spacing: 0.08em; color: var(--blood);
  text-shadow: 0 0 10px rgba(255, 77, 77, 0.8); margin-top: 4px; }
.fight-arena .rec { font-size: 9px; color: var(--blood); letter-spacing: 0.1em; }

/* Лог: верх гаснет, а не режется; первая строка раунда — ярче. */
#fight .fight-log {
  padding-top: 14px;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 14px);
  mask-image: linear-gradient(180deg, transparent 0, #000 14px);
}
#fight .fight-log .log-line { border-radius: 2px; }
#fight .fight-log .log-line.from-you { background: linear-gradient(90deg, rgba(79, 227, 216, 0.1), transparent); }
#fight .fight-log .log-line.from-foe { background: linear-gradient(270deg, rgba(255, 77, 77, 0.1), transparent); }
#fight .fight-log .legend { display: flex; gap: 8px; align-items: flex-start; padding: 4px 8px; background: rgba(79, 227, 216, 0.05);
  border-left: 2px solid rgba(79, 227, 216, 0.5); }
#fight .fight-log .legend-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
#fight .fight-log .legend-grid .legend { font-size: 12px; line-height: 1.3; padding: 5px 7px; }
#fight .fight-log .legend .ic { color: var(--sys); flex: 0 0 auto; margin-top: 2px; filter: drop-shadow(0 0 4px var(--sys)); }
#fight > .hint { display: flex; gap: 8px; align-items: center; justify-content: center; color: var(--sys);
  text-shadow: 0 0 8px rgba(79, 227, 216, 0.5); }
#fight > .hint .ic { flex: 0 0 auto; }

/* Кнопки хода: значок над словом, цена мелко. */
#fight .btn-act .act-name { display: inline-flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 800; }
#fight .btn-act .act-name .ic { width: 17px; height: 17px; }
#fight .btn-act .act-sub { font-size: 10px; }
/* Фильтры руки — одной строкой, листаются пальцем. */
#fight .fight-kinds { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; gap: 6px; }
#fight .fight-kinds::-webkit-scrollbar { display: none; }
#fight .fight-kinds .chip { flex: 0 0 auto; }
/* Выход — тихая строка, не два больших блока. */
#fight .fight-exit .btn { min-height: 36px; font-size: 12px; }
/* Веер: верхняя карта светится. */
#fight .fan-card.is-top { box-shadow: 0 0 18px rgba(79, 227, 216, 0.55), 0 0 0 1px var(--sys); }

@media (max-height: 680px) {
  #fight .fight-arena { min-height: 118px; padding: 6px 10px; gap: 6px; }
  .arena-side .meter { height: 14px; }
  .fight-arena .scene-num { font-size: 24px; }
  /* Панель удара ниже — целиком влезает в низкий лог, цифра видна. */
  #fight .panel-hit { height: 60px; margin: 2px 0 4px; }
  #fight .panel-hit .ph-num { font-size: 27px; }
  #fight .panel-hit .ph-burst { width: 70px; height: 70px; }
}
@media (prefers-reduced-motion: no-preference) {
  html:not([data-fx="off"]) #fight.fight-enter .is-you { animation: fight-from-left 0.55s cubic-bezier(0.2, 0.9, 0.25, 1) 0.35s both; }
  html:not([data-fx="off"]) #fight.fight-enter .is-foe { animation: fight-from-right 0.55s cubic-bezier(0.2, 0.9, 0.25, 1) 0.45s both; }
  html:not([data-fx="off"]) #fight.fight-enter .scene-mid { animation: sys-burst 0.7s cubic-bezier(0.2, 0.9, 0.25, 1.4) 0.6s both; }
}

/* ===== Удары на портретах (17.10.2026) =====
   Выпад атакующего, вспышка, искры и нарисованный звук по цели; крит —
   золотом и крупнее, блок — щит, промах — уход в сторону, нокдаун — падение.
   Только transform/opacity; при reduced-motion и «без эффектов» скрипт их
   не создаёт вовсе. */
.hit-fx { position: absolute; inset: 0; z-index: 3; pointer-events: none; display: grid; place-items: center; color: #fff; }
.hit-fx > * { grid-area: 1 / 1; }
.hf-flash { position: absolute; inset: 0;
  background: radial-gradient(circle at 50% 45%, rgba(255, 255, 255, 0.85), rgba(255, 77, 77, 0.45) 40%, transparent 72%);
  animation: hf-flash 0.32s ease-out both; }
.hit-crit .hf-flash { background: radial-gradient(circle at 50% 45%, #fff, rgba(240, 195, 90, 0.75) 36%, transparent 74%); }
.hit-block .hf-flash { background: radial-gradient(circle, rgba(79, 227, 216, 0.55), transparent 70%); }
.hit-heal .hf-flash { background: radial-gradient(circle, rgba(91, 217, 138, 0.5), transparent 70%); }
.hit-power .hf-flash { background: radial-gradient(circle, rgba(240, 195, 90, 0.55), transparent 70%); }
.hit-miss .hf-flash { display: none; }
@keyframes hf-flash { 0% { opacity: 0; } 15% { opacity: 1; } 100% { opacity: 0; } }

.hf-burst { width: 72%; max-width: 120px; filter: drop-shadow(0 0 8px var(--blood)); animation: hf-burst 0.45s cubic-bezier(0.2, 0.9, 0.3, 1) both; }
.hit-fx.is-big .hf-burst { width: 84%; max-width: 140px; }
.hit-crit .hf-burst { color: #ffe6a0; filter: drop-shadow(0 0 12px #f0c35a); }
.hit-down .hf-burst { color: #ffd0d0; }
@keyframes hf-burst { 0% { transform: scale(0.2) rotate(-20deg); opacity: 1; } 60% { opacity: 0.9; } 100% { transform: scale(1.15) rotate(8deg); opacity: 0; } }

.hf-spark { position: absolute; left: 50%; top: 46%; width: 3px; height: 12px; margin: -6px 0 0 -1.5px; border-radius: 2px;
  background: #fff; box-shadow: 0 0 6px #ffb199, 0 0 10px var(--blood);
  transform: rotate(var(--a)); animation: hf-spark 0.5s ease-out both; }
.hit-crit .hf-spark { background: #fff3c4; box-shadow: 0 0 8px #f0c35a; }
.hf-spark.hf-deflect { background: #e6fffd; box-shadow: 0 0 6px #4FE3D8, 0 0 12px #4FE3D8; animation-delay: 0.1s; }
@keyframes hf-spark {
  0% { transform: rotate(var(--a)) translateY(0) scaleY(1.4); opacity: 1; }
  100% { transform: rotate(var(--a)) translateY(calc(-1 * var(--d))) scaleY(0.4); opacity: 0; }
}

.hf-slash { position: absolute; left: -10%; right: -10%; top: 50%; height: 3px;
  background: linear-gradient(90deg, transparent, #fff 30%, #ff9a9a 60%, transparent); box-shadow: 0 0 10px var(--blood);
  transform: rotate(-32deg) scaleX(0); animation: hf-slash 0.36s cubic-bezier(0.2, 0.9, 0.3, 1) both; }
.hf-slash-2 { --r: 28deg; animation-delay: 0.08s; }
@keyframes hf-slash {
  0% { transform: rotate(var(--r, -32deg)) scaleX(0); opacity: 1; }
  60% { transform: rotate(var(--r, -32deg)) scaleX(1); opacity: 1; }
  100% { transform: rotate(var(--r, -32deg)) scaleX(1); opacity: 0; }
}

/* Блок: шестигранный щит с сотами встаёт перед бойцом, от удара по нему
   идёт волна, искры отлетают вбок, щит мерцает и гаснет; крупный удар
   оставляет трещины. Сам боец отжимается назад. */
.hf-hex { width: 84%; max-width: 140px; overflow: visible; filter: drop-shadow(0 0 6px #4FE3D8);
  animation: hex-in 0.75s cubic-bezier(0.2, 0.9, 0.3, 1.4) both; }
.hf-hex .hex-edge { fill: none; stroke: #c9fffb; stroke-width: 2.6; }
.hf-hex .hex-cells polygon { fill: none; stroke: rgba(79, 227, 216, 0.6); stroke-width: 0.9; }
.hf-hex .hf-crack { fill: none; stroke: #fff; stroke-width: 1.8; stroke-linecap: round;
  stroke-dasharray: 90; stroke-dashoffset: 90; animation: crack-draw 0.22s 0.12s ease-out forwards; }
@keyframes crack-draw { to { stroke-dashoffset: 0; } }
@keyframes hex-in {
  0% { transform: scale(0.4); opacity: 0; }
  20% { transform: scale(1.08); opacity: 1; }
  32% { transform: scale(0.96); }
  44% { transform: scale(1); }
  66% { opacity: 1; } 72% { opacity: 0.35; } 78% { opacity: 0.95; } 84% { opacity: 0.5; }
  100% { transform: scale(1.06); opacity: 0; }
}
.hit-fx.is-big .hf-hex { animation-duration: 0.85s; }
.hf-ripple { width: 30%; aspect-ratio: 1; border-radius: 50%; border: 2px solid #dffffb; box-shadow: 0 0 12px #4FE3D8, inset 0 0 8px #4FE3D8;
  animation: hf-ripple 0.55s 0.1s ease-out both; }
@keyframes hf-ripple { 0% { transform: scale(0.2); opacity: 1; } 100% { transform: scale(3.2); opacity: 0; } }
.hit-block .hf-word { top: auto; bottom: 14%; }
.arena-side .fighter-you.is-guard .fig-main { animation: guard-l 0.45s ease-out; }
.arena-side .fighter-foe.is-guard .fig-main { animation: guard-r 0.45s ease-out; }
@keyframes guard-l { 25% { translate: -8px 0; } }
@keyframes guard-r { 25% { translate: 8px 0; } }
.arena-side .fighter.is-guard { border-color: #4FE3D8; }

.hf-rise { position: absolute; inset: 0; background: linear-gradient(0deg, rgba(91, 217, 138, 0.45), transparent 70%); animation: hf-rise 0.7s ease-out both; }
.hit-power .hf-rise { background: linear-gradient(0deg, rgba(240, 195, 90, 0.5), transparent 70%); }
@keyframes hf-rise { 0% { opacity: 0; transform: translateY(30%); } 40% { opacity: 1; } 100% { opacity: 0; transform: translateY(-20%); } }

.hf-word { position: absolute; top: 10%; left: 11%; z-index: 2; font-family: var(--font-display); font-weight: 900; font-size: 19px;
  letter-spacing: 0.04em; color: #fff; -webkit-text-stroke: 1px rgba(0, 0, 0, 0.55);
  text-shadow: 0 0 10px var(--blood), 2px 2px 0 #000; rotate: -10deg; animation: hf-word 0.85s cubic-bezier(0.2, 0.9, 0.3, 1.3) both; }
.hf-word.on-foe { left: auto; right: 11%; rotate: 10deg; }
.hit-crit .hf-word { font-size: 27px; color: #ffe6a0; text-shadow: 0 0 14px #f0c35a, 2px 2px 0 #000; }
.hit-block .hf-word { color: #c9fffb; text-shadow: 0 0 10px var(--sys), 2px 2px 0 #000; }
.hit-miss .hf-word { color: #e6eef2; text-shadow: 0 0 8px rgba(255, 255, 255, 0.5), 2px 2px 0 #000; }
.hit-heal .hf-word { color: #c8ffd9; text-shadow: 0 0 10px var(--good), 2px 2px 0 #000; }
.hit-power .hf-word { font-size: 16px; color: #ffe6a0; text-shadow: 0 0 12px #f0c35a, 2px 2px 0 #000; }
.hit-down .hf-word { font-size: 24px; }
@keyframes hf-word { 0% { scale: 2.2; opacity: 0; } 18% { scale: 0.9; opacity: 1; } 30% { scale: 1; } 80% { opacity: 1; } 100% { opacity: 0; translate: 0 -8px; } }

/* Выпад: рамка атакующего бросается к центру. */
.arena-side .fighter.is-lunge { z-index: 4; }
.arena-side .fighter-you.is-lunge { animation: lunge-r 0.3s cubic-bezier(0.3, 0, 0.2, 1); }
.arena-side .fighter-foe.is-lunge { animation: lunge-l 0.3s cubic-bezier(0.3, 0, 0.2, 1); }
@keyframes lunge-r { 40% { translate: 16px -3px; scale: 1.06; } }
@keyframes lunge-l { 40% { translate: -16px -3px; scale: 1.06; } }
/* Уход от удара, падение. */
.arena-side .fighter.is-dodge .fig-main { animation: fig-dodge 0.6s ease-out; }
.arena-side .fighter-foe.is-dodge .fig-main { animation-name: fig-dodge-l; }
@keyframes fig-dodge { 30%, 55% { translate: 24% 0; opacity: 0.35; } }
@keyframes fig-dodge-l { 30%, 55% { translate: -24% 0; opacity: 0.35; } }
.arena-side .fighter.is-down .fig-main { animation: fig-down 1.1s ease-in both; }
@keyframes fig-down { 35% { translate: 0 14%; rotate: 7deg; opacity: 0.6; } 100% { translate: 0 22%; rotate: 9deg; opacity: 0.45; } }
/* Сила / лечение — рамка вспыхивает своим цветом. */
.arena-side .fighter.is-heal { border-color: var(--good); }
.arena-side .fighter.is-power { border-color: #f0c35a; }
/* Крупный удар: арена вздрагивает и вспыхивает. */
#fight-scene.is-impact { animation: arena-impact 0.36s linear; }
@keyframes arena-impact { 12% { translate: -5px 2px; } 30% { translate: 5px -2px; } 50% { translate: -3px 1px; } 70% { translate: 2px 0; } }
#fight-scene.is-impact .scene-fx { background: radial-gradient(circle at 50% 40%, rgba(255, 255, 255, 0.35), transparent 70%); animation: hf-flash 0.36s ease-out both; }

/* Живой портрет: лёгкое дыхание (только в полном режиме). */
html[data-fx="full"] .arena-side .fighter:not(.is-hit):not(.is-dodge):not(.is-down):not(.is-guard) .fig-main { animation: fig-breathe 3.2s ease-in-out infinite; }
html[data-fx="full"] .arena-side.is-foe .fighter:not(.is-hit):not(.is-dodge):not(.is-down):not(.is-guard) .fig-main { animation-delay: -1.6s; }
@keyframes fig-breathe { 50% { translate: 0 -2px; } }
/* На краю — рамка пульсирует красным. */
.arena-side .fighter.is-hurt::before { content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  box-shadow: inset 0 0 22px rgba(255, 77, 77, 0.75); animation: hurt-pulse 1.2s ease-in-out infinite; }
@keyframes hurt-pulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }
/* Число урона крупнее и с обводкой — его видно поверх портрета. */
.arena-side .fighter .pop { top: 40%; left: 50%; right: auto; font-size: 30px; z-index: 6;
  animation: pop-up-c 1.1s ease-out 0.14s both; }
@keyframes pop-up-c {
  0% { opacity: 0; translate: -50% 8px; scale: 0.6; }
  12% { opacity: 1; translate: -50% -2px; scale: 1.25; }
  24% { opacity: 1; translate: -50% -4px; scale: 1; }
  72% { opacity: 1; translate: -50% -16px; scale: 1; }
  100% { opacity: 0; translate: -50% -34px; scale: 1; }
}

.arena-side .fighter .pop { color: #fff; -webkit-text-stroke: 1.5px #9b1020;
  text-shadow: 0 0 14px rgba(255, 77, 77, 0.95), 3px 3px 0 #000; }
.arena-side .fighter .pop.heal { -webkit-text-stroke-color: #0f6b3a; text-shadow: 0 0 14px rgba(91, 217, 138, 0.95), 3px 3px 0 #000; }
.arena-side .fighter .pop.is-big { font-size: 40px; color: #fff3c4; -webkit-text-stroke-color: #8a5a00;
  text-shadow: 0 0 16px rgba(240, 195, 90, 0.95), 3px 3px 0 #000; }
.arena-side .pop { z-index: 5; -webkit-text-stroke: 1px rgba(0, 0, 0, 0.5); text-shadow: 0 0 12px rgba(255, 77, 77, 0.8), 2px 2px 0 #000; }
@media (prefers-reduced-motion: reduce) {
  .arena-side .fighter.is-hurt::before { animation: none; opacity: 0.7; }
  html[data-fx="full"] .arena-side .fighter .fig-main { animation: none !important; }
}

/* ===== Розыгрыш карт и приёмов (17.10.2026) =====
   Карта выходит со стороны того, кто её сыграл, переворачивается лицом,
   вокруг — лучи цвета редкости и плашка с именем. Приём улетает в
   противника, остальные карты уходят обратно в того, кто их сыграл. */
.cast { position: absolute; inset: 0; z-index: 7; pointer-events: none; display: grid; place-items: center;
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
  perspective: 600px; overflow: hidden; }
.cast > * { grid-area: 1 / 1; }
.cast::before { content: ""; position: absolute; inset: 0; background: rgba(2, 8, 12, 0.55); animation: cast-dim 1.1s ease-out both; }
@keyframes cast-dim { 0% { opacity: 0; } 18%, 70% { opacity: 1; } 100% { opacity: 0; } }
.cast-you { --from: -140px; }
.cast-foe { --from: 140px; }
.cast-you.is-attack { --to: 150px; }
.cast-foe.is-attack { --to: -150px; }
.cast-you.is-buff { --to: -130px; }
.cast-foe.is-buff { --to: 130px; }
.cast-rays { width: 170%; aspect-ratio: 1; border-radius: 50%;
  background: repeating-conic-gradient(from 0deg, var(--cast) 0 5deg, transparent 5deg 20deg);
  -webkit-mask-image: radial-gradient(circle, #000 12%, transparent 62%); mask-image: radial-gradient(circle, #000 12%, transparent 62%);
  animation: cast-rays 1.1s ease-out both; }
@keyframes cast-rays { 0% { opacity: 0; transform: rotate(0deg) scale(0.6); } 25% { opacity: 0.55; } 70% { opacity: 0.45; } 100% { opacity: 0; transform: rotate(50deg) scale(1.1); } }
.cast-card { position: relative; height: 72%; width: auto; max-width: 46%; aspect-ratio: 3 / 4.2; border: 2px solid var(--cast); border-radius: 6px; overflow: hidden;
  background: #071219; box-shadow: 0 0 22px var(--cast), 0 0 2px #fff; animation: cast-card 1.1s cubic-bezier(0.25, 0.8, 0.3, 1) both; }
.cast-card img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cast-card::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, 0.55) 50%, transparent 65%);
  transform: translateX(-120%); animation: cast-shine 1.1s ease-out both; }
@keyframes cast-shine { 0%, 28% { transform: translateX(-120%); } 55%, 100% { transform: translateX(120%); } }
@keyframes cast-card {
  0% { transform: translateX(var(--from)) translateY(24px) rotateY(90deg) scale(0.5); opacity: 0; }
  26% { transform: translateX(0) translateY(0) rotateY(0deg) scale(1.08); opacity: 1; }
  36% { transform: translateX(0) translateY(0) rotateY(0deg) scale(1); opacity: 1; }
  68% { transform: translateX(0) translateY(-3px) rotateY(0deg) scale(1); opacity: 1; }
  100% { transform: translateX(var(--to)) translateY(0) rotateY(0deg) scale(0.35); opacity: 0; }
}
.cast-name { align-self: end; margin-bottom: 8px; z-index: 1; text-align: center; padding: 3px 28px; max-width: 92%;
  background: linear-gradient(90deg, transparent, rgba(2, 8, 12, 0.92) 14%, rgba(2, 8, 12, 0.92) 86%, transparent);
  border-top: 1px solid var(--cast); border-bottom: 1px solid var(--cast);
  animation: cast-name 1.1s ease-out both; }
.cast-name small { display: block; font-family: var(--font-data); font-size: 9px; letter-spacing: 0.22em; text-transform: uppercase; color: var(--cast); }
.cast-name b { display: block; font-family: var(--font-display); font-weight: 900; font-size: 15px; color: #fff; line-height: 1.15;
  text-shadow: 0 0 10px var(--cast); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@keyframes cast-name { 0%, 14% { clip-path: inset(0 50% 0 50%); opacity: 0; } 30% { clip-path: inset(0 0 0 0); opacity: 1; } 78% { opacity: 1; } 100% { clip-path: inset(0 0 0 0); opacity: 0; } }
/* Тот, кто сыграл, вспыхивает цветом карты. */
.arena-side .fighter.is-casting { border-color: var(--cast); box-shadow: 0 0 22px var(--cast), inset 0 0 26px var(--cast); }

/* Имя приёма без карты — косой полосой через арену. */
.tech-banner { position: absolute; left: -12%; right: -12%; top: 38%; z-index: 7; pointer-events: none; text-align: center; padding: 6px 0;
  --c: #4FE3D8; rotate: -6deg; border-top: 1px solid var(--c); border-bottom: 1px solid var(--c);
  background: linear-gradient(90deg, transparent, rgba(2, 8, 12, 0.92) 14%, rgba(2, 8, 12, 0.92) 86%, transparent);
  animation: tech-in 0.9s cubic-bezier(0.2, 0.9, 0.3, 1) both; }
.tech-foe { --c: #FF4D4D; rotate: 6deg; }
.tech-banner b { font-family: var(--font-display); font-weight: 900; font-size: 20px; letter-spacing: 0.06em; color: #fff;
  text-shadow: 0 0 12px var(--c), 2px 2px 0 #000; }
@keyframes tech-in { 0% { translate: -60% 0; opacity: 0; } 22% { translate: 0 0; opacity: 1; } 75% { translate: 4% 0; opacity: 1; } 100% { translate: 30% 0; opacity: 0; } }
.tech-foe { animation-name: tech-in-r; }
@keyframes tech-in-r { 0% { translate: 60% 0; opacity: 0; } 22% { translate: 0 0; opacity: 1; } 75% { translate: -4% 0; opacity: 1; } 100% { translate: -30% 0; opacity: 0; } }

/* ===== Победа и поражение (17.10.2026) =====
   Заставка на весь экран боя перед окном итога, затем полоска дуэли. */
.fight-duel { flex: 0 0 auto; display: flex; align-items: center; gap: 10px; padding: 12px 14px 4px; }
.duel-side { flex: 1 1 0; min-width: 0; display: flex; align-items: center; gap: 8px; }
.duel-foe { flex-direction: row-reverse; text-align: right; }
.duel-side b { font-family: var(--font-display); font-size: 12px; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.duel-face { position: relative; flex: 0 0 auto; width: 50px; aspect-ratio: 0.86; overflow: hidden; border: 1px solid rgba(79, 227, 216, 0.6); background: #071219; }
.duel-face img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 15%; display: block; }
.duel-foe .duel-face img { transform: scaleX(-1); }
.duel-side.is-loser .duel-face img { filter: grayscale(1) brightness(0.55); }
.duel-side.is-loser .duel-face::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(45deg, transparent 46%, #FF4D4D 46% 54%, transparent 54%), linear-gradient(-45deg, transparent 46%, #FF4D4D 46% 54%, transparent 54%);
  opacity: 0.85; }
.duel-side.is-loser b { color: var(--ink-dim); }
.duel-side.is-winner .duel-face { border-color: var(--gold); box-shadow: 0 0 14px rgba(255, 198, 92, 0.6); }
.duel-mid { flex: 0 0 auto; display: grid; justify-items: center; font-size: 18px; font-weight: 900; letter-spacing: 0.08em; color: #effffe; }
.duel-mid small { font-size: 9px; letter-spacing: 0.2em; color: var(--ink-faint); font-weight: 400; text-transform: uppercase; }
.fight-duel.is-won .duel-mid, .fight-duel.is-await .duel-mid { color: #fff3c4; text-shadow: 0 0 10px var(--gold); }
.fight-duel.is-lost .duel-mid { color: #ffd0d0; text-shadow: 0 0 10px var(--blood); }
.fight-duel.is-fled .duel-mid { color: #c9fffb; text-shadow: 0 0 10px var(--sys); }
#fight .fight-result.after-finale { animation: none !important; opacity: 0; }

#fight > .finale, .finale { position: absolute; inset: 0; z-index: 60; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; overflow: hidden; cursor: pointer; background: rgba(2, 6, 10, 0.95); animation: fn-fade-in 0.3s ease-out both; }
.finale { --fn: rgba(255, 77, 77, 0.5); --fc: #FF4D4D; }
.finale.is-out { animation: fn-out 0.45s ease-in forwards; }
@keyframes fn-out { to { opacity: 0; visibility: hidden; } }
@keyframes fn-fade-in { from { opacity: 0; } }
.fn-won, .fn-await { --fn: rgba(255, 198, 92, 0.5); --fc: #FFC65C; }
.fn-fled { --fn: rgba(79, 227, 216, 0.4); --fc: #4FE3D8; }
.fn-glow { position: absolute; inset: -20%; background: radial-gradient(45% 35% at 50% 42%, var(--fn), transparent 70%); animation: fn-glow 2.6s ease-out both; }
@keyframes fn-glow { 0% { opacity: 0; } 30% { opacity: 1; } 34% { opacity: 1.6; } 100% { opacity: 0.8; } }
.fn-rays { position: absolute; left: 50%; top: 40%; width: 180vmax; height: 180vmax; margin: -90vmax 0 0 -90vmax;
  background: repeating-conic-gradient(rgba(255, 198, 92, 0.2) 0 6deg, transparent 6deg 18deg);
  -webkit-mask-image: radial-gradient(circle, #000 5%, transparent 40%); mask-image: radial-gradient(circle, #000 5%, transparent 40%);
  animation: fn-spin 10s linear infinite; }
@keyframes fn-spin { to { transform: rotate(360deg); } }
.fn-figs { position: relative; z-index: 1; display: flex; align-items: center; gap: 12px; }
.fn-fig { position: relative; width: 34vw; max-width: 150px; aspect-ratio: 0.86; overflow: hidden; border: 2px solid var(--fc);
  background: #071219; box-shadow: 0 0 22px var(--fn); }
.fn-fig img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 15%; display: block; }
.fn-foe img { transform: scaleX(-1); }
.fn-you { animation: fight-from-left 0.5s cubic-bezier(0.2, 0.9, 0.25, 1) both; }
.fn-foe { animation: fight-from-right 0.5s cubic-bezier(0.2, 0.9, 0.25, 1) both; }
.fn-fig.is-loser { border-color: #7a2a2a; box-shadow: none; }
.fn-fig.is-loser img { animation: fn-fall 0.9s 0.7s ease-in forwards; }
@keyframes fn-fall { 30% { translate: 0 5%; rotate: 4deg; } 100% { translate: 0 16%; rotate: 9deg; opacity: 0.5; } }
.fn-fig.is-loser::before { content: ""; position: absolute; inset: 0; z-index: 1; background: linear-gradient(180deg, rgba(40, 0, 0, 0.25), rgba(10, 0, 0, 0.8));
  opacity: 0; animation: fn-show 0.5s 0.8s forwards; }
.fn-fig.is-winner img { animation: fn-rise 0.7s 0.7s cubic-bezier(0.2, 0.9, 0.3, 1.3) forwards; }
@keyframes fn-rise { to { scale: 1.07; } }
.fn-fig.is-winner::after { content: ""; position: absolute; inset: 0; box-shadow: inset 0 0 30px var(--fc); opacity: 0; animation: fn-show 0.5s 0.7s forwards; }
@keyframes fn-show { to { opacity: 1; } }
.fn-ko { position: absolute; left: 50%; top: 50%; z-index: 2; font-family: var(--font-display); font-size: 34px; font-weight: 900; color: #fff;
  -webkit-text-stroke: 2px #9b1020; text-shadow: 0 0 18px #FF4D4D, 3px 3px 0 #000; translate: -50% -50%; rotate: -14deg;
  animation: fn-ko 0.45s 0.75s cubic-bezier(0.2, 0.9, 0.3, 1.4) both; }
@keyframes fn-ko { 0% { scale: 3.5; opacity: 0; } 60% { scale: 0.9; opacity: 1; } 100% { scale: 1; opacity: 1; } }
.fn-vs { font-style: normal; font-weight: 900; font-size: 18px; color: var(--fc); text-shadow: 0 0 10px var(--fc); animation: fn-fade-in 0.3s 0.3s both; }
.fn-won .fn-figs, .fn-lost .fn-figs, .fn-died .fn-figs, .fn-await .fn-figs { animation: arena-impact 0.36s 0.75s linear; }
.fn-title { position: relative; z-index: 1; margin: 8px 0 0; display: flex; font-family: var(--font-display); font-weight: 900;
  font-size: clamp(28px, 10vw, 46px); letter-spacing: 0.12em; line-height: 1; }
.fn-title span { display: inline-block; color: #fff; text-shadow: 0 0 14px var(--fc), 0 0 40px var(--fc);
  animation: fn-letter 0.5s calc(0.9s + var(--i) * 0.06s) cubic-bezier(0.2, 0.9, 0.3, 1.4) both; }
.fn-won .fn-title span, .fn-await .fn-title span { color: #fff3c4; }
@keyframes fn-letter { 0% { opacity: 0; translate: 0 -30px; scale: 1.8; } 100% { opacity: 1; translate: 0 0; scale: 1; } }
.fn-lost .fn-title span, .fn-died .fn-title span { color: #ffe0e0; animation-name: fn-letter-drop; }
@keyframes fn-letter-drop { 0% { opacity: 0; translate: 0 -12px; } 60% { opacity: 1; translate: 0 5px; } 100% { opacity: 1; translate: 0 0; } }
.fn-lost .fn-title, .fn-died .fn-title { animation: fn-glitch 0.3s 1.7s steps(2) 2; }
@keyframes fn-glitch { 50% { translate: 4px 0; opacity: 0.7; } }
.fn-sub { position: relative; z-index: 1; margin: 0; color: var(--fc); font-family: var(--font-data); font-size: 12px; letter-spacing: 0.2em;
  text-transform: uppercase; animation: fn-fade-in 0.5s 1.4s both; }
.fn-skip { position: absolute; bottom: 18px; margin: 0; opacity: 0.45; animation: fn-fade-in 0.5s 1.4s both; }
.fn-parts { position: absolute; inset: 0; pointer-events: none; }
.fn-p { position: absolute; left: var(--x); bottom: -12px; width: 4px; height: 10px; border-radius: 2px; background: #ffe6a0;
  box-shadow: 0 0 8px #FFC65C; opacity: 0; animation: fn-p-up 1.7s calc(0.8s + var(--t) * 0.6) ease-out infinite; }
@keyframes fn-p-up { 0% { opacity: 0; transform: translateY(0) rotate(var(--r)); } 15% { opacity: 1; }
  100% { opacity: 0; transform: translateY(calc(-1 * var(--d) - 240px)) rotate(var(--r)); } }
.fn-lost .fn-p, .fn-died .fn-p { top: -12px; bottom: auto; width: 7px; height: 7px; border-radius: 0; background: #ff6b6b; box-shadow: 0 0 6px #FF4D4D;
  clip-path: polygon(50% 0, 100% 60%, 30% 100%); animation-name: fn-p-down; }
@keyframes fn-p-down { 0% { opacity: 0; transform: translateY(0) rotate(0deg); } 15% { opacity: 0.9; }
  100% { opacity: 0; transform: translateY(calc(var(--d) + 320px)) rotate(var(--r)); } }
.fn-cracks { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.fn-cracks path { fill: none; stroke: rgba(255, 140, 140, 0.85); stroke-width: 0.5; stroke-linejoin: round;
  stroke-dasharray: 1; stroke-dashoffset: 1; filter: drop-shadow(0 0 3px #FF4D4D); animation: crack-draw 0.35s 0.75s ease-out forwards; }
.fn-speed { position: absolute; inset: 0; width: 100%; height: 100%; color: #4FE3D8; opacity: 0.45; animation: fn-speed 0.45s linear infinite; }
@keyframes fn-speed { from { translate: 30% 0; } to { translate: -30% 0; } }
.fn-fled .fn-you img { animation: fn-flee 0.7s 0.6s ease-in forwards; }
@keyframes fn-flee { to { translate: -130% 0; opacity: 0; } }
