/* ==========================================================================
   KRAZE upgrade

   Три вещи задают вид этого раздела, и все три взяты не с потолка.

   1. Скошенный угол вместо скругления. Скруглённые прямоугольники — это
      «любая панель любого сайта»; срезанный угол читается как оружейный
      кейс и совпадает с тем, как выглядят сами предметы CS.

   2. Свечение редкости под рендером. Игрок опознаёт скин по цвету раньше,
      чем читает название: красное — Covert, золотое — Contraband. Цвет
      приходит из каталога, здесь он только становится градиентом.

   3. Сцена стоит в вырезанном колодце, а не на такой же панели, как списки.
      Разная глубина отделяет «где играют» от «где выбирают» без единой
      подписи.

   Палитра, шрифты и радиусы — из home.css. Своих цветов тут нет; жёлтый
   остаётся цветом действия, и в него выкрашена ровно одна вещь — кнопка.

   Обновление (2026-10-15): всё вокруг кольца теперь говорит на языке
   «1 Клика» — индиго-стол, скругления, лаймовое действие, фиолетовая
   ставка (раздел «ТЕМА САЙТА» в конце файла). Срезанных углов и жёлтого
   вне кольца больше нет: на индиго-сайте они читались чужим разделом.
   Правила выше не удалены — новый раздел их перекрывает весом, а кольцо,
   окно исхода и терминал кейса по-прежнему живут на них.
   ========================================================================== */

.up-body {
  --up: var(--violet);
  --up-hi: #C46BFF;
  --win: var(--accent);
  --lose: var(--red);
  --dial: clamp(250px, 26vw, 360px);
  --cut: 10px;                 /* глубина среза угла */
}

/* Страница уже общей оболочки: сцена держится в ширине выровненного под
   шкалу кадра (≈1485 px при циферблате 360), иначе на широких экранах по
   бокам сцены оставались размытые поля. Инвентарь и витрина ниже сужаются
   вместе с ней. */
.up-page { position: relative; max-width: 1510px; margin: 0 auto; padding: 14px var(--pad-x, 20px) 56px; }
/* выровненный кадр шире страницы и выходит за края окна — режем, чтобы не
   было горизонтальной прокрутки (clip не создаёт scroll-контейнер) */
html, body { overflow-x: clip; }
/* Общий фон страницы (assets/upgrade_page_bg.webp) в два слоя.
   ::before — размытая тёмная подложка на весь экран (fixed, cover): она
   закрывает края, куда не дотягивается выровненный кадр.
   ::after — сам кадр, размер и положение считает скрипт (alignStageBg в
   upgrade.main.js): центр воронки ложится в центр шкалы, радиус воронки
   равен ободу шкалы. Слой в потоке страницы, поэтому при прокрутке едет
   вместе со шкалой. */
.up-page::before {
  content: ''; position: fixed; inset: -24px; z-index: -2; pointer-events: none;
  background: url("assets/upgrade_page_bg.webp") center / cover no-repeat;
  filter: blur(18px) brightness(.45);
  opacity: .6;
}
.up-page::after {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  left: var(--pbx, 0); top: var(--pby, 0); width: var(--pbw, 100%); height: var(--pbh, 100%);
  background: url("assets/upgrade_page_bg.webp") 0 0 / 100% 100% no-repeat;
  opacity: .5;
  -webkit-mask: linear-gradient(180deg, #000 55%, transparent 100%); mask: linear-gradient(180deg, #000 55%, transparent 100%);
}

[hidden] { display: none !important; }

/* ─────────────── ЗАГОЛОВОК ─────────────── */

/* Полоса честной игры убрана — ПОКА. Прячем стилями, а не вырезаем из
   разметки: под кнопкой висит окно с зерном, хешем и полем клиентского
   сида, и на эти узлы пишет upgrade.main.js в каждом раунде. Удалить их
   значило бы обвешать проверками весь раунд ради временно скрытой
   плашки. Вернуть — снять display: none с этой строки. */
.up-head { display: none; }
.up-head--on {
  display: flex; align-items: center; justify-content: flex-end; gap: 16px; flex-wrap: wrap;
  margin-bottom: 12px;
}
.up-head__title { display: flex; align-items: center; gap: 13px; }
.up-head__glyph {
  display: grid; place-items: center;
  width: 46px; height: 46px;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  background: linear-gradient(150deg, rgba(166,44,255,.32), rgba(166,44,255,.05));
  color: var(--up-hi);
}
.up-head__glyph svg { width: 26px; height: 26px; }
.up-head h1 {
  font-family: var(--f-cond); font-size: 25px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .04em; line-height: 1;
}
.up-head p { margin-top: 4px; font-size: 12px; color: var(--text-dim); }

/* Без подложки: это не кнопка действия, а строка состояния. Плашка с
   заливкой и срезанным углом тянула на себя внимание наравне с кнопкой
   «Апгрейд», хотя сообщает всего лишь, что хеш раунда готов. Осталась
   точка, две строки и подсветка текста при наведении. */
@keyframes up-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(67,217,122,.5); }
  70%  { box-shadow: 0 0 0 7px rgba(67,217,122,0); }
  100% { box-shadow: 0 0 0 0 rgba(67,217,122,0); }
}

/* ─────────────── СЦЕНА ───────────────
   Колодец: тёмный пол, фиолетовый разлив под шкалой и тонкая сетка, чтобы
   плоскость не выглядела пустой заливкой. */

.up-stage {
  position: relative; isolation: isolate;
  display: grid; justify-items: center;
  padding: clamp(20px, 3vw, 40px) 20px clamp(18px, 2.4vw, 30px);
  margin-bottom: var(--gap);
  /* Сцена полупрозрачная: своего кадра внутри больше нет, сквозь блок
     виден общий фон страницы, чуть размытый, чтобы шкала и плиты читались */
  background: rgba(8, 8, 10, .55);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
/* Фон сцены — готовый кадр: рамки-уголки, силуэты оружия по бокам и пол.
   Раньше это рисовалось градиентами и сеткой, но нарисованный «зал» так и
   оставался плоской заливкой: у кадра есть глубина и предметный план,
   которых градиентом не изобразить. */
/* Кадр assets/upgrade_stage2.webp: в его центре воронка, и она должна
   совпасть с кольцом шкалы. Поэтому картинка не «cover по центру», а
   позиционируется под циферблат: размер и сдвиг считает скрипт
   (alignStageBg в upgrade.main.js) и кладёт в --bgw/--bgh/--bgx/--bgy —
   центр воронки (838, 385 из 1672×941) ложится в центр шкалы, а её радиус
   (~195 px картинки) равен ободу шкалы. Там, куда выровненная картинка не
   дотягивается (широкие экраны), под ней лежит она же размытая на cover. */
/* Кадр внутри сцены отключён (просили): блок полупрозрачный поверх общего
   фона страницы. Правила ниже остаются на случай возврата. */
.up-stage__bg { display: none; }
.up-stage__bg--off {
  position: absolute; inset: 0; z-index: -1; overflow: hidden; background: #000;
}
.up-stage__bg::before {
  content: ''; position: absolute; inset: -24px;
  background: url('assets/upgrade_stage2.webp') center / cover no-repeat;
  filter: blur(16px) brightness(.35);
}
.up-stage__bg::after {
  content: ''; position: absolute; inset: 0;
  /* сверху тёмная плёнка: плотнее у верхнего края (подписи плит) и у
     нижнего (ряд множителей и кнопка), в середине почти прозрачная — там
     воронка и шкала */
  background:
    linear-gradient(180deg, rgba(6,6,8,.45) 0%, rgba(6,6,8,.08) 32%, rgba(6,6,8,.12) 62%, rgba(6,6,8,.72) 100%),
    url('assets/upgrade_stage2.webp') var(--bgx, 50%) var(--bgy, 50%) / var(--bgw, cover) var(--bgh, auto) no-repeat;
  filter: brightness(.66) saturate(.85);
}

/* Исход красит сцену отдельным слоем ПОВЕРХ кадра, а не подменой фона:
   подмена стирала бы картинку целиком, а нужен цветной разлив по ней. */
.up-stage__tint {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(54% 50% at 50% 46%, var(--tint, transparent) 0%, transparent 74%);
  opacity: 0;
  transition: opacity .45s;
}
/* Заливка сцены на исход убрана: пятно в полсцены светило сквозь всё —
   плиты ставки и цели, подписи, кнопку, — и предмет, ради которого сцена
   и затевалась, оказывался внутри цветного тумана. Исход называют
   вспышка в центре, волна и цвет цены. */
.up-page[data-state="won"]  .up-stage__tint,
.up-page[data-state="lost"] .up-stage__tint { opacity: 0; }
/* Нарисованная сетка пола убрана: на кадре пол уже есть, свой поверх него
   давал вторую поверхность под первой. Подмены фона на исход тоже убраны —
   их заменил слой .up-stage__tint выше. */

.up-duel {
  position: relative;
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center; gap: clamp(12px, 2.4vw, 38px);
  width: 100%; max-width: 1180px;
}

/* ── плиты ставки и цели ── */

/* Ширина ограничена: в колонке 1fr плита растягивается на треть экрана и
   становится пустым полем с картинкой посередине. Прижимаем обе к шкале —
   composition читается как «это против этого», а не как три блока в ряд. */
.up-slot {
  position: relative; isolation: isolate;
  width: 100%; max-width: 360px;
  display: grid; gap: 6px; justify-items: center;
  padding: 16px 14px 14px;
  /* Скругление, а не срез угла. Пока плита была тёмной, срез читался как
     форма самой плиты: за ним такой же тёмный фон. Плита в цвете разряда
     сделала его видимым — два чёрных клина по углам, будто оторвали
     кусок. Скругление ничего не вырезает и работает на любом фоне. */
  border-radius: 14px;
  /* плиты полупрозрачные, с размытием того, что за ними: кадр
     просвечивает, но текст и предметы читаются */
  background: linear-gradient(165deg, rgba(16,17,19,.78) 0%, rgba(10,10,12,.84) 100%);
  -webkit-backdrop-filter: blur(10px) saturate(1.1); backdrop-filter: blur(10px) saturate(1.1);
  transition: background .3s, transform .3s;
}
/* Тонкая светящаяся кромка. Отдельным слоем, потому что clip-path срезает
   border, и рамка по срезу просто исчезла бы. */
.up-slot::after {
  content: ''; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px var(--edge, rgba(255,255,255,.07));
  transition: box-shadow .3s;
}
/* Выбран предмет — плита целиком красится в цвет его разряда, а не только
   светится пятном под ним. Разряд игрок читает цветом раньше, чем читает
   подпись «Covert», и полутёмная плита с красным пятном посередине давала
   этот сигнал вполсилы: цвет был у подсветки, а не у самой вещи.

   Тот же приём, что у карточек скинов по всему сайту (см. .cr-item в
   home.css): насыщеннее к верху, к низу уходит в цвет панели. Цвет берётся
   из --r, его ставит upgrade.view.js по самому дорогому предмету ставки. */
.up-slot.is-set {
  background: linear-gradient(168deg,
    color-mix(in srgb, var(--r) 42%, #0F1013) 0%,
    color-mix(in srgb, var(--r) 13%, #0B0B0D) 100%);
}
.up-slot--stake { justify-self: end; }
.up-slot--target { justify-self: start; }
.up-slot--stake.is-set { --edge: rgba(166,44,255,.5); }
.up-slot--target.is-set { --edge: rgba(237,224,15,.45); }

.up-slot__glow {
  position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(58% 52% at 50% 46%, var(--r, transparent) 0%, transparent 70%);
  opacity: .3;
  transition: opacity .35s;
}
/* Пятно под предметом остаётся, но тише: на крашеной плите прежние 42%
   читались как второе, более яркое пятно поверх первого. */
.up-slot.is-set .up-slot__glow { opacity: .2; }

.up-slot__cap {
  font-family: var(--f-cond); font-size: 11px; font-weight: 500;
  text-transform: uppercase; letter-spacing: .22em; color: var(--text-mute);
}
.up-slot__body {
  position: relative; display: grid; place-items: center; gap: 6px;
  width: 100%; min-height: clamp(110px, 12vw, 158px);
}
.up-slot__body > img {
  max-width: 92%; max-height: clamp(104px, 11.5vw, 150px);
  object-fit: contain;
  filter: drop-shadow(0 12px 26px rgba(0,0,0,.75));
}
.up-slot__empty {
  font-size: 11px; color: var(--text-mute); text-align: center;
  max-width: 16ch; line-height: 1.45;
}
.up-slot__name {
  font-size: 11px; color: var(--text-dim); text-align: center;
  max-width: 26ch; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.up-slot__foot b {
  font-family: var(--f-cond); font-size: clamp(19px, 1.9vw, 27px); font-weight: 600;
  letter-spacing: .01em; font-variant-numeric: tabular-nums;
}
.up-slot--stake.is-set .up-slot__foot b { color: var(--up-hi); }
.up-slot--target.is-set .up-slot__foot b { color: var(--accent); }

/* Веер описан в конце файла: он переехал с голых картинок на карточки. */

/* ── шкала ── */

.up-dial { position: relative; width: var(--dial); height: var(--dial); display: grid; place-items: center; }
.up-dial__svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; z-index: 1; }

/* ── кольцо — как в апгрейд-батле (upbattle.css, .ub-w__*) ──
   Решение владельца 2026-10-14: кольцо и его механика из батла. Слои
   (viewBox 348): обод с рисками (r 162–173), секторы до r 162, тёмный
   зазор 145–160, толстая дуга 113–145 с процентом посередине (r 129),
   серое кольцо 100–113, тёмный центр r 100 и тонкий круг r 96, по которому
   на ходу бегут две светлые дуги. Углы — по часовой от ВЕРХА, как у
   прежней шкалы (в батле — от низа): сектор шанса — от 0 до шанс × 360°,
   всегда градиентом прежней шкалы (фиолет → жёлтый, #up-rgi; сплошной
   лайм владелец просил убрать), остальная дорожка пустая — сектора
   проигрыша, как в батле, нет: подсвечено только поле шанса (2026-10-15). Игла
   в покое вверху по центру, обходит кольцо и встаёт на угол исхода
   (upgrade.view.js). */
.up-ring { container-type: inline-size; }
.up-r__rim { fill: none; stroke: #1C1D21; stroke-width: 11; }
.up-r__ticks line { stroke: #34363D; stroke-width: 1; }
.up-r__track { fill: none; stroke: #131417; stroke-width: 44; }
.up-r__sec { fill: url(#up-rgi); transition: opacity .5s, filter .5s; }
.up-r__gap { fill: none; stroke: #0E0E10; stroke-width: 15; }
.up-r__inner { fill: none; stroke: #1F2024; stroke-width: 13; }
.up-r__core { fill: url(#up-rgc); }
.up-r__halo { fill: none; stroke: rgba(255, 255, 255, .07); stroke-width: 4.35; transition: stroke .5s; }
.up-r__run { opacity: 0; transform-origin: 174px 174px; transition: opacity .4s; }
.up-r__run circle { fill: none; stroke: #fff; stroke-width: 4.35; stroke-linecap: round; }
.up-dial.is-spin .up-r__run { opacity: .5; animation: up-orbit .9s linear infinite; }
@keyframes up-orbit { to { transform: rotate(360deg); } }
/* процент шанса — тёмный полупрозрачный, «выбитый» в дуге */
.up-r__pct { font-family: var(--f-body); font-size: 22px; font-weight: 700; letter-spacing: .01em; }
.up-r__pct0 { fill: rgba(0, 0, 0, .5); }
/* подписи некуда уйти из-под иглы (дуга короче подписи) — гаснет */
.up-r__pct text.is-dim { opacity: .22; }
/* итог: выигрыш — сектор шанса светится; проигрыш (игла на пустой
   дорожке) — сектор серо-тёмный, процент тише */
.up-dial.is-over .up-r__sec.is-lose { opacity: .5; filter: grayscale(.85) brightness(.45); }
.up-dial.is-w0 .up-r__sec.is-win { filter: drop-shadow(0 0 10px rgba(237, 224, 15, .45)) drop-shadow(0 0 14px rgba(196, 107, 255, .35)); }
.up-dial.is-over .up-r__pct text { transition: opacity .5s; }
.up-dial.is-w1 .up-r__pct0 { opacity: .4; }
.up-dial.is-w0 .up-r__halo { stroke: #EDE00F; }
.up-dial.is-w1 .up-r__halo { stroke: #B65CFF; }

/* Шанс не посчитан: кольцо стоит как прежняя шкала (просил владелец,
   2026-10-15) — неподвижная половина той же дуги от иглы по часовой,
   чуть тише живой; без процента. */
.up-dial.is-idle .up-r__sec { opacity: .85; }

/* центр: квадрат во весь тёмный круг (200 из 348); на ходу — стрелки
   апгрейда, влетают снизу: нижняя фиолетовая, за ней верхняя лаймовая */
.up-r__face { position: absolute; inset: 0; margin: auto; height: 57.47%; width: auto; aspect-ratio: 1; z-index: 2; display: grid; place-items: center; border-radius: 50%; pointer-events: none; }
/* Слои поверх кольца — квадрат по высоте блока, по центру. На телефоне
   блок шкалы шире своей высоты (mobile.css: flex 0 0 100%, высота 220):
   SVG кольца сам встаёт квадратом по центру, а игла в процентах от
   прямоугольника съезжала с кольца. */
.up-ring > .up-needle { inset: 0; margin: auto; width: auto; height: 100%; max-width: 100%; aspect-ratio: 1; }
.up-r__face > * { grid-area: 1 / 1; }
.up-r__chev { width: 100%; height: 100%; overflow: visible; }
.up-r__chev path { animation: up-fly .6s cubic-bezier(.2, .9, .25, 1) both, up-glowp 1.4s ease-in-out .7s infinite; }
.up-r__chev .c1 { fill: url(#up-rcl); animation-delay: .12s, .82s; }
.up-r__chev .c2 { fill: url(#up-rcv); }
@keyframes up-fly { from { opacity: 0; transform: translateY(60%); } to { opacity: 1; transform: none; } }
@keyframes up-glowp { 0%, 100% { opacity: 1; } 50% { opacity: .78; } }
.up-dial.is-collapse .up-r__face { opacity: 0; transition: opacity .18s; }

/* ── движение в покое ──
   Стрелка стоит неподвижно — просили; живёт только поле за кольцом и
   блик по дуге. */
/* Энергетическое поле за кольцом: медленно вращающийся размытый
   фиолетово-лаймовый диск. Лежит под кольцом (z-index -1), как и дыхание
   подсветки; оба гаснут на исходе. */
.up-dial::after {
  content: ''; position: absolute; inset: 4%;
  border-radius: 50%; pointer-events: none; z-index: -1;
  background: conic-gradient(from 0deg, rgba(166,44,255,0) 0deg, rgba(166,44,255,.32) 70deg, rgba(166,44,255,0) 140deg,
                             rgba(215,255,0,0) 200deg, rgba(215,255,0,.18) 260deg, rgba(215,255,0,0) 330deg);
  filter: blur(18px); opacity: .7;
  animation: up-field 14s linear infinite;
}
@keyframes up-field { to { transform: rotate(360deg); } }
.up-page[data-state="won"]  .up-dial::after,
.up-page[data-state="lost"] .up-dial::after { opacity: 0; animation: none; transition: opacity .3s; }

/* ── игла ──
   Игла апгрейд-батла (assets/upbattle/needle.svg) — в покое ВВЕРХУ кольца
   (как прежняя стрелка), остриём к тонкому ободу. Нарисована в единицах
   кольца (24 × 64 из 348) остриём вниз — здесь развёрнута на 180°: шарнир
   на r 100 (кромка тёмного центра), остриё у обода → top 2.87%, ширина
   6.9%. Отдельный слой поверх кольца (см. upgrade.html); обходит кольцо
   поворотом всей рамки вокруг центра — анимацией браузера на видеокарте,
   не покадровым скриптом. z-index выше центра: на ходу шлейф идёт по дуге. */
.up-needle { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
/* Поворот — на внутреннем слое: внешний сжимается вместе с кольцом при
   выигрыше (анимация transform), и на одном элементе она сбросила бы угол. */
.up-needle__rot { position: absolute; inset: 0; will-change: transform; transform: rotate(0deg); }
.up-needle__rot img {
  position: absolute; left: 50%; top: 2.87%; width: 6.9%; height: auto; transform: translateX(-50%) rotate(180deg); display: block;
  filter: drop-shadow(0 0 5px rgba(237, 224, 15, .4)) drop-shadow(0 -2px 4px rgba(0, 0, 0, .65));
}
/* тёмная подложка под иглой в итоге: на любой дуге игла стоит на
   «прорези» и не теряется (жёлтое на лайме само по себе слабое) */
.up-needle__rot::before {
  content: ''; position: absolute; left: 50%; top: 3.8%; width: 7.4%; height: 16.6%; transform: translateX(-50%);
  border-radius: 999px; opacity: 0; transition: opacity .45s .1s;
  background: radial-gradient(50% 50% at 50% 50%, rgba(4, 4, 6, .72) 0%, rgba(4, 4, 6, .55) 55%, rgba(4, 4, 6, 0) 100%);
}
.up-dial.is-over .up-needle__rot::before { opacity: 1; }
/* шлейф за иглой, пока она крутится: светлый клин позади (игла идёт
   по часовой), только по толстой дуге и зазору — r 113…160. Игла вверху —
   клин батла (128…180° от верха) повёрнут на 180°. */
.up-needle__rot::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%; opacity: 0; transition: opacity .35s;
  background: conic-gradient(from 180deg, rgba(255, 251, 224, 0) 0deg 128deg, rgba(255, 251, 224, .05) 140deg, rgba(255, 251, 224, .34) 178deg, rgba(255, 251, 224, 0) 180deg 360deg);
  -webkit-mask: radial-gradient(closest-side, transparent 64.6%, #000 65%, #000 91.6%, transparent 92%);
          mask: radial-gradient(closest-side, transparent 64.6%, #000 65%, #000 91.6%, transparent 92%);
}
.up-dial.is-spin .up-needle__rot::after { opacity: 1; }
/* возврат иглы наверх между раундами — плавно (homeNeedle) */
.up-needle__rot.is-homing { transition: transform .7s cubic-bezier(.2, .8, .3, 1); }
/* Показания снова по центру: оси в середине больше нет, спорить числу не
   с чем. */
/* Отсчёт живёт в НИЖНЕЙ половине циферблата, а не в центре.

   В центре его перечёркивала стрелка: ось вращения там же, где стояло
   число, и на трёх четвертях круга клинок шёл прямо по цифрам. На реальных
   приборах цифровое окно и стоит под осью — по той же причине.

   Позиция абсолютная, а не сдвиг трансформом: translateY считается от
   собственной высоты блока, а она меняется вместе с кеглем числа, и на
   разных экранах отсчёт уезжал бы на разную глубину. */
.up-dial__mid {
  position: absolute; left: 0; right: 0; bottom: 17%;
  z-index: 2;
  display: grid; justify-items: center; gap: 1px;
  pointer-events: none;
}
.up-dial__cap {
  font-family: var(--f-cond); font-size: 10px; font-weight: 500;
  text-transform: uppercase; letter-spacing: .26em; color: var(--text-mute);
}
/* Пустое состояние: тире мелким и приглушённым. В основном кегле оно было
   сплошной белой полосой шириной в треть колодца. */
.up-dial__pct.is-empty {
  font-size: 26px; color: var(--text-mute); opacity: .5;
}

/* Стрелку в покое только гасим. Поворачивать её отсюда нельзя: угол ставит
   скрипт инлайном, инлайн сильнее правила, и после первого же броска CSS
   перестал бы действовать — а учёт угла в скрипте разошёлся бы с картинкой. */
.up-dial.is-idle .up-needle { opacity: .45; }
.up-dial__pct {
  font-family: var(--f-cond); font-weight: 600;
  /* Кегль уменьшен: в нижней половине круга ширины меньше, чем в центре,
     и прежние 62px упирались в кромку колодца. */
  font-size: clamp(30px, 3.5vw, 46px); line-height: 1; letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
  transition: color .3s;
}
/* Строка под числом обязана уместиться в колодец. Ширина ограничена:
   у круга внизу узко, и длинная подпись вылезала за кольцо по обе
   стороны, ложась на дорожку. */
/* Строка под числом обязана уместиться в колодец. Ширину ограничиваем на
   всякий случай, но главное — где она стоит: см. .up-dial.is-idle ниже. */
.up-dial__mult {
  font-size: 11px; color: var(--text-dim);
  max-width: 58%; margin-inline: auto; text-align: center; line-height: 1.25;
}
.up-dial__mult.is-empty {
  font-family: var(--f-cond); font-size: 12px; font-weight: 500;
  text-transform: uppercase; letter-spacing: .1em; color: var(--text-mute);
}
.up-page[data-state="spinning"] .up-dial__mid { opacity: .3; transition: opacity .3s; }

/* Пока ставка не выбрана, надписи стоят по ЦЕНТРУ круга, а не у низа.
   Нижняя треть колодца узкая — там помещается число, но не строка из двух
   слов: «Выберите предмет» вылезало на дорожку с обеих сторон. В центре
   ширина круга наибольшая, и та же строка встаёт целиком.

   Когда шанс посчитан, блок возвращается вниз: там его место рядом с
   крупным числом процентов, под которое раскладка и делалась. */
/* Не по центру, а сразу под втулкой стрелки: ровно по центру надпись
   лежала бы на оси и хвосте стрелки (он уходит на 15% радиуса вниз).
   58% — первая точка ниже хвоста, и круг там ещё широкий: хорда 147px
   против 117px у строки. */
.up-dial.is-idle .up-dial__mid { bottom: auto; top: 58%; }
.up-dial.is-idle .up-dial__pct { display: none; }
/* В кольце показания — по центру тёмного круга: игла ходит по ободу и
   центр не пересекает (у прежней стрелки ось была в самой середине). На
   ходу центр отдан стрелкам апгрейда (.up-r__face). */
.up-ring .up-dial__mid, .up-ring.is-idle .up-dial__mid { top: 0; bottom: 0; align-content: center; }
.up-dial.is-spin .up-dial__mid { opacity: 0; transition: opacity .2s; }
/* Проигрыш: «Неудача» (.up-reveal.is-lost) встаёт в тот же центр — шанс
   под ней прячется, пока итог на столе (до сброса стола data-state снова
   idle). */
.up-page[data-state="lost"] .up-ring .up-dial__mid { opacity: 0; transition: opacity .2s; }

/* ═══════════════ ЯВЛЕНИЕ ПРЕДМЕТА ═══════════════

   Кольцо стягивается в точку и из неё выбивает предмет. Раньше исход был
   надписью поверх шкалы: «Апгрейд» и строчка мелким — то есть событие,
   ради которого сюда приходят, выглядело как системное сообщение.

   Порядок по времени:
     0.00  кольцо начинает стягиваться, центр гаснет
     0.42  кольца нет — вспышка ядра, две волны наружу
     0.42  предмет выходит из точки белым силуэтом
     0.75  силуэт остывает до текстуры, встаёт на место
     0.85  название и цена, цена набегает счётчиком              */

/* ── кольцо стягивается ── */
.up-dial.is-collapse .up-dial__svg, .up-dial.is-collapse .up-needle {
  animation: up-collapse .3s cubic-bezier(.55, 0, .85, .25) forwards;
}
@keyframes up-collapse {
  0%   { transform: scale(1);   opacity: 1;  filter: brightness(1); }
  65%  { transform: scale(.38); opacity: .95; filter: brightness(2.2); }
  100% { transform: scale(.04); opacity: 0;  filter: brightness(4); }
}
.up-dial.is-collapse .up-dial__mid { opacity: 0; transition: opacity .18s; }

/* ── и разворачивается обратно, когда стол сбросили ── */
.up-dial.is-restore .up-dial__svg, .up-dial.is-restore .up-needle {
  animation: up-restore .5s cubic-bezier(.2, 1.3, .4, 1) both;
}
@keyframes up-restore { from { transform: scale(.04); opacity: 0; } }

/* Огненное кольцо выигрыша. Лежит в .up-page поверх сцены; центр и
   размер ставит winRing() по шкале: кольцо в кадре — половина ширины
   видео, кольцо шкалы — 87,5% её размера, отсюда 173% от шкалы. Поверх
   затемнения сцены на выигрыш, иначе пламя гасло бы вместе с ней.
   Видно только пока играет. */
.up-winring {
  position: absolute; left: 0; top: 0; z-index: 5;
  width: 0; height: 0; max-width: none;
  transform: translate(-50%, -50%);
  mix-blend-mode: screen; pointer-events: none;
  opacity: 0; transition: opacity .2s;
}
.up-winring.is-on { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .up-winring { display: none; } }

/* ── терминал кейса для утешительного приза (View.compReel) ──
   Окно поверх сцены ровно её размера (позицию ставит JS), внутри — лента
   кейса из cases.css. Появляется из линии: сцена схлопывается по
   вертикали, терминал раскрывается. */
.up-term {
  --u: clamp(6.5px, .7vw, 10px);
  --cs-ink: #06090F;
  position: absolute; z-index: 6; box-sizing: border-box;
  display: grid; align-content: center; justify-items: center; gap: 14px;
  padding: 20px 24px; overflow: hidden; pointer-events: none;
  border-radius: var(--radius, 14px);
  border: 1px solid rgba(166, 44, 255, .45);
  background:
    radial-gradient(70% 60% at 50% 50%, rgba(92, 28, 160, .35), transparent 70%),
    linear-gradient(180deg, rgba(10, 8, 18, .97), rgba(6, 6, 12, .98));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .04), 0 0 60px rgba(166, 44, 255, .18);
  transform-origin: 50% 50%;
}
.up-term__title {
  font-family: var(--f-cond); font-size: 16px; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: #E7C8FF; text-shadow: 0 0 14px rgba(166, 44, 255, .7);
}
.up-term .cs-stage { width: min(100%, 1000px); margin-top: 0; box-shadow: 0 18px 50px rgba(0, 0, 0, .6), 0 0 0 1px rgba(166, 44, 255, .3); }
.up-term .cs-art img { filter: drop-shadow(0 18px 30px rgba(0, 0, 0, .7)) drop-shadow(0 0 22px rgba(166, 44, 255, .35)); }
/* выпавшая карточка — без свечения, только рамка цвета редкости */
.up-term .cs-reel.is-landed .cs-it.is-hit { box-shadow: 0 0 0 1px var(--rar); }
/* заголовок загорается с мерцанием, как лампа при включении (is-on) */
.up-term.is-on .up-term__title { animation: up-term-flick .6s steps(1, end) both; }
@keyframes up-term-flick {
  0% { opacity: 0; } 18% { opacity: .9; } 30% { opacity: .25; } 44% { opacity: 1; } 58% { opacity: .55; } 70%, 100% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .up-term.is-on .up-term__title { animation: none; } }
/* яркая линия «экрана» в момент схлопывания и раскрытия */
.up-term__line {
  position: absolute; z-index: 7; height: 2px; margin-top: -1px; pointer-events: none;
  background: linear-gradient(90deg, transparent, #F3E4FF 12%, #fff 50%, #F3E4FF 88%, transparent);
  box-shadow: 0 0 10px #A62CFF, 0 0 26px rgba(166, 44, 255, .85);
  opacity: 0;
}
.up-stage { transform-origin: 50% 50%; }
.up-reveal.is-won.is-comp .up-reveal__verdict { color: #E7C8FF; text-shadow: 0 0 14px rgba(166, 44, 255, .7); }

.up-reveal {
  position: absolute; inset: 0; z-index: 4;
  display: grid; place-content: center; justify-items: center; gap: 2px;
  pointer-events: none; --rar: var(--accent);
}
.up-reveal[hidden] { display: none !important; }

/* Ударная волна из втулки. Две, вторая с задержкой и белая: одна кажется
   рябью, две читаются как удар. */
.up-reveal__wave {
  position: absolute; left: 50%; top: 50%; width: 10px; height: 10px; margin: -5px 0 0 -5px;
  border-radius: 50%; border: 2px solid var(--rar);
  animation: up-wave .8s cubic-bezier(.15, .7, .3, 1) both;
}
.up-reveal__wave--2 { animation-delay: .12s; border-color: rgba(255,255,255,.8); }
@keyframes up-wave {
  from { transform: scale(1); opacity: .9; }
  to   { transform: scale(34); opacity: 0; }
}

/* Ядро — то, во что превратилось кольцо. */
.up-reveal__core {
  position: absolute; left: 50%; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px;
  border-radius: 50%; background: #fff;
  box-shadow: 0 0 36px 16px color-mix(in srgb, var(--rar) 65%, transparent);
  animation: up-core .55s ease-out both;
}
@keyframes up-core {
  0%   { transform: scale(.3); opacity: 1; }
  35%  { transform: scale(3);  opacity: 1; }
  100% { transform: scale(9);  opacity: 0; }
}

.up-reveal__verdict {
  font-family: var(--f-cond); font-size: clamp(15px, 1.6vw, 20px); font-weight: 600;
  text-transform: uppercase; letter-spacing: .16em; line-height: 1;
  text-shadow: 0 2px 10px rgba(0,0,0,.9);
  animation: up-rise .34s ease-out both;
}
.up-reveal.is-won  .up-reveal__verdict { color: var(--win); }

.up-reveal__art {
  position: relative; width: calc(var(--dial) * .56); aspect-ratio: 4 / 3;
  display: grid; place-items: center;
  animation: up-emerge .62s cubic-bezier(.16, 1.45, .35, 1) both;
}
/* Свечения за предметом нет: цветное пятно в полкольца перекрывало сцену
   и читалось как посторонний ореол, а не как часть предмета. Разряд и так
   назван цветом цены и волны. */
/* Без тени под предметом: тёмный ореол по контуру клинка на тёмной сцене
   читался как свечение вокруг него, а не как тень. Предмет показывается
   как есть. */
.up-reveal__art img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain;
}
/* Белого силуэта поверх предмета больше нет: он читался как свечение
   вокруг клинка и не давал разглядеть сам скин — а ради него всё и
   затевалось. Выход из точки показывают вспышка ядра и волна, они за
   предметом и гаснут до того, как он встанет на место. */
@keyframes up-emerge {
  0%   { opacity: 0; transform: scale(.24) rotateY(-110deg); }
  55%  { opacity: 1; }
  100% { opacity: 1; transform: none; }
}
@keyframes up-rise { from { opacity: 0; transform: translateY(9px); } }

.up-reveal__name {
  max-width: calc(var(--dial) * .78); text-align: center;
  font-size: 12px; color: var(--text); line-height: 1.25;
  text-shadow: 0 1px 8px rgba(0, 0, 0, .9);
  animation: up-rise .38s ease-out .1s both;
}
/* Сумма зелёная, как деньги на всём сайте: это выигрыш, а не подпись
   разряда. Цветом разряда остаются волна и вспышка — они про вещь. */
.up-reveal__price {
  font-family: var(--f-cond); font-size: clamp(20px, 2.4vw, 30px); font-weight: 600;
  color: var(--money); font-variant-numeric: tabular-nums; line-height: 1.1;
  text-shadow: 0 2px 12px rgba(0, 0, 0, .9);
  animation: up-rise .38s ease-out .16s both;
}

/* Что делать с выигрышем — двумя кнопками прямо в окне. «Продать» зелёная,
   как деньги на всём сайте; «Оставить» тёмная: она ничего не меняет, вещь
   и так уже в инвентаре. */
.up-reveal__act {
  display: flex; gap: 6px; margin-top: 10px; pointer-events: auto;
  animation: up-rise .38s ease-out .24s both;
}
.up-reveal__btn {
  min-width: 92px; height: 34px; padding: 0 14px; border: 0; border-radius: 9px;
  cursor: pointer; font: inherit; font-size: 12px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
  transition: filter .14s, background-color .14s, color .14s;
}
.up-reveal__btn--sell { background: var(--money); color: #08110B; }
.up-reveal__btn--sell:hover { filter: brightness(1.07); }
.up-reveal__btn--keep { background: rgba(255, 255, 255, .1); color: var(--text); }
.up-reveal__btn--keep:hover { background: rgba(255, 255, 255, .17); }

/* Проигрыш: в кольце остаётся одно слово. Ни предмета, ни цены, ни
   кнопок — забирать нечего, а кольцо не стягивается вовсе (см. flash в
   upgrade.view.js). Остальное рассказывает падающая плита ставки,
   .up-page[data-state="lost"] .up-slot--stake ниже. */
.up-reveal.is-lost .up-reveal__art,
.up-reveal.is-lost .up-reveal__name,
.up-reveal.is-lost .up-reveal__price,
.up-reveal.is-lost .up-reveal__act,
.up-reveal.is-lost .up-reveal__wave,
.up-reveal.is-lost .up-reveal__core { display: none; }
.up-reveal.is-lost .up-reveal__verdict { color: var(--lose); font-size: clamp(18px, 2vw, 24px); }

/* Бесплатный кейс за проигрыш (View.offerCase): то же окно, но вместо
   скина — обложка кейса, вместо цены — «приз до $X» (сам приз раскроет
   только открытие), и свой ряд кнопок: «Открыть сейчас» / «В инвентарь». */
.up-reveal__act--case { display: none; flex-wrap: wrap; justify-content: center; }
.up-reveal.is-case .up-reveal__act { display: none; }
.up-reveal.is-case .up-reveal__act--case { display: flex; }
.up-reveal.is-case .up-reveal__price { display: none; }
.up-reveal.is-case .up-reveal__name { color: #E7C8FF; font-weight: 600; }
.up-reveal.is-case .up-reveal__art img {
  filter: drop-shadow(0 14px 24px rgba(0, 0, 0, .6)) drop-shadow(0 0 22px rgba(166, 44, 255, .45));
  animation: up-case-float 3.2s ease-in-out .7s infinite;
}
@keyframes up-case-float { 50% { transform: translateY(-6px); } }
.up-reveal__btn--open { background: var(--accent); color: #100E00; }
.up-reveal__btn--open:hover { filter: brightness(1.07); }
.up-reveal__btn--later { background: rgba(255, 255, 255, .1); color: var(--text); }
.up-reveal__btn--later:hover { background: rgba(255, 255, 255, .17); }
.up-reveal__btn:disabled { opacity: .55; cursor: default; filter: none; }

/* Полоска «Бесплатные кейсы N · Открыть» в шапке склада: не плитка —
   поставить кейс нельзя, его можно только открыть. */
.up-cases {
  display: inline-flex; align-items: center; gap: 8px; margin-left: auto;
  height: 32px; padding: 0 10px 0 4px; border-radius: 8px; cursor: pointer;
  background: rgba(166, 44, 255, .14); border: 1px solid rgba(166, 44, 255, .45);
  color: var(--text); font: inherit; font-size: 11px; font-weight: 600; white-space: nowrap;
  transition: background-color .15s, border-color .15s;
}
.up-cases[hidden] { display: none; }
.up-cases:hover:not(:disabled) { background: rgba(166, 44, 255, .24); border-color: rgba(166, 44, 255, .7); }
.up-cases:disabled { opacity: .5; cursor: default; }
.up-cases img { width: 30px; height: 24px; object-fit: contain; flex: none; }
.up-cases b { color: #E7C8FF; font-variant-numeric: tabular-nums; }
.up-cases i { font-style: normal; text-transform: uppercase; letter-spacing: .06em; color: var(--accent); }
@media (max-width: 760px) {
  .up-reveal__btn--open, .up-reveal__btn--later { height: 40px; }
  .up-cases { height: 40px; }
}

.up-page[data-state="won"] .up-slot--target { animation: up-pop .55s cubic-bezier(.2,1.5,.4,1); }
@keyframes up-pop { 45% { transform: scale(1.06); } }
.up-page[data-state="lost"] .up-slot--stake {
  animation: up-drop .75s cubic-bezier(.5,.05,.75,.3) forwards;
}
@keyframes up-drop {
  20%  { filter: grayscale(1) brightness(.7); }
  100% { filter: grayscale(1) brightness(.35); transform: translateY(24px) rotate(-3deg); opacity: .28; }
}

.up-shards { position: absolute; inset: 0; z-index: 4; pointer-events: none; }

/* Стрелки апгрейда, взлетающие по фону на выход скина (View.arrows).
   z-index 4: над затемнением сцены (::after, 3); окно предмета — тоже 4,
   но идёт в разметке позже и остаётся поверх. */
.up-arrows { position: absolute; inset: 0; z-index: 4; pointer-events: none; overflow: hidden; contain: strict; }
/* свечение уже в самой картинке (запекается в upgrade.view.js) — никаких
   фильтров здесь: они пересчитывались бы на каждом кадре полёта */
.up-arrows img { position: absolute; height: auto; opacity: 0; will-change: transform, opacity; }
.up-shards i {
  position: absolute; left: 50%; top: 50%;
  width: 4px; height: 12px; border-radius: 1px;
  background: var(--sc, var(--accent));
  transform: rotate(var(--a)) translateY(0);
  animation: up-shard .9s cubic-bezier(.15,.75,.3,1) forwards;
  animation-delay: var(--d, 0s);
}
@keyframes up-shard {
  0%   { opacity: 0; transform: rotate(var(--a)) translateY(0) scaleY(.4); }
  18%  { opacity: 1; }
  100% { opacity: 0; transform: rotate(var(--a)) translateY(calc(var(--dial) * -.6)) scaleY(1.1); }
}

/* ── множители и кнопка ── */

.up-quick { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin-top: clamp(16px, 2vw, 26px); }
.up-chip {
  padding: 8px 16px;
  clip-path: polygon(7px 0, 100% 0, 100% calc(100% - 7px), calc(100% - 7px) 100%, 0 100%, 0 7px);
  background: var(--panel-2);
  font-family: var(--f-cond); font-size: 14px; font-weight: 500; letter-spacing: .03em;
  color: var(--text-dim);
  transition: color .15s, background .15s, transform .15s;
}
.up-chip:hover:not(:disabled) { color: var(--text); background: var(--panel-3); transform: translateY(-1px); }
.up-chip.is-on { color: #140021; background: var(--up-hi); }
.up-chip:disabled { opacity: .25; cursor: default; }

.up-actions { display: flex; align-items: center; gap: 10px; margin-top: 16px; }
.up-go {
  position: relative; overflow: hidden;
  min-width: clamp(220px, 26vw, 340px); height: 56px; padding: 0 36px;
  clip-path: polygon(12px 0, 100% 0, 100% calc(100% - 12px), calc(100% - 12px) 100%, 0 100%, 0 12px);
  background: linear-gradient(180deg, var(--accent-hi), var(--accent));
  color: #100E00;
  font-family: var(--f-cond); font-size: 18px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .1em;
  transition: transform .16s, filter .2s;
}
.up-go:hover:not(:disabled) { transform: translateY(-2px); filter: brightness(1.06); }
.up-go:active:not(:disabled) { transform: none; }
.up-go:disabled { background: var(--panel-3); color: var(--text-mute); cursor: default; }
.up-go__label { position: relative; z-index: 2; }
.up-go__glow {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(105deg, transparent 38%, rgba(255,255,255,.6) 50%, transparent 62%);
  transform: translateX(-120%);
}
.up-go:not(:disabled) .up-go__glow { animation: up-sheen 3.6s ease-in-out infinite; }
@keyframes up-sheen { 0%, 64% { transform: translateX(-120%); } 88%, 100% { transform: translateX(120%); } }

.up-turbo {
  width: 48px; height: 48px;
  clip-path: polygon(9px 0, 100% 0, 100% calc(100% - 9px), calc(100% - 9px) 100%, 0 100%, 0 9px);
  background: var(--panel-2); color: var(--text-mute);
  display: grid; place-items: center;
  transition: color .15s, background .15s;
}
.up-turbo svg { width: 20px; height: 20px; }
.up-turbo[aria-pressed="true"] { color: #140E00; background: var(--accent); }

.up-note { margin-top: 12px; font-size: 11px; color: var(--text-mute); text-align: center; }
.up-note:empty { display: none; }   /* пустая подсказка не занимает места */
.up-note b { color: var(--text-dim); font-weight: 600; }
.up-note.is-warn { color: var(--gold); }

/* ─────────────── СТОЛЫ ВНИЗУ ─────────────── */

.up-tables { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap); align-items: start; }

.up-panel {
  /* шапка, листалка, список — листалка переехала наверх (см. .up-pager) */
  display: grid; grid-template-rows: auto auto 1fr;
  min-width: 0;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
}
/* Склады — почти чёрные и слегка прозрачные, как сцена над ними: сквозь
   них виден фон раздела, но карточки скинов читаются. Глухая заливка
   var(--panel) делала из них два синевато-серых слепка поверх картинки, и
   страница распадалась на «фон» и «две плиты».

   Селектор с .gm-body — чтобы перевесить общее правило панелей из
   games.css: там та же пара классов, и решает порядок файлов. */
.gm-body .up-panel {
  /* .72, а не .55: на светлых участках камуфляжа полупрозрачная плита
     размывалась в фон, и карточки скинов теряли под собой опору. */
  background: rgba(6, 6, 8, .72);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
/* Шапка склада — не своя заливка, а осветление того, что под ней. Глухой
   var(--panel-2) поверх прозрачной панели читался как серая планка,
   приклеенная сверху.

   Только на широком экране. На телефоне панель прозрачная и лежит внутри
   общей карточки: там любое осветление шапки рисует поперёк карточки
   светлый прямоугольник — ту самую «обводку блока», которой быть не
   должно. Медиазапрос, а не правило в mobile.css: селектор с .gm-body
   перевешивает одноклассовый, сколько бы ниже тот ни стоял. */
@media (min-width: 761px) {
  .gm-body .up-panel__head { background: rgba(255, 255, 255, .045); }
}
.up-panel__head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 14px;
  background: var(--panel-2);
  border-bottom: 1px solid var(--line);
}
.up-panel__ico {
  display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 7px;
  background: var(--accent); color: #100E00;
}
.up-panel__ico svg { width: 18px; height: 18px; }
.up-panel__head h2 {
  font-family: var(--f-cond); font-size: 15px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .05em;
}
.up-panel__sum {
  display: flex; align-items: baseline; gap: 6px; margin-left: 6px;
  font-size: 10px; text-transform: uppercase; letter-spacing: .08em; color: var(--text-mute);
}
.up-panel__sum b {
  font-family: var(--f-cond); font-size: 17px; font-weight: 600; letter-spacing: 0;
  color: var(--up-hi); font-variant-numeric: tabular-nums;
}
.up-panel__sum i { font-style: normal; letter-spacing: .04em; }
/* Кнопка стоит там, где была подпись со ставкой — сразу за названием
   склада, а не прижатой к правому краю: так она относится к складу,
   а не к строке вообще. */
.up-panel__head .up-mini { margin-left: 4px; }

/* ── фильтр витрины ── */

.up-filter { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.up-filter__q, .up-filter__num {
  display: flex; align-items: center; gap: 6px;
  height: 34px; padding: 0 10px; border-radius: 7px;
  background: var(--bg); border: 1px solid var(--line);
  transition: border-color .15s;
}
.up-filter__q { width: 120px; font-size: 12px; color: var(--text); }
.up-filter__num { width: 92px; }
.up-filter__num input {
  width: 100%; min-width: 0; background: none; border: none; outline: none;
  font: inherit; font-size: 12px; color: var(--text);
  font-variant-numeric: tabular-nums;
}
/* Стрелки у number-полей крадут треть ширины и в тёмной теме выглядят
   инородно — диапазон вводят с клавиатуры. */
.up-filter__num input::-webkit-outer-spin-button,
.up-filter__num input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.up-filter__num input[type=number] { -moz-appearance: textfield; }
.up-filter__q:focus, .up-filter__num:focus-within { border-color: rgba(237,224,15,.45); outline: none; }
.up-filter__coin { display: grid; place-items: center; width: 13px; height: 13px; color: var(--accent); flex: none; }
.up-filter__coin svg { width: 100%; height: 100%; }
.up-filter__go {
  display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: 7px;
  background: var(--panel-3); color: var(--text-dim);
  transition: background .15s, color .15s;
}
.up-filter__go svg { width: 17px; height: 17px; }
.up-filter__go[aria-pressed="true"] { background: var(--accent); color: #100E00; }

/* «Снять всё» — не кнопка-плита, а ссылка. Серый прямоугольник рядом с
   названием склада весил столько же, сколько сам заголовок, хотя нажимают
   его раз в сессию. Осталась подпись с тонкой рамкой. */
.up-mini {
  padding: 6px 10px; border-radius: 7px;
  background: none; border: 1px solid var(--line); color: var(--text-mute);
  font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em;
  transition: color .15s, border-color .15s;
}
.up-mini:hover { color: var(--text); border-color: var(--text-mute); }

/* ── полка ── */

.up-shelf {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(122px, 1fr));
  align-content: start;
  gap: 8px; padding: 12px;
  min-height: 300px;
}
.up-shelf__none {
  grid-column: 1 / -1; align-self: center; padding: 40px 20px; text-align: center;
  font-size: 12px; color: var(--text-mute);
}

/* ── плитка ── */

.up-tile {
  position: relative; isolation: isolate; overflow: hidden;
  display: grid; grid-template-rows: auto 1fr auto auto;
  padding: 7px 8px 9px;
  /* Фон по разряду, рамка и состояния — в общем правиле home.css: та же
     карточка, что в инвентаре краша, в панели ставки и на входе контракта. */
  text-align: center;
  transition: transform .16s, border-color .16s;
}
/* Фирменная K за рендером — та же, что в гербе на главной. Красится в цвет
   редкости, поэтому несёт две вещи разом: держит бренд и повторяет цвет
   крупным пятном, по которому набор опознаётся с расстояния, где подписи
   уже не читаются. */
/* K взята маской, а не картинкой.

   Картинкой она была бы жёлтой на всех плитках сразу — и убила бы цвет
   редкости, по которому набор читается с расстояния. Маска берёт из файла
   только альфу, то есть форму мазка, а заливку даёт CSS: получается и
   фактура кисти, и красный у Covert, синий у Mil-Spec.

   Поэтому в файле лежит белое изображение с альфой — цветное было бы
   втрое тяжелее без единого выигрыша. */
/* Буквы K (старый знак Kraze) на плитках больше нет — просили убрать;
   фирменный знак DropHub на всех блоках со скинами ставит общее правило
   в home.css. */
.up-tile__mark { display: none; }
.up-tile__mark--old {
  position: absolute; inset: 4% 8% 14%; z-index: -1;
  /* Заливка — переход от цвета редкости к фирменному жёлтому: знак остаётся
     узнаваемо кразовским и при этом не теряет цветовой сигнал набора. */
  background: linear-gradient(150deg, var(--r, #4b69ff) 0%, var(--accent) 92%);
  -webkit-mask: url('assets/drophub_k_mask.png') center / contain no-repeat;
          mask: url('assets/drophub_k_mask.png') center / contain no-repeat;
  opacity: .17;
  transition: opacity .18s;
}
/* Заливка от нижней кромки держит подписи на контрасте, когда рендер
   светлый и сам по себе спорит с текстом. */
.up-tile::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, transparent 40%, rgba(0,0,0,.5) 100%),
              radial-gradient(78% 52% at 50% 22%, var(--r) 0%, transparent 72%);
  opacity: .3;
  transition: opacity .18s;
}
.up-tile:hover { transform: translateY(-3px); border-color: rgba(255,255,255,.16); }
.up-tile:hover .up-tile__mark { opacity: .28; }
.up-tile:hover::before { opacity: .46; }

.up-tile__top { display: flex; align-items: center; gap: 4px; }
.up-tile__corner { margin-left: auto; font-size: 9px; font-weight: 600; letter-spacing: .06em; color: var(--text-mute); }
.up-tile__x { font-family: var(--f-cond); font-size: 12px; font-weight: 600; letter-spacing: .02em; color: var(--up-hi); }
.up-tile.is-target .up-tile__x { color: var(--accent); }
.up-tile__price {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 11px; font-weight: 600; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.up-coin { display: grid; place-items: center; width: 11px; height: 11px; color: var(--accent); flex: none; }
.up-coin svg { width: 100%; height: 100%; }

.up-tile__art { display: block; height: 64px; width: 100%; margin: 4px 0 10px; }
/* Размер задан явно, а не через max-height.

   Через max-height рендер не вписывался: у картинки собственная высота
   96px, и она вылезала за свой бокс в 64px, наезжая на название снизу на
   двадцать с лишним пикселей. width/height + object-fit: contain снимают
   спор — картинка занимает ровно отведённое место и вписывается в него по
   своим пропорциям.

   Тень убрана: под каждым рендером она давала грязный ореол, а свечение
   редкости на плитке отделяет предмет от фона и без неё. */
.up-tile__art img { width: 100%; height: 100%; object-fit: contain; }

/* Серым — оружие, белым жирным — финиш. Именно так их читают: AWP это
   категория, а покупают Dragon Lore. */
.up-tile__weapon {
  font-size: 9px; font-weight: 500; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-mute);
  max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.up-tile__finish {
  font-family: var(--f-cond); font-size: 13px; font-weight: 600;
  letter-spacing: .02em; color: #fff; line-height: 1.15;
  max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.up-tile.is-on { border-color: var(--up); }
.up-tile.is-on .up-tile__mark { opacity: .32; }
.up-tile.is-on .up-tile__price { color: var(--up-hi); }
.up-tile__tick {
  flex: none; width: 14px; height: 14px; border-radius: 50%;
  background: var(--up); color: #fff;
  display: grid; place-items: center; font-size: 8px; font-weight: 700;
}

.up-tile.is-target { border-color: var(--accent); }
.up-tile.is-target .up-tile__price { color: var(--accent); }

.up-tile.is-off { opacity: .3; pointer-events: none; }

.up-tile.is-fresh { border-color: var(--accent); animation: up-land .6s cubic-bezier(.2,1.4,.4,1); }
@keyframes up-land { from { opacity: 0; transform: translateY(-14px) scale(.94); } }
.up-tile__new {
  position: absolute; bottom: 7px; left: 7px; z-index: 4;
  padding: 1px 5px; border-radius: 3px;
  background: var(--accent); color: #100E00;
  font-size: 8px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
}
.up-tile.is-on .up-tile__new { display: none; }

/* ── постраничность ── */

/* Листалка стоит НАД списком, а не под ним. Под списком до неё надо было
   долистать весь экран предметов — а нужна она ровно тогда, когда нужного
   на этой странице не нашлось. Сверху она видна сразу.

   position: relative — под счётчик слева, он уходит в абсолют, чтобы
   стрелки со страницей остались ровно по центру, а не были сдвинуты
   вправо на его ширину. */
.up-pager {
  position: relative; order: 2;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 8px 14px;
  border-bottom: 1px solid var(--line-soft);
}
.up-panel__head { order: 1; }
.up-shelf { order: 3; }
.up-pager__btn {
  display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 7px;
  background: var(--panel-3); color: var(--text-dim);
  transition: background .15s, color .15s;
}
.up-pager__btn svg { width: 16px; height: 16px; }
/* Иконка одна — шеврон вниз, поэтому назад и вперёд получаются поворотом,
   а не второй картинкой. */
.up-pager__btn[data-dir="-1"] svg { transform: rotate(90deg); }
.up-pager__btn[data-dir="1"]  svg { transform: rotate(-90deg); }
.up-pager__btn:hover:not(:disabled) { background: var(--line); color: var(--text); }
.up-pager__btn:disabled { opacity: .35; cursor: default; }
.up-pager__n {
  font-family: var(--f-cond); font-size: 13px; letter-spacing: .06em;
  color: var(--text-dim); font-variant-numeric: tabular-nums; min-width: 52px; text-align: center;
}
.up-pager__n--left { position: absolute; left: 14px; margin: 0; min-width: 0; font-size: 11px; color: var(--text-mute); }

/* ─────────────── ИСТОРИЯ ─────────────── */

.up-hist {
  margin-top: var(--gap);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
}
.up-hist__head { display: flex; align-items: center; padding: 10px 12px; border-bottom: 1px solid var(--line-soft); }
.up-hist__head h2 {
  font-family: var(--f-cond); font-size: 12px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .09em;
}
.up-hist__head span { margin-left: auto; font-size: 11px; color: var(--text-mute); font-variant-numeric: tabular-nums; }
.up-hist__row { display: flex; gap: 6px; padding: 10px; overflow-x: auto; }
.up-pill {
  flex: none; display: grid; gap: 1px; justify-items: center;
  min-width: 78px; padding: 7px 10px;
  clip-path: polygon(7px 0, 100% 0, 100% calc(100% - 7px), calc(100% - 7px) 100%, 0 100%, 0 7px);
  background: var(--panel-2); border-bottom: 2px solid var(--lose);
  animation: up-slide .3s cubic-bezier(.2,1.2,.4,1);
}
.up-pill.is-won { border-bottom-color: var(--win); }
.up-pill b { font-family: var(--f-cond); font-size: 14px; font-weight: 600; color: var(--lose); }
.up-pill.is-won b { color: var(--win); }
.up-pill span { font-size: 9px; color: var(--text-mute); font-variant-numeric: tabular-nums; }
@keyframes up-slide { from { opacity: 0; transform: translateX(-10px); } }

/* ─────────────── ПАНЕЛЬ ЧЕСТНОСТИ ─────────────── */
@keyframes up-fade { from { opacity: 0; } }
@keyframes up-rise { from { opacity: 0; transform: translateY(14px); } }

/* ─────────────── АДАПТИВ ─────────────── */

@media (max-width: 1000px) {
  .up-tables { grid-template-columns: minmax(0, 1fr); }
}
/* Два склада рядом — строки общие (subgrid): шапки, листалки и сетки
   скинов стоят на одном уровне, даже если шапка витрины с полями поиска
   выше шапки инвентаря. Панели одной высоты. */
@media (min-width: 1001px) {
  @supports (grid-template-rows: subgrid) {
    .up-tables { grid-template-rows: auto auto 1fr; align-items: stretch; }
    .up-tables > .up-panel { grid-row: span 3; grid-template-rows: subgrid; }
    .up-tables .up-panel__head { grid-row: 1; }
    .up-tables .up-pager { grid-row: 2; }
    .up-tables .up-shelf { grid-row: 3; }
  }
}
@media (max-width: 720px) {
  .up-duel { grid-template-columns: minmax(0, 1fr); }
  /* Порядок «что ставлю → шанс → что беру» и есть объяснение режима,
     поэтому на узком экране шкала остаётся между плитами. */
  .up-slot--stake { order: 1; justify-self: center; }
  .up-dial { order: 2; }
  .up-slot--target { order: 3; justify-self: center; }
  /* Перемычки связывают плиты со шкалой по горизонтали. В столбик они
     показывали бы связь, которой на экране уже нет. */
  .up-go { flex: 1; min-width: 0; }
  .up-panel__q { width: 100%; order: 9; margin-left: 0; }
}

@media (prefers-reduced-motion: reduce) {
.up-go__glow { animation: none; }
.up-pill,
.up-tile.is-fresh { animation: none; }
  /* Явление предмета без движения: он просто есть, кольцо не стягивается. */
  .up-reveal, .up-reveal *, .up-dial.is-collapse .up-dial__svg,
  .up-dial.is-restore .up-dial__svg, .up-dial.is-collapse .up-needle,
  .up-dial.is-restore .up-needle { animation: none !important; }
  .up-reveal__wave, .up-reveal__core { display: none; }
  .up-shards, .up-arrows { display: none; }
  .up-page[data-state="lost"] .up-slot--stake { animation: none; filter: grayscale(1) brightness(.5); }
  .up-page[data-state="won"] .up-slot--target { animation: none; }
}

/* ═══════════════ СЦЕНА: ГЛУБИНА И ЖИЗНЬ ═══════════════
   Всё ниже добавлено к уже описанной шкале. Ни одна анимация тут не
   декоративная: каждая сообщает состояние, которое иначе пришлось бы
   подписывать словами. */

/* Перемычек между плитами и шкалой больше нет.

   Две тонкие горизонтальные черты по бокам кольца задумывались как связь
   «ставка → шкала → цель», но на кадре читались как обрывки линий, забытые
   в вёрстке. Связь и так очевидна: три блока стоят в ряд, между ними ничего
   другого нет. */

/* ── глубина шкалы ── */

/* Дыхание подсветки в покое. Останавливается на время броска: там своей
   динамики достаточно, и лишняя пульсация читается как рябь. */
.up-dial::before {
  content: ''; position: absolute; inset: 8%;
  border-radius: 50%; pointer-events: none; z-index: -1;
  background: radial-gradient(circle, rgba(166,44,255,.16) 0%, transparent 68%);
  animation: up-breathe 4.6s ease-in-out infinite;
}
@keyframes up-breathe {
  0%, 100% { opacity: .55; transform: scale(.94); }
  50%      { opacity: 1;   transform: scale(1.04); }
}
.up-page[data-state="spinning"] .up-dial::before { animation: none; opacity: 1; }
/* ─── ЗАТЕМНЕНИЕ СЦЕНЫ НА ВЫИГРЫШ ───

   Всё, кроме выигранного предмета, уходит в тень: плиты ставки и цели,
   кнопка, подписи. Тот же приём, что у выдвижного меню на телефоне —
   гаснет страница, а то, ради чего её открыли, остаётся ярким.

   z-index: 3 — выше плит (у них z-index auto) и ниже окна выигрыша (4),
   поэтому предмет с кнопками остаётся поверх. pointer-events: none —
   слой не должен перехватывать нажатия по «Продать» и «Оставить». */
.up-stage::after {
  content: ''; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: rgba(3, 4, 6, .62);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  opacity: 0; transition: opacity .32s;
}
.up-page[data-state="won"] .up-stage::after { opacity: 1; }

/* На исходе подсветка гаснет совсем. Пока в центре была цифра шанса,
   цветное пятно под ней читалось как отклик шкалы. Теперь там стоит сам
   выигранный предмет, и жёлтое пятно вокруг него выглядит свечением
   скина — вещь будто светится изнутри, хотя это фон под ней. */
.up-page[data-state="won"]  .up-dial::before,
.up-page[data-state="lost"] .up-dial::before { opacity: 0; animation: none; }

/* Риски-границы зоны выигрыша больше нет.

   Ставилась на конец дуги, чтобы после остановки было видно, на сколько
   именно промахнулся. Но она вращается вместе с шансом, и на трёх четвертях
   круга встаёт почти горизонтально — тогда это уже не метка на шкале, а
   короткая чёрточка, висящая сбоку без видимой причины. */

/* ── вспышки-щелчка больше нет ──
   Задумывалась как «щёлк, щёлк» механизма на подходе к остановке. Но у
   самой остановки риски проходят часто, вспышки ложились подряд — и это
   читалось не как механизм, а как мигающая стрелка, то есть как сбой
   отрисовки. Торможение и без неё видно по скорости самой метки. */

/* ── цифра шанса ── */

/* Мигание при смене выбора: число не просто подменяется, а коротко
   вспыхивает — иначе правка ставки на копейку проходит незамеченной. */
.up-dial__pct { transition: color .3s, text-shadow .3s; }
.up-dial.is-bump .up-dial__pct { animation: up-bump .32s cubic-bezier(.2,1.6,.4,1); }
@keyframes up-bump {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.07); }
  100% { transform: scale(1); }
}
.up-page[data-state="won"] .up-dial__pct { text-shadow: 0 0 26px rgba(237,224,15,.6); }

/* ── плиты: реакция на выбор ── */

.up-slot.is-set { animation: up-slot-in .42s cubic-bezier(.2,1.4,.4,1); }
@keyframes up-slot-in {
  0%   { transform: scale(.97); }
  55%  { transform: scale(1.015); }
  100% { transform: scale(1); }
}
/* Рендер слегка покачивается в покое — предмет лежит, а не наклеен. */
.up-art__img { animation: up-float 5.5s ease-in-out infinite; }
@keyframes up-float {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -5px; }
}
.up-page[data-state="spinning"] .up-art__img { animation-play-state: paused; }

/* ── кнопка ── */

/* Пока крутится, кнопка не просто заблокирована — по ней идёт полоса,
   тем же ритмом, что и импульс на перемычках. */
.up-page[data-state="spinning"] .up-go {
  background: var(--panel-3); color: var(--text-mute);
  overflow: hidden;
}
.up-page[data-state="spinning"] .up-go::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(196,107,255,.35), transparent);
  animation: up-sweep 1.1s linear infinite;
}
@keyframes up-sweep {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}

@media (prefers-reduced-motion: reduce) {
  .up-dial::before, .up-dial::after,
  .up-r__run, .up-r__chev path,
  .up-art__img, .up-fan__card,
  .up-page[data-state="spinning"] .up-go::after { animation: none !important; }
  .up-slot.is-set { animation: none; }
  .up-dial.is-bump .up-dial__pct { animation: none; }
}

/* ═══════════════ ОКНА СТАВКИ И ЦЕЛИ ═══════════════
   Раньше это были два тёмных прямоугольника с картинкой посередине — форма,
   которая ничего не сообщала и ни к чему не относилась. Теперь у предмета
   есть подставка, отражение, подпись редкости и уголковая рамка. */

/* Уголки. Стоят по диагонали, на верхнем правом и нижнем левом. Раньше
   выбор был вынужденным — два других угла срезал clip-path; теперь плита
   скруглена со всех сторон, а диагональ оставлена как есть: скобы на всех
   четырёх углах превращают плиту в мишень прицела. */
.up-slot__frame { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.up-slot__frame::before, .up-slot__frame::after {
  content: ''; position: absolute; width: 20px; height: 20px;
  border: 2px solid var(--corner, rgba(255,255,255,.12));
  transition: border-color .3s;
}
.up-slot__frame::before { top: 10px; right: 10px; border-left: 0; border-bottom: 0; }
.up-slot__frame::after  { bottom: 10px; left: 10px; border-right: 0; border-top: 0; }
.up-slot--stake.is-set  { --corner: rgba(196,107,255,.75); }
.up-slot--target.is-set { --corner: rgba(237,224,15,.7); }

/* ── подставка ── */

.up-art {
  position: relative;
  display: block; width: 100%;
  /* отступ снизу был местом под отражение — отражения больше нет */
}
.up-art__img, .up-art__mirror {
  display: block; margin: 0 auto;
  max-width: 88%; max-height: clamp(96px, 10.5vw, 138px);
  object-fit: contain;
}
.up-art__img { filter: drop-shadow(0 14px 22px rgba(0,0,0,.8)); }

/* Ни отражения, ни светового пятна под предметом. Пол имеет смысл, когда
   плита нейтральная: пятно цвета редкости говорило, что вещь «стоит», а не
   «висит». На плите, целиком покрашенной в тот же цвет, оно превратилось в
   светлую полосу поперёк, а перевёрнутая копия ножа под ней читалась не
   отблеском, а вторым предметом. */
.up-art__mirror { display: none; }

/* ── подписи ── */

.up-slot__tag {
  display: inline-block; padding: 2px 9px; border-radius: 3px;
  background: color-mix(in srgb, var(--r) 22%, transparent);
  color: var(--r);
  font-size: 9px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
}
/* Запасной вариант для движков без color-mix: цвет текста всё равно
   приходит из --r, поэтому подпись останется читаемой и без фона. */
@supports not (background: color-mix(in srgb, red 10%, transparent)) {
  .up-slot__tag { background: rgba(255,255,255,.07); }
}

.up-slot__name {
  font-size: 12px; color: var(--text-dim); text-align: center;
  max-width: 28ch; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ── пустое окно ──
   Не серая надпись посреди пустоты, а обозначенное место под предмет:
   штриховой контур сразу говорит, что сюда что-то кладут. */
.up-slot__empty {
  display: grid; justify-items: center; gap: 7px;
  font-size: 11px; color: var(--text-mute); text-align: center;
}
/* Силуэт вместо пунктирного квадрата. Обесцвечен и притушен: он занимает
   место будущего предмета и подсказывает, чего от плиты ждут, но не
   притворяется выбранным скином.

   Картинка берётся из каталога (см. ghostSrc в upgrade.view.js) — у неё
   настоящая прозрачность. Локальный рендер ножа лежал здесь чёрным
   прямоугольником: он непрозрачный, а вырезать фон по яркости не выходит
   — клинок на нём почти такой же тёмный, как подложка. */
.up-slot__ghost {
  display: block; width: clamp(96px, 10vw, 132px); height: auto;
  object-fit: contain;
  filter: grayscale(1) brightness(1.1) contrast(.95);
  opacity: .26;
}
/* .up-slot__box больше не рисуется (см. blank в upgrade.view.js). */

/* Пустая плита показывает только силуэт и подпись. Слово «Ставка» над
   пустым местом повторяет то же, что говорит подпись под ним, а «0.00»
   внизу — сумма несуществующей ставки. Как только предмет выбран, и
   заголовок, и цена возвращаются. */
.up-slot:not(.is-set) .up-slot__cap,
.up-slot:not(.is-set) .up-slot__foot { display: none; }
.up-slot__empty b {
  font-family: var(--f-cond); font-size: 13px; font-weight: 500;
  text-transform: uppercase; letter-spacing: .09em; color: var(--text-dim);
}
.up-slot__empty em {
  font-style: normal; font-size: 10px; max-width: 20ch; line-height: 1.4;
}

/* ── цена ──
   Крупная строка внизу окна на своей подложке: это второе по важности
   число на сцене после шанса, и оно не должно теряться под картинкой. */
.up-slot__foot {
  width: 100%; padding-top: 10px; margin-top: 2px;
  border-top: 1px solid rgba(255,255,255,.06);
  text-align: center;
}

/* Окно чуть просторнее: подставке, подписи и цене нужен воздух, иначе они
   слипаются в одну кашу. */
.up-slot { padding: 18px 16px 14px; gap: 8px; }
.up-slot__body { min-height: clamp(126px, 13vw, 176px); }

/* ═══════════════ ВЕЕР: НЕСКОЛЬКО ПРЕДМЕТОВ В СТАВКЕ ═══════════════

   Голые рендеры внахлёст сливались в одно пятно: у оружия нет собственной
   границы, и пятая картинка просто пропадала в четвёртой. Каждый предмет
   получает свою карточку с подложкой и цветом редкости — граница появляется,
   и стопка снова читается как стопка.

   Раскладка дугой: сдвиг вниз растёт как квадрат расстояния от центра, а не
   линейно. При линейном сдвиге карточки выстраиваются по прямой наклонной
   линии, при квадратичном — по дуге, как веер карт в руке. */

.up-fan {
  display: flex; justify-content: center; align-items: flex-end;
  width: 100%; padding-top: 6px;
}

.up-fan__card {
  position: relative; isolation: isolate;
  flex: none;
  width: clamp(58px, 7vw, 84px);
  aspect-ratio: 4 / 3;
  margin-inline: clamp(-20px, -1.8vw, -12px);
  display: grid; place-items: center;
  padding: 6px;
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
  background: linear-gradient(168deg, #16171A 0%, #0B0B0D 100%);
  transform: rotate(var(--rot, 0deg)) translateY(var(--dy, 0));
  transform-origin: 50% 120%;
  transition: transform .28s cubic-bezier(.2,1.3,.4,1), filter .2s;
  animation: up-card-in .42s cubic-bezier(.2,1.4,.4,1) both;
  animation-delay: calc(var(--i, 0) * 55ms);
}
@keyframes up-card-in {
  from { opacity: 0; transform: rotate(0deg) translateY(22px) scale(.86); }
}

/* Свечение редкости под рендером — то же, что на плитках внизу, поэтому
   предмет в ставке и он же в инвентаре выглядят одним и тем же предметом. */
.up-fan__card::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(68% 58% at 50% 38%, var(--r) 0%, transparent 72%);
  opacity: .3;
}
.up-fan__card::after {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  clip-path: inherit;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.07);
}
.up-fan__card img {
  max-width: 100%; max-height: 100%; object-fit: contain;
  filter: drop-shadow(0 4px 9px rgba(0,0,0,.6));
}

/* Наведение вытаскивает карточку из стопки и ставит прямо: иначе средние
   предметы нельзя рассмотреть вовсе, а в ставке из шести это половина. */
.up-fan__card:hover {
  transform: rotate(0deg) translateY(-12px) scale(1.06);
  z-index: 20 !important;
}

/* Счётчик остатка держит форму карточки — иначе он читается как отдельный
   элемент интерфейса, а не как «и ещё столько же таких же». */
.up-fan__more {
  flex: none;
  width: clamp(40px, 5vw, 56px);
  aspect-ratio: 4 / 3;
  margin-left: 4px;
  display: grid; place-items: center;
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
  background: rgba(166,44,255,.16);
  color: var(--up-hi);
  font-family: var(--f-cond); font-size: 15px; font-weight: 600; letter-spacing: .02em;
}

/* ═══════════════ ТЕМА САЙТА: ЯЗЫК «1 КЛИКА» ═══════════════
   Всё вокруг кольца собрано из деталей «1 Клика»: индиго-стол, стекло,
   «колодцы» под суммы и поля, лаймовая главная кнопка, подписи с разрядкой.
   Кольцо (.up-dial целиком), окно исхода и терминал кейса здесь не
   трогаются. Общие токены (--text-mute, --text-dim, --accent, --money,
   --up-hi, --radius) не переопределяются — на них стоят подписи и кнопки
   кольца; новые цвета живут только под своими именами --upx-*.
   Цвета повторяют дугу кольца: фиолет — что ставлю (её начало), лайм —
   что беру и главное действие (её конец). Жёлтый остался только в кольце.

   Вес селекторов не случайный: games.css (зелёная .gm-body .up-go, рамки
   .gm-body .up-panel) идёт раньше, mobile.css и drophub.skincard.css — позже.
   Поэтому общее — с префиксом .up-body, панели — .gm-body.up-body, а то,
   что только для широкого экрана, — в @media (min-width: 761px).

   Широких селекторов вроде «.up-stage button» здесь нет намеренно: под них
   попали бы кнопки окна исхода («Продать», «Открыть сейчас») — они часть
   кольца. Всё перечислено поимённо. */
.up-body { background-color: #1A1430; }
.up-page {
  --upx-s1: #221B3E; --upx-s2: #2C2452; --upx-s3: #372E62; --upx-deep: #150F2B;
  --upx-glass: linear-gradient(180deg, #2C2452 0%, #241D45 100%);
  --upx-well:  linear-gradient(180deg, #150F2B 0%, #1B1436 100%);
  --upx-line: #3A3166; --upx-line2: #4C4182;
  --upx-hl: inset 0 1px 0 rgba(255, 255, 255, .07);
  --upx-text: #F5F3FF; --upx-dim: #BDB7DE; --upx-mute: #A69FCF; --upx-faint: #8F87B8; --upx-ink: #CFC8F0;
  --upx-stake: #C46BFF;   /* что ставлю — фиолет, начало дуги */
  --upx-goal: #D7FF00;    /* что беру — лайм, конец дуги */
  /* «включено» лаймом — индиго-заливка и чистая лаймовая рамка, как
     активная сумма в рулетке (см. .up-chip.is-on) */
  --upx-on-bg: linear-gradient(180deg, #2E2658 0%, #241D45 100%);
  --upx-on-shadow: inset 0 1px 0 rgba(255, 255, 255, .07), 0 0 12px rgba(215, 255, 0, .18);
  max-width: 1480px;
}
/* Граффити-кадр за страницей выключен: яркий слой по краям спорил с
   кольцом и делал раздел чужим остальному сайту. --pb* от alignStageBg
   продолжают считаться и никем не читаются — безвредно, а --dial оттуда
   же по-прежнему задаёт размер кольца. */
.up-page::before, .up-page::after { display: none; }

/* ── заголовок раздела ──
   На линиях, как .oc-title. Саму полосу ставит drophub.gamebar.js перед
   <main>, поэтому перекраска здесь, а не в разметке. Подпись «Подними скин
   до дорогого» убрана: под заголовком сразу стол, и он объясняет сам. */
.up-body .kz-gbar { max-width: 1480px; padding: 10px var(--pad-x, 20px) 0; justify-content: center; gap: 12px; }
.up-body .kz-gbar::before, .up-body .kz-gbar::after { content: ''; flex: 1; height: 1px; min-width: 24px; }
.up-body .kz-gbar::before { margin-right: 6px; background: linear-gradient(90deg, transparent, rgba(166, 120, 255, .35)); }
.up-body .kz-gbar::after  { margin-left: 6px;  background: linear-gradient(270deg, transparent, rgba(166, 120, 255, .35)); }
.up-body .kz-gbar .kz-gico { width: 30px; height: 30px; flex: none; }
.up-body .kz-gbar__txt { display: block; flex: none; }
.up-body .kz-gbar__txt b { font-size: 30px; font-weight: 600; letter-spacing: .06em; line-height: 1.1; color: var(--upx-text); text-shadow: 0 0 24px rgba(166, 44, 255, .45); }
.up-body .kz-gbar__txt i { display: none; }

/* ── стол ──
   Как .oc-game: лампа сверху, угловые разливы, сетка и искры. Без
   transform — его анимирует compReel, сжимая стол в линию под терминал
   кейса; position, isolation и overflow — из базового правила. */
.up-body .up-stage {
  margin-bottom: 14px;
  /* Низ тоньше верха: под кнопкой всегда стоит строка подсказки (18 px +
     8 отступа). Вместе выходит ~30 сверху и ~36 снизу — при 24/18 кнопка
     казалась прижатой вверх, а низ стола пустой полосой. */
  padding: 30px 24px 10px;
  border: 1px solid var(--upx-line); border-radius: 28px;
  background:
    radial-gradient(40% 46% at 50% 0%, rgba(140, 90, 255, .30), transparent 72%),
    radial-gradient(60% 50% at 0% 100%, rgba(110, 80, 230, .14), transparent 70%),
    radial-gradient(60% 50% at 100% 100%, rgba(110, 80, 230, .14), transparent 70%),
    linear-gradient(180deg, #261E4A 0%, #201941 58%, #1D163A 100%);
  box-shadow: 0 24px 60px rgba(8, 4, 24, .45), inset 0 1px 0 rgba(255, 255, 255, .07), inset 0 0 120px rgba(14, 8, 36, .35);
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
/* сетка 44 px, гаснет к краям — плоскость не выглядит пустой заливкой */
.up-body .up-stage::before {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image:
    linear-gradient(rgba(190, 170, 255, .06) 1px, transparent 1px),
    linear-gradient(90deg, rgba(190, 170, 255, .06) 1px, transparent 1px);
  background-size: 44px 44px; background-position: center -1px;
  -webkit-mask-image: radial-gradient(64% 70% at 50% 40%, #000 0%, rgba(0, 0, 0, .35) 55%, transparent 85%);
          mask-image: radial-gradient(64% 70% at 50% 40%, #000 0%, rgba(0, 0, 0, .35) 55%, transparent 85%);
}
/* .up-stage__tint исходом больше не пользуется (заливку на исход убрали
   выше) — слой свободен и несёт редкие искры, как .oc-game::after */
.up-body .up-stage__tint {
  opacity: 1; transition: none;
  background:
    radial-gradient(1.6px 1.6px at 7% 18%, rgba(215, 255, 0, .8), transparent),
    radial-gradient(1.2px 1.2px at 13% 52%, rgba(255, 255, 255, .55), transparent),
    radial-gradient(1.8px 1.8px at 19% 82%, rgba(166, 120, 255, .8), transparent),
    radial-gradient(1.2px 1.2px at 27% 30%, rgba(255, 255, 255, .4), transparent),
    radial-gradient(1.4px 1.4px at 74% 24%, rgba(166, 120, 255, .85), transparent),
    radial-gradient(1.2px 1.2px at 81% 58%, rgba(255, 255, 255, .5), transparent),
    radial-gradient(1.7px 1.7px at 88% 14%, rgba(215, 255, 0, .7), transparent),
    radial-gradient(1.3px 1.3px at 93% 76%, rgba(166, 120, 255, .7), transparent),
    radial-gradient(1.1px 1.1px at 64% 88%, rgba(255, 255, 255, .35), transparent),
    radial-gradient(1.1px 1.1px at 36% 92%, rgba(255, 255, 255, .35), transparent);
  animation: up-twinkle 5s ease-in-out infinite alternate;
}
@keyframes up-twinkle { from { opacity: .45; } to { opacity: 1; } }
/* затемнение на выигрыш — тот же слой (z 3, без нажатий), только индиго:
   чёрная плёнка на фиолетовом столе давала грязно-серый */
.up-body .up-stage::after { background: rgba(16, 10, 36, .66); border-radius: inherit; }

/* Гнездо под кольцом: угольное кольцо прямо на фиолетовом столе читалось
   чужим кругом, наклеенным сверху; в тёмном углублении — прибором,
   вставленным в стол. Слой сцены ПОД кольцом (z -1), --dial — только на
   чтение. У .up-duel нет z-index/transform — иначе окно исхода ушло бы
   под затемнение. */
@media (min-width: 761px) {
  .up-body .up-duel::before {
    content: ''; position: absolute; left: 50%; top: 50%; z-index: -1; pointer-events: none;
    width: calc(var(--dial) + 40px); aspect-ratio: 1; border-radius: 50%;
    transform: translate(-50%, -50%);
    background: rgba(21, 15, 43, .78);
    box-shadow: inset 0 0 0 1px rgba(166, 120, 255, .16), inset 0 2px 14px rgba(6, 2, 20, .5),
                0 0 0 10px rgba(166, 120, 255, .035);
  }
  /* Гнездо (+ ореол 10 px) выходит за шкалу на 30 px с каждой стороны, а
     отступы считались от самой шкалы: сверху до кромки стола оставался
     1 px, до плит по бокам — 4 px, кольцо выглядело зажатым (владелец
     2026-11-02). Сверху и между колонками — плюс этот вылет. */
  .up-body .up-stage { padding-top: 50px; }
  .up-body .up-duel { column-gap: calc(clamp(12px, 2.4vw, 38px) + 22px); }
}

/* ── плиты ставки и цели ── */
.up-body .up-slot {
  --edge: var(--upx-line);
  border-radius: 20px;
  background: var(--upx-glass);
  -webkit-backdrop-filter: none; backdrop-filter: none;
  box-shadow: 0 14px 30px rgba(8, 4, 24, .35);
}
.up-body .up-slot::after { box-shadow: inset 0 0 0 1px var(--edge), inset 0 1px 0 rgba(255, 255, 255, .07); }
.up-body .up-slot--stake.is-set  { --edge: rgba(196, 107, 255, .55); }
/* лайм кромки — плотный: при .42 он мешался с индиго в оливковую линию */
.up-body .up-slot--target.is-set { --edge: rgba(215, 255, 0, .75); }
/* Цвет разряда — пятном под предметом и лёгким тоном сверху, а не заливкой
   всей плиты: сплошной бордовый у Covert на индиго превращался в муть. */
.up-body .up-slot.is-set {
  background:
    radial-gradient(72% 58% at 50% 36%, color-mix(in srgb, var(--r) 34%, transparent), transparent 72%),
    linear-gradient(180deg, color-mix(in srgb, var(--r) 14%, #2C2452) 0%, #241D45 78%);
}
/* Уголки-скобы и отдельное пятно больше не нужны: кромку держит ::after,
   пятно — сам фон плиты */
.up-body .up-slot__glow, .up-body .up-slot__frame { display: none; }
/* молнии сайта, как у карточек скинов (drophub.skincard.css): плита с
   предметом и он же на складе выглядят одним семейством */
.up-body .up-slot::before {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none; border-radius: inherit;
  background: linear-gradient(180deg, color-mix(in srgb, var(--r) 40%, #fff) 0%, transparent 58%);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill='%23000'%3E%3Cpath d='M11.5 2 5 12.2h4.3L7 20l7.2-10.8H9.8z'/%3E%3Cpath d='M31.5 22 25 32.2h4.3L27 40l7.2-10.8h-4.4z'/%3E%3C/g%3E%3C/svg%3E") 0 0 / 40px 40px repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill='%23000'%3E%3Cpath d='M11.5 2 5 12.2h4.3L7 20l7.2-10.8H9.8z'/%3E%3Cpath d='M31.5 22 25 32.2h4.3L27 40l7.2-10.8h-4.4z'/%3E%3C/g%3E%3C/svg%3E") 0 0 / 40px 40px repeat;
  opacity: 0; transition: opacity .3s;
}
.up-body .up-slot.is-set::before { opacity: .1; }
/* подпись с цветной точкой — та же роль, что у дуги: фиолет / лайм */
.up-body .up-slot__cap {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--f-body); font-size: 11px; font-weight: 700; letter-spacing: .14em; color: var(--upx-mute);
}
.up-body .up-slot__cap::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--upx-stake); box-shadow: 0 0 8px rgba(196, 107, 255, .7); }
.up-body .up-slot--target .up-slot__cap::before { background: var(--upx-goal); box-shadow: 0 0 8px rgba(215, 255, 0, .6); }
.up-body .up-slot__tag {
  padding: 3px 8px; border-radius: 7px;
  background: color-mix(in srgb, var(--r) 16%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--r) 42%, transparent);
  color: color-mix(in srgb, var(--r) 55%, #fff);
  font-size: 9.5px; font-weight: 800; letter-spacing: .12em;
}
.up-body .up-slot__name { font-size: 12.5px; font-weight: 600; color: var(--upx-dim); }
/* цена — в «колодце», как сумма ставки в «1 Клике»: второе число стола
   после шанса стоит на своём месте, а не висит под чертой */
.up-body .up-slot__foot {
  display: flex; align-items: center; justify-content: center;
  height: 46px; padding: 0 12px; margin-top: 2px; border-top: 0; border-radius: 14px;
  background: var(--upx-well);
  box-shadow: inset 0 2px 6px rgba(6, 2, 20, .45), 0 1px 0 rgba(255, 255, 255, .05);
}
.up-body .up-slot__foot b { font-size: 24px; color: var(--upx-text); }
.up-body .up-slot--stake.is-set .up-slot__foot b { color: #DCC4FF; }
.up-body .up-slot--target.is-set .up-slot__foot b { color: var(--upx-goal); text-shadow: 0 0 14px rgba(215, 255, 0, .25); }
/* пустая плита — обозначенное место под предмет: штрих и силуэт */
.up-body .up-slot:not(.is-set) .up-slot__body {
  border: 1px dashed rgba(166, 120, 255, .26); border-radius: 16px;
  background: radial-gradient(60% 60% at 50% 45%, rgba(140, 90, 255, .10), transparent 75%);
}
.up-body .up-slot__ghost { opacity: .22; filter: grayscale(1) brightness(1.5) contrast(.9); }
/* 16ch из базового правила уже силуэта (до 132 px): картинка вылезала
   вправо, и пустая плита стояла со смещённым центром */
.up-body .up-slot__empty { max-width: 100%; }
.up-body .up-slot__empty b { font-family: var(--f-body); font-size: 11px; font-weight: 700; letter-spacing: .12em; color: var(--upx-mute); max-width: 22ch; }
/* Текущий шаг — кромка цветом своей роли: без ставки зовёт «Ставка»
   (фиолет), после неё — «Цель» (лайм). Подписи над пустой плитой нет
   намеренно — см. «Пустая плита показывает только силуэт и подпись» выше. */
.up-body .up-slot--stake:not(.is-set) { --edge: rgba(196, 107, 255, .5); }
.up-body .up-slot--stake:not(.is-set) .up-slot__body { border-color: rgba(196, 107, 255, .42); }
.up-body .up-slot--stake.is-set ~ .up-slot--target:not(.is-set) { --edge: rgba(215, 255, 0, .6); }
.up-body .up-slot--stake.is-set ~ .up-slot--target:not(.is-set) .up-slot__body { border-color: rgba(215, 255, 0, .5); }

/* Пустая плита — кнопка к своему складу (клик — toShelf в upgrade.main.js,
   роль и tabindex — slotBtn в upgrade.view.js). Под подписью стрелка вниз:
   склад под столом. Наведение ярче кромкой, силуэтом и стрелкой. */
.up-body .up-slot:not(.is-set) { cursor: pointer; }
.up-body .up-slot:not(.is-set) .up-slot__body { transition: border-color .18s, background-color .18s; }
.up-body .up-slot__ghost { transition: opacity .18s; }
.up-body .up-slot__arrow {
  display: grid; place-items: center; width: 26px; height: 26px; margin-top: 2px; border-radius: 50%;
  color: var(--upx-mute); background: rgba(21, 15, 43, .55);
  box-shadow: inset 0 0 0 1px var(--upx-line2);
  transition: transform .18s, color .18s, box-shadow .18s;
}
.up-body .up-slot__arrow svg { width: 14px; height: 14px; }
/* стрелка в цвете текущего шага: без ставки — фиолет у «Ставки», после
   неё — лайм у «Цели» */
.up-body .up-slot--stake:not(.is-set) .up-slot__arrow { color: #D9B8FF; box-shadow: inset 0 0 0 1px rgba(196, 107, 255, .55); }
.up-body .up-slot--stake.is-set ~ .up-slot--target:not(.is-set) .up-slot__arrow { color: var(--upx-goal); box-shadow: inset 0 0 0 1px rgba(215, 255, 0, .55); }
@media (hover: hover) {
  .up-body .up-slot--stake:not(.is-set):hover { --edge: rgba(196, 107, 255, .85); }
  .up-body .up-slot--stake:not(.is-set):hover .up-slot__body { border-color: rgba(196, 107, 255, .7); background-color: rgba(166, 44, 255, .05); }
  .up-body .up-slot--target:not(.is-set):hover { --edge: rgba(215, 255, 0, .8); }
  .up-body .up-slot--target:not(.is-set):hover .up-slot__body { border-color: rgba(215, 255, 0, .6); }
  .up-body .up-slot:not(.is-set):hover .up-slot__ghost { opacity: .34; }
  .up-body .up-slot:not(.is-set):hover .up-slot__arrow { transform: translateY(2px); }
}
.up-body .up-slot:not(.is-set):focus-visible { outline: 2px solid var(--lime); outline-offset: 3px; }

@media (min-width: 761px) {
  /* плиты по высоте ряда (= кольцо): ставка и цель всегда одного роста,
     выбор предмета не дёргает раскладку */
  .up-body .up-duel > .up-slot { align-self: stretch; align-content: center; padding: 16px; gap: 10px; }
  .up-body .up-duel > .up-slot:not(.is-set) { align-content: stretch; }
  /* С предметом: подпись прижата к верху, колодец цены — к низу с тем же
     отступом, что по бокам, лишнее место забирает арт. По центру веер из
     двух предметов сдвигал подпись и цену на 4 px против соседней плиты. */
  .up-body .up-duel > .up-slot.is-set { grid-template-rows: auto 1fr auto; align-content: stretch; }
}
/* Веер (несколько предметов в ставке): те же скругления и индиго, что у
   плиток склада. Со срезанными углами на чёрном он один остался бы из
   прежнего вида. */
.up-body .up-fan__card {
  clip-path: none; border-radius: 10px;
  background:
    radial-gradient(90% 70% at 50% 0%, color-mix(in srgb, var(--r) 55%, transparent), transparent 70%),
    linear-gradient(180deg, color-mix(in srgb, var(--r) 24%, #2A2250) 0%, #1F1940 100%);
  box-shadow: inset 0 2px 0 var(--r), 0 8px 18px rgba(8, 4, 24, .45);
}
.up-body .up-fan__card::before { display: none; }
.up-body .up-fan__card::after { clip-path: none; border-radius: inherit; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08); }
.up-body .up-fan__more {
  clip-path: none; border-radius: 10px;
  background: rgba(166, 44, 255, .14); box-shadow: inset 0 0 0 1px rgba(196, 107, 255, .4); color: #E2CCFF;
}

/* ── управление: подпись, ×N в колодце, кнопка + турбо, подсказка ── */
.up-body .up-cap {
  display: flex; align-items: center; gap: 10px; width: 100%; max-width: 440px; margin: 22px 0 0;
  font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--upx-mute);
}
.up-body .up-cap::before, .up-body .up-cap::after { content: ''; flex: 1; height: 1px; background: linear-gradient(90deg, transparent, rgba(166, 120, 255, .3)); }
.up-body .up-cap::after { transform: scaleX(-1); }
/* множители — сегментом в одном колодце, а не россыпью: это один выбор */
.up-body .up-quick {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 4px;
  width: 100%; max-width: 440px; margin-top: 8px; padding: 4px;
  border: 1px solid var(--upx-line); border-radius: 14px;
  background: var(--upx-well); box-shadow: inset 0 2px 6px rgba(6, 2, 20, .45), 0 1px 0 rgba(255, 255, 255, .05);
}
.up-body .up-chip, .up-body .up-chip:hover:not(:disabled) {
  height: 36px; padding: 0 6px; clip-path: none; transform: none;
  border: 1px solid var(--upx-line); border-radius: 10px;
  background: linear-gradient(180deg, #3A3070 0%, #2C2452 100%);
  box-shadow: var(--upx-hl), 0 2px 6px rgba(0, 0, 0, .3);
  font-family: var(--f-body); font-size: 13px; font-weight: 800; letter-spacing: .02em; color: var(--upx-ink);
  font-variant-numeric: tabular-nums;
  transition: color .14s, background-color .14s, border-color .14s, transform .14s;
}
@media (hover: hover) {
  .up-body .up-chip:hover:not(:disabled) { color: var(--upx-text); border-color: var(--upx-line2); background: linear-gradient(180deg, #44397F 0%, #342B60 100%); }
}
.up-body .up-chip:active:not(:disabled) { transform: translateY(1px); }
/* Активный множитель — лаймом: он выбирает ЦЕЛЬ, а цель — лаймовая.
   Как активная сумма в рулетке: индиго-заливка и чистая лаймовая рамка.
   Полупрозрачный лайм поверх индиго давал грязный хаки (#3A3A23), и
   активный ×2 выглядел темнее соседних. Тот же рецепт — у включённого
   турбо, «К кейсам», значка витрины (--upx-on-*). Сплошной лайм остался
   у «Апгрейда». */
.up-body .up-chip.is-on, .up-body .up-chip.is-on:hover:not(:disabled) {
  color: var(--lime); border-color: var(--lime);
  background: var(--upx-on-bg);
  box-shadow: var(--upx-on-shadow);
}
.up-body .up-chip:disabled { opacity: .4; box-shadow: none; }
.up-body .up-chip:focus-visible { outline: 2px solid var(--lime); outline-offset: 2px; }

.up-body .up-actions { width: 100%; max-width: 440px; margin-top: 10px; gap: 8px; }
/* Лаймовая, как .oc-cta в «1 Клике». Перебивает зелёную .gm-body .up-go из
   games.css: тот же вес, файл позже. */
.up-body .up-go, .up-body .up-go:hover:not(:disabled) {
  flex: 1; min-width: 0; height: 58px; padding: 0 24px; clip-path: none; transform: none;
  border: 0; border-radius: 16px;
  background: linear-gradient(180deg, #EEFF7A 0%, #D7FF00 46%, #B4E200 100%); color: #10150A;
  box-shadow: 0 14px 32px -8px rgba(215, 255, 0, .5), 0 0 0 1px rgba(215, 255, 0, .55),
              inset 0 1px 0 rgba(255, 255, 255, .7), inset 0 -3px 0 rgba(70, 100, 0, .3);
  font-size: 19px; font-weight: 700; letter-spacing: .12em;
  transition: filter .14s, transform .14s, box-shadow .14s;
}
@media (hover: hover) {
  .up-body .up-go:hover:not(:disabled) { filter: brightness(1.05); box-shadow: 0 16px 38px -8px rgba(215, 255, 0, .65), 0 0 0 1px rgba(215, 255, 0, .7), inset 0 1px 0 rgba(255, 255, 255, .7), inset 0 -3px 0 rgba(70, 100, 0, .3); }
  .up-body .up-go:hover:not(:disabled) .up-go__glow { transform: translateX(120%); }
}
.up-body .up-go:active:not(:disabled) { transform: translateY(1px) scale(.995); }
.up-body .up-go:focus-visible { outline: 2px solid var(--lime); outline-offset: 3px; }
/* блик — только по наведению: вечный пробег по лаймовой кнопке рядом с
   живым кольцом был третьим движением на столе */
.up-body .up-go:not(:disabled) .up-go__glow { animation: none; transition: transform .7s ease; }
/* «Выберите ставку/цель», «Крутим…» — стекло, а не тусклый лайм: тусклый
   лайм читается как «почти можно нажать». На ходу кнопка выключена
   (setGo(false)), и полоса up-sweep из базового правила идёт поверх. */
.up-body .up-go:disabled {
  background: var(--upx-glass); color: var(--upx-faint);
  box-shadow: inset 0 0 0 1px var(--upx-line), inset 0 1px 0 rgba(255, 255, 255, .07);
  filter: none;
}
/* Турбо — маленький инструмент в углу стола, как в «1 Клике», а не вторая
   плитка 58×58 рядом с «Апгрейдом»: там блок под кольцом был тяжелее
   справа и вылезал за ширину ряда ×N. В разметке турбо по-прежнему в
   .up-actions, но та стоит без позиционирования, и угол считается от
   .up-stage (position: relative из базового правила). «Апгрейд» один в
   своей строке — строго по оси кольца. */
.up-body .up-actions { position: static; }
.up-body .up-turbo {
  position: absolute; z-index: 2; left: 16px; bottom: 16px;
  width: 40px; height: 40px; clip-path: none; border-radius: 12px;
  border: 1px solid var(--upx-line); background: var(--upx-glass); color: var(--upx-ink);
  box-shadow: var(--upx-hl), 0 4px 12px rgba(8, 4, 24, .3);
  transition: color .14s, border-color .14s, box-shadow .14s, opacity .2s;
}
.up-body .up-turbo svg { width: 18px; height: 18px; }
.up-body .up-turbo[aria-pressed="true"] {
  color: var(--lime); border-color: var(--lime);
  background: var(--upx-on-bg); box-shadow: var(--upx-on-shadow);
}
@media (hover: hover) { .up-body .up-turbo:hover { color: var(--upx-text); border-color: var(--upx-line2); } }
.up-body .up-turbo[aria-pressed="true"]:hover { color: var(--lime); border-color: var(--lime); }
.up-body .up-turbo:focus-visible { outline: 2px solid var(--lime); outline-offset: 2px; }
/* Верхний левый угол — как «Правила» и турбо в «1 Клике» — только там,
   где плита ставки отходит от края стола дальше, чем на ширину кнопки:
   от 1280 px и не слишком высокое окно (кольцо растёт с высотой окна и
   прижимает плиты к краям). Уже — нижний левый угол: там под плитой
   всегда пусто, ряд ×N и кнопка стоят по центру. */
@media (min-width: 1280px) and (min-aspect-ratio: 7/5) {
  .up-body .up-turbo { top: 16px; bottom: auto; }
}
/* На ходу ряд ×N и турбо гаснут и не нажимаются: клик по ×N и так не
   проходит (locked() в upgrade.main.js), а горящие кнопки обещали
   обратное. Турбо переключают между бросками. */
.up-body .up-cap, .up-body .up-quick { transition: opacity .2s; }
.up-body .up-page[data-state="spinning"] :is(.up-cap, .up-quick, .up-turbo) { opacity: .45; pointer-events: none; }
.up-body .up-note { margin-top: 8px; max-width: 560px; min-height: 18px; font-size: 12.5px; line-height: 18px; color: var(--upx-dim); }
.up-body .up-note b { color: var(--upx-text); font-weight: 700; }
.up-body .up-note.is-warn { color: #FFD27A; }
@media (min-width: 761px) {
  /* строка держит место и пустой — склады не прыгают в момент клика по
     скину, когда появляется «Под эту ставку доступны цели…» */
  .up-body .up-note:empty { display: block; visibility: hidden; }
}

/* ── склады ── */
.up-body .up-tables { gap: 14px; }
@media (min-width: 1001px) {
  /* Строки панелей — подсетка .up-tables (см. АДАПТИВ выше), а подсетка
     наследует зазор родителя: между шапкой, листалкой и списком стояли
     пустые полосы по 14 px. Внутри панели строки идут встык, их делят
     линии шапки и листалки. */
  .up-body .up-tables > .up-panel { row-gap: 0; }
}
.gm-body.up-body .up-panel {
  border: 1px solid var(--upx-line); border-radius: 22px;
  background: linear-gradient(180deg, #241D45 0%, #1F1940 100%);
  box-shadow: 0 18px 40px -22px rgba(8, 4, 24, .8), inset 0 1px 0 rgba(255, 255, 255, .06);
  -webkit-backdrop-filter: none; backdrop-filter: none;
  transition: border-color .25s, box-shadow .25s;
  /* клик по пустой плите доводит сюда (toShelf) — шапка сайта липкая,
     68 px, и без отступа закрыла бы заголовок склада */
  scroll-margin-top: 84px;
}
@media (min-width: 761px) {
  .gm-body.up-body .up-panel__head {
    min-height: 62px; padding: 12px 16px; gap: 12px;
    background: radial-gradient(60% 160% at 0% 0%, rgba(150, 100, 255, .16), transparent 70%), rgba(255, 255, 255, .02);
    border-bottom: 1px solid var(--upx-line);
  }
  /* Панель текущего шага — тем же цветом, что плита над ней: взгляд идёт
     от подсвеченной плиты прямо к складу, где её заполняют. Без :has()
     (старые браузеры) панель просто не подсвечивается — плиты подсвечены
     и без него. */
  .up-body .up-page:has(#up-slot-stake:not(.is-set)) .up-tables > .up-panel:first-child {
    border-color: rgba(196, 107, 255, .5);
    box-shadow: 0 0 0 3px rgba(196, 107, 255, .06), 0 18px 40px -22px rgba(8, 4, 24, .8), inset 0 1px 0 rgba(255, 255, 255, .06);
  }
  /* лайм рамки плотный: при .38 он ложился на индиго оливковой линией */
  .up-body .up-page:has(#up-slot-stake.is-set):has(#up-slot-target:not(.is-set)) .up-tables > .up-panel:last-child {
    border-color: rgba(215, 255, 0, .62);
    box-shadow: 0 0 14px -4px rgba(215, 255, 0, .2), 0 18px 40px -22px rgba(8, 4, 24, .8), inset 0 1px 0 rgba(255, 255, 255, .06);
  }
}
/* «Снять всё» — только когда есть что снимать; visibility, чтобы строка
   счёта не прыгала. Стоит в строке счёта, справа (перед стрелками). */
.up-body .up-page:has(#up-slot-stake:not(.is-set)) #up-inv-clear { visibility: hidden; }
.up-body .up-pager #up-inv-clear { flex: none; margin-left: 4px; }
/* Значки шапок — цвета своей роли вместо жёлтых квадратов: склад (что
   ставлю) фиолетовый, витрина (что беру) — индиго с лаймовой рамкой, как
   прочие «лаймовые» кнопки: полупрозрачный лайм давал хаки. */
.up-body .up-panel__ico {
  flex: none; width: 36px; height: 36px; border-radius: 11px; color: var(--lime);
  background: var(--upx-on-bg);
  box-shadow: inset 0 0 0 1px rgba(215, 255, 0, .7), inset 0 1px 0 rgba(255, 255, 255, .07);
}
.up-body .up-panel__ico--inv {
  color: var(--upx-stake);
  background: linear-gradient(180deg, rgba(196, 107, 255, .2), rgba(196, 107, 255, .06));
  box-shadow: inset 0 0 0 1px rgba(196, 107, 255, .38), inset 0 1px 0 rgba(255, 255, 255, .08);
}
.up-body .up-panel__ico svg { width: 20px; height: 20px; }
.up-body .up-panel__head h2 { font-size: 16px; letter-spacing: .08em; color: var(--upx-text); }
.up-body .up-mini {
  height: 30px; padding: 0 11px; border-radius: 10px;
  border: 1px solid var(--upx-line); background: var(--upx-glass); color: var(--upx-ink); box-shadow: var(--upx-hl);
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em;
}
@media (hover: hover) { .up-body .up-mini:hover { color: var(--upx-text); border-color: var(--upx-line2); } }
.up-body .up-cases {
  height: 34px; padding: 0 5px 0 4px; gap: 8px; border-radius: 11px;
  border: 1px solid rgba(166, 120, 255, .45);
  background: linear-gradient(180deg, rgba(166, 44, 255, .24), rgba(166, 44, 255, .08));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .07);
  font-size: 11.5px; font-weight: 600; color: var(--upx-text);
}
.up-body .up-cases b { color: #fff; }
.up-body .up-cases i {
  display: inline-grid; place-items: center; height: 24px; padding: 0 9px; border-radius: 8px;
  background: var(--lime); color: #10150A; font-size: 10.5px; font-weight: 800; letter-spacing: .06em;
}
/* поля фильтра — «колодцами», как поле суммы в «1 Клике» */
.up-body .up-filter { gap: 6px; }
.up-body .up-filter__q, .up-body .up-filter__num {
  height: 36px; padding: 0 11px; border-radius: 11px;
  border: 1px solid var(--upx-line); background: var(--upx-well);
  box-shadow: inset 0 2px 6px rgba(6, 2, 20, .45), 0 1px 0 rgba(255, 255, 255, .05);
  color: var(--upx-text); font-size: 12.5px; font-weight: 600;
}
.up-body .up-filter__q {
  width: 150px; padding-left: 32px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238F87B8' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.6-3.6'/%3E%3C/svg%3E") 11px 50% / 14px 14px no-repeat, var(--upx-well);
}
.up-body .up-filter__num { width: 100px; }
.up-body .up-filter__num input { font-size: 12.5px; font-weight: 600; color: var(--upx-text); }
.up-body .up-filter input::placeholder { color: var(--upx-faint); }
.up-body .up-filter__q:focus, .up-body .up-filter__num:focus-within {
  outline: none; border-color: rgba(215, 255, 0, .8);
  box-shadow: inset 0 2px 6px rgba(6, 2, 20, .45), 0 0 10px -2px rgba(215, 255, 0, .25);
}
/* Листалка: счётчик в потоке слева, стрелки справа. Абсолютный счётчик
   наезжал на «назад», как только строка становилась уже (телефон). */
.up-body .up-pager { justify-content: flex-end; gap: 8px; min-height: 52px; padding: 8px 16px; border-bottom: 1px solid rgba(58, 49, 102, .6); }
.up-body .up-pager__n { font-size: 14px; color: var(--upx-text); min-width: 56px; }
.up-body .up-pager__n--left {
  position: static; margin-right: auto; min-width: 0; text-align: left;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--f-body); font-size: 11.5px; font-weight: 600; letter-spacing: .02em; color: var(--upx-mute);
}
.up-body .up-pager__btn {
  width: 32px; height: 32px; border-radius: 10px;
  border: 1px solid var(--upx-line); background: var(--upx-glass); color: var(--upx-ink); box-shadow: var(--upx-hl);
}
@media (hover: hover) { .up-body .up-pager__btn:hover:not(:disabled) { color: var(--upx-text); border-color: var(--upx-line2); background: var(--upx-glass); } }
/* Страница одна — стрелок и «1 / 1» нет (is-single ставит view): две
   выключенные стрелки над тремя предметами были шумом. Счёт слева и
   «Снять всё» остаются. Строка без счёта (is-empty: пустой склад, гость)
   не рисуется вовсе — на широком экране её место забирает список ниже. */
.up-body .up-pager.is-single .up-pager__btn,
.up-body .up-pager.is-single .up-pager__n:not(.up-pager__n--left) { display: none; }
.up-body .up-pager.is-empty { display: none; }
@media (min-width: 1001px) {
  .up-body .up-tables > .up-panel:has(> .up-pager.is-empty) > .up-shelf { grid-row: 2 / span 2; }
}
/* Без ставки на месте счёта целей — подсказка с фиолетовой точкой (цвет
   ставки): что сделать сначала. Кнопка «К ставке» / «Войти» рядом — только
   на телефоне, где склады вкладками; на широком экране склад и так рядом. */
.up-body .up-pager.is-hint .up-pager__n--left { display: flex; align-items: center; gap: 10px; overflow: visible; }
.up-body .up-pager__hint {
  display: inline-flex; align-items: center; gap: 8px; min-width: 0;
  font-family: var(--f-body); font-size: 12.5px; font-weight: 600; letter-spacing: 0; color: var(--upx-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.up-body .up-pager__hint::before {
  content: ''; flex: none; width: 7px; height: 7px; border-radius: 50%;
  background: var(--upx-stake); box-shadow: 0 0 8px rgba(196, 107, 255, .7);
}
.up-body .up-pager__go {
  display: none; flex: none; height: 30px; padding: 0 12px; border-radius: 10px;
  border: 1px solid rgba(196, 107, 255, .6); background: var(--upx-glass); color: #E2CCFF;
  box-shadow: var(--upx-hl);
  font-family: var(--f-body); font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
}
.up-body .up-shelf { position: relative; gap: 10px; padding: 14px; grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); }
/* пустой склад — не тупик: заголовок, причина и выход к кейсам (гостю —
   ко входу). По центру панели, а не прижатым к верху над пустотой. */
.up-body .up-shelf:has(> .up-shelf__none) { align-content: center; }
.up-body .up-shelf__none {
  display: grid; justify-items: center; gap: 6px; padding: 48px 20px;
  font-size: 12.5px; line-height: 1.45; color: var(--upx-mute);
}
.up-body .up-shelf__none b { font-family: var(--f-cond); font-size: 16px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--upx-text); }
.up-body .up-restock {
  display: inline-flex; align-items: center; gap: 8px; height: 36px; padding: 0 16px; margin-top: 8px; border-radius: 11px;
  color: var(--lime); border: 1px solid var(--lime);
  background: var(--upx-on-bg); box-shadow: var(--upx-on-shadow);
  font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  transition: color .14s, box-shadow .14s;
}
.up-body .up-restock svg { flex: none; }
.up-body .up-restock--login { height: 40px; padding: 0 18px; font-size: 11.5px; }
@media (hover: hover) { .up-body .up-restock:hover { color: #EEFF7A; box-shadow: inset 0 1px 0 rgba(255, 255, 255, .07), 0 0 16px rgba(215, 255, 0, .3); } }

/* ── плитки ──
   Карточка сайта (skincard), но на индиго-основе вместо сине-серой: та же
   заливка редкости и молнии, другой «пол». Вес .up-body перебивает
   drophub.skincard.css, подключённый последним. */
.up-body .up-tile {
  border: 1px solid rgba(167, 139, 250, .14); border-radius: 14px; padding: 8px 8px 10px;
  background:
    radial-gradient(90% 70% at 50% 0%, color-mix(in srgb, var(--sc) 60%, transparent), transparent 70%),
    linear-gradient(180deg, color-mix(in srgb, var(--sc) 34%, #261F49) 0%, #221B3E 74%);
  box-shadow: inset 0 2px 0 var(--sc), inset 0 10px 16px -10px var(--sc);
  transition: transform .16s, border-color .16s, box-shadow .16s, opacity .16s;
}
.up-body .up-tile:hover:not([disabled]) { border-color: color-mix(in srgb, var(--sc) 50%, rgba(167, 139, 250, .3)); }
.up-body .up-tile__price { font-size: 11.5px; font-weight: 700; color: #fff; }
/* износ и строка оружия — самый мелкий текст страницы: 10 px и светлее,
   на розово-фиолетовых плитках прежние 9 px с альфой .55–.62 пропадали */
.up-body .up-tile__corner { font-size: 10px; font-weight: 700; color: rgba(245, 243, 255, .72); }
.up-body .up-tile__art { height: 68px; margin: 6px 0 8px; }
.up-body .up-tile__weapon { font-size: 10px; font-weight: 700; letter-spacing: .06em; color: rgba(245, 243, 255, .75); }
.up-body .up-tile__finish { font-size: 13.5px; }
/* Множитель цели — сплошной плашкой с тёмными цифрами (владелец 2026-11-01:
   «вот так» — как у выбранной цели): лайм до ×10, золото от ×10. Заливка
   непрозрачная — полупрозрачный лайм на цвете редкости давал болотный тон.
   1px снизу: у Oswald строка 14+3 px, и цифры по центру строки сидят
   ниже середины плашки — так они ровно посередине. */
.up-body .up-tile__x {
  display: inline-grid; place-items: center; height: 18px; padding: 0 6px 1px; border-radius: 6px;
  font-size: 12px; font-weight: 700; color: #10150A; background: var(--lime); box-shadow: 0 2px 6px rgba(10, 6, 24, .35);
}
.up-body .up-tile__x--hi { color: #1A1200; background: #FFCE4D; }
/* у цели цвет текста ставит .up-tile.is-target .up-tile__x выше (лайм) — здесь
   тёмный, иначе лайм на лайме */
.up-body .up-tile.is-target .up-tile__x { color: #10150A; box-shadow: 0 0 10px rgba(215, 255, 0, .45); }
/* выбранное в ставку — фиолетом, выбранная цель — лаймом */
.up-body .up-tile.is-on {
  border-color: var(--upx-stake);
  box-shadow: inset 0 2px 0 var(--sc), 0 0 0 1px rgba(196, 107, 255, .55), 0 8px 20px -8px rgba(166, 44, 255, .6);
}
.up-body .up-tile.is-on .up-tile__price { color: #E2CCFF; }
.up-body .up-tile__tick { width: 16px; height: 16px; background: var(--upx-stake); font-size: 9px; box-shadow: 0 0 8px rgba(196, 107, 255, .6); }
/* Выбранная в ставку: всё содержимое плитки притухает, по центру — крупная
   галочка в фиолете ставки. Рамка и свечение выше остаются яркими. */
.up-body .up-tile.is-on > :not(.up-tile__check) { opacity: .38; transition: opacity .15s; }
.up-tile__check {
  position: absolute; left: 50%; top: 50%; z-index: 5; width: 40px; height: 40px; margin: -20px 0 0 -20px;
  display: grid; place-items: center; border-radius: 50%; pointer-events: none; color: #fff;
  background: linear-gradient(160deg, #C46BFF 0%, #8A3DFF 100%);
  box-shadow: 0 0 0 3px rgba(28, 20, 56, .75), 0 8px 22px -6px rgba(166, 44, 255, .9);
  animation: up-check .28s cubic-bezier(.2, 1.4, .4, 1) both;
}
.up-tile__check svg { width: 22px; height: 22px; }
@keyframes up-check { from { opacity: 0; transform: scale(.5); } }
@media (max-width: 760px) {
  .up-tile__check { width: 34px; height: 34px; margin: -17px 0 0 -17px; }
  .up-tile__check svg { width: 19px; height: 19px; }
}
@media (prefers-reduced-motion: reduce) { .up-tile__check { animation: none; } }
.up-body .up-tile.is-target {
  border-color: rgba(215, 255, 0, .85);
  box-shadow: inset 0 2px 0 var(--sc), 0 0 0 1px rgba(215, 255, 0, .5), 0 8px 20px -8px rgba(215, 255, 0, .45);
}
.up-body .up-tile.is-target .up-tile__price { color: var(--lime); }
.up-body .up-tile.is-off { opacity: .38; filter: saturate(.5); }
.up-body .up-tile.is-fresh { border-color: rgba(215, 255, 0, .7); }
.up-body .up-tile__new { padding: 2px 6px; border-radius: 6px; background: var(--lime); color: #10150A; font-size: 8.5px; font-weight: 800; }
/* фокус с клавиатуры — лаймом; кнопки окна исхода (.up-reveal) сюда
   намеренно не входят — они часть кольца */
.up-body :is(.up-tile, .up-mini, .up-cases, .up-pager__btn, .up-restock, .up-mtab, .up-mpill):focus-visible { outline: 2px solid var(--lime); outline-offset: 2px; }

/* 1001–1099: шапка склада в одну строку — у полоски кейсов остаются
   обложка, число и «Открыть». Шире подпись влезает целиком: «Снять всё»
   из шапки переехала в строку счёта. */
@media (min-width: 1001px) and (max-width: 1099px) {
  .up-body .up-cases span { font-size: 0; }
  .up-body .up-cases span b { font-size: 12px; }
}

/* ── телефон ──
   Перебиваем «склеенную» карточку mobile.css (он подключён позже, поэтому
   вес .up-body). Размер кольца (.up-dial min(220px, 62vw) !important) не
   трогаем. */
@media (max-width: 760px) {
  /* заголовок, как у «1 Клика» на телефоне */
  .up-body .kz-gbar { display: flex; padding: 6px 12px 0; gap: 10px; }
  .up-body .kz-gbar .kz-gico { width: 26px; height: 26px; }
  .up-body .kz-gbar__txt b { font-size: 24px; }
  .up-body .up-page { border: 0; padding: 10px 12px 20px; gap: 8px; }
  .up-body .up-stage { margin: 0; padding: 14px 12px; border-radius: 22px; box-shadow: 0 14px 30px rgba(8, 4, 24, .4), inset 0 1px 0 rgba(255, 255, 255, .07); }
  .up-body .up-stage::before { background-size: 34px 34px; }
  .up-body .up-slot { padding: 10px 8px; gap: 6px; border-radius: 16px; }
  .up-body .up-slot:not(.is-set) .up-slot__body { border-radius: 12px; }
  .up-body .up-slot__cap { font-size: 10px; letter-spacing: .12em; }
  .up-body .up-slot__name { font-size: 11px; max-width: 100%; }
  /* в плите шириной ~150 px разрядка .12em ломала подпись на три строки */
  .up-body .up-slot__empty b { font-size: 10px; letter-spacing: .07em; }
  /* стрелка к складу и силуэт мельче: плита не должна вырасти от стрелки */
  .up-body .up-slot__empty { gap: 5px; }
  .up-body .up-slot__ghost { width: 66px; }
  .up-body .up-slot__arrow { width: 20px; height: 20px; margin-top: 0; }
  .up-body .up-slot__arrow svg { width: 12px; height: 12px; }
  .up-body .up-slot__foot { height: 38px; border-radius: 11px; }
  .up-body .up-slot__foot b { font-size: 17px; }
  .up-body .up-cap, .up-body .up-quick { display: none; }   /* ряд ×N на телефоне скрыт, как и был */
  .up-body .up-actions { margin-top: 12px; }
  /* Турбо — угловой инструмент и здесь: 36×36 в левом верхнем углу стола,
     сбоку от кольца (там пусто: круг вписан в квадрат). mobile.css его
     прятал, потому что он висел второй плиткой под кнопкой и читался
     вторым, непонятным действием; в углу этого нет. */
  .up-body .up-turbo { display: grid; place-items: center; top: 12px; bottom: auto; left: 12px; width: 36px; height: 36px; border-radius: 11px; }
  .up-body .up-turbo svg { width: 16px; height: 16px; }
  .up-body .up-go, .up-body .up-go:hover:not(:disabled) { height: 56px; }
  /* Ошибки, «войдите» и лимит кейсов видны и на телефоне — без них
     нажатие оставалось без ответа. Строка с диапазоном цен (без .is-warn)
     скрыта, как и была. */
  .up-body .up-note.is-warn:not(:empty) { display: block; order: 3; max-width: none; min-height: 0; margin-top: 10px; font-size: 12px; text-align: center; }
  /* Вкладки — сегментом в подложке, как .oc-tabs. Названия — те же, что
     на плитах над ними, с точкой цвета роли: «Ставка» (фиолет) и «Цель»
     (лайм). Раньше у двух понятий было четыре набора имён (плиты, панели,
     вкладки, пилюли), и «ЖЕЛАЕМЫЕ ПРЕДМ…» не влезало. Текст вкладок пишет
     drophub.mobile.js (чужой файл), поэтому подпись здесь — ::after, а его
     текст свёрнут в ноль. */
  .up-body .up-mtabs {
    display: grid; grid-template-columns: 1fr 1fr; gap: 4px;
    margin: 0; padding: 3px; border: 1px solid var(--upx-line); border-radius: 14px;
    background: #1B1536; box-shadow: none;
    scroll-margin-top: 68px;      /* липкая шапка сайта на телефоне — 56 px */
  }
  .up-body .up-mtab {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    height: 38px; padding: 0 6px; border: 1px solid transparent; border-radius: 11px; background: transparent;
    color: var(--upx-faint); font-size: 0; letter-spacing: 0; white-space: nowrap; overflow: hidden;
  }
  .up-body .up-mtab::before {
    content: ''; flex: none; width: 7px; height: 7px; border-radius: 50%;
    background: var(--upx-stake); opacity: .55;
  }
  .up-body .up-mtab[data-i="1"]::before { background: var(--upx-goal); }
  .up-body .up-mtab::after {
    content: 'Ставка';
    font-family: var(--f-cond); font-size: 14px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  }
  .up-body .up-mtab[data-i="1"]::after { content: 'Цель'; }
  .up-body .up-mtab.is-on { color: var(--upx-text); background: var(--upx-glass); box-shadow: var(--upx-hl), 0 4px 12px rgba(8, 4, 24, .35); }
  .up-body .up-mtab.is-on::before { opacity: 1; box-shadow: 0 0 8px rgba(196, 107, 255, .8); }
  .up-body .up-mtab.is-on[data-i="1"]::before { box-shadow: 0 0 8px rgba(215, 255, 0, .7); }
  .up-body .up-mtab.is-on[data-i="0"] { border-color: rgba(196, 107, 255, .55); }
  .up-body .up-mtab.is-on[data-i="1"] { border-color: rgba(215, 255, 0, .6); }
  /* Пилюли «Мои скины / Магазин» выбирают источник СТАВКИ — значит,
     фиолетом, а не лаймом: лайм на странице — то, что берёшь. */
  .up-body .up-msrc { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin: 0; padding: 0; border: 0; background: none; }
  .up-body .up-mpill {
    height: 32px; border: 1px solid var(--upx-line); border-radius: 11px;
    background: transparent; color: var(--upx-mute); box-shadow: none;
    font-size: 12px; font-weight: 700; letter-spacing: .04em;
  }
  .up-body .up-mpill.is-on {
    color: #E2CCFF; border-color: rgba(196, 107, 255, .6);
    background: var(--upx-glass);
    box-shadow: var(--upx-hl), 0 0 12px rgba(166, 44, 255, .18);
  }
  .up-body .up-tables {
    margin: 0; padding: 0 12px 12px; border: 1px solid var(--upx-line); border-radius: 22px;
    background: linear-gradient(180deg, #241D45 0%, #1F1940 100%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);
  }
  .gm-body.up-body .up-tables > .up-panel { border: 0; border-radius: 0; background: none; box-shadow: none; }
  /* Шапка склада без названия и значка: раздел уже назван вкладкой, а три
     подписи подряд («Ставка» — «Мои скины» — «Мой инвентарь») говорили
     одно и то же. В шапке остаются полоска кейсов (склад) и фильтр
     (витрина); пустая шапка не рисуется. */
  .up-body .up-panel__head h2, .up-body .up-panel__ico { display: none; }
  .gm-body.up-body .up-panel__head { padding: 8px 0 0; row-gap: 6px; }
  .up-body .up-panel__head:not(:has(.up-filter, .up-cases:not([hidden]))) { display: none; }
  .up-body .up-cases { margin-left: 0; flex: 1 1 100%; }
  /* фильтр — одной строкой: поиск и «от/до» по 84 px */
  .up-body .up-filter { grid-template-columns: minmax(0, 1fr) 84px 84px; }
  .up-body .up-filter > :first-child { grid-column: auto; }
  .up-body .up-filter__q, .up-body .up-filter__num { width: 100%; padding: 0 9px; }
  .up-body .up-filter__q { padding-left: 30px; background-position: 10px 50%, 0 0; }
  /* Строка счёта: «N предметов · сумма» и «Снять всё»; стрелки — только
     если страниц больше одной. Без ставки у витрины здесь подсказка и
     «К ставке» (гостю «Войти») — стрелки тогда не нужны: листать
     погашенный список незачем, а подсказке нужна ширина. */
  /* Вкладки 38, пилюли 32, строка счёта 37: от вкладок до первой плитки
     ~180 px вместо прежних 268 — первый ряд склада виден сразу под ними. */
  .up-body .up-pager { min-height: 0; padding: 6px 0 4px; gap: 6px; }
  .up-body .up-pager .up-mini { height: 26px; padding: 0 10px; font-size: 10px; }
  .up-body .up-pager.is-hint .up-pager__btn,
  .up-body .up-pager.is-hint .up-pager__n:not(.up-pager__n--left) { display: none; }
  .up-body .up-pager.is-hint .up-pager__n--left { flex: 1; justify-content: space-between; }
  .up-body .up-pager__hint { font-size: 12px; white-space: normal; line-height: 1.3; }
  .up-body .up-pager__go { display: inline-flex; align-items: center; }
  .up-body .up-shelf { gap: 8px !important; padding: 8px 0 0; min-height: 220px; }
  /* С плитками высота по содержимому: под одним рядом из трёх скинов
     карточка тянулась пустым индиго ещё на две сотни пикселей. Запас
     высоты нужен только пустому складу и подсказке. */
  .up-body .up-shelf:has(> .up-tile) { min-height: 0; }
  .up-body .up-tile { padding: 6px 5px 7px; border-radius: 12px; }
  .up-body .up-tile__art { height: 56px; margin: 4px 0 6px; }
  .up-body .up-tile__finish { font-size: 12px; }
  .up-body .up-tile__weapon { font-size: 9.5px; }
}
@media (prefers-reduced-motion: reduce) {
  .up-body .up-stage__tint { animation: none; }
  .up-body .up-go__glow { transition: none; }
  .gm-body.up-body .up-panel { transition: none; }
}

/* ═══ ВЫБРАННОЕ И ВКЛЮЧЁННОЕ — ГРАДИЕНТ ЛОГОТИПА ═══
   Статичный градиент кислотный → розовый через светлый тон (напрямую
   смесь рыжеет), как ⚡/🛒 в «1 Клике» (oneclick.css). Стоит в конце
   файла: те же селекторы выше рисовали лаймовую рамку. */
.up-body .up-chip.is-on, .up-body .up-chip.is-on:hover:not(:disabled),
.up-body .up-turbo[aria-pressed="true"], .up-body .up-turbo[aria-pressed="true"]:hover,
.up-filter__go[aria-pressed="true"] {
  color: #F4FFD6;
  border: 1.5px solid transparent;
  background: linear-gradient(180deg, #2A2158 0%, #1C1540 100%) padding-box, linear-gradient(135deg, #D7FF00 0%, #F0FFC8 45%, #FFD6F7 55%, #F535F0 100%) border-box;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .08), -4px -4px 14px rgba(215, 255, 0, .16), 4px 4px 14px rgba(245, 53, 240, .2);
}
/* значок — тем же градиентом (#dh-acid в upgrade.html) */
.up-body .up-turbo[aria-pressed="true"] svg path { fill: url(#dh-acid); }

/* ═══ ТУРБО — РЯДОМ С «АПГРЕЙДОМ» ═══
   Квадрат высотой с кнопку, в одном ряду с ней — как ⚡/🛒 и «Авто» в
   «1 Клике»: переключатель стоит там же, где запуск, а не в углу стола.
   Ряд кнопки той же ширины, что ряд ×N (440 px). Перебивает угловые
   правила выше и прятанье в mobile.css. */
.up-body .up-actions { display: flex; flex-wrap: nowrap; }
.up-body .up-turbo {
  position: static; flex: none; display: grid; place-items: center;
  width: 58px; height: 58px; border-radius: 16px;
}
.up-body .up-turbo svg { width: 20px; height: 20px; }
@media (max-width: 760px) {
  .up-body .up-go, .up-body .up-go:hover:not(:disabled) { flex: 1 1 auto; }
  .up-body .up-turbo { width: 56px; height: 56px; border-radius: 15px; }
}

/* ═══ СТАВКА С БАЛАНСА (владелец 2026-10-28) ═══
   Блок под левой плитой «Ставка» (просил владелец): вторая строка сетки
   .up-duel, та же колонка и ширина, что у плиты, — кольцо и цель стоят
   в первой строке и не сдвигаются. Сверху подпись, точная сумма и
   1/2 · MAX, снизу ползунок до всего баланса во всю ширину блока.
   Колодец в коже ряда ×N: это часть ставки, а не отдельный инструмент.
   Заливка дорожки — переменная --fill (upgrade.main.js paintBal). */
.up-body .up-duel { row-gap: 12px; }
/* Гнездо под кольцом (.up-duel::before) центрировалось по высоте всей
   сетки — со второй строкой оно уехало бы вниз от кольца. Абсолютный
   ребёнок сетки берёт рамкой свою область: только первая строка. Конец
   строки — явно (1 / 2): у абсолютного ребёнка «auto» значит край всей
   сетки, и grid-row: 1 растягивал рамку на обе строки. */
@media (min-width: 761px) { .up-body .up-duel::before { grid-row: 1 / 2; grid-column: 1 / -1; } }
.up-body .up-bal {
  grid-column: 1; grid-row: 2; justify-self: end; align-self: start;
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px 8px;
  width: 100%; max-width: 360px; padding: 6px 6px 12px 14px;
  border: 1px solid var(--upx-line); border-radius: 14px;
  background: var(--upx-well); box-shadow: inset 0 2px 6px rgba(6, 2, 20, .45), 0 1px 0 rgba(255, 255, 255, .05);
  transition: border-color .2s, opacity .2s;
}
.up-body .up-bal.is-on { border-color: rgba(196, 107, 255, .55); }
.up-body .up-bal__cap {
  flex: none; margin-right: auto; font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--upx-mute); white-space: nowrap; cursor: pointer;
}
.up-body .up-bal.is-on .up-bal__cap { color: #DCC4FF; }
.up-body .up-bal__range {
  order: 5; flex: 1 1 100%; height: 6px; margin: 0 8px 0 0;
  -webkit-appearance: none; appearance: none; border-radius: 6px; outline: none; cursor: pointer;
  background: linear-gradient(90deg, var(--upx-stake) 0 var(--fill, 0%), rgba(255, 255, 255, .12) var(--fill, 0%) 100%);
}
.up-body .up-bal__range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%;
  background: #F5F3FF; border: 3px solid var(--upx-stake); box-shadow: 0 0 10px rgba(196, 107, 255, .6);
}
.up-body .up-bal__range::-moz-range-thumb {
  width: 12px; height: 12px; border-radius: 50%;
  background: #F5F3FF; border: 3px solid var(--upx-stake); box-shadow: 0 0 10px rgba(196, 107, 255, .6);
}
.up-body .up-bal__range:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--upx-text); outline-offset: 2px; }
.up-body .up-bal__in {
  flex: none; display: flex; align-items: center; width: 112px; height: 34px; padding: 0 9px;
  border: 1px solid var(--upx-line); border-radius: 10px; background: var(--upx-deep);
  font-size: 14px;
}
.up-body .up-bal__in:focus-within { border-color: var(--upx-stake); }
.up-body .up-bal__in input {
  width: 100%; min-width: 0; padding: 0; border: 0; outline: 0; background: none;
  color: var(--upx-text); font: 700 14px var(--f-body); font-variant-numeric: tabular-nums;
}
.up-body .up-bal__chips { flex: none; display: flex; gap: 4px; }
.up-body .up-bal__chips button {
  height: 34px; min-width: 36px; padding: 0 7px; cursor: pointer;
  border: 1px solid var(--upx-line); border-radius: 10px;
  background: linear-gradient(180deg, #3A3070 0%, #2C2452 100%); box-shadow: var(--upx-hl);
  color: var(--upx-ink); font: 800 12px var(--f-body); letter-spacing: .02em;
  transition: color .14s, border-color .14s, background-color .14s;
}
@media (hover: hover) {
  .up-body .up-bal__chips button:hover:not(:disabled) { color: var(--upx-text); border-color: var(--upx-line2); background: linear-gradient(180deg, #44397F 0%, #342B60 100%); }
}
.up-body .up-bal__chips button:active:not(:disabled) { transform: translateY(1px); }
.up-body .up-bal :disabled { opacity: .45; cursor: default; }
.up-body .up-page[data-state="spinning"] .up-bal { opacity: .45; pointer-events: none; }
/* плита: монета вместо скина и строка «+ сумма с баланса» под скинами */
.up-body .up-art--coin .up-art__img { max-height: clamp(76px, 8vw, 112px); }
.up-body .up-slot__bal {
  padding: 3px 9px; border-radius: 8px;
  background: rgba(228, 174, 57, .14); box-shadow: inset 0 0 0 1px rgba(228, 174, 57, .4);
  color: #F4D58A; font-size: 11.5px; font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums;
}
.up-body .up-slot__bal[hidden] { display: none; }
/* Телефон: .up-duel — flex (mobile.css: кольцо, под ним две плиты в ряд),
   под одной плитой ползунку места нет — блок встаёт строкой под обеими. */
@media (max-width: 760px) {
  .up-body .up-bal { order: 3; flex: 0 0 100%; max-width: none; padding: 6px 6px 10px 12px; row-gap: 10px; }
  /* на 375 px подпись, сумма и обе кнопки — одной строкой */
  .up-body .up-bal__in { width: 86px; padding: 0 7px; }
  .up-body .up-bal__chips button { min-width: 32px; padding: 0 6px; }
  .up-body .up-slot__bal { font-size: 10px; padding: 2px 6px; }
}
