/* ══════════════════════════════════════════════════════════
   МОДАЛКИ И ОВЕРЛЕИ · Pixel Wars
   Продолжение theme.css. Подключать ПОСЛЕ него.

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

   Что чинилось по существу, а не ради красоты:

   1. ИЕРАРХИЯ. В окне предмета четыре кнопки стояли сеткой 2×2
      одинакового веса: «Надеть» ничем не отличалась от «Разобрать».
      Теперь главное действие занимает всю ширину и залито золотом,
      разрушающее — тихое, серое, с красной подписью.

   2. ИМЯ ПРЕДМЕТА — главное на экране, а было 16px наравне с
      остальным. Поднято до 24px (сетка Tiny5, 3×8). Побочный
      выигрыш: цвет редкости приходит инлайном из RARITIES в
      data.js, и эпический #9b59b6 давал на карточке контраст 4.0
      при норме 4.5 для мелкого. На 24px порог по WCAG — 3.0,
      его проходят все шесть редкостей (минимум 4.02).

   3. РЕЗУЛЬТАТ ЗАТОЧКИ был тремя строками текста, висящими в
      пустоте: ни рамки, ни карточки, ни фокуса. Ради этого окна
      игрок тратит золото и рискует вещью — оно получило гнездо
      с лучами, ленту-плашку под заголовок и разбег анимаций.

   4. КЕГЛИ НИЖЕ СЕТКИ. На экране выбора персонажа было 7px
      (названия навыков), 8px (заголовки разделов), 9px (подписи
      шкал, признаки, описание перка). Всё поднято минимум до 10.
      Длинное описание перка переведено на системный шрифт —
      кириллица в пиксельных 9px не читалась.

   5. ПОДЛОЖКА. Все оверлеи заливались одинаковым rgba(0,0,0,.88).
      Плоская чёрная плёнка не отделяет окно от экрана, а просто
      гасит его. Заменена на радиальную с размытием: центр светлее,
      края глуше — взгляд сам идёт в середину.

   Цвета берутся только из theme.css. Новых нет: где нужен
   оттенок — color-mix от существующего.
   ══════════════════════════════════════════════════════════ */


/* ══════════════════════════════════════════════════════════
   1 · ОБЩЕЕ ДЛЯ ОВЕРЛЕЕВ
   ══════════════════════════════════════════════════════════ */

/* Подложка. Светлее в центре — там окно, туда и смотрим.
   Размытие слабое: сильное съедает пиксельную сетку фона и
   на телефоне заметно греет. */
#itemModal,
#refineOverlay,
.offl-modal,
.death-modal,
.sell-modal,
.market-unlock-modal,
.conn-overlay {
  background:
    radial-gradient(120% 90% at 50% 45%,
      rgba(30,26,50,0.60) 0%,
      rgba(7,6,13,0.93) 60%,
      rgba(4,3,8,0.97) 100%);
  -webkit-backdrop-filter: blur(2px) saturate(0.7);
          backdrop-filter: blur(2px) saturate(0.7);
}

#itemModal.show,
#refineOverlay.show,
.offl-modal:not(.hidden),
.death-modal:not(.hidden),
.sell-modal:not(.hidden),
.market-unlock-modal:not(.hidden) {
  animation: mdlScrim 0.18s ease-out both;
}

@keyframes mdlScrim { from { opacity: 0; } to { opacity: 1; } }

/* Появление окна: короткий подъём с лёгким перелётом.
   Перелёт маленький (1.12 по кривой) — большой на пиксельной
   графике читается как «резина». */
@keyframes mdlPop {
  from { opacity: 0; transform: translateY(10px) scale(0.965); }
  to   { opacity: 1; transform: translateY(0)    scale(1); }
}
@keyframes mdlSheetUp {
  from { transform: translateY(26px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}
@keyframes mdlRise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Общая фактура окна-диалога. Собрана из тех же слоёв, что и
   .panel в theme.css: зерно, блик сверху, тёмный низ. */
.offl-box,
.death-modal-box,
.sell-box,
.market-unlock-box,
.conn-overlay-box {
  position: relative;
  border-radius: var(--r-lg);
  border: 1px solid var(--line-strong);
  background:
    var(--grain),
    var(--sheen),
    radial-gradient(130% 70% at 50% -8%, var(--acc-wash, rgba(143,111,212,0.16)), transparent 62%),
    linear-gradient(180deg, #191627 0%, #0c0a14 100%);
  background-blend-mode: overlay, normal, normal, normal;
  background-size: 120px 120px, auto, auto, auto;
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,0.04),
    0 0 0 1px #07060d,
    0 18px 44px rgba(0,0,0,0.62);
  animation: mdlPop 0.24s cubic-bezier(.2,.9,.3,1) both;
}

/* Уголки-засечки, как на карточках в theme.css: четыре коротких
   штриха цветом акцента окна. */
.offl-box::after,
.death-modal-box::after,
.sell-box::after,
.market-unlock-box::after {
  content: '';
  position: absolute; inset: 4px;
  pointer-events: none;
  --acc: var(--line-strong);
  background:
    linear-gradient(var(--acc), var(--acc)) left  top    / 6px 1px no-repeat,
    linear-gradient(var(--acc), var(--acc)) left  top    / 1px 6px no-repeat,
    linear-gradient(var(--acc), var(--acc)) right top    / 6px 1px no-repeat,
    linear-gradient(var(--acc), var(--acc)) right top    / 1px 6px no-repeat,
    linear-gradient(var(--acc), var(--acc)) left  bottom / 6px 1px no-repeat,
    linear-gradient(var(--acc), var(--acc)) left  bottom / 1px 6px no-repeat,
    linear-gradient(var(--acc), var(--acc)) right bottom / 6px 1px no-repeat,
    linear-gradient(var(--acc), var(--acc)) right bottom / 1px 6px no-repeat;
  opacity: 0.7;
}

/* Заголовок окна: второй шрифт, без разрядки, с чертой под ним.
   Черта — тот же приём, что у .sec-title в theme.css. */
.offl-header,
.death-modal-title,
.sell-title,
.market-unlock-title {
  font-family: var(--font-ui) !important;
  font-weight: 400;
  letter-spacing: 0 !important;
  line-height: 1.2;
  text-shadow: 0 2px 0 rgba(0,0,0,0.75);
}


/* ══════════════════════════════════════════════════════════
   2 · ОКНО ПРЕДМЕТА
   Нижняя шторка. Порядок чтения сверху вниз: что за вещь →
   что она даёт → с чем сравниваем → что можно сделать.
   ══════════════════════════════════════════════════════════ */

#itemModalCard {
  position: relative;
  max-width: 440px;

  /* Порядок чтения. В разметке блок «что на тебе сейчас» стоит
     ВЫШЕ характеристик открытой вещи, и получалось, что сразу под
     именем предмета идут чужие числа. Между тем стрелки ▲+66 в
     характеристиках как раз и есть сравнение с надетым — значит
     сначала вещь, потом то, с чем её сравнивают. Меняем местами
     раскладкой, не трогая разметку. */
  display: flex;
  flex-direction: column;
  /* Высоких вещей (стат + сравнение с надетым + четыре кнопки)
     раньше не хватало на экран, и нижние кнопки уезжали за край.
     Ограничиваем высоту и разрешаем прокрутку внутри шторки. */
  max-height: 86vh;
  overflow-y: auto;
  overscroll-behavior: contain;

  padding: 20px var(--sp-4) calc(var(--sp-5) + env(safe-area-inset-bottom, 0px));
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  border: 1px solid var(--line-strong);
  border-bottom: none;
  border-top-color: color-mix(in srgb, var(--gold-dim) 55%, var(--line-strong));

  /* Хват-полоска нарисована фоном, а не элементом: у шторки есть
     собственная прокрутка, и псевдоэлемент уезжал бы вместе с
     содержимым, а фон привязан к рамке. */
  background:
    linear-gradient(var(--line-strong), var(--line-strong)) 50% 8px / 40px 3px no-repeat,
    var(--grain),
    var(--sheen),
    radial-gradient(120% 42% at 50% 0%, rgba(245,197,66,0.09), transparent 60%),
    var(--vign),
    linear-gradient(180deg, #1a1729 0%, #0e0c17 100%);
  background-blend-mode: normal, overlay, normal, normal, normal, normal;
  background-size: 40px 3px, 120px 120px, auto, auto, auto, auto;

  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.06),
    0 -2px 0 #07060d,
    0 -14px 34px rgba(0,0,0,0.6);
}

#itemModal.show #itemModalCard {
  animation: mdlSheetUp 0.22s cubic-bezier(.2,.9,.3,1) both;
}

/* Редкость открытой вещи. inventory.js вешает на карточку rarity-<id> — те же
   имена, что у плиток инвентаря в theme.css. Здесь редкость только объявлена
   переменными: сейчас окно рисуется одинаково для любой вещи, и менять это в
   рамках перевода на классы нельзя. Когда рамку и свечение решат красить под
   предмет — красить нужно через --rar / --rar-glow, а не через литерал цвета
   имени, как приходилось раньше. */
#itemModalCard.rarity-common   { --rar: var(--r-common);   --rar-glow: rgba(111,106,133,0.28); }
#itemModalCard.rarity-uncommon { --rar: var(--r-uncommon); --rar-glow: rgba(86,165,82,0.30); }
#itemModalCard.rarity-rare     { --rar: var(--r-rare);     --rar-glow: rgba(74,143,199,0.32); }
#itemModalCard.rarity-epic     { --rar: var(--r-epic);     --rar-glow: rgba(143,111,212,0.34); }
#itemModalCard.rarity-legend   { --rar: var(--r-legend);   --rar-glow: rgba(245,197,66,0.34); }
#itemModalCard.rarity-unique   { --rar: var(--r-unique);   --rar-glow: rgba(224,122,60,0.40); }

.modal-header  { order: 1; }
.modal-stats   { order: 2; }
#mEquipped     { order: 3; }
#mRefine       { order: 4; }
.modal-actions { order: 5; }

/* ── Шапка ── */
.modal-header {
  gap: var(--sp-3);
  align-items: center;
  margin-bottom: var(--sp-3);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line-soft);
}

/* Иконка — не голая картинка, а гнездо: фаска внутрь, свечение
   снизу, тёмный контур. Тот же язык, что у .inv-slot. */
.modal-icon {
  flex: 0 0 58px;
  width: 58px; height: 58px;
  display: flex; align-items: center; justify-content: center;
  font-size: 34px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background:
    radial-gradient(110% 90% at 50% 118%, rgba(143,111,212,0.26), transparent 68%),
    linear-gradient(180deg, #1e1a32 0%, #100e1a 100%);
  box-shadow: var(--bevel-in), 0 0 0 1px #07060d;
}
.modal-icon img { filter: drop-shadow(0 2px 3px rgba(0,0,0,0.7)); }

.modal-title { min-width: 0; }

/* Имя вещи — заголовок окна. 24px = 3 клетки сетки Tiny5.
   Цвет приходит инлайном из RARITIES, поэтому свечение берём
   currentColor: оно само подстроится под редкость. */
.modal-name {
  font-size: var(--fs-5);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: 0;
  overflow-wrap: anywhere;
  text-shadow: 0 0 16px currentColor, 0 2px 0 rgba(0,0,0,0.9);
}

/* Подпись «Легендарный · Боты». Пиксельный шрифт основной сетки:
   Tiny5 наследовался от .modal-title и на 10px мылился —
   его клетка 8px, десятка в неё не попадает. */
.modal-sub {
  font-family: var(--font);
  font-size: var(--fs-1);
  color: var(--text-3);
  margin-top: 5px;
  line-height: 1.4;
}

/* ── Сравнение с надетым ──
   Блок собирается инлайном в inventory.js и помечен там классом
   .equipped-compare. Раньше его брали как «единственный div внутри
   #mEquipped» — обёртка появилась бы, и оформление молча отвалилось.
   Отбиваем золотой гранью слева: «вот что на тебе сейчас» — это точка
   отсчёта, а не ещё одна карточка. */
#mEquipped { margin-bottom: 0; }
.equipped-compare {
  background: linear-gradient(180deg, #16131f 0%, #100e1a 100%) !important;
  border: 1px solid var(--line-soft) !important;
  border-left: 2px solid var(--gold-dim) !important;
  border-radius: var(--r-md) !important;
  padding: var(--sp-2) var(--sp-3) !important;
  margin-bottom: var(--sp-3) !important;
  box-shadow: var(--bevel-in);
}

/* ── Таблица характеристик ──
   Была голыми строками с полоской-разделителем прямо на фоне
   шторки. Стала утопленной панелью: у чисел появилась «своя»
   поверхность, и они перестали спорить с шапкой. */
.modal-stats {
  padding: 0 var(--sp-3);
  margin-bottom: var(--sp-3);
  border-radius: var(--r-md);
  border: 1px solid var(--line-soft);
  background: linear-gradient(180deg, #16131f 0%, #0f0d19 100%);
  box-shadow: var(--bevel-in), 0 0 0 1px #07060d;
}
.modal-stats:empty { display: none; }

.modal-stat-row {
  padding: 7px 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: var(--fs-1);
  color: var(--text-3);
  gap: var(--sp-3);
}
.modal-stat-row:last-child { border-bottom: none; }

/* Значение — светлое и спокойное. Было #4cf жирным: голубой
   кегль спорил с цветом редкости в шапке и с зелёными «+»
   в сравнении, из-за чего в окне было четыре акцента разом. */
.modal-stat-row > span:last-child {
  color: var(--text);
  font-weight: 400;
  text-align: right;
}
.modal-stat-row > span:first-child { flex: 1; min-width: 0; }

/* ── Заточка ── */
.refine-info {
  margin: 0 0 var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  border-color: color-mix(in srgb, var(--magic) 34%, var(--line));
  background:
    linear-gradient(180deg, rgba(162,136,224,0.13) 0%, rgba(162,136,224,0.03) 100%);
  box-shadow: var(--bevel);
  font-size: var(--fs-1);
  color: var(--text-3);
}
.refine-stars {
  color: var(--magic);
  font-size: var(--fs-2);
  letter-spacing: 1px;
  text-shadow: 0 0 8px rgba(162,136,224,0.45);
}
.refine-chance {
  color: var(--gold);
  font-weight: 400;
  font-size: var(--fs-2);
}

/* ── Кнопки ──
   Главное действие («Надеть» / «Снять») занимает всю ширину и
   залито золотом — так его видно первым. Остальное остаётся
   сеткой 2×2 и держит обводку по смыслу. */
.modal-actions {
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}

.modal-btn {
  padding: 13px 8px;
  font-size: var(--fs-2);
  letter-spacing: 0;
  font-weight: 400;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-strong);
  background:
    var(--sheen),
    linear-gradient(180deg, #2a2442 0%, #191630 100%);
  color: var(--text-2);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.09), 0 2px 0 #07060d;
  text-shadow: 0 1px 0 rgba(0,0,0,0.6);
  transition: filter .12s;
}
.modal-btn:active {
  transform: translateY(2px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05), 0 0 0 #07060d;
  filter: brightness(1.08);
}

.modal-btn.equip,
.modal-btn.unequip { grid-column: 1 / -1; }

.modal-btn.equip {
  border-color: var(--gold-dim);
  color: #1a1405;
  background:
    linear-gradient(180deg, rgba(255,255,255,0.30) 0%, rgba(255,255,255,0) 45%),
    linear-gradient(180deg, #f0bd3c 0%, #c2911f 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.45),
    0 2px 0 #6b4f0e,
    0 0 14px var(--gold-glow);
  text-shadow: 0 1px 0 rgba(255,255,255,0.28);
}

/* Главное действие набирается вдвое крупнее прочих: 20px — две
   клетки сетки Ark Pixel, цифры и буквы остаются резкими. */
.modal-btn.equip,
.modal-btn.unequip {
  font-size: var(--fs-3);
  padding: 12px 8px;
}

.modal-btn.unequip {
  border-color: color-mix(in srgb, var(--danger) 55%, var(--line-strong));
  color: var(--danger);
  background:
    var(--sheen),
    linear-gradient(180deg, rgba(228,104,92,0.16) 0%, rgba(228,104,92,0.05) 100%);
}

.modal-btn.refine {
  border-color: var(--magic);
  color: var(--magic);
  background:
    var(--sheen),
    linear-gradient(180deg, rgba(162,136,224,0.22) 0%, rgba(162,136,224,0.07) 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08), 0 2px 0 #07060d, 0 0 12px rgba(162,136,224,0.2);
}

/* Разбор — действие необратимое, но не главное. Тихая кнопка с
   красной подписью: заметить можно, промахнуться мимо «Надеть»
   уже нельзя. */
.modal-btn.destroy {
  border-color: var(--line);
  color: color-mix(in srgb, var(--danger) 70%, var(--text-3));
  background: linear-gradient(180deg, #191527 0%, #120f1e 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04), 0 2px 0 #07060d;
}

.modal-btn:disabled {
  filter: grayscale(0.7) brightness(0.62);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
  transform: none;
}

/* ── Кнопки, которые пока красит инлайн ──
   «Продать», «Эволюция» и «Снять руну» собираются в inventory.js вместе с
   цветом прямо в атрибуте style, поэтому до оформления .modal-btn у них
   доходят только кегль, отбивка и тень — заливку и рамку задаёт инлайн.
   Теперь у каждой есть свой класс, и правила ниже описывают их палитрой темы.
   Инлайн пока сильнее (снимать его — отдельная работа, и вид сейчас меняться
   не должен), но как только он уйдёт, цвета возьмутся отсюда, а не из
   литералов в JS. Оттенки подобраны в тон соседям: продажа звучит как
   .sell-confirm-btn, эволюция — как .refine, снятие руны — как .destroy. */
.modal-btn.sell {
  border-color: color-mix(in srgb, var(--success) 70%, var(--line-strong));
  color: var(--success);
  background:
    var(--sheen),
    linear-gradient(180deg, rgba(86,165,82,0.20) 0%, rgba(86,165,82,0.06) 100%);
}

.modal-btn.evolve {
  border-color: var(--magic);
  color: var(--magic);
  background:
    var(--sheen),
    linear-gradient(180deg, rgba(162,136,224,0.20) 0%, rgba(162,136,224,0.06) 100%);
}

.modal-btn.rune-off {
  border-color: color-mix(in srgb, var(--danger) 60%, var(--line-strong));
  color: var(--danger);
  background:
    var(--sheen),
    linear-gradient(180deg, rgba(228,104,92,0.14) 0%, rgba(228,104,92,0.04) 100%);
}

/* Вещь чужого класса: кнопка на месте, но надеть нельзя. Отдельно от :disabled —
   там причина техническая («ждём ответа», «нечем платить»), а тут смысловая, и
   красить их со временем будут по-разному. Заливку не трогаем: у книги чужого
   класса её в инлайне нет, и любое значение здесь сразу изменило бы вид. */
.modal-btn.is-locked {
  border-color: var(--line);
  color: var(--text-4);
}


/* ══════════════════════════════════════════════════════════
   3 · РЕЗУЛЬТАТ ЗАТОЧКИ
   Единственный экран, ради которого игрок рискует вещью.
   Было: три строки текста в пустоте. Стало: гнездо с лучами,
   лента-плашка под заголовком, подпись — и разбег во времени,
   чтобы взгляд шёл иконка → итог → подробности.
   ══════════════════════════════════════════════════════════ */

#refineOverlay {
  gap: 0;
  padding: var(--sp-5);
}

/* Мягкий свет за всей группой */
#refineOverlay.show::before {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  width: 460px; height: 460px;
  margin: -230px 0 0 -230px;
  pointer-events: none;
  background: radial-gradient(circle, rgba(143,111,212,0.20) 0%, transparent 62%);
  animation: mdlScrim 0.5s ease-out both;
}

/* Гнездо для значка */
.refine-result-icon {
  position: relative;
  width: 112px; height: 112px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-lg);
  border: 1px solid var(--line-strong);
  background:
    radial-gradient(80% 80% at 50% 50%, rgba(255,255,255,0.05), transparent 70%),
    linear-gradient(180deg, #1d1932 0%, #0c0a15 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.08),
    0 0 0 1px #07060d,
    0 10px 28px rgba(0,0,0,0.6);
  animation: mdlIconPop 0.42s cubic-bezier(.2,1.1,.35,1) both;
}
@keyframes mdlIconPop {
  0%   { transform: scale(0.55) rotate(-4deg); opacity: 0; }
  62%  { transform: scale(1.08) rotate(0deg);  opacity: 1; }
  100% { transform: scale(1)    rotate(0deg);  opacity: 1; }
}

/* Лучи вокруг гнезда. Маска вырезает середину, поэтому лучи идут
   кольцом и не ложатся на сам значок. Держим их еле заметными:
   яркие спицы на тёмном читаются как клипарт «солнышко». */
.refine-result-icon::after {
  content: '';
  position: absolute; inset: -30px;
  pointer-events: none;
  background: repeating-conic-gradient(from 0deg,
    rgba(255,255,255,0.09) 0deg 1.5deg,
    transparent 1.5deg 11deg);
  filter: blur(0.6px);
  -webkit-mask: radial-gradient(circle, transparent 45%, #000 57%, #000 68%, transparent 78%);
          mask: radial-gradient(circle, transparent 45%, #000 57%, #000 68%, transparent 78%);
  animation: mdlRays 16s linear infinite, mdlScrim 0.8s 0.15s ease-out both;
}
@keyframes mdlRays { to { transform: rotate(360deg); } }

/* Удар в момент появления: кольцо расходится от гнезда и гаснет.
   Один раз — повтор превратил бы окно в мигалку. */
.refine-result-icon::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: var(--r-lg);
  border: 1px solid var(--text-2);
  pointer-events: none;
  animation: mdlShock 0.7s 0.06s cubic-bezier(.1,.7,.3,1) both;
}
@keyframes mdlShock {
  0%   { opacity: 0;    transform: scale(0.7); }
  25%  { opacity: 0.75; }
  100% { opacity: 0;    transform: scale(1.85); }
}

/* Итог — лента. Полоски сверху и снизу набраны currentColor,
   то есть цветом результата: удача фиолетовая, поломка красная,
   «мало золота» золотая. Одна строка CSS вместо ветвления в JS. */
.refine-result-text {
  position: relative;
  margin-top: var(--sp-4);
  padding: var(--sp-2) var(--sp-4);
  max-width: 320px;
  text-align: center;
  font-family: var(--font-ui);
  font-size: var(--fs-5);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.15;
  text-shadow: 0 0 18px currentColor, 0 2px 0 rgba(0,0,0,0.9);
  background:
    linear-gradient(90deg, transparent, currentColor 22%, currentColor 78%, transparent) 0 0    / 100% 1px no-repeat,
    linear-gradient(90deg, transparent, currentColor 22%, currentColor 78%, transparent) 0 100% / 100% 1px no-repeat,
    linear-gradient(90deg, transparent, rgba(6,5,12,0.88) 14%, rgba(6,5,12,0.88) 86%, transparent);
  animation: mdlRise 0.34s 0.10s cubic-bezier(.2,.9,.3,1) both;
}

/* Подпись — длинная фраза, поэтому системный шрифт: пиксельная
   кириллица в 10px на «щ» и «ж» вырождается (правило из theme.css
   для .craft-desc, здесь тот же случай). */
.refine-result-sub {
  margin-top: var(--sp-3);
  max-width: 300px;
  text-align: center;
  text-wrap: balance;
  font-family: -apple-system, 'Segoe UI', Roboto, sans-serif;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.1px;
  color: var(--text-2);
  animation: mdlRise 0.34s 0.18s cubic-bezier(.2,.9,.3,1) both;
}


/* ══════════════════════════════════════════════════════════
   4 · ОКНО ОФЛАЙН-НАГРАДЫ
   Игрок вернулся и что-то получил. Значит, главное здесь —
   числа и кнопка «Забрать», а не заголовок.
   ══════════════════════════════════════════════════════════ */

.offl-box {
  --acc-wash: rgba(74,143,199,0.18);
  width: 86%; max-width: 320px;
  padding: var(--sp-5) var(--sp-4) var(--sp-4);
  gap: var(--sp-3);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,0.04),
    0 0 0 1px #07060d,
    0 18px 44px rgba(0,0,0,0.62),
    0 0 40px rgba(74,143,199,0.16);
}
.offl-box::after { --acc: var(--info); }

.offl-header {
  font-size: var(--fs-4);
  color: var(--info);
  text-shadow: 0 0 12px rgba(74,143,199,0.45), 0 2px 0 rgba(0,0,0,0.75);
}
/* Черта под заголовком: гасит к краям, как у .sec-title */
.offl-header::after {
  content: '';
  display: block;
  height: 1px;
  margin-top: var(--sp-2);
  background: linear-gradient(90deg, transparent, var(--info), transparent);
  opacity: 0.55;
}

.offl-time {
  font-family: var(--font);
  font-size: var(--fs-1);
  color: var(--text-3);
  line-height: 1.5;
}

/* Утопленная панель под числами */
.offl-rewards {
  gap: 0;
  padding: 0 var(--sp-3);
  border-radius: var(--r-md);
  border: 1px solid var(--line-soft);
  background: linear-gradient(180deg, #100e1a 0%, #0a0812 100%);
  box-shadow: var(--bevel-in), 0 0 0 1px #07060d;
}
.offl-row {
  padding: 8px 0;
  border-bottom: 1px solid var(--line-soft);
  font-family: var(--font);
  font-size: var(--fs-1);
  gap: var(--sp-3);
}
.offl-row:last-child { border-bottom: none; }
.offl-row span:first-child {
  color: var(--text-3);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Число крупнее подписи вдвое — это и есть награда.
   20px = две клетки сетки Ark Pixel, цифры остаются резкими. */
.offl-row span:last-child {
  font-size: var(--fs-3);
  font-weight: 400;
  line-height: 1;
  white-space: nowrap;
  flex: 0 0 auto;
  text-shadow: 0 2px 0 rgba(0,0,0,0.8);
}
.offl-row--gold span:last-child { color: var(--gold); }
.offl-row--xp   span:last-child { color: var(--info); }
.offl-row--pixr span:last-child { color: var(--pixr); }

/* Забрать — главное действие, значит золото.
   Кегль 20, а не 16: theme.css принудительно ставит кнопкам
   основной шрифт (`button { font-family: var(--font) !important }`),
   а у Ark Pixel клетка 10px — шестнадцать в неё не попадают и
   надпись мылится. Двадцать — ровно две клетки. */
.offl-claim-btn {
  padding: 13px;
  border-radius: var(--r-sm);
  border: 1px solid var(--gold-dim);
  font-size: var(--fs-3);
  font-weight: 400;
  letter-spacing: 0;
  color: #1a1405;
  background:
    linear-gradient(180deg, rgba(255,255,255,0.30) 0%, rgba(255,255,255,0) 45%),
    linear-gradient(180deg, #f0bd3c 0%, #c2911f 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.45),
    0 2px 0 #6b4f0e,
    0 0 16px var(--gold-glow);
  text-shadow: 0 1px 0 rgba(255,255,255,0.28);
  transition: filter .12s;
}
.offl-claim-btn:active {
  transform: translateY(2px) scale(1);
  opacity: 1;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.3), 0 0 0 #6b4f0e;
  filter: brightness(1.06);
}
.offl-claim-btn:disabled {
  filter: grayscale(0.7) brightness(0.62);
  transform: none;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
}


/* ══════════════════════════════════════════════════════════
   5 · ПОДТВЕРЖДЕНИЯ
   Смерть, продажа, разблокировка рынка. Один каркас, разный
   акцент: красный — потеря, зелёный — сделка.
   ══════════════════════════════════════════════════════════ */

/* ── Смерть ── */
.death-modal-box {
  --acc-wash: rgba(228,104,92,0.20);
  width: 84%; max-width: 310px;
  padding: var(--sp-5) var(--sp-4) var(--sp-4);
  gap: var(--sp-3);
  border-color: color-mix(in srgb, var(--danger) 45%, var(--line-strong));
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,0.04),
    0 0 0 1px #07060d,
    0 18px 44px rgba(0,0,0,0.62),
    0 0 44px rgba(228,104,92,0.20);
}
.death-modal-box::after { --acc: var(--danger); }

.death-modal-skull { font-size: 52px; filter: drop-shadow(0 4px 8px rgba(0,0,0,0.7)); }

.death-modal-title {
  font-size: var(--fs-5);
  color: var(--danger);
  text-shadow: 0 0 16px rgba(228,104,92,0.5), 0 2px 0 rgba(0,0,0,0.85);
}

.death-modal-penalty {
  font-family: -apple-system, 'Segoe UI', Roboto, sans-serif;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-2);
  background-image: none;
}

/* Возрождение — единственная кнопка в игре со светлой надписью на
   тёмной заливке. Это сознательная разница: золотые и зелёные
   кнопки означают выигрыш, у них яркая заливка и тёмный текст;
   красная означает потерю и звучит глуше.
   Замер: #ffe0dc на градиенте #a8382e → #6e2019 даёт 5.2 в самом
   светлом месте. Обратная пара (тёмный текст на ярко-красном)
   в нижней части градиента давала 2.9 и не проходила. */
.death-revive-btn {
  padding: 13px;
  border-radius: var(--r-sm);
  border: 1px solid color-mix(in srgb, var(--danger) 62%, #000);
  font-size: var(--fs-3);
  font-weight: 400;
  letter-spacing: 0;
  color: #ffe0dc;
  background:
    linear-gradient(180deg, rgba(255,255,255,0.14) 0%, rgba(255,255,255,0) 45%),
    linear-gradient(180deg, #a8382e 0%, #6e2019 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.22),
    0 2px 0 #3a0d0a,
    0 0 16px rgba(228,104,92,0.24);
  text-shadow: 0 1px 0 rgba(0,0,0,0.55);
}
.death-revive-btn:active {
  transform: translateY(2px) scale(1);
  opacity: 1;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.16), 0 0 0 #3a0d0a;
}

/* ── Выставить на продажу ── */
.sell-box,
.market-unlock-box {
  --acc-wash: rgba(86,165,82,0.18);
  border-color: color-mix(in srgb, var(--success) 40%, var(--line-strong));
}
.sell-box::after,
.market-unlock-box::after { --acc: var(--success); }

.sell-title,
.market-unlock-title {
  font-size: var(--fs-4);
  color: var(--success);
  text-shadow: 0 0 12px rgba(86,165,82,0.4), 0 2px 0 rgba(0,0,0,0.75);
  margin-bottom: var(--sp-3);
}
.sell-title::after,
.market-unlock-title::after {
  content: '';
  display: block;
  height: 1px;
  margin-top: var(--sp-2);
  background: linear-gradient(90deg, transparent, var(--success), transparent);
  opacity: 0.5;
}

.sell-item-preview {
  border-radius: var(--r-md);
  border: 1px solid var(--line-soft);
  background: linear-gradient(180deg, #16131f 0%, #0f0d19 100%);
  box-shadow: var(--bevel-in);
  padding: var(--sp-3);
}

.sell-price-input {
  /* Без min-width:0 поле типа number не сжимается ниже своей
     «естественной» ширины, и на кегле 20 оно вылезало из окна
     вместе со значком PIXR. */
  min-width: 0;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #0a0812 0%, #100e1a 100%);
  box-shadow: var(--bevel-in);
  color: var(--pixr);
  font-family: var(--font);
  font-size: var(--fs-3);
  padding: 8px 10px;
}
.sell-price-input:focus {
  border-color: var(--success);
  box-shadow: var(--bevel-in), 0 0 0 1px rgba(86,165,82,0.35);
}
.sell-price-input::placeholder { color: var(--text-4); font-size: var(--fs-1); }

.sell-commission-note {
  font-size: var(--fs-1);
  color: var(--text-3);
}

.sell-confirm-btn,
.market-unlock-btn {
  padding: 13px 8px;
  border-radius: var(--r-sm);
  border: 1px solid color-mix(in srgb, var(--success) 70%, #000);
  font-size: var(--fs-2);
  font-weight: 400;
  letter-spacing: 0;
  /* Замер: #05170a на #7ccf77 → 9.8, на #56a552 (низ градиента)
     → 6.1. Прежний, более тёмный градиент давал внизу 3.7. */
  color: #05170a;
  background:
    linear-gradient(180deg, rgba(255,255,255,0.26) 0%, rgba(255,255,255,0) 45%),
    linear-gradient(180deg, #7ccf77 0%, #56a552 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.40),
    0 2px 0 #1d4a1c;
  text-shadow: 0 1px 0 rgba(255,255,255,0.2);
}
.sell-confirm-btn:active,
.market-unlock-btn:active {
  transform: translateY(2px) scale(1);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.26), 0 0 0 #1d4a1c;
}

/* Отмена — тихая. Кнопка отказа не должна ловить палец. */
.sell-cancel-btn,
.market-unlock-close {
  padding: 13px 8px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #191527 0%, #120f1e 100%);
  color: var(--text-3);
  font-size: var(--fs-2);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04), 0 2px 0 #07060d;
}
.sell-cancel-btn:active,
.market-unlock-close:active {
  transform: translateY(2px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.03), 0 0 0 #07060d;
}

/* ── Разблокировка рынка ── */
.market-unlock-icon { filter: drop-shadow(0 4px 8px rgba(0,0,0,0.6)); }
.market-unlock-desc {
  font-family: -apple-system, 'Segoe UI', Roboto, sans-serif;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-2);
  background-image: none;
}
.market-unlock-cost {
  font-family: var(--font);
  font-size: var(--fs-3);
  font-weight: 400;
  color: var(--pixr);
  text-shadow: 0 0 12px rgba(224,85,184,0.35), 0 2px 0 rgba(0,0,0,0.8);
}

/* ── Потеря связи ── */
.conn-overlay-box {
  --acc-wash: rgba(228,104,92,0.16);
  padding: var(--sp-5) var(--sp-4);
  border-color: color-mix(in srgb, var(--danger) 35%, var(--line-strong));
}
.conn-overlay-title {
  font-family: var(--font-ui) !important;
  font-size: var(--fs-4);
  font-weight: 400;
  letter-spacing: 0 !important;
  color: var(--danger);
  text-shadow: 0 2px 0 rgba(0,0,0,0.8);
}
.conn-overlay-sub {
  font-family: -apple-system, 'Segoe UI', Roboto, sans-serif;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-2);
}


/* ══════════════════════════════════════════════════════════
   6 · ВЫБОР ПЕРСОНАЖА
   Первое, что видит игрок. Порядок чтения: герой → имя →
   чем он силён → кнопка. Всё, что мельче 10px, поднято на
   сетку: тут было четыре разных кегля ниже нормы.
   ══════════════════════════════════════════════════════════ */

/* Зерно и виньетка поверх радиального фона: ровная заливка
   читается как веб-градиент, зерно делает её поверхностью. */
.cs-bg {
  background:
    var(--grain),
    var(--vign),
    radial-gradient(ellipse at 50% 30%, #1c0a38 0%, #08040f 55%, #030207 100%);
  background-blend-mode: overlay, normal, normal;
  background-size: 120px 120px, auto, auto;
}

.cs-title {
  font-family: var(--font-ui);
  font-size: var(--fs-1);
  letter-spacing: 5px;
  color: var(--text-4);
}

/* Имя героя — самое крупное на экране. Цвет класса приходит
   инлайном, поэтому ореол берём currentColor. */
.cs-hero-name {
  font-family: var(--font-ui) !important;
  font-size: var(--fs-5);
  font-weight: 400;
  letter-spacing: 2px;
  text-shadow: 0 0 20px currentColor, 0 3px 0 rgba(0,0,0,0.85);
}
.cs-hero-class {
  font-family: var(--font);
  font-size: var(--fs-1);
  letter-spacing: 2px;
  opacity: 0.85;
  text-shadow: 0 1px 0 rgba(0,0,0,0.8);
}

/* Стрелки карусели: гранёная плитка вместо круглой кнопки —
   круг единственный на всём экране и выбивался из языка. */
.cs-nav-btn {
  width: 42px; height: 42px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-strong);
  background:
    var(--sheen),
    linear-gradient(180deg, #221d36 0%, #12101c 100%);
  color: var(--text-2);
  font-size: var(--fs-3);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08), 0 2px 0 #07060d;
  text-shadow: 0 1px 0 rgba(0,0,0,0.7);
}
.cs-nav-btn:active {
  transform: translateY(2px);
  background: linear-gradient(180deg, #2a2442 0%, #191630 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05), 0 0 0 #07060d;
}

.cs-dot {
  width: 7px; height: 7px;
  border-radius: var(--r-sm);
  background: var(--line-strong);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5);
}
.cs-dot.active { transform: scale(1.5); }

/* Заголовки разделов: 8px → сетка, плюс уводящая черта */
.cs-section-label {
  display: flex; align-items: center; gap: var(--sp-2);
  font-family: var(--font-ui);
  font-size: var(--fs-1);
  letter-spacing: 2px;
  color: var(--text-4);
  margin-bottom: 0;
}
.cs-section-label::after {
  content: '';
  flex: 1; height: 1px;
  background: linear-gradient(90deg, var(--line-strong), transparent);
}

/* ── Шкалы ── */
.cs-bars {
  gap: var(--sp-2);
  padding: var(--sp-3);
  border-radius: var(--r-md);
  border: 1px solid var(--line-soft);
  background: linear-gradient(180deg, #14111f 0%, #0c0a14 100%);
  box-shadow: var(--bevel-in), 0 0 0 1px #07060d;
}
.cs-bar-label {
  font-family: var(--font);
  font-size: var(--fs-1);
  width: 38px;
  color: var(--text-3);
}
/* Жёлоб и заливка — как у полосок здоровья в theme.css */
.cs-bar-track {
  height: 8px;
  border-radius: var(--r-sm);
  background: linear-gradient(180deg, #06050c 0%, #0d0b16 100%);
  border: 1px solid #07060d;
  box-shadow: inset 0 2px 3px rgba(0,0,0,0.75), 0 1px 0 rgba(255,255,255,0.05);
}
.cs-bar-fill {
  position: relative;
  border-radius: 0;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.32), inset 0 -2px 0 rgba(0,0,0,0.28);
}
.cs-bar-fill::after {
  content: '';
  position: absolute; inset: 0;
  background: repeating-linear-gradient(90deg, rgba(0,0,0,0.22) 0 1px, transparent 1px 6px);
}

/* ── Навыки ──
   Иконка одного навыка иногда не грузится, и JS её удаляет
   (onerror="this.remove()"). Раньше подпись такого навыка
   уезжала к верху ряда и ломала строку. Прижимаем содержимое
   к низу — подписи выравниваются в любом случае. */
.cs-skills-row {
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-2);
  border-radius: var(--r-md);
  border: 1px solid var(--line-soft);
  background: linear-gradient(180deg, #14111f 0%, #0c0a14 100%);
  box-shadow: var(--bevel-in), 0 0 0 1px #07060d;
}
.cs-skill-item {
  flex: 1 1 0;
  min-width: 0;
  min-height: 71px;
  justify-content: flex-end;
  gap: 5px;
}
/* Картинка навыка сама становится гнездом: отдельного элемента под рамку в
   разметке нет. Берём её по классу с самой картинки (ui-charselect.js), а не
   как «img внутри пункта»: подпись со значком рядом сломала бы такой отбор. */
.cs-skill-img {
  width: 40px !important;
  height: 40px !important;
  padding: 5px;
  box-sizing: border-box;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background:
    radial-gradient(110% 90% at 50% 118%, rgba(143,111,212,0.24), transparent 68%),
    linear-gradient(180deg, #1e1a32 0%, #100e1a 100%);
  box-shadow: var(--bevel-in), 0 0 0 1px #07060d;
}
/* Место под две строки резервируем всегда: на узком экране
   «Тройной удар» переносится, и без резерва иконка этого навыка
   поднималась выше соседних — ряд ехал. */
.cs-skill-name {
  font-family: var(--font);
  font-size: var(--fs-1);
  letter-spacing: 0;
  line-height: 1.3;
  min-height: 26px;
  color: var(--text-3);
}

/* ── Сильные и слабые стороны ──
   Пять плашек в столбик занимали треть экрана и отжимали кнопку
   выбора за сгиб. В два столбца строки короткие, всё влезает. */
.cs-traits {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-1) var(--sp-2);
}
/* Первая слабая сторона начинает новую строку: иначе «Мало HP»
   вставало в паре с «Высокая атака» и плюсы с минусами
   перемешивались прямо в одном ряду. */
.cs-trait-good + .cs-trait-bad { grid-column: 1; }

.cs-trait {
  font-family: var(--font);
  font-size: var(--fs-1);
  padding: 6px 8px;
  border-radius: var(--r-sm);
  gap: 5px;
  box-shadow: var(--bevel);
  min-width: 0;
}
.cs-trait-good {
  color: #8dbd8e;
  color: color-mix(in srgb, var(--success) 62%, var(--text));
  background: linear-gradient(180deg, rgba(86,165,82,0.16) 0%, rgba(86,165,82,0.05) 100%);
  border: 1px solid rgba(86,165,82,0.30);
}
.cs-trait-bad {
  color: #e59794;
  color: color-mix(in srgb, var(--danger) 62%, var(--text));
  background: linear-gradient(180deg, rgba(228,104,92,0.16) 0%, rgba(228,104,92,0.05) 100%);
  border: 1px solid rgba(228,104,92,0.30);
}
.cs-trait-label { font-weight: 400; opacity: 0.8; font-size: var(--fs-1); }

/* ── Особенность класса ──
   Длинная фраза. Пиксельный шрифт в 9px её не тянул: системный
   плюс золотая грань слева — это цитата, а не ещё одна плашка. */
.cs-perk-box {
  font-family: -apple-system, 'Segoe UI', Roboto, sans-serif;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.1px;
  text-align: left;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  border: 1px solid var(--line-soft);
  border-left: 2px solid var(--gold-dim);
  background: linear-gradient(180deg, #16131f 0%, #0f0d19 100%);
  background-image: none;
  box-shadow: var(--bevel-in);
  color: var(--text-2);
}

/* ── Кнопка выбора ──
   Главное действие экрана. Пока персонаж не выбран — тихая
   плашка; как только выбран, JS ставит --cs-col, и кнопка
   загорается цветом класса. */
.cs-confirm {
  margin-top: var(--sp-4);
  padding: 15px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-strong);
  background: linear-gradient(180deg, #191527 0%, #110f1c 100%);
  color: var(--text-4);
  font-family: var(--font-ui);
  font-size: var(--fs-4);
  font-weight: 400;
  letter-spacing: 1px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.06), 0 2px 0 #07060d;
  text-shadow: 0 2px 0 rgba(0,0,0,0.7);
  backdrop-filter: none;
  transition: filter .15s;
}
.cs-confirm.ready {
  border-color: var(--line-strong);
  border-color: color-mix(in srgb, var(--cs-col) 65%, var(--line-strong));
  color: #fff;
  color: color-mix(in srgb, var(--cs-col) 40%, #ffffff);
  background: linear-gradient(180deg, #241f3c 0%, #14111f 100%);
  background:
    linear-gradient(180deg, rgba(255,255,255,0.10) 0%, rgba(255,255,255,0) 45%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--cs-col) 30%, #14111f) 0%,
      color-mix(in srgb, var(--cs-col) 12%, #0c0a14) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.14),
    0 2px 0 #07060d,
    0 0 22px color-mix(in srgb, var(--cs-col) 26%, transparent);
}
.cs-confirm:active {
  transform: translateY(2px) scale(1);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08), 0 0 0 #07060d;
  filter: brightness(1.08);
}


/* ══════════════════════════════════════════════════════════
   7 · ЩАДЯЩИЙ РЕЖИМ
   Если в системе выключены анимации — окна просто появляются.
   Лучи и пульсация в таком режиме мешают, а не украшают.
   ══════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  #itemModal.show,
  #refineOverlay.show,
  #refineOverlay.show::before,
  #itemModal.show #itemModalCard,
  .offl-modal:not(.hidden),
  .death-modal:not(.hidden),
  .sell-modal:not(.hidden),
  .market-unlock-modal:not(.hidden),
  .offl-box, .death-modal-box, .sell-box, .market-unlock-box, .conn-overlay-box,
  .refine-result-icon,
  .refine-result-icon::before,
  .refine-result-icon::after,
  .refine-result-text,
  .refine-result-sub {
    animation: none !important;
  }
}
