/* Атмосферный слой: арт, глубина, акценты, микродвижение.

   Подключается последним и правит не разметку, а «громкость» интерфейса.
   Правило пропорции: примерно 80% спокойного тёмного UI, 15% атмосферного
   арта и 5% по-настоящему ярких акцентов. До этого слоя все элементы звучали
   одинаково громко — панель, плитка и кнопка отличались только текстом.

   Три плана глубины:
     фон      — почти чёрный, арт под сильным размытием;
     панели   — стекло со светлой кромкой сверху и мягкой тенью снизу;
     действия — единственные насыщенные пятна цвета (CTA, значки, орб маны).

   Движение намеренно редкое: медленный наплыв портрета, редкие искры у
   героини и блик по главной кнопке. Всё остальное статично, иначе экран
   начинает мельтешить. */

/* ---------------- 1. Героиня как центр композиции ---------------- */

/* Свечение стихии из-под портрета: холодная стеклянная панель сама по себе
   не даёт понять, что героиня — главное на экране. */
.char-panel {
  position: relative;
  /* Сцена стихии во всю ширину панели (art/banner_*.webp): портрет
     растворяется прямо в ней, и кадр читается как один рисунок, а не как
     «картинка слева, стекло справа». Вуаль у каждой стихии своя — синий и
     зелёный баннеры вышли светлее огненного и глушат текст. */
  --banner-veil: rgba(6, 6, 8, 0.5);
  background:
    radial-gradient(70% 120% at 12% 50%, color-mix(in srgb, var(--accent, #0a84ff) 20%, transparent), transparent 65%),
    /* Тёмная подложка под левой половиной: портрет должен растворяться
       в темноте, иначе на месте, где маска доходит до нуля, видно ступеньку
       яркости — стекло панели светлее самого арта. */
    linear-gradient(90deg, rgba(0, 0, 0, 0.45) 0 38%, rgba(0, 0, 0, 0.15) 62%, transparent 82%),
    linear-gradient(180deg, var(--banner-veil), var(--banner-veil)),
    var(--banner, linear-gradient(transparent, transparent)) center / cover no-repeat,
    linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.015));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.1),
    0 18px 40px -18px rgba(0, 0, 0, 0.95);
}

.char-panel.elem-fire   { --banner: url('art/banner_fire.webp');   --banner-veil: rgba(6, 6, 8, 0.34); }
.char-panel.elem-water  { --banner: url('art/banner_water.webp');  --banner-veil: rgba(4, 8, 14, 0.7); }
.char-panel.elem-nature { --banner: url('art/banner_nature.webp'); --banner-veil: rgba(4, 10, 8, 0.68); }
.char-panel.elem-light  { --banner: url('art/banner_light.webp');  --banner-veil: rgba(8, 6, 4, 0.6); }
.char-panel.elem-dark   { --banner: url('art/banner_dark.webp');   --banner-veil: rgba(6, 4, 10, 0.5); }

/* Портрет перестаёт обрываться вертикальной границей: колонка арта заходит
   под текст, а её правый край растворяется маской. Текст лежит выше и стоит
   уже на прозрачной части, поэтому читаемость не страдает. */
.char-panel-inner { grid-template-columns: minmax(190px, 42%) 1fr; }
.char-art { position: relative; z-index: 0; margin-right: -13%; }
.char-art-inner { position: relative; }
.char-info { position: relative; z-index: 1; }
.char-portrait {
  -webkit-mask-image: linear-gradient(90deg, #000 0 46%, rgba(0, 0, 0, 0.5) 72%, transparent 96%);
  mask-image: linear-gradient(90deg, #000 0 46%, rgba(0, 0, 0, 0.5) 72%, transparent 96%);
}
.char-portrait img {
  transform-origin: 40% 30%;
  animation: art-drift 26s ease-in-out infinite alternate;
}

/* Правая половина панели прозрачнее: фон ей больше не нужен, его роль
   взяло свечение стихии. */
.char-info.parchment {
  background: none;
  padding: 24px 26px 24px 10px;
  gap: 10px;
}

/* Способность — настоящий skill-chip: знак стихии, название, стоимость. */
.ability-plate {
  gap: 12px;
  padding: 8px 8px 8px 8px;
  border-radius: 16px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));
  border: 1px solid color-mix(in srgb, var(--accent, #0a84ff) 28%, var(--hairline, rgba(255, 255, 255, 0.1)));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 10px 24px -14px color-mix(in srgb, var(--accent, #0a84ff) 80%, transparent);
}
.ability-icon {
  flex: 0 0 auto;
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: 12px;
  background:
    radial-gradient(80% 80% at 50% 120%, color-mix(in srgb, var(--accent, #0a84ff) 75%, transparent), transparent 70%),
    color-mix(in srgb, var(--accent, #0a84ff) 22%, transparent);
  color: #fff;
  font-size: 17px; font-weight: 600;
  text-shadow: 0 0 12px color-mix(in srgb, var(--accent, #0a84ff) 90%, transparent);
}
.ability-text { display: flex; flex-direction: column; gap: 1px; line-height: 1.25; }
.ability-text b { font-size: var(--fs-15, 15px); font-weight: 700; }
.ability-desc { font-size: var(--fs-13, 13px); color: var(--text-2, #a8a8ad); }
.ability-cost {
  flex: 0 0 auto;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-width: 46px; height: 38px;
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.32);
  border: 1px solid var(--hairline, rgba(255, 255, 255, 0.1));
  font-size: var(--fs-15, 15px); font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: #64d2ff;
}
.ability-cost i {
  font-style: normal; font-size: 9px; font-weight: 600;
  letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--text-3, #7c7c82);
}

/* «Сменить госпожу» — служебное действие, а не второй призыв к действию. */
.char-info .fbtn-wood {
  align-self: flex-start;
  background: transparent;
  border-color: var(--hairline, rgba(255, 255, 255, 0.1));
  color: var(--text-2, #a8a8ad);
  height: var(--btn-h-sm, 34px);
  font-size: var(--fs-13, 13px);
}
.char-info .fbtn-wood:hover { background: var(--surface-1, rgba(255, 255, 255, 0.055)); color: var(--text-1, #f5f5f7); }

/* На высоком широком экране героине отдаётся больше места: дорогой арт в
   полоске 230 px не работает. Порог по высоте тот же, что у «компактного»
   правила в styles-menu.css, иначе меню перестаёт помещаться без прокрутки. */
@media (min-width: 860px) and (min-height: 951px) {
  .char-portrait { min-height: 340px; }
  .char-info.parchment { padding: 28px 30px 28px 12px; }
}

/* Две колонки разделов только с 1040 px: на 900 px в колонку шириной 400
   переносятся и заголовок, и подпись, и заметка. */
@media (max-width: 1039px) {
  .menu-panel { display: flex; flex-direction: column; }
}

/* ---------------- 2. Плитки: свой воздух и своя атмосфера ---------------- */

.screen-menu { gap: 18px; }
.menu-panel { gap: 12px; }
.tile-body { padding: 16px 18px; }
.menu-tile-primary .tile-body { padding: 22px 20px; }

/* Панель второго плана: светлая кромка сверху, мягкая тень снизу. */
.menu-tile, .bottom-bar, .topbar-plate {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.02));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 14px 30px -16px rgba(0, 0, 0, 0.9);
}

/* Подложка режима видна примерно на 15%: она даёт настроение, но не спорит
   с текстом. Кампания — исключение, там портрет соперницы и он должен читаться. */
.tile-art { opacity: 0.44; background-position: center 45%; filter: saturate(1.45) contrast(1.08); }
.menu-tile:hover .tile-art { opacity: 0.58; }
.menu-tile-primary .tile-art { opacity: 0.5; background-position: center 22%; }
.tile-veil {
  background: linear-gradient(90deg, rgba(8, 8, 10, 0.96) 24%, rgba(8, 8, 10, 0.7) 54%, rgba(8, 8, 10, 0.24));
}
/* Зелёные фонари и золотые печати светлее прочих подложек — им отдельная мера:
   и меньше видимости, и сдвиг кадра, чтобы яркое пятно ушло под затемнение. */
.menu-tile-quests .tile-art, .menu-tile-summon .tile-art { opacity: 0.16; }
.menu-tile-quests .tile-art { background-position: 22% 60%; }
.menu-tile-summon .tile-art { background-position: 30% 55%; }
.menu-tile-quests:hover .tile-art, .menu-tile-summon:hover .tile-art { opacity: 0.26; }

/* Цвет режима: слабое пятно у иконки и подкрашенная рамка. */
.menu-tile::before {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  background:
    radial-gradient(55% 130% at 6% 50%, color-mix(in srgb, var(--tile-tint, transparent) 26%, transparent), transparent 70%),
    linear-gradient(90deg, transparent 45%, color-mix(in srgb, var(--tile-tint, transparent) 16%, transparent));
}
.menu-tile-campaign { --tile-tint: #64d2ff; }
.menu-tile-duel { --tile-tint: #bf5af2; }
.menu-tile-summon { --tile-tint: #f2c14e; }
.menu-tile-arena { --tile-tint: #ff6961; }
.menu-tile-quests { --tile-tint: #30d158; }
.menu-tile-collection { --tile-tint: #5ac8fa; }

.icon-tile {
  background: color-mix(in srgb, var(--tile-tint, #fff) 16%, rgba(255, 255, 255, 0.06));
  border-color: color-mix(in srgb, var(--tile-tint, #fff) 26%, transparent);
  box-shadow: 0 6px 16px -10px color-mix(in srgb, var(--tile-tint, #000) 90%, transparent);
}

/* Подъём при наведении — на 2 px, этого хватает, чтобы плитка ощущалась
   отдельным предметом. */
.menu-tile { transition: transform 0.16s cubic-bezier(0.2, 0.8, 0.3, 1), box-shadow 0.2s ease, background 0.2s ease; }
.menu-tile:hover {
  transform: translateY(-2px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    0 20px 36px -18px rgba(0, 0, 0, 0.95);
}
.menu-tile:active { transform: translateY(0) scale(0.995); }

/* ---------------- 3. Главное действие ---------------- */

/* Кнопка кампании — единственное по-настоящему яркое пятно на экране:
   градиент в цвет героини, кромка света сверху, окрашенная тень и редкий блик. */
.row-cta {
  height: var(--btn-h-lg, 50px);
  padding: 0 26px;
  border-radius: 14px;
  font-size: var(--fs-17, 17px); font-weight: 700;
  color: #fff;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--accent, #0a84ff) 78%, #fff) 0%,
      var(--accent, #0a84ff) 52%,
      color-mix(in srgb, var(--accent, #0a84ff) 86%, #000) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.4),
    0 2px 6px rgba(0, 0, 0, 0.4),
    0 14px 30px -10px color-mix(in srgb, var(--accent, #0a84ff) 75%, transparent);
  overflow: hidden;
}
.row-cta::after {
  content: '';
  position: absolute; top: 0; bottom: 0; left: -60%;
  width: 45%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.28), transparent);
  transform: skewX(-18deg);
  animation: cta-sheen 6.5s ease-in-out infinite;
}
.menu-tile-primary:hover .row-cta { filter: brightness(1.06); }

/* Остальные кнопки звучат тише главной. */
.bar-center .fbtn, .bottom-bar .fbtn-wood {
  background: rgba(255, 255, 255, 0.05);
  border-color: var(--hairline, rgba(255, 255, 255, 0.1));
  color: var(--text-2, #a8a8ad);
}
.bar-center .fbtn:hover, .bottom-bar .fbtn-wood:hover { color: var(--text-1, #f5f5f7); }

/* ---------------- 4. Движение ---------------- */

@keyframes art-drift {
  from { transform: scale(1.015) translate3d(0, 0, 0); }
  to   { transform: scale(1.07) translate3d(-1.2%, -1.6%, 0); }
}

@keyframes cta-sheen {
  0%, 62% { left: -60%; }
  92%, 100% { left: 120%; }
}

@media (prefers-reduced-motion: reduce) {
  .char-portrait img, .row-cta::after { animation: none; }
  .menu-tile:hover { transform: none; }
}

/* ---------------- 5. Мелкий экран ---------------- */

@media (max-width: 720px) {
  /* Маска мягче: колонка портрета узкая, и сильный градиент съедал лицо. */
  .char-portrait {
    -webkit-mask-image: linear-gradient(90deg, #000 0 74%, transparent 100%);
    mask-image: linear-gradient(90deg, #000 0 74%, transparent 100%);
  }
  .char-panel-inner { grid-template-columns: minmax(150px, 40%) 1fr; }
  .char-art { margin-right: -8%; }
  .char-info.parchment { padding: 18px 16px 18px 8px; }
  .ability-plate { gap: 10px; padding: 6px; }
  .ability-icon { width: 32px; height: 32px; font-size: 15px; }
  .ability-cost { min-width: 40px; height: 32px; }
  .row-cta { height: var(--btn-h-md, 42px); padding: 0 18px; font-size: var(--fs-15, 15px); }
}

/* ---------------- 6. Мелочи боя ----------------

   Оба правила чинят выход за край экрана: подпись героини центрировалась по
   портрету, а портрет стоит у самого края, и первая буква имени уезжала за
   границу; кнопка хода после укрупнения шрифта переставала помещаться
   на 390 px ровно на пиксель. */

body.in-battle .hero-name {
  left: 0;
  transform: none;
  text-align: left;
  max-width: min(140px, 40vw);
}

@media (max-width: 430px) {
  body.in-battle .btn-turn {
    padding: 0 14px;
    min-width: 0;
    font-size: var(--fs-15, 15px);
  }
}

/* ---------------- 7. Стихия на баннере ----------------

   У каждой госпожи свой характер кадра: у Хомуры искры и жар, у Мидзуки
   пузыри и холодный блик, у Кадзэ листья, у Хикари золотая пыль и луч,
   у Курохане фиолетовый туман. Раньше на всех была одна и та же горстка
   точек в цвет акцента — баннер выглядел одинаково у любой героини.

   Частицы рисуются радиальными градиентами на трёх слоях (.char-fx и два
   вложенных <i>), у каждого свой размер поля, скорость и отрицательная
   задержка — иначе все точки идут строем. Анимируются только transform и
   opacity, поэтому слой не заставляет браузер пересчитывать раскладку. */

.char-fx {
  position: absolute; inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 2;
  /* Маска повторяет растворение портрета: частицы не должны сыпаться
     поверх текста справа. */
  -webkit-mask-image: linear-gradient(90deg, #000 0 52%, transparent 92%);
  mask-image: linear-gradient(90deg, #000 0 52%, transparent 92%);
}
.char-fx i {
  position: absolute; inset: -10% 0 0;
  display: block;
  background-repeat: repeat;
  will-change: transform, opacity;
}

/* Общее свечение снизу — «жар» под ногами героини, красится стихией. */
.char-fx::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: -18%;
  height: 55%;
  background: radial-gradient(60% 100% at 32% 100%,
    color-mix(in srgb, var(--accent, #0a84ff) 45%, transparent), transparent 72%);
  opacity: 0.55;
  animation: fx-breathe 5.5s ease-in-out infinite;
}

/* Редкий блик по всему баннеру — «сверкание», о котором просил заказчик.
   Раз в девять секунд, иначе панель начинает мигать. */
.char-art-inner::before {
  content: '';
  position: absolute; top: -30%; bottom: -30%; left: -40%;
  width: 28%;
  z-index: 3;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.16), transparent);
  transform: skewX(-14deg);
  animation: fx-shine 9s ease-in-out infinite;
  pointer-events: none;
}

/* ---- Пламя: искры вверх, мелкие и частые.

   У каждой искры не точка, а ядро с ореолом (два стопа в градиенте): без
   ореола точки читаются как пыль на экране, а не как угольки. Плотность
   задаётся размером плитки фона — она меньше слоя, поэтому рисунок
   повторяется несколько раз. ---- */
.elem-fire .char-fx i:nth-child(1) {
  background-image:
    radial-gradient(3px 3px at 18% 88%, #ffe0b0 0 34%, rgba(255, 150, 60, 0.45) 58%, transparent 72%),
    radial-gradient(2.2px 2.2px at 52% 62%, #ffab5c 0 34%, rgba(255, 110, 40, 0.4) 60%, transparent 74%),
    radial-gradient(3.4px 3.4px at 78% 40%, #ffc978 0 32%, rgba(255, 140, 50, 0.4) 58%, transparent 72%),
    radial-gradient(2px 2px at 34% 18%, #ff8f4c 0 34%, rgba(255, 90, 30, 0.35) 60%, transparent 74%);
  background-size: 56% 34%;
  animation: fx-rise 7s linear infinite;
}
.elem-fire .char-fx i:nth-child(2) {
  background-image:
    radial-gradient(2.4px 2.4px at 66% 80%, #ffd98e 0 34%, rgba(255, 160, 70, 0.4) 58%, transparent 72%),
    radial-gradient(3.6px 3.6px at 28% 46%, #ff8f3c 0 30%, rgba(255, 110, 40, 0.35) 58%, transparent 74%),
    radial-gradient(2px 2px at 88% 22%, #ffeec4 0 34%, rgba(255, 190, 110, 0.4) 60%, transparent 74%);
  background-size: 64% 30%;
  animation: fx-rise 4.6s linear infinite -1.8s;
  opacity: 0.9;
}
.elem-fire .char-fx i:nth-child(3) {
  background-image: radial-gradient(3.4px 3.4px at 44% 70%, rgba(255, 150, 60, 0.9), transparent 60%);
  background-size: 100% 62%;
  animation: fx-rise 10s linear infinite -4s;
  opacity: 0.5;
}

/* ---- Волна: пузыри вверх, крупнее и медленнее, с боковым качанием ---- */
.elem-water .char-fx i:nth-child(1) {
  background-image:
    radial-gradient(3.4px 3.4px at 24% 84%, rgba(150, 230, 255, 0.9), transparent 64%),
    radial-gradient(2.2px 2.2px at 58% 58%, rgba(90, 200, 255, 0.85), transparent 64%),
    radial-gradient(4px 4px at 80% 30%, rgba(190, 245, 255, 0.7), transparent 64%);
  background-size: 62% 40%;
  animation: fx-rise 11s linear infinite, fx-sway 6s ease-in-out infinite;
}
.elem-water .char-fx i:nth-child(2) {
  background-image:
    radial-gradient(2px 2px at 70% 76%, rgba(200, 245, 255, 0.85), transparent 64%),
    radial-gradient(5px 5px at 36% 40%, rgba(80, 190, 255, 0.5), transparent 62%);
  background-size: 70% 34%;
  animation: fx-rise 8s linear infinite -3s, fx-sway 7.5s ease-in-out infinite -2s;
  opacity: 0.8;
}
/* Холодный блик по воде — тонкая полоса, идущая сверху вниз. */
.elem-water .char-fx i:nth-child(3) {
  inset: 0;
  background: linear-gradient(180deg, transparent 40%, rgba(150, 225, 255, 0.14) 50%, transparent 60%);
  background-size: 100% 220%;
  animation: fx-wave 9s ease-in-out infinite;
}

/* ---- Листва: лепестки и листья вниз, с качанием ---- */
.elem-nature .char-fx i:nth-child(1) {
  background-image:
    radial-gradient(3px 2px at 22% 20%, rgba(140, 230, 160, 0.9), transparent 62%),
    radial-gradient(2.4px 1.6px at 62% 44%, rgba(255, 190, 210, 0.85), transparent 62%),
    radial-gradient(3.4px 2.2px at 84% 72%, rgba(120, 215, 145, 0.75), transparent 62%);
  background-size: 58% 38%;
  animation: fx-fall 9s linear infinite, fx-sway 5s ease-in-out infinite;
}
.elem-nature .char-fx i:nth-child(2) {
  background-image:
    radial-gradient(2.6px 1.8px at 44% 30%, rgba(190, 245, 200, 0.8), transparent 62%),
    radial-gradient(3.2px 2px at 76% 62%, rgba(255, 200, 220, 0.7), transparent 62%);
  background-size: 66% 32%;
  animation: fx-fall 12s linear infinite -5s, fx-sway 8s ease-in-out infinite -3s;
  opacity: 0.75;
}

/* ---- Свет: золотая пыль вверх и медленный луч ---- */
.elem-light .char-fx i:nth-child(1) {
  background-image:
    radial-gradient(2px 2px at 26% 78%, rgba(255, 226, 150, 0.95), transparent 62%),
    radial-gradient(1.6px 1.6px at 60% 52%, rgba(255, 244, 205, 0.9), transparent 62%),
    radial-gradient(2.6px 2.6px at 84% 26%, rgba(255, 210, 120, 0.8), transparent 62%);
  background-size: 60% 36%;
  animation: fx-rise 13s linear infinite;
}
.elem-light .char-fx i:nth-child(2) {
  background-image:
    radial-gradient(1.4px 1.4px at 40% 66%, rgba(255, 250, 225, 0.9), transparent 62%),
    radial-gradient(2.2px 2.2px at 72% 34%, rgba(255, 220, 140, 0.75), transparent 62%);
  background-size: 68% 30%;
  animation: fx-rise 9s linear infinite -4s, fx-twinkle 3.2s ease-in-out infinite;
}
.elem-light .char-fx i:nth-child(3) {
  inset: -30% -20%;
  background: linear-gradient(102deg, transparent 42%, rgba(255, 226, 160, 0.22) 50%, transparent 58%);
  background-size: 260% 100%;
  animation: fx-ray 11s ease-in-out infinite;
}

/* ---- Тьма: фиолетовый туман и редкие вспышки ---- */
.elem-dark .char-fx i:nth-child(1) {
  inset: 0;
  background:
    radial-gradient(40% 45% at 30% 80%, rgba(150, 90, 255, 0.35), transparent 70%),
    radial-gradient(35% 40% at 62% 40%, rgba(110, 60, 210, 0.3), transparent 70%);
  animation: fx-drift 16s ease-in-out infinite alternate;
}
.elem-dark .char-fx i:nth-child(2) {
  background-image:
    radial-gradient(2px 2px at 34% 70%, rgba(214, 180, 255, 0.9), transparent 62%),
    radial-gradient(1.6px 1.6px at 70% 44%, rgba(180, 130, 255, 0.85), transparent 62%),
    radial-gradient(2.6px 2.6px at 20% 30%, rgba(160, 110, 255, 0.7), transparent 62%);
  background-size: 62% 40%;
  animation: fx-rise 12s linear infinite, fx-twinkle 4s ease-in-out infinite;
}

@keyframes fx-rise {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, -46%, 0); }
}
@keyframes fx-fall {
  from { transform: translate3d(0, -46%, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
@keyframes fx-sway {
  0%, 100% { margin-left: -6px; }
  50%      { margin-left: 6px; }
}
@keyframes fx-twinkle {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 0.95; }
}
@keyframes fx-breathe {
  0%, 100% { opacity: 0.4; }
  50%      { opacity: 0.72; }
}
@keyframes fx-wave {
  0%, 100% { background-position: 0 -60%; }
  50%      { background-position: 0 160%; }
}
@keyframes fx-ray {
  0%, 55%  { background-position: -80% 0; }
  85%, 100% { background-position: 180% 0; }
}
@keyframes fx-drift {
  from { transform: translate3d(-3%, 2%, 0) scale(1); }
  to   { transform: translate3d(4%, -3%, 0) scale(1.12); }
}
@keyframes fx-shine {
  0%, 72%   { left: -40%; opacity: 0; }
  76%       { opacity: 1; }
  96%, 100% { left: 120%; opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .char-fx i, .char-fx::after, .char-art-inner::before { animation: none; }
  .char-art-inner::before { opacity: 0; }
}

/* ---------------- 8. Стол боя ----------------

   Поле было ровной бежевой заливкой: карты на нём читались, но смотреть было
   не на что. Тот же приём, что и в меню — материал вместо заливки, свет вместо
   ровной яркости, цвет только там, где идёт действие.

   Слои снизу вверх: базовый цвет → ткань (art/bg_battle.webp) → затемнение
   краёв → светлая полоса поля (полупрозрачная, чтобы сквозь неё была видна
   фактура) → тёплое пятно свечи по центру → отсветы стихий у героинь. */

body.in-battle .battle {
  background:
    /* отсвет стихии игрока снизу и тёплый отсвет соперницы сверху */
    radial-gradient(70% 22% at 50% 100%, color-mix(in srgb, var(--accent, #0a84ff) 26%, transparent), transparent 70%),
    radial-gradient(70% 20% at 50% 0%, rgba(255, 190, 120, 0.22), transparent 70%),
    /* свеча над столом */
    radial-gradient(80% 34% at 50% 48%, rgba(255, 226, 172, 0.24), transparent 72%),
    /* Сукно с генерации тёмное — добавляем тёплый свет над серединой стола,
       иначе жёлтое поле уходит в грязно-коричневый. */
    radial-gradient(75% 40% at 50% 46%, rgba(255, 214, 130, 0.12), transparent 72%),
    /* Полоса поля: янтарное сукно. Бежевое было слишком светлым, зелёное
       заказчик забраковал; жёлтое даёт то же, ради чего всё затевалось —
       карты и существа не тонут в почти чёрном интерфейсе, — но держит
       тёплый тон всей игры. Верх полосы светлее низа: так стол читается
       наклонённым от игрока, а не плоской заливкой. */
    linear-gradient(180deg,
      transparent 0 13%,
      rgba(196, 152, 62, 0.16) 15%,
      rgba(196, 152, 62, 0.82) 19%,
      rgba(178, 134, 52, 0.86) 46%,
      rgba(150, 108, 40, 0.86) 72%,
      rgba(150, 108, 40, 0.16) 77%,
      transparent 79% 100%),
    /* тёмные края */
    linear-gradient(180deg,
      rgba(4, 4, 6, 0.92) 0%, rgba(4, 4, 6, 0.55) 16%,
      rgba(4, 4, 6, 0.12) 34%, rgba(4, 4, 6, 0.12) 66%,
      rgba(4, 4, 6, 0.6) 84%, rgba(4, 4, 6, 0.95) 100%),
    /* Ткань берётся крупнее кадра: складки должны читаться фактурой,
       а не узнаваемым куском простыни. */
    url('art/bg_battle.webp') center / 190% auto no-repeat,
    #08080a;
}

/* Разделительная полоса — тонкая золотая нить, гаснущая к краям. */
body.in-battle .table-line {
  background: linear-gradient(90deg,
    transparent, rgba(255, 214, 150, 0.35) 22%, rgba(255, 230, 190, 0.5) 50%,
    rgba(255, 214, 150, 0.35) 78%, transparent);
  box-shadow: 0 0 18px -6px rgba(255, 200, 130, 0.7);
}
body.in-battle .turn-banner {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent, #0a84ff) 82%, #fff),
    var(--accent, #0a84ff));
  border-color: transparent;
  color: #fff;
  font-weight: 700;
  box-shadow: 0 6px 18px -6px color-mix(in srgb, var(--accent, #0a84ff) 85%, transparent);
}
/* Ход соперницы: полоса гаснет, баннер становится нейтральным. */
body.in-battle .battle:not(.my-turn) .turn-banner {
  background: rgba(28, 22, 14, 0.85);
  color: #f0e6d2;
  box-shadow: none;
}

/* Портреты героинь: кольцо в цвет стихии и свечение под ним. У соперницы
   кольцо её стихии — по нему видно, чего ждать, ещё до первой карты. */
body.in-battle .hero .hero-art {
  box-shadow:
    0 0 0 2px color-mix(in srgb, var(--accent, #0a84ff) 70%, transparent),
    0 0 24px -6px color-mix(in srgb, var(--accent, #0a84ff) 90%, transparent),
    0 6px 16px rgba(0, 0, 0, 0.55);
}
/* Чей ход — та и светится. */
body.in-battle .battle.my-turn .hero-player .hero-art,
body.in-battle .battle:not(.my-turn) .hero-enemy .hero-art {
  animation: hero-pulse 2.6s ease-in-out infinite;
}
@keyframes hero-pulse {
  0%, 100% {
    box-shadow:
      0 0 0 2px color-mix(in srgb, var(--accent, #0a84ff) 70%, transparent),
      0 0 22px -8px color-mix(in srgb, var(--accent, #0a84ff) 90%, transparent),
      0 6px 16px rgba(0, 0, 0, 0.55);
  }
  50% {
    box-shadow:
      0 0 0 2px color-mix(in srgb, var(--accent, #0a84ff) 95%, transparent),
      0 0 34px -2px color-mix(in srgb, var(--accent, #0a84ff) 95%, transparent),
      0 6px 16px rgba(0, 0, 0, 0.55);
  }
}

/* Существа на столе: подсветка стихии снизу вместо плоской рамки. */
body.in-battle .minion {
  border-color: color-mix(in srgb, var(--accent, #0a84ff) 55%, rgba(40, 30, 18, 0.5));
  box-shadow:
    0 0 14px -6px color-mix(in srgb, var(--accent, #0a84ff) 95%, transparent),
    0 6px 14px rgba(40, 28, 12, 0.5);
}
body.in-battle .minion.can-attack {
  box-shadow:
    0 0 0 2px rgba(150, 255, 190, 0.55),
    0 0 18px -4px rgba(120, 255, 180, 0.8),
    0 6px 14px rgba(40, 28, 12, 0.5);
}

/* Карты в руке: глубже тень и подъём у выбранной — рука должна ощущаться
   ближе к игроку, чем стол. */
body.in-battle .hand-player .card {
  box-shadow: 0 10px 20px -8px rgba(0, 0, 0, 0.85), 0 2px 4px rgba(0, 0, 0, 0.4);
}
body.in-battle .hand-player .card.playable {
  box-shadow:
    0 0 0 1.5px color-mix(in srgb, var(--accent, #0a84ff) 60%, transparent),
    0 0 16px -6px color-mix(in srgb, var(--accent, #0a84ff) 90%, transparent),
    0 10px 20px -8px rgba(0, 0, 0, 0.85);
}
body.in-battle .hand-player .card.selected {
  box-shadow:
    0 0 0 2px color-mix(in srgb, var(--accent, #0a84ff) 95%, transparent),
    0 0 28px -4px color-mix(in srgb, var(--accent, #0a84ff) 95%, transparent),
    0 14px 26px -8px rgba(0, 0, 0, 0.9);
}

/* Кристаллы маны — те же, что и в лавке: голубой камень со свечением. */
body.in-battle .mana-gem.full {
  box-shadow: 0 0 10px -2px rgba(100, 210, 255, 0.9);
}

/* Кнопка хода — главное действие боя, звучит как «Начать» в меню. */
body.in-battle .my-turn .btn-turn {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent, #0a84ff) 80%, #fff) 0%,
    var(--accent, #0a84ff) 52%,
    color-mix(in srgb, var(--accent, #0a84ff) 86%, #000) 100%);
  border-color: transparent;
  color: #fff;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.38),
    0 12px 26px -10px color-mix(in srgb, var(--accent, #0a84ff) 85%, transparent);
}
body.in-battle .btn-turn:disabled { box-shadow: none; }

@media (prefers-reduced-motion: reduce) {
  body.in-battle .hero .hero-art { animation: none; }
}

/* Половины стола под зелёное сукно: тёплая коричневая полка под рукой
   осталась от бежевого стола и рядом с зелёным читалась как грязь. */
body.in-battle .side-player {
  background: linear-gradient(0deg, rgba(6, 14, 11, 0.85), transparent 78%);
}
body.in-battle .board-player {
  background: radial-gradient(60% 80% at 50% 100%,
    color-mix(in srgb, var(--accent, #0a84ff) 14%, transparent), transparent 70%);
}
body.in-battle .board-enemy {
  background: radial-gradient(60% 80% at 50% 0%, rgba(255, 190, 120, 0.1), transparent 70%);
}
body.in-battle .board-player.empty::after { color: rgba(226, 240, 232, 0.4); }

/* Карты и существа крупнее: на телефоне 62 px в ширину — это подпись
   в четыре буквы и нечитаемый текст способности. */
body.in-battle {
  --card-w: clamp(76px, 10.4vh, 112px);
  --card-h: clamp(106px, 14.4vh, 154px);
}
body.in-battle .hero {
  width: clamp(68px, 9.8vh, 100px);
  height: clamp(68px, 9.8vh, 100px);
}
body.in-battle .hero-power {
  width: clamp(62px, 9vh, 88px);
  height: clamp(62px, 9vh, 88px);
}

/* ---------------- 9. Стол как поле боя ----------------

   Замечания заказчика: стол читался как «бежевый прямоугольник с картами
   где-то посередине». Здесь он разбирается на понятные зоны — сверху
   соперница, снизу игрок, между ними линия фронта, — и каждая зона объясняет
   себя сама: пустые слоты показывают, куда класть существо, полка отделяет
   руку от поля, дорожки связывают существо с линией столкновения.

   Порядок сверху вниз намеренно совпадает с ходом взгляда:
   героиня соперницы → её рука → её ряд → линия фронта → свой ряд → своя рука →
   свой герой, мана и кнопка хода. */

/* Зал за столом: очень размытая сцена, чтобы у боя была глубина, но карты
   оставались главным объектом. */
body.in-battle::before {
  background-image: url('art/bg_hall.webp');
  filter: blur(16px) saturate(0.7) brightness(0.34);
}

/* ---- зоны ---- */

body.in-battle .board {
  position: relative;
  border-radius: 14px;
  padding: 6px 6px;
}
/* Ряды прижимаются к центру: пустая половина больше не разводит существ
   по разным краям экрана. */
body.in-battle .board-enemy { align-items: flex-end; }
body.in-battle .board-player { align-items: flex-start; }

/* Половина соперницы холоднее и темнее, своя — теплее и подсвечена стихией.
   Разница мягкая: это подсказка, а не раскраска. */
body.in-battle .board-enemy {
  background:
    linear-gradient(180deg, rgba(10, 6, 16, 0.5) 0%, rgba(10, 6, 16, 0.12) 70%, transparent),
    radial-gradient(70% 90% at 50% 0%, rgba(255, 170, 120, 0.1), transparent 72%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
body.in-battle .board-player {
  background:
    linear-gradient(0deg, rgba(6, 14, 11, 0.45) 0%, rgba(6, 14, 11, 0.1) 70%, transparent),
    radial-gradient(70% 90% at 50% 100%, color-mix(in srgb, var(--accent, #0a84ff) 16%, transparent), transparent 72%);
  box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.05);
}

/* ---- слоты ----

   Семь мест с каждой стороны — столько и вмещает поле по правилам. Рисуются
   фоном: доска устроена как flex-ряд существ, и настоящие элементы-заглушки
   пришлось бы вплетать в syncList, который двигает узлы по uid. */
body.in-battle .board::before {
  content: '';
  position: absolute; left: 50%;
  transform: translateX(-50%);
  width: min(calc((var(--minion-w) + 6px) * 7), 100%);
  height: var(--minion-h);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 128' preserveAspectRatio='none'%3E%3Crect x='4' y='2' width='92' height='124' rx='11' fill='rgba(255,255,255,0.045)' stroke='rgba(255,255,255,0.1)' stroke-width='1.5' stroke-dasharray='6 5'/%3E%3C/svg%3E");
  background-size: calc(100% / 7) 100%;
  background-repeat: repeat-x;
  opacity: 0.34;
  pointer-events: none;
  transition: opacity 0.2s ease;
}
/* Слоты стоят там же, где встают существа: ряды прижаты к линии фронта,
   поэтому у соперницы места внизу зоны, а у игрока — вверху. */
body.in-battle .board-enemy::before { opacity: 0.2; bottom: 6px; }
body.in-battle .board-player::before { top: 6px; }
/* Выбрана карта — свободные места на своей половине разгораются. */
body.in-battle .board-player.placing::before { opacity: 1; }
body.in-battle .board.placing {
  background:
    radial-gradient(70% 90% at 50% 100%, color-mix(in srgb, var(--accent, #0a84ff) 26%, transparent), transparent 72%),
    rgba(120, 255, 190, 0.06);
  outline: 1px dashed color-mix(in srgb, var(--accent, #0a84ff) 65%, transparent);
}

/* ---- линия фронта ---- */

body.in-battle .table-line {
  position: relative;
  overflow: visible;   /* баннер «Ваш ход» висит выше линии */
  height: 18px;
  background:
    linear-gradient(90deg, transparent, rgba(255, 214, 150, 0.5) 20%, rgba(255, 236, 200, 0.75) 50%, rgba(255, 214, 150, 0.5) 80%, transparent) center / 100% 2px no-repeat,
    radial-gradient(50% 140% at 50% 50%, rgba(255, 200, 130, 0.16), transparent 70%);
  box-shadow: none;
}
/* Огонёк, пробегающий по линии: столкновение, а не разделитель интерфейса. */
body.in-battle .table-line::before {
  content: '';
  position: absolute; top: 50%; left: 0;
  width: 22%; height: 3px;
  transform: translateY(-50%);
  background: linear-gradient(90deg, transparent, rgba(255, 245, 220, 0.85), transparent);
  filter: blur(0.4px);
  animation: front-sweep 7s ease-in-out infinite;
  border-radius: 999px;
  opacity: 0.9;
}
body.in-battle .table-line::after { content: none; }
@keyframes front-sweep {
  0%, 8%   { left: -25%; opacity: 0; }
  14%      { opacity: 0.9; }
  80%      { opacity: 0.9; }
  90%, 100% { left: 92%; opacity: 0; }
}

/* «Ваш ход» остаётся на линии, но как табличка на ней, а не как подпись к
   разделителю: над линией пробовали — при полном ряде соперницы надпись
   накрывала её существ, потому что ряды теперь прижаты к центру. */
body.in-battle .turn-banner {
  position: relative;
  z-index: 6;
  padding: 3px 14px;
  font-size: var(--fs-12, 12px);
  letter-spacing: 0.01em;
  white-space: nowrap;
}

/* ---- существа крупнее ---- */

body.in-battle {
  --minion-w: clamp(78px, 10.8vh, 108px);
  --minion-h: clamp(98px, 13.4vh, 134px);
}
body.in-battle .minion {
  width: var(--minion-w);
  /* Высота идёт от ширины: когда мест занято много, существа ужимаются,
     а не вылезают за край — и при этом не превращаются в вытянутые полоски,
     как было бы с фиксированной высотой. */
  height: auto;
  /* Пропорция числом, а не через clamp-переменные: aspect-ratio принимает
     только безразмерные числа, с px-значениями свойство молча отбрасывается
     и карточка схлопывается в двухпиксельную полоску. */
  aspect-ratio: 78 / 98;
  flex: 0 1 auto;
  min-width: 52px;
}

/* Дорожка от существа к линии фронта: видно, кто с кем стоит напротив. */
body.in-battle .minion::after {
  content: '';
  position: absolute; left: 50%; width: 2px;
  transform: translateX(-50%);
  opacity: 0;
  transition: opacity 0.18s ease;
  pointer-events: none;
}
body.in-battle .board-player .minion::after {
  bottom: 100%; height: 14px;
  background: linear-gradient(0deg, color-mix(in srgb, var(--accent, #0a84ff) 80%, transparent), transparent);
}
body.in-battle .board-enemy .minion::after {
  top: 100%; height: 14px;
  background: linear-gradient(180deg, rgba(255, 190, 130, 0.8), transparent);
}
body.in-battle .minion.ready::after { opacity: 0.5; }
body.in-battle .minion:hover::after,
body.in-battle .minion.selected::after,
body.in-battle .minion.targetable::after { opacity: 1; }

/* ---- состояния ---- */

body.in-battle .minion.ready {
  box-shadow:
    0 0 0 1.5px rgba(150, 255, 190, 0.5),
    0 0 16px -6px rgba(120, 255, 180, 0.9),
    0 6px 14px rgba(0, 0, 0, 0.5);
}
body.in-battle .minion.selected {
  transform: translateY(-4px);
  box-shadow:
    0 0 0 2px color-mix(in srgb, var(--accent, #0a84ff) 95%, transparent),
    0 0 26px -4px color-mix(in srgb, var(--accent, #0a84ff) 95%, transparent),
    0 10px 20px rgba(0, 0, 0, 0.6);
}
body.in-battle .minion.targetable, body.in-battle .hero.targetable {
  box-shadow:
    0 0 0 2px rgba(255, 120, 150, 0.85),
    0 0 24px -4px rgba(255, 90, 130, 0.9);
}

/* ---- полка руки ----

   Рука лежала на той же сцене, что и стол. Теперь под ней тёмная панель
   со светлой кромкой: это отдельная зона, а не продолжение поля. */
body.in-battle .side-player {
  position: relative;
  border-radius: 18px 18px 0 0;
  background: linear-gradient(0deg, rgba(4, 8, 7, 0.94) 55%, rgba(4, 8, 7, 0.7) 82%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.09);
  padding: 0 4px 2px;
}
body.in-battle .hand-player .card.playable {
  transform: translateY(-4px) rotate(calc((var(--i) - (var(--n) - 1) / 2) * 2.2deg));
}
body.in-battle .hand-player .card.selected {
  transform: translateY(-18px) scale(1.1) rotate(0deg);
}

@media (prefers-reduced-motion: reduce) {
  body.in-battle .table-line::before { animation: none; opacity: 0; }
}

/* ---------------- 10. Стихии сторон на столе ----------------

   На поле должно быть видно, чья это половина: снизу идёт стихия своей
   госпожи, сверху — соперницы. Частицы те же, что на баннере в меню
   (раздел 7), поэтому огонь Хомуры одинаково выглядит и в меню, и в бою;
   класс стихии висит на обёртке, а рисуют вложенные слои .char-fx.

   Слой лежит под содержимым стола и не ловит нажатия: это атмосфера,
   а не элемент управления. */

body.in-battle .zone-fx {
  position: absolute;
  left: 0; right: 0;
  height: 42%;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  border-radius: 14px;
}
body.in-battle .zone-fx-enemy { top: 0; }
body.in-battle .zone-fx-player { bottom: 0; }

/* Мягкий отсвет стихии по своему краю стола — «здесь я, там соперница». */
body.in-battle .zone-fx-enemy {
  background: radial-gradient(85% 75% at 50% 0%,
    color-mix(in srgb, var(--accent, #0a84ff) 32%, transparent), transparent 74%);
}
body.in-battle .zone-fx-player {
  background: radial-gradient(85% 75% at 50% 100%,
    color-mix(in srgb, var(--accent, #0a84ff) 34%, transparent), transparent 74%);
}

body.in-battle .zone-fx .char-fx {
  position: absolute; inset: 0;
  opacity: 0.9;
  /* На баннере маска гасила частицы справа, у стола гасить надо к линии
     фронта и к краю экрана — иначе искры лезут на портреты и на руку. */
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 16%, #000 88%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 16%, #000 88%, transparent);
}
/* Нижнее свечение с баннера здесь лишнее: его роль играет отсвет зоны. */
body.in-battle .zone-fx .char-fx::after { content: none; }

@media (prefers-reduced-motion: reduce) {
  body.in-battle .zone-fx .char-fx i { animation: none; }
}

/* ---------------- 11. Удары и вспышки ----------------

   Раньше атака была одним рывком карточки и всплывающим числом: попадание
   ничем не отличалось от промаха, и бой шёл беззвучно для глаза. Здесь у
   каждого события боя своя вспышка, а у попадания — ещё и встряска стола.

   Все эффекты рисуются одним узлом .fx поверх стола и сами себя убирают:
   привязывать их к существу нельзя — оно может погибнуть тем же ударом. */

.fx {
  position: absolute;
  z-index: 45;
  width: 10px; height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 50%;
  pointer-events: none;
}
/* Ядро вспышки. */
.fx::before,
.fx::after {
  content: '';
  position: absolute; inset: 50% auto auto 50%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
}

/* Попадание: белая вспышка, разлетающееся кольцо и веер искр. */
.fx-hit::before {
  width: 54px; height: 54px;
  background: radial-gradient(circle, rgba(255, 250, 235, 0.95) 0 18%, rgba(255, 190, 120, 0.55) 42%, transparent 70%);
  animation: fx-flash 0.34s ease-out forwards;
}
.fx-hit::after {
  width: 26px; height: 26px;
  border: 2px solid rgba(255, 226, 180, 0.9);
  animation: fx-ring 0.45s cubic-bezier(0.2, 0.8, 0.3, 1) forwards;
}
/* Искры — точки на общей окружности, разлетающиеся вместе со слоем. */
.fx-hit {
  background:
    radial-gradient(2.5px 2.5px at 50% 12%, #fff2d0, transparent 60%),
    radial-gradient(2.5px 2.5px at 84% 40%, #ffce8a, transparent 60%),
    radial-gradient(2.5px 2.5px at 72% 84%, #ffb066, transparent 60%),
    radial-gradient(2.5px 2.5px at 24% 78%, #fff0c8, transparent 60%),
    radial-gradient(2.5px 2.5px at 12% 34%, #ffc078, transparent 60%);
  width: 64px; height: 64px; margin: -32px 0 0 -32px;
  animation: fx-sparks 0.5s ease-out forwards;
}

/* Смерть: тёмный выброс с пеплом. */
.fx-death {
  width: 70px; height: 70px; margin: -35px 0 0 -35px;
  background:
    radial-gradient(3px 3px at 30% 70%, rgba(255, 160, 120, 0.9), transparent 60%),
    radial-gradient(2px 2px at 66% 40%, rgba(220, 200, 190, 0.8), transparent 60%),
    radial-gradient(2.5px 2.5px at 48% 22%, rgba(255, 120, 90, 0.8), transparent 60%);
  animation: fx-sparks 0.62s ease-out forwards;
}
.fx-death::before {
  width: 48px; height: 48px;
  background: radial-gradient(circle, rgba(60, 20, 30, 0.85) 0 30%, transparent 72%);
  animation: fx-flash 0.5s ease-out forwards;
}

/* Лечение, щит, мороз, сила героя — то же кольцо в своём цвете. */
.fx-heal::before {
  width: 46px; height: 46px;
  background: radial-gradient(circle, rgba(150, 255, 190, 0.85) 0 22%, transparent 70%);
  animation: fx-flash 0.42s ease-out forwards;
}
.fx-heal::after {
  width: 22px; height: 22px;
  border: 2px solid rgba(150, 255, 190, 0.9);
  animation: fx-ring 0.5s ease-out forwards;
}
.fx-shield::after,
.fx-buff::after {
  width: 24px; height: 24px;
  border: 2px solid rgba(255, 214, 120, 0.95);
  animation: fx-ring 0.5s ease-out forwards;
}
.fx-frost::before {
  width: 46px; height: 46px;
  background: radial-gradient(circle, rgba(180, 235, 255, 0.9) 0 20%, transparent 70%);
  animation: fx-flash 0.45s ease-out forwards;
}
.fx-power::before {
  width: 70px; height: 70px;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent, #0a84ff) 85%, #fff) 0 14%, transparent 68%);
  animation: fx-flash 0.5s ease-out forwards;
}
.fx-power::after {
  width: 30px; height: 30px;
  border: 2px solid color-mix(in srgb, var(--accent, #0a84ff) 90%, #fff);
  animation: fx-ring 0.6s ease-out forwards;
}

@keyframes fx-flash {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.3); }
  25%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1.25); }
}
@keyframes fx-ring {
  0%   { opacity: 0.9; transform: translate(-50%, -50%) scale(0.4); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(2.6); }
}
@keyframes fx-sparks {
  0%   { opacity: 1; transform: scale(0.35); }
  70%  { opacity: 0.8; }
  100% { opacity: 0; transform: scale(1.5); }
}

/* Цель удара: белая засветка и отдача. */
body.in-battle .minion.struck,
body.in-battle .hero.struck {
  animation: struck 0.3s ease-out;
}
@keyframes struck {
  0%   { filter: brightness(2.2) saturate(0.5); transform: scale(1.06); }
  40%  { filter: brightness(1.3); }
  100% { filter: none; transform: none; }
}

/* Нападающий на время удара выходит на передний план. */
body.in-battle .minion.striking,
body.in-battle .hero.striking { z-index: 30; }

/* Встряска стола — короткая и мелкая: большая амплитуда мешает читать поле. */
body.in-battle .battle.quake { animation: quake 0.26s ease-in-out; }
@keyframes quake {
  20%  { transform: translate(2px, -2px); }
  45%  { transform: translate(-3px, 1px); }
  70%  { transform: translate(2px, 2px); }
  100% { transform: none; }
}

/* Свой герой получил урон — красная засветка по краям экрана. */
.fx-veil {
  position: absolute; inset: 0;
  z-index: 44;
  pointer-events: none;
  background: radial-gradient(120% 80% at 50% 110%, rgba(255, 40, 60, 0.35), transparent 62%);
  animation: fx-veil 0.6s ease-out forwards;
}
@keyframes fx-veil {
  0%   { opacity: 0; }
  20%  { opacity: 1; }
  100% { opacity: 0; }
}

/* Числа урона крупнее и с обводкой, тяжёлый удар — заметно крупнее. */
.pop {
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.02em;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.95), 0 0 14px rgba(0, 0, 0, 0.6);
}
.pop-dmg { color: #ff5f75; }
.pop-big { font-size: 32px; }
.pop-heal { color: #5ddc8a; }

/* Гибель: существо оседает и гаснет, а не просто исчезает. */
body.in-battle .minion.dying { animation: die 0.34s cubic-bezier(0.4, 0, 0.7, 0.2) forwards; }
@keyframes die {
  30%  { transform: translateY(-4px) scale(1.04) rotate(-3deg); filter: brightness(1.6); }
  100% { opacity: 0; transform: translateY(10px) scale(0.72) rotate(9deg); filter: blur(3px) brightness(0.6); }
}

@media (prefers-reduced-motion: reduce) {
  body.in-battle .battle.quake,
  body.in-battle .minion.struck,
  body.in-battle .hero.struck { animation: none; }
  .fx, .fx-veil { display: none; }
}

/* ---------------- 12. Второстепенные экраны ----------------

   Меню и бой получили материал, свет и цвет — а кампания, коллекция, лавка
   и арена остались списками на стекле. Здесь тот же язык доводится до них:
   появление экрана, глубина панелей, цвет стихии там, где он что-то значит.

   Ничего не двигается само по себе: анимация только на входе экрана и на
   действиях пользователя. */

/* Появление экрана: короткий подъём с прозрачностью. Ключ — 0.22 с; всё,
   что дольше, начинает восприниматься как задержка интерфейса. */
.screen { animation: screen-in 0.22s ease-out; }
@keyframes screen-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
/* В бою вход не нужен: стол и так въезжает своими анимациями,
   а сдвиг всего экрана ломает координаты вспышек. */
body.in-battle .screen { animation: none; }

/* Заголовок раздела: под ним тонкая линия в цвет стихии — экран сразу
   принадлежит выбранной госпоже, как и остальной интерфейс. */
.screen-head {
  position: relative;
  padding-bottom: 10px;
  margin-bottom: 4px;
}
.screen-head::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--accent, #0a84ff) 60%, transparent),
    color-mix(in srgb, var(--accent, #0a84ff) 12%, transparent) 42%,
    transparent 78%);
}

/* ---- кампания ---- */

.chapter-head {
  position: relative;
  padding: 14px 2px 8px;
}
.chapter-name {
  font-size: var(--fs-12, 12px); font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: color-mix(in srgb, var(--accent, #0a84ff) 60%, #fff);
}

/* Ступень кампании — не строка списка, а карточка соперницы: слева её
   стихия, справа награда. Цвет берётся из класса elem-* на самой ступени. */
.stage {
  position: relative;
  overflow: hidden;
  padding: 12px 14px;
  background:
    radial-gradient(60% 140% at 0% 50%, color-mix(in srgb, var(--accent, #0a84ff) 14%, transparent), transparent 70%),
    linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.02));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 10px 22px -14px rgba(0, 0, 0, 0.9);
  transition: transform 0.16s cubic-bezier(0.2, 0.8, 0.3, 1), box-shadow 0.2s ease, background 0.2s ease;
}
.stage:not(.locked):hover {
  transform: translateY(-2px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.1),
    0 16px 30px -16px rgba(0, 0, 0, 0.95);
}
/* Портрет соперницы крупнее и в кольце своей стихии. */
.stage-art {
  width: 58px; height: 72px;
  border-radius: 14px;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--accent, #0a84ff) 45%, transparent),
    0 0 18px -8px color-mix(in srgb, var(--accent, #0a84ff) 90%, transparent);
}
.stage-index {
  background: color-mix(in srgb, var(--accent, #0a84ff) 22%, rgba(255, 255, 255, 0.06));
  border: 1px solid color-mix(in srgb, var(--accent, #0a84ff) 35%, transparent);
  color: var(--text-1, #f5f5f7);
  font-weight: 700;
}
/* Следующая дуэль — единственная подсвеченная строка экрана. */
.stage:not(.locked):not(.done) {
  border-color: color-mix(in srgb, var(--accent, #0a84ff) 40%, transparent);
}
.stage:not(.locked):not(.done)::after {
  content: '';
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 3px;
  background: linear-gradient(180deg,
    transparent, var(--accent, #0a84ff) 20% 80%, transparent);
}
/* Пройденные не должны спорить с текущей, но и пропадать им незачем. */
.stage.done { opacity: 0.68; }
.stage.done .stage-art { filter: grayscale(0.35); }
.stage.done .stage-index {
  background: #30d158; border-color: transparent; color: #08080a;
}
.stage.locked { opacity: 0.52; }
.stage.locked .stage-art { filter: grayscale(0.8) brightness(0.7); }

/* Награда — два чипа, а не два числа в столбик. */
.stage-reward {
  display: flex; flex-direction: column; gap: 4px;
  align-items: flex-end;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  white-space: nowrap;
}

/* ---- коллекция ---- */

/* Карта под курсором приподнимается — сетка перестаёт быть ковром. */
.catalog-grid > * {
  transition: transform 0.16s cubic-bezier(0.2, 0.8, 0.3, 1), filter 0.2s ease;
}
.catalog-grid > *:hover { transform: translateY(-3px); }
.catalog-grid > .unowned { filter: grayscale(0.55) brightness(0.75); }
.catalog-grid > .unowned:hover { filter: grayscale(0.25) brightness(0.9); }

/* Панель колоды — та же плита, что и всё остальное. */
.deck-panel {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.02));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 14px 30px -16px rgba(0, 0, 0, 0.9);
}
.deck-count-big {
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--accent, #0a84ff) 70%, #fff);
}
/* Столбики кривой маны в цвет стихии, с подсветкой по верхней кромке. */
.curve-bar {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent, #0a84ff) 85%, #fff),
    var(--accent, #0a84ff));
  box-shadow: 0 0 12px -6px color-mix(in srgb, var(--accent, #0a84ff) 90%, transparent);
}

/* ---- окна ---- */

/* Панель поверх экрана: под ней светится стихия, чтобы окно не выглядело
   вырезанным из другого приложения. */
.panel {
  position: relative;
  background:
    radial-gradient(90% 60% at 50% 0%, color-mix(in srgb, var(--accent, #0a84ff) 14%, transparent), transparent 70%),
    rgba(28, 28, 32, 0.88);
  animation: panel-in 0.24s cubic-bezier(0.2, 0.9, 0.3, 1.1);
}
@keyframes panel-in {
  from { opacity: 0; transform: translateY(10px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
.panel-emblem {
  color: color-mix(in srgb, var(--accent, #0a84ff) 55%, #fff);
  text-shadow: 0 0 24px color-mix(in srgb, var(--accent, #0a84ff) 70%, transparent);
}

@media (prefers-reduced-motion: reduce) {
  .screen, .panel { animation: none; }
  .catalog-grid > *:hover, .stage:not(.locked):hover { transform: none; }
}

/* ---------------- 13. Лавка ----------------

   Свиток был тёмным прямоугольником с иероглифом: покупать нечего, смотреть
   не на что. Рубашка карты уже нарисована (art/card_back.webp) — она и
   становится товаром, а вокруг встаёт золотое свечение и лёгкое парение.
   Гарантированная легендарная добавляет к этому золотую кромку. */

.pack-visual {
  position: relative;
  width: 148px; height: 208px;
  border-radius: 16px;
  border: 1px solid rgba(255, 214, 140, 0.28);
  background: url('art/card_back.webp') center / cover no-repeat, #14100c;
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.6),
    0 18px 40px -16px rgba(0, 0, 0, 0.9),
    0 0 40px -14px rgba(255, 200, 110, 0.8);
  animation: pack-float 5.5s ease-in-out infinite alternate;
  cursor: pointer;
  transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.3, 1), box-shadow 0.2s ease;
}
.pack-visual:hover {
  transform: translateY(-4px) scale(1.02);
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.6),
    0 24px 46px -16px rgba(0, 0, 0, 0.95),
    0 0 56px -12px rgba(255, 210, 130, 0.9);
}
.pack-visual:active { transform: translateY(0) scale(0.99); }
/* Иероглиф был заглушкой на месте арта — теперь арт есть. */
.pack-emblem { display: none; }

/* Свечение вернулось, но мягкое и позади свитка. */
.pack-glow {
  display: block;
  position: absolute; inset: -26%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 200, 110, 0.28), transparent 66%);
  animation: pack-pulse 3.4s ease-in-out infinite;
}
.pack-visual.guaranteed {
  border-color: rgba(255, 226, 150, 0.85);
  box-shadow:
    0 0 0 1px rgba(255, 226, 150, 0.5),
    0 18px 40px -16px rgba(0, 0, 0, 0.9),
    0 0 60px -10px rgba(255, 210, 120, 1);
}

@keyframes pack-float {
  from { transform: translateY(-3px); }
  to   { transform: translateY(4px); }
}
@keyframes pack-pulse {
  0%, 100% { opacity: 0.55; transform: scale(0.96); }
  50%      { opacity: 1; transform: scale(1.06); }
}

/* Полоса жалости — тот же язык, что и полоса опыта в профиле. */
.pity-bar > span,
.pity > span > span {
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--gold-1, #f2c14e) 70%, #fff),
    var(--gold-1, #f2c14e));
}

@media (prefers-reduced-motion: reduce) {
  .pack-visual, .pack-glow { animation: none; }
}

/* ---------------- 14. Арена ----------------

   Баннер брал старый снимок доски и выглядел случайной картинкой. Теперь под
   ним арт самой арены — тот же, что на плитке в меню, — и красное свечение
   снизу: забег должен ощущаться отдельным режимом, а не разделом настроек. */

.arena-banner {
  min-height: 148px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 16px 34px -18px rgba(0, 0, 0, 0.95);
}
.arena-banner-art {
  background: url('art/tile_arena.webp') center 45% / cover no-repeat;
  opacity: 0.6;
  filter: saturate(1.35) contrast(1.06);
  animation: art-drift 30s ease-in-out infinite alternate;
}
.arena-banner-veil {
  background:
    radial-gradient(90% 120% at 50% 120%, rgba(255, 90, 60, 0.25), transparent 65%),
    linear-gradient(0deg, rgba(10, 10, 12, 0.94), rgba(10, 10, 12, 0.4) 66%, rgba(10, 10, 12, 0.15));
}

/* Ступени: пройденные горят акцентом, текущая обведена и чуть приподнята,
   последняя — золотая, потому что за ней премия. */
.ladder-step {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.02));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
  transition: transform 0.16s cubic-bezier(0.2, 0.8, 0.3, 1), background 0.2s ease, box-shadow 0.2s ease;
}
.ladder-step.done {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent, #0a84ff) 22%, transparent),
    color-mix(in srgb, var(--accent, #0a84ff) 8%, transparent));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.ladder-step.done .step-mark {
  box-shadow: 0 0 14px -4px color-mix(in srgb, var(--accent, #0a84ff) 90%, transparent);
}
.ladder-step.current {
  transform: translateY(-3px);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--accent, #0a84ff) 60%, transparent),
    0 12px 24px -12px color-mix(in srgb, var(--accent, #0a84ff) 80%, transparent);
}
.ladder-step.final {
  border-color: rgba(242, 193, 78, 0.4);
  background: linear-gradient(180deg, rgba(242, 193, 78, 0.14), rgba(242, 193, 78, 0.04));
}
.ladder-step.final .step-mark { box-shadow: 0 0 16px -4px rgba(242, 193, 78, 0.9); }

/* Портрет соперницы забега — в кольце её стихии, как на ступенях кампании. */
.foe-art {
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--accent, #0a84ff) 45%, transparent),
    0 0 20px -8px color-mix(in srgb, var(--accent, #0a84ff) 90%, transparent);
}
.foe-reward {
  background: linear-gradient(180deg, rgba(242, 193, 78, 0.14), rgba(242, 193, 78, 0.04));
  border: 1px solid rgba(242, 193, 78, 0.28);
}

/* Жизни: потухшие остаются на месте, но гаснут по-настоящему. */
.life { box-shadow: 0 0 12px -4px rgba(255, 159, 10, 0.8); }
.life.spent { color: var(--text-3, #7c7c82); box-shadow: none; opacity: 0.5; }

@media (prefers-reduced-motion: reduce) {
  .arena-banner-art { animation: none; }
  .ladder-step.current { transform: none; }
}

/* ---------------- 15. Выбор госпожи ----------------

   Первый экран новой игры, а выглядел он списком карточек с портретами:
   выбирать характер по нему было нельзя. Теперь каждая карточка — маленький
   вариант баннера из меню: сцена стихии фоном, портрет, растворяющийся в ней
   книзу, свой цвет у названия, силы и кромки.

   Карточки равной высоты: подпись «выдадим стартовую колоду» прижата к низу,
   иначе ряд из пяти разной длины выглядит сломанным. */

.leaders-head h1 { font-size: var(--fs-32, 32px); font-weight: 800; letter-spacing: -0.03em; }
.leaders-head p { font-size: var(--fs-13, 13px); }

.leader-grid { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }

.leader-card {
  display: flex; flex-direction: column;
  overflow: hidden;
  border-radius: var(--radius-lg, 22px);
  border: 1px solid var(--hairline, rgba(255, 255, 255, 0.1));
  background:
    radial-gradient(80% 50% at 50% 100%, color-mix(in srgb, var(--accent, #0a84ff) 20%, transparent), transparent 70%),
    linear-gradient(180deg, rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.72)),
    var(--banner, linear-gradient(transparent, transparent)) center / cover no-repeat,
    #0b0b0e;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 14px 30px -16px rgba(0, 0, 0, 0.9);
  transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.3, 1), box-shadow 0.22s ease, border-color 0.2s ease;
}
.leader-card.elem-fire   { --banner: url('art/banner_fire.webp'); }
.leader-card.elem-water  { --banner: url('art/banner_water.webp'); }
.leader-card.elem-nature { --banner: url('art/banner_nature.webp'); }
.leader-card.elem-light  { --banner: url('art/banner_light.webp'); }
.leader-card.elem-dark   { --banner: url('art/banner_dark.webp'); }

.leader-card:hover {
  transform: translateY(-4px);
  border-color: color-mix(in srgb, var(--accent, #0a84ff) 55%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.1),
    0 22px 40px -18px rgba(0, 0, 0, 0.95),
    0 0 40px -18px color-mix(in srgb, var(--accent, #0a84ff) 90%, transparent);
}

/* Портрет уходит в фон карточки, а не обрывается прямой линией. */
.leader-art {
  height: 240px;
  -webkit-mask-image: linear-gradient(180deg, #000 0 62%, rgba(0, 0, 0, 0.55) 84%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0 62%, rgba(0, 0, 0, 0.55) 84%, transparent 100%);
}
.leader-frame::after { content: none; }

/* Без backdrop-filter: внутри карточки с overflow:hidden и маской на портрете
   он роняет отрисовку всего слоя — карточка перестаёт рисоваться целиком,
   причём через раз. Базовое правило в styles.css его всё ещё ставит,
   поэтому гасим явно, а не просто «не добавляем». */
.elem-chip {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  background: rgba(0, 0, 0, 0.55);
  border: 1px solid color-mix(in srgb, var(--accent, #0a84ff) 40%, transparent);
  color: color-mix(in srgb, var(--accent, #0a84ff) 65%, #fff);
  font-size: var(--fs-11, 11px); font-weight: 600;
}
.leader-caption { padding-bottom: 4px; }
.leader-name {
  font-size: var(--fs-20, 20px); font-weight: 800; letter-spacing: -0.02em;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.9);
}
.leader-title { color: color-mix(in srgb, var(--accent, #0a84ff) 65%, #fff); font-size: var(--fs-12, 12px); }

/* Тело карточки: сила героя чипом, лор, а внизу — состояние колоды. */
.leader-body {
  flex: 1;
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px 14px 14px;
}
.leader-power {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 8px 10px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid color-mix(in srgb, var(--accent, #0a84ff) 22%, var(--hairline, rgba(255, 255, 255, 0.1)));
  font-size: var(--fs-12, 12px);
  line-height: 1.35;
}
.power-pill {
  flex: 0 0 auto;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: #0a84ff;
  color: #fff;
  font-size: var(--fs-11, 11px); font-weight: 700;
  box-shadow: 0 0 12px -3px rgba(100, 210, 255, 0.9);
}
.leader-lore { font-size: var(--fs-12, 12px); color: var(--text-3, #7c7c82); font-style: normal; }
.leader-flag {
  margin-top: auto;
  padding-top: 8px;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  font-size: var(--fs-11, 11px);
  color: var(--text-3, #7c7c82);
}
/* Уже собранная колода — единственная зелёная отметка на экране. */
.leader-card .leader-flag:first-letter { font-size: var(--fs-13, 13px); }

/* ---------------- 16. Лицо карты ----------------

   Карту игрок видит чаще всего остального: в руке, на столе, в коллекции,
   при вскрытии свитка. Геометрию не трогаем — она уже посчитана в cqw и
   одинаково работает во всех размерах; меняется только материал.

   Числа были плоскими кружками. Теперь у каждого свой камень: мана —
   голубой кристалл, атака — золото, здоровье — кровь. У всех трёх светлая
   кромка сверху, тень снизу и лёгкое свечение своим цветом: так они читаются
   на любом арте, а не только на тёмном. */

.card-cost, .card-atk, .card-hp, .minion .card-cost, .minion .card-atk, .minion .card-hp {
  box-shadow:
    inset 0 1.5cqw 0 rgba(255, 255, 255, 0.35),
    inset 0 -1cqw 1.5cqw rgba(0, 0, 0, 0.35),
    0 1cqw 2cqw rgba(0, 0, 0, 0.6);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0.5cqw 1cqw rgba(0, 0, 0, 0.35);
}
.card-cost {
  background:
    radial-gradient(70% 70% at 35% 25%, #8fd4ff, transparent 60%),
    linear-gradient(180deg, #3aa0ff, #0a6fd8);
}
.card-atk {
  background:
    radial-gradient(70% 70% at 35% 25%, #fff0c0, transparent 60%),
    linear-gradient(180deg, #f7cf6a, #d9a12c);
}
.card-hp {
  background:
    radial-gradient(70% 70% at 35% 25%, #ff9a90, transparent 60%),
    linear-gradient(180deg, #ff5347, #c9291f);
}
.card-hp.hurt {
  background:
    radial-gradient(70% 70% at 35% 25%, #ff7a70, transparent 60%),
    linear-gradient(180deg, #e0261c, #8f0f08);
}
/* Усиленные статы: зелёное кольцо остаётся, но теперь ещё и светится. */
.card-atk.buffed, .card-hp.buffed {
  box-shadow:
    0 0 0 0.6cqw #30d158,
    0 0 3cqw rgba(48, 209, 88, 0.8),
    inset 0 1.5cqw 0 rgba(255, 255, 255, 0.3);
}

/* Полоса подписи: тонкая линия в цвет стихии по верхней кромке —
   класс карты виден, даже когда значок стихии не читается. */
.card::after {
  border-top: 1px solid color-mix(in srgb, var(--accent, rgba(255, 255, 255, 0.2)) 45%, transparent);
  box-shadow: 0 -0.5cqw 3cqw color-mix(in srgb, var(--accent, transparent) 22%, transparent);
}

/* Имя чуть плотнее и с тенью — оно стоит на границе арта и подложки. */
.card-name { text-shadow: 0 0.4cqw 1.2cqw rgba(0, 0, 0, 0.85); }

/* Редкая карта получает свой холодный ободок: раньше отличались только
   эпическая и легендарная, и «редкая» ничем не отличалась от обычной. */
.card.rarity-2 {
  border-color: rgba(90, 169, 255, 0.5);
  box-shadow: 0 0 10px -2px rgba(90, 169, 255, 0.35), 0 6px 14px rgba(0, 0, 0, 0.45);
}
.card.rarity-3 {
  border-color: rgba(195, 123, 255, 0.55);
}

/* Портрет карты чуть контрастнее: арт генерировался под тёмную рамку. */
.card-art img, .minion .card-art img { filter: saturate(1.08) contrast(1.04); }

/* Существо на столе: выбранное поднимается и светится своим классом. */
body.in-battle .minion.selected {
  box-shadow:
    0 0 0 2px color-mix(in srgb, var(--accent, #0a84ff) 90%, transparent),
    0 0 22px -4px color-mix(in srgb, var(--accent, #0a84ff) 95%, transparent),
    0 8px 18px rgba(40, 28, 12, 0.55);
}

/* Кнопки и блоки объявлены через display: flex, и атрибут hidden их не
   прячет — правило возвращает ему силу. */
[hidden] { display: none !important; }

/* ---------------- 17. Витрина и сообщество ----------------

   Товары за голоса и ОКи стоят под свитком: сначала игрок видит, что можно
   получить бесплатно (ролик, задания, подписка), и только потом — за деньги.
   Витрина намеренно спокойная: ярче остального интерфейса ей быть незачем. */

.shop { margin-top: 22px; }
.shop-title {
  margin: 0 0 10px;
  font-size: var(--fs-15, 15px); font-weight: 700; letter-spacing: -0.01em;
  color: var(--text-1, #f5f5f7);
}
.shop-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 10px;
}
.shop-item {
  position: relative;
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  border-radius: var(--radius-md, 16px);
  border: 1px solid var(--hairline, rgba(255, 255, 255, 0.1));
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.02));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
  color: var(--text-1, #f5f5f7);
  text-align: left;
  cursor: pointer;
  transition: transform 0.16s cubic-bezier(0.2, 0.8, 0.3, 1), box-shadow 0.2s ease, border-color 0.2s ease;
}
.shop-item:hover {
  transform: translateY(-2px);
  border-color: rgba(242, 193, 78, 0.4);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 14px 26px -16px rgba(0, 0, 0, 0.9);
}
.shop-item:active { transform: translateY(0) scale(0.995); }
.shop-item:disabled { opacity: 0.5; pointer-events: none; }
.shop-item-icon {
  flex: 0 0 auto;
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: 12px;
  background: rgba(242, 193, 78, 0.14);
  border: 1px solid rgba(242, 193, 78, 0.25);
  color: var(--gold-1, #f2c14e);
}
.shop-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.shop-item-title { font-size: var(--fs-15, 15px); font-weight: 700; }
.shop-item-note { font-size: var(--fs-12, 12px); color: var(--text-3, #7c7c82); }
/* Цена — число крупно, валюта площадки мелко под ним. */
.shop-item-price {
  flex: 0 0 auto;
  display: flex; flex-direction: column; align-items: center;
  min-width: 58px;
  font-size: var(--fs-20, 20px); font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--gold-1, #f2c14e);
  line-height: 1.05;
}
.shop-item-price i {
  font-style: normal;
  font-size: 10px; font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-3, #7c7c82);
}
.shop-item-best { border-color: rgba(242, 193, 78, 0.35); }
.shop-item-flag {
  position: absolute; top: -8px; right: 12px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--gold-1, #f2c14e);
  color: #1c1c1e;
  font-size: 10px; font-weight: 700; letter-spacing: 0.03em;
  text-transform: uppercase;
}
.shop-note { margin: 10px 2px 0; font-size: var(--fs-12, 12px); color: var(--text-3, #7c7c82); }

/* Блок подписки: единственное место, где игре что-то нужно от игрока. */
.community {
  display: flex; align-items: center; gap: 12px;
  margin-top: 16px;
  padding: 14px;
  border-radius: var(--radius-md, 16px);
  border: 1px solid color-mix(in srgb, var(--accent, #0a84ff) 30%, transparent);
  background:
    radial-gradient(70% 140% at 0% 50%, color-mix(in srgb, var(--accent, #0a84ff) 16%, transparent), transparent 70%),
    linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.02));
}
.community-icon {
  flex: 0 0 auto;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border-radius: 12px;
  background: color-mix(in srgb, var(--accent, #0a84ff) 20%, transparent);
  color: color-mix(in srgb, var(--accent, #0a84ff) 70%, #fff);
}
.community-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.community-title { font-size: var(--fs-15, 15px); font-weight: 700; }
.community-text { font-size: var(--fs-12, 12px); color: var(--text-2, #a8a8ad); }
.community-text b { color: var(--text-1, #f5f5f7); }
.community-actions { flex: 0 0 auto; display: flex; gap: 8px; }

@media (max-width: 520px) {
  .community { flex-wrap: wrap; }
  .community-actions { width: 100%; }
  .community-actions .fbtn { flex: 1; }
}

/* ---------------- 18. Читаемость текста на арте ----------------

   Арт стал заметнее (подложки режимов, баннеры стихий), и приглушённый текст
   на нём поплыл: серый `--text-3` на светлом баннере Волны или Листвы почти
   не виден. Правило простое: если под текстом может оказаться картинка, у
   него либо своя тёмная подложка, либо тень — цвета одного мало.

   Не «сделать весь текст белым»: тогда пропадает иерархия, ради которой
   вторичный текст и приглушают. */

/* Тело карточки госпожи стоит на собственном затемнении, а не на баннере. */
.leader-body {
  background: linear-gradient(180deg, rgba(8, 8, 10, 0.62), rgba(8, 8, 10, 0.88) 45%);
}
.leader-lore { color: var(--text-2, #a8a8ad); }
.leader-flag {
  color: var(--text-2, #a8a8ad);
  border-top-color: rgba(255, 255, 255, 0.12);
}
.leader-power { background: rgba(0, 0, 0, 0.42); }
/* Имя и звание лежат прямо на портрете — им нужна тень, а не подложка. */
.leader-name { text-shadow: 0 2px 14px rgba(0, 0, 0, 0.95), 0 0 4px rgba(0, 0, 0, 0.8); }
.leader-title { text-shadow: 0 1px 10px rgba(0, 0, 0, 0.9); }
.elem-chip { text-shadow: 0 1px 6px rgba(0, 0, 0, 0.8); }

/* Плитки разделов: подпись и заметка лежат поверх подложки режима. */
.row-sub, .row-note, .row-title, .progress-count {
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.9);
}
.row-note { color: var(--text-2, #a8a8ad); }
.row-sub { color: #bcbcc2; }

/* Панель героини: лор и подпись стоят на баннере стихии. */
.char-lore { color: var(--text-2, #a8a8ad); text-shadow: 0 1px 8px rgba(0, 0, 0, 0.9); }
.char-title, .char-name { text-shadow: 0 2px 12px rgba(0, 0, 0, 0.85); }

/* Арена: описание забега лежит на баннере с искрами. */
.arena-banner-sub { color: #c8c8ce; text-shadow: 0 1px 8px rgba(0, 0, 0, 0.9); }
.arena-banner-title { text-shadow: 0 2px 12px rgba(0, 0, 0, 0.9); }

/* Ступени кампании: портрет соперницы светлый, а текст рядом — серый. */
.stage-text { color: #9a9aa2; }

/* Стол боя стал жёлтым, и светлая подсказка на нём пропала. */
body.in-battle .board-player.empty::after {
  color: rgba(52, 38, 18, 0.7);
  text-shadow: 0 1px 0 rgba(255, 240, 200, 0.25);
}
body.in-battle .hero-name {
  color: #e8dcc0;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.95);
}

/* ---------------- 19. Обучение ----------------

   Затемнение с «дырой» над подсвеченным местом: сам элемент не двигается и
   не копируется, поэтому подсказка не может разойтись с интерфейсом. Слой
   не ловит нажатия — играть во время подсказки можно, и это важно: обучение
   ждёт действия, а не заменяет его. */

.tut {
  position: absolute; inset: 0;
  z-index: 60;
  pointer-events: none;
}

.tut-hole {
  position: absolute;
  border-radius: 16px;
  border: 2px solid color-mix(in srgb, var(--accent, #0a84ff) 85%, #fff);
  box-shadow:
    0 0 0 9999px rgba(4, 4, 6, 0.62),
    0 0 24px -2px color-mix(in srgb, var(--accent, #0a84ff) 90%, transparent);
  animation: tut-pulse 2.2s ease-in-out infinite;
}
@keyframes tut-pulse {
  0%, 100% { border-color: color-mix(in srgb, var(--accent, #0a84ff) 55%, #fff); }
  50%      { border-color: color-mix(in srgb, var(--accent, #0a84ff) 95%, #fff); }
}

.tut-tip {
  position: absolute;
  left: 50%; bottom: 22%;
  transform: translateX(-50%);
  width: min(340px, calc(100% - 32px));
  display: flex; flex-direction: column; gap: 6px;
  padding: 14px 16px;
  border-radius: 18px;
  border: 1px solid var(--hairline-strong, rgba(255, 255, 255, 0.16));
  background: rgba(24, 22, 26, 0.94);
  box-shadow: 0 20px 44px -18px rgba(0, 0, 0, 0.95);
  pointer-events: auto;      /* кнопки должны нажиматься */
  animation: tut-in 0.24s cubic-bezier(0.2, 0.9, 0.3, 1.1);
}
/* Если подсвечено что-то внизу экрана (рука, кнопка хода) — подсказка уходит вверх. */
.tut-tip-top { bottom: auto; top: 14%; }

@keyframes tut-in {
  from { opacity: 0; transform: translate(-50%, 10px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

.tut-step {
  font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  color: color-mix(in srgb, var(--accent, #0a84ff) 65%, #fff);
  font-variant-numeric: tabular-nums;
}
.tut-title { font-size: var(--fs-17, 17px); font-weight: 700; color: #f5f5f7; }
.tut-text { font-size: var(--fs-13, 13px); line-height: 1.4; color: #c4c4ca; }
.tut-actions { display: flex; gap: 8px; margin-top: 6px; }
.tut-actions .fbtn, .tut-actions .btn { flex: 0 0 auto; }
.tut-actions [data-role="skip"] { margin-left: auto; }

@media (prefers-reduced-motion: reduce) {
  .tut-hole, .tut-tip { animation: none; }
}
