/* ─── Responsive scale variables ────────────────────────────
   --ui-scale  scales icons, buttons, font-sizes
   --ui-space  scales padding / gap / margin
   Base (1.0) = screen height ≥ 500 px in landscape.
   Breakpoints cover short phones down to 320 px tall.
────────────────────────────────────────────────────────────── */
:root {
  --ui-scale: 1;
  --ui-space: 1;

  /* Общий множитель РАЗМЕРА ТЕКСТА, поверх --ui-scale. Отдельный от него
     намеренно: --ui-scale ведёт ещё и рамки с кнопками, а прибавить хотелось
     только буквам — иконки, поля и отступы остаются на месте. Крутится одной
     строкой здесь; ниже он вмешан во все ступени --fs-* и в текстовые единицы
     экранов со своей меркой (--au-text у входа, --pf-text у профиля). */
  --fs-scale: 1.08;

  /* Ступени размера текста. Все они — один и тот же множитель --ui-scale,
     выписанный до этого тремястами одинаковых calc(). Держим ряд здесь: так
     видно, что ступеней двадцать на четырнадцать пикселей разницы, и что
     половинки (10.5, 11.5, 12.5) — не система, а следы правок по месту.
     Крупнее 22px — это не текст, а эмодзи-запаски и цифры на арте; у них
     размеры разовые, и токенов им не заводим. */
  --fs-9: calc(9px * var(--ui-scale) * var(--fs-scale));
  --fs-10: calc(10px * var(--ui-scale) * var(--fs-scale));
  --fs-10-5: calc(10.5px * var(--ui-scale) * var(--fs-scale));
  --fs-11: calc(11px * var(--ui-scale) * var(--fs-scale));
  --fs-11-5: calc(11.5px * var(--ui-scale) * var(--fs-scale));
  --fs-12: calc(12px * var(--ui-scale) * var(--fs-scale));
  --fs-12-5: calc(12.5px * var(--ui-scale) * var(--fs-scale));
  --fs-13: calc(13px * var(--ui-scale) * var(--fs-scale));
  --fs-13-5: calc(13.5px * var(--ui-scale) * var(--fs-scale));
  --fs-14: calc(14px * var(--ui-scale) * var(--fs-scale));
  --fs-15: calc(15px * var(--ui-scale) * var(--fs-scale));
  --fs-15-5: calc(15.5px * var(--ui-scale) * var(--fs-scale));
  --fs-16: calc(16px * var(--ui-scale) * var(--fs-scale));
  --fs-17: calc(17px * var(--ui-scale) * var(--fs-scale));
  --fs-17-5: calc(17.5px * var(--ui-scale) * var(--fs-scale));
  --fs-18: calc(18px * var(--ui-scale) * var(--fs-scale));
  --fs-19: calc(19px * var(--ui-scale) * var(--fs-scale));
  --fs-20: calc(20px * var(--ui-scale) * var(--fs-scale));
  --fs-21: calc(21px * var(--ui-scale) * var(--fs-scale));
  --fs-22: calc(22px * var(--ui-scale) * var(--fs-scale));
  /* Крупнее всего в игре — заголовок окна выигрыша (ui/modals/PrizeReveal.js):
     он один на весь экран, и читаться должен как объявление, а не как строка. */
  --fs-28: calc(28px * var(--ui-scale) * var(--fs-scale));
}

/* ─── Арт сплэша ───────────────────────────────────────────────
   Принимаем и .png, и .webp: у фонов нет onerror (в отличие от <img>,
   см. ui/imgFallback.js), поэтому кладём оба расширения слоями — то,
   чего нет в assets/, просто не отрисуется. Если лежат оба, сверху
   окажется webp: слои рисуются в порядке объявления, первый — верхний.

   Кадр 2592×1080 (2.4:1) — намеренно шире любого экрана: героиня стоит в
   левой половине (её край — 49% ширины кадра, макушка и подошва отбивают
   по ~5% сверху и снизу), а справа тянется пустой фон. Поэтому арт везде
   кладётся как cover от левого края: героиня не режется никогда, а лишний
   фон справа просто уходит за край экрана. Если меняешь картинку — держи
   ту же геометрию и поправь --splash-art-ratio.
────────────────────────────────────────────────────────────── */
:root {
  --splash-art: url('../assets/sprites/splash.webp'), url('../assets/sprites/splash.png');
  --splash-art-ratio: 2.4;
}

/* Tiny phones landscape: height < 380 px (e.g. Galaxy Fold outer) */
@media (max-height: 379px) and (orientation: landscape) {
  :root { --ui-scale: 0.62; --ui-space: 0.60; }
}
/* Small phones landscape: 380–449 px (iPhone SE landscape ~375 px) */
@media (min-height: 380px) and (max-height: 449px) and (orientation: landscape) {
  :root { --ui-scale: 0.72; --ui-space: 0.70; }
}
/* Medium phones landscape: 450–499 px */
@media (min-height: 450px) and (max-height: 499px) and (orientation: landscape) {
  :root { --ui-scale: 0.84; --ui-space: 0.82; }
}
/* Standard landscape / portrait tablet ≥ 500 px — defaults (1.0) */
/* Large screens ≥ 700 px */
@media (min-height: 700px) {
  :root { --ui-scale: 1.08; --ui-space: 1.06; }
}

*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html, body {
  width: 100%;
  height: 100%;
  background: linear-gradient(160deg, #a8d8f0 0%, #c9b8e8 50%, #f0c0d8 100%);
  color: #2a1a40;
  font-family: 'Segoe UI', system-ui, sans-serif;
  overflow: hidden;
  touch-action: none;
}

/* ─── Утилиты ────────────────────────────────────────────────
   Классы для наборов свойств, которые в этом файле были не просто похожи, а
   скопированы: одна и та же вещь под тридцатью тремя разными именами. Правило
   отбора одно — утилита заводится там, где селекторы описывают ОДНО И ТО ЖЕ
   (иконка заполняет свою рамку, длинное имя обрезается многоточием), а не там,
   где у разных вещей случайно совпали числа. Поэтому размерных утилит
   (.sq-44 и подобных) здесь нет: 22×22 у сердца в шапке и у монетки в подарках —
   совпадение, и половина таких размеров переопределяется в @media под узкий
   экран, где утилита из разметки только мешала бы.

   Утилиты стоят В НАЧАЛЕ файла намеренно: при равной силе селекторов побеждает
   тот, что ниже, поэтому любое правило компонента перебивает утилиту, а не
   наоборот. Дописывать сюда новые — только по тому же правилу.
─────────────────────────────────────────────────────────────── */

/* Картинка заполняет свою рамку целиком, не обрезаясь: рамку задаёт обёртка
   (у неё и размер), <img> внутри просто вписывается. display:block — чтобы под
   картинкой не оставался зазор строчного «хвоста». */
.icon-fill {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* Эмодзи-запаска ПОД картинкой: арта нет — onerror прячет <img>, и проступает
   она. Лежит ровно в той же рамке, z-index:0 держит её под картинкой (у той —
   z-index:1). Размер эмодзи у каждой свой, поэтому font-size остаётся на месте. */
.art-fallback {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

/* Длинный текст в одну строку: ужать до ширины родителя и оборвать многоточием.
   Во flex-строке этого мало — элементу нужен ещё min-width:0, иначе он не даст
   себя ужать; min-width остаётся у самих правил, он про раскладку, а не про текст. */
.u-ellipsis {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Значок в углу кнопки: счётчик («сколько») или метка «новое». Цвет, размер и
   угол — у каждого свои, общее здесь только «кружок с цифрой поверх кнопки». */
.dot-badge {
  position: absolute;
  z-index: 5;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-weight: 900;
  line-height: 1;
}

/* Тонкая сиреневая полоса прокрутки внутри карточек и списков. Псевдоэлементы
   класса не имеют, поэтому у полосы нет другого способа не размножаться. */
.thin-scroll::-webkit-scrollbar { width: 5px; }
.thin-scroll::-webkit-scrollbar-thumb { background: rgba(155,111,200,0.4); border-radius: 5px; }

#app {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  width: 100%;
  height: 100%;
  height: 100dvh;
  position: relative;
  overflow: hidden;
}

/* В альбоме поле — квадрат уже экрана. Центрируем весь игровой ряд (показатели → поле →
   предметы) и по вертикали, и по горизонтали, чтобы боковые колонки стояли вплотную к
   полю. Меню и экраны — это .screen (position:absolute), на них flex #app не влияет. */
@media (orientation: landscape) {
  #app {
    align-items: center;
    justify-content: center;
  }
}

/* ─── Раскладка матча ────────────────────────────────────────
   .game-stage — горизонтальный ряд из трёх колонок: показатели (.hud), поле
   (.game-main) и предметы (.hud-booster-bar). Обе полосы стоят СБОКУ, а не сверху
   и снизу: в альбоме размер квадратного поля упирается в высоту экрана, и каждый
   пиксель, отданный полосе над полем, поле теряло дважды — по высоте и по ширине.

   Порядок колонок задаёт order, а не порядок вставки: .game-main создаёт Game, а
   ленту и полку предметов — конструктор HUD, то есть после неё. */
.game-stage {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: calc(12px * var(--ui-space));
  max-width: 100%;
  max-height: 100%;
}

.game-main {
  order: 1;
  position: relative;   /* якорь для .hud-badges (индикаторы поверх верха поля) */
  display: flex;
  flex-direction: column;
  align-items: center;
  flex-shrink: 0;
}

#game-canvas {
  display: none;
  /* Поле — низ колонки .game-main: над ним в потоке стоит только полоса дуэли
     (order:0), и та лишь в дуэли. */
  order: 2;
  background: linear-gradient(180deg, #b8e4f8 0%, #d4c4ee 100%);
  border-radius: 12px;
  box-shadow: 0 0 40px rgba(155, 111, 200, 0.35);
  touch-action: none;
  flex-shrink: 0;
}

#game-canvas.active {
  display: block;
}

/* ─── HUD ───────────────────────────────────────────────────
   Лента показателей — ЛЕВАЯ колонка ряда матча (order:0): Время/Сердца/Цель стоят
   друг под другом слева от поля, как предметы стоят справа. Полосой над полем она
   отъедала 62px высоты, а высота в альбоме и есть предел размера поля.

   Ширина колонки ПОСТОЯННАЯ и не зависит от содержимого: набор чипов у режимов
   разный (в Выживании нет сердец, в вызове — времени), и «по содержимому» поле
   ездило бы вбок от каждого исчезнувшего чипа. Её же цифру знает Game._resize. */
.hud {
  order: 0;
  position: relative;
  width: calc(108px * var(--ui-scale));
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(9px * var(--ui-space));
  background: rgba(255,255,255,0.55);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(155,111,200,0.2);
  border-radius: calc(26px * var(--ui-scale));
  box-shadow: 0 calc(4px * var(--ui-scale)) calc(16px * var(--ui-scale)) rgba(120,80,170,0.14);
  padding: calc(10px * var(--ui-space)) calc(7px * var(--ui-space));
  z-index: 10;
}

/* Чип показателя внутри ленты — светлая пилюля с монеткой-иконкой слева.
   max-width — чтобы чип не распирал колонку постоянной ширины. */
.hud-chip {
  display: flex;
  align-items: center;
  max-width: 100%;
  gap: calc(6px * var(--ui-scale));
  padding: calc(3px * var(--ui-scale)) calc(11px * var(--ui-scale)) calc(3px * var(--ui-scale)) calc(3px * var(--ui-scale));
  border-radius: 999px;
  background: rgba(255,255,255,0.42);
}

.hud-chip--lives { padding-left: calc(11px * var(--ui-scale)); }

.hud-coin {
  width: calc(30px * var(--ui-scale));
  height: calc(30px * var(--ui-scale));
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(80,40,120,0.28);
}

.hud-coin-ico { width: 60%; height: 60%; display: block; }
.hud-coin--time  { background: linear-gradient(135deg, #ffb64d, #f2760c); }

/* Скрытая подпись «Время/Взрывы» — код обновляет её текст в режиме Выживания,
   но в ленте показатель обозначает монетка, а не текст. */
.hud-label--hidden { display: none; }

.hud-label {
  font-size: var(--fs-12);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgba(42,26,64,0.5);
}

.hud-value {
  font-size: var(--fs-18);
  font-weight: 700;
  color: #2a1a40;
  line-height: 1.2;
}

#hud-timer {
  color: #d4830a;
  transition: color 0.4s;
}

/* Timer urgency: <30s — red + pulse */
.hud-timer-urgent {
  color: #FF4D6D !important;
  animation: hud-timer-pulse 0.6s ease-in-out infinite;
}

@keyframes hud-timer-pulse {
  0%, 100% { transform: scale(1); }
  50%       { transform: scale(1.15); }
}


/* Life-loss flash */
@keyframes hud-lives-lost {
  0%   { transform: scale(1.4); color: #FF2244; }
  60%  { transform: scale(1.1); }
  100% { transform: scale(1); }
}

.hud-lives-lost {
  animation: hud-lives-lost 0.4s ease-out forwards;
}

/* Сердца матча — картинками (assets/hud/heart-full.png). Полное — сама картинка,
   пустое (.hud-heart--empty) — та же картинка, обесцвеченная. За картинкой лежит
   эмодзи-фолбэк (❤️/🖤): нет файла — onerror прячет <img>, проступает эмодзи. */
.hud-lives-hearts {
  display: inline-flex;
  align-items: center;
  gap: calc(3px * var(--ui-scale));
}

.hud-heart {
  position: relative;
  display: inline-flex;
  width: calc(22px * var(--ui-scale));
  height: calc(22px * var(--ui-scale));
}

.hud-heart-img {
  position: relative;
  z-index: 1;
}

.hud-heart-fallback {
  font-size: var(--fs-18);
}

/* Потерянное сердце — та же картинка, обесцвеченная и приглушённая. */
.hud-heart--empty .hud-heart-img { filter: grayscale(1) brightness(1.15); opacity: 0.3; }
.hud-heart--empty .hud-heart-fallback { opacity: 0.85; }

/* Взрывы в Выживании — картинками (assets/hud/blast.png). Случившийся взрыв —
   сама картинка, оставшийся слот (.hud-blast--empty) — та же картинка,
   обесцвеченная. За картинкой эмодзи-фолбэк (💥/○): нет файла — onerror прячет
   <img>, проступает эмодзи. Тот же приём, что и у сердец матча. */
.hud-blast {
  position: relative;
  display: inline-flex;
  width: calc(22px * var(--ui-scale));
  height: calc(22px * var(--ui-scale));
  vertical-align: middle;
}

.hud-blast + .hud-blast { margin-left: calc(3px * var(--ui-scale)); }

.hud-blast-img {
  position: relative;
  z-index: 1;
}

.hud-blast-fallback {
  font-size: var(--fs-18);
}

/* Оставшийся (ещё не сгоревший) слот — та же картинка, обесцвеченная. Эмодзи-фолбэк
   у пустого слота ПРЯЧЕМ: картинка здесь полупрозрачная (opacity .3), и золотой «○»
   (цвет #hud-timer) просвечивал сквозь неё кольцом. Фолбэк 💥 у сгоревших слотов
   остаётся — там картинка непрозрачная и его не видно, пока арт на месте. */
.hud-blast--empty .hud-blast-img { filter: grayscale(1) brightness(1.15); opacity: 0.3; }
.hud-blast--empty .hud-blast-fallback { display: none; }

/* Выживание: в шапке только слоты взрывов. Снимаем всё оформление ленты (фон-пилюля,
   рамка, тень) и чипа, оставляем сами взрывы — крупнее. Ставит класс HUD.update. */
.hud--blasts {
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: none;
  box-shadow: none;
}
.hud--blasts .hud-chip--time {
  background: none;
  padding: 0;
}
.hud--blasts .hud-blast {
  width: calc(44px * var(--ui-scale));
  height: calc(44px * var(--ui-scale));
}
/* Столбиком, как и остальные показатели в колонке: три картинки по 44px в ряд
   шире самой колонки. */
.hud--blasts .hud-value {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.hud--blasts .hud-blast + .hud-blast { margin-left: 0; margin-top: calc(8px * var(--ui-scale)); }
.hud--blasts .hud-blast-fallback { font-size: calc(34px * var(--ui-scale)); }

/* ─── Fever Mode HUD ─────────────────────────────────────── */
.hud-fever {
  display: flex;
  align-items: center;
  gap: 5px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
  min-width: 0;
}

.hud-fever-active {
  opacity: 1;
  animation: fever-hud-appear 0.3s ease-out;
}

@keyframes fever-hud-appear {
  0%   { transform: scale(0.7); opacity: 0; }
  70%  { transform: scale(1.08); }
  100% { transform: scale(1);   opacity: 1; }
}

.hud-fever-label {
  font-size: var(--fs-11);
  font-weight: 800;
  color: #e07020;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
  animation: fever-label-pulse 0.7s ease-in-out infinite;
}

@keyframes fever-label-pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.6; }
}

.hud-fever-bar-track {
  width: calc(44px * var(--ui-scale));
  height: calc(6px * var(--ui-scale));
  background: rgba(155,111,200,0.2);
  border-radius: 3px;
  overflow: hidden;
  flex-shrink: 0;
}

.hud-fever-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, #e07020, #f5c518);
  border-radius: 3px;
  transition: width 0.1s linear;
  box-shadow: 0 0 6px rgba(224,112,32,0.6);
}

.hud-fever-mult {
  font-size: var(--fs-13);
  font-weight: 800;
  color: #d4830a;
  white-space: nowrap;
}

/* ─── Шкала цели матча ──────────────────────────────────────
   Цель задаёт сервер по рангу игрока (rating_rules.target_score): взял — очки
   рейтинга идут с множителем. Пока цель не взята полоса фиолетовая, как весь HUD;
   взял — становится золотой, как FEVER, и подпись меняется на «ЦЕЛЬ ВЗЯТА».
   Цели нет (оффлайн) — блок скрыт, см. HUD#_updateTarget.
────────────────────────────────────────────────────────────── */
.hud-target {
  display: none;   /* показывается, только когда сервер прислал цель (hud-target-active) */
  align-items: center;
}

.hud-target-active { display: flex; }

/* Чип цели — кольцо-прогресс с процентом в центре, под ним подпись и число.
   Столбиком, а не в ряд: в ряд («🎯 ЦЕЛЬ ВЗЯТА» + число) чип шире колонки. */
.hud-chip--goal {
  flex-direction: column;
  gap: calc(3px * var(--ui-scale));
  padding: calc(7px * var(--ui-scale)) calc(8px * var(--ui-scale));
  background: rgba(123,63,190,0.13);
}

.hud-goal-ring {
  position: relative;
  width: calc(30px * var(--ui-scale));
  height: calc(30px * var(--ui-scale));
  flex: 0 0 auto;
}

.hud-goal-ring svg { width: 100%; height: 100%; display: block; transform: rotate(-90deg); }
.hud-goal-ring-bg { fill: none; stroke: rgba(155,111,200,0.25); stroke-width: 4; }

.hud-goal-ring-fg {
  fill: none;
  stroke: #7b3fbe;
  stroke-width: 4;
  stroke-linecap: round;
  stroke-dasharray: 81.68;
  stroke-dashoffset: 81.68;
  transition: stroke-dashoffset 0.25s ease-out;
}

.hud-goal-pct {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-9);
  font-weight: 800;
  color: #7b3fbe;
  font-variant-numeric: tabular-nums;
}

.hud-goal-info { display: flex; flex-direction: column; align-items: center; line-height: 1.05; }
.hud-goal-info .hud-label { font-size: var(--fs-9); white-space: nowrap; }

.hud-target-val {
  font-size: var(--fs-13);
  font-weight: 800;
  color: #7b3fbe;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.hud-target-hit .hud-goal-ring-fg { stroke: #f08c00; }
.hud-target-hit .hud-goal-pct { color: #e07020; }
.hud-target-hit .hud-target-val { color: #e07020; }

.hud-target-hit .hud-label {
  color: #c8860a;
  animation: target-hit-pulse 0.9s ease-in-out infinite;
}

@keyframes target-hit-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.6; }
}

/* ─── Цель ежедневного вызова ──────────────────────────────
   Норма пузырей по каждому цвету дня: цветная точка + «n/N». Закрытая норма
   гаснет и получает галочку. Показывается только когда режим прислал colorGoal
   (hud-colorgoal-active), см. HUD#_updateColorGoal.
────────────────────────────────────────────────────────────── */
.hud-chip--colorgoal {
  display: none;
  flex-direction: column;
  gap: calc(5px * var(--ui-scale));
  padding: calc(7px * var(--ui-scale)) calc(8px * var(--ui-scale));
  background: rgba(123,63,190,0.13);
}
.hud-colorgoal-active { display: flex; }

.hud-cg-label { font-size: var(--fs-9); white-space: nowrap; }

/* Цвета дня — столбиком: их бывает два, и «пузырь + 60/60» в ряд не влезает в колонку. */
.hud-cg-items {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(5px * var(--ui-scale));
}

.hud-cg-item {
  display: flex;
  align-items: center;
  gap: calc(5px * var(--ui-scale));
  transition: opacity 0.2s ease;
}

/* Пузырь: арт с поля поверх цветного кружка-фолбэка (тот же приём, что у сердец
   и кнопок предметов — картинка на z-index:1, запасной кружок под ней). */
.hud-cg-bub {
  position: relative;
  width: calc(22px * var(--ui-scale));
  height: calc(22px * var(--ui-scale));
  flex: 0 0 auto;
  border-radius: 50%;
  filter: drop-shadow(0 calc(1px * var(--ui-scale)) calc(3px * var(--ui-scale)) rgba(80,40,120,0.4));
  transition: filter 0.2s ease;
}

.hud-cg-bub-img {
  position: relative;
  z-index: 1;
}

.hud-cg-dot {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: 50%;
  box-shadow: inset 0 calc(-2px * var(--ui-scale)) calc(3px * var(--ui-scale)) rgba(0,0,0,0.22),
              0 0 0 calc(1.5px * var(--ui-scale)) rgba(255,255,255,0.6);
}

.hud-cg-count {
  font-size: var(--fs-14);
  font-weight: 800;
  color: #7b3fbe;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Норма закрыта: пузырь получает зелёный ореол, число зеленеет с галочкой. */
.hud-cg-item--done { opacity: 0.9; }
.hud-cg-item--done .hud-cg-count { color: #2f9e44; }
.hud-cg-item--done .hud-cg-count::after { content: ' ✓'; }
.hud-cg-item--done .hud-cg-bub {
  filter: drop-shadow(0 0 calc(4px * var(--ui-scale)) rgba(47,158,68,0.85));
}

/* ─── Обучение в первом матче ───────────────────────────────
   Одна подсказка за раз, поверх верхних рядов поля. Плашка та же, что у итога
   рейтинга (.go-league): стекло, фиолетовая рамка.

   Отступ отмеряем от НИЗА колонки поля — тем же приёмом, что и слой индикаторов
   (.hud-badges): низ .game-main совпадает с низом поля, высота поля лежит в
   --board-w. Так подсказка садится на одно и то же место поля во всех режимах и
   всегда проходит НИЖЕ строки индикаторов (та отбивает 34px от верха поля).
   Прежние «60px от верха экрана» после переезда ленты вбок сажали её ровно на
   «КРИТИЧЕСКАЯ ЛИНИЯ», а в дуэли — ещё и вкось.

   pointer-events: none — ОБЯЗАТЕЛЬНО. Плашка висит над верхним рядом поля, и с
   кликабельностью она перехватывала бы касания: игрок начал бы свайп по шару под
   ней и не понял, почему цепочка не собирается. Свайп проходит сквозь; подсказка
   гаснет сама (см. ui/Tutorial.js).
────────────────────────────────────────────────────────────── */
.tut-hint {
  position: absolute;
  bottom: calc(var(--board-w, 100%) - 104px * var(--ui-scale));
  left: 50%;
  transform: translateX(-50%) translateY(-6px);
  z-index: 12;
  /* Как и у .hud-badges: ширина по содержимому, иначе left:50% ужимает плашку до
     половины поля и текст ломается лишними строками. */
  width: max-content;
  max-width: min(86vw, calc(460px * var(--ui-scale)));
  padding: calc(7px * var(--ui-space)) calc(16px * var(--ui-space));
  border-radius: 50px;
  background: rgba(255,255,255,0.82);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(155,111,200,0.35);
  box-shadow: 0 4px 16px rgba(80,40,120,0.18);
  font-size: var(--fs-13);
  font-weight: 600;
  line-height: 1.35;
  color: #2a1a40;
  text-align: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.28s ease, transform 0.28s ease;
}

.tut-hint-show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  animation: tut-hint-in 0.34s ease-out;
}

@keyframes tut-hint-in {
  0%   { opacity: 0; transform: translateX(-50%) translateY(-10px) scale(0.96); }
  70%  { transform: translateX(-50%) translateY(0) scale(1.03); }
  100% { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
}

/* ─── Golden Frenzy HUD badge ───────────────────────────── */
.hud-golden {
  font-size: var(--fs-11);
  font-weight: 800;
  color: #c8860a;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
  text-shadow: 0 0 8px rgba(200,134,10,0.6);
}

.hud-golden-active {
  opacity: 1;
  animation: golden-badge-appear 0.3s ease-out, golden-pulse 0.8s ease-in-out infinite;
}

@keyframes golden-badge-appear {
  0%   { transform: scale(0.7); opacity: 0; }
  70%  { transform: scale(1.12); }
  100% { transform: scale(1);   opacity: 1; }
}

@keyframes golden-pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.65; }
}

/* ─── Critical Line HUD indicator ───────────────────────── */
.hud-critical-line {
  font-size: var(--fs-11);
  font-weight: 800;
  color: #FF6B6B;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.hud-critical-line-active {
  opacity: 1;
  animation: critline-appear 0.3s ease-out, critline-pulse 0.6s ease-in-out infinite;
}

@keyframes critline-appear {
  0%   { transform: translateY(-4px); opacity: 0; }
  100% { transform: translateY(0);    opacity: 1; }
}

@keyframes critline-pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.55; }
}

/* ─── Combo HUD ─────────────────────────────────────────── */
.hud-combo {
  font-size: var(--fs-11);
  font-weight: 800;
  color: #7b3fbe;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.hud-combo-active {
  opacity: 1;
  animation: combo-appear 0.3s ease-out, combo-pulse 0.5s ease-in-out infinite;
}

@keyframes combo-appear {
  0%   { transform: scale(0.7); opacity: 0; }
  60%  { transform: scale(1.12); opacity: 1; }
  100% { transform: scale(1);   opacity: 1; }
}

@keyframes combo-pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.6; }
}

/* ─── Плавающие индикаторы поверх верха поля ─────────────────
   FEVER / ЗОЛОТО / КРИТ. ЛИНИЯ / КОМБО — плашки во всю ширину поля, и в узкую
   колонку показателей они не помещаются; лежат отдельным слоем в колонке поля
   (.game-main), вне потока, а неактивные прячутся display:none — тогда активный
   встаёт ровно по центру, а не сдвинут соседями.

   Отсчёт ведём от НИЗА колонки: низ .game-main совпадает с низом поля, а высота
   поля лежит в --board-w (её кладёт Game._resize). Поэтому плашка садится на
   верхние ряды поля и в дуэли, где над полем есть ещё полоса соперника.
   pointer-events:none — свайп по верхнему ряду поля проходит сквозь индикатор. */
.hud-badges {
  position: absolute;
  bottom: calc(var(--board-w, 100%) - 34px * var(--ui-scale));
  left: 50%;
  /* Ширина по содержимому: у элемента с left:50% она иначе считается как «сколько
     осталось до правого края родителя», и плашка, что шире половины поля, поехала
     бы вправо от середины. */
  width: max-content;
  transform: translateX(-50%);
  z-index: 11;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(4px * var(--ui-scale));
  pointer-events: none;
  white-space: nowrap;
}

/* Внутри слоя показываем только активные индикаторы (правило идёт ПОСЛЕ базовых
   .hud-fever/.hud-golden/… — при равной специфичности побеждает более позднее). */
.hud-badges > * { display: none; }
.hud-badges > .hud-fever-active { display: flex; }
.hud-badges > .hud-golden-active,
.hud-badges > .hud-critical-line-active,
.hud-badges > .hud-combo-active { display: block; }

/* …и только СТАРШИЙ из активных: столбик в две-четыре строки закрывал верх поля
   (порядок старшинства — HUD#_syncBadges). Правило идёт последним, значит при
   равной специфичности побеждает оно. */
.hud-badges > .hud-badge-off { display: none; }

/* ─── Splash Screen ──────────────────────────────────────── */
/* Сплэш держит ровно то же кадрирование splash-арта, что и экран входа
   (.auth-screen ниже): кадр прижат влево и растянут по cover — героиня нигде
   не режется, за край экрана уходит только пустой фон справа, а при переходе
   сплэш → форма входа картинка остаётся на месте и под ней просто всплывает
   карточка. Правила-близнецы — если правишь кадр здесь, правь и там. */
.splash-screen {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: linear-gradient(180deg, #a9d9ef 0%, #cfe0f2 60%, #ecf0f7 100%);
  overflow: hidden;
  transition: opacity 0.4s ease;
}

.splash-screen.splash-fade-out {
  opacity: 0;
  pointer-events: none;
}

.splash-img {
  position: absolute;
  z-index: 1;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: left center;
}

/* Портрет — арт полосой по низу экрана. Размер элемента задан в пропорции
   самого арта, поэтому object-fit ничего не режет; лишнее по ширине обрезает
   overflow. Пустое место над полосой добирает размытая заливка — кроп неба из
   правого верхнего угла того же арта. */
@media (max-aspect-ratio: 6 / 5) {
  .splash-screen::before {
    content: '';
    position: absolute;
    inset: -8%;
    background-image: var(--splash-art);
    background-position: 82% 0%;
    background-size: auto 260%;
    background-repeat: no-repeat;
    filter: blur(52px) saturate(1.08) brightness(1.04);
    transform: scale(1.12);
  }
  .splash-img {
    top: auto;
    bottom: 0;
    height: var(--auth-art-h);
    width: var(--auth-art-w);
    max-width: none;
    object-fit: fill;
    -webkit-mask-image:
      linear-gradient(to bottom, transparent 0%, #000 6%),
      linear-gradient(to right, #000 calc(100% - 48px), transparent 100%);
            mask-image:
      linear-gradient(to bottom, transparent 0%, #000 6%),
      linear-gradient(to right, #000 calc(100% - 48px), transparent 100%);
    -webkit-mask-composite: source-in;
            mask-composite: intersect;
  }
}

/* ─── Screen transitions ─────────────────────────────────── */
.screen {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  background: linear-gradient(160deg, rgba(168,216,240,0.97) 0%, rgba(201,184,232,0.97) 50%, rgba(240,192,216,0.97) 100%);
  z-index: 20;
  padding: 24px;
  opacity: 0;
  transform: scale(0.96);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.screen-enter {
  opacity: 1;
  transform: scale(1);
}

.screen-exit {
  opacity: 0;
  transform: scale(1.04);
}

/* ─── Main Menu ──────────────────────────────────────────── */
.main-menu {
  justify-content: flex-start;
  overflow: hidden;
  padding: 0;
  gap: 0;
}

.menu-logo {
  margin-bottom: 4px;
}

.menu-logo-img {
  max-width: calc(320px * var(--ui-scale));
  width: 80vw;
  height: auto;
  display: block;
  filter: drop-shadow(0 2px 16px rgba(155, 111, 200, 0.55));
}


.menu-hint {
  font-size: var(--fs-13);
  color: rgba(42,26,64,0.45);
  text-align: center;
  max-width: 240px;
  margin-top: 8px;
}

.menu-lives {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}




/* ─── Buttons ────────────────────────────────────────────── */
.btn-play {
  padding: calc(14px * var(--ui-space)) calc(48px * var(--ui-space));
  font-size: var(--fs-20);
  font-weight: 800;
  border: none;
  border-radius: 50px;
  background: linear-gradient(135deg, #9b6fc8, #e07020);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 4px 24px rgba(155,111,200,0.45);
  transition: transform 0.1s, box-shadow 0.1s;
}

.btn-play:hover {
  transform: scale(1.03);
  box-shadow: 0 6px 28px rgba(155,111,200,0.6);
}

.btn-play:active {
  transform: scale(0.96);
  box-shadow: 0 2px 12px rgba(155,111,200,0.3);
}

.btn-play:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.btn-close {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 10;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0.85;
  transition: opacity 0.15s, transform 0.15s;
}

.btn-close:hover {
  opacity: 1;
  transform: scale(1.1);
}

.btn-close img {
  width: 36px;
  height: 36px;
  display: block;
}

.btn-menu {
  padding: calc(10px * var(--ui-space)) calc(32px * var(--ui-space));
  font-size: var(--fs-15);
  font-weight: 600;
  border: 1.5px solid rgba(155,111,200,0.35);
  border-radius: 50px;
  background: rgba(255,255,255,0.45);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: rgba(42,26,64,0.75);
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}

.btn-menu:hover {
  border-color: rgba(155,111,200,0.65);
  color: #2a1a40;
  background: rgba(255,255,255,0.65);
}

/* Mode buttons */
.menu-modes {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  max-width: 300px;
}

.btn-mode {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: calc(14px * var(--ui-space)) calc(20px * var(--ui-space));
}


.mode-name {
  font-size: var(--fs-17);
  font-weight: 800;
}


/* Per-mode colour themes */
.btn-mode-daily {
  background: linear-gradient(135deg, #f5c518, #e07020) !important;
  box-shadow: 0 4px 20px rgba(224,112,32,0.35) !important;
  color: #fff !important;
}

.btn-mode-daily:hover {
  box-shadow: 0 6px 26px rgba(224,112,32,0.5) !important;
}

.btn-mode-survival {
  background: linear-gradient(135deg, #e04060, #f090a0) !important;
  box-shadow: 0 4px 20px rgba(224,64,96,0.35) !important;
  color: #fff !important;
}

.btn-mode-survival:hover {
  box-shadow: 0 6px 26px rgba(224,64,96,0.5) !important;
}

.btn-mode-duel {
  background: linear-gradient(135deg, #7b3fbe, #a898e8) !important;
  box-shadow: 0 4px 20px rgba(123,63,190,0.35) !important;
  color: #fff !important;
}

.btn-mode-duel:hover {
  box-shadow: 0 6px 26px rgba(123,63,190,0.5) !important;
}

/* Ежедневный вызов уже сыгран сегодня: кнопка носит счётчик до полуночи, но
   остаётся такой же яркой, как при наличии жизней — не гаснет после победы/траты
   попыток. Класс нужен JS, чтобы по клику открыть блокирующее окно (см. MainMenu). */
.btn-mode-locked { /* без затемнения — яркость как у доступной кнопки */ }

/* Нет жизней — запертая кнопка ежедневного вызова тускнеет наравне с остальными
   режимами (иначе она осталась бы единственной яркой при 0 сердцах). Клик по ней
   всё ещё открывает окно с отсчётом до полуночи, поэтому disabled не ставим —
   гасим только визуально, как opacity у .btn-play:disabled у прочих кнопок. */
.btn-mode-daily.btn-mode-nolives { opacity: 0.35; }


/* ─── Game Over ───────────────────────────────────────────────────────────────
   Экран конца матча собран тем же «бланком», что и мастер дуэли (.dw-card): белая
   обводка, тёплый градиент, мягкие пятна за карточкой. Внутри — эмблема результата,
   причина строкой-плашкой, заголовок, блок предложений за рекламу и подвал с парой
   равных кнопок. Счёта тут намеренно нет: очки, рекорд и таймер с экрана убраны
   раньше (см. историю файла) — карточка говорит только ЧЕМ кончился матч.
────────────────────────────────────────────────────────────────────────────── */
.game-over {
  /* --go-scale / --go-space — собственный масштаб ЭКРАНА ИТОГА: по умолчанию общий,
     на телефоне поднят (медиазапрос в конце блока). Ступени кегля объявляем заново
     от него: --fs-* с :root уже посчитаны общим --ui-scale и подмены не увидят —
     значение переменной вычисляется там, где объявлено, а не там, где читается. */
  --go-scale: var(--ui-scale);
  --go-space: var(--ui-space);
  --fs-10: calc(10px * var(--go-scale));
  --fs-10-5: calc(10.5px * var(--go-scale));
  --fs-11: calc(11px * var(--go-scale));
  --fs-11-5: calc(11.5px * var(--go-scale));
  --fs-12-5: calc(12.5px * var(--go-scale));
  --fs-13: calc(13px * var(--go-scale));
  --fs-14: calc(14px * var(--go-scale));
  --fs-15: calc(15px * var(--go-scale));
  --fs-16: calc(16px * var(--go-scale));
  --fs-19: calc(19px * var(--go-scale));
  --fs-22: calc(22px * var(--go-scale));
  /* Фон БЕЗ прозрачности, в отличие от общего .screen: сквозь его 0.97 просвечивало
     оставшееся позади меню, и карточка ложилась на сиреневый муар из чужих кнопок. */
  background: linear-gradient(160deg, #a8d8f0 0%, #c9b8e8 50%, #f0c0d8 100%);
  justify-content: center;
  padding: calc(14px * var(--go-space));
  gap: 0;
}

/* Пятна за карточкой — как на экране дуэли: глубина фону, но не рисунок. Это
   radial-gradient, а не blur(): фильтр по такой площади греет слабые телефоны. */
.go-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}
.go-glow i {
  position: absolute;
  display: block;
  border-radius: 50%;
  animation: go-drift 11s ease-in-out infinite;
}
.go-glow i:nth-child(1) {
  width: 44vh; height: 44vh; left: 5%; top: -8%;
  background: radial-gradient(circle, rgba(255,198,110,0.5), rgba(255,198,110,0) 62%);
}
/* Цвета подобраны ПОД МЕСТО на фоне: янтарь ложится на голубой верх слева, мята —
   на розовый низ справа. Пятно в тон фона под собой просто не видно. */
.go-glow i:nth-child(2) {
  width: 46vh; height: 46vh; right: 4%; bottom: -14%;
  background: radial-gradient(circle, rgba(120,225,190,0.45), rgba(120,225,190,0) 62%);
  animation-delay: -5.5s;
}
/* Белый ореол ровно под карточкой: она приподнимается над фоном, а её тень
   перестаёт выглядеть грязным пятном на сиреневом. */
.go-glow i:nth-child(3) {
  width: min(calc(720px * var(--go-scale)), 92vw); height: 60vh;
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  background: radial-gradient(ellipse, rgba(255,255,255,0.55), rgba(255,255,255,0) 66%);
  animation: none;
}
@keyframes go-drift {
  0%, 100% { transform: translate3d(0, 0, 0)    scale(1);    }
  50%      { transform: translate3d(0, -4vh, 0) scale(1.08); }
}

/* ── Карточка результата ─────────────────────────────────────────────────── */
.go-card {
  position: relative;
  z-index: 1;
  width: min(calc(440px * var(--go-scale)), 92vw);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(8px * var(--go-space));
  padding: calc(16px * var(--go-space)) calc(20px * var(--go-space)) calc(14px * var(--go-space));
  background: linear-gradient(165deg, #fef6ff 0%, #f4e9ff 55%, #ffeef4 100%);
  border: calc(3px * var(--go-scale)) solid #ffffff;
  border-radius: calc(30px * var(--go-scale));
  box-shadow:
    0 calc(16px * var(--go-scale)) calc(44px * var(--go-scale)) rgba(42,26,64,0.35),
    0 0 0 calc(4px * var(--go-scale)) rgba(155,111,200,0.4),
    inset 0 calc(2px * var(--go-scale)) calc(6px * var(--go-scale)) rgba(255,255,255,0.9);
  box-sizing: border-box;
  animation: go-card-in 0.32s ease-out;
}
/* Победа — тот же бланк, но в золотом канте игры вместо сиреневого. */
.go-card--win {
  box-shadow:
    0 calc(16px * var(--go-scale)) calc(44px * var(--go-scale)) rgba(42,26,64,0.35),
    0 0 0 calc(4px * var(--go-scale)) rgba(255,178,72,0.55),
    inset 0 calc(2px * var(--go-scale)) calc(6px * var(--go-scale)) rgba(255,255,255,0.9);
}
@keyframes go-card-in {
  from { opacity: 0; transform: translateY(calc(16px * var(--go-scale))) scale(0.96); }
  to   { opacity: 1; transform: none; }
}

/* ── Эмблема результата ──────────────────────────────────────────────────────
   Кружок с артом: кубок за победу и рекорд, сердце/взрыв/часы за поражение. За
   картинкой лежит эмодзи-фолбэк — нет файла, onerror прячет <img> (imgFallback.js)
   и проступает эмодзи. Значок из строки причины при этом убран, чтобы не двоить. */
.go-badge {
  position: relative;
  flex: 0 0 auto;
  /* Отбивка снизу — под расходящееся кольцо победы (.go-badge::after выходит за
     круг), иначе оно наезжает на плашку причины. */
  margin-bottom: calc(3px * var(--go-space));
  width: calc(84px * var(--go-scale));
  height: calc(84px * var(--go-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: linear-gradient(165deg, #ffffff, #e8dbfa);
  box-shadow: 0 calc(6px * var(--go-scale)) calc(16px * var(--go-scale)) rgba(120,80,170,0.3),
              inset 0 0 0 calc(3px * var(--go-scale)) rgba(255,255,255,0.9);
}
.go-card--win .go-badge {
  background: linear-gradient(165deg, #fff8e4, #ffd98f);
  box-shadow: 0 calc(6px * var(--go-scale)) calc(18px * var(--go-scale)) rgba(224,140,20,0.42),
              inset 0 0 0 calc(3px * var(--go-scale)) rgba(255,255,255,0.9);
  animation: go-badge-pop 0.5s cubic-bezier(0.2, 1.5, 0.5, 1) both;
}
/* Расходящееся кольцо у победной эмблемы — единственное живое место наверху карточки */
.go-badge::after {
  content: '';
  position: absolute;
  inset: calc(-7px * var(--go-scale));
  border-radius: 50%;
  border: calc(2px * var(--go-scale)) solid rgba(255,194,102,0.55);
  opacity: 0;
  pointer-events: none;
}
.go-card--win .go-badge::after { animation: go-badge-ring 2.6s ease-out infinite; }
.go-badge-art {
  position: relative;
  z-index: 1;
  width: 62%;
  height: 62%;
  object-fit: contain;
  filter: drop-shadow(0 calc(3px * var(--go-scale)) calc(4px * var(--go-scale)) rgba(90,50,20,0.28));
}
.go-badge-fallback {
  font-size: calc(38px * var(--go-scale));
}
/* Арт эмблемы загрузился — запаска гасится совсем: эмодзи выше картинки, и из-под
   кубка торчала его подставка. Метку ставит onload (GameOverScreen#emblemHtml). */
.go-badge-art[data-loaded] + .go-badge-fallback { display: none; }
@keyframes go-badge-pop {
  from { transform: scale(0.6); opacity: 0; }
  to   { transform: scale(1);   opacity: 1; }
}
@keyframes go-badge-ring {
  0%        { transform: scale(0.92); opacity: 0.7; }
  70%, 100% { transform: scale(1.3);  opacity: 0;   }
}

/* ── Причина и заголовок ─────────────────────────────────────────────────── */
.go-reason {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: calc(3px * var(--go-space)) calc(12px * var(--go-space));
  border-radius: 999px;
  background: rgba(155,111,200,0.16);
  color: #8b6fb5;
  font-size: var(--fs-11);
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
}
.go-card--win .go-reason {
  background: rgba(255,194,102,0.32);
  color: #a8762a;
}

.go-title {
  font-size: calc(30px * var(--go-scale) * var(--fs-scale));
  font-weight: 900;
  line-height: 1.05;
  letter-spacing: 0.5px;
  text-align: center;
  color: #3a2358;
}
/* Победный заголовок залит янтарём игры — тем же градиентом, что кнопка «Забрать» */
.go-card--win .go-title {
  background: linear-gradient(180deg, #ffd062 0%, #e0850f 100%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  filter: drop-shadow(0 calc(2px * var(--go-scale)) calc(3px * var(--go-scale)) rgba(224,133,15,0.4));
  animation: go-title-shine 0.6s ease-out;
}
@keyframes go-title-shine {
  0%   { transform: scale(0.86); opacity: 0; }
  60%  { transform: scale(1.06); opacity: 1; }
  100% { transform: scale(1); }
}

/* ── Табло дуэли с другом ────────────────────────────────────────────────────
   Заменяет на этом экране всё, что относится к одиночному матчу: у дуэли итог —
   не «игра окончена», а КТО КОГО и с каким счётом. Счёта, победу, очки и личные
   встречи присылает сервер уже после конца матча (GameOverScreen#_applyDuel), до
   ответа счёт соперника пульсирует многоточием. */
.go-duel {
  width: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: calc(3px * var(--go-space));
  padding: calc(7px * var(--go-space)) calc(8px * var(--go-space));
  border-radius: calc(20px * var(--go-scale));
  border: 1px solid rgba(155,111,200,0.22);
  background: rgba(255,255,255,0.6);
}
.go-duel-row {
  display: flex;
  align-items: center;
  gap: calc(8px * var(--go-space));
  padding: calc(5px * var(--go-space)) calc(9px * var(--go-space));
  border-radius: calc(15px * var(--go-scale));
  background: rgba(255,255,255,0.75);
  transition: background 0.3s ease, opacity 0.3s ease;
}
/* Кружок лица — тот же виджет, что в полосе дуэли внутри матча (.ds-ava*), здесь
   только крупнее: это главная строка экрана, а не строка HUD. */
.go-duel-ava {
  width: calc(36px * var(--go-scale));
  height: calc(36px * var(--go-scale));
}
.go-duel-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-14);
  font-weight: 800;
  color: #4a2d6e;
}
.go-duel-score {
  flex-shrink: 0;
  font-size: var(--fs-19);
  font-weight: 900;
  color: #4a2d6e;
  font-variant-numeric: tabular-nums;
}
/* Счёт, которого ещё нет: ждём ответа сервера (пульс) либо друг сыграет позже. */
.go-duel-score--pending { animation: go-duel-wait 1.2s ease-in-out infinite; }
.go-duel-score--wait {
  font-size: var(--fs-11-5);
  font-weight: 700;
  color: #8b7aa5;
}
@keyframes go-duel-wait {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 1; }
}
/* Победителя красим в зелень полосы дуэли, проигравшего приглушаем — итог должен
   читаться раньше, чем игрок сравнит два числа. */
.go-duel-row--won {
  background: linear-gradient(90deg, rgba(110,214,140,0.34), rgba(110,214,140,0.12));
}
.go-duel-row--won .go-duel-score { color: #1f7d4a; }
.go-duel-row--lost { opacity: 0.7; }

.go-duel-vs {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}
.go-duel-vs::before {
  content: '';
  position: absolute;
  left: 8%;
  right: 8%;
  height: calc(2px * var(--go-scale));
  border-radius: 999px;
  background: linear-gradient(90deg, rgba(155,111,200,0), rgba(155,111,200,0.3), rgba(155,111,200,0));
}
.go-duel-vs span {
  position: relative;
  padding: calc(1px * var(--go-space)) calc(9px * var(--go-space));
  border-radius: 999px;
  background: #ffffff;
  box-shadow: 0 calc(1px * var(--go-scale)) calc(4px * var(--go-scale)) rgba(120,80,170,0.2);
  font-size: var(--fs-10);
  font-weight: 900;
  letter-spacing: 0.12em;
  color: #9b7fc0;
}

/* Очки: начисленные за дуэль или лежащие в эскроу до ответа друга */
.go-duel-prize {
  padding: calc(3px * var(--go-space)) calc(14px * var(--go-space));
  border-radius: 999px;
  background: rgba(255,194,102,0.32);
  color: #a8762a;
  font-size: var(--fs-12-5);
  font-weight: 900;
}
/* Счёт личных встреч с этим другом — из БД, по всем сыгранным дуэлям пары */
.go-duel-h2h {
  font-size: var(--fs-11-5);
  font-weight: 800;
  color: #7b5a9a;
}
.go-duel-hint {
  max-width: 92%;
  text-align: center;
  font-size: var(--fs-11);
  font-weight: 700;
  line-height: 1.25;
  color: #8b7aa5;
}

/* ── Предложения за рекламу: продолжить матч и удвоить награду ────────────── */
.go-acts {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(7px * var(--go-space));
  width: 100%;
  margin-top: calc(2px * var(--go-space));
}
.btn-rv {
  position: relative;
  overflow: hidden;
  width: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: calc(10px * var(--go-space)) calc(16px * var(--go-space));
  font-size: var(--fs-15);
  font-weight: 900;
  letter-spacing: 0.3px;
  border: calc(2px * var(--go-scale)) solid rgba(255,255,255,0.8);
  border-radius: calc(16px * var(--go-scale));
  color: #fff;
  cursor: pointer;
  transition: transform 0.12s ease, filter 0.12s ease;
}
.btn-rv-continue {
  background: linear-gradient(180deg, #c9a9ee, #8e5fd0);
  text-shadow: 0 calc(2px * var(--go-scale)) 0 rgba(70,35,130,0.35);
  box-shadow: 0 calc(5px * var(--go-scale)) calc(14px * var(--go-scale)) rgba(120,80,170,0.45),
              inset 0 calc(2px * var(--go-scale)) 0 rgba(255,255,255,0.45);
}
.btn-rv-double {
  background: linear-gradient(180deg, #ffc266, #e0850f);
  text-shadow: 0 calc(2px * var(--go-scale)) 0 rgba(150,80,10,0.35);
  box-shadow: 0 calc(5px * var(--go-scale)) calc(14px * var(--go-scale)) rgba(224,112,32,0.45),
              inset 0 calc(2px * var(--go-scale)) 0 rgba(255,255,255,0.55);
}
/* Блик, пробегающий по главному предложению — как у кнопки мастера дуэли */
.btn-rv-double::after {
  content: '';
  position: absolute;
  top: 0;
  left: -60%;
  width: 34%;
  height: 100%;
  background: linear-gradient(100deg, rgba(255,255,255,0), rgba(255,255,255,0.5), rgba(255,255,255,0));
  transform: skewX(-18deg);
  animation: go-shine 3.6s ease-in-out infinite;
}
.btn-rv-double:disabled::after { display: none; }
@keyframes go-shine {
  0%, 62%   { left: -60%; }
  92%, 100% { left: 130%; }
}
/* Подпись поверх блика (и её же подменяет JS после просмотра ролика) */
.btn-rv-label { position: relative; z-index: 1; }
.btn-rv:hover:not(:disabled)  { filter: brightness(1.05); }
.btn-rv:active:not(:disabled) { transform: scale(0.97); }
.btn-rv:disabled {
  opacity: 0.5;
  filter: grayscale(0.6);
  cursor: default;
  transform: none !important;
}
/* Награда уже удвоена: кнопка остаётся выключенной, но это УСПЕХ, а не отказ —
   гасить её серым нельзя. Горячее золото уходит в голубой шарик игры (#4D9FFF из
   палитры поля): дело сделано, и ни с одной живой кнопкой карточки — сиреневой
   «Продолжить», розовой «Играть снова» — этот цвет не путается. */
.btn-rv-double.btn-rv-done {
  opacity: 1;
  filter: none;
  background: linear-gradient(180deg, #a8d5ff, #4d9fff);
  text-shadow: 0 calc(2px * var(--go-scale)) 0 rgba(20,75,145,0.32);
  box-shadow: 0 calc(4px * var(--go-scale)) calc(12px * var(--go-scale)) rgba(77,159,255,0.42),
              inset 0 calc(2px * var(--go-scale)) 0 rgba(255,255,255,0.55);
}

/* ── Подвал: поделиться/вызвать и выход из матча ──────────────────────────── */
.go-foot {
  flex-shrink: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(7px * var(--go-space));
  padding-top: calc(6px * var(--go-space));
}
/* Тающая линия: отделяет выход из матча от предложений мягче, чем зазор */
.go-foot::before {
  content: '';
  width: 78%;
  height: calc(2px * var(--go-scale));
  margin-bottom: calc(3px * var(--go-space));
  border-radius: 999px;
  background: linear-gradient(90deg, rgba(155,111,200,0), rgba(155,111,200,0.28), rgba(155,111,200,0));
}

/* Позвать друга — тихая кнопка подвала: цвет на карточке держат кнопки действия,
   а не она. Стояла в паре с «Поделиться», осталась одна — поэтому не тянется во всю
   ширину (как «Главное меню» без «Играть снова», см. .go-nav--solo). */
.btn-challenge {
  flex: 0 1 auto;
  min-width: min(calc(220px * var(--go-scale)), 62%);
  padding: calc(7px * var(--go-space)) calc(10px * var(--go-space));
  font-size: var(--fs-12-5);
  font-weight: 800;
  border: calc(2px * var(--go-scale)) solid rgba(255,255,255,0.9);
  border-radius: calc(13px * var(--go-scale));
  background: linear-gradient(180deg, #ffffff, #ffd9e6);
  color: #c93b70;
  box-shadow: 0 calc(2px * var(--go-scale)) calc(7px * var(--go-scale)) rgba(224,64,96,0.28);
  cursor: pointer;
  white-space: nowrap;
  transition: transform 0.12s ease, filter 0.12s ease;
}
.btn-challenge:hover:not(:disabled)  { filter: brightness(1.04); }
.btn-challenge:active:not(:disabled) { transform: scale(0.96); }
.btn-challenge:disabled {
  opacity: 0.45;
  cursor: default;
  transform: none !important;
}

/* Выход из матча: «Играть снова» — розовая кнопка игры, «Главное меню» — молочная.
   Обе одного размера, как пара в подвале мастера дуэли. */
.go-nav-row {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: calc(10px * var(--go-space));
  width: 100%;
}
.go-nav {
  flex: 1 1 0;
  min-width: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: calc(10px * var(--go-space)) calc(14px * var(--go-space));
  font-size: var(--fs-15);
  font-weight: 900;
  letter-spacing: 0.3px;
  border: calc(2px * var(--go-scale)) solid rgba(255,255,255,0.9);
  border-radius: calc(16px * var(--go-scale));
  cursor: pointer;
  transition: transform 0.12s ease, filter 0.12s ease;
}
.go-nav--again {
  color: #fff;
  background: linear-gradient(180deg, #ffa8c8, #e8517f);
  text-shadow: 0 calc(2px * var(--go-scale)) 0 rgba(150,25,70,0.3);
  box-shadow: 0 calc(5px * var(--go-scale)) calc(14px * var(--go-scale)) rgba(224,64,96,0.4),
              inset 0 calc(2px * var(--go-scale)) 0 rgba(255,255,255,0.5);
}
.go-nav--menu {
  color: #6b4a94;
  background: linear-gradient(180deg, #ffffff, #f4ebfc);
  box-shadow: 0 calc(3px * var(--go-scale)) calc(9px * var(--go-scale)) rgba(155,111,200,0.22);
}
/* Ежедневный вызов доигран — «Играть снова» нет (попытки считает меню), и одинокое
   «Главное меню» не должно растягиваться во всю карточку. */
.go-nav--solo { flex: 0 1 auto; min-width: min(calc(220px * var(--go-scale)), 62%); }
.go-nav:hover  { filter: brightness(1.04); }
.go-nav:active { transform: scale(0.96); }

/* Плашка-ответ на «Вызов» и на отказ рекламы — висит под карточкой, у самых кнопок */
.go-toast {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translate(-50%, calc(100% + 4px));
  z-index: 5;
  max-width: 90%;
  padding: calc(8px * var(--go-space)) calc(18px * var(--go-space));
  border: calc(2px * var(--go-scale)) solid rgba(255,255,255,0.9);
  border-radius: 999px;
  background: rgba(255,255,255,0.95);
  box-shadow: 0 calc(4px * var(--go-scale)) calc(16px * var(--go-scale)) rgba(120,80,170,0.3);
  font-size: var(--fs-12-5);
  font-weight: 800;
  color: #7b3fbe;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.go-toast-show {
  opacity: 1;
  transform: translate(-50%, calc(100% + 12px));
}

@media (prefers-reduced-motion: reduce) {
  .go-glow i,
  .go-card,
  .btn-rv-double::after,
  .go-duel-score--pending,
  .go-card--win .go-badge,
  .go-card--win .go-badge::after,
  .go-card--win .go-title { animation: none; }
}

/* Узкая адаптация: карточка должна влезать по высоте без прокрутки — жмём отступы
   и кегль, а не кнопки, по ним попадают пальцем. */
@media (max-width:1100px),(max-height:660px) and (orientation:landscape) {
  .game-over    { padding: calc(8px * var(--go-space)); }
  .go-card      { width: min(calc(400px * var(--go-scale)), 90vw);
                  gap: calc(6px * var(--go-space));
                  padding: calc(11px * var(--go-space)) calc(14px * var(--go-space)) calc(10px * var(--go-space));
                  border-radius: calc(24px * var(--go-scale)); }
  .go-badge     { width: calc(58px * var(--go-scale)); height: calc(58px * var(--go-scale)); }
  .go-badge-fallback { font-size: calc(26px * var(--go-scale)); }
  .go-reason    { font-size: var(--fs-10);
                  padding: calc(2px * var(--go-space)) calc(9px * var(--go-space)); }
  .go-title     { font-size: var(--fs-22); }
  .go-acts      { gap: calc(5px * var(--go-space)); margin-top: 0; }
  .btn-rv       { font-size: var(--fs-13);
                  padding: calc(8px * var(--go-space)) calc(12px * var(--go-space));
                  border-radius: calc(13px * var(--go-scale)); }
  .go-foot      { padding-top: calc(4px * var(--go-space)); gap: calc(5px * var(--go-space)); }
  .go-foot::before { margin-bottom: calc(2px * var(--go-space)); }
  .btn-challenge { font-size: var(--fs-11);
                  padding: calc(6px * var(--go-space)) calc(8px * var(--go-space)); }
  .go-nav       { font-size: var(--fs-13);
                  padding: calc(8px * var(--go-space)) calc(10px * var(--go-space));
                  border-radius: calc(13px * var(--go-scale)); }
  .go-duel      { padding: calc(5px * var(--go-space)) calc(6px * var(--go-space));
                  border-radius: calc(16px * var(--go-scale)); }
  .go-duel-row  { padding: calc(3px * var(--go-space)) calc(7px * var(--go-space));
                  gap: calc(6px * var(--go-space)); }
  .go-duel-ava  { width: calc(28px * var(--go-scale)); height: calc(28px * var(--go-scale)); }
  .go-duel-name { font-size: var(--fs-12-5); }
  .go-duel-score { font-size: var(--fs-16); }
  /* Идёт ПОСЛЕ .go-duel-score: та же специфичность, и без этой строки узкий экран
     раздул бы «сыграет позже» до размера счёта. */
  .go-duel-score--wait { font-size: var(--fs-10-5); }
  .go-duel-prize { font-size: var(--fs-11);
                  padding: calc(2px * var(--go-space)) calc(11px * var(--go-space)); }
  .go-duel-h2h  { font-size: var(--fs-10-5); }
  .go-duel-hint { font-size: var(--fs-10); }
}

/* Телефон в альбомной: карточка итога занимает всего треть высоты экрана (замер —
   134 px из 312 на 750×312), а --ui-scale там 0.62–0.84, и эмблема, заголовок и
   кнопки читаются мелко. Свободного места по высоте много, поэтому весь экран
   итога держим на четверть крупнее общего масштаба: и размеры (--go-scale), и
   промежутки (--go-space) — пропорции карточки при этом не едут.

   Больше 1.25 не берём из-за САМОЙ ВЫСОКОЙ карточки — итога дуэли с другом (там
   ещё табло на две строки): с этим множителем она выходит 215 px из 312 и 304 px
   из 480, то есть две трети экрана, а выше уже упрётся в края. */
@media (max-height: 499px) and (orientation: landscape) {
  .game-over {
    --go-scale: calc(var(--ui-scale) * 1.25);
    --go-space: calc(var(--ui-space) * 1.25);
  }
}

/* ─── New layout: sidebar + main ────────────────────────── */
.menu-layout {
  display: flex;
  flex-direction: row;
  width: 100%;
  flex: 1;
  min-height: 0;
  align-items: stretch;
  gap: 0;
}

/* Left sidebar */
.menu-sidebar {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-evenly;
  gap: 0px;
  padding: calc(10px * var(--ui-space)) calc(8px * var(--ui-space)) calc(10px * var(--ui-space)) calc(14px * var(--ui-space));
  width: max(calc(96px * var(--ui-scale)), 60px);
  flex-shrink: 0;
  background: none;
  border-right: none;
  /* Бейджи (.nav-badge) торчат за края кнопок, пульсируют и отбрасывают тень —
     обрезка по колонке срезала бы их. */
  overflow: visible;
  position: relative;
  z-index: 3;              /* поверх .menu-main, иначе бейдж уходит под неё */
  /* Fill the full height of the layout so buttons auto-distribute */
  align-self: stretch;
}

/* Carved figure nav button */
.nav-fig {
  position: relative;
  /* Stretch to fill available column height equally; shrink on small screens */
  flex: 1 1 0;
  min-height: 0;
  min-width: 0;
  /* Cap at natural size on large screens */
  max-height: calc(68px * var(--ui-scale));
  /* Square: width tracks the sidebar inner width */
  width: 100%;
  aspect-ratio: 1 / 1;
  border: none;
  background: none;
  cursor: pointer;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.14s, filter 0.14s;
  filter: drop-shadow(0 2px 6px rgba(155,111,200,0.35));
}

.nav-fig:hover {
  transform: scale(1.1);
  filter: drop-shadow(0 4px 10px rgba(155,111,200,0.55));
}

.nav-fig:active {
  transform: scale(0.93);
}

/* СТОЛБЕЦ БЕЗ «ДРУГИХ ПРОЕКТОВ» — шесть кнопок вместо семи.
   Седьмую кнопку включает флажок в БД (remote_config.other_projects_enabled,
   см. systems/ProjectsService.js), и «выключена» здесь значит не «оставила
   дыру»: .nav-fig и так flex:1 1 0 внутри space-evenly, то есть оставшиеся
   разъезжаются по высоте сами. Держит их от роста ОДИН потолок max-height — он
   тут и поднят, иначе шесть кнопок остались бы прежнего размера, а освободившаяся
   высота ушла бы в промежутки между ними. 79px — это прежние 68 × 7 / 6: доля
   седьмой кнопки, поделённая между шестью оставшимися. */
.menu-sidebar--noprojects .nav-fig {
  max-height: calc(79px * var(--ui-scale));
}

/* Fallback emoji sits behind the image; shows through when image errors */
.nav-fig-fallback {
  position: absolute;
  font-size: calc(26px * var(--ui-scale));
  line-height: 1;
  pointer-events: none;
  z-index: 0;
}

.nav-fig-img {
  position: relative;
  z-index: 1;
}

/* ─── Right-side quick buttons (profile + friends), under the currency stats ──
   Absolutely positioned inside .menu-main so they overlay the empty right area
   and never affect the vertical centring of the play block. Same visual size as
   the left sidebar buttons (which cap at 68px * --ui-scale). */
.menu-rightnav {
  position: absolute;
  top: calc(62px * var(--ui-scale));
  right: calc(16px * var(--ui-space));
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(18px * var(--ui-space));
}
.menu-rightnav .nav-fig {
  flex: 0 0 auto;
  width: calc(64px * var(--ui-scale));
  height: calc(64px * var(--ui-scale));
  max-height: none;
}
/* Профиль — это «я» пользователя, главный элемент группы: делаем его
   заметно, но органично крупнее кнопки «Друзья» (визуальная иерархия). */
.menu-rightnav #btn-profile {
  width: calc(80px * var(--ui-scale));
  height: calc(80px * var(--ui-scale));
}
/* «Лототрон» — единственный вытянутый арт в колонке (320×547 против квадратных
   у соседей). В общей рамке 64×64 он вписывается ПО ВЫСОТЕ, и автомат выходит
   вдвое уже соседей — рядом с ними он читался как значок поменьше, хотя кнопка
   такая же. Поэтому рамке дана своя высота: автомат встаёт вровень с соседними
   значками по весу, а колонка остаётся прежней ширины. */
.menu-rightnav .nav-fig-lottery {
  width: calc(64px * var(--ui-scale));
  height: calc(100px * var(--ui-scale));
}
/* СВЕТЛАЯ ПОДСВЕТКА автомата: колонка стоит на пастельном фоне меню, и лиловая
   тень остальных кнопок автомат только притапливает — а это единственная кнопка
   меню, которая обещает выигрыш, и звать она должна светом.

   Свечение висит на КАРТИНКЕ, а не на кнопке: у .nav-fig своё drop-shadow, и
   :hover его целиком перебивает — ореол пропадал бы ровно в тот миг, когда
   игрок наводит. Фильтр родителя ложится на потомка сверху, поэтому обе тени
   складываются сами, без повторов.

   СВЕТ РАЗМЫТЫЙ, БЕЗ КРОМКИ. Сперва первым слоем стоял почти непрозрачный белый
   в 3px — на таком радиусе он ложился по контуру автомата ровной ниткой, и
   подсветка читалась обводкой, наклеенной поверх арта, а не светом вокруг него.
   Поэтому тесного слоя нет вовсе, а два широких заодно убавлены (0.85 → 0.62 и
   0.55 → 0.46): у самой фигуры свет слабый, гаснет он плавно, и контур автомата
   не обводит. Замер на фоне меню: лавандовый (205,185,230) у края фигуры
   становится (224,202,221) — свет виден, ниткой не читается.

   Потом яркость дважды попросили поднять на 5%: 0.62/0.46 → 0.64/0.475 (+5.1%) и
   0.64/0.475 → 0.66/0.49 (+5.3%). Шаги мерены, а не на глаз: свет считается
   суммой подъёма яркости по всему ореолу — снимок кнопки с фильтром против
   снимка без него. Прямой пропорции тут нет, слои складываются: множитель 1.05
   на обе альфы дал бы сразу +7.5%, а нужный шаг — примерно 1.033. Радиусы не
   трогаем: blur округляется до целого пикселя, и шаг в 5% ими не отмерить
   (см. ту же заметку у .gift-glow--premium).

   Радиус нарочно скромный (до 13px * --ui-scale): колонка отстоит от правого
   края .menu-main на 16px, а у той overflow-y: auto — ореол пошире срезался бы
   краем или поднял горизонтальную прокрутку. Цвет — тёплый белый в жёлтый: тот
   же свет, что у подарка от игры (.gift-glow--gold), только бледнее. */
.menu-rightnav .nav-fig-lottery .nav-fig-img {
  filter:
    drop-shadow(0 0 calc(7px * var(--ui-scale)) rgba(255,252,242,0.66))
    drop-shadow(0 0 calc(13px * var(--ui-scale)) rgba(255,232,178,0.49));
  transition: filter 0.14s;
}
/* Наведение только прибавляет свету — кнопка отзывается тем же, чем и светится.
   Прибавка идёт плотностью, а не радиусом: подросший радиус на наведении читался
   бы скачком размера, а не откликом. */
.menu-rightnav .nav-fig-lottery:hover .nav-fig-img {
  filter:
    drop-shadow(0 0 calc(7px * var(--ui-scale)) rgba(255,252,242,0.86))
    drop-shadow(0 0 calc(13px * var(--ui-scale)) rgba(255,232,178,0.63));
  /* Наведение подрагивание гасит: игрок уже смотрит на кнопку, звать больше
     некуда, а тряска под курсором мешает отклику на сам курсор. Покой у
     подрагивания — это identity-трансформация, поэтому снятие анимации
     возвращает автомат ровно туда, где он стоит. */
  animation: none;
}

/* ПОДРАГИВАНИЕ АВТОМАТА С ПЕРЕРЫВОМ. Кнопка обещает выигрыш, и одного света ей
   мало: неподвижный ореол глаз перестаёт замечать через полминуты в меню.
   Поэтому раз в 5 секунд автомат коротко трясёт — как настоящий, когда внутри
   крутятся барабаны.

   ДВИЖЕНИЕ ЖИВЁТ НА КАРТИНКЕ, А НЕ НА КНОПКЕ. У .nav-fig свои transform на
   :hover (scale 1.1) и :active (scale 0.93); анимация перебивает обычные
   объявления, так что тряска на кнопке отняла бы у неё отклик на нажатие.
   Внутри кнопка масштабируется, картинка внутри неё качается — не мешают.

   ТРЯСКА — МЕЛКАЯ, ЗАТУХАЮЩАЯ И КОРОТКАЯ: 0.6 с движения на 5 с цикла (первые
   12% кадров), дальше автомат стоит. Размах убывает 3% → 0.3%, поворот 2° → 0.2°.

   Размах вдвое меньше первого захода (было 6% и 4°): крупное качание читалось
   не дрожью автомата, а тем, что кнопка отваливается от колонки. Взамен взято
   ЧИСЛО колебаний — девять полуразмахов вместо семи, шаг 1.2% цикла (60 мс,
   ≈8 Гц). Мелко и часто — это вибрация; крупно и редко — это качели.

   Сдвиг задан в процентах — так он сам следует за --ui-scale, отдельного calc()
   не нужно.

   Точка вращения — низ: автомат стоит на ножках, качаться он должен вокруг них,
   а не вокруг середины корпуса (иначе картинка «плавает» в воздухе).

   Задержка в 3 с — чтобы первый толчок не пришёлся на выезд меню: на входе
   экран и так движется, и тряска в этот миг читалась бы сбоем анимации. */
@keyframes nav-lottery-buzz {
  0%, 12%, 100% { transform: translateX(0) rotate(0deg); }
  1.2%          { transform: translateX(-3%) rotate(-2deg); }
  2.4%          { transform: translateX(2.6%) rotate(1.7deg); }
  3.6%          { transform: translateX(-2.2%) rotate(-1.4deg); }
  4.8%          { transform: translateX(1.8%) rotate(1.2deg); }
  6%            { transform: translateX(-1.5%) rotate(-1deg); }
  7.2%          { transform: translateX(1.2%) rotate(0.8deg); }
  8.4%          { transform: translateX(-0.9%) rotate(-0.6deg); }
  9.6%          { transform: translateX(0.6%) rotate(0.4deg); }
  10.8%         { transform: translateX(-0.3%) rotate(-0.2deg); }
}
.menu-rightnav .nav-fig-lottery .nav-fig-img {
  transform-origin: 50% 100%;
  animation: nav-lottery-buzz 5s ease-in-out 3s infinite;
}

@media (prefers-reduced-motion: reduce) {
  .menu-rightnav .nav-fig-lottery .nav-fig-img { animation: none; }
}

/* Badge on nav buttons */
.nav-badge {
  top: calc(-6px * var(--ui-scale));
  right: calc(-6px * var(--ui-scale));
  /* Квадрат с закруглёнными краями, цифры по центру */
  min-width: calc(20px * var(--ui-scale));
  height: calc(20px * var(--ui-scale));
  padding: 0 calc(4px * var(--ui-scale));
  border-radius: calc(7px * var(--ui-scale));
  background: linear-gradient(135deg, #ff5a4e, #c11414);
  font-size: var(--fs-11);
  text-align: center;
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(193,20,20,0.5);
  animation: badge-pulse 1s ease-in-out infinite;
}

@keyframes badge-pulse {
  0%, 100% { transform: scale(1); }
  50%       { transform: scale(1.18); }
}

/* Индикатор «новые лоты» на кнопке «Магазин»: «!» слева сверху (не путать со
   счётчиком бустеров справа), пока игрок не посмотрит новинки. */
.nav-new-dot {
  top: calc(-6px * var(--ui-scale));
  left: calc(-6px * var(--ui-scale));
  width: calc(20px * var(--ui-scale));
  height: calc(20px * var(--ui-scale));
  border-radius: calc(7px * var(--ui-scale));
  background: linear-gradient(135deg, #ff5a4e, #c11414);
  font-size: var(--fs-12);
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(193,20,20,0.5);
  pointer-events: none;
  animation: badge-pulse 1s ease-in-out infinite;
}

/* Main content area */
.menu-main {
  flex: 1;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  overflow-y: auto;
  padding: 0 calc(16px * var(--ui-space)) calc(24px * var(--ui-space));
  gap: calc(12px * var(--ui-space));
}

/* Play block (lives + modes + hint) — fills the FULL height of the content
   area and centres its contents. The top row (logo + stats) is taken out of
   flow (see .menu-toprow below), so the block sits at the true centre and the
   logo image is never counted — its (late) load can't shift the block. */
.menu-play {
  flex: 1;
  min-height: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(12px * var(--ui-space));
  /* Логотип лежит АБСОЛЮТОМ поверх (.menu-toprow, z-index 2) и в поток не входит,
     поэтому центрируемый блок обязан сам зарезервировать его высоту. Раньше вместо
     этого стоял transform: translateY(-5vh) — на невысоких ландшафтах (≈450–650 px)
     он затягивал строку жизней ПОД логотип, и «5/5» просто пропадали. Резерв —
     отступ логотипа сверху (36px) плюс его высота (112px) в масштабе интерфейса. */
  padding-top: calc(148px * var(--ui-scale));
}

@media (max-height: 449px) and (orientation: landscape) {
  .menu-play {
    flex: 1;
    justify-content: center;
    gap: calc(8px * var(--ui-space));
    /* Здесь логотип уже в потоке (.menu-toprow position:relative), резерв не нужен. */
    padding-top: 0;
  }
  .menu-main {
    justify-content: space-evenly;
    overflow-y: hidden;
    padding: 0 calc(10px * var(--ui-space)) 0;
    gap: 0;
  }
}

/* ─── Top row: logo + stats wrapper ─────────────────────── */
/* Overlaid at the top and taken out of flow so it never affects the vertical
   centring of the play block (the logo image can load late without shifting
   anything). Short landscape re-enables in-flow layout below. */
.menu-toprow {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2;
}

/* On wide landscape (≥450px height): stats pinned top-right, logo below stats row */
@media (min-height: 450px) and (orientation: landscape) {
  .menu-toprow {
    flex-direction: column;
    align-items: center;
  }
  /* .main-menu — иначе базовое .menu-topbar { width: 100% } ниже по файлу
     перебивает width:auto, и абсолютная полоска шириной во весь экран висит
     на 28px левее вьюпорта (пустым краем поверх шапки меню). */
  .main-menu .menu-topbar {
    position: absolute;
    top: 0;
    right: calc(28px * var(--ui-scale));
    width: auto;
    padding: 6px 0 4px;
    justify-content: flex-end;
  }
  .menu-logo-toprow {
    margin-top: calc(36px * var(--ui-scale));
    margin-bottom: 0;
  }
}

/* On narrow landscape: logo centered, stats pinned right in same row */
@media (max-height: 449px) and (orientation: landscape) {
  .menu-toprow {
    /* Only the width is ever set on the image, so the 935×328 aspect ratio is
       kept. 2.85 = 935/328, so the 15vh term caps the rendered height. */
    --menu-logo-w: min(60vw, calc(320px * var(--ui-scale)), calc(15vh * 2.85));
    flex-direction: row;
    align-items: center;
    position: relative;
    gap: 0;
  }
  .menu-logo-toprow {
    position: absolute;
    top: calc(10px * var(--ui-space));
    left: 50%;
    transform: translateX(-50%);
    margin-bottom: 0;
    pointer-events: none;
  }
  .menu-logo-toprow .menu-logo-img {
    width: var(--menu-logo-w);
    max-width: none;
    height: auto;
  }
  .menu-topbar {
    margin-left: auto;
    margin-right: calc(16px * var(--ui-space));
    width: auto;
    justify-content: flex-end;
  }
}

/* ─── Top bar: stats right only ─────────────────────────── */
.menu-topbar {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 10px calc(16px * var(--ui-space)) 4px 0;
  gap: 8px;
}

@media (max-height: 449px) and (orientation: landscape) {
  .menu-topbar {
    padding: 2px 0 2px;
  }
}

/* ─── Lives block: under logo, centered ──────────────────── */
.menu-lives-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  margin-bottom: 6px;
}

.menu-lives-row {
  display: flex;
  align-items: center;
  gap: 6px;
}

.menu-lives-icon {
  width: calc(40px * var(--ui-scale));
  height: calc(40px * var(--ui-scale));
}

.menu-lives-count {
  font-size: var(--fs-22);
  font-weight: 700;
  color: #c0405a;
}

.menu-lives-timer {
  font-size: var(--fs-12);
  color: rgba(42,26,64,0.45);
}

.menu-topbar-stats {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

.menu-stat {
  display: flex;
  align-items: center;
  gap: 3px;
}

.menu-stat-img {
  width: calc(40px * var(--ui-scale));
  height: calc(40px * var(--ui-scale));
  object-fit: contain;
  flex-shrink: 0;
}

.menu-stat-val {
  font-size: var(--fs-18);
  font-weight: 700;
  color: #2a1a40;
}

/* Ранг вместо уровня в верхней панели — имя ранга чуть мельче, чтобы влезало */

.menu-stat-coins .menu-stat-val { color: #c8860a; }
.menu-stat-crystals .menu-stat-val { color: #d03888; }


/* ─── Quests Panel — «Ежедневные» и «Заказы» ─────────────── */
/* Палитра окна — палитра игры (та же, что у .screen): пастельный голубой → сирень →
   розовый, карточки цвета сливок, акценты — оранжевый и жёлтый, «голографический»
   блик как на арте с девочкой. Ничего синего-«чужого» здесь больше нет.
   Шапка (заголовок + крестик) взята из магазина: те же .sp2-topbar/.sp2-close-btn,
   только вместо счётчиков валют — переключатель вкладок. */
.quests-panel {
  padding: 0;
  gap: 0;
  overflow: hidden;
}

/* Общие цвета шкалы с подарками — правятся в одном месте.
   Классами .qb-track/.qb-chest/.qb-gift рисуются ТРИ места: недельная шкала
   заданий, шкала акции «Пригласи друзей» на странице «Друзья» и окошко «что
   внутри» в окне ежедневного бонуса. Поэтому палитра объявлена сразу на всех
   трёх хозяевах — иначе var(--qb-…) там просто не подставится, и текст молча
   уедет в унаследованный цвет (так и случилось с подписью окошка в бонусе:
   заявленный --qb-ink не разрешался, и она красилась чернилами body). */
.quests-panel,
.friends-panel,
.db-overlay {
  --qb-ink:        #4a2d62;   /* основной текст (тёмно-сиреневый) */
  --qb-ink-soft:   #6b4a8e;   /* второстепенный текст */
  --qb-accent:     #e07020;   /* оранжевый акцент (числа, таймеры) */
  --qb-lilac:      #9b6fc8;   /* сиреневый — рамки, тени */
  --qb-card:       #fff6e6;   /* сливочная карточка задания */
  --qb-card-edge:  #ffe2b8;
  --qb-holo: linear-gradient(135deg, #bfe6f5 0%, #d9c9f0 34%, #f6c9e0 66%, #ffe6a8 100%);
}

.qb-layout {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  overflow: hidden;
  padding: 0 calc(12px * var(--ui-space)) calc(10px * var(--ui-space)) calc(28px * var(--ui-space));
  box-sizing: border-box;
}

/* ── Вкладки: своя строка под шапкой ── */
.qb-tabs {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(8px * var(--ui-space));
  flex-shrink: 0;
  padding: 0 calc(14px * var(--ui-space)) calc(12px * var(--ui-space));
}

/* Вкладок в шапке больше нет — крестик сам отходит к правому краю. */
.quests-panel .sp2-close-btn { margin-left: auto; }

/* Те же вкладки, что в почте (.mail-tab): сиренево-розовая пара — цвет игры. */
.qb-tab {
  min-height: calc(52px * var(--ui-scale));
  padding: 0 calc(26px * var(--ui-space));
  font-size: var(--fs-17);
  font-weight: 800;
  color: #7b3fbe;
  background: linear-gradient(160deg, #ffffff, #f7edff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.3);
  border-radius: 50px;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: 0 2px 8px rgba(155,111,200,0.15);
  transition: transform 0.12s, background 0.15s, color 0.15s, box-shadow 0.15s;
}

.qb-tab:hover  { transform: translateY(-2px); box-shadow: 0 5px 14px rgba(155,111,200,0.28); }
.qb-tab:active { transform: scale(0.96); }

.qb-tab-active {
  color: #fff;
  background: linear-gradient(135deg, #b06fd8, #d873ac);
  border-color: #b06fd8;
  box-shadow: 0 5px 16px rgba(176,111,216,0.45);
}

.qb-content {
  flex: 1;
  /* min-height:0 обязателен: у flex-элемента min-height по умолчанию = auto, поэтому
     колонка карточек не давала .qb-content сжаться, он перерастал .qb-layout
     (overflow:hidden) и на низком ландшафте нижний ряд заданий обрезался вместе с
     кнопками «Забрать» — прокрутка при этом не появлялась. */
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: calc(8px * var(--ui-space));
}

.qb-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: calc(40px * var(--ui-space));
  font-size: var(--fs-17);
  font-weight: 700;
  color: var(--qb-ink-soft);
  text-align: center;
}

/* ── Баннер недели: подсказка, таймер и шкала очков ──
   Голографический пастельный градиент с арта; текст тёмно-сиреневый, а не белый. */
.qb-banner {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(8px * var(--ui-space));
  padding: calc(14px * var(--ui-space)) calc(18px * var(--ui-space));
  border-radius: calc(24px * var(--ui-scale));
  background: var(--qb-holo);
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.8);
  box-shadow: inset 0 2px 0 rgba(255,255,255,0.75), 0 8px 22px rgba(155,111,200,0.28);
}

.qb-banner-timer {
  font-size: var(--fs-16);
  font-weight: 800;
  color: var(--qb-ink-soft);
  text-shadow: 0 1px 0 rgba(255,255,255,0.7);
}

.qb-banner-timer b { color: var(--qb-accent); }

/* ── Шкала очков недели ──
   Подарки лежат ПОВЕРХ полосы: полоса проходит у них по середине и уходит за
   подарок (он её перекрывает), порог — под полосой. Все подарки центрируются в
   слоте .qb-chest-art одной высоты, поэтому середина у большого подарка недели и
   у обычных — на одной линии. Геометрию всей шкалы задают две величины ниже. */
.qb-track {
  --qb-art-h:  calc(74px * var(--ui-scale));   /* слот подарка: по самому большому */
  --qb-line-h: calc(26px * var(--ui-scale));   /* толщина полосы */
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: calc(10px * var(--ui-space));
  width: 100%;
  padding: calc(6px * var(--ui-space)) 0;
}

/* Счётчик очков — по центру полосы, а не по центру всей шкалы с подарками. */
.qb-track-points {
  display: flex;
  align-items: center;
  gap: calc(6px * var(--ui-space));
  flex-shrink: 0;
  margin-top: calc(var(--qb-art-h) / 2);
  transform: translateY(-50%);
}

.qb-track-points .qb-reward {
  background: rgba(255,255,255,0.75);
  border-color: rgba(255,255,255,0.9);
  padding: calc(4px * var(--ui-space)) calc(10px * var(--ui-space));
}

.qb-track-points .qb-reward-val { font-size: var(--fs-17); }

/* Очко шкалы: картинка assets/quests/icon-points.png, а пока её нет — кружок из CSS. */
.qb-point-ico {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: calc(22px * var(--ui-scale));
  height: calc(22px * var(--ui-scale));
  flex-shrink: 0;
}

.qb-point-fb {
  display: none;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: linear-gradient(160deg, #ff9a5a, #e2542a);
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.9);
  box-shadow: 0 2px 6px rgba(226,84,42,0.4);
  box-sizing: border-box;
}

.qb-point-fb::after {
  content: '✔';
  font-size: var(--fs-11);
  font-weight: 900;
  color: #fff;
  line-height: 1;
}

.qb-point-ico-lg { width: calc(34px * var(--ui-scale)); height: calc(34px * var(--ui-scale)); }
.qb-point-ico-lg .qb-point-fb::after { font-size: var(--fs-17); }

/* Полоса и ряд подарков живут в общем блоке — полоса тянется по всей его ширине. */
.qb-track-bar {
  position: relative;
  flex: 1;
  min-width: 0;
  margin-right: calc(10px * var(--ui-space));
}

.qb-track-line {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--qb-art-h) / 2 - var(--qb-line-h) / 2);   /* по середине подарков */
  height: var(--qb-line-h);
  border-radius: 50px;
  background: rgba(255,255,255,0.7);
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.9);
  box-shadow: inset 0 2px 5px rgba(120,90,160,0.25);
  overflow: hidden;
  z-index: 0;
}

.qb-track-fill {
  height: 100%;
  border-radius: 50px;
  background: linear-gradient(90deg, #ffd166, var(--qb-accent));
  box-shadow: 0 0 10px rgba(255,180,90,0.7);
  transition: width 0.4s ease;
}

.qb-chests {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;   /* последний подарок — впритык к концу полосы */
  padding-left: 7%;   /* первый подарок с заметным отступом от начала полосы (в %, масштабируется с шириной) */
  z-index: 1;
}

/* Подарок на пороге: клик открывает окошко с содержимым — забрать можно оттуда.
   --qb-img — размер картинки этого подарка; по нему же ставится галочка «забрано». */
.qb-chest {
  --qb-img: calc(52px * var(--ui-scale));
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  filter: none;                     /* подарки сразу своего цвета, не бледные */
  transition: transform 0.15s, filter 0.2s;
}

.qb-chest-final { --qb-img: calc(70px * var(--ui-scale)); }

.qb-chest:hover  { transform: scale(1.08); }
.qb-chest:active { transform: scale(0.94); }

/* Слот одной высоты для всех подарков: картинка по центру — там же проходит полоса. */
.qb-chest-art {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--qb-art-h);
}

.qb-chest-img   { width: var(--qb-img); height: var(--qb-img); object-fit: contain; display: block; }
.qb-chest-emoji { font-size: calc(var(--qb-img) * 0.74); line-height: 1; }

/* Порог — под полосой. */
.qb-chest-val {
  margin-top: calc(2px * var(--ui-scale));
  font-size: var(--fs-15);
  font-weight: 900;
  color: var(--qb-ink);
  text-shadow: 0 1px 0 rgba(255,255,255,0.8);
}

/* Порог взят, подарок ещё не забран — он НЕМНОГО ДРОЖИТ и ТЁПЛО СВЕТИТСЯ:
   дрожь и свечение и есть «его можно забрать» (порог под полосой при этом стоит на месте).
   Дрожит и светится сама картинка (drop-shadow по её контуру), а не прямоугольник кнопки. */
.qb-chest-ready { filter: none; }
.qb-chest-ready .qb-chest-art {
  animation: qb-chest-shake 1.6s ease-in-out infinite,
             qb-chest-glow  1.8s ease-in-out infinite;
}

@keyframes qb-chest-glow {
  0%, 100% { filter: drop-shadow(0 0 calc(4px  * var(--ui-scale)) rgba(255,190,90,0.55)); }
  50%      { filter: drop-shadow(0 0 calc(12px * var(--ui-scale)) rgba(255,205,110,0.95)); }
}

/* Подарок забран — он остаётся таким же, как обычный: полный цвет, без затемнения
   и без галочки. Просто перестаёт дрожать и светиться (класс qb-chest-ready на
   забранный подарок уже не вешают). */
.qb-chest-claimed { filter: none; opacity: 1; }

/* «Немного дрожит»: короткая дрожь в начале цикла, потом покой — подарок будто
   просится, чтобы его забрали, но не мельтешит без остановки. */
@keyframes qb-chest-shake {
  0%, 24%, 100% { transform: translateX(0) rotate(0deg); }
  4%  { transform: translateX(calc(-2px * var(--ui-scale))) rotate(-5deg); }
  8%  { transform: translateX(calc( 2px * var(--ui-scale))) rotate( 5deg); }
  12% { transform: translateX(calc(-2px * var(--ui-scale))) rotate(-4deg); }
  16% { transform: translateX(calc( 2px * var(--ui-scale))) rotate( 4deg); }
  20% { transform: translateX(calc(-1px * var(--ui-scale))) rotate(-2deg); }
}

/* ── Окошко «что внутри подарка» ──
   Тот же приём, что у призов в рейтинге (.lb-prize): карточка с хвостиком,
   позиционируется в координатах баннера. Здесь она висит ПОД подарком. */
.qb-gift {
  position: absolute;
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(6px * var(--ui-space));
  box-sizing: border-box;
  padding: calc(9px * var(--ui-space)) calc(13px * var(--ui-space));
  background: linear-gradient(180deg, #fffdff, #fdf1fa);
  border: calc(2px * var(--ui-scale)) solid #fff;
  border-radius: calc(16px * var(--ui-scale));
  box-shadow: 0 8px 20px rgba(120,90,160,0.34), inset 0 1px 0 rgba(255,255,255,0.85);
  white-space: nowrap;
  animation: qb-gift-in 0.14s ease-out;
}

.qb-gift-off { opacity: 0.85; }

@keyframes qb-gift-in {
  from { opacity: 0; transform: translateY(calc(-4px * var(--ui-scale))); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Хвостик смотрит вверх, в подарок. */
.qb-gift::after {
  content: '';
  position: absolute;
  left: var(--qb-gift-arrow, 50%);
  bottom: 100%;
  width: 0;
  height: 0;
  margin-left: calc(-6px * var(--ui-scale));
  border: calc(6px * var(--ui-scale)) solid transparent;
  border-bottom-color: #fff;
}

/* Окошко над подарком — так оно встаёт у нижнего ряда сетки ежедневного бонуса,
   где снизу места нет (см. place() в ui/lib/giftPopup.js). Хвостик переезжает
   под карточку и смотрит вниз. */
.qb-gift--above::after {
  bottom: auto;
  top: 100%;
  border-bottom-color: transparent;
  border-top-color: #fdf1fa;   /* нижний край карточки — конец её градиента */
}

/* Заголовок и нижняя подпись окошка держатся на ТЁМНОМ конце палитры, а не на
   сиреневом: карточка окошка почти белая (#fffdff → #fdf1fa), и прежний
   --qb-lilac (#9b6fc8) на ней еле проступал — светлый текст по светлому фону.
   Заголовок берёт тот же густой фиолетовый, что заголовки окон игры, подпись —
   основной текстовый --qb-ink вместо приглушённого --qb-ink-soft. Середина
   (значки с числами) и без того тёмная, её не трогаем. */
.qb-gift-title {
  font-size: var(--fs-13);
  font-weight: 900;
  letter-spacing: 0.02em;
  color: #7b3fbe;
}

.qb-gift-items {
  display: flex;
  align-items: center;
  gap: calc(12px * var(--ui-space));
}

.qb-gift-item {
  display: inline-flex;
  align-items: center;
  gap: calc(4px * var(--ui-space));
}

.qb-gift-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: calc(26px * var(--ui-scale));
  height: calc(26px * var(--ui-scale));
}

.qb-gift-val {
  font-size: var(--fs-16);
  font-weight: 900;
  color: #2a1a40;
  font-variant-numeric: tabular-nums;
}

.qb-gift-btn {
  min-height: calc(34px * var(--ui-scale));
  padding: 0 calc(20px * var(--ui-space));
  font-size: var(--fs-14);
  font-weight: 900;
  color: #fff;
  background: linear-gradient(135deg, #ffb347, var(--qb-accent));
  border: none;
  border-radius: 50px;
  cursor: pointer;
  box-shadow: 0 4px 12px rgba(224,112,32,0.45);
  transition: transform 0.12s, filter 0.15s;
}

.qb-gift-btn:hover    { transform: translateY(-1px); }
.qb-gift-btn:active   { transform: scale(0.95); }
.qb-gift-btn:disabled { opacity: 0.6; cursor: default; transform: none; }

.qb-gift-note {
  font-size: var(--fs-12);
  font-weight: 800;
  color: var(--qb-ink);
}

.qb-gift-note-done { color: #e0850f; }

/* Обе вкладки живут в колонке ограниченной ширины по центру окна: на широком
   экране карточки не растягиваются во всю ширину, а шкала недели стоит ровно
   над ними. Узкое окно — колонка просто ужимается. */
.qb-daily,
.qb-orders {
  width: 100%;
  max-width: calc(1080px * var(--ui-scale));
  margin: 0 auto;
}

/* Подсказка над сеткой испытаний: .qb-content — обычный поток, поэтому зазор до
   сетки строка держит сама. */
.qb-content .qb-note { margin: 0 auto calc(10px * var(--ui-space)); }

/* ── Карточки ежедневных заданий ── */
.qb-daily {
  display: flex;
  flex-direction: column;
  gap: calc(12px * var(--ui-space));
  padding-bottom: calc(6px * var(--ui-space));
}

/* Карточка дня «лежачая», как цель испытания (.qb-goal): крупная картинка слева, всё
   про задание — справа, в колонку. Поэтому в ряду их две, а не четыре: в четвертинке
   окна такой карточке тесно, картинке пришлось бы съёжиться обратно. */
.qb-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(12px * var(--ui-space));
}

.qb-card {
  position: relative;
  display: flex;
  align-items: center;
  gap: calc(14px * var(--ui-space));
  padding: calc(12px * var(--ui-space));
  background: linear-gradient(180deg, #fffaf0, var(--qb-card));
  border: calc(2px * var(--ui-scale)) solid var(--qb-card-edge);
  border-radius: calc(20px * var(--ui-scale));
  box-shadow: 0 6px 16px rgba(155,111,200,0.2), inset 0 1px 0 rgba(255,255,255,0.9);
  transition: transform 0.15s, box-shadow 0.2s;
}

.qb-card-done {
  border-color: #ffc46b;
  box-shadow: 0 8px 20px rgba(224,112,32,0.3), 0 0 0 calc(2px * var(--ui-scale)) rgba(255,196,107,0.6);
}

.qb-card-art {
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(104px * var(--ui-scale));
  height: calc(104px * var(--ui-scale));
  flex-shrink: 0;
}

.qb-card-img   { border-radius: calc(16px * var(--ui-scale)); }
.qb-card-emoji { font-size: calc(64px * var(--ui-scale)); line-height: 1; }

.qb-card-body {
  display: flex;
  flex-direction: column;
  gap: calc(8px * var(--ui-space));
  flex: 1;
  min-width: 0;
}

.qb-card-title {
  font-size: var(--fs-16);
  font-weight: 900;
  color: var(--qb-ink-soft);
  line-height: 1.25;
}

.qb-card-progress {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(3px * var(--ui-space));
  width: 100%;
}

/* Шкала — «леденцовая», как у целей испытания (.qb-goal-bar): толстая, в белой
   кайме, с бликом поверх заливки. Толщину правят здесь и в --qb-line-h. */
.qb-progress-track {
  position: relative;
  width: 100%;
  height: calc(28px * var(--ui-scale));
  border-radius: 50px;
  background: rgba(155,111,200,0.2);
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.9);
  box-shadow: inset 0 2px 4px rgba(120,90,160,0.25);
  box-sizing: border-box;
  overflow: hidden;
}

/* Заливка — один градиент вдоль шкалы: слева направо, от светлого к тёмному. */
.qb-progress-fill {
  height: 100%;
  border-radius: 50px;
  background: linear-gradient(90deg, #d7b6f0, var(--qb-lilac));
  transition: width 0.4s ease;
}

.qb-progress-text {
  position: absolute;
  font-size: var(--fs-14);
  font-weight: 900;
  color: var(--qb-ink);
  line-height: calc(28px * var(--ui-scale));
  text-shadow: 0 1px 0 rgba(255,255,255,0.7);
}

/* Низ карточки дня: слева — что дадут, справа — кнопка «Забрать». */
.qb-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(10px * var(--ui-space));
  flex-wrap: wrap;
}

.qb-card-foot .qb-rewards-row { justify-content: flex-start; }

/* «Забрать» — ОДНА кнопка на всю страницу заданий: и на карточке дня, и на
   испытании (.qb-deliver-btn ниже добавляет только размер). Тёплая янтарная —
   под цвет игры (акцент --qb-accent), как кнопка подарка, в белой кайме, шириной
   по надписи — во всю ширину она читалась как полоса, а не как кнопка.
   Пульсирует: это и есть «награда ждёт, забери». */
.qb-claim-btn,
.qb-deliver-btn {
  align-self: center;
  max-width: 100%;
  min-height: calc(44px * var(--ui-scale));
  padding: 0 calc(24px * var(--ui-space));
  font-size: var(--fs-16);
  font-weight: 900;
  color: #fff;
  background: linear-gradient(180deg, #ffc266, #e0850f);
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.8);
  border-radius: calc(16px * var(--ui-scale));
  cursor: pointer;
  box-sizing: border-box;
  text-shadow: 0 2px 0 rgba(150,80,10,0.35);
  box-shadow: 0 5px 14px rgba(224,112,32,0.45), inset 0 2px 0 rgba(255,255,255,0.55);
  animation: qb-claim-pulse 1.2s ease-in-out infinite;
  transition: transform 0.12s, filter 0.15s;
}

.qb-claim-btn:hover,
.qb-deliver-btn:hover  { filter: brightness(1.05); }
.qb-claim-btn:active,
.qb-deliver-btn:active { transform: scale(0.95); }

@keyframes qb-claim-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}

.qb-rewards-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(10px * var(--ui-space));
  flex-wrap: wrap;
}

.qb-reward {
  display: inline-flex;
  align-items: center;
  gap: calc(4px * var(--ui-space));
  padding: calc(3px * var(--ui-space)) calc(8px * var(--ui-space));
  background: rgba(255,255,255,0.7);
  border: calc(1px * var(--ui-scale)) solid rgba(155,111,200,0.2);
  border-radius: 50px;
}

.qb-reward-icon { width: calc(22px * var(--ui-scale)); height: calc(22px * var(--ui-scale)); object-fit: contain; }
.qb-reward-val  { font-size: var(--fs-14); font-weight: 900; color: var(--qb-ink); }

/* Подвал — не плашка во всю ширину, а две плашки по содержимому, по центру.
   Оформление то же, что у вкладок и .mail-tab: белое с сиреневой каймой. */
.qb-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: calc(10px * var(--ui-space));
}

.qb-footer-chip {
  padding: calc(9px * var(--ui-space)) calc(20px * var(--ui-space));
  font-size: var(--fs-14);
  font-weight: 800;
  color: #7b3fbe;
  background: linear-gradient(160deg, #ffffff, #f7edff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.3);
  border-radius: 50px;
  box-shadow: 0 2px 8px rgba(155,111,200,0.15);
  white-space: nowrap;
}

.qb-footer b { color: var(--qb-accent); }

/* ── Вкладка «Испытания»: сетка 3×3 слева, карточка испытания справа ── */
/* Карточка испытания стоит по середине высоты сетки — align-items: center. */
.qb-orders {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: calc(14px * var(--ui-space));
  align-items: center;
  padding-bottom: calc(6px * var(--ui-space));
}

/* minmax(0, 1fr), а не 1fr: иначе клетку распирает её же подпись (она в одну строку),
   колонка не даёт себя ужать, и сетка вылезает за свою половину окна. */
.qb-order-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: calc(10px * var(--ui-space));
  /* Отступ внутри сетки: свечение и приподнятая при наведении клетка остаются внутри
     обрезающего .qb-content (overflow), а не срезаются его краем. box-sizing: border-box
     (глобально) — отступ ужимает клетки, а не распирает колонку. */
  padding: calc(16px * var(--ui-space));
}

.qb-order {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(4px * var(--ui-space));
  aspect-ratio: 1 / 1;
  padding: calc(8px * var(--ui-space));
  background: linear-gradient(180deg, #fffaf0, var(--qb-card));
  border: calc(2px * var(--ui-scale)) solid var(--qb-card-edge);
  border-radius: calc(18px * var(--ui-scale));
  box-shadow: 0 4px 12px rgba(155,111,200,0.18), inset 0 1px 0 rgba(255,255,255,0.9);
  cursor: pointer;
  transition: transform 0.15s, box-shadow 0.2s, border-color 0.2s;
}

.qb-order:hover  { transform: translateY(-2px); }
.qb-order:active { transform: scale(0.97); }

/* Выбранная клетка: мягкий сине-фиолетовый барвинок (перивинкль) из голографической
   гаммы игры — прохладный, не «девчачий», но насыщенный, поэтому читается на лаванде.
   Свечение в тот же тон, компактное — умещается в отступ .qb-order-grid и не срезается.
   z-index поднимает клетку, чтобы ореол лёг поверх соседей, а не спрятался. */
.qb-order-active {
  border-color: #7b6ce6;
  box-shadow:
    0 0 0 calc(1px * var(--ui-scale)) rgba(123,108,230,0.5),
    0 0 12px calc(2px * var(--ui-scale)) rgba(139,124,236,0.58),
    inset 0 1px 0 rgba(255,255,255,0.9);
  z-index: 1;
}

.qb-order-ready {
  border-color: #ffc46b;
  box-shadow: 0 6px 18px rgba(224,112,32,0.35), 0 0 0 calc(2px * var(--ui-scale)) rgba(255,196,107,0.7);
}

.qb-order-art {
  display: flex;
  align-items: center;
  justify-content: center;
  align-self: stretch;
  flex: 1;
  min-height: 0;
}

/* Скругление режет рамку самой картинки, поэтому <img> должна быть по размеру
   рисунка, а не слота: при width/height: 100% + object-fit: contain рисунок стоит
   с полями внутри бокса, и скругляются поля, а не его углы. */
.qb-order-img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: calc(14px * var(--ui-scale));
}
.qb-order-emoji { font-size: calc(40px * var(--ui-scale)); line-height: 1; }

.qb-order-name {
  font-size: var(--fs-12);
  font-weight: 900;
  color: var(--qb-ink-soft);
  text-align: center;
  line-height: 1.2;
  max-width: 100%;
}

/* Правая карточка — открытое испытание. */
.qb-order-detail {
  display: flex;
  flex-direction: column;
  gap: calc(12px * var(--ui-space));
  padding: calc(16px * var(--ui-space));
  background: linear-gradient(180deg, #fffaf0, var(--qb-card));
  border: calc(2px * var(--ui-scale)) solid var(--qb-card-edge);
  border-radius: calc(24px * var(--ui-scale));
  box-shadow: 0 6px 18px rgba(155,111,200,0.22), inset 0 1px 0 rgba(255,255,255,0.9);
}

.qb-order-title {
  font-size: var(--fs-19);
  font-weight: 900;
  color: var(--qb-ink);
  text-align: center;
  padding-bottom: calc(10px * var(--ui-space));
}

.qb-goals {
  display: flex;
  flex-direction: column;
  gap: calc(10px * var(--ui-space));
}

/* Цель испытания: крупная картинка в рамке, рядом название и жирная шкала. */
.qb-goal {
  display: flex;
  align-items: center;
  gap: calc(12px * var(--ui-space));
  padding: calc(10px * var(--ui-space));
  background: linear-gradient(180deg, #ffffff, #fdf7ff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.22);
  border-radius: calc(20px * var(--ui-scale));
  box-shadow: 0 3px 10px rgba(155,111,200,0.14), inset 0 1px 0 rgba(255,255,255,0.9);
}

.qb-goal-ok {
  background: linear-gradient(180deg, #fffaf0, #ffedcf);
  border-color: rgba(230,150,40,0.45);
  box-shadow: 0 3px 10px rgba(224,112,32,0.18), inset 0 1px 0 rgba(255,255,255,0.9);
}

.qb-goal-art {
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(58px * var(--ui-scale));
  height: calc(58px * var(--ui-scale));
  flex-shrink: 0;
  overflow: hidden;
  background: linear-gradient(160deg, #ffffff, #f4e9ff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.28);
  border-radius: calc(16px * var(--ui-scale));
  box-shadow: inset 0 2px 0 rgba(255,255,255,0.9), 0 2px 6px rgba(155,111,200,0.2);
}

.qb-goal-ok .qb-goal-art { border-color: rgba(230,150,40,0.45); }

.qb-goal-emoji { font-size: calc(34px * var(--ui-scale)); line-height: 1; }

.qb-goal-body {
  display: flex;
  flex-direction: column;
  gap: calc(6px * var(--ui-space));
  flex: 1;
  min-width: 0;
}

.qb-goal-title {
  font-size: var(--fs-15);
  font-weight: 900;
  color: var(--qb-ink-soft);
}

/* Шкала — «леденцовая»: толстая, в белой кайме, с бликом поверх заливки. */
.qb-goal-bar {
  height: calc(24px * var(--ui-scale));
  border-radius: 50px;
  background: rgba(155,111,200,0.2);
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.9);
  box-shadow: inset 0 2px 4px rgba(120,90,160,0.25);
  box-sizing: border-box;
  overflow: hidden;
}

/* Заливка — один градиент вдоль шкалы: слева направо, от светлого к тёмному. */
.qb-goal-fill {
  height: 100%;
  border-radius: 50px;
  background: linear-gradient(90deg, #d7b6f0, var(--qb-lilac));
  transition: width 0.4s ease;
}

.qb-goal-ok .qb-goal-bar  { background: rgba(224,112,32,0.2); }
.qb-goal-ok .qb-goal-fill { background: linear-gradient(90deg, #ffcf7a, #e0850f); }

/* Все шкалы одного испытания — одной длины. Раньше счётчик занимал столько, сколько
   занимало ЕГО число («0/8» и «0/12000» — разная ширина), и шкала рядом получалась то
   длиннее, то короче. Теперь ширину счётчика задаёт самое длинное число ЭТОГО испытания
   (--qb-count-ch ставит QuestsPanel#_renderOrders), одну на все его цели: цифры табличные,
   поэтому 1ch — ровно одна цифра, и колонка сходится точно по символам. */
.qb-goal-count {
  width: calc(var(--qb-count-ch, 9) * 1ch);
  text-align: right;
  font-size: var(--fs-17);
  font-weight: 900;
  color: var(--qb-ink);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
  white-space: nowrap;
}

.qb-goal-ok .qb-goal-count { color: #e0850f; }

.qb-order-rewards {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(6px * var(--ui-space));
  padding-top: calc(10px * var(--ui-space));
}

/* Награда испытания — плашки крупнее и выпуклее, чем у ежедневных заданий. */
.qb-order-rewards .qb-reward {
  gap: calc(6px * var(--ui-space));
  padding: calc(5px * var(--ui-space)) calc(12px * var(--ui-space));
  background: #fff;
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.22);
  box-shadow: 0 3px 8px rgba(155,111,200,0.16), inset 0 1px 0 rgba(255,255,255,0.9);
}

.qb-order-rewards .qb-reward-icon,
.qb-order-rewards .qb-point-ico {
  width: calc(28px * var(--ui-scale));
  height: calc(28px * var(--ui-scale));
}

.qb-order-rewards .qb-reward-val { font-size: var(--fs-16); }

/* Кнопка «Забрать» стоит РОВНО ПО ЦЕНТРУ карточки: три колонки, крайние одной
   ширины (1fr) — корзина слева, справа пустая колонка. Растянись кнопка на всю
   строку — она бы спорила с наградами за главную роль на карточке. */
.qb-order-actions {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: calc(10px * var(--ui-space));
}

/* Кнопка «заменить испытание» — ВАША картинка assets/quests/btn-discard.png.
   Пока файла нет — вместо неё рисуется 🗑, кнопка не «съезжает». Плашку под
   картинкой не рисуем: рамка нарисована на самой картинке. */
.qb-trash-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  justify-self: start;
  width: calc(54px * var(--ui-scale));
  height: calc(54px * var(--ui-scale));
  padding: 0;
  font-size: calc(34px * var(--ui-scale));   /* размер emoji-заглушки, пока нет картинки */
  color: var(--qb-ink-soft);
  background: none;
  border: none;
  cursor: pointer;
  flex-shrink: 0;
  transition: transform 0.12s, filter 0.15s;
}

.qb-trash-btn:hover    { transform: translateY(-1px); filter: brightness(1.06); }
.qb-trash-btn:active   { transform: scale(0.94); }
.qb-trash-btn:disabled { opacity: 0.6; cursor: default; }

/* ── Индикаторы «здесь ждёт награда» ──
   Один и тот же язык на всех уровнях: цифра на кнопке «Задания» в меню (.nav-badge),
   цифра на вкладке, галочка на клетке испытания и плашка на самом испытании. */

/* Цифра на вкладке — сколько наград ждёт за ней. */
.qb-tab { position: relative; }

.qb-tab-badge {
  position: absolute;
  top: calc(-4px * var(--ui-scale));
  right: calc(-4px * var(--ui-scale));
  min-width: calc(22px * var(--ui-scale));
  height: calc(22px * var(--ui-scale));
  padding: 0 calc(5px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  font-size: var(--fs-13);
  font-weight: 900;
  color: #fff;
  background: linear-gradient(135deg, #ff5a4e, #c11414);
  border-radius: calc(7px * var(--ui-scale));
  box-shadow: 0 2px 6px rgba(193,20,20,0.5);
  animation: qb-badge-pop 1.6s ease-in-out infinite;
}

@keyframes qb-badge-pop {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.12); }
}

/* Галочка на клетке пройденного испытания. */
.qb-order-flag {
  position: absolute;
  top: calc(-6px * var(--ui-scale));
  right: calc(-6px * var(--ui-scale));
  width: calc(26px * var(--ui-scale));
  height: calc(26px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  font-size: var(--fs-14);
  font-weight: 900;
  color: #fff;
  background: #f0a81f;
  border: calc(2px * var(--ui-scale)) solid #fff;
  border-radius: 50%;
  box-shadow: 0 2px 6px rgba(224,112,32,0.5);
  z-index: 2;
}

/* Пройденное испытание светится в сетке — как подарок, который можно забрать. */
.qb-order-ready {
  animation: qb-order-glow 1.8s ease-in-out infinite;
}

@keyframes qb-order-glow {
  0%, 100% { box-shadow: 0 6px 18px rgba(224,112,32,0.35), 0 0 0 calc(2px * var(--ui-scale)) rgba(255,196,107,0.7); }
  50%      { box-shadow: 0 6px 22px rgba(224,112,32,0.5),  0 0 0 calc(4px * var(--ui-scale)) rgba(255,196,107,0.9); }
}

/* Плашка на самом испытании — видно, что оно пройдено, ещё до кнопки «Забрать». */
.qb-order-detail-ready { border-color: rgba(230,150,40,0.5); }

.qb-order-done {
  align-self: center;
  padding: calc(6px * var(--ui-space)) calc(18px * var(--ui-space));
  font-size: var(--fs-15);
  font-weight: 900;
  color: #fff;
  background: linear-gradient(180deg, #ffc266, #e0850f);
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.85);
  border-radius: 50px;
  text-shadow: 0 1px 0 rgba(150,80,10,0.35);
  box-shadow: 0 4px 12px rgba(224,112,32,0.35);
}

/* ── Окно «потратить мармелад?» (ui/modals/ConfirmSpend.js) ───────────────────
   Одно окно на все траты мармелада: покупка подарка и аватара, кручение
   лототрона, замена испытания. Ни цены, ни баланса в нём нет: цена написана на
   кнопке, с которой игрок пришёл, баланс — в шапке страницы, а окно спрашивает
   одно — «да или нет».

   Оформление — карточка игры, а не белый прямоугольник: тот же язык, что у
   ежедневного бонуса (.db-card) и плашки «нужна авторизация» (.sp2-guest-*) —
   пастельный градиент в белой окантовке, размытые шары по углам и мармеладка на
   ореоле сверху. Затемнение общее со всеми окнами (.sp2-modal-overlay). */
/* Поля затемнения: на коротком экране карточка не должна липнуть к краям. */
.cs-overlay { padding: calc(12px * var(--ui-space)); }

.cs-card {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(9px * var(--ui-space));
  width: min(88%, calc(400px * var(--ui-scale)));
  max-height: 92vh;
  overflow-y: auto;
  padding: calc(16px * var(--ui-space)) calc(22px * var(--ui-space)) calc(18px * var(--ui-space));
  text-align: center;
  border-radius: calc(28px * var(--ui-scale));
  background: linear-gradient(160deg, #fffdff 0%, #f4e8fc 55%, #fde7f4 100%);
  border: calc(3px * var(--ui-scale)) solid #fff;
  box-shadow: 0 calc(18px * var(--ui-scale)) calc(46px * var(--ui-scale)) rgba(70,30,120,0.45);
  animation: cs-pop 0.24s cubic-bezier(0.34, 1.4, 0.64, 1);
}

@keyframes cs-pop {
  from { transform: scale(0.90); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}

/* Шары клипуются скруглением карточки, поэтому лежат в своём слое, а не в ней. */
.cs-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  overflow: hidden;
  pointer-events: none;
}

.cs-bubble {
  position: absolute;
  border-radius: 50%;
  filter: blur(6px);
  animation: sp2-guest-bubble-drift 7s ease-in-out infinite;
}
.cs-bubble--a {
  width: calc(88px * var(--ui-scale)); height: calc(88px * var(--ui-scale));
  top: calc(-22px * var(--ui-scale)); right: calc(-22px * var(--ui-scale));
  background: radial-gradient(circle at 34% 30%, #ffe4f2, #ffc2e0 72%);
  opacity: 0.55;
}
.cs-bubble--b {
  width: calc(64px * var(--ui-scale)); height: calc(64px * var(--ui-scale));
  bottom: calc(-18px * var(--ui-scale)); left: calc(-16px * var(--ui-scale));
  background: radial-gradient(circle at 34% 30%, #fff6d6, #ffe694 72%);
  opacity: 0.48;
  animation-delay: -2.4s;
}
.cs-bubble--c {
  width: calc(40px * var(--ui-scale)); height: calc(40px * var(--ui-scale));
  top: calc(30px * var(--ui-scale)); left: calc(-12px * var(--ui-scale));
  background: radial-gradient(circle at 34% 30%, #e8fff6, #b6efd8 72%);
  opacity: 0.42;
  animation-delay: -4.8s;
}

/* Мармеладка на ореоле — герой окна: о ней и спрашивают. Тот же приём, что у
   замка на плашке «нужна авторизация» (.sp2-guest-lock). */
.cs-hero {
  position: relative;
  z-index: 1;
  width: calc(72px * var(--ui-scale));
  height: calc(72px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  animation: sp2-guest-lock-float 3.2s ease-in-out infinite;
}
.cs-hero::before {
  content: '';
  position: absolute;
  inset: calc(-12px * var(--ui-scale));
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,0.9) 0%, rgba(232,218,255,0.42) 45%, rgba(232,218,255,0) 70%);
  pointer-events: none;
}
.cs-hero-img {
  position: relative;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 calc(8px * var(--ui-scale)) calc(10px * var(--ui-scale)) rgba(130,90,190,0.30));
}

.cs-title {
  position: relative;
  z-index: 1;
  font-size: var(--fs-21);
  font-weight: 900;
  line-height: 1.2;
  color: #7b3fbe;
  letter-spacing: 0.02em;
  text-shadow: 0 2px 0 rgba(255,255,255,0.9);
}

.cs-text {
  position: relative;
  z-index: 1;
  font-size: var(--fs-13);
  font-weight: 700;
  line-height: 1.35;
  color: rgba(42,26,64,0.66);
}

/* Последний вопрос перед кнопками: заголовок называет трату, эта строка
   спрашивает согласие. Ни капсулы, ни рамки у неё нет намеренно — в капсуле,
   да ещё вплотную к двум кнопкам, строка читалась третьей кнопкой и звала
   нажать себя. Это текст, и выглядеть он должен текстом. */
.cs-sure {
  position: relative;
  z-index: 1;
  margin-top: calc(-2px * var(--ui-space));
  font-size: var(--fs-16);
  font-weight: 900;
  color: #7b3fbe;
  text-shadow: 0 1px 0 rgba(255,255,255,0.9);
}

.cs-actions {
  position: relative;
  z-index: 1;
  display: flex;
  gap: calc(10px * var(--ui-space));
  width: 100%;
  margin-top: calc(2px * var(--ui-space));
}

/* Кнопки делят ширину поровну: вопрос «да/нет», и обе двери равны собой. */
.cs-btn {
  flex: 1;
  min-height: calc(48px * var(--ui-scale));
  padding: 0 calc(14px * var(--ui-space));
  font-size: var(--fs-16);
  font-weight: 900;
  border-radius: 50px;
  cursor: pointer;
  white-space: nowrap;
  transition: transform 0.12s, filter 0.15s;
}
.cs-btn:hover  { filter: brightness(1.05); }
.cs-btn:active { transform: scale(0.95); }
.cs-btn:disabled { opacity: 0.6; cursor: default; transform: none; }

/* Согласие — оранжевая кнопка игры (та же, что «Забрать» в бонусе и заданиях):
   единственная кнопка окна, которая тратит, и выглядит она как действие. */
.cs-btn--ok {
  color: #fff;
  background: linear-gradient(180deg, #ffc266, #e0850f);
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.8);
  text-shadow: 0 2px 0 rgba(150,80,10,0.35);
  box-shadow: 0 5px 14px rgba(224,112,32,0.45), inset 0 2px 0 rgba(255,255,255,0.55);
}

/* Отказ — тихая сиреневая кнопка: уйти ни на что не тратя должно быть спокойно,
   а не так же громко, как согласиться. */
.cs-btn--ghost {
  color: #7b3fbe;
  background: rgba(255,255,255,0.85);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.35);
  box-shadow: inset 0 2px 0 rgba(255,255,255,0.8);
}

/* Короткий экран (телефон в горизонтали) — окно ужимается: герой мельче,
   поля уже. Правило то же, что у плашки «нужна авторизация». */
@media (max-height: 379px) and (orientation: landscape) {
  .cs-card  { gap: calc(6px * var(--ui-space));
              padding: calc(12px * var(--ui-space)) calc(16px * var(--ui-space)) calc(12px * var(--ui-space)); }
  .cs-hero  { width: calc(52px * var(--ui-scale)); height: calc(52px * var(--ui-scale)); }
  .cs-title { font-size: var(--fs-18); }
  .cs-text  { font-size: var(--fs-12); }
  .cs-sure  { font-size: var(--fs-14); }
  .cs-btn   { min-height: calc(42px * var(--ui-scale)); font-size: var(--fs-14); }
}

/* На испытании та же кнопка крупнее — карточка широкая, кнопка на ней главная. */
.qb-deliver-btn {
  min-width: calc(200px * var(--ui-scale));
  min-height: calc(54px * var(--ui-scale));
  padding: 0 calc(32px * var(--ui-space));
  font-size: var(--fs-20);
  border-radius: calc(18px * var(--ui-scale));
}

/* Пока задание не выполнено, а испытание не пройдено — не серая грязь, а спокойная
   сиреневая плашка. И не пульсирует: пульс означает «есть что забрать». */
.qb-claim-btn:disabled,
.qb-deliver-btn:disabled {
  cursor: default;
  transform: none;
  animation: none;
  color: #fff;
  background: linear-gradient(180deg, #e4d7f3, #c3b0dd);
  text-shadow: 0 2px 0 rgba(122,95,160,0.3);
  box-shadow: inset 0 2px 0 rgba(255,255,255,0.6);
}

/* ── Узкий экран: телефон в горизонтали ──────────────────────────────────────
   Раскладка остаётся той же, что и на широком экране: задания — сеткой 2×2,
   испытания — сетка и карточка рядом. Меняется только плотность: арт карточки,
   шкала недели и кнопки становятся мельче. Вкладки при этом поднимаются под самый
   заголовок — на низком экране освободившаяся полоса это целый ряд карточек.
   Низкий экран считается узким наравне с тесным по ширине: --ui-scale держит
   полный размер вплоть до высоты 500px, поэтому доска в полную величину не
   помещается в невысокое окно ничуть не лучше, чем в узкое. */
@media (max-width: 1100px), (max-height: 660px) and (orientation: landscape) {
  .quests-panel .sp2-topbar {
    padding-top: calc(4px * var(--ui-space));
    padding-bottom: 0;
  }

  .qb-tabs {
    margin-top: calc(-6px * var(--ui-space));
    padding-bottom: calc(8px * var(--ui-space));
  }

  .qb-layout { padding-left: calc(14px * var(--ui-space)); }

  /* Задания дня: две карточки в ряд, только теснее — и колонку не даём разъезжаться
     на всю ширину. Игра всегда горизонтальная, поэтому окно широкое; без предела
     «лежачая» карточка растягивается, арт остаётся крошечным слева, а шкала тянется
     через всё поле. Держим доску ограниченной по ширине и по центру. */
  .qb-daily { max-width: calc(720px * var(--ui-scale)); }

  .qb-card {
    gap: calc(10px * var(--ui-space));
    padding: calc(9px * var(--ui-space));
  }

  .qb-card-body    { gap: calc(5px * var(--ui-space)); }
  .qb-card-art     { width: calc(72px * var(--ui-scale)); height: calc(72px * var(--ui-scale)); }
  .qb-card-emoji   { font-size: calc(46px * var(--ui-scale)); }
  .qb-card-title   { font-size: var(--fs-14); }
  .qb-progress-track { height: calc(22px * var(--ui-scale)); }
  .qb-progress-text  { line-height: calc(22px * var(--ui-scale)); }

  /* Карточка дня узкая — кнопке «Забрать» хватает полей по надписи. */
  .qb-claim-btn {
    min-height: calc(36px * var(--ui-scale));
    padding: 0 calc(12px * var(--ui-space));
    font-size: var(--fs-14);
  }

  .qb-reward-icon,
  .qb-point-ico { width: calc(18px * var(--ui-scale)); height: calc(18px * var(--ui-scale)); }

  .qb-footer-chip { padding: calc(6px * var(--ui-space)) calc(16px * var(--ui-space)); }

  /* Шкала недели: полоса остаётся на месте, просто тоньше — прогресс так же виден. */
  .qb-track {
    --qb-art-h:  calc(46px * var(--ui-scale));
    --qb-line-h: calc(16px * var(--ui-scale));
  }

  .qb-chest       { --qb-img: calc(34px * var(--ui-scale)); }
  .qb-chest-final { --qb-img: calc(44px * var(--ui-scale)); }
  .qb-track-points .qb-point-ico { width: calc(26px * var(--ui-scale)); height: calc(26px * var(--ui-scale)); }

  /* Испытания: сетка и карточка остаются рядом (места по ширине хватает — окно
     горизонтальное), но клетки тесные, и подпись под картинкой в них не читается,
     только отнимает у неё место. Прячем подпись совсем — картинка занимает клетку
     целиком (.qb-order-art растёт на flex:1) и становится крупнее. */
  .qb-orders   { gap: calc(10px * var(--ui-space)); }

  .qb-order-name { display: none; }
  .qb-order      { gap: 0; padding: calc(6px * var(--ui-space)); }
  .qb-order-emoji { font-size: calc(52px * var(--ui-scale)); }

  .qb-goal     { gap: calc(8px * var(--ui-space)); padding: calc(6px * var(--ui-space)); }
  .qb-goal-art { width: calc(36px * var(--ui-scale)); height: calc(36px * var(--ui-scale)); }
  .qb-goal-bar { height: calc(16px * var(--ui-scale)); }

  .qb-order-rewards .qb-reward-icon,
  .qb-order-rewards .qb-point-ico { width: calc(22px * var(--ui-scale)); height: calc(22px * var(--ui-scale)); }
}

/* ── Низкий экран: доска целиком, без прокрутки ──
   Тут дефицит не в ширине, а в высоте, поэтому ужимаются именно вертикальные
   размеры: отступы доски, шкалы целей и кнопки. Сетка испытаний отдаёт часть
   ширины карточке — от этого её клетки становятся ниже, и все девять помещаются
   рядом с открытым испытанием, а не уезжают под него. */
@media (max-height: 780px) and (orientation: landscape) {
  .qb-daily  { gap: calc(6px * var(--ui-space)); }
  .qb-banner { gap: calc(4px * var(--ui-space)); padding: calc(7px * var(--ui-space)) calc(16px * var(--ui-space)); }
  .qb-track  { padding: calc(2px * var(--ui-space)) 0; }

  .qb-card      { padding: calc(8px * var(--ui-space)); }
  .qb-card-body { gap: calc(4px * var(--ui-space)); }

  .qb-orders { grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr); }

  /* Клетки квадратные, поэтому высота сетки равна её ширине: ограничив ширину
     долей высоты окна, ограничиваем и высоту — все девять клеток видны сразу,
     на какой бы низкий экран окно ни попало. */
  .qb-order-grid {
    gap: calc(6px * var(--ui-space));
    max-width: 70vh;
    justify-self: center;
  }
  .qb-order-detail { gap: calc(6px * var(--ui-space)); padding: calc(12px * var(--ui-space)); }
  .qb-order-title  { padding-bottom: calc(6px * var(--ui-space)); }
  .qb-goals        { gap: calc(5px * var(--ui-space)); }
  .qb-order-rewards { padding-top: calc(6px * var(--ui-space)); }
  .qb-deliver-btn  { min-width: calc(150px * var(--ui-scale)); min-height: calc(44px * var(--ui-scale)); font-size: var(--fs-17); }
  .qb-trash-btn    { width: calc(44px * var(--ui-scale)); height: calc(44px * var(--ui-scale)); }
}

/* ─── Reward Toast ──────────────────────────────────────── */
.qp-toast {
  position: fixed;
  bottom: 32px;
  left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: rgba(255,255,255,0.92);
  border: 1px solid rgba(155,111,200,0.45);
  border-radius: 50px;
  padding: 10px 22px;
  font-size: calc(14px * var(--fs-scale));
  font-weight: 700;
  color: #7b3fbe;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.3s ease, transform 0.3s ease;
  z-index: 100;
  box-shadow: 0 4px 20px rgba(155,111,200,0.25);
  pointer-events: none;
}

.qp-toast-show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}


/* ─── Полка предметов (справа от поля, колонкой) ─────────────
   Стоит в ряду .game-stage справа от поля отдельной вертикальной колонкой (order:2 —
   последняя, после ленты показателей и самого поля). Кнопки — того же размера и вида,
   что кнопки меню (.nav-fig): квадратная картинка из assets/items/ с эмодзи-фолбэком
   за ней (проступает, если арта нет) и бейджем-счётчиком в углу. */
.hud-booster-bar {
  order: 2;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: calc(14px * var(--ui-space));
  z-index: 10;
}

/* ─── Плашка попыток ежедневного вызова ──────────────────────
   Левый верхний угол страницы вызова. Оформлена как чип шапки матча: светлая
   полупрозрачная пилюля + оранжевая монетка-мишень (оранжевый — цвет режима).
   z-index ниже .screen (20), чтобы экран конца матча перекрывал её. */
.daily-attempts-plaque {
  position: absolute;
  top: calc(10px * var(--ui-space));
  left: calc(10px * var(--ui-space));
  z-index: 12;
  display: flex;
  align-items: center;
  gap: calc(8px * var(--ui-scale));
  padding: calc(5px * var(--ui-scale)) calc(14px * var(--ui-scale)) calc(5px * var(--ui-scale)) calc(5px * var(--ui-scale));
  background: rgba(255,255,255,0.55);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(155,111,200,0.2);
  border-radius: 999px;
  box-shadow: 0 calc(4px * var(--ui-scale)) calc(16px * var(--ui-scale)) rgba(120,80,170,0.14);
}

.dap-coin {
  width: calc(30px * var(--ui-scale));
  height: calc(30px * var(--ui-scale));
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  font-size: var(--fs-15);
  line-height: 1;
  background: linear-gradient(135deg, #f5c518, #e07020);
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(224,112,32,0.4);
}

.dap-info {
  display: flex;
  flex-direction: column;
  line-height: 1.05;
}

.dap-label {
  font-size: var(--fs-9);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgba(42,26,64,0.5);
}

.dap-count {
  font-size: var(--fs-17);
  font-weight: 800;
  color: #2a1a40;
}

.dap-sep {
  margin: 0 1px;
  color: rgba(42,26,64,0.4);
}

.item-btn {
  position: relative;
  width: calc(78px * var(--ui-scale));
  height: calc(78px * var(--ui-scale));
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.14s, filter 0.14s;
  filter: drop-shadow(0 2px 6px rgba(155,111,200,0.35));
}

.item-btn:hover:not(:disabled) {
  transform: scale(1.1);
  filter: drop-shadow(0 4px 10px rgba(155,111,200,0.55));
}

.item-btn:active:not(:disabled) {
  transform: scale(0.93);
}

/* Картинка предмета поверх, эмодзи-фолбэк — за ней (проступает при onerror). */
.item-btn-img {
  position: relative;
  z-index: 1;
}

.item-btn-fallback {
  font-size: calc(40px * var(--ui-scale));
  pointer-events: none;
}

/* Предмета нет — приглушаем, но кнопка кликабельна (откроет окно «купить в магазине»). */
.item-btn--empty {
  opacity: 0.7;
  filter: grayscale(0.45) drop-shadow(0 2px 6px rgba(155,111,200,0.22));
}

/* Предмет действует прямо сейчас — светящийся ореол. */
.item-btn--active {
  animation: item-active-pulse 0.7s ease-in-out infinite;
}

@keyframes item-active-pulse {
  0%, 100% { filter: drop-shadow(0 0 6px rgba(155,111,200,0.55)); }
  50%       { filter: drop-shadow(0 0 16px rgba(155,111,200,0.95)); }
}

/* Счётчик количества — «сколько есть», поэтому круглый бейдж (как у меню), а не
   квадратный (тот — для тревог/новинок). Оранжевый круглый счётчик — как значок
   «сколько у игрока» во всём остальном интерфейсе (.sp2-owned-badge в магазине). */
.item-btn-badge {
  top: calc(-5px * var(--ui-scale));
  right: calc(-5px * var(--ui-scale));
  min-width: calc(20px * var(--ui-scale));
  height: calc(20px * var(--ui-scale));
  padding: 0 calc(5px * var(--ui-scale));
  border-radius: 999px;
  background: linear-gradient(135deg, #ffb64d, #f2760c);
  font-size: var(--fs-11);
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(242,118,12,0.5);
}

.item-btn-badge--empty {
  background: linear-gradient(135deg, #d9c3a8, #b39a7a);
  box-shadow: none;
}

/* Убывающий отсчёт действия предмета (заморозка, стабилизатор, антивзрыв) — секунды
   по центру кнопки поверх картинки. Голубой чип, чтобы не спутать с оранжевым
   счётчиком количества в углу. hidden — предмет не активен, отсчёта нет. */
.item-btn-timer {
  position: absolute;
  left: 50%;
  bottom: calc(-2px * var(--ui-scale));
  transform: translateX(-50%);
  z-index: 6;
  box-sizing: border-box;
  min-width: calc(24px * var(--ui-scale));
  padding: calc(1px * var(--ui-scale)) calc(6px * var(--ui-scale));
  border-radius: 999px;
  background: linear-gradient(135deg, #7cc4ff, #2f7fd6);
  color: #fff;
  font-size: var(--fs-13);
  font-weight: 900;
  line-height: calc(18px * var(--ui-scale));
  text-align: center;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(47,127,214,0.5);
}
.item-btn-timer[hidden] { display: none; }

/* ─── Окно «предмет закончился» в матче ──────────────────────
   Магазин во время игры недоступен, поэтому клик по пустому предмету не уводит со
   страницы, а показывает это окно. Пока оно открыто, матч на паузе (Game._showBuyPrompt). */
.item-buy-modal {
  position: absolute;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(20px * var(--ui-space));
  background: rgba(40,20,70,0.42);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  animation: item-buy-fade 0.2s ease-out;
}

@keyframes item-buy-fade { from { opacity: 0; } to { opacity: 1; } }

.item-buy-card {
  width: min(86vw, calc(360px * var(--ui-scale)));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(12px * var(--ui-space));
  padding: calc(24px * var(--ui-space)) calc(22px * var(--ui-space));
  border-radius: calc(22px * var(--ui-scale));
  background: linear-gradient(160deg, rgba(255,255,255,0.96), rgba(240,230,252,0.96));
  border: 1px solid rgba(155,111,200,0.3);
  box-shadow: 0 calc(16px * var(--ui-scale)) calc(48px * var(--ui-scale)) rgba(70,30,120,0.4);
  text-align: center;
  animation: item-buy-pop 0.28s cubic-bezier(.2,.9,.3,1.3);
}

@keyframes item-buy-pop {
  0%   { transform: scale(0.82); opacity: 0; }
  100% { transform: scale(1);    opacity: 1; }
}

.item-buy-iconwrap {
  position: relative;
  width: calc(72px * var(--ui-scale));
  height: calc(72px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  filter: drop-shadow(0 4px 10px rgba(155,111,200,0.45));
}

.item-buy-icon {
  position: relative;
  z-index: 1;
}

.item-buy-icon-fallback {
  font-size: calc(56px * var(--ui-scale));
}

.item-buy-title {
  font-size: var(--fs-20);
  font-weight: 900;
  color: #2a1a40;
}

.item-buy-text {
  font-size: var(--fs-14);
  font-weight: 600;
  color: rgba(42,26,64,0.72);
  line-height: 1.4;
}

.item-buy-ok {
  margin-top: calc(4px * var(--ui-space));
  padding: calc(11px * var(--ui-space)) calc(30px * var(--ui-space));
  border: none;
  border-radius: 999px;
  cursor: pointer;
  background: linear-gradient(135deg, #9b6fc8, #7b3fbe);
  color: #fff;
  font-size: var(--fs-15);
  font-weight: 800;
  box-shadow: 0 calc(6px * var(--ui-scale)) calc(16px * var(--ui-scale)) rgba(123,63,190,0.45);
  transition: transform 0.12s, box-shadow 0.12s;
}

.item-buy-ok:hover  { transform: translateY(-1px); }
.item-buy-ok:active { transform: scale(0.95); }

/* Блокирующее окно ежедневного вызова: плашка-блокировка (как у гостя) с крупным
   обратным отсчётом до полуночи. Контент сидит над пастельным фоном .sp2-guest-bg.
   Отсчёт и кнопка живут внутри .sp2-guest-plaque, поэтому и мерка у них плашечная:
   --gg-text (см. «Своя мерка плашки») крупнит буквы на телефоне — иначе рядом с
   выросшим заголовком «Понятно» осталось бы вдвое мельче остального. */
.daily-lock-timer {
  position: relative;
  z-index: 1;
  font-size: calc(34px * var(--ui-scale) * var(--fs-scale) * var(--gg-text));
  font-weight: 900;
  color: #7b3fbe;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

.daily-lock-plaque .daily-lock-ok {
  position: relative;
  z-index: 1;
  margin-top: calc(6px * var(--gg-space));
  padding: calc(11px * var(--gg-space)) calc(30px * var(--gg-space));
  font-size: calc(var(--fs-15) * var(--gg-text));
}

/* ─── Shop Panel ────────────────────────────────────────── */
/* ─── Shop Panel v2 ──────────────────────────────────────────── */
.shop-panel {
  padding: 0;
  gap: 0;
  overflow: hidden;
}

.sp2-layout {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  overflow: hidden;
  padding: 0 calc(12px * var(--ui-space)) 0 calc(28px * var(--ui-space));
  box-sizing: border-box;
}

/* ── Top bar — transparent, no background stripe ── */
.sp2-topbar {
  display: flex;
  align-items: center;
  gap: calc(10px * var(--ui-space));
  padding: calc(10px * var(--ui-space)) calc(14px * var(--ui-space));
  background: transparent;
  flex-shrink: 0;
  box-sizing: border-box;
}

.sp2-topbar-title {
  font-size: calc(26px * var(--ui-scale) * var(--fs-scale));
  font-weight: 900;
  letter-spacing: 0.03em;
  color: #2a1a40;
  white-space: nowrap;
  flex-shrink: 0;
}

.sp2-topbar-currencies {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  justify-content: center;
}

/* Currency pill */
.sp2-currency {
  display: flex;
  align-items: center;
  gap: calc(6px * var(--ui-space));
  background: rgba(255,255,255,0.65);
  border: 1.5px solid rgba(155,111,200,0.25);
  border-radius: 50px;
  min-height: calc(56px * var(--ui-scale));
  padding: 0 calc(20px * var(--ui-space)) 0 calc(14px * var(--ui-space));
}

.sp2-currency-icon {
  width: calc(36px * var(--ui-scale));
  height: calc(36px * var(--ui-scale));
  object-fit: contain;
  flex-shrink: 0;
}

.sp2-currency-val {
  font-size: var(--fs-19);
  font-weight: 700;
  line-height: 1;
  color: #2a1a40;
}

.sp2-coins-val    { color: #c8860a; }
.sp2-crystals-val { color: #d03888; }

/* Close button */
.sp2-close-btn {
  width: calc(64px * var(--ui-scale));
  height: calc(64px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  transition: transform 0.15s, filter 0.15s;
  filter: drop-shadow(0 2px 6px rgba(155,111,200,0.45));
}

.sp2-close-btn:hover  { transform: scale(1.10); filter: drop-shadow(0 4px 10px rgba(155,111,200,0.65)); }
.sp2-close-btn:active { transform: scale(0.93); }

.sp2-close-btn img {
  width: calc(52px * var(--ui-scale));
  height: calc(52px * var(--ui-scale));
  display: block;
  object-fit: contain;
}

/* ── Body = sidenav + content ── */
.sp2-body {
  display: flex;
  flex: 1;
  overflow-x: hidden;
  overflow-y: hidden;
  align-items: stretch;
  min-height: 0;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.sp2-body::-webkit-scrollbar {
  display: none;
}

/* ── Left side nav — separated pill buttons, like the reference ── */
.sp2-sidenav {
  display: flex;
  flex-direction: column;
  gap: calc(10px * var(--ui-space));
  padding: calc(14px * var(--ui-space)) calc(10px * var(--ui-space));
  width: clamp(64px, calc(118px * var(--ui-scale)), 22vw);
  flex-shrink: 0;
  background: transparent;
  overflow-y: auto;
  overflow-x: hidden;
  box-sizing: border-box;
  align-items: stretch;
  justify-content: center;
  align-self: stretch;
}

/* Each nav pill */
.sp2-nav-item {
  min-height: calc(76px * var(--ui-scale));
  padding: calc(12px * var(--ui-space)) calc(8px * var(--ui-space));
  font-size: var(--fs-13);
  font-weight: 700;
  text-align: center;
  background: rgba(255,255,255,0.65);
  border: 1.5px solid rgba(155,111,200,0.30);
  border-radius: 18px;
  color: #2a1a40;
  cursor: pointer;
  transition: transform 0.13s, box-shadow 0.13s, background 0.13s, border-color 0.13s;
  line-height: 1.3;
  box-shadow: 0 2px 8px rgba(155,111,200,0.15);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
}

.sp2-nav-item:hover {
  transform: scale(1.05);
  background: rgba(255,255,255,0.85);
  box-shadow: 0 4px 14px rgba(155,111,200,0.28);
}

.sp2-nav-item:active { transform: scale(0.95); }

/* Active: purple fill — matches btn-mode gradient */
.sp2-nav-active {
  background: linear-gradient(135deg, #9b6fc8, #7b3fbe);
  border-color: transparent;
  color: #fff;
  box-shadow: 0 4px 16px rgba(123,63,190,0.45);
}

.sp2-nav-icon {
  font-size: var(--fs-20);
  line-height: 1;
}

/* ── Main content area ── */
.sp2-content {
  flex: 1;
  overflow-x: hidden;
  overflow-y: auto;
  padding: calc(14px * var(--ui-space)) calc(14px * var(--ui-space)) calc(14px * var(--ui-space)) calc(6px * var(--ui-space));
  box-sizing: border-box;
  display: flex;
  align-items: stretch;
  justify-content: center;
  min-width: 0;
  min-height: 0;
  scrollbar-width: thin;
  scrollbar-color: rgba(155,111,200,0.35) transparent;
  cursor: default;
  touch-action: pan-y;
}

.sp2-content::-webkit-scrollbar {
  width: 4px;
}

.sp2-content::-webkit-scrollbar-thumb {
  background: rgba(155,111,200,0.35);
  border-radius: 4px;
}

.sp2-content:active {
  cursor: grabbing;
}

/* ── Offer cards grid (centered, wrapping) ── */
.sp2-cards-grid {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: calc(12px * var(--ui-space));
  align-items: center;
  justify-content: center;
  align-content: center;
}

/* Base offer card */
.sp2-offer-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(10px * var(--ui-space));
  padding: calc(26px * var(--ui-space)) calc(16px * var(--ui-space)) calc(18px * var(--ui-space));
  border-radius: 24px;
  border: 1.5px solid rgba(155,111,200,0.22);
  background: rgba(255,255,255,0.62);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 4px 16px rgba(155,111,200,0.10);
  transition: transform 0.14s, box-shadow 0.14s;
  text-align: center;
  box-sizing: border-box;
  width: calc(190px * var(--ui-scale));
  min-height: calc(300px * var(--ui-scale));
  flex-shrink: 0;
  align-self: stretch;
  justify-content: space-between;
}

.sp2-offer-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 24px rgba(155,111,200,0.22);
}

/* Colour accents per section — subtle tints over the white glass */
.sp2-offer-card--promo {
  border-color: rgba(208,56,136,0.30);
  background: rgba(255,240,250,0.72);
}

.sp2-offer-card--coin {
  border-color: rgba(200,134,10,0.30);
  background: rgba(255,250,230,0.72);
}

.sp2-offer-card--diamond {
  border-color: rgba(123,63,190,0.28);
  background: rgba(245,240,255,0.72);
}

.sp2-offer-card--deco {
  border-color: rgba(208,56,136,0.22);
  background: rgba(255,240,248,0.72);
}

/* Украшения (аватары): аватар — чистый круг, без квадратной плашки вокруг.
   Арт круглый (портрет на светлом фоне) → клипаем в круг, лёгкий зум скрывает
   светлые углы PNG. Подложка-ореол — в блоке витрины украшений ниже. */
.sp2-offer-card--deco .sp2-card-img {
  border-radius: 50%;
  object-fit: cover;
  transform: scale(1.06);
}


.sp2-offer-card--equipped {
  border-color: rgba(123,63,190,0.55);
  background: rgba(230,220,255,0.55);
  box-shadow: 0 4px 18px rgba(123,63,190,0.20);
}

.sp2-offer-card--starter {
  border-color: rgba(123,63,190,0.22);
  background: rgba(240,255,245,0.72);
}

.sp2-offer-card--item {
  border-color: rgba(123,63,190,0.22);
  background: rgba(248,245,255,0.72);
}


/* "Хит!" badge */
.sp2-offer-badge {
  position: absolute;
  top: -11px;
  left: 50%;
  transform: translateX(-50%);
  background: linear-gradient(135deg, #d03888, #7b3fbe);
  color: #fff;
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.04em;
  padding: 4px 16px;
  border-radius: 50px;
  white-space: nowrap;
  box-shadow: 0 2px 8px rgba(208,56,136,0.45);
}

.sp2-offer-icon-wrap {
  width: calc(130px * var(--ui-scale));
  height: calc(130px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255,255,255,0.60);
  border-radius: 20px;
  border: 1px solid rgba(155,111,200,0.18);
  flex-shrink: 0;
  overflow: hidden;
}

/* icon slot: stacks img + fallback emoji */
.sp2-icon-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}


/* Nav icon images */
.sp2-nav-icon-wrap {
  width: calc(48px * var(--ui-scale));
  height: calc(48px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
}

.sp2-nav-img {
  width: calc(48px * var(--ui-scale));
  height: calc(48px * var(--ui-scale));
  object-fit: contain;
  display: block;
}


.sp2-offer-title {
  font-size: var(--fs-15);
  font-weight: 700;
  color: #2a1a40;
  line-height: 1.3;
  word-break: break-word;
  min-height: 2.6em;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  width: 100%;
}


/* Reward rows inside promo cards */
.sp2-offer-includes {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
}

.sp2-offer-reward {
  display: flex;
  align-items: center;
  gap: calc(6px * var(--ui-space));
  font-size: var(--fs-13);
  font-weight: 700;
  color: #2a1a40;
  background: rgba(255,255,255,0.55);
  border: 1px solid rgba(155,111,200,0.18);
  border-radius: 50px;
  padding: calc(5px * var(--ui-space)) calc(10px * var(--ui-space));
}

.sp2-reward-icon {
  width: calc(20px * var(--ui-scale));
  height: calc(20px * var(--ui-scale));
  object-fit: contain;
  flex-shrink: 0;
}

/* Buy button — amber/gold */
.sp2-buy-offer-btn {
  margin-top: auto;
  min-height: calc(56px * var(--ui-scale));
  padding: 0 calc(16px * var(--ui-space));
  font-size: var(--fs-17);
  font-weight: 800;
  border: none;
  border-radius: 50px;
  background: linear-gradient(135deg, #f5c518, #e07020);
  color: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 5px;
  justify-content: center;
  box-shadow: 0 3px 12px rgba(200,134,10,0.45);
  transition: transform 0.10s, box-shadow 0.10s;
  white-space: nowrap;
  width: 100%;
}

.sp2-buy-offer-btn:hover  { transform: scale(1.05); box-shadow: 0 5px 16px rgba(200,134,10,0.60); }
.sp2-buy-offer-btn:active { transform: scale(0.94); }

.sp2-buy-offer-btn--disabled {
  opacity: 0.35;
  cursor: not-allowed;
  transform: none !important;
  box-shadow: none !important;
}

/* Подарки: несколько кнопок цены (по одной на валюту), стопкой снизу карточки */
.sp2-gift-prices {
  margin-top: auto;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: calc(7px * var(--ui-space));
}
.sp2-gift-prices .sp2-buy-offer-btn {
  margin-top: 0;
  min-height: calc(48px * var(--ui-scale));
}

/* Цена в мармеладе — фиолетовая кнопка */
.sp2-buy-offer-btn--diamond {
  background: linear-gradient(135deg, #b06be6, #7b3fbe);
  box-shadow: 0 3px 12px rgba(123,63,190,0.45);
}
.sp2-buy-offer-btn--diamond:hover { box-shadow: 0 5px 16px rgba(123,63,190,0.60); }

/* Цена в рублях — розовая кнопка */
.sp2-buy-offer-btn--rub {
  background: linear-gradient(135deg, #ff8fb3, #d03888);
  box-shadow: 0 3px 12px rgba(208,56,136,0.45);
}
.sp2-buy-offer-btn--rub:hover { box-shadow: 0 5px 16px rgba(208,56,136,0.60); }

/* Сезонный лот: один ярлычок в одну строку — часы, слово «Сезонный» и остаток
   сезона. Сидит верхом на кромке карточки, ровно как «Хит!» (.sp2-offer-badge)
   и «✦ Премиум» (.sp2-premium-ribbon), и вынут из потока: арт, название и цена
   сезонного лота стоят на той же высоте, что и у соседних лотов, — карточка
   ничем не выше и не съезжает вниз. Исключение — витрина аватаров: там у
   карточки уже есть своя полоса бейджей, ярлычок остаётся в ней (ниже). */
.sp2-season {
  position: absolute;
  top: calc(-14px * var(--ui-scale));
  left: 50%;
  transform: translateX(-50%);
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: calc(4px * var(--ui-space));
  padding: calc(2px * var(--ui-space)) calc(9px * var(--ui-space))
           calc(2px * var(--ui-space)) calc(5px * var(--ui-space));
  background: linear-gradient(180deg, #f2fff8, #c8f2dc);
  border: calc(2px * var(--ui-scale)) solid #fff;
  border-radius: 50px;
  box-shadow: 0 3px 9px rgba(46,138,90,0.35);
  white-space: nowrap;
}

/* Часы — та же картинка, что тикает над таблицей рейтинга (.st-lb-timer-ico-img),
   только без оранжевого кружка: ярлычок и так зелёный. */
.sp2-season-ico {
  width: calc(15px * var(--ui-scale));
  height: calc(15px * var(--ui-scale));
  object-fit: contain;
  flex-shrink: 0;
  display: block;
}

/* Слово «Сезонный» — зелёное, под цвет всего ярлычка с часами и остатком срока.
   В профиле такой же ярлычок лавандовый (.pf-tile-season): там он про редкость
   уже купленного лица, здесь — про то, сколько ещё продаётся этот лот.
   Заливка теперь у всего ярлычка, у слова её нет. */
.sp2-season-badge {
  font-size: var(--fs-10);
  font-weight: 900;
  color: #2a8a5a;
  letter-spacing: 0.02em;
}
/* Остаток сезона — за тонкой чертой, справа от слова */
.sp2-season-left {
  display: inline-flex;
  align-items: center;
  padding-left: calc(5px * var(--ui-space));
  border-left: 1px solid rgba(46,138,90,0.30);
  font-size: var(--fs-10);
  font-weight: 800;
  color: #2a8a5a;
  letter-spacing: 0.02em;
}
/* Остаток тикает каждую секунду — моноширинные цифры, чтобы ярлычок не дёргался. */
.sp2-season-left-val { font-variant-numeric: tabular-nums; }

/* Кромка занята своим ярлычком («Хит!») — сезонный уходит строкой ниже, в
   верхний отступ карточки, чтобы ярлычки не наезжали друг на друга. С лентой
   «✦ Премиум» сезонный больше не встречается: сезонный лот подписан сезоном, а
   не ценой, и ленты не носит (см. тир в _renderGifts). */
.sp2-offer-badge ~ .sp2-season { top: calc(14px * var(--ui-scale)); }

/* Новинка «!» стоит в левом верхнем углу — под сезонным ярлычком её половина
   скрывалась бы, поэтому на сезонном лоте опускаем её ниже кромки, а если
   ярлычок сам съехал на строку ниже (кромку занял «Хит!») — ещё ниже. */
.sp2-offer-card .sp2-new-badge--seasonal     { top: calc(16px * var(--ui-scale)); }
.sp2-offer-card .sp2-new-badge--seasonal-low { top: calc(41px * var(--ui-scale)); }

/* Витрина аватаров: ярлычок остаётся в потоке — в полосе бейджей над артом
   (.sp2-deco-top), рядом с «Приобретено» и таймером распродажи. Полоса держит
   свою высоту и пустой, поэтому цены и там стоят на одной высоте, а «!» ничем
   не перекрыт и остаётся в углу. */
.sp2-deco-card .sp2-season {
  position: static;
  transform: none;
  top: auto;
  left: auto;
}
.sp2-deco-card .sp2-new-badge--seasonal,
.sp2-deco-card .sp2-new-badge--seasonal-low { top: 8px; }

/* Купленный сезонный аватар — то же слово, что у этой плитки в профиле
   (.pf-tile-season): лавандовое и одно, без часов. Цвет разводит два разных
   смысла одного слова: зелёный с отсчётом — «столько ещё продаётся»,
   лавандовый — «сезон был твой, лицо осталось навсегда».

   Лента верхом на кромке карточки — там же и той же формы, что «✦ Премиум»
   (.sp2-premium-ribbon): оба ярлычка говорят, ЧЕМ это лицо было куплено, и
   стоят вместе, а полоса под кромкой остаётся пометкам витрины («Приобретено»,
   таймер распродажи). */
.sp2-deco-card .sp2-owned-season {
  position: absolute;
  top: -10px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  padding: 4px 14px;
  font-size: var(--fs-12);
  font-weight: 900;
  letter-spacing: 0.03em;
  border-radius: 50px;
  white-space: nowrap;
  background: linear-gradient(135deg, #d9c2ff, #b794ff);
  border: 1px solid rgba(123,63,190,0.35);
  color: #3a2358;
  box-shadow: 0 3px 9px rgba(123,63,190,0.38);
}

/* Кромку занял «✦ Премиум» (аватар за деньги в этой игре всегда ещё и сезонный) —
   сезонная лента сходит с неё и встаёт строкой ниже, В ПОТОКЕ: там же, где на
   непроданном лоте стоит зелёный ярлычок. Именно в потоке, а не вторым слоем на
   кромке, — иначе лента легла бы на полосу с «Приобретено»; так же стоят два
   ярлычка на плитке этого аватара в профиле (.pf-tile-tags). */
.sp2-deco-card .sp2-premium-ribbon ~ .sp2-owned-season {
  position: static;
  transform: none;
  top: auto;
  left: auto;
}

/* Сезон дотикал при открытой витрине — гасим до серого (лот уже не купить).
   Часы и слово убираем: в сером ярлычке остаётся «Сезон закончился». */
.sp2-season--ended {
  background: linear-gradient(180deg, #f6f6f6, #dcdcdc);
  box-shadow: 0 2px 7px rgba(90,90,90,0.30);
}
.sp2-season--ended .sp2-season-ico,
.sp2-season--ended .sp2-season-badge { display: none; }
.sp2-season--ended .sp2-season-left {
  padding-left: 0;
  border-left: none;
  color: #7a7a7a;
}

/* Оранжевый индикатор с обратным отсчётом до конца распродажи (из sale_end).
   В потоке карточки, по центру сверху — над артом. Обновляется каждую секунду. */
.sp2-sale-timer {
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-11);
  font-weight: 800;
  color: #fff;
  background: linear-gradient(135deg, #ffb300, #ff7a00);
  border: 1px solid rgba(255,122,0,0.55);
  padding: 3px 11px;
  border-radius: 50px;
  white-space: nowrap;
  letter-spacing: 0.02em;
  box-shadow: 0 2px 8px rgba(255,122,0,0.40);
  z-index: 3;
}
.sp2-sale-timer-ico { font-size: var(--fs-12); line-height: 1; }
.sp2-sale-timer-val { font-variant-numeric: tabular-nums; }

/* Меньше часа до конца — красно-оранжевый и пульсирует (срочность) */
.sp2-sale-timer--urgent {
  background: linear-gradient(135deg, #ff7a00, #e53935);
  border-color: rgba(229,57,53,0.55);
  box-shadow: 0 2px 10px rgba(229,57,53,0.45);
  animation: sp2-sale-pulse 1.1s ease-in-out infinite;
}
/* Распродажа завершилась при открытой панели — гасим до нейтрального серого */
.sp2-sale-timer--ended {
  background: linear-gradient(135deg, #b8b8b8, #8f8f8f);
  border-color: rgba(120,120,120,0.5);
  box-shadow: none;
  animation: none;
}
@keyframes sp2-sale-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); }
}

/* ══════════════════════════════════════════════════════════════════════════
   Подарки — карамельная витрина (карточки-подарки для друзей)
   Класс-слой поверх базовой .sp2-offer-card--item: сохраняет размеры/выравнивание
   высот, добавляет тир-раскраску, ореол под артом и нарядные детали.
   ══════════════════════════════════════════════════════════════════════════ */

/* Обёртка раздела: приветственная шапка + сетка карточек в колонку */
.sp2-gifts-wrap,
.sp2-decos-wrap {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: calc(14px * var(--ui-space));
  width: 100%;
  min-height: 0;
  align-self: stretch;
}

/* Сетка подарков — чуть плотнее обычной. Сверху отступ под ярлычки, сидящие
   верхом на кромке карточки («✦ Премиум», «Сезонный»): у первого ряда их
   срезала бы прокрутка витрины. */
.sp2-gifts-grid,
.sp2-decos-grid {
  gap: calc(14px * var(--ui-space));
  padding-top: calc(13px * var(--ui-scale));
}

/* Карточка-подарок: наряднее базовой, с игривым наклоном при наведении.
   Без названия — арт и цена сгруппированы вплотную (без пустоты между ними). */
.sp2-gift-card {
  transition: transform 0.16s, box-shadow 0.16s;
  justify-content: center;
  min-height: calc(230px * var(--ui-scale));
}
.sp2-offer-card.sp2-gift-card:hover {
  transform: translateY(-4px) rotate(-0.6deg);
  box-shadow: 0 12px 28px rgba(155,111,200,0.26);
}

/* Тир-раскраска карточки по валюте */
.sp2-gift-card--coin {
  border-color: rgba(255,138,101,0.38);
  background: linear-gradient(160deg, rgba(255,247,236,0.92), rgba(255,226,210,0.82));
}
.sp2-gift-card--diamond {
  border-color: rgba(155,111,200,0.42);
  background: linear-gradient(160deg, rgba(249,243,255,0.94), rgba(232,219,255,0.82));
}
.sp2-gift-card--premium {
  border-color: rgba(232,120,170,0.52);
  background: linear-gradient(160deg, rgba(255,240,248,0.95), rgba(255,229,210,0.86));
  box-shadow: 0 6px 22px rgba(232,120,170,0.26);
}
/* Сезонный подарок красится сезоном, а не ценой: за рубли он или за драже, лот
   стоит одно окно дат и уходит навсегда — это про него главное (тот же порядок
   у свечения и у GET /api/gifts/styles, см. тир в _renderGifts). Лавандовый —
   цвет сезонности во всей игре (кольцо .gift-glow--season, ярлычок
   .pf-tile-season). Он гуще мармеладного тира выше: тот нарочно бледный, чтобы
   не спорить с ценой на карточке, а сезонный обязан отличаться от соседа с
   одного взгляда — отсюда и тень, которой у мармелада нет. */
.sp2-gift-card--season {
  border-color: rgba(150,104,220,0.55);
  background: linear-gradient(160deg, rgba(245,236,255,0.96), rgba(219,199,255,0.88));
  box-shadow: 0 6px 22px rgba(140,90,210,0.24);
}

/* Ореол-подложка под артом подарка (вместо квадратной плашки) */
.sp2-gift-art {
  background: radial-gradient(circle at 50% 46%, rgba(255,255,255,0.85), rgba(255,255,255,0) 68%);
  border: none;
  border-radius: 50%;
  box-shadow: none;
  overflow: visible;
}
.sp2-gift-card--coin    .sp2-gift-art { background: radial-gradient(circle at 50% 46%, rgba(255,212,180,0.72), rgba(255,212,180,0) 66%); }
/* Мармеладный ореол — на 10% гуще остальных (0.62 → 0.68): лавандовый лежит на
   почти белой карточке тира, и в ту же силу, что персиковый у драже, он читается
   бледнее соседа, а не спокойнее. */
.sp2-gift-card--diamond .sp2-gift-art { background: radial-gradient(circle at 50% 46%, rgba(196,168,240,0.68), rgba(196,168,240,0) 66%); }
.sp2-gift-card--premium .sp2-gift-art { background: radial-gradient(circle at 50% 46%, rgba(255,196,150,0.78), rgba(255,182,212,0) 70%); }
/* Сезонный ореол — тот же лавандовый, что у мармелада, но насыщённее и гуще
   (183,148,255 против 196,168,240): он лежит на лавандовой же карточке тира, и
   в мармеладную силу растворился бы в ней. */
.sp2-gift-card--season  .sp2-gift-art { background: radial-gradient(circle at 50% 46%, rgba(183,148,255,0.74), rgba(183,148,255,0) 66%); }
.sp2-gift-art .sp2-card-img {
  filter: drop-shadow(0 6px 10px rgba(120,60,120,0.22));
  transform: scale(1.05);
}

/* Лента «Премиум» для лотов за реальные деньги — и подарков, и аватаров. Розовая
   карточка тира и цена в рублях отличают лот от соседей, но не называют тир;
   премиум-лотов на полке несколько, и общее слово над ними — это ряд, а не
   случайный дорогой лот. СЕЗОННЫЙ ПОДАРОК ЛЕНТЫ НЕ НОСИТ, даже когда куплен за
   рубли: он красится сезоном (.sp2-gift-card--season), и кромка остаётся
   ярлычку «Сезонный» с остатком срока. У аватара сезонный ярлычок стоит в своей
   полосе под кромкой (.sp2-deco-top), и лента там сезону не мешает — сезонному
   лицу она пока достаётся. Тот же ярлычок носит
   купленный аватар в профиле (.pf-tile-premium): слово и цвет общие, чтобы
   премиум узнавался и в магазине, и в инвентаре. */
.sp2-premium-ribbon {
  position: absolute;
  top: -10px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  padding: 4px 14px;
  font-size: var(--fs-12);
  font-weight: 900;
  letter-spacing: 0.03em;
  color: #7a3b00;
  background: linear-gradient(135deg, #ffe08a, #ffb347);
  border-radius: 50px;
  white-space: nowrap;
  box-shadow: 0 3px 9px rgba(214,140,20,0.45);
}

/* Ценовые пилюли подарка — компактнее и ровнее */
.sp2-gift-card .sp2-gift-prices { gap: calc(6px * var(--ui-space)); }
.sp2-gift-card .sp2-gift-prices .sp2-buy-offer-btn {
  min-height: calc(44px * var(--ui-scale));
  font-size: var(--fs-16);
  border-radius: 40px;
}

/* ══════════════════════════════════════════════════════════════════════════
   Украшения (аватары) — витрина, оформленная как «Подарки»
   Тот же слой поверх .sp2-offer-card--item: тир-раскраска по валюте, ореол под
   портретом, без названия — арт и цена сгруппированы вплотную (без пустоты).
   ══════════════════════════════════════════════════════════════════════════ */
/* Карточка — три слота по вертикали: полоса бейджей (постоянной высоты), арт и
   ряд с ценой/статусом. Без justify-content:center: содержимое идёт сверху вниз,
   а цена прижата к низу (margin-top:auto в .sp2-deco-actions). */
.sp2-deco-card {
  transition: transform 0.16s, box-shadow 0.16s;
  min-height: calc(230px * var(--ui-scale));
}

/* Полоса над артом: «Сезонный», таймер распродажи, «Приобретено». Занимает свою
   высоту и когда пуста — иначе бейдж сдвигал бы арт и цену вниз, и цены на
   карточках вставали бы на разной высоте. */
.sp2-deco-card .sp2-deco-top {
  min-height: calc(24px * var(--ui-scale));
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: calc(6px * var(--ui-space));
}
.sp2-deco-card .sp2-acquired-badge { margin-bottom: 0; }
.sp2-offer-card.sp2-deco-card:hover {
  transform: translateY(-4px) rotate(-0.6deg);
  box-shadow: 0 12px 28px rgba(155,111,200,0.26);
}

/* Тир-раскраска карточки по валюте лота */
.sp2-deco-card--coin {
  border-color: rgba(255,138,101,0.38);
  background: linear-gradient(160deg, rgba(255,247,236,0.92), rgba(255,226,210,0.82));
}
.sp2-deco-card--diamond {
  border-color: rgba(155,111,200,0.42);
  background: linear-gradient(160deg, rgba(249,243,255,0.94), rgba(232,219,255,0.82));
}
/* Третий аватар сезона — за рубли: розовый тир, как у премиальных подарков */
.sp2-deco-card--rub {
  border-color: rgba(208,56,136,0.40);
  background: linear-gradient(160deg, rgba(255,244,249,0.94), rgba(255,219,235,0.84));
}
/* Надетый аватар — подсветка поверх тир-раскраски */
.sp2-deco-card.sp2-offer-card--equipped {
  border-color: rgba(123,63,190,0.55);
  background: linear-gradient(160deg, rgba(238,230,255,0.95), rgba(216,200,250,0.86));
  box-shadow: 0 6px 22px rgba(123,63,190,0.24);
}

/* Ореол-подложка под круглым портретом (вместо квадратной плашки) */
.sp2-deco-card .sp2-deco-art {
  background: radial-gradient(circle at 50% 46%, rgba(255,255,255,0.85), rgba(255,255,255,0) 68%);
  border: none;
  border-radius: 50%;
  box-shadow: none;
  overflow: visible;
}
.sp2-deco-card--coin    .sp2-deco-art { background: radial-gradient(circle at 50% 46%, rgba(255,212,180,0.72), rgba(255,212,180,0) 66%); }
.sp2-deco-card--diamond .sp2-deco-art { background: radial-gradient(circle at 50% 46%, rgba(196,168,240,0.62), rgba(196,168,240,0) 66%); }
.sp2-deco-card--rub     .sp2-deco-art { background: radial-gradient(circle at 50% 46%, rgba(255,168,205,0.60), rgba(255,168,205,0) 66%); }
.sp2-deco-card .sp2-deco-art .sp2-card-img {
  filter: drop-shadow(0 6px 10px rgba(120,60,120,0.22));
}

/* Цена/статус аватара — всегда у нижнего края карточки, на одной высоте у всех
   лотов независимо от бейджей сверху */
.sp2-deco-actions {
  margin-top: auto;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(6px * var(--ui-space));
}
.sp2-deco-actions .sp2-buy-offer-btn,
.sp2-deco-actions .sp2-equip-offer-btn,
.sp2-deco-actions .sp2-equipped-badge {
  margin-top: 0;
  min-height: calc(44px * var(--ui-scale));
  font-size: var(--fs-16);
  border-radius: 40px;
}
/* «Надето» — та же пилюля по высоте, что и цена/«Надеть» */
.sp2-deco-actions .sp2-equipped-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
}

/* Equipped badge */
.sp2-equipped-badge {
  font-size: var(--fs-13);
  font-weight: 800;
  color: #7b3fbe;
  padding: 7px 16px;
  border: 1.5px solid rgba(155,111,200,0.45);
  border-radius: 50px;
  white-space: nowrap;
}

/* Equip button — purple */
.sp2-equip-offer-btn {
  min-height: calc(56px * var(--ui-scale));
  padding: 0 calc(16px * var(--ui-space));
  font-size: var(--fs-16);
  font-weight: 800;
  border: none;
  border-radius: 50px;
  background: linear-gradient(135deg, #9b6fc8, #7b3fbe);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 2px 10px rgba(123,63,190,0.40);
  transition: transform 0.10s;
  white-space: nowrap;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.sp2-equip-offer-btn:hover  { transform: scale(1.05); }
.sp2-equip-offer-btn:active { transform: scale(0.94); }

/* Item count badge */

.sp2-item-desc {
  font-size: var(--fs-13);
  color: rgba(42,26,64,0.50);
  line-height: 1.3;
}

/* ══════════════════════════════════════════════════════════════════════════
   Магазин: боковое меню «только картинки» (как в главном меню/статистике)
   ══════════════════════════════════════════════════════════════════════════ */
.shop-panel .sp2-sidenav {
  /* Preferred icon size, capped by viewport height so 6 sections always fit the
     column. flex-shrink below is the hard guarantee if this estimate is off. */
  --sp2-nav-size: min(calc(80px * var(--ui-scale)), 11vh);
  justify-content: center;
  gap: min(calc(20px * var(--ui-scale)), 2vh);
  overflow-y: hidden;
}
.shop-panel .sp2-nav-item {
  position: relative;
  background: transparent;
  border: none;
  box-shadow: none;
  border-radius: 0;
  /* Shrinkable: `flex: 0 0 auto` here used to beat the `flex: 1` in the short-
     landscape media query (media queries add no specificity), so the sections
     never scaled down and the column scrolled. */
  flex: 0 1 auto;
  min-height: 0;
  padding: 0;
  opacity: 0.55;
  transition: transform 0.13s, opacity 0.13s;
}
.shop-panel .sp2-nav-item:hover {
  background: transparent;
  box-shadow: none;
  opacity: 1;
}
.shop-panel .sp2-nav-active {
  background: transparent;
  box-shadow: none;
  opacity: 1;
  transform: scale(1.08);
}
/* Прячем подпись — остаётся только картинка */
.shop-panel .sp2-nav-label { display: none; }
.shop-panel .sp2-nav-icon-wrap {
  width: var(--sp2-nav-size);
  height: var(--sp2-nav-size);
  max-width: var(--sp2-nav-size);
  max-height: var(--sp2-nav-size);
  /* Follow the button when the column compresses it. */
  flex: 0 1 auto;
  min-height: 0;
}
.shop-panel .sp2-nav-img {
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  object-fit: contain;
}

/* Бейдж «новинок» на кнопке раздела (число непросмотренных) */
.sp2-nav-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  background: linear-gradient(135deg, #ff5a4e, #c11414);
  color: #fff;
  font-size: 12px;
  font-weight: 800;
  line-height: 20px;
  text-align: center;
  border-radius: 6px;
  box-shadow: 0 2px 6px rgba(193,20,20,0.5);
  pointer-events: none;
  z-index: 5;
}

/* ── Индикаторы на карточке лота ── */
/* Новинка: «!» (не число), слева сверху */
.sp2-new-badge {
  position: absolute;
  top: 8px;
  left: 8px;
  width: 24px;
  height: 24px;
  background: linear-gradient(135deg, #ff5a4e, #c11414);
  color: #fff;
  font-size: 15px;
  font-weight: 900;
  line-height: 24px;
  text-align: center;
  border-radius: 7px;
  box-shadow: 0 2px 6px rgba(193,20,20,0.5);
  pointer-events: none;
  z-index: 2;
}

/* Владение: жёлто-оранжевый счётчик (сколько у игрока), справа сверху */
.sp2-owned-badge {
  position: absolute;
  top: 8px;
  right: 8px;
  min-width: 22px;
  height: 22px;
  padding: 0 5px;
  background: linear-gradient(135deg, #ffb64d, #f2760c);
  color: #fff;
  font-size: 13px;
  font-weight: 800;
  line-height: 22px;
  text-align: center;
  border-radius: 50px;
  box-shadow: 0 2px 6px rgba(242,118,12,0.45);
  pointer-events: none;
  z-index: 2;
}

/* «Приобретено» вместо цены (купленный аватар) */
.sp2-acquired-badge {
  font-size: var(--fs-12);
  font-weight: 800;
  color: #ff7a00;
  padding: 4px 12px;
  border: 1.5px solid rgba(255,122,0,0.40);
  border-radius: 50px;
  white-space: nowrap;
  margin-bottom: 4px;
}

/* Заблокированный лот (гость): бледный + курсор-запрет */
.sp2-locked {
  opacity: 0.45;
  filter: grayscale(0.35);
  cursor: pointer;
}
.sp2-locked-btn { cursor: pointer; }

/* Баннер и приглашения в разделе «Украшения» */
.sp2-gender-prompt {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(16px * var(--ui-space));
  width: 100%;
  text-align: center;
}
.sp2-gender-prompt-text {
  font-size: var(--fs-16);
  font-weight: 700;
  color: #7b3fbe;
  max-width: 480px;
  line-height: 1.35;
}

/* ── Плашка «нужна авторизация» поверх платных вкладок (гость) ────────────────
   Оформление в стиле витрины: белое «стекло», карамельная лента-ярлычок сверху,
   круглый значок-замок с ореолом и подсказка-пилюля — как на карточках лотов. */
.sp2-guest-gate {
  position: relative;
  flex: 1;
  align-self: stretch;
  width: 100%;
  min-width: 0;
  min-height: 0;
  display: flex;
}
/* Витрина за плашкой: видна, но приглушена и не кликается */
.sp2-guest-gate-behind {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  overflow: hidden;
  pointer-events: none;
  filter: blur(3px) grayscale(0.45);
  opacity: 0.38;
}
/* Сетка лотов за плашкой тянется на всю ширину и переносится по строкам,
   иначе узкий ряд карточек целиком прячется под плашкой (украшения, бустеры).
   Так же — содержимое «Друзей» и «Писем» → «От друзей» под плашкой. */
.sp2-guest-gate-behind > .sp2-cards-grid,
.sp2-guest-gate-behind > .sp2-gifts-wrap,
.sp2-guest-gate-behind > .sp2-decos-wrap,
.sp2-guest-gate-behind > .freq-list,
.sp2-guest-gate-behind > .mail-empty,
.sp2-guest-gate-behind > .fp-add,
.sp2-guest-gate-behind > .mail-friend {
  flex: 1 1 auto;
  min-width: 0;
}
/* Своя мерка плашки (--gg-*), отдельная от общей --ui-scale. Плашка — короткое
   сообщение во весь экран: его читают один раз и уходят, поэтому ужимать его
   вместе со всем интерфейсом нельзя. На телефоне в альбоме (высота ~400 px,
   --ui-scale 0.72) заголовок выходил 17 px, а текст и подсказка — 11 и 10 px:
   в приложении это уже не читается.

     --gg-scale  замок, шары, скругления;
     --gg-space  отступы и зазоры;
     --gg-text   множитель поверх ступеней --fs-* (только буквы);
     --gg-width  предел ширины плашки;
     --gg-lead   поле сверху под ленту «Заблокировано».

   На коротком альбоме --gg-text возвращает буквам полный размер, а место под
   них берётся из ШИРИНЫ: плашка расширяется до --gg-width, и текст с подсказкой
   ложатся в одну строку вместо двух — по высоте плашка от этого не растёт.

   Ручки живут в :root, а не на самой плашке, потому что по ним меряются и те,
   кто плашку ДЕРЖИТ: окно профиля (.pf-modal--gate) и карточки «Друзей» и
   дуэлей с другом — предку значение с потомка не достаётся.

   Поле сверху (--gg-lead) — ручка отдельная от --gg-space нарочно. Лента
   «Заблокировано» висит на верхней кромке и половиной себя заходит внутрь
   плашки, а размер её — БУКВЕННЫЙ (--gg-text), не отступной. Пока поле мерилось
   отступами, на телефоне оно ужималось до 6 px при ленте в 22 px, и лента
   ложилась замку на дужку — в приложении замок выглядел обрезанным. */
:root {
  --gg-scale: var(--ui-scale);
  --gg-space: var(--ui-space);
  --gg-text: 1;
  --gg-width: 380px;
  --gg-lead: 30px;
}

/* Прозрачный: только перехватывает клики по витрине, ничем её не подкрашивает */
.sp2-guest-overlay {
  position: absolute;
  inset: 0;
  z-index: 6;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(16px * var(--gg-space));
  box-sizing: border-box;
}
/* Пастельная «3D-рендер» плашка. overflow не режем — лента свисает за край,
   фон с шарами живёт в отдельном клипящем слое .sp2-guest-bg */
.sp2-guest-plaque {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(10px * var(--gg-space));
  width: min(92%, var(--gg-width));
  /* Выше своего места плашка не растёт. Гейт бывает низким (карточка «Друзей»
     отдаёт под него остаток после вкладок и подсказки), и там плашка вылезала
     поверх вкладок сверху и за нижний край карточки снизу. Лишнее отдаёт ЗАМОК —
     он декоративный (flex-shrink ниже), а слова не жмутся никогда. */
  max-height: 100%;
  padding: var(--gg-lead) calc(24px * var(--gg-space)) calc(22px * var(--gg-space));
  text-align: center;
  box-sizing: border-box;
  border-radius: calc(30px * var(--gg-scale));
  box-shadow: 0 20px 46px rgba(90,60,140,0.24);
  animation: sp2-guest-pop 0.28s cubic-bezier(0.34, 1.4, 0.64, 1);
}
/* Фон: чистый пастельный градиент; клипует шары по скруглению плашки */
.sp2-guest-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  overflow: hidden;
  background: linear-gradient(160deg, #eef7ff 0%, #f5f1ff 52%, #fdeff7 100%);
  border: 2px solid rgba(255,255,255,0.9);
  box-shadow: 0 1px 0 rgba(255,255,255,0.95) inset;
  pointer-events: none;
}
/* Голографический ободок — как переливы на бомбере */
.sp2-guest-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 2px;
  background: linear-gradient(115deg, #ffd6eb, #d9c8ff, #bfeaff, #c6f6e0, #fff0b8, #ffd6eb);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: 0.75;
}
@keyframes sp2-guest-pop {
  from { transform: scale(0.90); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}

/* Пастельные шары — по углам, сильно размыты, текст не задевают */
.sp2-guest-bubble {
  position: absolute;
  border-radius: 50%;
  filter: blur(6px);
  animation: sp2-guest-bubble-drift 7s ease-in-out infinite;
}
.sp2-guest-bubble--a {
  width: calc(88px * var(--gg-scale)); height: calc(88px * var(--gg-scale));
  top: calc(-22px * var(--gg-scale)); right: calc(-22px * var(--gg-scale));
  background: radial-gradient(circle at 34% 30%, #ffe4f2, #ffc2e0 72%);
  opacity: 0.55;
}
.sp2-guest-bubble--b {
  width: calc(64px * var(--gg-scale)); height: calc(64px * var(--gg-scale));
  bottom: calc(-20px * var(--gg-scale)); left: calc(-18px * var(--gg-scale));
  background: radial-gradient(circle at 34% 30%, #fff6d6, #ffe694 72%);
  opacity: 0.48;
  animation-delay: -2.4s;
}
.sp2-guest-bubble--c {
  width: calc(40px * var(--gg-scale)); height: calc(40px * var(--gg-scale));
  bottom: calc(24px * var(--gg-scale)); right: calc(-12px * var(--gg-scale));
  background: radial-gradient(circle at 34% 30%, #e8fff6, #b6efd8 72%);
  opacity: 0.42;
  animation-delay: -4.8s;
}
@keyframes sp2-guest-bubble-drift {
  0%, 100% { transform: translateY(0)    scale(1);    }
  50%      { transform: translateY(-8px) scale(1.04); }
}

/* Лента-ярлычок сверху — как «Хит!» на карточках лотов */
.sp2-guest-ribbon {
  position: absolute;
  /* Сидит на кромке ровно половиной себя — мерка своя, а не в пикселях от
     --gg-scale: буквы ленты меряются --gg-text, и на телефоне лента остаётся
     крупной там, где пиксельный подъём уже ужат. */
  top: 0;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  background: linear-gradient(135deg, #ff9ecd 0%, #c78bf0 52%, #9b7bf0 100%);
  color: #fff;
  font-size: calc(var(--fs-13) * var(--gg-text));
  font-weight: 900;
  letter-spacing: 0.04em;
  line-height: 1.15;
  padding: calc(6px * var(--gg-space)) calc(18px * var(--gg-space));
  border: 2px solid #fff;
  border-radius: 50px;
  white-space: nowrap;
  box-shadow: 0 6px 16px rgba(190,120,220,0.40);
}

/* Замок — картинка (assets/shop/guest-lock.png) на мягком пастельном ореоле */
.sp2-guest-lock {
  position: relative;
  z-index: 1;
  width: calc(104px * var(--gg-scale));
  height: calc(104px * var(--gg-scale));
  margin-top: calc(6px * var(--gg-space));
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 1;      /* единственный, кто уступает высоту в тесном гейте */
  min-height: 0;
  animation: sp2-guest-lock-float 3.2s ease-in-out infinite;
}
/* Ореол-подсветка под картинкой */
.sp2-guest-lock::before {
  content: '';
  position: absolute;
  inset: calc(-14px * var(--gg-scale));
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,0.85) 0%, rgba(232,218,255,0.40) 45%, rgba(232,218,255,0) 70%);
  pointer-events: none;
}
.sp2-guest-lock-img {
  position: relative;
  filter: drop-shadow(0 10px 12px rgba(130,90,190,0.28));
}
@keyframes sp2-guest-lock-float {
  0%, 100% { transform: translateY(0)    scale(1);    }
  50%      { transform: translateY(-6px) scale(1.03); }
}

.sp2-guest-plaque-title {
  position: relative;
  z-index: 1;
  flex-shrink: 0;
  font-size: calc(var(--fs-22) * var(--gg-text));
  font-weight: 900;
  letter-spacing: 0.01em;
  line-height: 1.2;
  background: linear-gradient(120deg, #ff6fb8 0%, #a95ce0 55%, #6f5cec 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.sp2-guest-plaque-text {
  position: relative;
  z-index: 1;
  flex-shrink: 0;
  max-width: calc(280px * var(--ui-scale));
  font-size: calc(var(--fs-14) * var(--gg-text));
  font-weight: 600;
  color: #6b5590;
  line-height: 1.45;
}
/* Подсказка-пилюля: куда идти регистрироваться */
.sp2-guest-plaque-hint {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  max-width: calc(300px * var(--ui-scale));
  margin-top: calc(2px * var(--gg-space));
  padding: calc(10px * var(--gg-space)) calc(18px * var(--gg-space));
  font-size: calc(var(--fs-13) * var(--gg-text));
  font-weight: 800;
  color: #7b4fd0;
  background: #fff;
  border: 2px solid rgba(200,180,240,0.45);
  border-radius: calc(22px * var(--gg-scale));
  line-height: 1.35;
  box-shadow: 0 6px 16px rgba(140,100,200,0.18);
}
/* Та же пилюля, но кнопкой: подсказка ведёт в раздел «Аккаунт» (ui/lib/accountGate.js,
   разметка — ui/modals/GuestGate.js). Шрифт кнопке приходится назначать: <button>
   не наследует его от родителя, и без строки подсказка съехала бы на системный.
   Отклик на наведение и нажатие — по образцу .item-buy-ok: пилюля выглядит
   надписью, и без движения игрок не догадается, что по ней жмут. */
button.sp2-guest-plaque-hint {
  font-family: inherit;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.12s, box-shadow 0.12s;
}
button.sp2-guest-plaque-hint:hover {
  transform: translateY(-1px);
  box-shadow: 0 calc(8px * var(--ui-scale)) calc(20px * var(--ui-scale)) rgba(140,100,200,0.26);
}
button.sp2-guest-plaque-hint:active { transform: scale(0.96); }

/* Телефон в альбоме (высота ≤ 499 px — сюда попадают все три ступени --ui-scale
   ниже единицы). Буквам возвращаем полный размер: --gg-text = 1 / --ui-scale,
   то есть ровно тот множитель, которым общая мерка их ужала. Высоту это не
   съедает — плашка расходится вширь (--gg-width 520 px вместо 380), и обе
   длинные строки, «…нельзя приобрести с анонимного аккаунта» и подсказка про
   раздел «Аккаунт», встают в одну строку каждая. Отступы при этом ужимаем
   (×0.85): место, которое буквы забрали, приходится откуда-то взять. */
@media (max-height: 499px) and (orientation: landscape) {
  :root {
    --gg-scale: calc(var(--ui-scale) * 1.28);
    --gg-space: calc(var(--ui-space) * 0.85);
    --gg-text: calc(1.06 / var(--ui-scale));
    --gg-width: 520px;
    --gg-lead: 24px;
  }
  /* 96 % вместо 92 %: в узком гейте («Друзья», окно профиля) четырёх процентов
     как раз хватает, чтобы строка не переломилась надвое, а с ней не выросла
     и высота. Поле сверху — под ленту «Заблокировано»: она висит выше плашки,
     и без запаса ложилась бы на то, что стоит над гейтом. */
  .sp2-guest-overlay { padding-top: calc(28px * var(--gg-space)); }
  .sp2-guest-plaque { width: min(96%, var(--gg-width)); }
  .sp2-guest-lock   { margin-top: 0; }
  /* Карточка «Друзей» и дуэлей с другом ужата под свой список (720×--ui-scale =
     518 px на телефоне), и плашке в ней не хватало полусотни пикселей: строки
     ломались надвое, высота росла, а замок отдавал ей всё своё место и оставался
     сплющенным. Когда в карточке ПЛАШКА, а не список, ширину меряем от плашки:
     её предел плюс поля карточки. :has() — прогрессивно: где его нет, карточка
     просто останется прежней, и плашка в ней всё равно уместится (max-height). */
  .fp-card:has(.sp2-guest-gate),
  .df-card:has(.sp2-guest-gate) { width: min(calc(var(--gg-width) + 120px), 94vw); }
  /* Меру строки снимаем: на широкой плашке она и есть предел ширины, а ради
     одной строки вместо двух весь размен и затевался. */
  .sp2-guest-plaque-text,
  .sp2-guest-plaque-hint { max-width: 100%; }
}

/* Очень низкий ландшафт (Fold в развороте, ~280 px): плашка гостя не влезала —
   нижний край свисал за экран, а кнопка-подсказка уезжала под обрез. Полного
   размера буквы туда не входят, поэтому берём 0.8 от него — это всё равно
   в полтора раза крупнее прежнего, — и дополнительно ужимаем зазоры.

   Замок при этом меряется как ступенью выше (×1.28), а не мельче её. Сюда же
   попадает обычный телефон в оболочке: экран 2712×1220 при плотности 3.5 — это
   349 CSS-пикселей, и места в плашке там с запасом. Где его правда нет (тот же
   Fold), замок отдаёт высоту сам — max-height плашки и flex-shrink на нём. */
@media (max-height: 379px) and (orientation: landscape) {
  :root {
    --gg-scale: calc(var(--ui-scale) * 1.28);
    --gg-space: calc(var(--ui-space) * 0.72);
    --gg-text: calc(0.8 / var(--ui-scale));
    --gg-width: 480px;
    --gg-lead: 18px;
  }
  .sp2-guest-overlay { padding: calc(22px * var(--gg-space)) calc(8px * var(--gg-space)) calc(8px * var(--gg-space)); }
  .sp2-guest-plaque  { gap: calc(6px * var(--gg-space));
                       padding: var(--gg-lead) calc(18px * var(--gg-space)) calc(14px * var(--gg-space)); }
  .sp2-guest-plaque-text { line-height: 1.3; }
}

/* ── Всплывающее окно (авторизация / выбор пола) ── */
.sp2-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(20,10,35,0.55);
  backdrop-filter: blur(2px);
}
.sp2-modal {
  background: #fff;
  border-radius: 22px;
  padding: calc(24px * var(--ui-space));
  max-width: 360px;
  width: 82%;
  text-align: center;
  box-shadow: 0 12px 40px rgba(40,20,70,0.35);
  display: flex;
  flex-direction: column;
  gap: calc(14px * var(--ui-space));
}
.sp2-modal-title {
  font-size: var(--fs-20);
  font-weight: 900;
  color: #2a1a40;
}
.sp2-modal-text {
  font-size: var(--fs-14);
  color: rgba(42,26,64,0.72);
  line-height: 1.4;
}
.sp2-modal-btn {
  min-height: calc(50px * var(--ui-scale));
  padding: 0 calc(18px * var(--ui-space));
  font-size: var(--fs-16);
  font-weight: 800;
  border: none;
  border-radius: 50px;
  background: linear-gradient(135deg, #9b6fc8, #7b3fbe);
  color: #fff;
  cursor: pointer;
  transition: transform 0.10s;
}
.sp2-modal-btn:hover  { transform: scale(1.04); }
.sp2-modal-btn:active { transform: scale(0.95); }
.sp2-gender-choices {
  display: flex;
  gap: calc(12px * var(--ui-space));
}
.sp2-gender-btn { flex: 1; }

/* Надетый аватар как фото профиля на кнопке главного меню */
.nav-fig-avatar {
  border-radius: 50%;
  object-fit: cover;
}


/* Shop button in bottom row */
.btn-shop {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border-color: rgba(224,112,32,0.5);
  color: #c8860a;
}


/* ─── Shop Tabs ─────────────────────────────────────────────── */


/* ─── LeaderboardPanel ───────────────────────────────────────────────────── */


.lb-title {
  font-size: calc(18px * var(--fs-scale));
  font-weight: 700;
  flex: 1;
  color: #2a1a40;
}


.lb-list {
  flex: 1;
  overflow-y: auto;
  padding: 0 16px 8px;
}

.lb-empty {
  text-align: center;
  color: rgba(42,26,64,0.5);
  padding: 40px 0;
  font-size: calc(14px * var(--fs-scale));
}

.lb-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 10px;
  margin-bottom: 4px;
  background: rgba(255,255,255,0.4);
  transition: background 0.15s;
}
.lb-row-me {
  background: rgba(201,184,232,0.45);
  border: 1px solid rgba(155,111,200,0.4);
}

.lb-rank {
  width: 26px;
  text-align: center;
  font-weight: 700;
  font-size: calc(14px * var(--fs-scale));
  color: rgba(42,26,64,0.5);
  flex-shrink: 0;
}
.lb-row:nth-child(1) .lb-rank { color: #c8860a; }
.lb-row:nth-child(2) .lb-rank { color: #888; }
.lb-row:nth-child(3) .lb-rank { color: #b06030; }

.lb-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  flex-shrink: 0;
  object-fit: cover;
}

.lb-name {
  flex: 1;
  font-size: calc(14px * var(--fs-scale));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: #2a1a40;
}

.lb-score {
  font-weight: 700;
  font-size: calc(15px * var(--fs-scale));
  color: #c8860a;
  flex-shrink: 0;
}


/* Medals override — the nth-child colour rules still apply for ranks 4+ */
.lb-row:nth-child(1) .lb-rank,
.lb-row:nth-child(2) .lb-rank,
.lb-row:nth-child(3) .lb-rank { color: inherit; } /* emoji handles colour */


/* ─── AuthScreen (startup fullscreen gate) ──────────────────────────────── */
/* --au — единица вёрстки формы входа, следует общему --ui-scale. Карточка
   всегда одноколоночная и не ужимается под высоту экрана: она ограничена
   вьюпортом, а её содержимое скроллится внутри (.auth-card-scroll). */
:root {
  --au: calc(1px * var(--ui-scale));
  /* Та же мерка, но для букв: --au ведёт и поля с кнопками, а расти
     должен только текст. Множитель — общий --fs-scale. */
  --au-text: calc(var(--au) * var(--fs-scale));
}

/* Полоса splash-арта в портрете — общая для сплэша и экрана входа, чтобы при
   переходе между ними героиня не прыгала. Высота — минимум из трёх ограничений:
     80vw  — героиня шириной в 1.18 высоты кадра, выше нельзя: срежет кроссовок;
     45vh  — на планшетах не даём арту съесть весь экран;
     остаток высоты — карточка входа (526 × --au) не должна уезжать в скролл. */
@media (max-aspect-ratio: 6 / 5) {
  :root {
    --auth-art-h: max(0px, min(80vw, 45vh, calc(100vh - 560 * var(--au))));
    /* пропорция самого арта от высоты полосы */
    --auth-art-w: calc(var(--auth-art-h) * var(--splash-art-ratio));
  }
}

.auth-screen {
  justify-content: center;
  align-items: center;
  gap: 0;
  padding: calc(16 * var(--au)) 3%;
  /* Подложка на случай, если арт ещё не догрузился: тон неба со splash */
  background: linear-gradient(180deg, #a9d9ef 0%, #cfe0f2 60%, #ecf0f7 100%);
  z-index: 10000;
  /* Скроллит не экран, а сама плашка — иначе полоса уезжала бы к краю окна */
  overflow: hidden;
}

/* Фон экрана входа — тот же арт сплэша, одним слоем и во весь экран.
   Кадр прижат влево и растянут по cover: героиня занимает левую половину
   картинки, поэтому её не режет ни один ландшафт — за край уходит только
   пустой фон справа. Никаких размытых добивок: арт всегда шире экрана.
   Правила-близнецы со .splash-img выше — правишь кадр здесь, правь и там. */
.auth-screen::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: var(--splash-art);
  background-repeat: no-repeat;
  background-position: left center;
  background-size: cover;
}

/* Уже 6:5 (все телефоны и планшеты в портрете) — cover режет героиню:
   кладём арт целиком на низ экрана, карточка живёт над ним, а пустоту сверху
   добирает размытый слой (::before) — тот же, что на сплэше, чтобы при
   переходе сплэш → форма входа фон не менялся.
   Высота полосы — минимум из трёх ограничений:
     80vw  — героиня шириной в 1.18 высоты кадра, шире нельзя: срежет кроссовок;
     45vh  — на планшетах не даём арту съесть весь экран;
     остаток высоты — карточка (526 × --au) не должна уезжать в скролл. */
@media (max-aspect-ratio: 6 / 5) {
  .auth-screen {
    padding-bottom: var(--auth-art-h);
  }
  .auth-screen::before {
    /* Вылет за края + scale — чтобы размытие не оголяло границы экрана.
       Кроп взят из правого верхнего угла арта (небо с шариками, героини там
       нет) и растянут по высоте, чтобы у стыка с полосой стояла та же
       голубизна, что и в верхней кромке самой картинки. */
    content: '';
    position: absolute;
    inset: -8%;
    z-index: 0;
    pointer-events: none;
    background-image: var(--splash-art);
    background-repeat: no-repeat;
    background-position: 82% 0%;
    background-size: auto 260%;
    filter: blur(52px) saturate(1.08) brightness(1.04);
    transform: scale(1.12);
  }
  .auth-screen::after {
    top: auto;
    height: var(--auth-art-h);
    background-size: auto 100%;
    background-position: left bottom;
    /* Обе кромки арта растворяются в размытом слое:
       — сверху 6% высоты полосы: это ровно полоска неба над макушкой (макушка
         на 5.5% от верха кадра), поэтому градиент съедает стык, а не волосы;
       — справа последние 48px картинки: страховка на случай, если арт окажется
         уже вьюпорта. Кадр 2.4:1 шире любого телефона, поэтому градиент уходит
         за край экрана и ничего не трогает. */
    -webkit-mask-image:
      linear-gradient(to bottom, transparent 0%, #000 6%),
      linear-gradient(to right, #000 calc(var(--auth-art-w) - 48px), transparent var(--auth-art-w));
            mask-image:
      linear-gradient(to bottom, transparent 0%, #000 6%),
      linear-gradient(to right, #000 calc(var(--auth-art-w) - 48px), transparent var(--auth-art-w));
    -webkit-mask-composite: source-in;
            mask-composite: intersect;
  }
}

/* Ландшафт: арт splash остаётся слева, карточка занимает свободную половину */
@media (orientation: landscape) and (min-height: 500px) {
  .auth-screen { padding-left: 52%; padding-right: 2%; }
}
/* Узкий ландшафт (планшет 4:3): героиня в кадре крупнее — отодвигаем карточку,
   чтобы она не легла на лицо */
@media (orientation: landscape) and (min-height: 500px) and (max-aspect-ratio: 3 / 2) {
  .auth-screen { padding-left: 58%; }
}

.auth-screen-card {
  position: relative;
  /* Над обоими слоями фона (::before/::after) */
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 0 1 auto;
  min-height: 0;
  /* Только отступ под полосу прокрутки: основные поля живут на .auth-card-scroll,
     иначе логотипу негде «прыгать» — overflow режет его по краю скролл-области */
  padding: calc(6 * var(--au)) calc(8 * var(--au));
  width: 100%;
  max-width: calc(330 * var(--au));
  max-height: 100%;
  border-radius: calc(30 * var(--au));
  /* Клипует внутренний скролл по скруглению; фон-подложка остаётся на месте */
  overflow: hidden;
  box-shadow: 0 calc(18 * var(--au)) calc(44 * var(--au)) rgba(90, 60, 140, 0.28);
  animation: auth-card-pop 0.3s cubic-bezier(0.34, 1.4, 0.64, 1);
}

/* Прокручиваемое нутро плашки: полоса прокрутки живёт внутри карточки */
.auth-card-scroll {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(12 * var(--au));
  width: 100%;
  min-height: 0;
  flex: 0 1 auto;
  /* Верхний запас (18) — под подпрыгивание логотипа и его drop-shadow */
  padding: calc(18 * var(--au)) calc(14 * var(--au)) calc(16 * var(--au));
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: rgba(155,111,200,0.45) transparent;
}
.auth-card-scroll::-webkit-scrollbar { width: calc(6 * var(--au)); }
.auth-card-scroll::-webkit-scrollbar-track { background: transparent; }
.auth-card-scroll::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, #d9c8ff, #ffd6eb);
  border-radius: calc(6 * var(--au));
}
@keyframes auth-card-pop {
  from { transform: scale(0.94); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}

/* Фон карточки: пастельный градиент + голографический ободок, как на плашке
   гостя в магазине. Клипует пузыри по скруглению. */
.auth-card-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  overflow: hidden;
  background: linear-gradient(160deg, rgba(238,247,255,0.97) 0%, rgba(245,241,255,0.97) 52%, rgba(253,239,247,0.97) 100%);
  border: calc(2 * var(--au)) solid rgba(255,255,255,0.9);
  box-shadow: 0 1px 0 rgba(255,255,255,0.95) inset;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  pointer-events: none;
}
.auth-card-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: calc(2 * var(--au));
  background: linear-gradient(115deg, #ffd6eb, #d9c8ff, #bfeaff, #c6f6e0, #fff0b8, #ffd6eb);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: 0.75;
}

.auth-card-bubble {
  position: absolute;
  border-radius: 50%;
  filter: blur(6px);
  animation: auth-bubble-drift 7s ease-in-out infinite;
}
.auth-card-bubble--a {
  width: calc(96 * var(--au)); height: calc(96 * var(--au));
  top: calc(-24 * var(--au)); right: calc(-24 * var(--au));
  background: radial-gradient(circle at 34% 30%, #ffe4f2, #ffc2e0 72%);
  opacity: 0.5;
}
.auth-card-bubble--b {
  width: calc(70 * var(--au)); height: calc(70 * var(--au));
  bottom: calc(-22 * var(--au)); left: calc(-20 * var(--au));
  background: radial-gradient(circle at 34% 30%, #fff6d6, #ffe694 72%);
  opacity: 0.45;
  animation-delay: -2.4s;
}
.auth-card-bubble--c {
  width: calc(44 * var(--au)); height: calc(44 * var(--au));
  bottom: calc(30 * var(--au)); right: calc(-14 * var(--au));
  background: radial-gradient(circle at 34% 30%, #e8fff6, #b6efd8 72%);
  opacity: 0.4;
  animation-delay: -4.8s;
}
@keyframes auth-bubble-drift {
  0%, 100% { transform: translateY(0)    scale(1);    }
  50%      { transform: translateY(-8px) scale(1.04); }
}

@media (prefers-reduced-motion: reduce) {
  .auth-screen-card,
  .auth-card-bubble,
  .auth-screen-logo-img { animation: none; }
}

.auth-screen-head,
.auth-screen-main {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  min-width: 0;
}
.auth-screen-head { gap: calc(6 * var(--au)); }
.auth-screen-main { gap: calc(12 * var(--au)); }

.auth-screen-logo-img {
  max-width: calc(240 * var(--au));
  width: 100%;
  height: auto;
  display: block;
  margin: 0 auto;
  filter: drop-shadow(0 calc(3 * var(--au)) calc(14 * var(--au)) rgba(200, 120, 255, 0.5));
  animation: auth-logo-float 4.5s ease-in-out infinite;
}
/* Амплитуда в --au: запас под неё заложен в padding-top у .auth-card-scroll */
@keyframes auth-logo-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(calc(-4 * var(--au))); }
}

.auth-screen-tagline {
  font-family: 'Segoe UI', system-ui, sans-serif;
  font-size: calc(14 * var(--au-text));
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1.25;
  text-align: center;
  background: linear-gradient(120deg, #ff6fb8 0%, #a95ce0 55%, #6f5cec 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

/* Ландшафт телефона: карточка остаётся одной колонкой и скроллится по вертикали,
   splash-арт сдвигается меньше — иначе узкая колонка не влезает по ширине */
@media (orientation: landscape) and (max-height: 499px) {
  .auth-screen { padding-left: 44%; padding-right: 2%; }
  .auth-screen-logo-img { max-width: calc(200 * var(--au)); }
}

/* ─── AuthPanel ──────────────────────────────────────────────────────────── */
/* Фон непрозрачный: сквозь 0.97 просвечивали строки настроек под панелью */
.auth-panel {
  background: linear-gradient(160deg, #a8d8f0 0%, #c9b8e8 50%, #f0c0d8 100%);
  align-items: stretch;
  justify-content: flex-start;
  padding: 0;
  gap: 0;
  overflow: hidden;
}

.auth-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(14px * var(--ui-space));
  padding: calc(28px * var(--ui-space)) calc(24px * var(--ui-space));
  flex: 1;
  overflow-y: auto;
}


.auth-avatar {
  width: calc(72px * var(--ui-scale));
  height: calc(72px * var(--ui-scale));
  border-radius: 20px;
  object-fit: cover;
}
.auth-avatar-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(155,111,200,0.4);
  font-weight: 700;
  font-size: calc(28px * var(--ui-scale));
  color: #fff;
}


.auth-email {
  font-size: var(--fs-13);
  color: rgba(42,26,64,0.5);
  margin-top: -8px;
}

.auth-desc {
  margin-top: calc(2 * var(--au));
  font-size: calc(13 * var(--au-text));
  font-weight: 600;
  color: #6b5590;
  text-align: center;
  max-width: calc(300 * var(--au));
  line-height: 1.45;
}

.auth-uid-label { font-size: calc(12px * var(--fs-scale)); color: rgba(42,26,64,0.5); }
.auth-uid {
  flex: 1;
  font-size: calc(12px * var(--fs-scale));
  color: #7b3fbe;
  font-family: monospace;
}

/* Конфетные 3D-кнопки: объём даёт «дно» из сплошной тени, нажатие его съедает */
.btn-auth {
  position: relative;
  width: 100%;
  max-width: calc(300 * var(--au));
  padding: calc(13 * var(--au)) calc(20 * var(--au));
  border: none;
  border-radius: calc(17 * var(--au));
  font-family: 'Segoe UI', system-ui, sans-serif;
  font-size: calc(15 * var(--au-text));
  font-weight: 700;
  line-height: 1.2;
  cursor: pointer;
  transition: transform 0.1s, box-shadow 0.1s, filter 0.15s;
}
/* Верхний блик — как на глянцевых шарах */
.btn-auth::before {
  content: '';
  position: absolute;
  left: calc(4 * var(--au));
  right: calc(4 * var(--au));
  top: calc(3 * var(--au));
  height: 42%;
  border-radius: calc(14 * var(--au));
  background: linear-gradient(180deg, rgba(255,255,255,0.5), rgba(255,255,255,0));
  pointer-events: none;
}

.btn-auth-primary {
  background: linear-gradient(180deg, #cba4ff 0%, #9d63ef 52%, #8a49e2 100%);
  color: #fff;
  text-shadow: 0 calc(1 * var(--au)) calc(2 * var(--au)) rgba(60,25,110,0.28);
  box-shadow:
    0 calc(5 * var(--au)) 0 #6b34bd,
    0 calc(10 * var(--au)) calc(20 * var(--au)) rgba(138,73,226,0.38);
}
.btn-auth-primary:hover:not(:disabled) { filter: brightness(1.06); }
.btn-auth-primary:active:not(:disabled) {
  transform: translateY(calc(4 * var(--au)));
  box-shadow: 0 calc(1 * var(--au)) 0 #6b34bd;
}

/* Гостевой вход — второстепенное действие: белая «пилюля» вместо заливки */
.btn-guest {
  background: linear-gradient(180deg, #ffffff 0%, #f3ecfd 100%);
  color: #7b3fbe;
  box-shadow:
    0 calc(5 * var(--au)) 0 #dccbf2,
    0 calc(9 * var(--au)) calc(18 * var(--au)) rgba(140,100,200,0.22);
}
.btn-guest:hover:not(:disabled) { filter: brightness(1.03); }
.btn-guest:active:not(:disabled) {
  transform: translateY(calc(4 * var(--au)));
  box-shadow: 0 calc(1 * var(--au)) 0 #dccbf2;
}
.btn-guest::before { background: none; }

.btn-auth:disabled { opacity: 0.55; cursor: default; }
.btn-auth-primary.is-busy { opacity: 0.7; }

/* ─── AuthForm (email + пароль) ──────────────────────────────────────────── */
.auth-form-wrap {
  width: 100%;
  max-width: calc(300 * var(--au));
  display: flex;
  flex-direction: column;
  gap: calc(10 * var(--au));
}

/* Сегменты «Вход / Регистрация» — вдавленная дорожка, выпуклая активная пилюля */
.auth-tabs {
  display: flex;
  gap: calc(4 * var(--au));
  padding: calc(4 * var(--au));
  border-radius: calc(16 * var(--au));
  background: rgba(155,111,200,0.12);
  box-shadow: inset 0 calc(2 * var(--au)) calc(5 * var(--au)) rgba(120,80,180,0.14);
}

.auth-tab {
  flex: 1;
  padding: calc(9 * var(--au)) 0;
  border: none;
  border-radius: calc(12 * var(--au));
  background: transparent;
  color: #7c66a6;
  font-family: 'Segoe UI', system-ui, sans-serif;
  font-size: calc(13 * var(--au-text));
  font-weight: 700;
  cursor: pointer;
  transition: all 0.15s;
}
.auth-tab.is-active {
  background: linear-gradient(180deg, #ffffff 0%, #f6f0ff 100%);
  color: #6f3fb8;
  box-shadow:
    0 calc(3 * var(--au)) 0 rgba(155,111,200,0.26),
    0 calc(6 * var(--au)) calc(12 * var(--au)) rgba(155,111,200,0.16);
}
.auth-tab:disabled { cursor: default; }

.auth-form {
  display: flex;
  flex-direction: column;
  gap: calc(9 * var(--au));
}

.auth-field {
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--au));
}
/* [hidden] обязан победить display:flex — иначе поля регистрации видны во «Входе» */
.auth-field[hidden] { display: none; }

.auth-field-label {
  font-family: 'Segoe UI', system-ui, sans-serif;
  font-size: calc(10.5 * var(--au-text));
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #8a76ad;
  padding-left: calc(4 * var(--au));
}

.auth-input {
  width: 100%;
  padding: calc(11 * var(--au)) calc(14 * var(--au));
  border-radius: calc(14 * var(--au));
  border: calc(2 * var(--au)) solid #e6dcf7;
  background: #fff;
  color: #3a2a5c;
  font-size: calc(14.5 * var(--au-text));
  font-family: inherit;
  box-shadow: inset 0 calc(2 * var(--au)) calc(4 * var(--au)) rgba(120,80,180,0.07);
  transition: border-color 0.15s, box-shadow 0.15s;
}
.auth-input::placeholder { color: #b3a5c9; }
.auth-input:focus {
  outline: none;
  border-color: #c9a6ee;
  box-shadow:
    0 0 0 calc(3 * var(--au)) rgba(190,140,240,0.22),
    inset 0 calc(2 * var(--au)) calc(4 * var(--au)) rgba(120,80,180,0.07);
}
.auth-input:disabled { opacity: 0.6; }

.auth-gender { display: flex; gap: calc(8 * var(--au)); }

.auth-gender-btn {
  position: relative;
  flex: 1;
  padding: calc(10 * var(--au)) 0;
  border-radius: calc(14 * var(--au));
  border: calc(2 * var(--au)) solid #e6dcf7;
  background: linear-gradient(180deg, #ffffff 0%, #f7f3ff 100%);
  color: #6b5590;
  font-family: 'Segoe UI', system-ui, sans-serif;
  font-size: calc(13 * var(--au-text));
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 calc(3 * var(--au)) 0 #e8ddf8;
  transition: transform 0.1s, box-shadow 0.1s, background 0.15s, color 0.15s;
}
/* Блик появляется вместе с выбором — невыбранная кнопка остаётся матовой */
.auth-gender-btn::before {
  content: '';
  position: absolute;
  left: calc(4 * var(--au));
  right: calc(4 * var(--au));
  top: calc(3 * var(--au));
  height: 40%;
  border-radius: calc(11 * var(--au));
  background: linear-gradient(180deg, rgba(255,255,255,0.55), rgba(255,255,255,0));
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s;
}
.auth-gender-btn.is-active::before { opacity: 1; }
.auth-gender-btn:active:not(:disabled) {
  transform: translateY(calc(2 * var(--au)));
  box-shadow: 0 calc(1 * var(--au)) 0 #e8ddf8;
}
/* Выбранный пол подсвечен «своим» цветом — как аватары в магазине.
   Пастель светлая, поэтому подпись тёмная «своего» оттенка, а не белая. */
.auth-gender-btn.is-active {
  border-color: rgba(255,255,255,0.85);
  text-shadow: 0 calc(1 * var(--au)) 0 rgba(255,255,255,0.5);
}
/* Внутренняя тень снизу «округляет» кнопку — как затемнённый бок у леденца */
.auth-gender-btn.is-active[data-gender="male"] {
  background: linear-gradient(180deg, #cfeaf8 0%, #a5d5ec 50%, #86c2e0 100%);
  color: #1c5c85;
  box-shadow:
    inset 0 calc(-4 * var(--au)) calc(8 * var(--au)) rgba(30,110,160,0.18),
    0 calc(3 * var(--au)) 0 #6fadd0,
    0 calc(6 * var(--au)) calc(12 * var(--au)) rgba(134,194,224,0.42);
}
.auth-gender-btn.is-active[data-gender="female"] {
  background: linear-gradient(180deg, #fbdcee 0%, #f5bbda 50%, #eda0c8 100%);
  color: #a63a76;
  box-shadow:
    inset 0 calc(-4 * var(--au)) calc(8 * var(--au)) rgba(180,60,130,0.16),
    0 calc(3 * var(--au)) 0 #dc86b4,
    0 calc(6 * var(--au)) calc(12 * var(--au)) rgba(237,160,200,0.42);
}
.auth-gender-btn:disabled { cursor: default; opacity: 0.6; }

.auth-error {
  margin: 0;
  padding: calc(8 * var(--au)) calc(11 * var(--au));
  border-radius: calc(12 * var(--au));
  background: #ffeef2;
  border: calc(2 * var(--au)) solid rgba(240,120,150,0.35);
  color: #d1436a;
  font-size: calc(12 * var(--au-text));
  font-weight: 700;
  text-align: center;
}
.auth-error[hidden] { display: none; }

/* Разделитель «или» между формой и гостевым входом */
.auth-divider {
  display: flex;
  align-items: center;
  gap: calc(10 * var(--au));
  width: 100%;
  max-width: calc(300 * var(--au));
  color: #9a88b8;
  font-size: calc(10.5 * var(--au-text));
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.auth-divider::before,
.auth-divider::after {
  content: '';
  flex: 1;
  height: calc(2 * var(--au));
  border-radius: 2px;
  background: rgba(155,111,200,0.22);
}

/* ─── Выбор способа входа: почта, ВКонтакте, Яндекс (ui/modals/AuthForm.js) ── */
/* Три равноправные кнопки столбиком в пастельно-конфетной гамме: почта —
   лавандовая, сервисы — в своих цветах, разбавленных до леденцовых.
   [hidden] обязан победить display:flex, иначе выбор остаётся на экране
   поверх открытой формы. */
.auth-methods {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(9 * var(--au));
  width: 100%;
}
.auth-methods[hidden] { display: none; }

/* Углы — общие для всех кнопок входа (.btn-auth), своего скругления здесь нет.
   Блик берём заметнее обычного: пастельная заливка без него выглядит плоской
   плёнкой, а тень под буквами держит белый текст читаемым на светлом верхе. */
.auth-method {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(9 * var(--au));
  padding: calc(12 * var(--au)) calc(14 * var(--au));
  color: #fff;
  text-shadow: 0 calc(1 * var(--au)) calc(3 * var(--au)) rgba(40,20,80,0.30);
}
.auth-method::before {
  background: linear-gradient(180deg, rgba(255,255,255,0.62), rgba(255,255,255,0));
}
.auth-method-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Буквенная метка вместо логотипа: чужие знаки в assets/ не лежат (см. AuthForm.js). */
.auth-method-mark {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(24 * var(--au));
  height: calc(24 * var(--au));
  border-radius: calc(8 * var(--au));
  background: #fff;
  font-size: calc(12 * var(--au-text));
  font-weight: 900;
  letter-spacing: -0.02em;
}
/* Пастельные леденцы: лаванда, небесно-голубой, коралл. Верх почти белый, низ
   держит цвет — иначе кнопка сливается с фоном экрана входа. Фирменные цвета
   сервисов сюда разбавлены, узнаваемость держит буквенная метка. */
.auth-method--email {
  background: linear-gradient(180deg, #e6d2ff 0%, #b98efa 52%, #a06cf3 100%);
  box-shadow:
    0 calc(5 * var(--au)) 0 #8552dd,
    0 calc(9 * var(--au)) calc(18 * var(--au)) rgba(160,108,243,0.34);
}
.auth-method--email:active:not(:disabled) {
  box-shadow: 0 calc(1 * var(--au)) 0 #8552dd;
}
.auth-method--email .auth-method-mark { color: #a06cf3; }

.auth-method--vk {
  background: linear-gradient(180deg, #c2e9ff 0%, #74c8fb 52%, #4fb3f4 100%);
  box-shadow: 0 calc(5 * var(--au)) 0 #3494d6, 0 calc(9 * var(--au)) calc(18 * var(--au)) rgba(79,179,244,0.34);
}
.auth-method--vk:hover:not(:disabled) { filter: brightness(1.06); }
.auth-method--vk:active:not(:disabled) {
  transform: translateY(calc(4 * var(--au)));
  box-shadow: 0 calc(1 * var(--au)) 0 #3494d6;
}
.auth-method--vk .auth-method-mark { color: #2f9be6; }

.auth-method--yandex {
  background: linear-gradient(180deg, #ffcdbe 0%, #ff9880 52%, #ff7d63 100%);
  box-shadow: 0 calc(5 * var(--au)) 0 #e35f46, 0 calc(9 * var(--au)) calc(18 * var(--au)) rgba(255,125,99,0.32);
}
.auth-method--yandex:hover:not(:disabled) { filter: brightness(1.06); }
.auth-method--yandex:active:not(:disabled) {
  transform: translateY(calc(4 * var(--au)));
  box-shadow: 0 calc(1 * var(--au)) 0 #e35f46;
}
.auth-method--yandex .auth-method-mark { color: #f26a4d; }

/* Возврат от полей почты к выбору способа. Тот же вид, что у .auth-reg-back в
   панели профиля, но в единицах экрана входа (--au). */
.auth-form-back {
  align-self: flex-start;
  padding: calc(5 * var(--au)) calc(12 * var(--au));
  border: none;
  border-radius: 50px;
  background: rgba(155,111,200,0.12);
  font-family: 'Segoe UI', system-ui, sans-serif;
  font-size: calc(12 * var(--au-text));
  font-weight: 700;
  color: #7b3fbe;
  cursor: pointer;
  transition: transform 0.1s, background 0.15s;
}
.auth-form-back:hover:not(:disabled)  { background: rgba(155,111,200,0.2); }
.auth-form-back:active:not(:disabled) { transform: scale(0.95); }

/* Форма второго шага скрыта, пока способ не выбран. Правило накрывает и форму
   кода (.auth-code-form несёт тот же .auth-form) — [hidden] обязан победить
   display:flex, иначе скрытая форма остаётся на экране. */
.auth-form[hidden] { display: none; }
/* На шаге кода вкладки «Вход / Регистрация» убираются целиком (см. AuthForm.js). */
.auth-tabs[hidden] { display: none; }

/* ─── Шаг 3: код из письма (ui/modals/AuthForm.js) ──────────────────────────── */
/* Подпись «Код отправлен на …» — тихая плашка над полем: она объясняет, почему
   игрок вдруг оказался не в игре, а в почте, и должна читаться раньше поля. */
.auth-code-note {
  margin: 0;
  padding: calc(9 * var(--au)) calc(12 * var(--au));
  border-radius: calc(12 * var(--au));
  background: #f6f1ff;
  border: calc(2 * var(--au)) solid #e6dcf7;
  color: #6b5590;
  font-size: calc(11.5 * var(--au-text));
  line-height: 1.5;
  text-align: center;
}
.auth-code-mail {
  color: #7b3fbe;
  font-weight: 700;
  word-break: break-all;   /* длинный адрес не должен распирать карточку входа */
}

/* Само поле кода: моноширинный шрифт и разрядка — восемь знаков читаются по
   одному, как в письме, и опечатка видна глазом до нажатия «Подтвердить». */
.auth-code-input {
  font-family: 'Courier New', Courier, monospace;
  font-size: calc(19 * var(--au-text));
  font-weight: 700;
  letter-spacing: 0.22em;
  text-align: center;
  text-transform: uppercase;
}
.auth-code-input::placeholder {
  font-family: 'Segoe UI', system-ui, sans-serif;
  font-size: calc(13 * var(--au-text));
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}

/* «Отправить письмо ещё раз» — не кнопка-леденец: это запасной путь, и выглядеть
   он должен ссылкой под главной кнопкой, а не спорить с ней за нажатие. */
.auth-code-resend {
  align-self: center;
  padding: calc(6 * var(--au)) calc(12 * var(--au));
  border: none;
  border-radius: 50px;
  background: none;
  font-family: 'Segoe UI', system-ui, sans-serif;
  font-size: calc(12 * var(--au-text));
  font-weight: 700;
  color: #7b3fbe;
  text-decoration: underline;
  text-underline-offset: calc(3 * var(--au));
  cursor: pointer;
  transition: transform 0.1s, background 0.15s;
}
.auth-code-resend:hover:not(:disabled)  { background: rgba(155,111,200,0.14); }
.auth-code-resend:active:not(:disabled) { transform: scale(0.95); }
.auth-code-resend:disabled { opacity: 0.5; cursor: default; }

/* Добрая весть («письмо отправлено») — зелёная сестра .auth-error: одинаковая
   плашка, другой смысл, и красная рамка отказа для неё не годится. */
.auth-note {
  margin: 0;
  padding: calc(8 * var(--au)) calc(11 * var(--au));
  border-radius: calc(12 * var(--au));
  background: #ecfbf1;
  border: calc(2 * var(--au)) solid rgba(90,200,140,0.38);
  color: #2f8f5b;
  font-size: calc(12 * var(--au-text));
  font-weight: 700;
  text-align: center;
}
.auth-note[hidden] { display: none; }

/* Шаг «Создать аккаунт» для гостя: конфетная плашка, как .sp2-guest-plaque */
/* Форма скроллится, поэтому её верх обязан начинаться под топбаром:
   высота топбара = кнопка «закрыть» + его вертикальные отступы. */
.auth-body-form {
  justify-content: flex-start;
  padding-top: calc(64px * var(--ui-scale) + min(24px, 3.5vh));
  overflow-y: auto;
  overflow-x: hidden;
}

.auth-reg-plaque {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(6px * var(--ui-space));
  width: min(100%, 360px);
  padding: calc(20px * var(--ui-space)) calc(20px * var(--ui-space)) calc(22px * var(--ui-space));
  box-sizing: border-box;
  text-align: center;
  border-radius: calc(30px * var(--ui-scale));
  box-shadow: 0 20px 46px rgba(90,60,140,0.24);
  animation: sp2-guest-pop 0.28s cubic-bezier(0.34, 1.4, 0.64, 1);
}
.auth-reg-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  overflow: hidden;
  background: linear-gradient(160deg, #eef7ff 0%, #f5f1ff 52%, #fdeff7 100%);
  border: 2px solid rgba(255,255,255,0.9);
  box-shadow: 0 1px 0 rgba(255,255,255,0.95) inset;
  pointer-events: none;
}
.auth-reg-bubble {
  position: absolute;
  border-radius: 50%;
  opacity: 0.5;
  animation: auth-bubble-drift 7s ease-in-out infinite;
}
.auth-reg-bubble--a {
  width: calc(70 * var(--au)); height: calc(70 * var(--au));
  top: -10%; right: -6%;
  background: radial-gradient(circle at 30% 30%, #ffd9ec, rgba(255,217,236,0));
}
.auth-reg-bubble--b {
  width: calc(52 * var(--au)); height: calc(52 * var(--au));
  bottom: 6%; left: -6%;
  background: radial-gradient(circle at 30% 30%, #d4e8ff, rgba(212,232,255,0));
  animation-delay: -2.5s;
}
.auth-reg-bubble--c {
  width: calc(36 * var(--au)); height: calc(36 * var(--au));
  top: 42%; right: -4%;
  background: radial-gradient(circle at 30% 30%, #e6dbff, rgba(230,219,255,0));
  animation-delay: -4.5s;
}
@media (prefers-reduced-motion: reduce) {
  .auth-reg-plaque, .auth-reg-bubble { animation: none; }
}

/* Возврат к выбору «зарегистрироваться / выйти» */
.auth-reg-back {
  position: relative;
  z-index: 1;
  align-self: flex-start;
  padding: calc(4px * var(--ui-space)) calc(10px * var(--ui-space));
  margin-bottom: calc(2px * var(--ui-space));
  border: none;
  border-radius: 50px;
  background: rgba(155,111,200,0.12);
  font-family: inherit;
  font-size: var(--fs-13);
  font-weight: 700;
  color: #7b3fbe;
  cursor: pointer;
  transition: transform 0.1s, background 0.15s;
}
.auth-reg-back:hover  { background: rgba(155,111,200,0.2); }
.auth-reg-back:active { transform: scale(0.95); }

.auth-reg-title {
  position: relative;
  z-index: 1;
  font-size: var(--fs-22);
  font-weight: 900;
  line-height: 1.2;
  background: linear-gradient(120deg, #ff6fb8 0%, #a95ce0 55%, #6f5cec 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.auth-reg-desc {
  position: relative;
  z-index: 1;
  margin: 0 0 calc(6px * var(--ui-space));
  max-width: calc(280px * var(--ui-scale));
  font-size: var(--fs-13);
  font-weight: 600;
  color: #6b5590;
  line-height: 1.45;
}
.auth-reg-plaque .auth-form-wrap {
  position: relative;
  z-index: 1;
  width: 100%;
  text-align: left;
}

/* Подтверждение выхода: «Остаться» — яркая кнопка, «Выйти» — невзрачная.
   Обе в сиреневой гамме игры: уход не подсвечиваем красным. */
.auth-modal-actions {
  display: flex;
  gap: calc(10px * var(--ui-space));
}
.auth-modal-actions .sp2-modal-btn { flex: 1; }
.sp2-modal-btn--ghost {
  background: #f3ecfd;
  color: #9080ab;
  font-weight: 700;
  box-shadow: inset 0 0 0 1px rgba(155,111,200,0.18);
}
.sp2-modal-btn:disabled {
  opacity: 0.6;
  cursor: default;
  transform: none !important;
}

.btn-signout {
  background: rgba(192,64,90,0.1);
  border-color: rgba(192,64,90,0.3);
  color: #c0405a;
}
.btn-signout:hover { background: rgba(192,64,90,0.18); }

/* ─── Auth panel — settings-style rows ──────────────────── */
.auth-profile-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: min(10px, 1.5vh);
  padding: 0;
  width: 100%;
  max-width: 360px;
  flex-shrink: 0;
}

/* Аватар: без обводки, только мягкое сиреневое сияние под ним */
.auth-profile-hero .auth-avatar,
.auth-profile-hero .auth-avatar-placeholder {
  width: min(158px, 22vh);
  height: min(158px, 22vh);
  font-size: min(62px, 9vh);
  border-radius: 50%;
  box-shadow: 0 calc(10px * var(--ui-scale)) calc(26px * var(--ui-scale)) rgba(120,80,180,0.30);
}

/* Ник — мягкий градиент в пределах тёмно-фиолетовой гаммы, без розового */
.auth-profile-name {
  font-size: min(calc(22px * var(--fs-scale)), 3vh);
  font-weight: 900;
  letter-spacing: 0.01em;
  background: linear-gradient(120deg, #3f2a63 0%, #6b4796 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.auth-email-small {
  font-size: min(calc(12px * var(--fs-scale)), 1.8vh);
  color: rgba(42,26,64,0.5);
}

/* «Гость» — пилюля-бейдж, а не подпись */
.auth-tag-guest {
  padding: calc(3px * var(--ui-scale)) calc(12px * var(--ui-scale));
  border-radius: 50px;
  background: rgba(255,255,255,0.6);
  border: 1px solid rgba(255,255,255,0.85);
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(8px * var(--ui-scale)) rgba(120,80,180,0.16);
  font-size: min(calc(11px * var(--fs-scale)), 1.6vh);
  font-weight: 800;
  color: #8a5cc4;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.auth-body-rows {
  justify-content: center;
  gap: min(14px, 1.8vh) !important;
  overflow: hidden;
}

/* ID игрока — «вдавленная» дорожка, как трек вкладок .auth-tabs.
   Все правила строк ниже идут через .auth-panel: голый .auth-cta-row проигрывал
   бы по каскаду блоку .sett-row (та же специфичность, но объявлен ниже по файлу). */
.auth-panel .auth-uid-sett-row {
  cursor: default;
  gap: 8px;
  background: rgba(255,255,255,0.40);
  border-color: rgba(255,255,255,0.65);
  box-shadow: inset 0 calc(2px * var(--ui-scale)) calc(5px * var(--ui-scale)) rgba(120,80,180,0.14);
}

.auth-divider-soft {
  background: linear-gradient(90deg,
    rgba(155,111,200,0) 0%, rgba(155,111,200,0.28) 50%, rgba(155,111,200,0) 100%);
}

/* Главное действие — конфетная 3D-кнопка в малиново-оранжевой гамме:
   «дно» из сплошной тени съедается нажатием */
.auth-panel .auth-cta-row {
  position: relative;
  cursor: pointer;
  border: none;
  background: linear-gradient(180deg, #ffd45e 0%, #ff9a3a 46%, #ef3f74 100%);
  box-shadow:
    0 calc(5px * var(--ui-scale)) 0 #c31f57,
    0 calc(11px * var(--ui-scale)) calc(22px * var(--ui-scale)) rgba(239,63,116,0.38);
  transition: transform 0.1s, box-shadow 0.1s, filter 0.15s;
}
/* Верхний блик — как на глянцевых шарах */
.auth-panel .auth-cta-row::before {
  content: '';
  position: absolute;
  left: calc(5px * var(--ui-scale));
  right: calc(5px * var(--ui-scale));
  top: calc(3px * var(--ui-scale));
  height: 42%;
  border-radius: calc(16px * var(--ui-scale));
  background: linear-gradient(180deg, rgba(255,255,255,0.40), rgba(255,255,255,0));
  pointer-events: none;
}
/* Блик — позиционированный псевдоэлемент: без z-index он бы лёг поверх текста */
.auth-panel .auth-cta-row > * { position: relative; z-index: 1; }
.auth-panel .auth-cta-row .sett-row-label {
  color: #fff;
  text-shadow: 0 calc(1px * var(--ui-scale)) calc(2px * var(--ui-scale)) rgba(150,25,60,0.35);
}
.auth-panel .auth-cta-row .sett-row-arrow { color: rgba(255,255,255,0.9); }
.auth-panel .auth-cta-row:hover { filter: brightness(1.06); }
.auth-panel .auth-cta-row:active {
  transform: translateY(calc(4px * var(--ui-scale)));
  box-shadow: 0 calc(1px * var(--ui-scale)) 0 #c31f57;
}

/* «Выйти» — конфетная 3D-кнопка в сиреневой гамме игры: глянцевый блик сверху,
   сплошная «подошва» снизу, которую съедает нажатие (как у .auth-cta-row). */
.auth-panel .auth-signout-row {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  border: none;
  cursor: pointer;
  background: linear-gradient(180deg, #c8aefb 0%, #a877ec 52%, #9660e0 100%);
  box-shadow:
    0 calc(5px * var(--ui-scale)) 0 #7742c4,
    0 calc(11px * var(--ui-scale)) calc(22px * var(--ui-scale)) rgba(138,73,226,0.34);
  transition: transform 0.1s, box-shadow 0.1s, filter 0.15s;
}
/* Верхний блик — как на глянцевых шарах */
.auth-panel .auth-signout-row::before {
  content: '';
  position: absolute;
  left: calc(5px * var(--ui-scale));
  right: calc(5px * var(--ui-scale));
  top: calc(3px * var(--ui-scale));
  height: 42%;
  border-radius: calc(16px * var(--ui-scale));
  background: linear-gradient(180deg, rgba(255,255,255,0.42), rgba(255,255,255,0));
  pointer-events: none;
}
.auth-panel .auth-signout-row > * { position: relative; z-index: 1; }
.auth-panel .auth-signout-row:hover  { filter: brightness(1.05); }
.auth-panel .auth-signout-row:active {
  transform: translateY(calc(4px * var(--ui-scale)));
  box-shadow: 0 calc(1px * var(--ui-scale)) 0 #7742c4;
}

.auth-signout-label {
  color: #fff !important;
  font-weight: 800;
  /* центрируем надпись по всей объёмной кнопке с учётом нижней «подошвы» (box-shadow 5px) */
  transform: translateY(calc(2.5px * var(--ui-scale)));
  text-shadow: 0 calc(1px * var(--ui-scale)) calc(2px * var(--ui-scale)) rgba(60,25,110,0.3);
}

/* Challenge banner (opened via ?challenge= URL) */
.challenge-banner {
  gap: 14px;
}

.cb-icon {
  font-size: 52px;
  line-height: 1;
  animation: cb-icon-pulse 1.2s ease-in-out infinite;
}

@keyframes cb-icon-pulse {
  0%, 100% { transform: scale(1) rotate(-5deg); }
  50%       { transform: scale(1.15) rotate(5deg); }
}

.cb-title {
  font-size: calc(26px * var(--fs-scale));
  font-weight: 900;
  color: #2a1a40;
  text-align: center;
}

.cb-desc {
  font-size: calc(17px * var(--fs-scale));
  color: rgba(42,26,64,0.65);
  text-align: center;
}

.cb-desc strong {
  color: #c8860a;
  font-weight: 900;
}

/* ─── Landscape-only overlay ────────────────────────────── */
#orient-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: linear-gradient(160deg, #a8d8f0 0%, #c9b8e8 50%, #f0c0d8 100%);
  align-items: center;
  justify-content: center;
}

.orient-msg {
  font-size: calc(20px * var(--fs-scale));
  font-weight: 700;
  color: #2a1a40;
  text-align: center;
  padding: 24px;
}

/* ─── Settings Panel ──────────────────────────────────────── */
.sett-panel {
  background: linear-gradient(160deg, rgba(168,216,240,0.97) 0%, rgba(201,184,232,0.97) 50%, rgba(240,192,216,0.97) 100%);
  align-items: stretch;
  justify-content: flex-start;
  padding: 0;
  gap: 0;
}

/* Топбар и тело кладутся в одну ячейку сетки: блок центрируется по всей высоте
   экрана, а не по остатку под заголовком. Сетка (в отличие от absolute)
   сохраняет несимметричные отступы .sett-layout, поэтому заголовок не съезжает. */
.sett-layout {
  display: grid;
  grid-template: "stack" 1fr / 1fr;
  width: 100%;
  height: 100%;
  overflow: hidden;
  padding: 0 12px 0 28px;
  box-sizing: border-box;
}

/* ── Top bar ── */
.sett-topbar {
  grid-area: stack;
  align-self: start;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: calc(10px * var(--ui-space));
  padding: min(calc(10px * var(--ui-space)), 1.5vh) calc(14px * var(--ui-space));
  background: transparent;
  flex-shrink: 0;
  min-height: 0;
  box-sizing: border-box;
  /* полоса заголовка лежит поверх тела — прозрачные её участки не должны
     перехватывать нажатия по строкам, которые заезжают под неё */
  pointer-events: none;
}
.sett-topbar-title,
.sett-topbar .sp2-close-btn {
  pointer-events: auto;
}

.sett-topbar-title {
  font-size: min(calc(26px * var(--ui-scale) * var(--fs-scale)), 4vh);
  font-weight: 900;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: #2a1a40;
  white-space: nowrap;
  flex-shrink: 0;
}

/* ── Body ── */
.sett-body {
  grid-area: stack;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
  padding: min(24px, 2vh) calc(20px * var(--ui-space));
  overflow: hidden;
}

/* ── Row ── */
.sett-row {
  display: flex;
  align-items: center;
  gap: calc(16px * var(--ui-space));
  width: 100%;
  max-width: 360px;
  flex: 1;
  min-height: 0;
  max-height: calc(72px * var(--ui-scale));
  padding: 0 calc(20px * var(--ui-space));
  background: rgba(255,255,255,0.55);
  border: 1.5px solid rgba(255,255,255,0.75);
  border-radius: 20px;
  cursor: default;
  box-shadow: 0 4px 18px rgba(155,111,200,0.12);
  transition: transform 0.12s;
}

.sett-row + .sett-row,
.sett-divider + .sett-row {
  margin-top: min(12px, 1.5vh);
}

.sett-divider {
  width: 100%;
  max-width: 360px;
  height: 1px;
  background: rgba(155,111,200,0.15);
  margin: min(8px, 1vh) 0;
  flex-shrink: 0;
}

.sett-row--account {
  cursor: pointer;
  background: linear-gradient(135deg, rgba(155,111,200,0.18) 0%, rgba(240,192,216,0.35) 100%);
  border-color: rgba(155,111,200,0.30);
}
.sett-row--account:hover  { transform: scale(1.02); }
.sett-row--account:active { transform: scale(0.97); }

.sett-row-icon-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  width: min(calc(36px * var(--ui-scale)), 5vh);
  height: min(calc(36px * var(--ui-scale)), 5vh);
  flex-shrink: 0;
}

.sett-row-img {
  width: min(calc(36px * var(--ui-scale)), 5vh);
  height: min(calc(36px * var(--ui-scale)), 5vh);
  object-fit: contain;
}


.sett-row-label {
  flex: 1;
  font-size: min(calc(17px * var(--ui-scale) * var(--fs-scale)), 2.8vh);
  font-weight: 700;
  color: #2a1a40;
  letter-spacing: 0.01em;
}

.sett-row-arrow {
  font-size: min(calc(22px * var(--ui-scale)), 3vh);
  color: rgba(155,111,200,0.7);
  font-weight: 700;
}

/* ── Toggle switch ── */
.sett-toggle {
  position: relative;
  width: min(calc(54px * var(--ui-scale)), 7.5vh);
  height: min(calc(30px * var(--ui-scale)), 4.2vh);
  border-radius: 50px;
  border: none;
  cursor: pointer;
  background: linear-gradient(135deg, #b07fe0 0%, #9b6fc8 100%);
  box-shadow: 0 3px 10px rgba(155,111,200,0.35);
  transition: background 0.22s, box-shadow 0.22s;
  flex-shrink: 0;
  padding: 0;
}

.sett-toggle--off {
  background: rgba(155,111,200,0.22);
  box-shadow: none;
}

.sett-toggle-knob {
  position: absolute;
  top: min(calc(3px * var(--ui-scale)), 0.42vh);
  left: min(calc(3px * var(--ui-scale)), 0.42vh);
  width: min(calc(24px * var(--ui-scale)), 3.36vh);
  height: min(calc(24px * var(--ui-scale)), 3.36vh);
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 2px 6px rgba(0,0,0,0.18);
  transition: transform 0.22s cubic-bezier(0.34,1.56,0.64,1);
  pointer-events: none;
}

.sett-toggle:not(.sett-toggle--off) .sett-toggle-knob {
  transform: translateX(min(calc(24px * var(--ui-scale)), 3.36vh));
}

/* ─── Landscape: ensure panels scroll & layout fills height ──
   Size scaling is done via CSS variables in :root above.
   Only layout/overflow rules remain here.
────────────────────────────────────────────────────────────── */
@media (orientation: landscape) {
  .screen {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  .menu-layout {
    height: 100%;
    position: relative;
  }
  /* Overlay the nav sidebar on the left so .menu-main spans the full width
     and the play block centres on the TRUE viewport centre, not the area to
     the right of the sidebar. (Landscape has plenty of room, so no overlap.) */
  .menu-sidebar {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    z-index: 3;
  }
  /* All content panels: allow scrolling on short screens */
  .shop-panel,
  .quests-panel {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
}

/* ── Shop sidenav: shrink to fit on short landscape screens ── */
@media (max-height: 560px) and (orientation: landscape) {
  /* Cards: single scrollable row, no vertical scroll.
     ВАЖНО: только в магазине. .sp2-content — общий класс, его использует ещё и
     «Статистика»; без .shop-panel этот overflow-y:hidden убивал ей вертикальную
     прокрутку, и на низком ландшафте нижний ряд цифр становился недостижим. */
  .shop-panel .sp2-content {
    overflow-x: hidden;
    overflow-y: hidden;
    touch-action: pan-x;
    align-items: stretch;
    justify-content: flex-start;
  }
  .sp2-cards-grid {
    flex-wrap: nowrap;
    justify-content: safe center;
    align-items: center;
    align-content: center;
    align-self: stretch;
    width: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -ms-overflow-style: none;
    cursor: grab;
    touch-action: pan-x;
  }
  .sp2-cards-grid:active { cursor: grabbing; }
  .sp2-cards-grid::-webkit-scrollbar { display: none; }
  /* Подарки и украшения: сетка с переносом строк и вертикальной прокруткой —
     та же раскладка лотов, что и на большом экране */
  .sp2-gifts-wrap, .sp2-decos-wrap { gap: calc(8px * var(--ui-space)); }
  /* .shop-panel — чтобы удельный вес был не ниже, чем у .shop-panel .sp2-content
     выше: иначе тот overflow-y:hidden перебил бы прокрутку витрины подарков. */
  .shop-panel .sp2-content--grid {
    overflow-y: auto;
    touch-action: pan-y;
    /* витрина по высоте — по содержимому, иначе ряд карточек растягивается
       на всю высоту контента и лоты выглядят вытянутыми */
    align-items: flex-start;
  }
  .sp2-content--grid .sp2-gifts-wrap,
  .sp2-content--grid .sp2-decos-wrap {
    align-self: flex-start;
    height: auto;
  }
  .sp2-content--grid .sp2-cards-grid {
    flex-wrap: wrap;
    overflow: visible;
    justify-content: center;
    align-content: flex-start;
    touch-action: pan-y;
    cursor: default;
  }
  .sp2-content--grid .sp2-cards-grid:active { cursor: default; }
  /* Карточка — своей высоты (ряд выравнивается по самой высокой), как в широкой вёрстке */
  .sp2-content--grid .sp2-offer-card { align-self: stretch; }
  /* Card: natural size, centered vertically, slightly scaled down */
  .sp2-offer-card {
    align-self: center;
    min-height: 0;
    height: auto;
    width: auto;
    min-width: calc(185px * var(--ui-scale));
    gap: calc(8px * var(--ui-space));
    padding: calc(18px * var(--ui-space)) calc(16px * var(--ui-space)) calc(16px * var(--ui-space));
    border-radius: 22px;
  }
  .sp2-offer-icon-wrap {
    width: calc(126px * var(--ui-scale));
    height: calc(126px * var(--ui-scale));
    flex-shrink: 0;
  }
  .sp2-offer-title  { font-size: var(--fs-13); }
  .sp2-buy-offer-btn {
    min-height: calc(38px * var(--ui-scale));
    font-size: var(--fs-13);
    padding: 0 calc(13px * var(--ui-space));
  }
  .sp2-offer-reward { font-size: var(--fs-12); padding: calc(4px * var(--ui-space)) calc(9px * var(--ui-space)); }
  .sp2-reward-icon  { width: calc(16px * var(--ui-scale)); height: calc(16px * var(--ui-scale)); }
  .sp2-offer-card--item {
    align-self: center;
    width: calc(185px * var(--ui-scale));
    white-space: normal;
    word-break: break-word;
  }

  .sp2-layout {
    padding-left: calc(8px * var(--ui-space));
  }
  /* Заголовок статистики держим на одной линии с магазином (8+14 на узких экранах).
     Селектор с .screen — чтобы перебить менее специфичный базовый .stats-panel .sp2-topbar,
     который в файле идёт ниже этого медиа-запроса. */
  .screen.stats-panel .sp2-topbar {
    padding-left: calc(22px * var(--ui-space));
  }
  .sp2-sidenav {
    width: clamp(52px, 18vw, 72px);
    gap: calc(4px * var(--ui-space));
    padding: calc(6px * var(--ui-space)) calc(6px * var(--ui-space));
    justify-content: stretch;
  }
  .sp2-nav-item {
    flex: 1;
    min-height: 0;
    padding: calc(4px * var(--ui-space)) calc(4px * var(--ui-space));
    font-size: var(--fs-10);
    border-radius: 12px;
    gap: 2px;
    overflow: hidden;
  }
  .sp2-nav-item > span:last-child {
    display: none;
  }
  .sp2-nav-icon-wrap {
    width: calc(40px * var(--ui-scale));
    height: calc(40px * var(--ui-scale));
    flex-shrink: 1;
    max-height: 80%;
  }
  .sp2-nav-img {
    width: 100%;
    height: 100%;
    max-width: calc(40px * var(--ui-scale));
    max-height: calc(40px * var(--ui-scale));
  }
}

/* ── Shop sidenav: icon-only on narrow portrait screens ── */
@media (max-width: 500px) and (orientation: portrait) {
  /* Cards: single scrollable row, no vertical scroll */
  .sp2-content {
    overflow-x: hidden;
    overflow-y: hidden;
    touch-action: pan-x;
    align-items: stretch;
    justify-content: flex-start;
  }
  .sp2-cards-grid {
    flex-wrap: nowrap;
    justify-content: safe center;
    align-items: center;
    align-content: center;
    align-self: stretch;
    width: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -ms-overflow-style: none;
    cursor: grab;
    touch-action: pan-x;
  }
  .sp2-cards-grid:active { cursor: grabbing; }
  .sp2-cards-grid::-webkit-scrollbar { display: none; }
  /* Подарки и украшения: сетка с переносом строк и вертикальной прокруткой —
     та же раскладка лотов, что и на большом экране */
  .sp2-gifts-wrap, .sp2-decos-wrap { gap: calc(8px * var(--ui-space)); }
  .sp2-content--grid {
    overflow-y: auto;
    touch-action: pan-y;
    /* витрина по высоте — по содержимому, иначе ряд карточек растягивается
       на всю высоту контента и лоты выглядят вытянутыми */
    align-items: flex-start;
  }
  .sp2-content--grid .sp2-gifts-wrap,
  .sp2-content--grid .sp2-decos-wrap {
    align-self: flex-start;
    height: auto;
  }
  .sp2-content--grid .sp2-cards-grid {
    flex-wrap: wrap;
    overflow: visible;
    justify-content: center;
    align-content: flex-start;
    touch-action: pan-y;
    cursor: default;
  }
  .sp2-content--grid .sp2-cards-grid:active { cursor: default; }
  /* Карточка — своей высоты (ряд выравнивается по самой высокой), как в широкой вёрстке */
  .sp2-content--grid .sp2-offer-card { align-self: stretch; }
  /* Card: natural size, centered vertically, slightly scaled down */
  .sp2-offer-card {
    align-self: center;
    min-height: 0;
    height: auto;
    width: auto;
    min-width: calc(188px * var(--ui-scale));
    gap: calc(9px * var(--ui-space));
    padding: calc(20px * var(--ui-space)) calc(16px * var(--ui-space)) calc(16px * var(--ui-space));
    border-radius: 22px;
  }
  .sp2-offer-icon-wrap {
    width: calc(128px * var(--ui-scale));
    height: calc(128px * var(--ui-scale));
    flex-shrink: 0;
  }
  .sp2-offer-title  { font-size: var(--fs-13); }
  .sp2-buy-offer-btn {
    min-height: calc(40px * var(--ui-scale));
    font-size: var(--fs-13);
    padding: 0 calc(13px * var(--ui-space));
  }
  .sp2-offer-reward { font-size: var(--fs-12); padding: calc(4px * var(--ui-space)) calc(9px * var(--ui-space)); }
  .sp2-reward-icon  { width: calc(17px * var(--ui-scale)); height: calc(17px * var(--ui-scale)); }
  .sp2-offer-card--item {
    align-self: center;
    width: calc(188px * var(--ui-scale));
    white-space: normal;
    word-break: break-word;
  }

  .sp2-layout {
    padding-left: calc(8px * var(--ui-space));
  }
  /* Заголовок статистики держим на одной линии с магазином (8+14 на узких экранах).
     Селектор с .screen — чтобы перебить менее специфичный базовый .stats-panel .sp2-topbar,
     который в файле идёт ниже этого медиа-запроса. */
  .screen.stats-panel .sp2-topbar {
    padding-left: calc(22px * var(--ui-space));
  }
  .sp2-sidenav {
    width: clamp(52px, 18vw, 72px);
    gap: calc(6px * var(--ui-space));
    padding: calc(8px * var(--ui-space)) calc(6px * var(--ui-space));
  }
  .sp2-nav-item {
    flex: 1;
    min-height: 0;
    padding: calc(6px * var(--ui-space)) calc(4px * var(--ui-space));
    font-size: var(--fs-10);
    border-radius: 14px;
    gap: 2px;
    overflow: hidden;
  }
  .sp2-nav-item > span:last-child {
    display: none;
  }
  .sp2-nav-icon-wrap {
    width: calc(44px * var(--ui-scale));
    height: calc(44px * var(--ui-scale));
    flex-shrink: 1;
    max-height: 100%;
  }
  .sp2-nav-img {
    width: 100%;
    height: 100%;
    max-width: calc(44px * var(--ui-scale));
    max-height: calc(44px * var(--ui-scale));
  }
  /* Фигурки магазина крупнее (как в главном меню), но в узкой портретной
     колонке ограничиваем, чтобы не обрезались краями */
  .shop-panel .sp2-nav-icon-wrap,
  .shop-panel .sp2-nav-img {
    width: calc(60px * var(--ui-scale));
    height: calc(60px * var(--ui-scale));
    max-width: calc(60px * var(--ui-scale));
    max-height: calc(60px * var(--ui-scale));
  }
}

/* ═══════════════════════════════════════════════════════════════
   COLLECTION PANEL
   ═══════════════════════════════════════════════════════════════ */

.col-panel {
  padding: 0;
  gap: 0;
  justify-content: flex-start;
  overflow: hidden;
}

.col-layout {
  /* inherits all from .sp2-layout — no overrides needed */
}

/* Top bar reuses .sp2-topbar — just add a tiny modifier if needed */
.col-topbar {
  flex-shrink: 0;
}

/* ── СУНДУЧОК с повторками ──────────────────────────────────────────────────
   Своя строка между заголовком и лентой обложек, по центру страницы.
   Картинку кладите в  assets/collection/chest.png  (или .webp — подхватится).
   Это КНОПКА: клик открывает магазин сундучка (.chest-shop-overlay ниже). */
.col-chest {
  flex-shrink: 0;
  align-self: center;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(8px * var(--ui-space));
  margin-top: calc(6px * var(--ui-space));
  padding: calc(4px * var(--ui-space)) calc(10px * var(--ui-space));
  background: none;
  border: none;
  cursor: pointer;
  transition: transform 0.14s;
}

.col-chest:hover  { transform: translateY(-2px) scale(1.04); }
.col-chest:active { transform: scale(0.96); }

.col-chest-img {
  width: calc(64px * var(--ui-scale));
  height: calc(64px * var(--ui-scale));
  object-fit: contain;
  display: block;
  filter: drop-shadow(0 3px 8px rgba(100,60,160,0.35));
}

/* Сколько повторок в сундучке — голое число без плашки и рамки,
   залито фирменным градиентом «сирень → малина» */
.col-chest-count {
  font-size: calc(26px * var(--ui-scale) * var(--fs-scale));
  font-weight: 900;
  line-height: 1;
  letter-spacing: 0.01em;
  background: linear-gradient(135deg, #a05ce0, #e0286f);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 2px 4px rgba(100,60,160,0.22));
}

/* Подсказка под сундучком: у .col-chest своих полей почти нет, зазор от кнопки
   строка держит сама. */
.col-layout .col-note { margin: calc(4px * var(--ui-space)) auto 0; }

/* ── СЕЗОННАЯ КОЛЛЕКЦИЯ: ярлычок на обложке ─────────────────────────────────
   Коллекция живёт только своё окно дат (в БД — collection_prizes.is_seasonal +
   season_start/season_end). Пока окно идёт, на обложке горит обратный отсчёт:
   не собрал до конца — коллекция исчезнет вместе с фантиками. Собрал вовремя —
   остаётся навсегда, и ярлычок меняется на зелёное «Навсегда».
   Отсчёт тикает в ui/seasonTimer.js; тот же ярлычок стоит на карточках магазина
   сундучка и в строке счётчика на странице коллекции. */
.col-season {
  position: absolute;
  top: calc(8px * var(--ui-scale));
  left: calc(8px * var(--ui-scale));
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: calc(4px * var(--ui-space));
  max-width: calc(100% - calc(16px * var(--ui-scale)));
  padding: calc(3px * var(--ui-space)) calc(10px * var(--ui-space));
  border-radius: 50px;
  font-size: var(--fs-11);
  font-weight: 800;
  letter-spacing: 0.02em;
  white-space: nowrap;
  color: #fff;
}

/* Идёт сезон — фирменный «сирень → малина», как у баллов сундучка */
.col-season--live {
  background: linear-gradient(135deg, #a05ce0, #e0286f);
  border: 1px solid rgba(224,40,111,0.45);
  box-shadow: 0 2px 8px rgba(160,92,224,0.40);
}

/* Меньше суток до конца — красно-оранжевый и пульсирует (успей собрать!) */
.col-season--urgent {
  background: linear-gradient(135deg, #ff7a00, #e53935);
  border-color: rgba(229,57,53,0.55);
  box-shadow: 0 2px 10px rgba(229,57,53,0.45);
  animation: col-season-pulse 1.1s ease-in-out infinite;
}

/* Сезон истёк при открытой панели — гасим до нейтрального серого */
.col-season--over {
  background: linear-gradient(135deg, #b8b8b8, #8f8f8f);
  border-color: rgba(120,120,120,0.5);
  box-shadow: none;
  animation: none;
}

/* Коллекция собрана вовремя — она у игрока навсегда */
.col-season--kept {
  background: rgba(120,230,170,0.30);
  border: 1px solid rgba(46,138,90,0.40);
  color: #1f6b45;
}

.col-season-ico { font-size: var(--fs-12); line-height: 1; }
.col-season-val { font-variant-numeric: tabular-nums; }

@keyframes col-season-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); }
}

/* Индикатор «пришли новые фантики» на обложке коллекции (гаснет после просмотра) */
.col-card-new {
  position: absolute;
  top: calc(8px * var(--ui-scale));
  right: calc(8px * var(--ui-scale));
  min-width: calc(24px * var(--ui-scale));
  height: calc(24px * var(--ui-scale));
  padding: 0 calc(6px * var(--ui-scale));
  border-radius: 50px;
  background: linear-gradient(135deg, #ff5f7a, #e0284f);
  border: calc(2px * var(--ui-scale)) solid #fff;
  box-shadow: 0 2px 8px rgba(224,40,79,0.5);
  color: #fff;
  font-size: var(--fs-13);
  font-weight: 900;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ── Scroll container ── */
.col-strip-wrap {
  flex: 1;
  display: flex;
  align-items: center;
  overflow: hidden;
  padding: calc(12px * var(--ui-space)) 0 calc(20px * var(--ui-space));
  box-sizing: border-box;
  /* cap card height on wide screens */
  max-height: calc(520px * var(--ui-scale));
  /* once capped by max-height, the leftover vertical space is split into the
     auto top/bottom margins so the cover strip sits centered on the page */
  margin-top: auto;
  margin-bottom: auto;
}

.col-strip {
  display: flex;
  flex-direction: row;
  gap: calc(20px * var(--ui-space));
  width: 100%;
  height: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding: 0 calc(16px * var(--ui-space));
  box-sizing: border-box;
  align-items: stretch;
  cursor: grab;
}
.col-strip::-webkit-scrollbar { display: none; }
.col-strip:active { cursor: grabbing; }

/* ── Single collection card ── */
.col-card {
  flex-shrink: 0;
  scroll-snap-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(10px * var(--ui-space));
  background: rgba(255,255,255,0.72);
  border: 2px solid rgba(155,111,200,0.22);
  border-radius: calc(22px * var(--ui-scale));
  padding: calc(14px * var(--ui-space)) calc(14px * var(--ui-space)) calc(18px * var(--ui-space));
  box-shadow: 0 4px 18px rgba(100,60,160,0.12);
  transition: transform 0.16s, box-shadow 0.16s;
  width: clamp(180px, calc(240px * var(--ui-scale)), 290px);
  box-sizing: border-box;
  overflow: hidden;
}

.col-card:hover {
  transform: translateY(-4px) scale(1.02);
  box-shadow: 0 8px 28px rgba(100,60,160,0.22);
}

/* ── Poster ── */
.col-card-poster {
  position: relative;
  width: 100%;
  flex: 1 1 0;
  min-height: 0;
  border-radius: calc(14px * var(--ui-scale));
  overflow: hidden;
  background: linear-gradient(135deg, #c9b8e8, #f0c0d8);
}

.col-poster-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.col-card-poster--clickable {
  cursor: pointer;
}
.col-card-poster--clickable:hover .col-poster-img {
  filter: brightness(1.08);
}

.col-poster-fallback {
  width: 100%;
  min-height: calc(140px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: calc(56px * var(--ui-scale));
  font-weight: 900;
  color: rgba(42,26,64,0.35);
}

/* ── Name ── */
.col-card-name {
  font-size: var(--fs-15);
  font-weight: 900;
  color: #2a1a40;
  letter-spacing: 0.02em;
  text-align: center;
  line-height: 1.2;
}

/* ── Progress ── */
.col-progress-wrap {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(4px * var(--ui-space));
}


.col-progress-label {
  font-size: var(--fs-22);
  font-weight: 900;
  color: rgba(42,26,64,0.85);
}

/* ── Reward row ── */
.col-reward {
  display: flex;
  align-items: center;
  gap: calc(5px * var(--ui-space));
  background: rgba(245,197,24,0.18);
  border: 1.5px solid rgba(200,134,10,0.25);
  border-radius: 999px;
  padding: calc(4px * var(--ui-space)) calc(12px * var(--ui-space));
}

.col-reward-icon {
  width: calc(22px * var(--ui-scale));
  height: calc(22px * var(--ui-scale));
  object-fit: contain;
  flex-shrink: 0;
}

.col-reward-amount {
  font-size: var(--fs-14);
  font-weight: 900;
  color: #c8860a;
}

/* ── Приз за собранную коллекцию ──
   Ярлычок с наградой (.col-reward) — один и тот же элемент в трёх состояниях, и
   различаются они только заливкой: обещание (как было), готовая кнопка «Забрать»
   и погашенная пометка «Приз получен». Ничего не двигается и не появляется —
   карточка не прыгает, когда коллекция дособралась. */
.col-reward--claim {
  border: none;
  cursor: pointer;
  font: inherit;
  background: linear-gradient(135deg, #ffd75e, #f5a524);
  box-shadow: 0 3px 12px rgba(200,134,10,0.38);
  animation: col-reward-pulse 1.8s ease-in-out infinite;
  transition: transform 0.14s, box-shadow 0.14s;
}
.col-reward--claim .col-reward-amount { color: #5a3400; }
.col-reward--claim:hover  { transform: scale(1.05); box-shadow: 0 5px 16px rgba(200,134,10,0.5); }
.col-reward--claim:active { transform: scale(0.97); }
.col-reward--claim:disabled { opacity: 0.6; cursor: default; animation: none; }

@keyframes col-reward-pulse {
  0%, 100% { box-shadow: 0 3px 12px rgba(200,134,10,0.38); }
  50%      { box-shadow: 0 3px 18px rgba(245,165,36,0.75); }
}

.col-reward--claimed {
  background: rgba(120,200,140,0.18);
  border-color: rgba(60,150,90,0.28);
}
.col-reward--claimed .col-reward-amount {
  color: #2f7d4f;
  font-size: var(--fs-12);
}

/* Собрано целиком — счётчик перестаёт быть серым «сколько осталось». */
.col-progress-label--done { color: #2f7d4f; }

/* ── Responsive tweaks ── */
@media (max-width: 480px) {
  .col-strip-wrap {
    padding: calc(8px * var(--ui-space)) 0 calc(12px * var(--ui-space));
    max-height: none;
  }
  .col-card {
    width: clamp(140px, 42vw, 200px);
    gap: calc(7px * var(--ui-space));
    padding: calc(10px * var(--ui-space)) calc(10px * var(--ui-space)) calc(14px * var(--ui-space));
  }
  .col-card-name     { font-size: var(--fs-13); }
  .col-reward-amount { font-size: var(--fs-12); }
}

/* ════════════════════════════════════════════════════════════════════════════
   МАГАЗИН СУНДУЧКА — окно по клику на сундучок (ui/ChestShopPanel.js)
   ----------------------------------------------------------------------------
   Повторки копят баллы, здесь их тратят на фантики. Карточки коллекций —
   квадратные; собранная целиком коллекция погашена и стоит в конце списка
   (порядок задаёт сервер). Список тянется мышью и пальцем.
   ════════════════════════════════════════════════════════════════════════════ */

.chest-shop-overlay {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(16px * var(--ui-space));
  background: rgba(10, 5, 25, 0.0);
  transition: background 0.2s;
}

.chest-shop-overlay--visible {
  background: rgba(10, 5, 25, 0.72);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}

/* Бланк-карточка игры: тот же рецепт, что у мастера дуэлей (.dw-card) —
   сливочно-сиреневый градиент, белая кайма, сиреневое кольцо и блик внутри. */
.chest-shop-card {
  /* Ширины хватает, чтобы все шесть коллекций встали одним рядом и на широком
     экране — окно читается одинаково и на телефоне, и на десктопе */
  width: min(92vw, calc(860px * var(--ui-scale)));
  max-height: 92%;
  display: flex;
  flex-direction: column;
  gap: calc(11px * var(--ui-space));
  padding: calc(15px * var(--ui-space)) calc(18px * var(--ui-space)) calc(17px * var(--ui-space));
  border-radius: calc(30px * var(--ui-scale));
  background: linear-gradient(165deg, #fef6ff 0%, #f4e9ff 55%, #ffeef4 100%);
  border: calc(3px * var(--ui-scale)) solid #ffffff;
  box-shadow:
    0 calc(16px * var(--ui-scale)) calc(44px * var(--ui-scale)) rgba(42,26,64,0.35),
    0 0 0 calc(4px * var(--ui-scale)) rgba(155,111,200,0.4),
    inset 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(255,255,255,0.9);
  box-sizing: border-box;
  transform: scale(0.92) translateY(calc(10px * var(--ui-scale)));
  opacity: 0;
  transition: transform 0.26s cubic-bezier(.2,.9,.3,1.3), opacity 0.24s;
}

.chest-shop-overlay--visible .chest-shop-card {
  transform: none;
  opacity: 1;
}

/* ── Шапка: сундучок, баллы, крестик ── */
.chest-shop-head {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: calc(12px * var(--ui-space));
  padding-bottom: calc(9px * var(--ui-space));
  /* Сиреневая черта под шапкой отделяет её от витрины, не тратя пустую строку */
  border-bottom: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.18);
}

.chest-shop-head-img {
  width: calc(56px * var(--ui-scale));
  height: calc(56px * var(--ui-scale));
  object-fit: contain;
  flex-shrink: 0;
  filter: drop-shadow(0 calc(3px * var(--ui-scale)) calc(8px * var(--ui-scale)) rgba(100,60,160,0.35));
}

.chest-shop-head-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: calc(2px * var(--ui-space));
}

.chest-shop-title {
  font-size: var(--fs-19);
  font-weight: 900;
  color: #3a2358;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  line-height: 1.1;
}

/* Баллы — голое число фирменным градиентом, как у сундучка на странице коллекции */
.chest-shop-balance-num {
  font-size: calc(26px * var(--ui-scale) * var(--fs-scale));
  font-weight: 900;
  line-height: 1;
  background: linear-gradient(135deg, #a05ce0, #e0286f);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 calc(2px * var(--ui-scale)) calc(4px * var(--ui-scale)) rgba(100,60,160,0.22));
}

.chest-shop-close {
  flex-shrink: 0;
}

/* ── Список коллекций: скролл в стиле игры ── */
.chest-shop-grid-wrap {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  touch-action: pan-y;
  -webkit-overflow-scrolling: touch;
  padding: calc(2px * var(--ui-space)) calc(6px * var(--ui-space)) calc(2px * var(--ui-space)) 0;
  scrollbar-width: thin;
  scrollbar-color: rgba(155,111,200,0.4) transparent;
}

/* auto-FIT, а не auto-fill: пустые колонки схлопываются, и коллекции делят всю
   ширину окна между собой. С auto-fill лишние пустые колонки оставались стоять
   справа, и на телефоне ряд карточек жался к левому краю, не добирая до края
   окна. Потолок ширины карточки — чтобы две-три оставшиеся коллекции не
   раздулись во весь бланк. */
.chest-shop-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(calc(120px * var(--ui-scale)), 1fr));
  gap: calc(12px * var(--ui-space));
}

/* ── Карточка коллекции: молочный градиент и сиреневая кайма, как строки выбора
      в дуэлях (.dw-opt) и карточки коллекций ── */
.chest-shop-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  max-width: calc(190px * var(--ui-scale));
  justify-self: center;
  gap: calc(7px * var(--ui-space));
  padding: calc(10px * var(--ui-space));
  border-radius: calc(22px * var(--ui-scale));
  background: linear-gradient(160deg, #ffffff, #fbf2ff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.25);
  box-shadow: 0 calc(3px * var(--ui-scale)) calc(10px * var(--ui-scale)) rgba(155,111,200,0.16);
  box-sizing: border-box;
  transition: transform 0.14s ease, box-shadow 0.14s ease;
}

.chest-shop-item:not(.chest-shop-item--done):hover {
  transform: translateY(calc(-2px * var(--ui-scale)));
  box-shadow: 0 calc(7px * var(--ui-scale)) calc(18px * var(--ui-scale)) rgba(155,111,200,0.26);
}

/* Собранная коллекция: покупать нечего — гасим (в конец списка её ставит сервер) */
.chest-shop-item--done {
  opacity: 0.6;
  filter: grayscale(0.7);
  background: rgba(255,255,255,0.5);
  border-color: rgba(155,111,200,0.14);
  box-shadow: none;
}

/* КВАДРАТНАЯ обложка коллекции */
.chest-shop-card-img-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: calc(16px * var(--ui-scale));
  overflow: hidden;
  background: linear-gradient(135deg, #c9b8e8, #f0c0d8);
  box-shadow: inset 0 0 0 calc(2px * var(--ui-scale)) rgba(255,255,255,0.9),
              0 calc(2px * var(--ui-scale)) calc(7px * var(--ui-scale)) rgba(100,60,160,0.18);
}

.chest-shop-card-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.chest-shop-card-veil {
  position: absolute;
  inset: 0;
  background: rgba(255,255,255,0.35);
}

.chest-shop-item-name {
  font-size: var(--fs-13);
  font-weight: 900;
  color: #3a2358;
  letter-spacing: 0.4px;
  text-align: center;
  line-height: 1.15;
}

/* ── Кнопка «купить»: сундучок + цена. Янтарь — цвет действия в игре
      (та же кнопка, что «Играть» в мастере дуэлей). ── */
.chest-shop-buy {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(5px * var(--ui-space));
  margin-top: calc(1px * var(--ui-space));
  padding: calc(6px * var(--ui-space)) calc(16px * var(--ui-space));
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.8);
  border-radius: 999px;
  cursor: pointer;
  background: linear-gradient(180deg, #ffc266, #e0850f);
  box-shadow: 0 calc(4px * var(--ui-scale)) calc(12px * var(--ui-scale)) rgba(224,112,32,0.45),
              inset 0 calc(2px * var(--ui-scale)) 0 rgba(255,255,255,0.55);
  transition: transform 0.12s, box-shadow 0.12s, opacity 0.12s;
}

.chest-shop-buy:hover:not(:disabled)  { transform: translateY(calc(-1px * var(--ui-scale))); }
.chest-shop-buy:active:not(:disabled) { transform: scale(0.95); }

/* Баллов не хватает — кнопка на месте, но сиреневая и не нажимается */
.chest-shop-buy--poor {
  background: linear-gradient(180deg, #e3d8f4, #b9a8cf);
  border-color: rgba(255,255,255,0.7);
  box-shadow: inset 0 calc(2px * var(--ui-scale)) 0 rgba(255,255,255,0.5);
  cursor: default;
}
.chest-shop-buy--poor .chest-shop-price { text-shadow: none; color: #6b5a86; }
.chest-shop-buy--poor .chest-shop-price-icon { opacity: 0.7; }

.chest-shop-buy--busy { opacity: 0.6; cursor: progress; }

.chest-shop-price-icon {
  width: calc(18px * var(--ui-scale));
  height: calc(18px * var(--ui-scale));
  object-fit: contain;
  flex-shrink: 0;
}

.chest-shop-price {
  font-size: var(--fs-15);
  font-weight: 900;
  color: #fff;
  text-shadow: 0 calc(2px * var(--ui-scale)) 0 rgba(150,80,10,0.35);
}

/* Плашка вместо кнопки у собранной коллекции — сиреневая, как чипы игры */
.chest-shop-done {
  margin-top: calc(1px * var(--ui-space));
  padding: calc(6px * var(--ui-space)) calc(14px * var(--ui-space));
  border-radius: 999px;
  background: rgba(255,255,255,0.75);
  box-shadow: inset 0 0 0 calc(1.5px * var(--ui-scale)) rgba(155,111,200,0.22);
  font-size: var(--fs-12);
  font-weight: 800;
  color: #6c4a94;
}

.chest-shop-empty {
  padding: calc(28px * var(--ui-space)) 0;
  text-align: center;
  font-size: var(--fs-13);
  font-weight: 700;
  color: #9a86ad;
}

/* Тост поверх окна магазина (у .qp-toast z-index ниже оверлея) */
.chest-shop-toast { z-index: 10050; }

/* Узкая адаптация: в коротком ландшафте окно тянется во всю высоту,
   карточки мельче — список всё равно скроллится */
@media (max-width: 1100px), (max-height: 660px) and (orientation: landscape) {
  .chest-shop-card {
    max-height: 96%;
    padding: calc(12px * var(--ui-space)) calc(13px * var(--ui-space)) calc(13px * var(--ui-space));
    gap: calc(7px * var(--ui-space));
  }
  .chest-shop-head-img     { width: calc(44px * var(--ui-scale)); height: calc(44px * var(--ui-scale)); }
  .chest-shop-title        { font-size: var(--fs-16); }
  .chest-shop-balance-num  { font-size: var(--fs-22); }
  .chest-shop-head         { padding-bottom: calc(7px * var(--ui-space)); }
  /* Порог колонки ниже — на телефоне все шесть коллекций встают одним рядом, без
     полупустой второй строки. Ширину при этом карточки берут по месту (auto-fit
     выше), поэтому ряд тянется до края окна, как в браузере, а не жмётся влево. */
  .chest-shop-grid {
    grid-template-columns: repeat(auto-fit, minmax(calc(88px * var(--ui-scale)), 1fr));
    gap: calc(9px * var(--ui-space));
  }
  .chest-shop-item      { padding: calc(7px * var(--ui-space)); gap: calc(4px * var(--ui-space)); }
  .chest-shop-item-name { font-size: var(--fs-11); }
  .chest-shop-buy       { padding: calc(6px * var(--ui-space)) calc(12px * var(--ui-space)); }
}

/* ════════════════════════════════════════════════════════════════════════════
   COLLECTION DETAIL PANEL
   ════════════════════════════════════════════════════════════════════════════ */

.col-detail-panel {
  padding: 0;
  gap: 0;
  justify-content: flex-start;
  overflow: hidden;
}

.col-detail-layout {
  /* inherits sp2-layout */
}

.col-detail-topbar {
  flex-shrink: 0;
}

/* ── Counter "X / N" ── */
/* Строка счётчика: само «X / N» и, у сезонной коллекции, ярлычок с обратным
   отсчётом (или «Навсегда» у собранной) — см. .col-season ниже. */
.col-detail-counter-row {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(10px * var(--ui-space));
  flex-wrap: wrap;
}

.col-detail-counter {
  flex-shrink: 0;
  text-align: center;
  font-size: var(--fs-18);
  font-weight: 900;
  color: #2a1a40;
  letter-spacing: 0.04em;
  padding: calc(4px * var(--ui-space)) 0 calc(2px * var(--ui-space));
}

/* В строке счётчика ярлычок стоит В ПОТОКЕ, а не поверх обложки */
.col-detail-counter-row .col-season {
  position: static;
  transform: none;
}

/* Приз за коллекцию — рядом со счётчиком «8 / 8»: кнопка, пока приз не забран,
   и спокойная зелёная пометка после. Строка счётчика умеет переноситься, поэтому
   на узком экране кнопка просто уходит под число. */
.col-detail-claim {
  flex-shrink: 0;
  border: none;
  border-radius: 999px;
  padding: calc(6px * var(--ui-space)) calc(16px * var(--ui-space));
  font-size: var(--fs-14);
  font-weight: 900;
  color: #5a3400;
  background: linear-gradient(135deg, #ffd75e, #f5a524);
  box-shadow: 0 3px 12px rgba(200,134,10,0.38);
  cursor: pointer;
  animation: col-reward-pulse 1.8s ease-in-out infinite;
  transition: transform 0.14s, box-shadow 0.14s;
}
.col-detail-claim:hover  { transform: scale(1.05); box-shadow: 0 5px 16px rgba(200,134,10,0.5); }
.col-detail-claim:active { transform: scale(0.97); }
.col-detail-claim:disabled { opacity: 0.6; cursor: default; animation: none; }

.col-detail-claim--done {
  background: rgba(120,200,140,0.18);
  border: 1.5px solid rgba(60,150,90,0.28);
  box-shadow: none;
  color: #2f7d4f;
  font-size: var(--fs-12);
  cursor: default;
  animation: none;
}

/* ── Grid wrapper ── */
.col-detail-grid-wrap {
  flex: 1;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  overflow-x: hidden;
  overflow-y: auto;
  padding: calc(16px * var(--ui-space));
  box-sizing: border-box;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  cursor: grab;
  user-select: none;
}

.col-detail-grid-wrap::-webkit-scrollbar {
  display: none;
}

.col-detail-grid-wrap.is-dragging {
  cursor: grabbing;
}

.col-detail-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: auto;
  gap: calc(10px * var(--ui-space));
  width: 72%;
  flex-shrink: 0;
  margin: 0 auto;
}

/* ── Single wrapper card ── */
.col-detail-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 0;
}

.col-detail-item-img-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: calc(10px * var(--ui-scale));
  overflow: hidden;
  background: linear-gradient(135deg, #c9b8e8, #f0c0d8);
  box-shadow: 0 4px 14px rgba(100,60,160,0.18);
  transition: transform 0.15s, box-shadow 0.15s;
}

.col-detail-item-img-wrap:hover {
  transform: scale(1.03);
  box-shadow: 0 8px 28px rgba(100,60,160,0.26);
}

.col-detail-item-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ── Фантика ещё нет ──
   Показываем ЗАГЛУШКУ как есть (assets/collection/wrapper-locked.webp): это
   готовый арт, затемнять его не нужно — он и так читается как «пусто». */
.col-detail-item--locked .col-detail-item-img {
  filter: none;
}

/* ── Индикатор «новый фантик» ──
   Горит на только что полученном фантике и гаснет, как только игрок открыл
   коллекцию и посмотрел (сервер снимает is_new). */
.col-detail-item--fresh .col-detail-item-img-wrap {
  box-shadow: 0 0 0 calc(3px * var(--ui-scale)) #ffd34d,
              0 6px 20px rgba(255,180,40,0.55);
  animation: col-fresh-pulse 1.6s ease-in-out infinite;
}

@keyframes col-fresh-pulse {
  0%, 100% { box-shadow: 0 0 0 calc(3px * var(--ui-scale)) #ffd34d, 0 6px 20px rgba(255,180,40,0.45); }
  50%      { box-shadow: 0 0 0 calc(3px * var(--ui-scale)) #ffe27a, 0 8px 26px rgba(255,180,40,0.75); }
}

.col-detail-item-new {
  position: absolute;
  top: calc(5px * var(--ui-scale));
  left: calc(5px * var(--ui-scale));
  padding: calc(2px * var(--ui-scale)) calc(8px * var(--ui-scale));
  border-radius: 50px;
  background: linear-gradient(135deg, #ffd34d, #f0a020);
  color: #4a2c00;
  font-size: var(--fs-10);
  font-weight: 900;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  box-shadow: 0 2px 6px rgba(180,120,0,0.4);
}


/* ── РЕДКОСТЬ ФАНТИКА ──
   Редкость — ВНУТРЕННЯЯ механика: она нигде не подписана, игрок узнаёт её только
   по тому, как редко фантик попадается. Наружу выходит один намёк — бледная
   рамка в цвет уровня (цвет приходит с сервера в --rarity, палитра правится
   SQL-ом в collection_rarity_levels).

   Рамку рисуем псевдоэлементом, а не box-shadow: так её видно приглушить одной
   opacity, не трогая цвет из БД. */
.col-detail-item[data-rarity] .col-detail-item-img-wrap::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: calc(4px * var(--ui-scale)) solid var(--rarity, #b8c4d6);
  opacity: 0.30;
  pointer-events: none;
}

/* Ненайденный фантик — намёк ещё тише: рамка есть, но почти не читается. */
.col-detail-item--locked[data-rarity] .col-detail-item-img-wrap::after {
  opacity: 0.18;
}

/* Индикатор «новый» перебивает намёк редкости — он важнее и живёт один заход. */
.col-detail-item--fresh[data-rarity] .col-detail-item-img-wrap::after {
  display: none;
}


/* ── Lightbox ── */
.col-detail-item {
  cursor: pointer;
}

.col-lightbox-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 5, 25, 0.0);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10000;
  transition: background 0.2s;
}

.col-lightbox-overlay--visible {
  background: rgba(10, 5, 25, 0.82);
}

.col-lightbox-inner {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  max-width: 80%;
  max-height: 80%;
}

.col-lightbox-img {
  max-width: 100%;
  max-height: 70vh;
  border-radius: calc(16px * var(--ui-scale));
  box-shadow: 0 8px 48px rgba(100,60,160,0.45);
  object-fit: contain;
  display: block;
  transform: scale(0.88);
  transition: transform 0.2s;
}

.col-lightbox-overlay--visible .col-lightbox-img {
  transform: scale(1);
}

.col-lightbox-close {
  position: fixed;
  top: calc(12px * var(--ui-scale));
  right: calc(12px * var(--ui-scale));
}

/* ── Loading / error state ── */
.col-detail-loading {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-16);
  font-weight: 700;
  color: rgba(42,26,64,0.45);
  letter-spacing: 0.05em;
}

/* ── Responsive ── */
@media (max-width: 480px) {
  .col-detail-counter {
    font-size: var(--fs-15);
  }
  .col-detail-grid-wrap {
    padding: calc(10px * var(--ui-space));
  }
  .col-detail-grid {
    width: 90%;
    min-width: 90%;
    gap: calc(8px * var(--ui-space));
  }
}


/* ════════════════════════════════════════════════════════════════════════════
   StatsPanel — страница «Статистика» (reuses .sp2-* topbar / sidenav / content)
   ════════════════════════════════════════════════════════════════════════════ */
.stats-panel {
  padding: 0;
  gap: 0;
  overflow: hidden;
}

/* Нет валютного блока по центру — крестик прижимаем вправо */
.stats-panel .sp2-close-btn { margin-left: auto; }

/* Магазин в адаптивных медиа-запросах ставит .sp2-content в flex-start и pan-x
   (для горизонтальной ленты карточек). Статистике это ломает центрирование и
   вертикальный скролл — возвращаем по центру с более высокой специфичностью. */
.stats-panel .sp2-content {
  position: relative;         /* контекст для плавающей кнопки друзей (правый нижний угол) */
  justify-content: center;
  align-items: stretch;
  overflow: hidden;           /* без вертикального скролла — рейтинг перелистывается */
  touch-action: pan-y;
  /* симметричные отступы — чтобы центр контента совпал с центром экрана */
  padding-left: calc(14px * var(--ui-space));
  padding-right: calc(14px * var(--ui-space));
  /* сверху — зазор под абсолютный топбар (× и заголовок экрана), чтобы окно не налезало */
  padding-top: calc(72px * var(--ui-scale));
  /* снизу — место под свисающую с рамки пилюлю-таймер, чтобы её не срезало overflow */
  padding-bottom: calc(38px * var(--ui-scale));
}

/* Центрируем блок по центру ЭКРАНА: и левый бар, и верхний заголовок делаем
   оверлеями (вне потока) — тогда тело занимает всю ширину И высоту, а блок
   встаёт в истинный центр экрана. Бар и заголовок накладываются по краям. */
.stats-panel .sp2-layout {
  position: relative;
  padding-left: calc(12px * var(--ui-space));
}
.stats-panel .sp2-topbar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 4;
  /* Абсолютный топбар игнорирует левый отступ .sp2-layout, поэтому заголовок
     оказывался левее, чем в магазине. Повторяем магазинный отступ (28+14),
     чтобы «СТАТИСТИКА» стояла ровно там же, где «МАГАЗИН». */
  padding-left: calc(42px * var(--ui-space));
}
.stats-panel .sp2-body { position: relative; }
.stats-panel .sp2-sidenav {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  z-index: 3;
  /* Три кнопки — по центру с компактным зазором (не растягиваем на всю высоту). */
  justify-content: center;
  gap: calc(28px * var(--ui-scale));
}

/* ── Боковая навигация статистики: кнопка = только картинка, без рамки и подписи ──
   Активный раздел подсвечиваем не заливкой, а полной непрозрачностью + масштабом. */
.stats-panel .sp2-nav-item {
  background: transparent;
  border: none;
  box-shadow: none;
  border-radius: 0;
  flex: 0 0 auto;
  min-height: 0;
  padding: 0;
  opacity: 0.55;
  transition: transform 0.13s, opacity 0.13s;
}
.stats-panel .sp2-nav-item:hover {
  background: transparent;
  box-shadow: none;
  opacity: 1;
}
.stats-panel .sp2-nav-active {
  background: transparent;
  box-shadow: none;
  opacity: 1;
  transform: scale(1.08);
}
.stats-panel .sp2-nav-item > span:last-child { display: none; }
.stats-panel .sp2-nav-icon-wrap,
.stats-panel .sp2-nav-img {
  width: calc(68px * var(--ui-scale));
  height: calc(68px * var(--ui-scale));
  max-width: calc(68px * var(--ui-scale));
  max-height: calc(68px * var(--ui-scale));
}

/* Иконка-слот (img + emoji-фолбэк) — заполняет родителя фиксированного размера */
.st-icon-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

/* ── Раздел «Статистика»: только картинка + число рядом, без боксов и подписей ── */
.st-stats-wrap {
  width: 100%;
  max-width: calc(600px * var(--ui-scale));
  align-self: center;            /* по центру по вертикали */
  margin: auto 0;                /* не обрезается сверху, если контента много */
  display: flex;
  flex-direction: column;
  gap: calc(18px * var(--ui-space));
}

/* «Уровень» + картинка ранга — отдельной строкой по центру над остальными значками */
.st-stats-top {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(16px * var(--ui-space));
}

/* Картинка текущего ранга справа от уровня */
.st-rank-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: calc(84px * var(--ui-scale));
  height: calc(84px * var(--ui-scale));
  flex-shrink: 0;
}

/* XP-полоса прогресса до следующего ранга — в стиле игры (фиолетово-оранжевый градиент) */
.st-rank-xp {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: calc(5px * var(--ui-space));
}
.st-rank-name {
  font-size: var(--fs-14);
  font-weight: 800;
  letter-spacing: 0.02em;
  color: #4b2a8c;
}
.st-rank-xp-track {
  width: calc(190px * var(--ui-scale));
  height: calc(20px * var(--ui-scale));
  background: rgba(155, 111, 200, 0.18);
  border-radius: 999px;
  overflow: hidden;
}
.st-rank-xp-fill {
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #ef6ea0, #f7a838);
  box-shadow: 0 0 8px rgba(239, 110, 160, 0.45);
  transition: width 0.4s ease;
}
.st-rank-xp-text {
  font-size: var(--fs-11);
  font-weight: 700;
  color: rgba(42, 26, 64, 0.5);
}

.st-stats-grid {
  width: 100%;
  display: grid;
  grid-template-columns: repeat(3, auto);
  justify-content: center;          /* группируем колонки по центру, без растяжки */
  column-gap: calc(44px * var(--ui-space));
  row-gap: calc(22px * var(--ui-space));
}

/* Фикс. ширина ячейки. Подпись сверху, ниже — группа «значок + число».
   Подпись и группа центрируются в одной ячейке, поэтому подпись стоит ровно
   над связкой значок+значение. */
.st-stat-item {
  width: calc(150px * var(--ui-scale));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(4px * var(--ui-space));
}

/* Подпись над значком — в стиле игры (тёмно-фиолетовый, жирный) */
.st-stat-label {
  min-height: calc(26px * var(--ui-scale));
  display: flex;
  align-items: flex-end;
  justify-content: center;
  text-align: center;
  font-size: var(--fs-12);
  font-weight: 800;
  line-height: 1.12;
  letter-spacing: 0.02em;
  color: #4b2a8c;   /* тёмно-фиолетовый */
}


/* Ряд «значок + число» — в потоке, центрируется целиком */
.st-stat-icon-row {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(10px * var(--ui-space));
}

.st-stat-icon {
  width: calc(72px * var(--ui-scale));
  height: calc(72px * var(--ui-scale));
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.st-stat-val {
  font-size: calc(24px * var(--ui-scale) * var(--fs-scale));
  font-weight: 900;
  color: #2a1a40;
  white-space: nowrap;
}

/* Низкий ландшафт: у «Статистики» вертикальная прокрутка выключена намеренно
   (.stats-panel .sp2-content — рейтинг перелистывается вкладками), поэтому сетка
   ОБЯЗАНА влезать в высоту. На 390 px не влезала на 14 px, на 280 px — на 67 px,
   и нижний ряд («Лучшая серия побед», «Рекорд выживания», «Собрано фантиков»)
   срезался без возможности доскроллить. Ужимаем отступы, значки и шрифты. */
@media (max-height: 499px) and (orientation: landscape) {
  .stats-panel .sp2-content {
    padding-top: calc(46px * var(--ui-scale));
    padding-bottom: calc(18px * var(--ui-scale));
  }
  .st-stats-wrap  { gap: calc(8px * var(--ui-space)); }
  .st-stats-top   { gap: calc(10px * var(--ui-space)); }
  .st-stats-grid  { column-gap: calc(30px * var(--ui-space)); row-gap: calc(8px * var(--ui-space)); }
  .st-stat-item   { width: calc(126px * var(--ui-scale)); gap: 0; }
  .st-stat-label  { min-height: calc(18px * var(--ui-scale)); font-size: var(--fs-11); }
  .st-stat-icon   { width: calc(46px * var(--ui-scale)); height: calc(46px * var(--ui-scale)); }
  .st-stat-val    { font-size: var(--fs-19); }
  .st-rank-badge  { width: calc(56px * var(--ui-scale)); height: calc(56px * var(--ui-scale)); }
}

/* ── Разделы рейтингов: карточки-пилюли в стиле игры ───────────────────────────
   Единая стилистика на всех трёх вкладках, у каждой — своя цветовая гамма,
   заданная через --lb-rgb / --lb-score (см. .st-lb-theme-*). */
.st-board {
  position: relative;          /* контекст для пилюли-таймера на нижнем крае */
  width: 100%;
  max-width: calc(470px * var(--ui-scale));   /* немного меньше, чем раньше */
  height: 90%;                 /* чуть ниже полной высоты — чтобы окно не липло к нижнему краю */
  align-self: center;          /* по истинному центру области контента */
  margin: 0 auto;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: calc(7px * var(--ui-space));
  /* Рамка-окно в конфетной пастельной гамме вкладки */
  padding: calc(9px * var(--ui-space)) calc(12px * var(--ui-space)) calc(12px * var(--ui-space));
  background: linear-gradient(160deg, rgba(var(--lb-rgb), 0.85), rgba(var(--lb-rgb), 0.55));
  border: calc(3px * var(--ui-scale)) solid #fff;
  border-radius: calc(28px * var(--ui-scale));
  box-shadow: 0 12px 30px rgba(var(--lb-rgb), 0.42), inset 0 2px 0 rgba(255,255,255,0.6);
  /* дефолтная тема (пастельная лаванда) — на случай отсутствия класса вкладки */
  --lb-rgb: 198, 160, 236;
}

/* Конфетные пастельные гаммы вкладок */
.st-lb-theme-rank    { --lb-rgb: 198, 160, 236; } /* лаванда        — ранговый  */
.st-lb-theme-world   { --lb-rgb: 174, 220, 250; } /* нежно-конфетный голубой — мировой */
.st-lb-theme-friends { --lb-rgb: 245, 205, 80;  } /* конфетно-жёлтый — друзья    */

/* Заголовок-шапка окна: название рейтинга по центру рамки */
.st-lb-title {
  flex-shrink: 0;
  text-align: center;
  max-width: 100%;
  box-sizing: border-box;
  font-size: var(--fs-21);
  font-weight: 900;
  letter-spacing: 0.03em;
  color: #fff;
  padding: calc(3px * var(--ui-space)) calc(28px * var(--ui-space)) calc(5px * var(--ui-space));
  /* тёмная обводка тенью — чтобы белый заголовок читался на любой пастели, включая жёлтую */
  text-shadow: 0 2px 4px rgba(90,55,120,0.55), 0 1px 1px rgba(80,50,20,0.35);
}

/* Пилюля обратного отсчёта до выдачи подарков — кремовая капсула по центру
   нижнего края окна (наполовину свисает за рамку), как в примере: иконка-часы
   в оранжевом кружке + компактное время «9ч 05м». */
.st-lb-timer {
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translate(-50%, 45%);
  z-index: 4;
  display: flex;
  align-items: center;
  gap: calc(7px * var(--ui-space));
  box-sizing: border-box;
  padding: calc(4px * var(--ui-space)) calc(15px * var(--ui-space)) calc(4px * var(--ui-space)) calc(4px * var(--ui-space));
  background: linear-gradient(180deg, #fff7e9, #ffe9c6);
  border: calc(3px * var(--ui-scale)) solid #fff;
  border-radius: calc(999px * var(--ui-scale));
  box-shadow: 0 4px 12px rgba(150,110,40,0.28), inset 0 1px 0 rgba(255,255,255,0.8);
  white-space: nowrap;
}
/* Оранжевый кружок с иконкой часов (картинка перекрывает кружок, если есть) */
.st-lb-timer-ico {
  position: relative;
  flex-shrink: 0;
  width: calc(30px * var(--ui-scale));
  height: calc(30px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #ffcf7a, #f2971f 75%);
  box-shadow: inset 0 1px 2px rgba(255,255,255,0.6), 0 1px 3px rgba(180,110,20,0.45);
  font-size: var(--fs-16);
  line-height: 1;
}
.st-lb-timer-ico-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}
.st-lb-timer-val {
  font-size: var(--fs-19);
  font-weight: 900;
  letter-spacing: 0.01em;
  color: #6a4a1c;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 rgba(255,255,255,0.7);
}

/* Внутренняя панель со списком — почти белая с лёгким конфетным оттенком */
.st-lb-inset {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: calc(8px * var(--ui-space));
  box-sizing: border-box;
  padding: calc(10px * var(--ui-space));
  background: linear-gradient(180deg, #fffdff, #fdf4fb);
  border-radius: calc(20px * var(--ui-scale));
  box-shadow: inset 0 2px 7px rgba(150,120,190,0.16), 0 1px 0 rgba(255,255,255,0.7);
}

/* Один вертикальный список — тянется пальцем (нативно) или курсором (drag-to-scroll),
   без видимой полосы прокрутки. Никаких страниц. */
.st-lb-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  touch-action: pan-y;
  cursor: grab;
  user-select: none;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.st-lb-scroll::-webkit-scrollbar { display: none; }
.st-lb-scroll.st-lb-grabbing { cursor: grabbing; }

.st-lb-list {
  display: flex;
  flex-direction: column;
  gap: calc(8px * var(--ui-space));
}

/* Строка-пилюля: белая, конфетный ободок. Ранг несут кубки-картинки, не фон. */
.st-lb-row {
  display: flex;
  align-items: center;
  gap: calc(11px * var(--ui-space));
  background: #ffffff;
  border: 2px solid rgba(var(--lb-rgb), 0.32);
  border-radius: calc(16px * var(--ui-scale));
  padding: calc(6px * var(--ui-space)) calc(11px * var(--ui-space));
  box-shadow: 0 2px 5px rgba(150,120,190,0.16);
}

/* Топ-1 — усиленный ободок в цвете вкладки (у каждого рейтинга своя гамма) */
.st-lb-row.st-lb-r1 {
  border-color: rgba(var(--lb-rgb), 0.85);
  box-shadow: 0 2px 9px rgba(var(--lb-rgb), 0.45);
}

/* Строка текущего игрока — конфетная заливка в гамме вкладки */
.st-lb-row-me {
  background: linear-gradient(180deg, rgba(var(--lb-rgb), 0.24), rgba(var(--lb-rgb), 0.42));
  border-color: rgba(var(--lb-rgb), 0.65);
  box-shadow: 0 0 0 2px rgba(var(--lb-rgb), 0.45), 0 3px 10px rgba(var(--lb-rgb), 0.32);
}

/* Слот ранга слева: кубок-картинка (топ-3) или крупный номер (4+) */
.st-lb-rankslot {
  width: calc(42px * var(--ui-scale));
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.st-lb-num {
  font-size: var(--fs-20);
  font-weight: 900;
  color: #9a7ac0;
  text-shadow: 0 1px 0 rgba(255,255,255,0.7);
}

/* Иконки-картинки (кубок / медаль / подарок): фикс. слот + эмодзи-фолбэк, пока нет файлов */
.st-lb-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.st-lb-ico-trophy { width: calc(38px * var(--ui-scale)); height: calc(42px * var(--ui-scale)); }
.st-lb-ico-rank   { width: calc(34px * var(--ui-scale)); height: calc(34px * var(--ui-scale)); }
.st-lb-ico-gift   { width: calc(32px * var(--ui-scale)); height: calc(32px * var(--ui-scale)); }

/* Топ-3 подарки — особый вид: крупнее и с золотистым свечением (и своя картинка) */
.st-lb-ico-gift-top {
  width: calc(38px * var(--ui-scale));
  height: calc(38px * var(--ui-scale));
  filter: drop-shadow(0 0 6px rgba(255,205,90,0.75)) drop-shadow(0 2px 3px rgba(0,0,0,0.2));
}

/* Призовой подарок кликабелен — открывает окошко с содержимым */
.st-lb-gift-btn { cursor: pointer; transition: transform 0.12s ease-out; }
.st-lb-gift-btn:hover  { transform: scale(1.12); }
.st-lb-gift-btn:active { transform: scale(0.94); }
/* Непризовое место (21-е и ниже): пустой слот держит выравнивание строки */
.st-lb-gift-none { visibility: hidden; }

/* ── Окошко с содержимым подарка за место ─────────────────────────────────────
   Всплывает справа от подарка, за краем рамки рейтинга; хвостик смотрит в подарок. */
.lb-prize {
  position: absolute;
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(4px * var(--ui-space));
  box-sizing: border-box;
  padding: calc(7px * var(--ui-space)) calc(11px * var(--ui-space));
  background: linear-gradient(180deg, #fffdff, #fdf1fa);
  border: calc(2px * var(--ui-scale)) solid #fff;
  border-radius: calc(14px * var(--ui-scale));
  box-shadow: 0 6px 16px rgba(120,90,160,0.32), inset 0 1px 0 rgba(255,255,255,0.8);
  white-space: nowrap;
  animation: lb-prize-in 0.14s ease-out;
}
@keyframes lb-prize-in {
  from { opacity: 0; transform: scale(0.9); }
  to   { opacity: 1; transform: scale(1); }
}
/* Топ-3 — золотистая рамка, как у их подарка */
.lb-prize-top {
  border-color: #ffe6a8;
  box-shadow: 0 6px 16px rgba(190,140,40,0.36), 0 0 0 calc(1px * var(--ui-scale)) rgba(255,205,90,0.7);
}

/* Хвостик к подарку: слева от окошка (или справа, если окошко перекинуто) */
.lb-prize::after {
  content: '';
  position: absolute;
  top: var(--lb-prize-arrow, 50%);
  right: 100%;
  width: 0;
  height: 0;
  margin-top: calc(-6px * var(--ui-scale));
  border: calc(6px * var(--ui-scale)) solid transparent;
  border-right-color: #fff;
}
.lb-prize-flip::after {
  right: auto;
  left: 100%;
  border-right-color: transparent;
  border-left-color: #fff;
}

.lb-prize-place {
  font-size: var(--fs-13);
  font-weight: 900;
  letter-spacing: 0.02em;
  color: #9a7ac0;
}
.lb-prize-items {
  display: flex;
  align-items: center;
  gap: calc(10px * var(--ui-space));
}
.lb-prize-item {
  display: inline-flex;
  align-items: center;
  gap: calc(4px * var(--ui-space));
}
.lb-prize-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: calc(24px * var(--ui-scale));
  height: calc(24px * var(--ui-scale));
}
.lb-prize-val {
  font-size: var(--fs-17);
  font-weight: 900;
  color: #2a1a40;
  font-variant-numeric: tabular-nums;
}
/* Условие приза, которое ещё не выполнено (текст присылает сервер: пороги живут в
   БД). Показывается только у СВОЕЙ строки. Единственное место окошка, где текст
   переносится, — .lb-prize держит nowrap ради чисел в одну строку, а тут фраза, и
   без ширины с переносом она растянула бы окошко через весь экран. */
.lb-prize-note {
  max-width: calc(190px * var(--ui-scale));
  white-space: normal;
  text-align: center;
  font-size: var(--fs-11);
  line-height: 1.3;
  font-weight: 700;
  color: #8a76a8;
  border-top: calc(1px * var(--ui-scale)) dashed rgba(154,122,192,0.45);
  padding-top: calc(5px * var(--ui-space));
}

/* Аватар — круглый, фото из БД (photo_url); плейсхолдер — первая буква имени.
   Без дополнительной обводки — только круглое фото. */
.st-lb-avatar {
  width: calc(44px * var(--ui-scale));
  height: calc(44px * var(--ui-scale));
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  background: rgba(var(--lb-rgb), 0.25);
}
.st-lb-avatar-ph {
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 900;
  color: #fff;
  font-size: var(--fs-18);
  background: linear-gradient(135deg, rgba(var(--lb-rgb), 0.9), rgba(var(--lb-rgb), 0.62));
}

.st-lb-name {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-15);
  font-weight: 800;
  color: #6b4f86;
}

/* Очки: медаль-картинка + число конфетного цвета */
.st-lb-score-wrap {
  display: flex;
  align-items: center;
  gap: calc(5px * var(--ui-space));
  flex-shrink: 0;
}
.st-lb-score {
  font-size: var(--fs-18);
  font-weight: 900;
  color: #ef6ea0;
  min-width: calc(46px * var(--ui-scale));
  text-align: left;
  white-space: nowrap;
  text-shadow: 0 1px 0 rgba(255,255,255,0.6);
}

/* Закреплённая строка «вы» — у того края, за который ушла настоящая строка игрока:
   снизу, если она под списком, и сверху, если её пролистнули вверх. Пунктир всегда
   смотрит в список, поэтому у верхнего пина рамка и отступ зеркальные. */
.st-lb-pin {
  flex-shrink: 0;
  padding-top: calc(9px * var(--ui-space));
  border-top: 2px dashed rgba(var(--lb-rgb), 0.40);
}
.st-lb-pin.st-lb-pin-top {
  padding-top: 0;
  border-top: none;
  padding-bottom: calc(9px * var(--ui-space));
  border-bottom: 2px dashed rgba(var(--lb-rgb), 0.40);
}
.st-lb-row-pinned { margin: 0; }
.st-lb-unranked {
  text-align: center;
  font-size: var(--fs-15);
  font-weight: 700;
  color: rgba(var(--lb-rgb), 0.85);
  padding: calc(8px * var(--ui-space));
}

.st-loading, .st-empty {
  align-self: center;
  margin: auto;
  font-size: var(--fs-16);
  font-weight: 700;
  color: #7b5a9a;
  text-align: center;
}

/* ── Пустой рейтинг друзей: сообщение по центру рамки ────────────────────────── */
.st-lb-inset-empty {
  align-items: center;
  justify-content: center;
}
.st-lb-empty-msg {
  text-align: center;
  white-space: pre-line;      /* уважаем \n в тексте перевода */
  font-size: var(--fs-16);
  font-weight: 800;
  line-height: 1.4;
  color: #6b4f86;
  padding: calc(20px * var(--ui-space));
}

/* ── Плавающая кнопка «отправить запрос на дружбу» (правый нижний угол) ─────────
   Размер — как у кнопок левого меню (68px). Пока картинки нет — кружок с ➕. */
.fr-fab {
  position: absolute;
  right: calc(14px * var(--ui-space));
  bottom: calc(14px * var(--ui-space));
  z-index: 5;
  width: calc(68px * var(--ui-scale));
  height: calc(68px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  transition: transform 0.13s, filter 0.13s;
  filter: drop-shadow(0 4px 10px rgba(155,111,200,0.45));
}
.fr-fab:hover  { transform: scale(1.08); }
.fr-fab:active { transform: scale(0.93); }

/* ── Всплывающее окно запроса дружбы ─────────────────────────────────────────── */
.fr-modal-overlay {
  position: absolute;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(20px * var(--ui-space));
  background: rgba(60, 40, 90, 0.45);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  animation: fr-fade 0.16s ease;
}
@keyframes fr-fade { from { opacity: 0; } to { opacity: 1; } }

.fr-modal {
  position: relative;
  width: 100%;
  max-width: calc(420px * var(--ui-scale));
  max-height: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: calc(14px * var(--ui-space));
  padding: calc(20px * var(--ui-space)) calc(20px * var(--ui-space)) calc(20px * var(--ui-space));
  background: linear-gradient(160deg, #fffdff, #f6ecfb);
  border: calc(3px * var(--ui-scale)) solid #fff;
  border-radius: calc(28px * var(--ui-scale));
  box-shadow: 0 18px 44px rgba(90, 55, 130, 0.45);
  animation: fr-pop 0.18s ease;
}
@keyframes fr-pop { from { transform: scale(0.92); opacity: 0; } to { transform: scale(1); opacity: 1; } }

/* Крестик — как на статистике, чуть меньше, прижат в правый верхний угол окна */
.fr-modal-close {
  position: absolute;
  top: calc(8px * var(--ui-space));
  right: calc(8px * var(--ui-space));
  z-index: 3;
  width: calc(48px * var(--ui-scale));
  height: calc(48px * var(--ui-scale));
}
.fr-modal-close img {
  width: calc(40px * var(--ui-scale));
  height: calc(40px * var(--ui-scale));
}

/* Заголовок по центру (с боковыми отступами под крестик) */
.fr-modal-title {
  text-align: center;
  font-size: var(--fs-19);
  font-weight: 900;
  letter-spacing: 0.02em;
  line-height: 1.2;
  color: #4b2a8c;
  padding: calc(2px * var(--ui-space)) calc(50px * var(--ui-scale));
}

/* Два варианта — QR-код / добавить по нику */
.fr-modal-options {
  display: flex;
  gap: calc(12px * var(--ui-space));
}
.fr-opt {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(6px * var(--ui-space)) 0;
  background: none;
  border: none;
  cursor: pointer;
  opacity: 0.6;
  transition: transform 0.12s, opacity 0.12s, filter 0.12s;
}
.fr-opt:hover { transform: translateY(-2px); opacity: 0.85; }
.fr-opt-active {
  opacity: 1;
  transform: translateY(-2px);
  filter: drop-shadow(0 5px 10px rgba(123,63,190,0.35));
}
.fr-opt-ico {
  width: calc(68px * var(--ui-scale));
  height: calc(68px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Конфета-ссылка нарисована лежачей (361×300), поэтому в квадратном слоте она
   вписывалась по ширине и выходила ниже QR-кода и лупы. Слот под неё шире ровно
   на ту же долю — картинка добирает высоту соседей, а саму высоту по-прежнему
   задаёт правило выше (и его укороченный вариант в .fp-add). */
.fr-modal-options .fr-opt-link .fr-opt-ico {
  width: auto;
  aspect-ratio: 361 / 300;
}
/* Запаска под картинку варианта: если арт не загрузился (нет файла, другое
   расширение), onerror показывает значок — кнопка не остаётся пустой. */
.fr-opt-fb {
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  font-size: calc(38px * var(--ui-scale));
  line-height: 1;
}

/* Тело окна — переменная часть (QR или поиск) */
.fr-modal-body {
  min-height: calc(210px * var(--ui-scale));
  display: flex;
  flex-direction: column;
}
.fr-hint {
  text-align: center;
  color: #7b5a9a;
  font-weight: 700;
  font-size: var(--fs-14);
  padding: calc(16px * var(--ui-space));
}

/* QR-код */
.fr-qr {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(10px * var(--ui-space));
  padding: calc(4px * var(--ui-space)) 0;
}
.fr-qr-frame {
  width: calc(216px * var(--ui-scale));
  height: calc(216px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  background: #fff;
  border-radius: calc(18px * var(--ui-scale));
  padding: calc(10px * var(--ui-space));
  box-shadow: 0 4px 14px rgba(90,55,130,0.18);
}
.fr-qr-fb {
  display: none;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  text-align: center;
  color: #a0468a;
  font-weight: 700;
  font-size: var(--fs-13);
}
.fr-qr-hint {
  text-align: center;
  font-size: var(--fs-13);
  font-weight: 700;
  color: #6b4f86;
}
.fr-qr-id {
  font-family: monospace;
  font-size: var(--fs-11);
  color: rgba(75,42,140,0.55);
  word-break: break-all;
  text-align: center;
}

/* Ссылка на игру: её копируют и отправляют другу, который ещё не играет */
.fr-link {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(12px * var(--ui-space));
  padding: calc(6px * var(--ui-space)) 0;
}
.fr-link-hint {
  text-align: center;
  font-size: var(--fs-13);
  font-weight: 700;
  color: #6b4f86;
}
/* Рамка — та же, что у поля поиска по нику: это «строка со ссылкой», а не кнопка */
.fr-link-box {
  width: 100%;
  box-sizing: border-box;
  padding: calc(11px * var(--ui-space)) calc(14px * var(--ui-space));
  border: 2.5px solid transparent;
  border-radius: calc(14px * var(--ui-scale));
  background:
    linear-gradient(#fff, #fff) padding-box,
    linear-gradient(90deg, #9b5fc0, #ff7bc0, #5ec8e5) border-box;
  color: #2a1a40;
  font-size: var(--fs-14);
  font-weight: 700;
  text-align: center;
  word-break: break-all;
  cursor: pointer;
}
/* Кнопка — фирменный градиент, как у «Отправить запрос» (.fa-btn) */
.fr-link-copy {
  min-height: calc(38px * var(--ui-scale));
  padding: 0 calc(22px * var(--ui-space));
  border: none;
  border-radius: calc(14px * var(--ui-scale));
  background: linear-gradient(135deg, #f7a838, #ef6ea0);
  color: #fff;
  font-size: var(--fs-14);
  font-weight: 800;
  text-shadow: 0 calc(1px * var(--ui-scale)) calc(2px * var(--ui-scale)) rgba(0,0,0,0.22);
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(155,111,200,0.30);
  cursor: pointer;
  transition: transform 0.12s, filter 0.12s;
}
.fr-link-copy:hover  { filter: brightness(1.05); }
.fr-link-copy:active { transform: scale(0.95); }

/* Добавить по нику: строка ввода + кнопка поиска + результаты */
.fr-search {
  display: flex;
  gap: calc(8px * var(--ui-space));
  margin-bottom: calc(12px * var(--ui-space));
}
.fr-search-input {
  flex: 1;
  min-width: 0;
  box-sizing: border-box;
  padding: calc(11px * var(--ui-space)) calc(14px * var(--ui-space));
  font-size: var(--fs-15);
  border: 2.5px solid transparent;
  border-radius: calc(14px * var(--ui-scale));
  background:
    linear-gradient(#fff, #fff) padding-box,
    linear-gradient(90deg, #9b5fc0, #ff7bc0, #5ec8e5) border-box;
  color: #2a1a40;
  outline: none;
}
.fr-search-input:focus { box-shadow: none; }
.fr-search-btn {
  flex-shrink: 0;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
}
.fr-search-btn:active { transform: scale(0.94); }
.fr-search-img {
  width: calc(62px * var(--ui-scale));
  height: auto;
  display: block;
  filter: drop-shadow(0 calc(2px * var(--ui-scale)) calc(4px * var(--ui-scale)) rgba(0,0,0,0.2));
}
.fr-results {
  flex: 1 1 auto;
  min-height: 0;
  max-height: calc(250px * var(--ui-scale));
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: calc(8px * var(--ui-space));
}
.fr-res-row {
  display: flex;
  align-items: center;
  gap: calc(10px * var(--ui-space));
  padding: calc(7px * var(--ui-space)) calc(10px * var(--ui-space));
  background: #fff;
  border: 2px solid rgba(155,111,200,0.22);
  border-radius: calc(14px * var(--ui-scale));
}
.fr-res-avatar {
  width: calc(40px * var(--ui-scale));
  height: calc(40px * var(--ui-scale));
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  background: rgba(155,111,200,0.25);
}
.fr-res-avatar-ph {
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 900;
  color: #fff;
  font-size: var(--fs-16);
  background: linear-gradient(135deg, #b58fe0, #9b6fc8);
}
.fr-res-name {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-14);
  font-weight: 800;
  color: #6b4f86;
}
/* ─── Дружба: кнопка и плашки статуса (ui/FriendAction.js) ────────────────────
   ОДИН вид и размер на все места, где можно подружиться: карточка профиля игрока
   и поиск по нику в «Статистике» и на странице «Друзья». Без картинок — только
   текст. Правите здесь — меняется везде.                                        */
.fa-btn,
.fa-tag {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: calc(34px * var(--ui-scale));
  padding: 0 calc(18px * var(--ui-space));
  border-radius: calc(14px * var(--ui-scale));
  font-size: var(--fs-13);
  font-weight: 800;
  white-space: nowrap;
}
/* Кнопка — фирменный градиент кнопок игры */
.fa-btn {
  border: none;
  background: linear-gradient(135deg, #f7a838, #ef6ea0);
  color: #fff;
  text-shadow: 0 calc(1px * var(--ui-scale)) calc(2px * var(--ui-scale)) rgba(0,0,0,0.22);
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(155,111,200,0.30);
  cursor: pointer;
  transition: transform 0.12s, filter 0.12s;
}
.fa-btn:hover    { filter: brightness(1.05); }
.fa-btn:active   { transform: scale(0.95); }
.fa-btn:disabled { opacity: 0.65; cursor: default; }
/* Плашки статуса — та же форма, но мягкая заливка вместо градиента */
.fa-tag--friend  { background: rgba(79,174,107,0.16);  color: #2e8b57; }
.fa-tag--pending { background: rgba(247,168,56,0.20);  color: #a8762a; }
.fa-tag--self    { background: rgba(155,111,200,0.15); color: #7b5a9a; }

/* ─── Профиль игрока: клик по нику в рейтинге ────────────────────────────────
   Всплывающее окно поверх рейтинга. Крестик — как на статистике; крупный аватар
   по центру, ник, ранг, статус дружбы и компактная сетка чисел из БД.
   Ничего не скроллится по вертикали — всё влезает в карточку. */

/* Ник в таблице становится кликабельным */
/* Ник открывает профиль — курсор-указатель, без подчёркивания. Аватар с фото ведёт
   себя иначе: он разворачивает арт во весь экран (см. [data-ava-zoom]), а профиль
   открывает лишь кружок с буквой, у которого разворачивать нечего. */
.st-lb-player-link { cursor: pointer; }

.pl-card {
  position: relative;
  width: 100%;
  max-width: calc(360px * var(--ui-scale));
  max-height: 100%;
  box-sizing: border-box;
  padding: calc(22px * var(--ui-space)) calc(20px * var(--ui-space)) calc(20px * var(--ui-space));
  background: linear-gradient(160deg, #fffdff, #f3e8fb);
  border: calc(3px * var(--ui-scale)) solid #fff;
  border-radius: calc(28px * var(--ui-scale));
  /* конфетное свечение + глянцевый блик сверху — как на окнах рейтинга */
  box-shadow: 0 18px 44px rgba(123, 63, 190, 0.42), inset 0 2px 0 rgba(255,255,255,0.75);
  animation: fr-pop 0.18s ease;
}

/* Крестик — как на статистике, прижат в правый верхний угол окна */
.pl-close {
  position: absolute;
  top: calc(8px * var(--ui-space));
  right: calc(8px * var(--ui-space));
  z-index: 3;
  width: calc(48px * var(--ui-scale));
  height: calc(48px * var(--ui-scale));
}
.pl-close img {
  width: calc(40px * var(--ui-scale));
  height: calc(40px * var(--ui-scale));
}

.pl-body {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: calc(7px * var(--ui-space));
}
.pl-body .st-loading, .pl-error {
  padding: calc(48px * var(--ui-space)) 0;
  color: #7b5a9a;
  font-weight: 700;
  font-size: var(--fs-15);
  text-align: center;
}

/* Строка-повод над карточкой: её открыла сама игра, встречая пришедшего по
   ссылке-приглашению (main.js#_greetInviter). В остальных местах её нет. */
.pl-note {
  align-self: center;
  max-width: 100%;
  box-sizing: border-box;
  padding: calc(6px * var(--ui-space)) calc(14px * var(--ui-space));
  border-radius: calc(12px * var(--ui-scale));
  background: rgba(155, 95, 192, 0.12);
  color: #6b4f86;
  font-size: var(--fs-13);
  font-weight: 800;
  text-align: center;
}

/* Шапка профиля: круглый аватар слева, справа — ник, ранг и статус дружбы */
.pl-header {
  display: flex;
  align-items: center;
  gap: calc(16px * var(--ui-space));
  width: 100%;
  margin-top: calc(4px * var(--ui-space));
}
.pl-info {
  flex: 1 1 auto;
  min-width: 0;                 /* чтобы работал ellipsis у ника */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(7px * var(--ui-space));
}

/* Круглый аватар слева — без белой обводки */
.pl-avatar {
  flex: 0 0 auto;
  width: calc(116px * var(--ui-scale));
  height: calc(116px * var(--ui-scale));
  border-radius: 50%;
  object-fit: cover;
  box-shadow: 0 8px 20px rgba(123,63,190,0.38);
  background: rgba(155,111,200,0.25);
}
.pl-avatar-ph {
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 900;
  color: #fff;
  font-size: calc(50px * var(--ui-scale));
  background: linear-gradient(135deg, #b58fe0, #9b6fc8);
}

.pl-name {
  max-width: 100%;
  font-size: var(--fs-22);
  font-weight: 900;
  color: #4b2a8c;
  text-align: left;
}

/* Ранг (из БД) */
.pl-rank {
  display: inline-flex;
  align-items: center;
  gap: calc(6px * var(--ui-space));
}
.pl-rank-badge {
  width: calc(26px * var(--ui-scale));
  height: calc(26px * var(--ui-scale));
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.pl-rank-name {
  font-size: var(--fs-14);
  font-weight: 800;
  color: #7b5a9a;
}

/* Статус дружбы / кнопка добавления — общие .fa-btn / .fa-tag (ui/FriendAction.js) */

/* Компактная сетка чисел из БД — 3 колонки, оформление как на странице «Статистика»:
   значок сверху, тёмное число, тёмно-фиолетовая подпись. Без вертикального скролла. */
.pl-stats-grid {
  margin-top: calc(10px * var(--ui-space));
  width: 100%;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: calc(9px * var(--ui-space));
}
.pl-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(3px * var(--ui-space));
  padding: calc(11px * var(--ui-space)) calc(5px * var(--ui-space)) calc(9px * var(--ui-space));
  /* конфетная пилюля — как строки рейтинга: белая заливка, лавандовый ободок,
     мягкая тень и глянцевый блик сверху */
  background: linear-gradient(180deg, #ffffff, #f5edfb);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.30);
  border-radius: calc(18px * var(--ui-scale));
  box-shadow: 0 3px 8px rgba(150,120,190,0.18), inset 0 2px 0 rgba(255,255,255,0.9);
}
/* Значок статистики — как на странице «Статистика» */
.pl-stat-icon {
  width: calc(40px * var(--ui-scale));
  height: calc(40px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
}
.pl-stat-val {
  font-size: var(--fs-18);
  font-weight: 900;
  color: #2a1a40;            /* тёмное число — как на статистике */
  line-height: 1.1;
  white-space: nowrap;
}
.pl-stat-label {
  font-size: var(--fs-10);
  font-weight: 800;
  color: #4b2a8c;            /* тёмно-фиолетовая подпись — как на статистике */
  text-align: center;
  line-height: 1.15;
  letter-spacing: 0.02em;
}

/* Кнопка «Подарки» под сеткой чисел — та же кнопка-картинка, что на своей странице
   профиля (.pf-action). Её размеры считаются от --pf-*, а объявляет их .profile-panel,
   поэтому здесь, в чужом экране (рейтинг / друзья), задаём их сами. */
.pl-modal-overlay {
  --pf-scale: var(--ui-scale);
  --pf-space: var(--ui-space);
  /* Буквам — та же мерка, но с общим множителем текста --fs-scale:
     --pf-scale ведёт ещё и аватар с полосой опыта, их не трогаем. */
  --pf-text: calc(var(--pf-scale) * var(--fs-scale));
}
.pl-actions { margin-top: calc(12px * var(--ui-space)); }

/* Витрина подарков игрока — поверх карточки профиля: закрывается сама, профиль остаётся */
.pl-gifts-overlay { z-index: 31; }

/* ═══════════════════════════════════════════════════════════════════════════
   Письма (MailPanel) — милая центрированная карточка в стиле игры.
   Не на весь экран: полупрозрачный затемнённый фон + карточка-модалка.
   Боковые кнопки — картинки как на «Статистике» (assets/mail/nav-*.png).
   ═══════════════════════════════════════════════════════════════════════════ */

/* Фон-подложка: приглушаем и слегка размываем — карточка «всплывает» */
/* Фон и топбар — как в магазине: тот же пастельный градиент .screen,
   заголовок «ПИСЬМА» слева (тёмный, как «МАГАЗИН»), закрыть справа. Без затемнения. */
.mail-panel {
  padding: 0;
  gap: 0;
  overflow: hidden;
  justify-content: flex-start;
  /* фон наследуется от .screen — тот же градиент, что у магазина */
}

/* Верхняя панель — повторяет .sp2-topbar магазина (позиция заголовка/закрытия). */
.mail-topbar {
  width: 100%;
  padding: calc(10px * var(--ui-space)) calc(26px * var(--ui-space))
           calc(10px * var(--ui-space)) calc(42px * var(--ui-space));
  box-sizing: border-box;
}
.mail-topbar-spacer { flex: 1; }

/* Область под топбаром — центрирует карточку */
.mail-stage {
  flex: 1;
  width: 100%;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 calc(20px * var(--ui-space)) calc(20px * var(--ui-space));
  box-sizing: border-box;
}

/* ── Карточка с содержимым (не на весь экран) ── */
.mail-card {
  width: min(1040px, 94vw);
  height: min(560px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  background: linear-gradient(165deg, #fef6ff 0%, #f4e9ff 55%, #ffeef4 100%);
  border-radius: calc(30px * var(--ui-scale));
  border: calc(3px * var(--ui-scale)) solid #ffffff;
  box-shadow:
    0 calc(16px * var(--ui-scale)) calc(44px * var(--ui-scale)) rgba(42,26,64,0.35),
    0 0 0 calc(4px * var(--ui-scale)) rgba(155,111,200,0.4),
    inset 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(255,255,255,0.9);
  overflow: hidden;
  box-sizing: border-box;
}

/* Подсказка-описание раздела стоит НАД телом карточки: у .mail-card своих
   отступов нет (они на .mail-card-body), поэтому верхний зазор строка добавляет
   себе сама. Снизу зазор уже есть — верхнее поле тела. */
.mail-card .mail-note { margin: calc(12px * var(--ui-space)) auto 0; }

/* ── Тело: боковое меню + основная зона ── */
.mail-card-body {
  flex: 1;
  display: flex;
  min-height: 0;
  padding: calc(14px * var(--ui-space)) calc(16px * var(--ui-space)) calc(16px * var(--ui-space));
  gap: calc(14px * var(--ui-space));
  box-sizing: border-box;
}

/* ── Левое меню — кнопки-картинки (размер как на «Статистике») ── */
.mail-sidebar {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(26px * var(--ui-scale));
  flex-shrink: 0;
  padding: 0 calc(2px * var(--ui-space));
}
.mail-nav-btn {
  position: relative;
  width: calc(92px * var(--ui-scale));
  height: calc(92px * var(--ui-scale));
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  opacity: 0.55;
  transition: transform 0.13s, opacity 0.13s;
  display: flex;
  align-items: center;
  justify-content: center;
}
.mail-nav-btn:hover  { opacity: 1; transform: scale(1.05); }
.mail-nav-btn:active { transform: scale(0.94); }
.mail-nav-btn--active { opacity: 1; transform: scale(1.08); }
.mail-nav-btn--active:hover { transform: scale(1.1); }

.mail-nav-img {
  filter: drop-shadow(0 3px 6px rgba(123,63,190,0.3));
}
/* Фолбэк-эмодзи (пока нет картинки) — в виде милой круглой кнопки */
.mail-nav-badge {
  top: calc(-6px * var(--ui-scale));
  right: calc(-6px * var(--ui-scale));
  /* Квадрат с закруглёнными краями, цифры по центру */
  min-width: calc(22px * var(--ui-scale));
  height: calc(22px * var(--ui-scale));
  padding: 0 calc(5px * var(--ui-scale));
  border-radius: calc(7px * var(--ui-scale));
  background: linear-gradient(135deg, #ff5a4e, #c11414);
  font-size: var(--fs-12);
  text-align: center;
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(193,20,20,0.5);
}

/* ── Основная зона: список + просмотр ── */
.mail-main {
  flex: 1;
  display: flex;
  gap: calc(14px * var(--ui-space));
  min-width: 0;
  min-height: 0;
}

/* ── Список писем ── */
.mail-list {
  width: clamp(180px, calc(300px * var(--ui-scale)), 36%);
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: calc(10px * var(--ui-space));
  overflow-y: auto;
  touch-action: pan-y;
  -webkit-overflow-scrolling: touch;
  padding: calc(4px * var(--ui-space)) calc(6px * var(--ui-space)) calc(4px * var(--ui-space)) 0;
  scrollbar-width: thin;
  scrollbar-color: rgba(155,111,200,0.4) transparent;
}

.mail-list-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: calc(10px * var(--ui-space));
  padding: calc(11px * var(--ui-space)) calc(13px * var(--ui-space));
  background: linear-gradient(160deg, #ffffff, #fbf2ff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.25);
  border-radius: calc(18px * var(--ui-scale));
  cursor: pointer;
  text-align: left;
  transition: transform 0.12s, box-shadow 0.12s, border-color 0.12s;
  box-shadow: 0 3px 9px rgba(155,111,200,0.16);
  flex-shrink: 0;
}
.mail-list-item:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(155,111,200,0.3);
  border-color: rgba(155,111,200,0.5);
}
.mail-list-item:active { transform: scale(0.98); }
.mail-list-item--active {
  background: linear-gradient(160deg, #f3e6ff, #ffe6f3);
  border-color: #b06fd8;
  box-shadow: 0 6px 18px rgba(176,111,216,0.4);
}
/* Непрочитанные — малиновая полоса слева + подчёркнуто жирный заголовок.
   И полоса, и «жирность» только рисуются, места не занимают: рамка в 5px вместо
   2px и вес 900 вместо 700 меняли ширину строки, заголовок из двух строк
   складывался в одну — прочитанное письмо съёживалось, и список под ним
   подпрыгивал. Полоса — псевдоэлемент, жирность — обводка глифов. */
.mail-list-item--unread::before {
  content: '';
  position: absolute;
  left: 0;
  top: calc(8px * var(--ui-space));
  bottom: calc(8px * var(--ui-space));
  width: calc(5px * var(--ui-scale));
  border-radius: 999px;
  background: #c2185b;
}
.mail-list-item--unread .mail-list-title {
  -webkit-text-stroke: calc(0.5px * var(--ui-scale)) currentColor;
}

.mail-list-icon {
  width: calc(40px * var(--ui-scale));
  height: calc(40px * var(--ui-scale));
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.mail-list-icon-img { filter: drop-shadow(0 2px 3px rgba(123,63,190,0.25)); }

.mail-list-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.mail-list-sender {
  font-size: var(--fs-11);
  font-weight: 800;
  color: #c23a86;
}
.mail-list-title {
  font-size: var(--fs-14);
  font-weight: 700;
  color: #3a2358;
  line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

.mail-gift-dot {
  font-size: var(--fs-20);
  flex-shrink: 0;
  filter: drop-shadow(0 1px 3px rgba(0,0,0,0.2));
  animation: mail-gift-bounce 1.6s ease-in-out infinite;
}
.mail-gift-img {
  width: calc(30px * var(--ui-scale));
  height: calc(30px * var(--ui-scale));
  object-fit: contain;
  display: block;
}
@keyframes mail-gift-bounce {
  0%, 100% { transform: translateY(0) rotate(-6deg); }
  50%      { transform: translateY(-3px) rotate(6deg); }
}

/* ── Просмотр письма ── */
.mail-detail {
  flex: 1;
  min-width: 0;
  background: linear-gradient(160deg, #ffffff, #fdf4ff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.22);
  border-radius: calc(22px * var(--ui-scale));
  overflow: hidden;
  display: flex;
  box-shadow: inset 0 2px 10px rgba(155,111,200,0.1);
}
.mail-detail-scroll {
  flex: 1;
  overflow-y: auto;
  touch-action: pan-y;
  -webkit-overflow-scrolling: touch;
  padding: calc(16px * var(--ui-space));
  display: flex;
  flex-direction: column;
  gap: calc(12px * var(--ui-space));
  scrollbar-width: thin;
  scrollbar-color: rgba(155,111,200,0.4) transparent;
}

.mail-detail-empty {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: calc(10px * var(--ui-space));
  color: #a07bc8;
  font-size: var(--fs-15);
  font-weight: 700;
}
.mail-detail-empty-emoji { font-size: calc(58px * var(--ui-scale)); opacity: 0.8; }

.mail-empty {
  padding: calc(24px * var(--ui-space)) calc(14px * var(--ui-space));
  color: #a07bc8;
  font-size: var(--fs-14);
  font-weight: 700;
  text-align: center;
}

/* Тело письма — картинка (столбец `image` в БД) плавает в правом верхнем углу,
   заголовок и текст её обтекают. */
.mail-detail-article { display: block; }
.mail-detail-article::after { content: ''; display: block; clear: both; }
/* Показывается только после успешной загрузки (класс вешает onload в MailPanel):
   пока файла нет, пустой квадрат с рамкой и градиентом не должен мелькать. */
.mail-detail-image { display: none; }
.mail-detail-image.is-shown {
  display: block;
  float: right;
  width: calc(146px * var(--ui-scale));
  height: calc(146px * var(--ui-scale));
  margin: calc(2px * var(--ui-scale)) 0 calc(12px * var(--ui-space)) calc(16px * var(--ui-space));
  object-fit: cover;
  border-radius: calc(18px * var(--ui-scale));
  border: calc(2px * var(--ui-scale)) solid #fff;
  background: linear-gradient(135deg, #e6d4f5, #ffd9ea);
  box-shadow: 0 4px 14px rgba(123,63,190,0.25);
}

.mail-detail-timer-row { display: block; margin-top: calc(10px * var(--ui-space)); }
.mail-detail-timer {
  position: absolute;
  bottom: calc(-14px * var(--ui-scale));
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: calc(6px * var(--ui-scale));
  padding: calc(4px * var(--ui-scale)) calc(16px * var(--ui-scale)) calc(4px * var(--ui-scale)) calc(6px * var(--ui-scale));
  /* Плашка повторяет сами часы (assets/mail/icon-timer.png): голубой бок →
     сиреневая середина → розовый край. Оранжевый градиент, стоявший здесь
     раньше, спорил с пастельным артом — часы выглядели наклейкой на чужой
     кнопке. Текст начинается после иконки, то есть уже на сиреневом, где белый
     читается; лёгкая тень держит его и на розовом конце. */
  background: linear-gradient(135deg, #6fb9e8 0%, #9061d8 48%, #d264a6 100%);
  color: #fff;
  font-size: var(--fs-16);
  font-weight: 900;
  text-shadow: 0 1px 2px rgba(86,38,128,0.35);
  border-radius: 50px;
  border: calc(2px * var(--ui-scale)) solid #fff;
  box-shadow: 0 4px 12px rgba(140,80,190,0.45);
  white-space: nowrap;
}
.mail-detail-timer-row .mail-detail-timer { position: static; transform: none; }

/* ── СРОК ПИСЬМА: часы с убывающим счётчиком ──────────────────────────────────
   Одна разметка на список и на открытое письмо (MailPanel._timerHtml): картинка
   часов (assets/mail/icon-timer.png, если файла нет — ⏳) и текст счётчика.
   Текст лежит отдельным .mail-timer-val: тикер меняет раз в секунду только его,
   иначе подмена всей строки гасила бы пульс последних суток каждую секунду.
   Цифры моноширинные — счётчик не дёргает соседей, пока меняет разряды. */
.mail-timer {
  display: inline-flex;
  align-items: center;
  gap: calc(5px * var(--ui-scale));
  white-space: nowrap;
}
/* Циферблат крупный — он тут главный, а не подпись: мелкие часы читались
   значком-точкой, и понять, что это именно СРОК, можно было только по цифрам.
   Размер в em, поэтому часы растут вместе со шрифтом счётчика: в плашке письма
   он крупнее, в ярлычке списка мельче, а часы всюду одного веса относительно
   строки. Вертикальные поля плашки ужаты — иначе крупный циферблат раздувал бы
   её в овал. */
.mail-timer-ico {
  width: 1.75em;
  height: 1.75em;
  object-fit: contain;
  display: block;
  flex-shrink: 0;
  filter: drop-shadow(0 1px 2px rgba(86,38,128,0.28));
}
/* В ярлычке списка шрифт мельче — часам добавляем доли, чтобы они не потерялись. */
.mail-list-timer .mail-timer-ico { width: 2em; height: 2em; }
.mail-timer-emoji { font-size: 1.5em; line-height: 1; }
.mail-timer-val   { font-variant-numeric: tabular-nums; }

/* В списке — тот же леденцовый цвет, что у плашки, только светлой заливкой:
   ярлычок лежит на розово-белой карточке письма и не должен её перекрикивать. */
.mail-list-timer {
  align-self: flex-start;
  margin-top: calc(2px * var(--ui-space));
  padding: calc(1px * var(--ui-scale)) calc(9px * var(--ui-scale)) calc(1px * var(--ui-scale)) calc(3px * var(--ui-scale));
  font-size: var(--fs-11);
  font-weight: 800;
  color: #6b3f9e;
  background: linear-gradient(135deg, rgba(111,185,232,0.34), rgba(231,122,181,0.30));
  border-radius: 999px;
}

/* Последние сутки: счётчик уходит в малиновый (тот же, которым помечено
   непрочитанное письмо) и пульсирует — подарок ещё можно успеть забрать. */
.mail-list-timer.mail-timer--urgent {
  color: #c2185b;
  background: linear-gradient(135deg, rgba(255,143,176,0.40), rgba(216,27,96,0.26));
  animation: mail-timer-pulse 1.6s ease-in-out infinite;
}
.mail-detail-timer.mail-timer--urgent {
  background: linear-gradient(135deg, #ef5f96, #c2185b);
  box-shadow: 0 4px 12px rgba(200,20,70,0.45);
  animation: mail-timer-pulse 1.6s ease-in-out infinite;
}
@keyframes mail-timer-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.6; }
}

.mail-detail-title {
  font-family: 'Segoe UI', system-ui, sans-serif;
  font-size: calc(23px * var(--ui-scale) * var(--fs-scale));
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: 0.01em;
  text-align: center;
  /* Мягкий фиолетово-розовый градиент — лёгкий и ненавязчивый */
  background: linear-gradient(120deg, #8a52c8 0%, #a95fce 52%, #d873ac 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  margin-bottom: calc(9px * var(--ui-space));
}
.mail-detail-sender {
  font-size: var(--fs-13);
  font-weight: 800;
  color: #c23a86;
  text-align: left;
  margin-top: calc(4px * var(--ui-scale));
}
.mail-detail-body {
  font-size: var(--fs-15);
  font-weight: 500;
  color: #4a3568;
  line-height: 1.55;
  margin-top: calc(10px * var(--ui-space));
}

/* Плашка с наградой + кнопка «Забрать» */
.mail-reward-box {
  align-self: center;                /* по центру письма, не растягиваясь на всю ширину */
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: calc(5px * var(--ui-space));
  max-width: 100%;
  margin-top: calc(8px * var(--ui-scale));
  padding: calc(6px * var(--ui-space)) calc(10px * var(--ui-space));
  background: linear-gradient(135deg, #fff7fb, #f3e8ff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.3);
  border-radius: calc(18px * var(--ui-scale));
  box-shadow: 0 3px 10px rgba(155,111,200,0.15);
}
/* Наград может быть четыре (драже, мармелад, опыт и подарок), а рядом ещё
   фантик: в узком письме строка переносится, а не вылезает за плашку. */
.mail-reward-list {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap;
  gap: calc(11px * var(--ui-space));
  min-width: 0;
}
.mail-reward-item {
  display: flex; align-items: center; gap: calc(7px * var(--ui-scale));
  font-size: var(--fs-21);
  font-weight: 900;
  color: #3a2358;
}
.mail-reward-icon {
  width: calc(39px * var(--ui-scale));
  height: calc(39px * var(--ui-scale));
  object-fit: contain;
  filter: drop-shadow(0 3px 6px rgba(123,63,190,0.3));
}
/* ПРЕДМЕТ (подарок, бустер) в строке наград КРУПНЕЕ ВАЛЮТЫ — 64px против 39px.
   Драже и мармелад в письме читаются числом рядом с иконкой, а предмет — самой
   картинкой: по ней игрок и узнаёт, что дали. Вровень с валютой (39px) он для
   этого мелковат.
   64px + два поля под ореол (14px, значение по умолчанию) = 92px — ровно слот
   фантика, поэтому в плашке с фантиком строка наград ниже картинки и высоту
   плашки не поднимает. Свечение лежит в поле и не выходит за <img>
   (см. --gift-glow-room у .gift-glow). */
.mail-reward-item--gift .mail-reward-icon:not(.mail-reward-icon--candy) {
  width:  calc(64px * var(--ui-scale) + 2 * var(--gift-glow-room));
  height: calc(64px * var(--ui-scale) + 2 * var(--gift-glow-room));
}
/* Плашка с одиноким подарком — КВАДРАТ: арт по центру, кнопка под ним. Сторону
   выбирает содержимое (арт 92px + кнопка), a aspect-ratio равняет по ней вторую
   сторону — своих размеров плашке не назначаем, чтобы подпись любой длины
   осталась внутри. */
.mail-reward-box--solo {
  aspect-ratio: 1 / 1;
  justify-content: center;
}

/* ПОДАРОК СТОИТ ОДИН. Тогда он и есть всё письмо, и мерить его нечем: рядом нет
   ни драже, ни мармелада, под которые арт равняли на 39px. Такой подарок рисуем
   вровень с фантиком (92px) — иначе в плашке шириной с кнопку он теряется.
   Класс ставит MailPanel (`solo`): «одна награда, и она — картинка». */
.mail-reward-box--solo .mail-reward-item--gift .mail-reward-icon:not(.mail-reward-icon--candy) {
  width:  calc(92px * var(--ui-scale) + 2 * var(--gift-glow-room));
  height: calc(92px * var(--ui-scale) + 2 * var(--gift-glow-room));
}
/* Конфета-сюрприз («внутри фантик») занимает тот же слот, что и подарок: сама
   она не светится, поэтому поле под ореол ей отдано простым padding'ом — арт
   выходит те же 92px, а квадрат плашки получается один и тот же. */
.mail-reward-box--solo .mail-reward-icon--candy {
  width:  calc(92px * var(--ui-scale) + 2 * var(--gift-glow-room));
  height: calc(92px * var(--ui-scale) + 2 * var(--gift-glow-room));
  box-sizing: border-box;
  padding: var(--gift-glow-room);
}
.mail-reward-emoji { font-size: calc(44px * var(--ui-scale)); line-height: 1; }
/* Заглушка-эмодзи (арт подарка не прислали) растёт вместе с одиноким подарком,
   а строкой занимает ровно слот арта — квадрат плашки не зависит от того,
   прислали картинку или нет. */
.mail-reward-box--solo .mail-reward-emoji {
  font-size: calc(88px * var(--ui-scale));
  line-height: calc(92px * var(--ui-scale) + 2 * var(--gift-glow-room));
}
/* Конфета-сюрприз («внутри фантик») — тот же обещанный предмет, что и подарок
   рядом, и ростом с него: 64px. Одна в плашке — крупная
   (см. .mail-reward-box--solo выше). */
.mail-reward-icon--candy {
  width:  calc(64px * var(--ui-scale));
  height: calc(64px * var(--ui-scale));
}
/* Кнопка «Забрать» — фирменный стиль игры (золото→оранж, как «Играть» и кнопки магазина) */
.mail-claim-btn {
  min-height: calc(40px * var(--ui-scale));
  padding: 0 calc(22px * var(--ui-space));
  border: none;
  border-radius: 50px;
  background: linear-gradient(135deg, #f5c518, #e07020);
  color: #fff;
  font-size: var(--fs-15);
  font-weight: 800;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.10s, box-shadow 0.10s;
  box-shadow: 0 3px 14px rgba(200,134,10,0.5);
  white-space: nowrap;
}
.mail-claim-btn:hover  { transform: scale(1.05); box-shadow: 0 6px 18px rgba(200,134,10,0.65); }
.mail-claim-btn:active { transform: scale(0.94); }
.mail-claim-btn:disabled { opacity: 0.4; cursor: default; transform: none; box-shadow: none; }

/* ── ФАНТИК в письме ────────────────────────────────────────────────────────
   Маленькая картинка под текстом; по клику разворачивается на весь экран
   (тот же лайтбокс, что в «Коллекции» — .col-lightbox-*). Кнопка под ней подписана
   сервером: «Забрать» для нового фантика, «Положить в сундучок» для повторки. */
/* ФАНТИК И НАГРАДЫ СТОЯТ В РЯД. Столбиком (фантик → награды → кнопка) плашка
   вытягивалась на три строки, и высоты в ней было вдвое больше, чем содержимого.
   Сетка ставит награды СПРАВА от фантика, а кнопку — строкой ниже, во всю ширину:
   высота падает почти вдвое, а ширина прибавляет строку наград — колонка письма
   (~560px на большом экране) её принимает, на узких строка наград переносится
   (flex-wrap у .mail-reward-list).
   Класс ставится, ТОЛЬКО когда рядом с фантиком есть награды: пустой второй
   столбец сам нулевой ширины, но зазор между столбцами никуда не девается, и
   фантик в первом столбце уезжал влево на половину зазора от кнопки, растянутой
   на оба. Фантик один — плашка остаётся обычной колонкой (см. MailPanel). */
.mail-reward-box--wrapper {
  display: inline-grid;
  grid-template-columns: auto auto;
  justify-items: center;
  column-gap: calc(14px * var(--ui-space));
  row-gap: calc(8px * var(--ui-space));
}
.mail-reward-box--wrapper > .mail-wrapper-thumb { grid-area: 1 / 1; }
.mail-reward-box--wrapper > .mail-reward-list   { grid-area: 1 / 2; }
.mail-reward-box--wrapper > .mail-claim-btn,
.mail-reward-box--wrapper > .mail-claimed-badge { grid-column: 1 / -1; }

.mail-wrapper-thumb {
  position: relative;
  width: calc(92px * var(--ui-scale));
  padding: 0;
  border: none;
  background: none;
  /* Палец, а не лупа: фантик в письме — обычная кнопка (лупа осталась только у
     аватаров в профиле). Разворот на весь экран при этом никуда не делся. */
  cursor: pointer;
  display: block;
  line-height: 0;
}

.mail-wrapper-img {
  width: 100%;
  /* Квадрат, как в «Коллекции» (.col-detail-item-img-wrap): один и тот же фантик
     не должен менять пропорции при переходе из письма в коллекцию. */
  aspect-ratio: 1 / 1;
  object-fit: cover;
  display: block;
  border-radius: calc(10px * var(--ui-scale));
  box-shadow: 0 4px 14px rgba(100,60,160,0.3);
  transition: transform 0.15s, box-shadow 0.15s;
}

.mail-wrapper-thumb:hover .mail-wrapper-img {
  transform: scale(1.05);
  box-shadow: 0 8px 24px rgba(100,60,160,0.4);
}
.mail-wrapper-thumb:active .mail-wrapper-img { transform: scale(0.97); }

/* УРОВЕНЬ РЕДКОСТИ найденного фантика — только бледная рамка в цвет уровня,
   без подписи: редкость остаётся внутренней механикой. Цвет приходит с сервера
   в --rarity (collection_rarity_levels.color) — палитра правится в БД. */
.mail-wrapper-thumb[data-rarity]::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: calc(10px * var(--ui-scale));
  border: calc(4px * var(--ui-scale)) solid var(--rarity, #b8c4d6);
  opacity: 0.32;
  pointer-events: none;
  transition: transform 0.15s;
}

/* Картинка на наведении масштабируется — рамка едет вместе с ней. */
.mail-wrapper-thumb[data-rarity]:hover::after  { transform: scale(1.05); }
.mail-wrapper-thumb[data-rarity]:active::after { transform: scale(0.97); }

/* Метка на картинке: такой фантик у игрока уже есть. Лежит ВНУТРИ картинки, у
   нижнего края: снаружи она висела в зазоре плашки и держала его шире, чем нужно
   самой плашке (тот же приём, что у значков плитки — см. .tile-new-dot). */
.mail-wrapper-dupe {
  position: absolute;
  left: 50%;
  bottom: calc(5px * var(--ui-scale));
  transform: translateX(-50%);
  padding: calc(2px * var(--ui-scale)) calc(9px * var(--ui-scale));
  border-radius: 50px;
  background: rgba(42,26,64,0.82);
  color: #fff;
  font-size: var(--fs-10);
  font-weight: 800;
  letter-spacing: 0.03em;
  white-space: nowrap;
  line-height: 1.6;
}

/* Плашка «Получено» — фирменный «готово», как значок «Надето» в магазине.
   Ростом с кнопку «Забрать» (min-height): иначе в момент получения плашка
   письма подпрыгивала — кнопка уходила, а «Получено» вставало ниже ростом. */
.mail-claimed-badge {
  display: inline-flex;
  align-items: center;
  min-height: calc(40px * var(--ui-scale));
  padding: calc(7px * var(--ui-space)) calc(16px * var(--ui-space));
  border-radius: 50px;
  background: rgba(155,111,200,0.12);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.45);
  color: #7b3fbe;
  font-size: var(--fs-14);
  font-weight: 800;
}

/* ═══ Адаптив ═══ */
/* Планшет / узкий ландшафт — сжимаем список */
@media (max-width: 900px) {
  .mail-list { width: clamp(150px, calc(240px * var(--ui-scale)), 34%); }
}
/* Узкие / портрет — карточка почти на весь экран, вкладки в ряд, список сверху */
@media (max-width: 640px) {
  .mail-topbar { padding-left: calc(20px * var(--ui-space)); padding-right: calc(14px * var(--ui-space)); }
  .mail-stage  { padding: 0 calc(8px * var(--ui-space)) calc(8px * var(--ui-space)); }
  .mail-card   { width: 100%; height: 100%; }
  .mail-card-body { flex-direction: column; padding: calc(10px * var(--ui-space)); gap: calc(10px * var(--ui-space)); }
  .mail-sidebar {
    flex-direction: row;
    justify-content: center;
    gap: calc(22px * var(--ui-scale));
    padding: calc(2px * var(--ui-space)) 0;
    flex-shrink: 0;
  }
  .mail-main { flex-direction: column; min-height: 0; }
  .mail-list {
    width: 100%;
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    touch-action: pan-x;
    flex: 0 0 auto;
    max-height: calc(120px * var(--ui-scale));
    padding-bottom: calc(8px * var(--ui-space));
  }
  .mail-list-item { min-width: calc(200px * var(--ui-scale)); }
  .mail-detail { flex: 1; }
}
/* Совсем маленькие экраны */
@media (max-height: 430px) {
  .mail-card   { height: 100%; }
  .mail-topbar { padding-top: calc(6px * var(--ui-space)); padding-bottom: calc(6px * var(--ui-space)); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Раздел «От друзей»: две вкладки — Заявки и Подарки
   ═══════════════════════════════════════════════════════════════════════════ */
.mail-friend {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: calc(12px * var(--ui-space));
  padding-left: calc(18px * var(--ui-space));
  min-width: 0;
  min-height: 0;
}

/* ── Вкладки сверху ── */
.mail-tabs {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: calc(12px * var(--ui-space));
  flex-shrink: 0;
  padding-bottom: calc(2px * var(--ui-space));
}
.mail-tab {
  position: relative;
  padding: calc(10px * var(--ui-space)) calc(30px * var(--ui-space));
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.3);
  border-radius: 50px;
  background: linear-gradient(160deg, #ffffff, #f7edff);
  color: #7b3fbe;
  font-size: var(--fs-15);
  font-weight: 800;
  cursor: pointer;
  transition: transform 0.12s, box-shadow 0.12s, border-color 0.12s;
  box-shadow: 0 2px 8px rgba(155,111,200,0.15);
  white-space: nowrap;
}
.mail-tab:hover  { transform: translateY(-2px); box-shadow: 0 5px 14px rgba(155,111,200,0.28); }
.mail-tab:active { transform: scale(0.96); }
.mail-tab--active {
  background: linear-gradient(135deg, #b06fd8, #d873ac);
  border-color: #b06fd8;
  color: #fff;
  box-shadow: 0 5px 16px rgba(176,111,216,0.45);
}
.mail-tab-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: calc(20px * var(--ui-scale));
  height: calc(20px * var(--ui-scale));
  margin-left: calc(7px * var(--ui-scale));
  padding: 0 calc(5px * var(--ui-scale));
  background: linear-gradient(135deg, #ff5a4e, #c11414);
  color: #fff;
  font-size: var(--fs-12);
  font-weight: 900;
  border-radius: calc(7px * var(--ui-scale));
  box-shadow: 0 2px 6px rgba(193,20,20,0.5);
  vertical-align: middle;
}
.mail-tab--active .mail-tab-badge { background: #fff; color: #c11414; }

.mail-friend-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* ── Вкладка «Заявки» ── */
.freq-list {
  display: flex;
  flex-direction: column;
  gap: calc(10px * var(--ui-space));
  overflow-y: auto;
  padding: calc(4px * var(--ui-space)) calc(6px * var(--ui-space)) calc(4px * var(--ui-space)) 0;
  scrollbar-width: thin;
  scrollbar-color: rgba(155,111,200,0.4) transparent;
}

.freq-row {
  display: flex;
  align-items: center;
  gap: calc(12px * var(--ui-space));
  padding: calc(10px * var(--ui-space)) calc(14px * var(--ui-space));
  background: linear-gradient(160deg, #ffffff, #fbf2ff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.25);
  border-radius: calc(18px * var(--ui-scale));
  box-shadow: 0 3px 9px rgba(155,111,200,0.16);
  flex-shrink: 0;
  width: 100%;
  max-width: calc(440px * var(--ui-scale));
  align-self: center;
}
.freq-avatar {
  width: calc(46px * var(--ui-scale));
  height: calc(46px * var(--ui-scale));
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  border: calc(2px * var(--ui-scale)) solid #fff;
  box-shadow: 0 2px 6px rgba(123,63,190,0.25);
}
.freq-avatar-ph {
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #b06fd8, #d873ac);
  color: #fff;
  font-size: var(--fs-20);
  font-weight: 900;
}
.freq-name {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-15);
  font-weight: 800;
  color: #3a2358;
}

/* ── Список «Мои друзья»: аватар покрупнее, без белой окантовки; ник открывает окно
      профиля игрока (как в рейтингах), аватар разворачивает арт. ── */
.fp-row .freq-avatar {
  width: calc(56px * var(--ui-scale));
  height: calc(56px * var(--ui-scale));
  border: none;
}
.fp-row .freq-avatar-ph { font-size: calc(24px * var(--ui-scale)); }
.fp-row .freq-name { font-size: var(--fs-17-5); }
.fp-player-link { cursor: pointer; }
/* Значок ранга друга — между аватаром и ником (картинка из assets/leagues/). */
.fp-rank {
  display: flex; align-items: center; justify-content: center;
  width: calc(36px * var(--ui-scale));
  height: calc(36px * var(--ui-scale));
  flex-shrink: 0;
  margin-left: calc(-4px * var(--ui-space));
}
.freq-actions { display: flex; align-items: center; gap: calc(9px * var(--ui-space)); flex-shrink: 0; }
.freq-approve {
  min-height: calc(40px * var(--ui-scale));
  padding: 0 calc(20px * var(--ui-space));
  border: none;
  border-radius: 50px;
  background: linear-gradient(135deg, #b06fd8, #d873ac);
  color: #fff;
  font-size: var(--fs-14);
  font-weight: 800;
  cursor: pointer;
  transition: transform 0.10s, box-shadow 0.10s;
  box-shadow: 0 3px 12px rgba(176,111,216,0.45);
  white-space: nowrap;
}
.freq-approve:hover  { transform: scale(1.05); box-shadow: 0 6px 16px rgba(176,111,216,0.6); }
.freq-approve:active { transform: scale(0.94); }

/* ── Полученные подарки от друзей: строка с описанием подарка ── */
.gift-in-row .freq-name {
  white-space: normal;
  display: flex;
  flex-direction: column;
  gap: calc(3px * var(--ui-space));
  line-height: 1.2;
}
.gift-in-desc {
  display: inline-flex;
  align-items: center;
  gap: calc(5px * var(--ui-space));
  font-size: var(--fs-13);
  font-weight: 800;
  color: #7b3fbe;
}
.gift-in-coin, .gift-in-img {
  width: calc(20px * var(--ui-scale));
  height: calc(20px * var(--ui-scale));
  object-fit: contain;
  flex-shrink: 0;
}
/* У подарка картинка шире арта на два поля под ореол: сам арт те же 20px, что и у
   драже рядом, а свечение лежит в поле и не выходит за <img> (--gift-glow-room). */
.gift-in-img {
  width:  calc(20px * var(--ui-scale) + 2 * var(--gift-glow-room));
  height: calc(20px * var(--ui-scale) + 2 * var(--gift-glow-room));
}
.gift-in-claim {
  min-height: calc(40px * var(--ui-scale));
  padding: 0 calc(20px * var(--ui-space));
  font-size: var(--fs-14);
}

/* ── Вызов на дуэль во «Входящих»: тот же ряд, что у заявок в друзья, плюс счёт
      вызвавшего и остаток 12-часового окна (данные из duel_invites). ── */
.mail-duel-row .freq-name {
  white-space: normal;
  display: flex;
  flex-direction: column;
  gap: calc(3px * var(--ui-space));
  line-height: 1.2;
}
.mail-duel-desc {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: calc(6px * var(--ui-space));
  font-size: var(--fs-12-5);
  font-weight: 700;
  color: #7b5a9a;
}
.mail-duel-desc b { color: #3a2358; }
.mail-duel-timer {
  display: inline-flex;
  align-items: center;
  gap: calc(4px * var(--ui-space));
  padding: calc(1px * var(--ui-space)) calc(7px * var(--ui-space));
  background: rgba(247,168,56,0.16);
  border-radius: calc(10px * var(--ui-scale));
  color: #a8762a;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.mail-duel-timer-ico {
  width: calc(13px * var(--ui-scale));
  height: calc(13px * var(--ui-scale));
  object-fit: contain;
}
.mail-duel-accept { background: linear-gradient(135deg, #f7a838, #ef6ea0); }
.mail-duel-accept:hover { box-shadow: 0 6px 16px rgba(247,168,56,0.55); }
.freq-reject {
  width: calc(40px * var(--ui-scale));
  height: calc(40px * var(--ui-scale));
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border: calc(2px * var(--ui-scale)) solid rgba(194,24,91,0.4);
  border-radius: 50%;
  background: #fff5f9;
  color: #c2185b;
  font-size: var(--fs-18);
  font-weight: 900;
  cursor: pointer;
  transition: transform 0.10s, background 0.10s;
}
.freq-reject:hover  { transform: scale(1.08); background: #ffe6ef; }
.freq-reject:active { transform: scale(0.92); }
.freq-reject-img { width: 65%; height: 65%; object-fit: contain; display: block; }

/* ── Вкладка «Подарки»: список друзей + панель дарения ── */
.gift-wrap {
  flex: 1;
  display: flex;
  gap: calc(14px * var(--ui-space));
  min-width: 0;
  min-height: 0;
}
.gift-friends {
  width: clamp(160px, calc(260px * var(--ui-scale)), 36%);
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: calc(9px * var(--ui-space));
  overflow-y: auto;
  padding: calc(4px * var(--ui-space)) calc(6px * var(--ui-space)) calc(4px * var(--ui-space)) 0;
  scrollbar-width: thin;
  scrollbar-color: rgba(155,111,200,0.4) transparent;
}

.gift-friend-row {
  display: flex;
  align-items: center;
  gap: calc(10px * var(--ui-space));
  padding: calc(9px * var(--ui-space)) calc(12px * var(--ui-space));
  background: linear-gradient(160deg, #ffffff, #fbf2ff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.25);
  border-radius: calc(16px * var(--ui-scale));
  cursor: pointer;
  text-align: left;
  transition: transform 0.12s, box-shadow 0.12s, border-color 0.12s;
  box-shadow: 0 3px 9px rgba(155,111,200,0.16);
  flex-shrink: 0;
}
.gift-friend-row:hover  { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(155,111,200,0.3); border-color: rgba(155,111,200,0.5); }
.gift-friend-row:active { transform: scale(0.98); }
.gift-friend-row--active {
  background: linear-gradient(160deg, #f3e6ff, #ffe6f3);
  border-color: #b06fd8;
  box-shadow: 0 6px 18px rgba(176,111,216,0.4);
}
.gift-friend-avatar {
  width: calc(40px * var(--ui-scale));
  height: calc(40px * var(--ui-scale));
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  box-shadow: 0 2px 5px rgba(123,63,190,0.22);
}
.gift-friend-avatar-ph {
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #b06fd8, #d873ac);
  color: #fff;
  font-size: var(--fs-18);
  font-weight: 900;
}
.gift-friend-name {
  flex: 1; min-width: 0;
  font-size: var(--fs-14);
  font-weight: 800;
  color: #3a2358;
}

/* Панель дарения (правая колонка) */
.gift-compose {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: linear-gradient(160deg, #fffdff, #f7edff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.22);
  border-radius: calc(20px * var(--ui-scale));
  padding: calc(16px * var(--ui-space));
  overflow-y: auto;
}
.gift-compose-empty {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: calc(10px * var(--ui-space));
  color: #a07bc8;
  font-size: var(--fs-15);
  font-weight: 700;
  text-align: center;
}
.gift-compose-hero {
  width: calc(96px * var(--ui-scale));
  height: auto;
  object-fit: contain;
  filter: drop-shadow(0 6px 14px rgba(176,111,216,0.28));
}
.gift-compose-inner { display: flex; flex-direction: column; gap: calc(14px * var(--ui-space)); }
.gift-compose-title {
  font-size: var(--fs-16);
  font-weight: 800;
  color: #4a3568;
  text-align: center;
}
.gift-compose-title b { color: #c23a86; }

/* Переключатель Драже / Подарок */
.gift-seg {
  display: flex;
  gap: calc(8px * var(--ui-space));
  background: rgba(155,111,200,0.1);
  border-radius: 50px;
  padding: calc(4px * var(--ui-scale));
}
.gift-seg-btn {
  flex: 1;
  padding: calc(8px * var(--ui-space)) 0;
  border: none;
  border-radius: 50px;
  background: transparent;
  color: #7b3fbe;
  font-size: var(--fs-14);
  font-weight: 800;
  cursor: pointer;
  transition: background 0.12s, color 0.12s, box-shadow 0.12s;
}
.gift-seg-btn--active {
  background: linear-gradient(135deg, #b06fd8, #d873ac);
  color: #fff;
  box-shadow: 0 3px 10px rgba(176,111,216,0.4);
}

/* Баланс + пресеты драже */
.gift-balance {
  display: flex; align-items: center; justify-content: center;
  gap: calc(6px * var(--ui-scale));
  font-size: var(--fs-14);
  font-weight: 800;
  color: #4a3568;
}
.gift-balance-icon { width: calc(22px * var(--ui-scale)); height: calc(22px * var(--ui-scale)); object-fit: contain; }
.gift-presets {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: calc(10px * var(--ui-space));
}
.gift-preset {
  display: flex; align-items: center; justify-content: center;
  gap: calc(6px * var(--ui-scale));
  padding: calc(11px * var(--ui-space)) 0;
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.3);
  border-radius: calc(14px * var(--ui-scale));
  background: linear-gradient(160deg, #ffffff, #fbf2ff);
  color: #3a2358;
  font-size: var(--fs-16);
  font-weight: 900;
  cursor: pointer;
  transition: transform 0.10s, box-shadow 0.10s, border-color 0.10s;
}
.gift-preset:hover:not(:disabled)  { transform: translateY(-2px); box-shadow: 0 5px 14px rgba(155,111,200,0.28); }
.gift-preset:active:not(:disabled) { transform: scale(0.96); }
.gift-preset--active {
  background: linear-gradient(160deg, #f3e6ff, #ffe6f3);
  border-color: #b06fd8;
  box-shadow: 0 5px 16px rgba(176,111,216,0.4);
}
.gift-preset:disabled { opacity: 0.35; cursor: default; }
.gift-preset-icon { width: calc(22px * var(--ui-scale)); height: calc(22px * var(--ui-scale)); object-fit: contain; }

/* Сетка подарков из инвентаря */
.gift-inv-empty {
  color: #a07bc8;
  font-size: var(--fs-14);
  font-weight: 700;
  text-align: center;
  padding: calc(14px * var(--ui-space)) calc(6px * var(--ui-space));
}
/* Ровно три подарка в ряду — столько же, сколько в витрине инвентаря на странице
   профиля (.pf-grid--gift): это один и тот же список, и раскладываться он должен
   одинаково, где бы игрок его ни открыл. Число колонок задано, а не выведено из
   auto-fill: ширина панели дарения зависит и от экрана, и от списка друзей слева,
   поэтому auto-fill насчитывал от 4 колонок на широком экране до 8 на узком — ряд
   прыгал, а карточка на мелком экране становилась меньше, чем в неё можно попасть
   пальцем. minmax(0, 1fr) вместо 1fr: без него трек не может стать уже своего
   содержимого и три колонки вытолкнули бы сетку за край панели.
   Карточка теперь шире арта — так и задумано: арт вырос до 92px (см. .gift-inv-img),
   и карточка выходит почти квадратной. */
.gift-inv-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: calc(10px * var(--ui-space));
}
.gift-inv-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(5px * var(--ui-scale));
  padding: calc(10px * var(--ui-space)) calc(6px * var(--ui-space));
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.28);
  border-radius: calc(16px * var(--ui-scale));
  background: linear-gradient(160deg, #ffffff, #fbf2ff);
  cursor: pointer;
  transition: transform 0.10s, box-shadow 0.10s, border-color 0.10s;
  box-shadow: 0 3px 9px rgba(155,111,200,0.16);
}
.gift-inv-card:hover  { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(155,111,200,0.3); }
.gift-inv-card:active { transform: scale(0.97); }
.gift-inv-card--active {
  background: linear-gradient(160deg, #f3e6ff, #ffe6f3);
  border-color: #b06fd8;
  box-shadow: 0 6px 18px rgba(176,111,216,0.4);
}
.gift-inv-qty {
  position: absolute;
  top: calc(-8px * var(--ui-scale));
  right: calc(-6px * var(--ui-scale));
  min-width: calc(22px * var(--ui-scale));
  height: calc(22px * var(--ui-scale));
  display: flex; align-items: center; justify-content: center;
  padding: 0 calc(5px * var(--ui-scale));
  background: linear-gradient(135deg, #f5c518, #e07020);
  color: #fff;
  font-size: var(--fs-12);
  font-weight: 900;
  border-radius: calc(9px * var(--ui-scale));
  border: calc(2px * var(--ui-scale)) solid #fff;
  box-shadow: 0 2px 6px rgba(200,134,10,0.5);
}
/* Картинка шире арта на два поля под ореол: арт 92px (см. --gift-glow-room) — тот же
   размер, что у плитки инвентаря в профиле. В ряду теперь три карточки вместо четырёх
   и более, и в карточке шириной с треть панели арт на 54px тонул бы в пустом поле. */
.gift-inv-img {
  width:  calc(92px * var(--ui-scale) + 2 * var(--gift-glow-room));
  height: calc(92px * var(--ui-scale) + 2 * var(--gift-glow-room));
  object-fit: contain;
}

/* Кнопка «Подарить» — фирменный золотой стиль (как «Забрать») */
.gift-send-btn {
  align-self: center;
  min-height: calc(48px * var(--ui-scale));
  padding: 0 calc(34px * var(--ui-space));
  border: none;
  border-radius: 50px;
  background: linear-gradient(135deg, #f5c518, #e07020);
  color: #fff;
  font-size: var(--fs-16);
  font-weight: 800;
  cursor: pointer;
  transition: transform 0.10s, box-shadow 0.10s;
  box-shadow: 0 3px 14px rgba(200,134,10,0.5);
  margin-top: calc(4px * var(--ui-space));
}
.gift-send-btn:hover:not(:disabled)  { transform: scale(1.05); box-shadow: 0 6px 18px rgba(200,134,10,0.65); }
.gift-send-btn:active:not(:disabled) { transform: scale(0.94); }
.gift-send-btn:disabled { opacity: 0.4; cursor: default; box-shadow: none; }

/* Пустое состояние магазина (раздел «Подарки») */
.sp2-empty {
  padding: calc(30px * var(--ui-space)) calc(16px * var(--ui-space));
  color: #a07bc8;
  font-size: var(--fs-15);
  font-weight: 700;
  text-align: center;
}

/* Адаптив раздела друзей: на узких экранах стек */
@media (max-width: 640px) {
  .gift-wrap { flex-direction: column; }
  .gift-friends {
    width: 100%;
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    flex: 0 0 auto;
    max-height: calc(96px * var(--ui-scale));
  }
  .gift-friend-row { min-width: calc(170px * var(--ui-scale)); }
  .gift-compose { flex: 1; }
  .freq-approve { padding: 0 calc(14px * var(--ui-space)); }
}

/* ══════════════════════════════════════════════════════════════════════════════
   Страница «Друзья» (FriendsPanel) — кнопка 👥 в главном меню.
   Оболочка повторяет «Письма»: топбар магазина + карточка по центру.
   ══════════════════════════════════════════════════════════════════════════════ */
.friends-panel {
  padding: 0;
  gap: 0;
  overflow: hidden;
  justify-content: flex-start;
  /* фон наследуется от .screen — тот же градиент, что у магазина */
}

/* Верхняя панель — повторяет .sp2-topbar магазина (позиция заголовка/закрытия). */
.fp-topbar {
  width: 100%;
  padding: calc(10px * var(--ui-space)) calc(26px * var(--ui-space))
           calc(10px * var(--ui-space)) calc(42px * var(--ui-space));
  box-sizing: border-box;
}
.fp-topbar-spacer { flex: 1; }
.fp-topbar .sp2-topbar-title {
  min-width: 0;
}

/* Область под топбаром — центрирует карточку */
.fp-stage {
  flex: 1;
  width: 100%;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 calc(20px * var(--ui-space)) calc(20px * var(--ui-space));
  box-sizing: border-box;
}

/* Размер карточки масштабируется вместе с содержимым (--ui-scale): на низких
   экранах контент сжимается, и карточка фиксированной ширины 720px выглядела
   растянутой и полупустой. Пропорция 720/560 сохраняется на всех масштабах. */
.fp-card {
  width: min(calc(720px * var(--ui-scale)), 94vw);
  height: min(calc(560px * var(--ui-scale)), 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  gap: calc(12px * var(--ui-space));
  padding: calc(18px * var(--ui-space)) calc(18px * var(--ui-space)) calc(20px * var(--ui-space));
  background: linear-gradient(165deg, #fef6ff 0%, #f4e9ff 55%, #ffeef4 100%);
  border-radius: calc(30px * var(--ui-scale));
  border: calc(3px * var(--ui-scale)) solid #ffffff;
  box-shadow:
    0 calc(16px * var(--ui-scale)) calc(44px * var(--ui-scale)) rgba(42,26,64,0.35),
    0 0 0 calc(4px * var(--ui-scale)) rgba(155,111,200,0.4),
    inset 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(255,255,255,0.9);
  overflow: hidden;
  box-sizing: border-box;
}

.fp-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* Списку и заглушке нужен min-height:0, иначе их min-content высота не даёт
   .fp-body сжаться и карточка перерастает экран. */
.fp-body > .freq-list,
.fp-body > .mail-empty {
  flex: 1 1 auto;
  min-height: 0;
}

/* Напоминание про подарки через письма — общая плашка .ui-note (в конце файла).
   Здесь она стоит первой строкой карточки и ничем не отличается от такой же
   подсказки в коллекции, письмах или рейтинге. */

/* ── Вкладка «Мои друзья»: строки как в заявках + кнопка удаления ── */
.fp-row { max-width: calc(520px * var(--ui-scale)); }

.fp-del {
  width: calc(40px * var(--ui-scale));
  height: calc(40px * var(--ui-scale));
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border: calc(2px * var(--ui-scale)) solid rgba(194,24,91,0.4);
  border-radius: 50%;
  background: #fff5f9;
  color: #c2185b;
  font-size: var(--fs-18);
  font-weight: 900;
  cursor: pointer;
  transition: transform 0.10s, background 0.10s;
}
.fp-del:hover  { transform: scale(1.08); background: #ffe6ef; }
.fp-del:active { transform: scale(0.92); }
.fp-del:disabled { opacity: 0.5; cursor: default; }
.fp-del-img { width: 65%; height: 65%; object-fit: contain; display: block; }

/* Второй тап — подтверждение удаления */
.fp-del--confirm {
  width: auto;
  min-width: calc(84px * var(--ui-scale));
  padding: 0 calc(16px * var(--ui-space));
  border-radius: 50px;
  border-color: transparent;
  background: linear-gradient(135deg, #e0507a, #c2185b);
  color: #fff;
  font-size: var(--fs-14);
  font-weight: 800;
  box-shadow: 0 3px 12px rgba(194,24,91,0.45);
}
.fp-del--confirm:hover { background: linear-gradient(135deg, #ea5c86, #d21e66); transform: scale(1.04); }

/* ── Вкладка «Добавить друга»: QR / поиск по нику (стили .fr-* переиспользуются) ── */
.fp-add {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(14px * var(--ui-space));
  overflow: hidden;
}
/* .fp-add центрирует содержимое, поэтому ширину задаём явно — иначе flex:1
   у .fr-opt считался бы от ширины самих иконок. */
.fp-add .fr-modal-options {
  width: 100%;
  max-width: calc(300px * var(--ui-scale));
  flex: 0 0 auto;
}
/* Иконки QR/поиска отдают высоту содержимому на низких экранах. */
.fp-add .fr-opt-ico {
  width: min(calc(68px * var(--ui-scale)), 12vh);
  height: min(calc(68px * var(--ui-scale)), 12vh);
}
/* Базовый .fr-modal-body рассчитан на модалку с распорной min-height; здесь
   тело обязано укладываться в остаток карточки, а не задавать ей высоту. */
.fp-add .fr-modal-body {
  width: 100%;
  max-width: calc(420px * var(--ui-scale));
  flex: 1 1 auto;
  min-height: 0;
}

/* QR: подсказка и ID занимают свою высоту, рамка забирает весь остаток и
   переводит его в ширину через aspect-ratio — так код всегда квадратный и
   всегда влезает без вертикального скролла. */
.fp-add .fr-qr {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  justify-content: center;
}
.fp-add .fr-qr-frame {
  flex: 1 1 0;
  width: auto;
  height: auto;
  aspect-ratio: 1;
  min-height: calc(84px * var(--ui-scale));
  max-height: calc(216px * var(--ui-scale));
  max-width: 100%;
}
.fp-add .fr-qr-hint,
.fp-add .fr-qr-id { flex: 0 0 auto; }

/* Ссылка: тело карточки уже растянуто по высоте — блок просто центрируется в нём. */
.fp-add .fr-link { width: 100%; padding: 0; }

/* Поиск по нику: результаты растягиваются на остаток вместо фиксированных 250px. */
.fp-add .fr-search { flex: 0 0 auto; }
.fp-add .fr-results {
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;
}
/* Найденный игрок, который уже в друзьях — вместо кнопки «Отправить запрос» */


/* ── Вкладка «Акция»: бегущая обводка ──
   Пока вкладка НЕ выбрана, по её рамке БЕЗ ОСТАНОВКИ бежит по кругу радуга из
   цветов игры — так вкладка зовёт, не мигая и не дёргаясь.
   Слоёв три. Внизу — обойма .fp-tab-ring (пустой span в разметке) размером
   ровно с рамку; она скруглена и обрезает по себе всё, что внутри. Внутри неё
   крутится квадрат с КОНИЧЕСКОЙ радугой (::before обоймы). Сверху — заливка
   кнопки (::after самой кнопки), она закрывает радугу везде, кроме кромки в
   толщину рамки: эта кромка и читается как обводка.
   Круг замыкает сам поворот на 360°, поэтому шва на стыке цикла нет в принципе;
   крутит transform — он работает и в старом Android WebView, в отличие от угла
   через @property. Прежний приём — сдвиг background-position у линейного
   градиента — вёл цвета не по кругу, а поперёк кнопки, и на конце цикла прыгал:
   у левого края фиолетовый одним кадром сменялся жёлтым.
   Обрезает радугу обойма, а не сама кнопка: кнопке нельзя ни overflow (он режет
   по padding-box, и под прозрачной рамкой радуги не было бы видно), ни clip-path
   (он срезал бы вместе с радугой мягкую тень под кнопкой).
   isolation даёт кнопке свой слой, чтобы отрицательный z-index слоёв уводил их
   под текст кнопки, а не под всю панель.
   Выбранная вкладка обводку не носит: она и так залита цветом (.mail-tab--active). */
.fp-card .mail-tab.fp-tab-promo:not(.mail-tab--active) {
  border-color: transparent;
  background: none;
  isolation: isolate;
}
/* Обойма: растянута на border-box кнопки (наружу ровно на толщину рамки). */
.fp-card .mail-tab.fp-tab-promo:not(.mail-tab--active) .fp-tab-ring {
  position: absolute;
  z-index: -2;
  inset: calc(-2px * var(--ui-scale));
  border-radius: 50px;
  overflow: hidden;
  pointer-events: none;
}
/* Радуга. Квадрат со стороной в полторы ширины кнопки: диагональ кнопки короче
   её ширины × √2, поэтому на любом угле поворота он накрывает кнопку целиком. */
.fp-card .mail-tab.fp-tab-promo:not(.mail-tab--active) .fp-tab-ring::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 150%;
  aspect-ratio: 1 / 1;
  background: conic-gradient(
    #b06fd8, #d873ac, #f0836a, #ffc44d, #6fd06f, #57c7e8, #b06fd8);
  transform: translate(-50%, -50%);
  animation: fp-tab-run 3.2s linear infinite;
}
/* Заливка кнопки поверх радуги — та же, что у обычной вкладки. inset считается
   от padding-box, поэтому наружу остаётся ровно толщина рамки. */
.fp-card .mail-tab.fp-tab-promo:not(.mail-tab--active)::after {
  content: '';
  position: absolute;
  z-index: -1;
  inset: 0;
  border-radius: 50px;
  background: linear-gradient(160deg, #ffffff, #f7edff);
}

@keyframes fp-tab-run {
  from { transform: translate(-50%, -50%) rotate(0deg); }
  to   { transform: translate(-50%, -50%) rotate(360deg); }
}

/* Меньше движения — радуга просто стоит: рамка остаётся цветной, кнопка не
   теряет вид, но по кругу ничего не бежит. */
@media (prefers-reduced-motion: reduce) {
  .fp-card .mail-tab.fp-tab-promo:not(.mail-tab--active) .fp-tab-ring::before {
    animation: none;
  }
}

/* Индикатор «есть что забрать» на вкладке — общий .mail-tab-badge; на белой
   вкладке с бегущей рамкой он остаётся красным, как и в письмах. */

/* ── Вкладка «Акция»: шкала наград за число друзей ──
   Полоса, подарки и окошко «что внутри» берутся ГОТОВЫМИ у недельной шкалы
   заданий (.qb-track / .qb-chest / .qb-gift выше в этом файле) — вторая шкала в
   игре не должна выглядеть второй игрой. Здесь только то, чего у той шкалы нет:
   конверт-баннер акции, конфета в начале полосы, счётчик друзей и кнопка под ней. */
.fp-promo {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Содержимое стоит ПО ЦЕНТРУ карточки, а не липнет к её верху: у акции всего
     два блока (баннер и кнопка), и прижатые вверх они оставляли под собой пустую
     половину окна. margin:auto вместо justify-content — при прокрутке (низкий
     экран) он не срезает верх, в отличие от центрирования флексом. */
  justify-content: flex-start;
  gap: calc(16px * var(--ui-space));
  overflow-y: auto;
  overflow-x: hidden;
  padding: calc(2px * var(--ui-space)) calc(4px * var(--ui-space)) calc(6px * var(--ui-space));
}

.fp-promo > :first-child { margin-top: auto; }
.fp-promo > :last-child  { margin-bottom: auto; }

/* Голографический баннер — тот же, что у недельной шкалы заданий (.qb-banner).
   position: relative обязателен: в его координатах ставится окошко подарка
   (ui/lib/giftPopup.js), и без него оно уехало бы в угол страницы. */
.fp-promo-banner {
  position: relative;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(8px * var(--ui-space));
  padding: calc(16px * var(--ui-space)) calc(20px * var(--ui-space));
  border-radius: calc(24px * var(--ui-scale));
  /* Рамка у баннера БЕЛАЯ и неподвижная. Бегущую радугу здесь пробовали — она
     спорит с голографической заливкой под собой и перетягивает взгляд с самой
     шкалы, ради которой вкладку и открывают. Радуга в игре одна и осталась там,
     где она к месту: на корешке вкладки «Акция» (.fp-tab-promo выше). */
  background: var(--qb-holo);
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.8);
  box-shadow: inset 0 2px 0 rgba(255,255,255,0.75), 0 8px 22px rgba(155,111,200,0.28);
  box-sizing: border-box;
}

/* Заголовок акции — фирменной сиренево-розовой заливкой (тот же градиент, что у
   выбранной вкладки и у кнопок игры), а не плакатным красным: красного в
   Турбошоке нет нигде, и заголовок выпадал из окна.
   Заливка буквы — background-clip: text; -webkit-* нужен WebView на Android.
   Тень у градиентного текста не рисуется (буква прозрачная), поэтому объём даёт
   белая подложка снизу — псевдоэлемент с тем же текстом. */
.fp-promo-title {
  position: relative;
  font-size: calc(30px * var(--ui-scale) * var(--fs-scale));
  font-weight: 900;
  letter-spacing: 0.03em;
  text-align: center;
  background: linear-gradient(135deg, #7326b8 0%, #a53fc6 34%, #d4318f 68%, #e8622f 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  /* Тень у градиентной буквы не рисуется (сама буква прозрачная), объём даёт
     drop-shadow по её контуру. Белого тут ровно столько, чтобы отделить текст от
     голографического баннера, — больше и заголовок начинает выглядеть выцветшим. */
  filter: drop-shadow(0 calc(1px * var(--ui-scale)) 0 rgba(255,255,255,0.75))
          drop-shadow(0 calc(3px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(105,45,150,0.35));
}

.fp-promo-sub {
  max-width: calc(520px * var(--ui-scale));
  font-size: var(--fs-14);
  font-weight: 700;
  line-height: 1.35;
  color: var(--qb-ink-soft);
  text-shadow: 0 1px 0 rgba(255,255,255,0.7);
  text-align: center;
}

/* Шкала внутри баннера: полоса с подарками во всю ширину. */
.fp-promo-track { margin-top: calc(2px * var(--ui-space)); }

/* ── Цвет полосы: у акции СВОЙ, не как у заданий ──
   Обе шкалы рисуются одними и теми же .qb-track-* (это и держит их похожими),
   но заливка у них разная — иначе две разные вещи в одной игре читаются как
   одна. Недельная шкала заданий остаётся ЖЁЛТО-ОРАНЖЕВОЙ (см. .qb-track-fill
   выше — её не трогаем), у акции полоса сиренево-розовая, фирменная.
   Ложе полосы тоже слегка подкрашено — на голографическом баннере белое ложе
   под сиреневой заливкой выглядело обрывком чужой шкалы. */
.fp-promo-track .qb-track-fill {
  background: linear-gradient(90deg, #a86fe0 0%, #c46fd0 45%, #e878b4 100%);
  box-shadow: 0 0 calc(10px * var(--ui-scale)) rgba(190,110,215,0.65);
}

.fp-promo-track .qb-track-line {
  background: rgba(255,255,255,0.82);
  box-shadow: inset 0 2px 5px rgba(120,90,160,0.28);
}

/* Порог под полосой — тем же сиреневым, что и заливка. */
.fp-promo-track .qb-chest-val { color: #6b3f9e; }

/* «Друзья: 3/10» — под полосой, по центру. */
.fp-promo-count {
  font-size: var(--fs-17);
  font-weight: 800;
  color: var(--qb-ink);
  text-shadow: 0 1px 0 rgba(255,255,255,0.75);
}

.fp-promo-count b { color: var(--qb-accent); }

/* «Ещё двое на подходе» — про друзей, которые в зачёт пока не идут (дружба моложе
   срока или друг ещё не играл). Мелко и приглушённо: это сноска под счётчиком, а
   не сообщение об ошибке — красным её красить нельзя, ничего не сломалось. */
.fp-promo-pending {
  max-width: calc(520px * var(--ui-scale));
  font-size: var(--fs-12);
  font-weight: 700;
  line-height: 1.3;
  color: var(--qb-ink-soft);
  text-align: center;
  opacity: 0.85;
  text-shadow: 0 1px 0 rgba(255,255,255,0.65);
}

/* Кнопка под шкалой — «Пригласить друга», уводит на вкладку «Добавить друга».
   Жёлто-оранжевая: это единственное действие на вкладке, и оно должно звать. */
.fp-promo-btn {
  min-height: calc(52px * var(--ui-scale));
  padding: 0 calc(34px * var(--ui-space));
  font-size: var(--fs-17);
  font-weight: 800;
  color: #6a3410;
  background: linear-gradient(135deg, #ffd45e 0%, #ffb02e 55%, #f58a1f 100%);
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.9);
  border-radius: 50px;
  cursor: pointer;
  white-space: nowrap;
  text-shadow: 0 1px 0 rgba(255,255,255,0.5);
  box-shadow: 0 calc(5px * var(--ui-scale)) calc(14px * var(--ui-scale)) rgba(240,140,30,0.45),
              inset 0 calc(2px * var(--ui-scale)) 0 rgba(255,255,255,0.6);
  transition: transform 0.12s, box-shadow 0.15s;
}

.fp-promo-btn:hover  { transform: translateY(-2px); box-shadow: 0 7px 18px rgba(240,140,30,0.55); }
.fp-promo-btn:active { transform: scale(0.96); }

/* ── Узкие экраны: телефон в портрете ── */
@media (max-width: 640px) {
  .fp-topbar {
    padding-left: calc(18px * var(--ui-space));
    padding-right: calc(12px * var(--ui-space));
  }
  .fp-stage { padding: 0 calc(12px * var(--ui-space)) calc(12px * var(--ui-space)); }
  .fp-card {
    width: 100%;
    gap: calc(9px * var(--ui-space));
    padding: calc(14px * var(--ui-space));
    border-radius: calc(24px * var(--ui-scale));
  }
  .fp-card .mail-tab {
    padding: calc(9px * var(--ui-space)) calc(16px * var(--ui-space));
    font-size: var(--fs-13);
  }
  .fp-card .ui-note-text { font-size: var(--fs-12); }
  .fp-card .ui-note { padding: calc(7px * var(--ui-space)) calc(10px * var(--ui-space)); }
  .fp-add .fr-modal-body { max-width: 100%; }

}

@media (max-width: 400px) {
  .fp-topbar .sp2-topbar-title { font-size: var(--fs-22); }
  .fp-card .mail-tab {
    padding: calc(8px * var(--ui-space)) calc(11px * var(--ui-space));
    font-size: var(--fs-12);
  }
  .fp-card .ui-note-text { font-size: var(--fs-11-5); }
  .fp-row { padding: calc(9px * var(--ui-space)) calc(10px * var(--ui-space)); }
}

/* ── Низкие экраны: телефон в ландшафте — карточке нужен каждый пиксель ── */
@media (max-height: 449px) and (orientation: landscape) {
  .fp-stage { padding: 0 calc(14px * var(--ui-space)) calc(10px * var(--ui-space)); }
  .fp-card { gap: calc(7px * var(--ui-space)); padding: calc(12px * var(--ui-space)); }
  .fp-add { gap: calc(9px * var(--ui-space)); }
  .fp-card .ui-note { padding: calc(5px * var(--ui-space)) calc(10px * var(--ui-space)); }
  .fp-add .fr-opt { padding: calc(2px * var(--ui-space)) 0; }
  .fp-add .fr-qr { gap: calc(6px * var(--ui-space)); padding: 0; }
  .fp-add .fr-link { gap: calc(8px * var(--ui-space)); }
}

/* ══════════════════════════════════════════════════════════════════════════════
   Страница профиля (ProfilePanel) — кнопка 👤 в главном меню.
   Аватар с карандашом, ник, ID, ранг, полоса опыта и значок инвентаря.
   Витрины (аватары / подарки) открываются в общей модалке .pf-modal.
   ══════════════════════════════════════════════════════════════════════════════ */

/* Шапка — как в магазине и статистике: снимаем отступы .screen (их задаёт
   .sp2-layout) и прижимаем крестик к правому краю.

   --pf-scale / --pf-space — собственный масштаб КАРТОЧКИ (модалки его не берут).
   По умолчанию равен общему; на низких экранах общий --ui-scale падает до
   0.62–0.84 и карточка мельчает — там мы её укрупняем (см. медиазапрос ниже). */
.profile-panel {
  --pf-scale: var(--ui-scale);
  --pf-space: var(--ui-space);
  /* Буквам — та же мерка, но с общим множителем текста --fs-scale:
     --pf-scale ведёт ещё и аватар с полосой опыта, их не трогаем. */
  --pf-text: calc(var(--pf-scale) * var(--fs-scale));
  padding: 0;
  gap: 0;
  overflow: hidden;
}
.profile-panel .sp2-close-btn { margin-left: auto; }

/* Шапка вынесена из потока и плавает поверх: тогда область карточки занимает всю
   высоту экрана, и центр карточки = истинный центр экрана (заголовок её не сдвигает
   вниз). Карточка узкая и по центру, поэтому с заголовком слева и крестиком справа
   не пересекается; z-index держит крестик кликабельным.

   left/right повторяют боковые отступы .sp2-layout: абсолютный блок отсчитывается от
   padding-box и сам их не учитывает, а без этого «ПРОФИЛЬ» и крестик стояли не там,
   где «МАГАЗИН» в магазине (шапки экранов должны совпадать при переходах). */
.profile-panel .sp2-layout { position: relative; }
.profile-panel .sp2-topbar {
  position: absolute;
  top: 0;
  left: calc(28px * var(--ui-space));
  right: calc(12px * var(--ui-space));
  z-index: 5;
}

.pf-body {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(16px * var(--pf-space));
  overflow-y: auto;
}

.pf-card {
  position: relative;
  width: 100%;
  max-width: calc(380px * var(--pf-scale));
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(12px * var(--pf-space));
  padding: calc(22px * var(--pf-space)) calc(20px * var(--pf-space)) calc(20px * var(--pf-space));
  background: linear-gradient(160deg, #fffdff, #f3e8fb);
  border: calc(3px * var(--pf-scale)) solid #fff;
  border-radius: calc(28px * var(--pf-scale));
  box-shadow: 0 18px 44px rgba(123, 63, 190, 0.42), inset 0 2px 0 rgba(255,255,255,0.75);
  animation: fr-pop 0.18s ease;
}

/* ── Аватар с карандашом (нажатие открывает выбор аватара) ─────────────────── */
.pf-avatar {
  position: relative;
  flex: 0 0 auto;
  width: calc(132px * var(--pf-scale));
  height: calc(132px * var(--pf-scale));
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(155,111,200,0.25);
  box-shadow: 0 8px 20px rgba(123,63,190,0.38);
  cursor: pointer;
  transition: transform 0.15s ease;
}
.pf-avatar:hover  { transform: scale(1.04); }
.pf-avatar:active { transform: scale(0.97); }
.pf-avatar-img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  display: block;
}
.pf-avatar-fb {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  font-weight: 900;
  color: #fff;
  font-size: calc(56px * var(--pf-scale));
  background: linear-gradient(135deg, #b58fe0, #9b6fc8);
}
/* Карандаш — кружок в правом нижнем углу аватара */
.pf-avatar-pen {
  position: absolute;
  right: calc(-2px * var(--pf-scale));
  bottom: calc(-2px * var(--pf-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(44px * var(--pf-scale));
  height: calc(44px * var(--pf-scale));
  border-radius: 50%;
  background: linear-gradient(160deg, #ffffff, #f3e8fb);
  border: calc(2px * var(--pf-scale)) solid #fff;
  box-shadow: 0 4px 12px rgba(123,63,190,0.45);
}
.pf-avatar-pen-img {
  width: calc(26px * var(--pf-scale));
  height: calc(26px * var(--pf-scale));
  object-fit: contain;
  display: block;
}

/* ── Ник и ID ──────────────────────────────────────────────────────────────── */
.pf-name {
  max-width: 100%;
  font-size: calc(24px * var(--pf-text));
  font-weight: 900;
  color: #4b2a8c;
  text-align: center;
}

/* Плашка ID — компактная: не растягивается на всю карточку, длинный ID обрезается
   многоточием (по тапу копируется полный ID, он же в подсказке title). */
.pf-id {
  display: inline-flex;
  align-items: center;
  gap: calc(7px * var(--pf-space));
  max-width: min(100%, calc(190px * var(--pf-scale)));
  padding: calc(4px * var(--pf-space)) calc(12px * var(--pf-space));
  border: none;
  border-radius: 999px;
  background: rgba(155,111,200,0.16);
  cursor: pointer;
  transition: background 0.15s ease;
}
.pf-id:hover  { background: rgba(155,111,200,0.28); }
.pf-id:active { transform: scale(0.97); }
.pf-id-label {
  flex: 0 0 auto;
  font-size: calc(11px * var(--pf-text));
  font-weight: 800;
  color: rgba(75, 42, 140, 0.55);
}
.pf-id-val {
  min-width: 0;                 /* иначе flex-элемент не даст себя ужать и обрезать */
  font-size: calc(13px * var(--pf-text));
  font-weight: 800;
  letter-spacing: 0.08em;
  color: #4b2a8c;
}

/* ── Ранг ──────────────────────────────────────────────────────────────────── */
.pf-rank {
  display: flex;
  align-items: center;
  gap: calc(10px * var(--pf-space));
}
.pf-rank-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: calc(58px * var(--pf-scale));
  height: calc(58px * var(--pf-scale));
  flex-shrink: 0;
}
.pf-rank-name {
  font-size: calc(17px * var(--pf-text));
  font-weight: 900;
  color: #4b2a8c;
}

/* ── Опыт: полоса до следующего ранга (шкала абсолютная, как в «Статистике») ── */
.pf-xp {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: calc(5px * var(--pf-space));
}
.pf-xp-track {
  width: 100%;
  height: calc(20px * var(--pf-scale));
  background: rgba(155, 111, 200, 0.18);
  border-radius: 999px;
  overflow: hidden;
}
.pf-xp-fill {
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #ef6ea0, #f7a838);
  box-shadow: 0 0 8px rgba(239, 110, 160, 0.45);
  transition: width 0.4s ease;
}
.pf-xp-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(8px * var(--pf-space));
}
.pf-xp-text {
  font-size: calc(12px * var(--pf-text));
  font-weight: 800;
  color: rgba(42, 26, 64, 0.55);
}
.pf-xp-next {
  font-size: calc(11px * var(--pf-text));
  font-weight: 800;
  color: #9b6fc8;
  text-align: right;
}

/* ── Кнопки-картинки: «Инвентарь» (купленное) и «Мои подарки» (полученное) ────
   Кнопка — это сама картинка: без рамки и подписи, счётчик в углу (как у подарков
   в магазине, .sp2-owned-badge). Подпись живёт в title/aria-label. */
.pf-actions {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: calc(28px * var(--pf-space));
  margin-top: calc(4px * var(--pf-space));
}
.pf-action {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: calc(84px * var(--pf-scale));
  height: calc(84px * var(--pf-scale));
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  transition: transform 0.15s ease, filter 0.15s ease;
}
.pf-action:hover  { transform: translateY(-3px) scale(1.05); filter: drop-shadow(0 8px 14px rgba(123,63,190,0.35)); }
.pf-action:active { transform: scale(0.95); }
/* Счётчик на кнопке: инвентарь — сумма player_gifts.qty, подарки — сколько получено */
.pf-action-count {
  position: absolute;
  top: calc(-4px * var(--pf-scale));
  right: calc(-4px * var(--pf-scale));
  min-width: calc(22px * var(--pf-scale));
  padding: 0 calc(5px * var(--pf-space));
  border-radius: 50px;
  background: linear-gradient(135deg, #ffb64d, #f2760c);
  box-shadow: 0 2px 6px rgba(242,118,12,0.45);
  color: #fff;
  font-size: calc(13px * var(--pf-text));
  font-weight: 800;
  line-height: calc(22px * var(--pf-scale));
  text-align: center;
  pointer-events: none;
}

/* Индикатор «новое» на кнопке раздела («Достижения» — взят невиданный уровень,
   «Мои подарки» — пришёл подарок). Слева сверху, чтобы не спорить со счётчиком
   справа. Тот же красный «!», что и «новинки» магазина в меню (.nav-new-dot):
   в игре один значок «новое» — не заводим второй язык. Гаснет, когда игрок
   откроет витрину (см. ProfilePanel._markSeen). */
.pf-action-dot {
  top: calc(-4px * var(--pf-scale));
  left: calc(-4px * var(--pf-scale));
  width: calc(22px * var(--pf-scale));
  height: calc(22px * var(--pf-scale));
  border-radius: calc(7px * var(--pf-scale));
  background: linear-gradient(135deg, #ff5a4e, #c11414);
  font-size: calc(13px * var(--pf-text));
  box-shadow: 0 calc(2px * var(--pf-scale)) calc(6px * var(--pf-scale)) rgba(193,20,20,0.5);
  pointer-events: none;
  animation: badge-pulse 1s ease-in-out infinite;
}

/* Та же метка на самой плитке — какая именно ачивка/подарок новые. Показывается
   в момент открытия витрины; при следующем открытии плиток с меткой уже нет.

   Метка лежит ВНУТРИ плитки (без отрицательных top/left) — витрины стоят в
   скролл-контейнерах (.pf-modal-body), а те режут всё, что вылезло за их край:
   у крайних плиток метку срезало бы, да и сам вылет считается переполнением и
   поднимает лишнюю полосу прокрутки. Отступ 2px — запас на пульсацию значка
   (badge-pulse раздувает его до 1.18, это ~2px в каждую сторону). */
.tile-new-dot {
  top: calc(2px * var(--ui-scale));
  left: calc(2px * var(--ui-scale));
  width: calc(22px * var(--ui-scale));
  height: calc(22px * var(--ui-scale));
  border-radius: calc(7px * var(--ui-scale));
  background: linear-gradient(135deg, #ff5a4e, #c11414);
  font-size: var(--fs-13);
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(193,20,20,0.5);
  pointer-events: none;
  animation: badge-pulse 1s ease-in-out infinite;
}

/* ── Модалка: выбор аватара / инвентарь подарков ───────────────────────────── */
.pf-modal {
  position: relative;
  width: 100%;
  max-width: calc(460px * var(--ui-scale));
  max-height: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: calc(12px * var(--ui-space));
  padding: calc(10px * var(--ui-space)) calc(18px * var(--ui-space)) calc(18px * var(--ui-space));
  background: linear-gradient(160deg, #fffdff, #f6ecfb);
  border: calc(3px * var(--ui-scale)) solid #fff;
  border-radius: calc(28px * var(--ui-scale));
  box-shadow: 0 18px 44px rgba(90, 55, 130, 0.45);
  animation: fr-pop 0.18s ease;
}
.pf-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(10px * var(--ui-space));
}
.pf-modal-title {
  font-size: var(--fs-18);
  font-weight: 900;
  letter-spacing: 0.03em;
  text-transform: uppercase;   /* капс — как в шапках экранов, независимо от строки в i18n */
  color: #4b2a8c;
}
.pf-modal-close {
  width: calc(52px * var(--ui-scale));
  height: calc(52px * var(--ui-scale));
  flex-shrink: 0;
}
.pf-modal-close img {
  width: calc(44px * var(--ui-scale));
  height: calc(44px * var(--ui-scale));
}
/* Полоса прокрутки прижата к краю окна: тело выезжает в правый padding .pf-modal
   (margin-right), а плитки остаются на месте за счёт собственного padding-right.
   Поля под значки плиток тут не нужны: и метка «!», и счётчик лежат внутри своей
   плитки (см. .tile-new-dot и .pf-tile--gift .pf-tile-qty), поэтому за край тела
   ничто не вылезает — и не режется, и не поднимает полосу прокрутки на пустом
   месте. Прокрутка появляется, только когда подарков правда больше, чем влезло. */
.pf-modal-body {
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  margin-right: calc(-12px * var(--ui-space));
  padding-right: calc(12px * var(--ui-space));
  scrollbar-width: thin;
  scrollbar-color: rgba(155,111,200,0.45) transparent;
}
.pf-modal-body::-webkit-scrollbar { width: calc(6px * var(--ui-scale)); }
.pf-modal-body::-webkit-scrollbar-track { background: transparent; }
.pf-modal-body::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, #d9c8ff, #ffd6eb);
  border-radius: 999px;
}

/* Сетка плиток (аватары и подарки).
   Поле по краям — запас под зум плитки на ховере (.pf-tile-art--zoom, scale 1.05).
   У подарка плитка = сам арт (полей у неё нет), поэтому раздутый арт вылезает за
   край сетки, а .pf-modal-body (overflow-y: auto) считает такой вылет переполнением:
   всплывает полоса прокрутки, тело теряет её ширину, треки auto-fill пересчитываются
   — плитки уезжают из-под курсора, ховер спадает, полоса пропадает, и так по кругу
   (окно «дрожит»). 4px хватает на 5% от самого крупного арта (92px). */
.pf-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(calc(96px * var(--ui-scale)), 1fr));
  gap: calc(10px * var(--ui-space));
  padding: calc(4px * var(--ui-scale));
}
/* Сетка подарков: ровно три в ряду, число задано, а не выведено из auto-fill.
   auto-fill насчитывал три колонки, но впритык: плитка подарка = арт 92px и два поля
   под ореол (см. --gift-glow-room у .gift-glow), и три таких плитки с зазорами
   занимали всю ширину тела окна с запасом в единицы пикселей. Подарков в витрине
   почти всегда больше, чем влезает, поэтому у тела появляется полоса прокрутки — а
   там, где она не overlay-ная (обычный десктопный браузер), она забирает свои ~7px
   ширины, и запаса не хватало: ряд молча распадался на ДВА подарка, причём только у
   части игроков и только когда витрина проматывается. Заданное число колонок этого
   не знает и не считает — три ряд и есть три. */
.pf-grid--gift {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.pf-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(8px * var(--ui-space));
  padding: calc(10px * var(--ui-space));
  border-radius: calc(20px * var(--ui-scale));
  border: 1.5px solid rgba(155,111,200,0.22);
  background: rgba(255,255,255,0.66);
}
/* Надетый аватар — оранжевая рамка, как «Надето» в магазине */
.pf-tile--on {
  border-color: rgba(255,122,0,0.55);
  box-shadow: 0 0 0 calc(2px * var(--ui-scale)) rgba(255,122,0,0.18);
}
.pf-tile--ph { min-height: calc(110px * var(--ui-scale)); }
.pf-tile-art {
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(70px * var(--ui-scale));
  height: calc(70px * var(--ui-scale));
}
/* Картинка аватара — кнопка разворота (.ava-zoom-overlay), а не просто арт. */
.pf-tile-art--zoom {
  padding: 0;
  border: none;
  background: transparent;
  cursor: zoom-in;
  transition: transform 0.12s ease;
}
.pf-tile-art--zoom:hover  { transform: scale(1.05); }
.pf-tile-art--zoom:active { transform: scale(0.96); }
/* Подарки открывают карточку «от кого и когда», а не предпросмотр — поэтому обычный
   курсор-палец без лупы и без зума на наведении (лупа осталась только у аватаров). */
.pf-tile--gift .pf-tile-art--zoom { cursor: pointer; }
.pf-tile--gift .pf-tile-art--zoom:hover { transform: none; }
.pf-tile-btn {
  padding: calc(5px * var(--ui-space)) calc(14px * var(--ui-space));
  border: none;
  border-radius: 999px;
  background: linear-gradient(160deg, #b58fe0, #9b6fc8);
  color: #fff;
  font-size: var(--fs-12);
  font-weight: 800;
  cursor: pointer;
  box-shadow: 0 4px 10px rgba(123,63,190,0.35);
  transition: transform 0.12s ease;
}
.pf-tile-btn:hover  { transform: scale(1.05); }
.pf-tile-btn:active { transform: scale(0.95); }
.pf-tile-btn:disabled { opacity: 0.6; cursor: default; }
.pf-tile-on {
  font-size: var(--fs-12);
  font-weight: 800;
  color: #ff7a00;
  padding: calc(4px * var(--ui-space)) calc(12px * var(--ui-space));
  border: 1.5px solid rgba(255,122,0,0.40);
  border-radius: 999px;
  white-space: nowrap;
}
/* Счётчик подарка — тот же значок, что в магазине (.sp2-owned-badge): оранжевая
   плашка в правом верхнем углу арта. В инвентаре это player_gifts.qty, в «Моих
   подарках» — сколько штук пришло одной посылкой. */
.pf-tile-qty {
  position: absolute;
  top: calc(-4px * var(--ui-scale));
  right: calc(-4px * var(--ui-scale));
  min-width: calc(22px * var(--ui-scale));
  padding: 0 calc(5px * var(--ui-space));
  border-radius: 50px;
  background: linear-gradient(135deg, #ffb64d, #f2760c);
  box-shadow: 0 2px 6px rgba(242,118,12,0.45);
  color: #fff;
  font-size: var(--fs-13);
  font-weight: 800;
  line-height: calc(22px * var(--ui-scale));
  text-align: center;
  pointer-events: none;
}

/* Ярлычки аватара в профиле — столбиком ПО ЦЕНТРУ верхней кромки плитки, ровно
   как ярлычки лота в магазине («Хит!», «✦ Премиум», «Сезонный» — все по центру
   кромки своей карточки). В углу ярлычок сидел криво: у квадратной плитки угол
   занят рамкой скругления, и слово наезжало на неё то больше, то меньше в
   зависимости от длины.

   Столбик, а не строка: ярлычков бывает два сразу (премиальный аватар в игре
   всегда ещё и сезонный), а два слова рядом не влезают в плитку — самая узкая
   колонка витрины 140px, и строка «✦ Премиум · Сезонный» вылезла бы за край. За
   краем её срезал бы .pf-modal-body (скролл-контейнер), да и сам вылет поднял бы
   горизонтальную полосу прокрутки — то самое «дрожание» окна, от которого
   отступы плиток и заведены. Поэтому ярлычки стоят друг под другом и остаются
   внутри своей колонки при любой ширине.

   Полоса в потоке (а не поверх арта): второй ярлычок иначе лёг бы на лицо. Верхний
   поднят отрицательным margin — он садится верхом на кромку, как и раньше. */
.pf-tile-tags {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(3px * var(--ui-space));
  max-width: 100%;
  margin-top: calc(-20px * var(--ui-scale));
  margin-bottom: calc(-4px * var(--ui-space));
  pointer-events: none;
}
.pf-tile-tag {
  max-width: 100%;
  padding: calc(2px * var(--ui-space)) calc(9px * var(--ui-space));
  border-radius: 50px;
  font-size: var(--fs-11);
  font-weight: 800;
  line-height: 1.35;
}

/* Сезонный аватар: «куплен в свой сезон и остался навсегда» — в магазине такого
   лота уже может не быть. Цвет — лавандовый из палитры игры, тот же, каким
   светится кольцо вокруг сезонного лица (.ava-glow--season): в профиле плитки
   квадратные и кольца не носят, слово заменяет им подсветку, поэтому и цвет у
   них общий. Зелёный ярлычок магазина (.sp2-season) остаётся магазину: там он
   стоит в ряду распродажных плашек и говорит про срок продажи, а не про редкость. */
.pf-tile-season {
  background: rgba(183,148,255,0.9);
  border: 1px solid rgba(123,63,190,0.35);
  color: #3a2358;
}

/* Премиум-аватар: куплен за настоящие деньги. Медовая лента — та же, что у лота
   в магазине (.sp2-premium-ribbon), и слово то же: цены у аватара в игре нигде
   нет, и без подписи рублёвое лицо ничем не отличалось бы от накопленного за
   драже. Голубое кольцо (.ava-glow--paid) говорит то же самое там, где лицо
   круглое; здесь плитка квадратная — говорит слово. */
.pf-tile-premium {
  background: linear-gradient(135deg, #ffe08a, #ffb347);
  border: 1px solid rgba(214,140,20,0.45);
  color: #7a3b00;
}

/* Подарок — без ячейки: только арт покрупнее, счётчик поверх угла.
   Ширина плитки = ширина арта (max-width), justify-self — чтобы правый верхний угол
   плитки совпал с углом арта. Именно max-width, а не фиксированная ширина: колонок
   теперь ровно три (см. .pf-grid--gift), и на узком окне трек может оказаться уже
   плитки — тогда она сойдётся с ним, а не вылезет за его край, подняв горизонтальную
   прокрутку и «дрожание» тела окна. Ужимается она на единицы процентов и только там,
   где иначе ряд распался бы. */
.pf-tile--gift {
  width: 100%;
  max-width: calc(92px * var(--ui-scale) + 2 * var(--gift-glow-room));
  justify-self: center;
  gap: 0;
  padding: 0;
  border: none;
  background: transparent;
}
/* Слот шире арта на два поля под ореол: сам арт остаётся 92px, а свечение лежит в
   поле и не выходит за картинку (см. --gift-glow-room у .gift-glow). Размер слота
   держит плитка, слот лишь тянется за ней и остаётся квадратным. */
.pf-tile--gift .pf-tile-art {
  width: 100%;
  height: auto;
  aspect-ratio: 1;
}
/* Плитка подарка = сам арт (полей у неё нет), поэтому счётчик садится в угол арта,
   а не за него: за краем витрины его срезал бы скролл-контейнер тела окна. Угол
   арта теперь на поле под ореол внутрь от угла плитки — на столько же и сдвиг,
   иначе счётчик и метка «!» повиснут в пустом поле. */
.pf-tile--gift .pf-tile-qty {
  top: var(--gift-glow-room);
  right: var(--gift-glow-room);
}
.pf-tile--gift .tile-new-dot {
  top: calc(var(--gift-glow-room) + 2px * var(--ui-scale));
  left: calc(var(--gift-glow-room) + 2px * var(--ui-scale));
}

/* Карточка полученного подарка: крупный арт + «от кого» и «когда получен» (из БД) */
.pf-gift-detail {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(16px * var(--ui-space));
  padding: calc(10px * var(--ui-space)) 0;
}
/* Слот шире арта на два поля под ореол — арт те же 170px (см. --gift-glow-room). */
.pf-gift-art {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(170px * var(--ui-scale) + 2 * var(--gift-glow-room));
  height: calc(170px * var(--ui-scale) + 2 * var(--gift-glow-room));
}
.pf-gift-rows {
  display: flex;
  flex-direction: column;
  gap: calc(8px * var(--ui-space));
  width: 100%;
}
.pf-gift-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: calc(12px * var(--ui-space));
  padding: calc(10px * var(--ui-space)) calc(14px * var(--ui-space));
  border-radius: calc(16px * var(--ui-scale));
  background: rgba(155,111,200,0.12);
}
.pf-gift-key {
  font-size: var(--fs-13);
  font-weight: 800;
  color: #9b6fc8;
  white-space: nowrap;
}
.pf-gift-val {
  font-size: var(--fs-15);
  font-weight: 900;
  color: #4b2a8c;
  text-align: right;
  overflow-wrap: anywhere;
}
/* Строка «От кого» у подарка от игрока — целиком кнопка на его страницу (у подарка
   от игры строка обычная, .pf-gift-row). Нажимать удобнее, чем по одному имени:
   вся плашка — площадь нажатия, поэтому она заметнее и выше соседней. */
.pf-gift-row--link {
  width: 100%;
  min-height: calc(48px * var(--ui-scale));
  align-items: center;
  border: 0;
  font-family: inherit;
  cursor: pointer;
  background: rgba(155,111,200,0.18);
  box-shadow: inset 0 0 0 calc(2px * var(--ui-scale)) rgba(155,111,200,0.3);
  -webkit-tap-highlight-color: transparent;
  transition: background 0.12s ease, transform 0.12s ease;
}
.pf-gift-row--link:hover  { background: rgba(155,111,200,0.28); }
.pf-gift-row--link:active { transform: scale(0.98); }
/* Имя прижимаем вправо, подчёркивания нет — плашка и так читается кнопкой. */
.pf-gift-from {
  margin-left: auto;
  color: #7b3fd4;
  text-decoration: none;
}
.pf-gift-back { margin-top: calc(2px * var(--ui-space)); }

/* Пустой инвентарь / нет аватаров */
.pf-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(8px * var(--ui-space));
  padding: calc(26px * var(--ui-space)) calc(10px * var(--ui-space));
  text-align: center;
}
.pf-empty-img {
  width: calc(96px * var(--ui-scale));
  height: calc(96px * var(--ui-scale));
  object-fit: contain;
  filter: drop-shadow(0 calc(6px * var(--ui-scale)) calc(12px * var(--ui-scale)) rgba(75, 42, 140, 0.18));
}
.pf-empty-text {
  font-size: var(--fs-16);
  font-weight: 900;
  color: #4b2a8c;
}
.pf-empty-hint {
  font-size: var(--fs-13);
  font-weight: 700;
  color: rgba(42, 26, 64, 0.55);
}
.pf-shop-btn {
  margin-top: calc(6px * var(--ui-space));
  padding: calc(8px * var(--ui-space)) calc(22px * var(--ui-space));
  border: none;
  border-radius: 999px;
  background: linear-gradient(160deg, #ff9a3c, #ff7a00);
  color: #fff;
  font-size: var(--fs-14);
  font-weight: 800;
  cursor: pointer;
  box-shadow: 0 6px 14px rgba(255,122,0,0.45);
  transition: transform 0.12s ease;
}
.pf-shop-btn:hover  { transform: scale(1.05); }
.pf-shop-btn:active { transform: scale(0.95); }

/* ── Полоса под заголовком витрины инвентаря: кнопка «Подарить другу» ────────
   Стоит между шапкой и телом окна, а не внутри тела: тело прокручивается вместе
   с плитками подарков, и кнопка уезжала бы из виду. flex-shrink: 0 — чтобы её не
   сплющило, когда подарков много и тело просит всю высоту. */
.pf-modal-top {
  display: flex;
  justify-content: center;
  flex-shrink: 0;
}
/* Золотой градиент — тот же, что у «Подарить» в письмах (.gift-send-btn) и
   «Забрать» у награды (.mail-claim-btn): кнопка ведёт ровно к ним. Оранжевая
   пилюля профиля (.pf-shop-btn) занята магазином — цвета не путаются. */
.pf-gift-btn {
  min-height: calc(44px * var(--ui-scale));
  padding: 0 calc(30px * var(--ui-space));
  border: none;
  border-radius: 50px;
  background: linear-gradient(135deg, #f5c518, #e07020);
  color: #fff;
  font-size: var(--fs-15);
  font-weight: 800;
  cursor: pointer;
  white-space: nowrap;
  transition: transform 0.10s, box-shadow 0.10s;
  box-shadow: 0 3px 14px rgba(200,134,10,0.5);
}
.pf-gift-btn:hover  { transform: scale(1.05); box-shadow: 0 6px 18px rgba(200,134,10,0.65); }
.pf-gift-btn:active { transform: scale(0.94); }

/* ── Витрина аватаров: окно и плитки крупнее, чем у подарков ─────────────────
   Аватар — это будущее фото профиля, его хотят рассмотреть перед выбором, поэтому
   окно шире, плитка крупнее и в ряд их влезает три (у подарков — четыре мелких). */
.pf-modal--avatars {
  max-width: calc(620px * var(--ui-scale));
}
.pf-modal--avatars .pf-grid {
  grid-template-columns: repeat(auto-fill, minmax(calc(140px * var(--ui-scale)), 1fr));
  gap: calc(14px * var(--ui-space));
}
.pf-modal--avatars .pf-tile {
  gap: calc(10px * var(--ui-space));
  padding: calc(14px * var(--ui-space));
  border-radius: calc(24px * var(--ui-scale));
}
.pf-modal--avatars .pf-tile-art {
  width: calc(112px * var(--ui-scale));
  height: calc(112px * var(--ui-scale));
  /* Свободную высоту плитки забирает арт, а не то, что под ним: у плиток одного
     ряда высота общая (grid растягивает), а ярлычков сверху бывает ноль, один
     или два — без этого пилюля «Надеть» у соседей вставала бы на разной высоте,
     ровно на высоту лишнего ярлычка. Теперь пилюли стоят в ряд по низу, а
     разница уходит в поля вокруг портрета. */
  margin-block: auto;
}
.pf-modal--avatars .pf-tile-btn,
.pf-modal--avatars .pf-tile-on {
  font-size: var(--fs-14);
  padding: calc(7px * var(--ui-space)) calc(18px * var(--ui-space));
}

/* Разворот аватара по тапу — общий для всей игры виджет (ui/AvatarZoom.js):
   витрина своих аватаров, рейтинги, «Друзья», дуэли, письма, карточка игрока.
   Окно висит на <body>, поэтому position: fixed и z-index выше всех модалок:
   панель (.screen, z-index 20) и окна внутри неё (30/31/40) остаются под ним. */
.ava-zoom-overlay {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(24px * var(--ui-space));
  background: rgba(60, 40, 90, 0.62);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  cursor: zoom-out;
  animation: fr-fade 0.16s ease;
}
/* Без рамки и фона: картинка аватара прозрачная (круг), поэтому тень вешаем
   фильтром — она повторяет круг, а не квадрат самого <img>. */
.ava-zoom-img {
  width: min(78vw, calc(420px * var(--ui-scale)));
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 18px 40px rgba(45, 25, 75, 0.5));
  animation: fr-pop 0.18s ease;
}

/* Аватар, который разворачивается: лупа вместо пальца и лёгкий подъём под курсором
   (на пальце hover не срабатывает, так что список от этого не дёргается). */
[data-ava-zoom] {
  cursor: zoom-in;
  transition: transform 0.12s ease;
}
[data-ava-zoom]:hover  { transform: scale(1.06); }
[data-ava-zoom]:active { transform: scale(0.97); }

/* Узкая (низкая) адаптация — телефон в альбомной. На нём --ui-scale падает до
   ступеньки 0.62 / 0.72 / 0.84, и карточка вместе со всем содержимым мельчает; при
   этом по высоте она и так занимает почти весь экран, так что просто «сделать
   крупнее» нельзя — расти можно только за счёт собственных отступов.

   Считается это точно (замер: высота карточки ≈ 349 * --pf-scale + 127 * --pf-space,
   ещё 32 * --pf-space забирают поля .pf-body). Поэтому здесь мы поднимаем масштаб
   на 10% и в ту же меру ужимаем промежутки — с 0.78 до 0.60 от общего --ui-space:
   аватар, ник, ранг, полоса опыта и кнопки становятся на десятую крупнее, а сама
   карточка остаётся примерно того же роста.

   Ступеньки --ui-scale заданы по ВЕРХУ своего диапазона высот, поэтому опасна не
   середина, а НИЖНЯЯ граница (320 / 380 / 450 px): там карточка выходит 286 / 331 /
   387 px, то есть 89 / 87 / 86 % высоты экрана — зазор до краёв остаётся всегда.
   Больше 1.10 брать нельзя: у нижней границы карточка упрётся в рамку экрана. */
@media (max-height: 499px) and (orientation: landscape) {
  .profile-panel {
    --pf-scale: calc(var(--ui-scale) * 1.10);
    --pf-space: calc(var(--ui-space) * 0.60);
  }
}

/* Плашка «Заблокировано» (гость) внутри модалки профиля.
   Витрина-заглушка позади — обычная .pf-grid, и её, как и сетки лотов в магазине,
   надо растянуть по ширине: иначе grid схлопывается в одну колонку, вытягивает
   гейт по вертикали и плашка уезжает за нижний край окна. */
.sp2-guest-gate-behind > .pf-grid {
  flex: 1 1 auto;
  min-width: 0;
}
/* Заглушка низкая (2 ряда), сама плашка выше — задаём гейту высоту под плашку. */
.pf-modal-body .sp2-guest-gate {
  min-height: calc(392px * var(--ui-scale));
}
.pf-modal-body .sp2-guest-plaque {
  width: min(96%, calc(340px * var(--ui-scale)));
}

/* Телефон в альбоме: там плашка сжата в высоту и растянута вширь, и окно надо
   мерить по ней. Прежние 460×--ui-scale в ширину ломали её строки надвое, а
   392×--ui-scale в высоту оставляли под ней полокна пустоты — с прокруткой на
   пустом месте. .pf-modal--gate ставит ProfilePanel ровно на трёх гостевых
   витринах (аватары, инвентарь, «Мои подарки»); окно с плитками не трогаем. */
@media (max-height: 499px) and (orientation: landscape) {
  .pf-modal--gate { max-width: min(94%, calc(var(--gg-width) + 80px)); }
  .pf-modal-body .sp2-guest-gate  { min-height: calc(300px * var(--gg-scale)); }
  .pf-modal-body .sp2-guest-plaque { width: min(96%, var(--gg-width)); }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ДОСТИЖЕНИЯ (ачивки) — сетка 4×3, у каждой 5 уровней
   Открываются кнопкой .pf-action в своём профиле (ProfilePanel) и в окне чужого
   игрока (PlayerProfileModal) — окно общее (.pf-modal + модификатор .pf-modal--ach).

   Правила показа (разметка — ui/AchievementsShowcase.js):
     • картинка = взятый уровень: assets/achievements/{image_base}-{1..5}.png,
       от холодной на первом уровне до самой тёплой на пятом;
     • ачивка не получена (уровень 0) — та же ПЕРВАЯ картинка, но бледная
       (.ach-tile--locked: обесцвечиваем и гасим — отдельный «серый» арт не нужен);
     • под картинкой — градиентная шкала до следующего уровня; её цвет тоже идёт
       от холодного (.ach-bar--l0) к тёплому (.ach-bar--l4);
     • максимальный уровень — шкалы нет вообще (её просто не рисуем);
     • в чужом профиле шкал нет ни у одной ачивки — видно только полученное.
   ══════════════════════════════════════════════════════════════════════════════ */

/* Окно ачивок: строго четыре колонки — это сетка 4×3, а не «сколько влезет».
   Ачивок двенадцать, и растёт сетка ВШИРЬ, а не вниз: игра альбомная, лишний ряд
   упёрся бы в высоту окна (прокрутки тут нет), а лишняя колонка — только в ширину,
   которой в альбомном кадре с запасом. Ячейка — квадрат со стороной --ach-cell,
   высота блока от перехода 3×3 → 4×3 не изменилась вовсе.
   Вертикальной прокрутки тут не бывает: тело окна не скроллится. */
.pf-modal--ach {
  max-width: calc(546px * var(--ui-scale));   /* по ширине блока 4×3, без пустых полей по бокам */
}
.pf-modal--ach .pf-modal-body {
  display: flex;
  flex-direction: column;
  overflow: hidden;   /* прокрутки нет: содержимое обязано влезть */
  min-height: 0;
}
.ach-grid {
  --ach-cell: calc(112px * var(--ui-scale));   /* сторона квадратной ячейки — она же потолок */
  display: grid;
  grid-template-columns: repeat(4, minmax(0, var(--ach-cell)));   /* узкое окно — колонки ужимаются */
  grid-template-rows: repeat(3, auto);   /* высоту ряда задаёт сама плитка: она квадратная */
  gap: calc(14px * var(--ui-space));
  justify-content: center;   /* блок 4×3 по центру окна */
  align-content: center;
  /* Поле по краям — запас под подъём плитки на ховере (.ach-tile:hover — scale 1.05
     и сдвиг на 3px вверх). Тело окна с overflow:hidden иначе срезает крайние плитки
     и их метку «!»; тот же приём, что у .pf-grid. */
  padding: calc(8px * var(--ui-scale));
  flex: 1 1 auto;
  min-height: 0;
}

/* Плитка — голая кнопка без фона и рамки: только арт и шкала под ним.
   Занимает всю квадратную ячейку, шкала идёт по её ширине. */
.ach-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(6px * var(--ui-space));
  width: 100%;
  aspect-ratio: 1;   /* плитка = квадрат: сторона равна ширине колонки */
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  cursor: pointer;
  transition: transform 0.15s ease;
}
.ach-tile:hover  { transform: translateY(-3px) scale(1.05); }
.ach-tile:active { transform: scale(0.96); }

/* Арт занимает в ячейке всю высоту, что осталась от шкалы (пропорции бережёт
   object-fit: contain, поэтому картинка не тянется). */
.ach-art {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  /* Размер клетки задаёт сетка, а не картинка внутри: без этого арт растягивал бы
     плитку. Запасной эмодзи здесь больше нет (fd4a632) — ачивке без файла арта
     достаётся пустая клетка со шкалой, и это видно сразу. */
  container-type: size;
}

/* Не получена (уровень 0): показываем первую картинку бледной — без отдельного арта. */
.ach-tile--locked .ach-img,
.ach-detail-art.ach-tile--locked .ach-detail-img {
  filter: grayscale(1) brightness(1.15) contrast(0.75);
  opacity: 0.42;
}

/* Максимальный уровень — тёплое свечение под артом вместо шкалы (шкалы на нём нет). */
.ach-tile--max .ach-img {
  filter: drop-shadow(0 0 calc(10px * var(--ui-scale)) rgba(255,122,0,0.55));
}

/* Индикаторная шкала: путь до следующего уровня. Под артом и по его ширине. */
.ach-bar {
  display: block;
  width: 100%;
  height: calc(13px * var(--ui-scale));
  background: rgba(155, 111, 200, 0.18);
  border-radius: 999px;
  overflow: hidden;
}
.ach-tile .ach-bar { width: 100%; flex: 0 0 auto; }
.ach-bar--wide { height: calc(16px * var(--ui-scale)); }
.ach-bar-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  transition: width 0.4s ease;
}
/* Цвет шкалы по текущему уровню: холодный → тёплый (l4 — путь к максимуму). */
.ach-bar--l0 { background: linear-gradient(90deg, #7fd8ff, #4aa3ff); box-shadow: 0 0 8px rgba(74,163,255,0.45); }
.ach-bar--l1 { background: linear-gradient(90deg, #58e0d0, #2bb3a3); box-shadow: 0 0 8px rgba(43,179,163,0.45); }
.ach-bar--l2 { background: linear-gradient(90deg, #a8e85a, #5fc63a); box-shadow: 0 0 8px rgba(95,198,58,0.45); }
.ach-bar--l3 { background: linear-gradient(90deg, #ffd84a, #ffab2e); box-shadow: 0 0 8px rgba(255,171,46,0.5); }
.ach-bar--l4 { background: linear-gradient(90deg, #ff8a3d, #ff3b2f); box-shadow: 0 0 10px rgba(255,59,47,0.55); }

/* ── Карточка одной ачивки (тап по плитке) ─────────────────────────────────── */
/* Прокрутки тут тоже нет: в низком окне ужимается арт, текст и кнопка «Назад»
   остаются на своих местах. */
.ach-detail {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(10px * var(--ui-space));
  padding: calc(10px * var(--ui-space)) 0;
  flex: 1 1 auto;
  min-height: 0;
}
.ach-detail-art {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 1 auto;
  min-height: 0;
  width: calc(170px * var(--ui-scale));
  height: calc(170px * var(--ui-scale));
}
.ach-detail-title {
  font-size: var(--fs-20);
  font-weight: 900;
  color: #4b2a8c;
  text-align: center;
}
.ach-detail-level {
  font-size: var(--fs-14);
  font-weight: 800;
  color: #7b3fbe;
}
.ach-detail-level--max { color: #ff7a00; }
.ach-detail-desc {
  font-size: var(--fs-13);
  color: #6b5b8a;
  text-align: center;
}
.ach-detail-goal {
  font-size: var(--fs-13);
  font-weight: 700;
  color: #4b2a8c;
}
.ach-detail-goal--max { color: #ff7a00; font-weight: 800; }
.ach-detail .ach-bar { width: min(100%, calc(280px * var(--ui-scale))); }

/* Узкий экран (телефон в альбомной): плитки мельче, но сетка остаётся 4×3
   (четыре ячейки по 74px — это 354px вместе с промежутками, влезает и на 640px). */
@media (max-height: 499px) and (orientation: landscape) {
  .ach-grid { --ach-cell: calc(74px * var(--ui-scale)); }
  .ach-detail-art {
    width: calc(130px * var(--ui-scale));
    height: calc(130px * var(--ui-scale));
  }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ДУЭЛИ — хаб «Мир/Друзья», экран подбора соперника и панель дуэлей с другом.
   Оформление наследует систему панелей игры (--ui-scale/--ui-space, пастель, сирень)
   от «Друзей»/«Магазина»: те же .sp2-topbar, .mail-tabs, .freq-row, .fp-rank, .qp-toast.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── Хаб выбора вида дуэли ─────────────────────────────────────────────────── */
.duel-hub {
  padding: 0;
  gap: 0;
  overflow: hidden;
  justify-content: flex-start;
}
.duel-hub-topbar {
  width: 100%;
  padding: calc(10px * var(--ui-space)) calc(26px * var(--ui-space))
           calc(10px * var(--ui-space)) calc(42px * var(--ui-space));
  box-sizing: border-box;
}
.duel-hub-stage {
  flex: 1;
  width: 100%;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(16px * var(--ui-space));
  padding: 0 calc(20px * var(--ui-space)) calc(20px * var(--ui-space));
  box-sizing: border-box;
}
/* Две крупные кнопки экрана — «Мир» и «Друзья». Арт (assets/duel/) идёт БЕЗ подложки
   и рамки: тень рисуем по альфе самой картинки через drop-shadow, чтобы непрямоугольный
   глобус не сидел в невидимой «ячейке». Подпись и пояснение стоят ПОД артом — сами
   картинки без текста, название рисует интерфейс. */
.duel-hub-choices {
  display: flex;
  align-items: stretch;
  justify-content: center;
  flex-wrap: wrap;
  gap: calc(28px * var(--ui-space));
  width: 100%;
  min-height: 0;
  max-width: min(calc(560px * var(--ui-scale)), 94vw);
}
.duel-choice {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: calc(4px * var(--ui-space));
  padding: 0;
  border: 0;
  background: none;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  transition: transform 0.14s ease, filter 0.14s ease;
}
.duel-choice:hover:not(:disabled) { transform: translateY(calc(-4px * var(--ui-scale))); }
.duel-choice:active:not(:disabled) { transform: scale(0.96); }

.duel-choice-art {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Пара кнопок должна влезать и по ширине, и по высоте вплоть до 653×280 (Fold в
     ландшафте), поэтому берём самое тесное из трёх ограничений; на подпись под артом
     оставлен запас в vh. Арт нарочно НЕ во всю ширину экрана: две картинки во весь
     рост читались как заставка, а не как выбор из двух кнопок. */
  width: min(calc(148px * var(--ui-scale)), 25vw, 34vh);
  height: min(calc(148px * var(--ui-scale)), 25vw, 34vh);
  min-height: 0;
}
.duel-choice-img {
  filter: drop-shadow(0 calc(10px * var(--ui-scale)) calc(20px * var(--ui-scale)) rgba(42,26,64,0.35));
}
.duel-choice-badge { top: calc(2px * var(--ui-scale)); right: calc(6px * var(--ui-scale)); }
.duel-choice-cap {
  font-size: var(--fs-16);
  font-weight: 900;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #4a2d6e;
  text-shadow: 0 calc(2px * var(--ui-scale)) 0 rgba(255,255,255,0.6);
}
.duel-choice-sub {
  font-size: var(--fs-11-5);
  font-weight: 700;
  color: #8b7aa5;
}
.duel-hub-hint {
  font-size: var(--fs-13);
  font-weight: 700;
  color: #a8762a;
  text-align: center;
}

/* ── «Мир»: мастер дуэли постранично — DuelWorld ─────────────────────────────
   На экране ВСЕГДА один вопрос, и живёт он В КАРТОЧКЕ (.dw-card) — той же, что у
   панели дуэлей с другом (.df-card): молочно-сиреневый градиент, белая кайма,
   сиреневое кольцо и глубокая тень. Раньше страницы висели прямо на фоне экрана
   голым списком строк: выбор не читался как «бланк», а верх экрана пустовал.

   Внутри карточки: полоска шагов с подписями (.dw-rail), страница (.dw-page) и
   подвал с парой кнопок (.dw-foot). Страница — список крупных карточек .dw-opt
   (режим, полоса ранга) либо номиналов .dw-amount (сумма); карточка занимает всю
   ширину — раз вопрос на экране один, вариантам не за что бороться, и по ним
   удобно попадать пальцем. */
.duel-world { padding: 0; gap: 0; overflow: hidden; justify-content: flex-start; }
.dw-topbar {
  width: 100%;
  padding: calc(10px * var(--ui-space)) calc(26px * var(--ui-space))
           calc(10px * var(--ui-space)) calc(30px * var(--ui-space));
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: calc(10px * var(--ui-space));
}
/* Глобус из хаба повторён в шапке — экран продолжает нажатую кнопку «Мир» */
.dw-topbar-art {
  width: calc(38px * var(--ui-scale));
  height: calc(38px * var(--ui-scale));
  object-fit: contain;
  flex-shrink: 0;
  filter: drop-shadow(0 calc(3px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(42,26,64,0.3));
}
.dw-balance {
  display: inline-flex;
  align-items: center;
  gap: calc(6px * var(--ui-space));
  margin-right: calc(14px * var(--ui-space));
  padding: calc(4px * var(--ui-space)) calc(13px * var(--ui-space));
  background: linear-gradient(180deg, #ffffff, #f7edff);
  border-radius: 999px;
  box-shadow: 0 calc(3px * var(--ui-scale)) calc(9px * var(--ui-scale)) rgba(120,80,170,0.22),
              inset 0 0 0 calc(2px * var(--ui-scale)) rgba(155,111,200,0.22);
  font-size: var(--fs-15);
  font-weight: 900;
  color: #3a2358;
  font-variant-numeric: tabular-nums;
}
.dw-coin { width: calc(19px * var(--ui-scale)); height: calc(19px * var(--ui-scale)); object-fit: contain; }
.dw-stage {
  position: relative;   /* якорь для мягкой подсветки .dw-glow под карточкой */
  flex: 1;
  width: 100%;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 calc(20px * var(--ui-space)) calc(16px * var(--ui-space));
  box-sizing: border-box;
  overflow: hidden;
}
/* Три пастельных пятна за карточкой: глубина фону, но не рисунок — фон экрана
   остаётся ровным градиентом игры. Это radial-gradient, а не blur(): фильтр по
   такой площади заметно греет слабые телефоны. */
.dw-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}
.dw-glow i {
  position: absolute;
  display: block;
  border-radius: 50%;
  animation: dw-drift 11s ease-in-out infinite;
}
/* Цвета подобраны ПОД МЕСТО на фоне экрана: янтарь ложится на голубой верх слева,
   мята — на розовый низ справа. Пятно в тон фона под собой просто не видно. */
.dw-glow i:nth-child(1) {
  width: 44vh; height: 44vh; left: 4%; top: -6%;
  background: radial-gradient(circle, rgba(255,198,110,0.5), rgba(255,198,110,0) 62%);
}
.dw-glow i:nth-child(2) {
  width: 46vh; height: 46vh; right: 3%; bottom: -14%;
  background: radial-gradient(circle, rgba(120,225,190,0.45), rgba(120,225,190,0) 62%);
  animation-delay: -5.5s;
}
/* Третье пятно — белый ореол ровно под карточкой: она приподнимается над фоном,
   а тень перестаёт выглядеть грязным пятном на сиреневом. */
.dw-glow i:nth-child(3) {
  width: min(calc(760px * var(--ui-scale)), 92vw); height: 62vh;
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  background: radial-gradient(ellipse, rgba(255,255,255,0.55), rgba(255,255,255,0) 66%);
  animation: none;
}
@keyframes dw-drift {
  0%, 100% { transform: translate3d(0, 0, 0)        scale(1);    }
  50%      { transform: translate3d(0, -4vh, 0)     scale(1.08); }
}

/* Карточка мастера — «бланк» вопроса */
.dw-card {
  position: relative;
  z-index: 1;
  width: min(calc(560px * var(--ui-scale)), 94vw);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(10px * var(--ui-space));
  padding: calc(15px * var(--ui-space)) calc(18px * var(--ui-space)) calc(13px * var(--ui-space));
  background: linear-gradient(165deg, #fef6ff 0%, #f4e9ff 55%, #ffeef4 100%);
  border: calc(3px * var(--ui-scale)) solid #ffffff;
  border-radius: calc(30px * var(--ui-scale));
  box-shadow:
    0 calc(16px * var(--ui-scale)) calc(44px * var(--ui-scale)) rgba(42,26,64,0.35),
    0 0 0 calc(4px * var(--ui-scale)) rgba(155,111,200,0.4),
    inset 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(255,255,255,0.9);
  box-sizing: border-box;
  overflow: hidden;
}
/* Въезд бланка — только при первом показе экрана: карточка пересобирается на каждый
   выбор варианта, и «вечная» анимация заставляла её подпрыгивать на каждом тычке. */
.dw-card--in { animation: dw-card-in 0.3s ease-out; }
@keyframes dw-card-in {
  from { opacity: 0; transform: translateY(calc(14px * var(--ui-scale))) scale(0.97); }
  to   { opacity: 1; transform: none; }
}

/* ── Полоска шагов: где я в мастере и что ещё спросят ─────────────────────────
   У каждого кружка есть подпись («Игра», «Соперник», «Ставка»): голые цифры
   говорили только «сколько осталось». Пройденный шаг — сиреневая галочка и
   кнопка «вернуться», текущий горит янтарём игры, соединительная линия залита
   до текущего шага. */
.dw-rail {
  flex-shrink: 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  width: 100%;
  gap: calc(2px * var(--ui-space));
}
.dw-rail-step {
  flex: 0 0 auto;
  min-width: calc(58px * var(--ui-scale));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(3px * var(--ui-space));
  padding: 0;
  border: none;
  background: none;
  cursor: default;
}
.dw-rail-step:not(:disabled) { cursor: pointer; }
.dw-rail-step:not(:disabled):active .dw-rail-dot { transform: scale(0.9); }
.dw-rail-dot {
  width: calc(24px * var(--ui-scale));
  height: calc(24px * var(--ui-scale));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(255,255,255,0.72);
  box-shadow: inset 0 0 0 calc(2px * var(--ui-scale)) rgba(155,111,200,0.18);
  color: #b9a8cc;
  font-size: var(--fs-12);
  font-weight: 900;
  line-height: 1;
  transition: background 0.16s ease, color 0.16s ease, transform 0.12s ease, box-shadow 0.16s ease;
}
.dw-rail-label {
  font-size: var(--fs-10);
  font-weight: 900;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #b3a2c6;
  white-space: nowrap;
  transition: color 0.16s ease;
}
.dw-rail-step--done .dw-rail-dot {
  background: linear-gradient(180deg, #c9a9ee, #9b6fd8);
  color: #fff;
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(120,80,170,0.35);
}
.dw-rail-step--done .dw-rail-label { color: #8b6fb5; }
.dw-rail-step--on .dw-rail-dot {
  background: linear-gradient(180deg, #ffc266, #e0850f);
  color: #fff;
  transform: scale(1.12);
  box-shadow: 0 calc(3px * var(--ui-scale)) calc(9px * var(--ui-scale)) rgba(224,112,32,0.5),
              0 0 0 calc(3px * var(--ui-scale)) rgba(255,194,102,0.28);
}
.dw-rail-step--on .dw-rail-label { color: #a8762a; }
.dw-rail-link {
  flex: 1 1 auto;
  max-width: calc(70px * var(--ui-scale));
  height: calc(3px * var(--ui-scale));
  margin-top: calc(11px * var(--ui-scale));
  border-radius: 999px;
  background: rgba(155,111,200,0.18);
  transition: background 0.2s ease;
}
.dw-rail-link--on { background: linear-gradient(90deg, #c9a9ee, #ffc266); }

/* ── Страница мастера: заголовок, что уже выбрано, варианты ───────────────── */
.dw-page {
  flex: 0 1 auto;
  min-height: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(7px * var(--ui-space));
  overflow-y: auto;
}
/* Лист вперёд/назад: страница въезжает с той стороны, куда листали — на месте
   выбора это единственная подсказка о направлении. */
.dw-page--fwd  { animation: dw-page-in-fwd 0.2s ease-out; }
.dw-page--back { animation: dw-page-in-back 0.2s ease-out; }
@keyframes dw-page-in-fwd {
  from { opacity: 0; transform: translateX(calc(22px * var(--ui-scale))); }
  to   { opacity: 1; transform: none; }
}
@keyframes dw-page-in-back {
  from { opacity: 0; transform: translateX(calc(-22px * var(--ui-scale))); }
  to   { opacity: 1; transform: none; }
}
.dw-page-title {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(4px * var(--ui-space));
  font-size: var(--fs-16);
  font-weight: 900;
  color: #3a2358;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  text-align: center;
}
/* Янтарная чёрточка под вопросом — та же роль, что у подчёркнутой вкладки:
   отделяет вопрос от вариантов, не тратя на это пустую строку. */
.dw-page-title::after {
  content: '';
  width: calc(38px * var(--ui-scale));
  height: calc(3px * var(--ui-scale));
  border-radius: 999px;
  background: linear-gradient(90deg, #ffc266, #e0850f);
}
/* Что уже выбрано: мелкие плашки под вопросом. На третьей странице игрок иначе
   не видит, во что играет и с кем. */
.dw-recap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: calc(6px * var(--ui-space));
}
.dw-chip {
  display: inline-flex;
  align-items: center;
  gap: calc(5px * var(--ui-space));
  padding: calc(2px * var(--ui-space)) calc(10px * var(--ui-space));
  border-radius: 999px;
  background: rgba(255,255,255,0.75);
  box-shadow: inset 0 0 0 calc(1.5px * var(--ui-scale)) rgba(155,111,200,0.22);
  font-size: var(--fs-11);
  font-weight: 800;
  color: #6c4a94;
  white-space: nowrap;
}
.dw-chip-ico { width: calc(15px * var(--ui-scale)); height: calc(15px * var(--ui-scale)); object-fit: contain; }
.dw-page-note {
  font-size: var(--fs-11-5);
  font-weight: 700;
  color: #7b5a9a;
  text-align: center;
  line-height: 1.3;
}
/* Место страницы, пока грузится витрина или когда выбирать нечего (оффлайн) */
.dw-wait {
  width: 100%;
  padding: calc(14px * var(--ui-space));
  box-sizing: border-box;
  text-align: center;
  font-size: var(--fs-12-5);
  font-weight: 700;
  color: #9a86ad;
  background: rgba(255,255,255,0.5);
  border-radius: calc(16px * var(--ui-scale));
}

/* ── Варианты страницы: режим и полоса ранга ──────────────────────────────── */
.dw-opts {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: calc(7px * var(--ui-space));
}
.dw-opt {
  display: flex;
  align-items: center;
  gap: calc(11px * var(--ui-space));
  width: 100%;
  padding: calc(8px * var(--ui-space)) calc(12px * var(--ui-space));
  box-sizing: border-box;
  text-align: left;
  /* Строка выбора — молочный градиент, сиреневая кайма, мягкая тень (как .freq-row
     у «Друзей»). Выбранная — тёплая сливочная с янтарной каймой: янтарь в игре и
     значит «это выбрано». */
  background: linear-gradient(160deg, #ffffff, #fbf2ff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.25);
  border-radius: calc(20px * var(--ui-scale));
  box-shadow: 0 calc(3px * var(--ui-scale)) calc(9px * var(--ui-scale)) rgba(155,111,200,0.16);
  cursor: pointer;
  transition: transform 0.12s ease, background 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
}
.dw-opt:hover:not(:disabled) {
  background: linear-gradient(160deg, #ffffff, #fff7ff);
  transform: translateY(calc(-1px * var(--ui-scale)));
}
.dw-opt:active:not(:disabled) { transform: scale(0.99); }
.dw-opt--on {
  background: linear-gradient(180deg, #fffaf0, #ffedcf);
  border-color: #ffc46b;
  box-shadow: 0 calc(5px * var(--ui-scale)) calc(14px * var(--ui-scale)) rgba(224,112,32,0.28),
              inset 0 calc(1px * var(--ui-scale)) 0 rgba(255,255,255,0.9);
}
/* Полоса ранга без соперников: гаснет, но остаётся нажимаемой — выбрав её, игрок
   получает строку «Для этого ранга соперники пока не найдены» вместо немой кнопки.
   Платный режим оффлайн — тот же вид, но кнопка действительно disabled. */
.dw-opt--off { opacity: 0.5; }
.dw-opt--off.dw-opt--on { opacity: 0.85; }
.dw-opt:disabled { cursor: default; }

/* Медальон варианта: арт игры (звезда, драже, кубок, овощ ранга) в глазурованной
   плашке — тот же приём, что у иконок валют и наград. */
.dw-medal {
  flex-shrink: 0;
  width: calc(46px * var(--ui-scale));
  height: calc(46px * var(--ui-scale));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 34%;
  background: linear-gradient(165deg, #ffffff, #efe4fb);
  box-shadow: inset 0 calc(2px * var(--ui-scale)) 0 rgba(255,255,255,0.85),
              0 calc(3px * var(--ui-scale)) calc(8px * var(--ui-scale)) rgba(120,80,170,0.22);
}
.dw-medal--xp     { background: linear-gradient(165deg, #f2fff2, #c8ecd6); }
.dw-medal--money  { background: linear-gradient(165deg, #fff0f7, #ffcbe2); }
.dw-medal--bet    { background: linear-gradient(165deg, #fff6e0, #ffd88f); }
.dw-medal--rank   { border-radius: 50%; }
.dw-medal--lower  { background: linear-gradient(165deg, #f2fff5, #c8ecd6); }
.dw-medal--same   { background: linear-gradient(165deg, #f7f0ff, #dcc9f5); }
.dw-medal--higher { background: linear-gradient(165deg, #fff1e8, #ffcdb4); }
.dw-medal-img {
  width: 66%;
  height: 66%;
  object-fit: contain;
  filter: drop-shadow(0 calc(2px * var(--ui-scale)) calc(3px * var(--ui-scale)) rgba(42,26,64,0.25));
}
/* Полоса без своего ранга — прочерк вместо арта */
.dw-medal-none {
  font-size: var(--fs-18);
  font-weight: 900;
  line-height: 1;
  color: rgba(90,60,130,0.35);
}
/* Значка-галочки на медальоне НЕТ: выбранная карточка и так вся сливочно-янтарная,
   а второй маркер поверх арта только пачкал его. Вместо галочки медальон выбранного
   варианта получает янтарное кольцо — тот же язык, что у каймы самой карточки. */
.dw-opt--on .dw-medal {
  box-shadow: inset 0 calc(2px * var(--ui-scale)) 0 rgba(255,255,255,0.85),
              0 calc(3px * var(--ui-scale)) calc(8px * var(--ui-scale)) rgba(224,112,32,0.28),
              0 0 0 calc(2.5px * var(--ui-scale)) rgba(255,196,107,0.9);
}

.dw-opt-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: calc(1px * var(--ui-space));
}
.dw-opt-title {
  font-size: var(--fs-15);
  font-weight: 900;
  color: #3a2358;
}
/* Карточка режима — одна строка на всю высоту медальона, поэтому имя режима крупнее:
   мелкий заголовок в пустой строке выглядел бы потерянным. */
.dw-opt--mode .dw-opt-title { font-size: var(--fs-17-5); letter-spacing: 0.2px; }
.dw-opt-desc {
  font-size: var(--fs-11-5);
  font-weight: 700;
  color: #8b7aa5;
  line-height: 1.25;
}
/* Плашка-значение справа: цена входа на странице режима, множитель награды на
   странице соперника. Тонированная пилюля вместо цветного текста — так значение
   читается как ярлык варианта, а не как вторая строка описания. */
.dw-opt-tag {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: calc(4px * var(--ui-space));
  padding: calc(4px * var(--ui-space)) calc(11px * var(--ui-space));
  border-radius: 999px;
  font-size: var(--fs-11-5);
  font-weight: 900;
  white-space: nowrap;
  text-align: right;
  /* Общая «глазурь» плашек: белый блик сверху и мягкая тень под пилюлей — те же
     леденцовые плашки, что у кошелька и наград, а не плоская полупрозрачная заливка. */
  box-shadow: inset 0 calc(1.5px * var(--ui-scale)) 0 rgba(255,255,255,0.75),
              0 calc(2px * var(--ui-scale)) calc(5px * var(--ui-scale)) rgba(120,80,170,0.18);
}
/* «Бесплатно» — не серая приписка, а приманка: леденцовая малина игры (те же розовые,
   что у подарков и шаров подбора), белый текст с вишнёвой тенью и розовое свечение.
   Мятной она быть перестала: рядом стоит такой же мятный медальон «Разминки», плашка
   с ним сливалась в одно зелёное пятно — теперь цена отделена от арта цветом.
   Плашки цены рядом остаются светлыми — так «бесплатно» видно первым. */
.dw-opt-tag--free {
  color: #ffffff;
  background: linear-gradient(180deg, #ff93c8, #d8408f);
  text-shadow: 0 calc(1.5px * var(--ui-scale)) 0 rgba(140,25,85,0.38);
  box-shadow: inset 0 calc(1.5px * var(--ui-scale)) 0 rgba(255,255,255,0.55),
              0 calc(3px * var(--ui-scale)) calc(8px * var(--ui-scale)) rgba(216,64,143,0.42);
}
.dw-opt-tag--cost   { color: #a8762a; background: linear-gradient(180deg, #fff3d9, #ffdfa8); }
.dw-opt-tag--lower  { color: #2b7a4b; background: linear-gradient(180deg, #e8fbf0, #c8ecd6); }
.dw-opt-tag--same   { color: #6c4a94; background: linear-gradient(180deg, #f6eeff, #e0cff7); }
.dw-opt-tag--higher { color: #b4502f; background: linear-gradient(180deg, #fff0e8, #ffd5c0); }
.dw-tag-coin { width: calc(15px * var(--ui-scale)); height: calc(15px * var(--ui-scale)); object-fit: contain; }

/* ── Страница суммы: номиналы выбранного режима ───────────────────────────── */
.dw-amounts {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: calc(6px * var(--ui-space));
}
.dw-amount {
  display: flex;
  align-items: center;
  gap: calc(10px * var(--ui-space));
  padding: calc(7px * var(--ui-space)) calc(14px * var(--ui-space));
  background: linear-gradient(160deg, #ffffff, #fbf2ff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.25);
  border-radius: calc(20px * var(--ui-scale));
  box-shadow: 0 calc(3px * var(--ui-scale)) calc(9px * var(--ui-scale)) rgba(155,111,200,0.16);
  cursor: pointer;
  transition: transform 0.12s ease, background 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
}
.dw-amount:hover:not(:disabled) {
  background: linear-gradient(160deg, #ffffff, #fff7ff);
  transform: translateY(calc(-1px * var(--ui-scale)));
}
.dw-amount:active:not(:disabled) { transform: scale(0.99); }
.dw-amount--on {
  background: linear-gradient(180deg, #fffaf0, #ffedcf);
  border-color: #ffc46b;
  box-shadow: 0 calc(5px * var(--ui-scale)) calc(14px * var(--ui-scale)) rgba(224,112,32,0.28),
              inset 0 calc(1px * var(--ui-scale)) 0 rgba(255,255,255,0.9);
}
.dw-amount--poor, .dw-amount:disabled { opacity: 0.42; cursor: default; }
.dw-amount-bet {
  display: inline-flex;
  align-items: center;
  gap: calc(6px * var(--ui-space));
  font-size: var(--fs-15-5);
  font-weight: 900;
  color: #3a2358;
  font-variant-numeric: tabular-nums;
}
/* Пунктир от взноса к выигрышу: строка читается как «столько отдал → столько
   получишь», а не как два независимых числа по краям. */
.dw-amount-arrow {
  flex: 1 1 auto;
  min-width: calc(12px * var(--ui-scale));
  height: calc(2px * var(--ui-scale));
  border-radius: 999px;
  background: repeating-linear-gradient(90deg,
    rgba(155,111,200,0.30) 0 calc(4px * var(--ui-scale)),
    rgba(155,111,200,0) calc(4px * var(--ui-scale)) calc(9px * var(--ui-scale)));
}
.dw-amount--on .dw-amount-arrow {
  background: repeating-linear-gradient(90deg,
    rgba(224,112,32,0.45) 0 calc(4px * var(--ui-scale)),
    rgba(224,112,32,0) calc(4px * var(--ui-scale)) calc(9px * var(--ui-scale)));
}
.dw-amount-prize,
.dw-amount-odds {
  flex-shrink: 0;
  padding: calc(3px * var(--ui-space)) calc(10px * var(--ui-space));
  border-radius: 999px;
  font-size: var(--fs-12);
  font-weight: 900;
  white-space: nowrap;
}
.dw-amount-prize { color: #2b7a4b; background: rgba(79,174,107,0.16); }
.dw-amount-odds  { color: #6c4a94; background: rgba(155,111,200,0.18); }
/* Коэффициента ещё нет (сервер не дал оценку) — говорим это тише, чем число */
.dw-amount-odds--soft {
  color: #9a86ad;
  background: rgba(155,111,200,0.10);
  font-weight: 700;
  font-size: var(--fs-11-5);
}

/* ── Подвал: «Назад» и действие вперёд, СРАЗУ ПОД карточками ───────────────
   Подвал стоит внутри карточки и по ширине равен странице, поэтому кнопки
   выглядят продолжением блока выбора. Прижатый к низу экрана, он отрывался от
   вопроса пустотой в пол-экрана и читался как панель всего экрана. */
.dw-foot {
  flex-shrink: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(5px * var(--ui-space));
  padding: calc(7px * var(--ui-space)) 0 0;
  box-sizing: border-box;
}
/* Тающая линия над кнопками: отделяет действие от вариантов мягче, чем зазор */
.dw-foot::before {
  content: '';
  width: 78%;
  height: calc(2px * var(--ui-scale));
  margin-bottom: calc(6px * var(--ui-space));
  border-radius: 999px;
  background: linear-gradient(90deg, rgba(155,111,200,0), rgba(155,111,200,0.28), rgba(155,111,200,0));
}
.dw-foot-note {
  font-size: var(--fs-12);
  font-weight: 700;
  color: #a8762a;
  text-align: center;
  line-height: 1.3;
}
/* Обе кнопки ОДНОГО размера — ряд из двух равных долей: «Назад» молочная и тихая,
   действие вперёд — тёплая янтарная, тот же цвет игры, что у кнопки «Забрать». */
.dw-foot-row {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: calc(10px * var(--ui-space));
  width: 100%;
}
.dw-back,
.dw-go {
  flex: 1 1 0;
  min-width: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(8px * var(--ui-space));
  padding: calc(10px * var(--ui-space)) calc(16px * var(--ui-space));
  font-size: var(--fs-16);
  font-weight: 900;
  letter-spacing: 0.3px;
  border-radius: calc(16px * var(--ui-scale));
  cursor: pointer;
  transition: transform 0.12s ease, filter 0.12s ease, background 0.12s ease;
}
.dw-back {
  color: #6b4a94;
  background: linear-gradient(180deg, #ffffff, #f4ebfc);
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.9);
  box-shadow: 0 calc(3px * var(--ui-scale)) calc(9px * var(--ui-scale)) rgba(155,111,200,0.22);
}
.dw-back:hover { background: linear-gradient(180deg, #ffffff, #fbf5ff); }
.dw-back:active { transform: scale(0.96); }
.dw-go {
  position: relative;
  overflow: hidden;
  color: #fff;
  background: linear-gradient(180deg, #ffc266, #e0850f);
  border: calc(2px * var(--ui-scale)) solid rgba(255,255,255,0.8);
  text-shadow: 0 calc(2px * var(--ui-scale)) 0 rgba(150,80,10,0.35);
  box-shadow: 0 calc(5px * var(--ui-scale)) calc(14px * var(--ui-scale)) rgba(224,112,32,0.45),
              inset 0 calc(2px * var(--ui-scale)) 0 rgba(255,255,255,0.55);
}
/* Блик, медленно пробегающий по кнопке: экран выбора статичен, и единственное
   живое место на нём — то, куда надо нажать. */
.dw-go::after {
  content: '';
  position: absolute;
  top: 0;
  left: -60%;
  width: 34%;
  height: 100%;
  background: linear-gradient(100deg, rgba(255,255,255,0), rgba(255,255,255,0.5), rgba(255,255,255,0));
  transform: skewX(-18deg);
  animation: dw-shine 3.6s ease-in-out infinite;
}
@keyframes dw-shine {
  0%, 62%  { left: -60%; }
  92%, 100%{ left: 130%; }
}
.dw-go:disabled::after { display: none; }
.dw-go-label { position: relative; z-index: 1; }
.dw-go-ico {
  position: relative;
  z-index: 1;
  width: calc(23px * var(--ui-scale));
  height: calc(23px * var(--ui-scale));
  object-fit: contain;
  filter: drop-shadow(0 calc(2px * var(--ui-scale)) calc(2px * var(--ui-scale)) rgba(120,60,0,0.35));
}
.dw-go-arrow {
  position: relative;
  z-index: 1;
  font-size: var(--fs-21);
  line-height: 1;
  opacity: 0.85;
}
.dw-go:hover:not(:disabled) { filter: brightness(1.05); }
.dw-go:active:not(:disabled) { transform: scale(0.97); }
.dw-go:disabled { filter: grayscale(0.7); opacity: 0.5; cursor: default; }
.duel-world.dw-busy { pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .dw-glow i, .dw-go::after, .dw-card--in { animation: none; }
}

@media (max-width:1100px),(max-height:660px) and (orientation:landscape) {
  /* ── Акция «Пригласи друзей» на низком ландшафте ──
     Игра заблокирована в ландшафте (портрет закрывает плашка «поверните»),
     поэтому узкая адаптация живёт ЗДЕСЬ, а не в @media (max-width: 640px) —
     тот в этой игре не срабатывает никогда. Жмём отступы и подписи; полоса с
     подарками своё уменьшение получает от компактного правила .qb-track. */
  .fp-promo        { gap: calc(9px * var(--ui-space)); }
  .fp-promo-banner { padding: calc(10px * var(--ui-space)) calc(14px * var(--ui-space));
                     gap: calc(5px * var(--ui-space)); }
  .fp-promo-title  { font-size: calc(21px * var(--ui-scale) * var(--fs-scale)); }
  .fp-promo-sub    { font-size: var(--fs-12); line-height: 1.25;
                     max-width: calc(430px * var(--ui-scale)); }
  .fp-promo-count  { font-size: var(--fs-15); }
  .fp-promo-pending { font-size: var(--fs-11); max-width: calc(430px * var(--ui-scale)); }
  .fp-promo-track  { margin-top: 0; }
  .fp-promo-btn    { min-height: calc(42px * var(--ui-scale));
                     padding: 0 calc(22px * var(--ui-space));
                     font-size: var(--fs-15); }

  /* Страница должна влезать по высоте без прокрутки: жмём отступы и подписи,
     а не размер карточек — по ним попадают пальцем. */
  .dw-topbar     { padding-top: calc(6px * var(--ui-space)); padding-bottom: calc(6px * var(--ui-space)); }
  .dw-topbar-art { width: calc(30px * var(--ui-scale)); height: calc(30px * var(--ui-scale)); }
  .dw-stage      { padding-bottom: calc(8px * var(--ui-space)); }
  .dw-card       { width: min(calc(500px * var(--ui-scale)), 93vw);
                   gap: calc(7px * var(--ui-space));
                   padding: calc(11px * var(--ui-space)) calc(13px * var(--ui-space)) calc(10px * var(--ui-space));
                   border-radius: calc(24px * var(--ui-scale)); }
  .dw-rail-step  { min-width: calc(50px * var(--ui-scale)); }
  .dw-rail-dot   { width: calc(19px * var(--ui-scale)); height: calc(19px * var(--ui-scale));
                   font-size: var(--fs-10); }
  .dw-rail-label { font-size: var(--fs-9); }
  .dw-rail-link  { margin-top: calc(8.5px * var(--ui-scale)); max-width: calc(56px * var(--ui-scale)); }
  .dw-page       { gap: calc(5px * var(--ui-space)); }
  .dw-page-title { font-size: var(--fs-13); letter-spacing: 0.4px; gap: calc(3px * var(--ui-space)); }
  .dw-page-title::after { width: calc(30px * var(--ui-scale)); }
  .dw-chip       { font-size: var(--fs-10); padding: calc(1px * var(--ui-space)) calc(8px * var(--ui-space)); }
  .dw-chip-ico   { width: calc(13px * var(--ui-scale)); height: calc(13px * var(--ui-scale)); }
  .dw-page-note  { font-size: var(--fs-10-5); }
  .dw-wait       { padding: calc(9px * var(--ui-space)); font-size: var(--fs-11); }
  .dw-opts       { gap: calc(5px * var(--ui-space)); }
  .dw-opt        { gap: calc(9px * var(--ui-space));
                   padding: calc(6px * var(--ui-space)) calc(10px * var(--ui-space));
                   border-radius: calc(16px * var(--ui-scale)); }
  .dw-medal      { width: calc(36px * var(--ui-scale)); height: calc(36px * var(--ui-scale)); }
  .dw-opt-title  { font-size: var(--fs-13-5); }
  .dw-opt--mode .dw-opt-title { font-size: var(--fs-15); }
  .dw-opt-desc   { font-size: var(--fs-10-5); }
  .dw-opt-tag    { font-size: var(--fs-10-5);
                   padding: calc(3px * var(--ui-space)) calc(9px * var(--ui-space)); }
  .dw-tag-coin   { width: calc(13px * var(--ui-scale)); height: calc(13px * var(--ui-scale)); }
  .dw-amounts    { gap: calc(4px * var(--ui-space)); }
  .dw-amount     { padding: calc(5px * var(--ui-space)) calc(11px * var(--ui-space));
                   border-radius: calc(16px * var(--ui-scale)); }
  .dw-amount-bet { font-size: var(--fs-13-5); }
  .dw-amount-prize, .dw-amount-odds { font-size: var(--fs-11);
                   padding: calc(2px * var(--ui-space)) calc(8px * var(--ui-space)); }
  .dw-amount-odds--soft { font-size: var(--fs-10-5); }
  .dw-foot       { padding-top: calc(5px * var(--ui-space)); gap: calc(3px * var(--ui-space)); }
  .dw-foot::before { margin-bottom: calc(4px * var(--ui-space)); }
  .dw-foot-note  { font-size: var(--fs-10-5); }
  .dw-foot-row   { gap: calc(8px * var(--ui-space)); }
  .dw-back,
  .dw-go         { padding: calc(7px * var(--ui-space)) calc(12px * var(--ui-space));
                   font-size: var(--fs-14); border-radius: calc(14px * var(--ui-scale));
                   gap: calc(6px * var(--ui-space)); }
  .dw-go-ico     { width: calc(19px * var(--ui-scale)); height: calc(19px * var(--ui-scale)); }
  .dw-go-arrow   { font-size: var(--fs-18); }
}

/* ── Экран подбора соперника «Мир» (в стиле игры) ─────────────────────────── */
.duel-matchmaking {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: 60;   /* поверх поля/меню, пока идёт подбор */
}
.dm-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(22px * var(--ui-space));
}
.dm-bubbles {
  display: flex;
  align-items: flex-end;
  gap: calc(14px * var(--ui-space));
  height: calc(64px * var(--ui-scale));
}
.dm-bubble {
  width: calc(30px * var(--ui-scale));
  height: calc(30px * var(--ui-scale));
  border-radius: 50%;
  box-shadow: inset calc(-3px * var(--ui-scale)) calc(-4px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(0,0,0,0.15),
              inset calc(4px * var(--ui-scale)) calc(4px * var(--ui-scale)) calc(7px * var(--ui-scale)) rgba(255,255,255,0.7);
  animation: dm-bounce 0.9s ease-in-out infinite;
}
.dm-bubble--1 { background: radial-gradient(circle at 32% 30%, #ffd6ec, #ff7bb0); animation-delay: 0s; }
.dm-bubble--2 { background: radial-gradient(circle at 32% 30%, #d9c6ff, #9b6fd8); animation-delay: 0.12s; }
.dm-bubble--3 { background: radial-gradient(circle at 32% 30%, #c6ecff, #55b6f0); animation-delay: 0.24s; }
.dm-bubble--4 { background: radial-gradient(circle at 32% 30%, #fff0c6, #f7a838); animation-delay: 0.36s; }
.dm-bubble--5 { background: radial-gradient(circle at 32% 30%, #c9ffd6, #51cf66); animation-delay: 0.48s; }
@keyframes dm-bounce {
  0%, 100% { transform: translateY(0)      scale(1);    }
  50%      { transform: translateY(calc(-26px * var(--ui-scale))) scale(1.08); }
}
.dm-title {
  font-size: var(--fs-22);
  font-weight: 900;
  color: #fff;
  text-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(42,26,64,0.5);
  letter-spacing: 0.5px;
}

/* Соперник найден: шарики замирают, снизу выезжает лицо с ником. Пустой слот места
   не занимает — заголовок остаётся по центру, пока идёт поиск. */
.dm-found:empty { display: none; }
.dm-found {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(8px * var(--ui-space));
  animation: dm-found-in 0.32s ease-out both;
}
.dm--found .dm-bubble { animation-play-state: paused; }
@keyframes dm-found-in {
  from { opacity: 0; transform: translateY(calc(14px * var(--ui-scale))) scale(0.9); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.dm-ava {
  position: relative;
  width: calc(76px * var(--ui-scale));
  height: calc(76px * var(--ui-scale));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  overflow: visible;
  background: linear-gradient(180deg, #d9c6ff, #9b6fd8);
  box-shadow: 0 calc(4px * var(--ui-scale)) calc(14px * var(--ui-scale)) rgba(42,26,64,0.4),
              0 0 0 calc(3px * var(--ui-scale)) rgba(255,255,255,0.85);
}
.dm-ava-fb {
  font-size: calc(32px * var(--ui-scale));
  font-weight: 900;
  color: #fff;
  line-height: 1;
}
.dm-ava-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}
.dm-ava-rank {
  position: absolute;
  right: calc(-6px * var(--ui-scale));
  bottom: calc(-4px * var(--ui-scale));
  width: calc(30px * var(--ui-scale));
  height: calc(30px * var(--ui-scale));
  object-fit: contain;
  filter: drop-shadow(0 calc(2px * var(--ui-scale)) calc(3px * var(--ui-scale)) rgba(42,26,64,0.45));
}
.dm-found-name {
  max-width: min(calc(320px * var(--ui-scale)), 80vw);
  font-size: var(--fs-17);
  font-weight: 900;
  color: #fff;
  text-shadow: 0 calc(2px * var(--ui-scale)) calc(5px * var(--ui-scale)) rgba(42,26,64,0.5);
}

/* ── Панель дуэлей с другом (структура как у .friends-panel) ───────────────── */
.duel-friends { padding: 0; gap: 0; overflow: hidden; justify-content: flex-start; }
.df-topbar {
  width: 100%;
  padding: calc(10px * var(--ui-space)) calc(26px * var(--ui-space))
           calc(10px * var(--ui-space)) calc(42px * var(--ui-space));
  box-sizing: border-box;
}
.df-stage {
  flex: 1;
  width: 100%;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 calc(20px * var(--ui-space)) calc(20px * var(--ui-space));
  box-sizing: border-box;
}
.df-card {
  width: min(calc(720px * var(--ui-scale)), 94vw);
  height: min(calc(560px * var(--ui-scale)), 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  gap: calc(12px * var(--ui-space));
  padding: calc(18px * var(--ui-space));
  background: linear-gradient(165deg, #fef6ff 0%, #f4e9ff 55%, #ffeef4 100%);
  border-radius: calc(30px * var(--ui-scale));
  border: calc(3px * var(--ui-scale)) solid #ffffff;
  box-shadow:
    0 calc(16px * var(--ui-scale)) calc(44px * var(--ui-scale)) rgba(42,26,64,0.35),
    0 0 0 calc(4px * var(--ui-scale)) rgba(155,111,200,0.4),
    inset 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(255,255,255,0.9);
  overflow: hidden;
  box-sizing: border-box;
}
.df-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.df-body > .freq-list,
.df-body > .mail-empty { flex: 1 1 auto; min-height: 0; }
.df-body > .freq-list {
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: calc(10px * var(--ui-space));
  padding-right: calc(4px * var(--ui-space));
}
.df-note {
  flex-shrink: 0;
  text-align: center;
  font-size: var(--fs-12-5);
  font-weight: 700;
  color: #7b5a9a;
  padding: calc(4px * var(--ui-space)) calc(8px * var(--ui-space));
  line-height: 1.35;
}

/* Кнопки действий вкладок — фирменный градиент .fa-btn */
.df-challenge-btn, .df-accept-btn, .df-decline-btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: calc(34px * var(--ui-scale));
  padding: 0 calc(16px * var(--ui-space));
  border: none;
  border-radius: calc(14px * var(--ui-scale));
  font-size: var(--fs-13);
  font-weight: 800;
  white-space: nowrap;
  cursor: pointer;
  transition: transform 0.12s, filter 0.12s;
}
.df-challenge-btn, .df-accept-btn {
  background: linear-gradient(135deg, #f7a838, #ef6ea0);
  color: #fff;
  text-shadow: 0 calc(1px * var(--ui-scale)) calc(2px * var(--ui-scale)) rgba(0,0,0,0.22);
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(155,111,200,0.30);
}
/* Подтверждение вызова («Играть») — жёлтая кнопка: она отличается от обычного
   оранжево-розового «Вызвать» и читается как «сейчас начнётся матч». Текст тёмный:
   белый на жёлтом не читается. */
.df-challenge-btn--confirm {
  background: linear-gradient(135deg, #ffd83d, #ffab1f);
  color: #5a3a00;
  text-shadow: 0 calc(1px * var(--ui-scale)) 0 rgba(255,255,255,0.45);
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(8px * var(--ui-scale)) rgba(232,168,52,0.45);
}
.df-decline-btn {
  background: rgba(155,111,200,0.14);
  color: #7b5a9a;
}
.df-challenge-btn:hover:not(:disabled),
.df-accept-btn:hover:not(:disabled)   { filter: brightness(1.05); }
.df-challenge-btn:active, .df-accept-btn:active, .df-decline-btn:active { transform: scale(0.95); }
.df-challenge-btn:disabled, .df-accept-btn:disabled { opacity: 0.5; cursor: default; }
.df-sent { opacity: 0.9; }

/* Строка отклика: слева игрок + счёт + статус, справа таймер и действия */
.df-inv-row { flex-wrap: wrap; }
.df-inv-main {
  flex: 1;
  min-width: calc(120px * var(--ui-scale));
  display: flex;
  flex-direction: column;
  gap: calc(2px * var(--ui-space));
}
.df-inv-score { font-size: var(--fs-12-5); font-weight: 700; color: #7b5a9a; }
.df-inv-score b { color: #3a2358; }
.df-inv-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: calc(6px * var(--ui-space));
  flex-shrink: 0;
}
.df-inv-actions { display: flex; gap: calc(8px * var(--ui-space)); }
.df-timer {
  display: inline-flex;
  align-items: center;
  gap: calc(5px * var(--ui-space));
  padding: calc(3px * var(--ui-space)) calc(9px * var(--ui-space));
  background: rgba(247,168,56,0.16);
  border-radius: calc(11px * var(--ui-scale));
  font-size: var(--fs-12-5);
  font-weight: 800;
  color: #a8762a;
  font-variant-numeric: tabular-nums;
}
.df-timer-ico { width: calc(15px * var(--ui-scale)); height: calc(15px * var(--ui-scale)); object-fit: contain; }

/* Строки списков дуэлей повторяют «Друзей» (.fp-row): аватар крупнее, без окантовки.
   Строка отклика при этом остаётся двухэтажной — ник со статусом слева, таймер справа. */
.df-inv-row .freq-name { font-size: var(--fs-16); }

/* Статус/итог заявки в «Откликах» */
.df-out-status { font-size: var(--fs-12); font-weight: 800; }
.df-out-status--wait { color: #a8762a; }
.df-out-status--gone { color: #9a8bb0; }
.df-out-status--done { color: #3a2358; }

/* ── Вкладка «История»: два имени, конфета у победителя ── */
.df-hist-list { padding-top: calc(2px * var(--ui-space)); }
.df-hist-row {
  gap: calc(8px * var(--ui-space));
  max-width: calc(520px * var(--ui-scale));
  padding: calc(9px * var(--ui-space)) calc(14px * var(--ui-space));
}
.df-hist-row--win  { border-color: rgba(79,174,107,0.45); }
.df-hist-row--loss { border-color: rgba(255,77,109,0.35); }
.df-hist-side {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: calc(6px * var(--ui-space));
}
.df-hist-side--opp { justify-content: flex-end; }
.df-hist-name {
  min-width: 0;
  font-size: var(--fs-15);
  font-weight: 800;
  color: #3a2358;
}
.df-hist-side--opp .df-hist-name { text-align: right; cursor: pointer; }
/* Конфета победителя — игровой шарик из assets/bubbles/. У проигравшего то же место
   остаётся пустым, чтобы имена в строке не прыгали. */
.df-hist-candy {
  width: calc(26px * var(--ui-scale));
  height: calc(26px * var(--ui-scale));
  object-fit: contain;
  flex-shrink: 0;
  filter: drop-shadow(0 calc(2px * var(--ui-scale)) calc(3px * var(--ui-scale)) rgba(155,111,200,0.35));
}
.df-hist-candy--empty { display: inline-block; }
.df-hist-mid {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(1px * var(--ui-space));
}
.df-hist-score {
  font-size: var(--fs-15);
  font-weight: 900;
  color: #3a2358;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.df-hist-label { font-size: var(--fs-11); font-weight: 800; }
.df-hist-label--win  { color: #2e8b57; }
.df-hist-label--loss { color: #c0304c; }
.df-hist-label--draw { color: #7b5a9a; }

/* ── Полоса дуэли В МАТЧЕ ────────────────────────────────────────────────────
   Стоит ПЕРВОЙ в колонке поля (.game-main: полоса → поле) и повторяет его ширину —
   это единственное, что осталось НАД полем после переезда ленты показателей влево.
   До неё соперник жил текстом 13px в углу канвы — то есть дуэль визуально ничем не
   отличалась от обычного матча.

   Слева я, справа соперник, между нами полоса перетягивания: доля слева — моя (см.
   HUD.tugRatio). Смена лидера бьёт вспышкой .ds-flash поверх полосы, последние
   15 секунд полоса пульсирует (.duel-strip--final). */
.duel-strip {
  order: 0;
  position: relative;
  width: var(--board-w, 100%);
  max-width: 100%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: calc(8px * var(--ui-space));
  box-sizing: border-box;
  padding: calc(5px * var(--ui-space)) calc(10px * var(--ui-space));
  margin-bottom: calc(6px * var(--ui-space));
  border-radius: 999px;
  border: 1px solid rgba(155,111,200,0.2);
  background: rgba(255,255,255,0.55);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 calc(4px * var(--ui-scale)) calc(16px * var(--ui-scale)) rgba(120,80,170,0.14);
  z-index: 10;
}

.ds-side {
  display: flex;
  align-items: center;
  gap: calc(6px * var(--ui-space));
  min-width: 0;
  flex: 0 1 auto;
}
.ds-side--opp { flex-direction: row; }
.ds-side--opp .ds-txt { text-align: right; }

.ds-ava {
  position: relative;
  width: calc(32px * var(--ui-scale));
  height: calc(32px * var(--ui-scale));
  flex-shrink: 0;
  border-radius: 50%;
  overflow: visible;
}
.ds-ava-img,
.ds-ava-fb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}
/* Фолбэк стоит в разметке ПЕРЕД фото, поэтому фото ложится поверх него само:
   нет файла — onerror прячет <img>, и проступает буква ника. */
.ds-ava-fb {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(160deg, #b48ce0, #8a5fc0);
  color: #fff;
  font-size: var(--fs-15);
  font-weight: 900;
}
.ds-rank {
  position: absolute;
  right: calc(-3px * var(--ui-scale));
  bottom: calc(-3px * var(--ui-scale));
  width: calc(16px * var(--ui-scale));
  height: calc(16px * var(--ui-scale));
  object-fit: contain;
}

.ds-txt {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.1;
}
.ds-name {
  font-size: var(--fs-11);
  font-weight: 700;
  color: #7a6a92;
  max-width: calc(96px * var(--ui-scale));
}
.ds-score {
  font-size: var(--fs-16);
  font-weight: 900;
  color: #4a2d6e;
  font-variant-numeric: tabular-nums;
}

.ds-mid {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(2px * var(--ui-space));
}
/* Трек — цвет СОПЕРНИКА, заливка слева — мой: полоса читается как канат, который
   перетягивают, а не как обычный прогресс-бар. */
.ds-bar {
  position: relative;
  width: 100%;
  height: calc(9px * var(--ui-scale));
  border-radius: 999px;
  overflow: hidden;
  background: linear-gradient(90deg, #ff8fa3, #ff4d6d);
}
.ds-bar-fill {
  height: 100%;
  width: 50%;
  border-radius: 999px 0 0 999px;
  background: linear-gradient(90deg, #6fd48a, #35b85d);
  transition: width 0.25s ease-out;
}
.ds-lead {
  font-size: var(--fs-11-5);
  font-weight: 900;
  color: #7a6a92;
  font-variant-numeric: tabular-nums;
}
.duel-strip--lead   .ds-lead { color: #2f9e4f; }
.duel-strip--behind .ds-lead { color: #e0324f; }

/* Вызвавший друга играет «в запись»: соперника ещё нет — перетягивать нечего,
   полосу прячем, но лицо друга оставляем (видно, ЗА КОГО играем). */
.duel-strip--solo .ds-bar,
.duel-strip--solo .ds-lead { display: none; }
.duel-strip--solo .ds-side--opp .ds-score {
  font-size: var(--fs-11);
  font-weight: 700;
  color: #8b7aa5;
}

/* Концовка: те самые последние 15 секунд, когда всё и решается. */
.duel-strip--final { animation: ds-final-pulse 1s ease-in-out infinite; }
@keyframes ds-final-pulse {
  0%, 100% { box-shadow: 0 calc(4px * var(--ui-scale)) calc(16px * var(--ui-scale)) rgba(120,80,170,0.14); }
  50%      { box-shadow: 0 0 calc(18px * var(--ui-scale)) rgba(255,120,90,0.55); }
}

/* Вспышка «сменился лидер» — поверх полосы, не двигая раскладку матча. */
.ds-flash {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(0.8);
  padding: calc(3px * var(--ui-space)) calc(14px * var(--ui-space));
  border-radius: 999px;
  font-size: var(--fs-13);
  font-weight: 900;
  color: #fff;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.ds-flash--lead   { background: linear-gradient(160deg, #5ec97c, #2f9e4f); }
.ds-flash--behind { background: linear-gradient(160deg, #ff7a90, #e0324f); }
.ds-flash--show { opacity: 1; transform: translate(-50%, -50%) scale(1); }

@media (max-height: 449px) and (orientation: landscape) {
  .duel-strip { padding: calc(3px * var(--ui-space)) calc(8px * var(--ui-space)); }
  .ds-ava   { width: calc(26px * var(--ui-scale)); height: calc(26px * var(--ui-scale)); }
  .ds-score { font-size: var(--fs-14); }
  .ds-bar   { height: calc(7px * var(--ui-scale)); }
}

/* Тост об итоге дуэли с другом — чуть шире обычного (в нём счёт) */
.duel-toast { max-width: 90vw; text-align: center; }

/* Бейдж заявок на кнопке режима «Дуэль» в меню */
.btn-mode-duel { position: relative; }
.menu-mode-badge { top: calc(6px * var(--ui-scale)); right: calc(8px * var(--ui-scale)); }

/* ── Узкие экраны ── */
@media (max-width: 640px) {
  .duel-hub-choices { gap: calc(18px * var(--ui-space)); }
  .duel-choice-cap { font-size: var(--fs-15); }
  .df-stage { padding: 0 calc(12px * var(--ui-space)) calc(12px * var(--ui-space)); }
  .df-card { width: 100%; gap: calc(9px * var(--ui-space)); padding: calc(14px * var(--ui-space)); }
  .df-inv-side { align-items: stretch; }
  .df-hist-row { gap: calc(6px * var(--ui-space)); padding: calc(8px * var(--ui-space)) calc(10px * var(--ui-space)); }
  .df-hist-name { font-size: var(--fs-13-5); }
  .df-hist-candy { width: calc(22px * var(--ui-scale)); height: calc(22px * var(--ui-scale)); }
}

/* ── Низкие экраны: телефон в ландшафте — тот самый компактный брейкпоинт ── */
@media (max-height: 449px) and (orientation: landscape) {
  .duel-hub-stage { gap: calc(10px * var(--ui-space)); }
  /* Зазор больше самого арта не по прихоти: подписи под кнопками шире картинок и на
     телефоне в ландшафте сходятся вплотную. */
  .duel-hub-choices { gap: calc(34px * var(--ui-space)); }
  /* Арт ужимаем по высоте экрана, а подпись — по кеглю: пара кнопок с подписями
     должна влезать целиком, без прокрутки. */
  .duel-choice-art { width: min(calc(110px * var(--ui-scale)), 22vw, 32vh);
                     height: min(calc(110px * var(--ui-scale)), 22vw, 32vh); }
  .duel-choice-cap { font-size: var(--fs-14); }
  .duel-choice-sub { font-size: var(--fs-10); }
  .df-stage { padding: 0 calc(14px * var(--ui-space)) calc(10px * var(--ui-space)); }
  .df-card { gap: calc(7px * var(--ui-space)); padding: calc(12px * var(--ui-space)); }
  .df-note { padding: calc(2px * var(--ui-space)) calc(8px * var(--ui-space)); font-size: var(--fs-11-5); }
  .df-hist-row { padding: calc(7px * var(--ui-space)) calc(10px * var(--ui-space)); }
  .df-hist-candy { width: calc(21px * var(--ui-scale)); height: calc(21px * var(--ui-scale)); }
  .dm-bubble { width: calc(24px * var(--ui-scale)); height: calc(24px * var(--ui-scale)); }
  .dm-title { font-size: var(--fs-19); }
}

/* ═══ Подсветка платного и сезонного аватара ══════════════════════════════════
   Лицо игрока — это лот из магазина, но по кружку в рейтинге или письме не видно,
   куплен он или достался бесплатно при регистрации. Поэтому везде, КРОМЕ магазина
   (там лот и так подписан ценой), фото обводится свечением:

     голубое   — аватар за настоящие деньги (рубли);
     лавандовое — сезонный: продавался только своё окно дат и больше не продаётся
                 никому и никогда, поэтому цвет у него отдельный;
     ничего    — базовое лицо пола, гостевой «аноним», фото из внешнего аккаунта и
                 несезонное лицо за драже/мармелад: игровую валюту копит каждый.

   Кто есть кто, решает БД (shop_items → GET /api/avatars/styles), классы вешает
   ui/avatarGlow.js. Свечение — box-shadow, а не рамка: рамка съела бы пиксели
   самого лица, а кольцо ложится СНАРУЖИ круга и ничего не двигает в строке.

   Блок стоит в конце файла намеренно: у половины кружков (.freq-avatar, .pl-avatar,
   .dm-ava…) свой box-shadow, и подсветка должна лечь поверх — при равной силе
   селектора выигрывает тот, что ниже. Родную тень элемента не теряем: она
   возвращается третьим слоем через --ava-glow-base.
   Размер кольца — от --ui-scale, как всё остальное в игре.
   ═════════════════════════════════════════════════════════════════════════════ */
.ava-glow {
  --ava-glow-ring: calc(2px * var(--ui-scale));
  --ava-glow-halo: calc(9px * var(--ui-scale));
  box-shadow:
    0 0 0 var(--ava-glow-ring) rgba(var(--ava-glow-rgb), 0.85),
    0 0 var(--ava-glow-halo) calc(var(--ava-glow-halo) / 3) rgba(var(--ava-glow-rgb), 0.5),
    var(--ava-glow-base, 0 0 rgba(0,0,0,0));
}
/* Голубой — лот за рубли. Лавандовый — сезонный: он в палитре игры больше нигде не
   встречается, поэтому редкость видно с одного взгляда и её не спутать с покупкой. */
.ava-glow--paid   { --ava-glow-rgb: 132, 209, 255; }
.ava-glow--season { --ava-glow-rgb: 183, 148, 255; }

/* Кружки со своей тенью — возвращаем её третьим слоем (значения те же, что выше
   в их собственных правилах). */
.freq-avatar.ava-glow       { --ava-glow-base: 0 2px 6px rgba(123,63,190,0.25); }
.gift-friend-avatar.ava-glow{ --ava-glow-base: 0 2px 5px rgba(123,63,190,0.22); }

/* Крупные лица: карточка игрока, свой профиль и найденный соперник в подборе —
   кольцо и ореол крупнее, иначе на 116–132 px подсветка читается ниткой. */
.pl-avatar.ava-glow,
.pf-avatar.ava-glow {
  --ava-glow-ring: calc(3px * var(--ui-scale));
  --ava-glow-halo: calc(18px * var(--ui-scale));
  --ava-glow-base: 0 8px 20px rgba(123,63,190,0.38);
}
.pf-avatar.ava-glow {
  --ava-glow-ring: calc(3px * var(--pf-scale));
  --ava-glow-halo: calc(18px * var(--pf-scale));
}
/* Соперник на экране подбора: белую окантовку заменяет кольцо подсветки, тень остаётся. */
.dm-ava.ava-glow {
  --ava-glow-ring: calc(3px * var(--ui-scale));
  --ava-glow-halo: calc(16px * var(--ui-scale));
  --ava-glow-base: 0 calc(4px * var(--ui-scale)) calc(14px * var(--ui-scale)) rgba(42,26,64,0.4);
}

/* ═══ Подсветка премиум- и сезонного подарка ══════════════════════════════════
   Подарок в игре показывается ОДНИМ артом: цены у него вне магазина нет, а
   названия нет вообще (оно живёт в БД только ради id). Поэтому везде, КРОМЕ
   магазина, редкий подарок обводится свечением:

     голубое    — премиум: лот за настоящие деньги;
     лавандовое — сезонный: стоял на витрине одно окно дат и больше не продаётся;
     жёлтое     — подарок от игры: его не купить и не выиграть, он просто приходит
                  (сейчас это сундук за регистрацию);
     ничего     — подарок за драже или мармелад: игровую валюту копит каждый.

   Оба цвета взяты у лица игрока: голубой — у кольца аватара за рубли
   (.ava-glow--paid, `132,209,255`), лавандовый — у сезонного (.ava-glow--season,
   `183,148,255`). «Голубое = за рубли» и «лавандовое = сезонное» в игре по одному
   слову, и подарку незачем заводить второе. Оба оттенка здесь СВЕТЛЕЕ аватарных
   (`160,220,254` и `199,172,255`) по одной и той же причине: кольцо лица лежит по
   ровному кругу, а свечение подарка идёт по фигуре арта — густой цвет на ней
   читается пятном, а не свечением.

   Премиум был белым, и это не работало: панели, на которых подарок показывают
   (.gift-inv-card, .pf-modal), сами почти белые. Замер в Chromium по стеку ниже —
   среднее отклонение от фона карточки вокруг фигуры: 9 единиц из 765 у белого
   против 16 у лавандового сезонного, пик 38 против 133. Белого премиума на белой
   карточке просто не видно, и прибавка плотности этого не лечит: десять процентов
   от невидимого невидимы. Голубой на том же фоне даёт 21 при пике 162 — вот это
   и видно.

   Кто есть кто, решает БД (shop_items → GET /api/gifts/styles), классы вешает
   ui/giftGlow.js.

   Свечение — drop-shadow, а не box-shadow: арт подарка это фигура на прозрачном
   фоне, и кольцо box-shadow обвело бы КВАДРАТ картинки, а drop-shadow идёт по
   альфе — по самому подарку. Слои идут один за другим (каждый следующий обводит
   результат предыдущего): плотное ядро в цвет, широкий ореол в него же и третьим
   — бледно-фиолетовая кромка. Кромка держит светлый оттенок на светлом фоне:
   панели игры сами почти белые (.pf-modal, .gift-inv-card), и без неё край
   свечения на них расплывается.
   Родную тень элемента не теряем: она возвращается последним слоем через
   --gift-glow-base. Размеры — от --ui-scale, как всё остальное в игре.

   ─ ПОЛЕ ПОД ОРЕОЛ (--gift-glow-room) ─ почему свечение больше нигде не режется.

   drop-shadow рисует ЗА краями <img>, а витрины и письма стоят в скролл-
   контейнерах, и те режут всё, что вылезло за их край: у .pf-modal-body нет
   вертикальных полей вовсе — край тела и есть край видимого, а у сетки под ним
   запас 4px. Арты подарков при этом почти без прозрачных полей (у леденца
   turbopresent2.png сверху и снизу 5% картинки), так что ореол уходил за <img>
   на 20–35px и у верхнего ряда, у крайних плиток и на карточке «от кого» его
   срезало. Полями контейнеров это не лечится: под прокруткой любой запас
   когда-нибудь окажется под краем.

   Поэтому ореол живёт ВНУТРИ картинки. Каждому арту подарка отдано поле
   --gift-glow-room по краям (padding при box-sizing: border-box — object-fit
   сажает арт в остаток), а слот под арт на два таких поля увеличен: картинка
   прежнего размера, а свечению больше незачем выходить за <img>. Резать нечего —
   за краями картинки ореола просто нет. Тот же приём, которым внутрь плитки
   убраны её значки (см. .tile-new-dot).

   Поле = 2 × --gift-glow-halo: на этом расстоянии от фигуры ореол гаснет до ~3%
   (замер в Chromium по стеку ниже), а на почти белых панелях игры это меньше
   одного шага цвета. Поле держим у ВСЕХ артов подарка, а не только у светящихся:
   в сетке рядом стоят редкие и обычные, и картинка не должна быть меньше у
   соседа.
   ═════════════════════════════════════════════════════════════════════════════ */
/* Поле по умолчанию — арту, которому свечение поставили в новом месте, без своего
   слота: наследуется до картинки, а место показа перебивает его своим значением
   (ниже). Именно наследованием, а не правилом на .gift-glow: слот под арт и сама
   картинка — разные элементы, и размер поля им нужен общий. */
:root { --gift-glow-room: calc(14px * var(--ui-scale)); }

.gift-glow {
  --gift-glow-halo: calc(var(--gift-glow-room) / 2);
  --gift-glow-alpha: 1;
  --gift-glow-spread: 1;
  filter:
    drop-shadow(0 0 calc(var(--gift-glow-halo) * 0.25 * var(--gift-glow-spread)) rgba(var(--gift-glow-rgb), min(1, 1 * var(--gift-glow-alpha))))
    drop-shadow(0 0 calc(var(--gift-glow-halo) * 0.9 * var(--gift-glow-spread)) rgba(var(--gift-glow-rgb), min(1, 0.88 * var(--gift-glow-alpha))))
    drop-shadow(0 0 calc(var(--gift-glow-halo) * 1.3 * var(--gift-glow-spread)) rgba(123,63,190,0.31))
    var(--gift-glow-base, drop-shadow(0 0 rgba(0,0,0,0)));
}
/* Голубой — премиум (за рубли), светлее кольца аватара за рубли. Лавандовый —
   сезонный.

   Премиум светится заметнее остальных: это единственный подарок, который нельзя
   накопить, и видно его должно быть с первого взгляда. Заметность даёт ЦВЕТ, а не
   плотность — почему, показывает замер белого в шапке блока.

   Прибавка у премиума осталась одна — РАДИУС (--gift-glow-spread): ореол шире,
   света вокруг фигуры больше. Радиусы раньше трогать было нельзя, чтобы свечение
   не вышло за <img> и его не срезала прокрутка витрины, — но режется оно только за
   краем картинки, а внутри у нас поле --gift-glow-room = 2 × --gift-glow-halo. Самый
   широкий слой был 1.3 × halo, стал 1.43 × halo — по-прежнему с запасом внутри
   поля. Растить spread дальше нельзя: на 1.55 внешний слой упрётся в край поля, и
   придётся сперва расширять поле у каждого арта вместе с его слотом.

   Свечение убавляли тремя пятипроцентными шагами, и мерили их --gift-glow-alpha:
   1.21 → 1 (замер на карточке инвентаря 20.7 → 19.7), 1 → 0.92 (19.7 → 18.7) и
   последним шагом свою прибавку получил ЦВЕТ. Радиусом такие шаги не отмерить:
   blur округляется до целого пикселя, и соседние значения spread дают то −1.9%,
   то сразу −6.1% — пятипроцентной ступеньки там просто нет. Кромкой тоже: она
   общая с сезонным, и трогать её значило бы менять его заодно.

   Последний шаг стоит объяснить отдельно, иначе 1.05 выглядит прибавкой. Оттенок
   попросили нежнее, и `132,209,255` сменился на `160,220,254` — светлее и мягче.
   Но чем светлее свечение, тем меньше его видно на почти белой карточке: сам по
   себе новый оттенок при прежней плотности дал бы −12%, а просили −5%. Поэтому
   альфа поднята до 1.05 — ровно настолько, чтобы вернуть недостающие проценты
   (замер: 18.7 → 17.7, −4.9%). Множитель тут не «ярче», а мера цвета: он держит
   заказанную яркость, когда оттенок меняется.

   Звался множитель --gift-glow-boost, пока свечение только поднимал; со значением
   0.92 такое имя читалось бы наоборот, поэтому оно теперь нейтральное — просто
   множитель альфы обоих цветных слоёв. */
.gift-glow--premium {
  --gift-glow-rgb: 160, 220, 254;
  --gift-glow-alpha: 1.05;
  --gift-glow-spread: 1.1;
}
.gift-glow--season  { --gift-glow-rgb: 199, 172, 255; }

/* Жёлтый — подарок от игры (сундук за регистрацию): то же медовое свечение, что и
   у премиума, но на 8% ярче. Кому его зажечь, решает флаг `{"glow":"gold"}` в
   extra лота, а не цена и не сезон, — см. GET /api/gifts/styles.

   Оттенок подобран не на глаз, а по той же метрике, что и голубой: жёлтый на
   почти белой карточке виден иначе, и при одной плотности `255,214,120` дал бы
   +16% света к премиуму, а `255,236,186` — −14%. Сперва стоял `255,226,150`
   (+1.1%, вровень с премиумом), потом яркость попросили поднять на 8% — и её,
   как и у премиума, пришлось брать цветом: альфа тут в потолке (ореол
   0.88 × 1.05 = 0.924, дальше min() держит его на 1, и хоть 1.15, хоть 1.25 дают
   одни и те же +3.1%), а радиус до края поля дотягивает лишь +6.7%. Насыщенность
   же ходит плавно: `255,219,134` даёт ровно +8.0% (замер 17.9 → 19.4). */
.gift-glow--gold {
  --gift-glow-rgb: 255, 219, 134;
  --gift-glow-alpha: 1.05;
  --gift-glow-spread: 1.1;
}

/* Поле под ореол внутри самой картинки. Размер поля задан у каждого арта своим
   (ниже), а «сколько его» знает слот под арт — там же прибавлены эти два поля.
   Последним селектором поле достаётся любому арту, которому свечение поставили
   без своего слота: картинка в нём станет уже на поле, но не срежется. */
.pf-tile--gift .pf-tile-img,
.pf-gift-img,
.gift-inv-img,
.gift-in-img,
.mail-reward-item--gift .mail-reward-icon:not(.mail-reward-icon--candy),
.gift-glow {
  box-sizing: border-box;
  padding: var(--gift-glow-room);
}

/* Крупные арты — витрина подарков (92px), выбор подарка другу (тоже 92px) и карточка
   «от кого и когда» (170px): ореол крупнее, иначе на таком арте свечение читается
   ниткой. Поле плитки знает и сетка: колонка не должна быть уже плитки
   (см. .pf-grid--gift). */
.pf-grid--gift,
.pf-tile--gift,
.gift-inv-img  { --gift-glow-room: calc(18px * var(--ui-scale)); }
.pf-gift-art   { --gift-glow-room: calc(28px * var(--ui-scale)); }

/* Подарок в списке входящих (20px): у мелкого арта ореол по размеру картинки,
   иначе свечение шире самого подарка. */
.gift-in-img  { --gift-glow-room: calc(8px * var(--ui-scale)); }

/* Подарок в письме. В строке наград арт 64px — поле по умолчанию (14px) ему
   впору, отдельного правила не нужно.
   Одинокий подарок нарисован на 92px, но поле ему УЖЕ, чем витрине подарков
   (12px против 18px): сторону квадрата задаёт высота содержимого, и два поля
   уходят в неё целиком — каждый лишний пиксель поля растит квадрат на два. */
.mail-reward-box--solo .mail-reward-item--gift { --gift-glow-room: calc(12px * var(--ui-scale)); }

/* Арт подарка в письме (39px) стоит на поле по умолчанию. Своя тень у иконки уже
   есть: возвращаем её последним слоем (то же значение, что в .mail-reward-icon). */
.mail-reward-icon.gift-glow { --gift-glow-base: drop-shadow(0 3px 6px rgba(123,63,190,0.3)); }

/* ═══ Подсказка-описание раздела (.ui-note) ═══════════════════════════════════
   Одна строка правилом раздела: фантик приходит письмом, подарок дарят из «Писем»,
   приз за место выдают в понедельник. Разметку собирает ui/lib/hintNote.js, текст
   живёт в ui/lib/i18n.js.

   Почему плашкой, а не пузырём по title: пузырь (.gt-tip ниже) всплывает ТОЛЬКО
   под мышью — Tooltip.js сам отсеивает касания, — а игра живёт на телефоне. То,
   без чего раздел непонятен, обязано быть видно пальцу.

   Вид скромный: та же бело-сиреневая плашка, что у вкладок (.mail-tab) и строк
   списка, без «золотой» заливки, чтобы подсказка не спорила с содержимым.
   Своей ширины (fit-content) и по центру в обеих раскладках сразу: align-self —
   для flex-колонки (карточка друзей, письма, рейтинг), margin:auto — для обычного
   потока (лента заданий). Ужиматься по высоте плашке нельзя (flex-shrink:0):
   в низком ландшафте её строка схлопнулась бы в полоску. */
.ui-note {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(8px * var(--ui-space));
  flex-shrink: 0;
  align-self: center;
  width: fit-content;
  max-width: 100%;
  margin: 0 auto;
  padding: calc(7px * var(--ui-space)) calc(16px * var(--ui-space));
  background: linear-gradient(160deg, #ffffff, #f7edff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.28);
  border-radius: calc(18px * var(--ui-scale));
  box-shadow: 0 2px 8px rgba(155,111,200,0.15);
  box-sizing: border-box;
  text-align: center;
}
.ui-note-icon {
  width: calc(22px * var(--ui-scale));
  height: calc(22px * var(--ui-scale));
  object-fit: contain;
  flex-shrink: 0;
}
.ui-note-text {
  font-size: var(--fs-12-5);
  font-weight: 700;
  color: #7b3fbe;
  line-height: 1.35;
}

/* Низкий ландшафт: подсказка отдаёт содержимому раздела всё, что может отдать, —
   она полезна, но не ценой ряда карточек под ней. */
@media (max-height: 499px) and (orientation: landscape) {
  .ui-note {
    gap: calc(6px * var(--ui-space));
    padding: calc(4px * var(--ui-space)) calc(11px * var(--ui-space));
  }
  .ui-note-icon { width: calc(18px * var(--ui-scale)); height: calc(18px * var(--ui-scale)); }
  .ui-note-text { font-size: var(--fs-11-5); }
}

/* ─── Подсказки на кнопках (title) ──────────────────────────
   Кнопки в игре почти все без подписи — одна картинка, а что она делает,
   сказано в title. В браузере такой ярлычок рисует ОС: серый прямоугольник
   системным шрифтом, мимо всей палитры. ui/Tooltip.js снимает title и рисует
   вместо него этот пузырь — то же стекло и та же сиреневая рамка, что у
   подсказки обучения (.tut-hint), плюс хвостик к кнопке.

   Пузырь встаёт СБОКУ от кнопки (сторону считает pickPlacement в Tooltip.js):
   меню, магазин и рейтинг — это колонки кнопок, и подсказка над кнопкой закрывала
   бы соседнюю. Четыре стороны — четыре класса: --right/--left/--above/--below;
   у каждой свой хвостик, своя точка роста и свой сдвиг в анимации появления.

   z-index выше самого верхнего слоя игры (тост поверх магазина, 10050):
   подсказка обязана лечь поверх любого оверлея, к кнопке которого привязана.
   pointer-events: none — иначе пузырь, встающий над кнопкой, перехватывал бы
   у неё же клик (и мигал бы: наведение → пузырь → курсор на пузыре → ушли с
   кнопки → пузырь погас).
────────────────────────────────────────────────────────────── */
.gt-tip {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 10100;
  visibility: hidden;
  display: flex;
  flex-direction: column;
  gap: calc(2px * var(--ui-space));
  max-width: min(72vw, calc(280px * var(--ui-scale)));
  padding: calc(7px * var(--ui-space)) calc(12px * var(--ui-space));
  border: 1px solid rgba(155,111,200,0.35);
  border-radius: calc(12px * var(--ui-scale));
  background: rgba(255,255,255,0.94);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 calc(5px * var(--ui-scale)) calc(18px * var(--ui-scale)) rgba(80,40,120,0.22);
  font-size: var(--fs-12);
  font-weight: 600;
  line-height: 1.35;
  color: #2a1a40;
  text-align: center;
  text-wrap: balance;
  pointer-events: none;
  opacity: 0;
  transform: translateY(calc(3px * var(--ui-scale))) scale(0.97);
  transform-origin: 50% 100%;
  transition: opacity 0.16s ease, transform 0.16s ease;
}

.gt-tip--on   { visibility: visible; }
.gt-tip--show { opacity: 1; transform: translateY(0) scale(1); }

/* Однострочная подсказка — пилюля, как тост и подсказка обучения (см. fitShape()). */
.gt-tip--pill {
  border-radius: 999px;
  padding-left:  calc(15px * var(--ui-space));
  padding-right: calc(15px * var(--ui-space));
}

/* Куда пузырь встал — оттуда он и растёт: точка роста и сдвиг смотрят в кнопку.
   Сбоку (основной случай) сдвиг горизонтальный, сверху и снизу — вертикальный. */
.gt-tip--right {
  transform: translateX(calc(-3px * var(--ui-scale))) scale(0.97);
  transform-origin: 0 50%;
}
.gt-tip--left {
  transform: translateX(calc(3px * var(--ui-scale))) scale(0.97);
  transform-origin: 100% 50%;
}
.gt-tip--above {
  transform: translateY(calc(3px * var(--ui-scale))) scale(0.97);
  transform-origin: 50% 100%;
}
/* Пузырь под кнопкой (сверху не поместился) — растёт от верхнего края вниз. */
.gt-tip--below {
  transform: translateY(calc(-3px * var(--ui-scale))) scale(0.97);
  transform-origin: 50% 0;
}
.gt-tip--right.gt-tip--show,
.gt-tip--left.gt-tip--show  { transform: translateX(0) scale(1); }
.gt-tip--above.gt-tip--show,
.gt-tip--below.gt-tip--show { transform: translateY(0) scale(1); }

/* Первая строка двухстрочной подсказки — имя предмета (см. fill() в Tooltip.js):
   сиреневая и жирная, тем же цветом, каким в игре набрано всё «главное слово». */
.gt-tip-head {
  font-size: var(--fs-12-5);
  font-weight: 800;
  color: #7b3fbe;
}
.gt-tip-head + .gt-tip-text { font-weight: 500; opacity: 0.86; }

/* Хвостик: повёрнутый квадрат из того же стекла, рамка — только те две стороны,
   что смотрят наружу. --gt-arrow ставит JS: это центр кнопки, отсчитанный вдоль
   того края пузыря, которым он повёрнут к кнопке (пузырь у края экрана сдвинут, а
   хвостик всё равно смотрит в кнопку). У боковых пузырей край вертикальный —
   значит, смещение идёт сверху вниз, а не слева направо. */
.gt-tip::after {
  content: '';
  position: absolute;
  width: calc(9px * var(--ui-scale));
  height: calc(9px * var(--ui-scale));
  background: rgba(255,255,255,0.94);
  transform: rotate(45deg);
}
.gt-tip--above::after,
.gt-tip--below::after {
  left: var(--gt-arrow, 50%);
  margin-left: calc(-4.5px * var(--ui-scale));
}
.gt-tip--right::after,
.gt-tip--left::after {
  top: var(--gt-arrow, 50%);
  margin-top: calc(-4.5px * var(--ui-scale));
}
.gt-tip--above::after {
  bottom: calc(-5px * var(--ui-scale));
  border-right:  1px solid rgba(155,111,200,0.35);
  border-bottom: 1px solid rgba(155,111,200,0.35);
}
.gt-tip--below::after {
  top: calc(-5px * var(--ui-scale));
  border-left: 1px solid rgba(155,111,200,0.35);
  border-top:  1px solid rgba(155,111,200,0.35);
}
.gt-tip--right::after {
  left: calc(-5px * var(--ui-scale));
  border-left:   1px solid rgba(155,111,200,0.35);
  border-bottom: 1px solid rgba(155,111,200,0.35);
}
.gt-tip--left::after {
  right: calc(-5px * var(--ui-scale));
  border-right: 1px solid rgba(155,111,200,0.35);
  border-top:   1px solid rgba(155,111,200,0.35);
}

@media (prefers-reduced-motion: reduce) {
  .gt-tip { transition: opacity 0.12s ease; transform: none; }
  .gt-tip--right, .gt-tip--left, .gt-tip--above, .gt-tip--below { transform: none; }
  .gt-tip--show,
  .gt-tip--right.gt-tip--show, .gt-tip--left.gt-tip--show,
  .gt-tip--above.gt-tip--show, .gt-tip--below.gt-tip--show { transform: none; }
}

/* ─── Ежедневный бонус ───────────────────────────────────────
   Окно над меню при входе в игру (ui/modals/DailyBonus.js): лестница дней,
   на каждом своя награда. Забранные помечены галочкой, сегодняшний светится
   и дрожит — тем же языком, что подарки недельной шкалы («дрожит — значит
   можно забрать»), поэтому и кадры анимации взяты те же (qb-chest-shake /
   qb-chest-glow), а не переписаны второй раз под другими именами.

   Размеры дня заданы одной переменной --db-day: ступеней в лестнице столько,
   сколько строк в БД, и раскладка не должна знать их число заранее —
   auto-fit сам решает, встанут ли семь дней в ряд или свернутся в две
   строки на низком экране.
────────────────────────────────────────────────────────────── */
.db-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(14px * var(--ui-space));
  background: rgba(40,20,70,0.48);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity 0.2s ease-out;
}

.db-overlay--in { opacity: 1; }

.db-card {
  /* Сколько дней в ряд и сколько рядов — считает окно по длине лестницы, которая
     приехала из БД (ui/modals/DailyBonus.js#_cols). Здесь только умолчания. */
  --db-cols: 7;
  --db-rows: 1;
  --db-gap: calc(8px * var(--ui-space));
  /* СТОРОНА КЛЕТКИ — меньшее из трёх: как задумано, сколько даёт ширина экрана и
     сколько даёт высота. Клетка квадратная, поэтому упереться она может в любую из
     сторон, и телефон в горизонтали упирается именно в высоту: две строки по семь
     должны уместиться вместе с заголовком и кнопкой. Подгон одним числом в @media
     здесь и не годился: он ужимал клетку и тогда, когда по ширине места вдоволь. */
  --db-day: min(
    calc(104px * var(--ui-scale)),
    calc((92vw - 44px * var(--ui-space)) / var(--db-cols) - var(--db-gap)),
    calc((84vh - 140px * var(--ui-scale)) / var(--db-rows) - var(--db-gap))
  );
  position: relative;
  /* Ширина — ровно под свой ряд дней: колонки, зазоры между ними и поля карточки. */
  width: calc(var(--db-cols) * (var(--db-day) + var(--db-gap)) + 30px * var(--ui-space));
  max-height: 94vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(9px * var(--ui-space));
  padding: calc(16px * var(--ui-space)) calc(18px * var(--ui-space)) calc(14px * var(--ui-space));
  border-radius: calc(26px * var(--ui-scale));
  background: linear-gradient(160deg, #fffdff 0%, #f4e8fc 55%, #fde7f4 100%);
  border: calc(3px * var(--ui-scale)) solid #fff;
  box-shadow: 0 calc(18px * var(--ui-scale)) calc(46px * var(--ui-scale)) rgba(70,30,120,0.45);
  transform: scale(0.9);
  transition: transform 0.26s cubic-bezier(.2,.9,.3,1.3);
}

.db-overlay--in .db-card { transform: scale(1); }

/* Крестик — в самом углу карточки, как в окне подарка: своей шапки у окна нет. */
.db-close {
  position: absolute;
  top: calc(6px * var(--ui-space));
  right: calc(6px * var(--ui-space));
  width: calc(38px * var(--ui-scale));
  height: calc(38px * var(--ui-scale));
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  filter: drop-shadow(0 2px 6px rgba(155,111,200,0.45));
  transition: transform 0.15s;
}

.db-close:hover  { transform: scale(1.08); }
.db-close:active { transform: scale(0.92); }
.db-close img    { width: 100%; height: 100%; object-fit: contain; }

/* Запаска под картинкой: файла может не быть, а закрыть окно нужно всегда. */
.db-close-fallback {
  position: absolute;
  z-index: 0;
  pointer-events: none;
  font-size: var(--fs-18);
  font-weight: 900;
  color: #7b3fbe;
}

/* Картинка кладётся ПОВЕРХ запаски: пока файл на месте, крестика-текста не видно. */
.db-close img { position: relative; z-index: 1; }

.db-title {
  font-size: var(--fs-22);
  font-weight: 900;
  color: #7b3fbe;
  letter-spacing: 0.02em;
  text-shadow: 0 2px 0 rgba(255,255,255,0.9);
  padding: 0 calc(40px * var(--ui-space));   /* место крестику в углу */
  text-align: center;
}

.db-sub {
  font-size: var(--fs-12-5);
  font-weight: 700;
  color: rgba(42,26,64,0.66);
  text-align: center;
  line-height: 1.35;
  max-width: calc(520px * var(--ui-scale));
}

/* ── Лестница дней ── */
.db-grid {
  display: grid;
  /* Колонок ровно столько, сколько назначило окно: день, не влезающий в строку,
     не переносится «хвостом» — вместо этого ужимаются все (minmax от нуля). */
  grid-template-columns: repeat(var(--db-cols), minmax(0, 1fr));
  gap: var(--db-gap);
  width: 100%;
}

/* Клетка КВАДРАТНАЯ — ширину ей даёт колонка сетки, высоту aspect-ratio. Не
   min-height: лестница из двух строк по семь должна читаться как сетка, а день с
   четырьмя наградами не имеет права быть выше соседнего с одной. */
.db-day {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(3px * var(--ui-space));
  aspect-ratio: 1 / 1;
  font: inherit;                /* клетка — кнопка: по нажатию видно, что внутри */
  color: inherit;
  cursor: pointer;
  transition: transform 0.12s;
  padding: calc(7px * var(--ui-space)) calc(4px * var(--ui-space)) calc(7px * var(--ui-space));
  border-radius: calc(16px * var(--ui-scale));
  background: linear-gradient(180deg, #ffffff, #f5ecfd);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.28);
  box-shadow: 0 calc(4px * var(--ui-scale)) calc(10px * var(--ui-scale)) rgba(120,90,160,0.18),
              inset 0 1px 0 rgba(255,255,255,0.9);
}

.db-day:hover  { transform: translateY(calc(-2px * var(--ui-scale))); }
.db-day:active { transform: scale(0.96); }

.db-day-cap {
  font-size: var(--fs-11);
  font-weight: 900;
  color: #9b6fc8;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

/* Награды ложатся строкой С ПЕРЕНОСОМ, а не колонкой: в квадрате одна награда
   встаёт по центру, две — друг под другом, а четыре (последний день круга) —
   сеткой 2×2, куда колонка не поместилась бы. */
.db-day-art {
  display: flex;
  flex: 1;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  align-content: center;
  gap: calc(2px * var(--ui-space)) calc(5px * var(--ui-space));
  width: 100%;
  min-height: 0;
}

/* Подарок занимает всю свободную высоту клетки: он здесь главный, а не значок
   рядом с числом. Ширину ограничивает сама клетка (она квадратная). */
.db-day-img {
  max-width: 100%;
  max-height: 100%;
  min-height: 0;
  object-fit: contain;
}

/* Запаска: файла подарка нет — рисуем сами награды (см. _artHtml в модалке).
   Видимость включает onerror, поэтому здесь только раскладка. */
.db-day-rewards {
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  align-content: center;
  gap: calc(2px * var(--ui-space)) calc(5px * var(--ui-space));
}

/* Награда дня: значок и число. Их на дне может быть и три (последняя ступень) —
   тогда они встают колонкой, поэтому значок мельче, чем в окошке подарка. */
.db-rw {
  display: inline-flex;
  align-items: center;
  gap: calc(3px * var(--ui-space));
}

.db-rw-ico {
  width: calc(26px * var(--ui-scale));
  height: calc(26px * var(--ui-scale));
  flex-shrink: 0;
}

.db-rw-val {
  font-size: var(--fs-13);
  font-weight: 900;
  color: #2a1a40;
  font-variant-numeric: tabular-nums;
}

/* День с тремя и более наградами: значки мельче, иначе 2×2 не влезает в квадрат.
   Ставит класс само окно — оно одно знает, сколько наград приехало из БД. */
.db-day--multi .db-rw-ico { width: calc(19px * var(--ui-scale)); height: calc(19px * var(--ui-scale)); }
.db-day--multi .db-rw-val { font-size: var(--fs-11); }
.db-day--multi .db-day-art { gap: calc(1px * var(--ui-space)) calc(3px * var(--ui-space)); }

/* Сегодняшний день: янтарная рамка, тёплый свет и та же дрожь, что у подарка,
   который можно забрать. Дрожат значки наград, а не рамка дня: прыгающая
   карточка в ряду сдвигала бы соседние. */
.db-day--today {
  border-color: #ffc861;
  background: linear-gradient(180deg, #fffdf5, #ffeecd);
  box-shadow: 0 calc(6px * var(--ui-scale)) calc(16px * var(--ui-scale)) rgba(224,150,32,0.32),
              inset 0 1px 0 rgba(255,255,255,0.95);
}

.db-day--today .db-day-cap { color: #e0850f; }

.db-day--today .db-day-art {
  animation: qb-chest-shake 1.6s ease-in-out infinite,
             qb-chest-glow  1.8s ease-in-out infinite;
}

/* Забранный день гаснет, но не исчезает: пройденная лестница должна читаться. */
.db-day--claimed { opacity: 0.62; }
.db-day--claimed .db-day-art { filter: saturate(0.55); }

/* Подсказка под сеткой: подарки закрыты, и о том, что их можно открыть нажатием,
   надо сказать словами — сама картинка об этом не говорит. */
.db-hint {
  font-size: var(--fs-11);
  font-weight: 700;
  color: rgba(42,26,64,0.5);
  text-align: center;
}

/* ── Подвал: кнопка «Забрать» или отсчёт до полуночи ── */
.db-foot {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(44px * var(--ui-scale));
  margin-top: calc(2px * var(--ui-space));
}

.db-claim {
  padding: calc(11px * var(--ui-space)) calc(38px * var(--ui-space));
  border: none;
  border-radius: 999px;
  cursor: pointer;
  background: linear-gradient(135deg, #ffb347, #e07020);
  color: #fff;
  font-size: var(--fs-17);
  font-weight: 900;
  letter-spacing: 0.03em;
  box-shadow: 0 calc(6px * var(--ui-scale)) calc(16px * var(--ui-scale)) rgba(224,112,32,0.48);
  transition: transform 0.12s, filter 0.15s;
}

.db-claim:hover    { transform: translateY(-1px); }
.db-claim:active   { transform: scale(0.95); }
.db-claim:disabled { opacity: 0.6; cursor: default; transform: none; }

.db-next {
  display: flex;
  align-items: baseline;
  gap: calc(8px * var(--ui-space));
  font-size: var(--fs-13);
  font-weight: 700;
  color: rgba(42,26,64,0.68);
}

.db-next-time {
  font-size: var(--fs-20);
  font-weight: 900;
  color: #7b3fbe;
  font-variant-numeric: tabular-nums;
}

/* Низкий экран (телефон в горизонтали): лестница ужимается, но остаётся в ряд —
   карточка дня теряет высоту, а не переносится, иначе окно уходит за край. */
@media (max-height: 449px) and (orientation: landscape) {
  .db-card { gap: calc(6px * var(--ui-space)); }
  .db-day  { padding: calc(5px * var(--ui-space)) calc(3px * var(--ui-space)); }
  /* Пояснение к правилу прячем — оно видно по самой лестнице. А вот сообщение о
     сгоревшей серии остаётся: без него обнулившаяся лестница читается как поломка. */
  .db-sub:not(.db-sub--burned) { display: none; }
  .db-hint { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .db-overlay, .db-card { transition: none; }
  .db-day--today .db-day-art { animation: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ЛОТОТРОН — страница автомата с шариками (ui/panels/LotteryPanel.js)
   ------------------------------------------------------------------------------
   Раскладка страницы — три колонки: часы слева, автомат посередине, пустая
   колонка справа. Пустая не для симметрии ради симметрии: без неё автомат встаёт
   посередине ТОГО, ЧТО ОСТАЛОСЬ от часов, то есть заметно правее центра экрана, —
   а он здесь главный предмет, по нему и нажимают.

   Шапка и кошелёк взяты у магазина (.sp2-topbar, .sp2-currency): страница платная,
   и баланс должен читаться там же, где игрок привык его видеть.
   ══════════════════════════════════════════════════════════════════════════════ */

.lottery-panel {
  padding: 0;
  gap: 0;
  overflow: hidden;
  justify-content: flex-start;
}
.lot-topbar {
  width: 100%;
  padding: calc(10px * var(--ui-space)) calc(26px * var(--ui-space))
           calc(10px * var(--ui-space)) calc(42px * var(--ui-space));
  box-sizing: border-box;
  position: relative;
}

/* Кошелёк стоит посередине ВСЕЙ шапки, а не посередине промежутка между
   заголовком и крестиком: заголовок «ЛОТОТРОН» шире крестика, и в общей строке
   плашки уезжали вправо — мимо автомата, который стоит ровно по центру экрана.
   Поэтому кошелёк вынут из потока и привязан к середине, а крестик прижат
   вправо своим margin. */
.lot-topbar .sp2-topbar-currencies {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  flex: 0 0 auto;
}
.lot-topbar .sp2-close-btn { margin-left: auto; }

.lot-stage {
  flex: 1;
  width: 100%;
  min-height: 0;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: calc(14px * var(--ui-space));
  padding: 0 calc(20px * var(--ui-space)) calc(10px * var(--ui-space));
  box-sizing: border-box;
}
.lot-side {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(6px * var(--ui-space));
  min-width: 0;
  /* Отступ от края экрана: вплотную к нему плашка читалась как приклеенная.
     Пустая колонка-противовес справа такая же по ширине (1fr), поэтому автомат
     остаётся ровно посередине. */
  padding-left: calc(22px * var(--ui-space));
}

/* ── Часы: когда обновится бесплатное кручение ─────────────────────────────── */
.lot-clock {
  display: flex;
  align-items: center;
  gap: calc(12px * var(--ui-space));
  padding: calc(9px * var(--ui-space)) calc(16px * var(--ui-space));
  background: linear-gradient(160deg, #ffffff, #f7edff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.28);
  border-radius: calc(18px * var(--ui-scale));
  box-shadow: 0 calc(3px * var(--ui-scale)) calc(10px * var(--ui-scale)) rgba(155,111,200,0.18);
}
/* Слово и время — две строки справа от часов. */
.lot-clock-text {
  display: flex;
  flex-direction: column;
  gap: calc(2px * var(--ui-space));
}
.lot-clock-cap {
  font-size: var(--fs-11-5);
  font-weight: 700;
  color: #8b7aa5;
}
.lot-clock-time {
  font-size: var(--fs-22);
  font-weight: 900;
  color: #7b3fbe;
  /* Моноширинные цифры: иначе строка отсчёта дёргается на каждой секунде. */
  font-variant-numeric: tabular-nums;
}
/* Часы игры — слева, ростом в обе строки: это не значок при подписи, а первая
   половина плашки. Значок общий (assets/rating/icon-timer.png) — тот же, что у
   срока заявки на дуэль и у конца распродажи. */
.lot-clock-ico {
  width: calc(52px * var(--ui-scale));
  height: calc(52px * var(--ui-scale));
  object-fit: contain;
  flex: 0 0 auto;
}

/* ── Середина: автомат, приз, кнопка ───────────────────────────────────────── */
.lot-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(8px * var(--ui-space));
  min-height: 0;
}

/* Автомат — это кнопка: по картинке и нажимают. Размер берём самым тесным из
   трёх ограничений, чтобы вместе с кнопкой и подсказкой он влезал и на 653×280
   (Fold в ландшафте), и на большом экране не разрастался. */
.lot-machine {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: min(calc(340px * var(--ui-scale)), 46vw, 54vh);
  height: min(calc(340px * var(--ui-scale)), 46vw, 54vh);
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  /* WebView подсвечивает нажатую кнопку своим прямоугольником — по всей её
     рамке, а рамка тут квадратная и заметно шире автомата (арт вписан в неё по
     высоте). Квадрат читался бы подложкой, которой у автомата нет. */
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.14s ease, filter 0.14s ease;
}
.lot-machine:hover  { transform: translateY(calc(-4px * var(--ui-scale))); }
.lot-machine:active { transform: scale(0.96); }
/* Пока летит запрос — автомат не нажимается: два нажатия подряд это два кручения. */
.lot-machine--busy { pointer-events: none; filter: saturate(0.75) brightness(1.03); }

.lot-machine-img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 calc(12px * var(--ui-scale)) calc(22px * var(--ui-scale)) rgba(42,26,64,0.35));
}

/* Прыжок автомата в ответ на нажатие — вместе с залпом конфетти. */
.lot-machine--pop { animation: lot-pop 0.5s ease; }
@keyframes lot-pop {
  0%   { transform: scale(1) rotate(0deg); }
  22%  { transform: scale(1.07) rotate(-2.5deg); }
  52%  { transform: scale(0.97) rotate(2.5deg); }
  78%  { transform: scale(1.02) rotate(-1deg); }
  100% { transform: scale(1) rotate(0deg); }
}

/* ── Автомат, нарисованный стилями ─────────────────────────────────────────────
   Показывается, только если арта нет на диске (onerror у картинки). Не украшение
   и не замена арту: страница просит нажать на автомат, и пустая рамка вместо него
   читалась бы как поломка. Шарики в куполе — повторяющиеся радиальные градиенты,
   отдельных узлов под них не заводим. */
.lot-machine-css {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  filter: drop-shadow(0 calc(10px * var(--ui-scale)) calc(18px * var(--ui-scale)) rgba(42,26,64,0.3));
}
.lot-css-dome {
  width: 74%;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  border: calc(3px * var(--ui-scale)) solid rgba(255,255,255,0.85);
  background:
    radial-gradient(circle at 30% 28%, #ffb3c7 0 14%, transparent 15%),
    radial-gradient(circle at 62% 22%, #caffbf 0 12%, transparent 13%),
    radial-gradient(circle at 44% 46%, #bdb2ff 0 15%, transparent 16%),
    radial-gradient(circle at 74% 52%, #ffd6a5 0 13%, transparent 14%),
    radial-gradient(circle at 26% 62%, #9bf6ff 0 14%, transparent 15%),
    radial-gradient(circle at 58% 74%, #ffc6ff 0 13%, transparent 14%),
    linear-gradient(160deg, rgba(255,255,255,0.75), rgba(255,255,255,0.35));
}
.lot-css-neck {
  width: 62%;
  height: 8%;
  margin-top: -4%;
  border-radius: calc(8px * var(--ui-scale));
  background: linear-gradient(180deg, #a8e6d8, #7fd0be);
}
.lot-css-base {
  width: 68%;
  height: 26%;
  border-radius: calc(10px * var(--ui-scale)) calc(10px * var(--ui-scale))
                 calc(22px * var(--ui-scale)) calc(22px * var(--ui-scale));
  background: linear-gradient(180deg, #ffb98a, #f79a5f);
}

/* ── Кнопка «Играть» с ценой ───────────────────────────────────────────────── */
.lot-play {
  display: inline-flex;
  align-items: center;
  gap: calc(10px * var(--ui-space));
  padding: calc(10px * var(--ui-space)) calc(30px * var(--ui-space));
  border: none;
  border-radius: 999px;
  cursor: pointer;
  background: linear-gradient(135deg, #ffb347, #e07020);
  color: #fff;
  font-size: var(--fs-17);
  font-weight: 900;
  letter-spacing: 0.03em;
  box-shadow: 0 calc(6px * var(--ui-scale)) calc(16px * var(--ui-scale)) rgba(224,112,32,0.48);
  transition: transform 0.12s, filter 0.15s;
}
.lot-play:hover:not(:disabled)  { filter: brightness(1.06); }
.lot-play:active:not(:disabled) { transform: scale(0.96); }
.lot-play:disabled {
  cursor: default;
  filter: grayscale(0.5);
  opacity: 0.75;
  box-shadow: none;
}
.lot-play-cap { line-height: 1; }
/* «Бесплатно» — та же леденцовая малина, что у плашки бесплатного входа в дуэлях:
   зелёный в гамме игры чужой и на оранжевой кнопке читался как чужая наклейка,
   а малина — дополнительный к оранжевому цвет, поэтому пилюля видна первой. */
.lot-play-free {
  padding: calc(2px * var(--ui-space)) calc(10px * var(--ui-space));
  border-radius: 999px;
  background: rgba(255,255,255,0.9);
  color: #c8226f;
  font-size: var(--fs-13);
  font-weight: 900;
}
.lot-play-price {
  display: inline-flex;
  align-items: center;
  gap: calc(5px * var(--ui-space));
  padding: calc(2px * var(--ui-space)) calc(10px * var(--ui-space));
  border-radius: 999px;
  background: rgba(255,255,255,0.9);
  color: #a8762a;
  font-size: var(--fs-14);
  font-weight: 900;
}
/* Не хватает драже: кнопка остаётся живой (нажатие должно СКАЗАТЬ, чего не
   хватает), но цена горит красным — отказ виден до нажатия. */
.lot-play-price--poor { color: #d8443c; }
.lot-play-coin {
  width: calc(17px * var(--ui-scale));
  height: calc(17px * var(--ui-scale));
  object-fit: contain;
}

/* Подсказка стоит НАД автоматом и написана неярко: она нужна один раз — понять,
   что картинка нажимается, — и спорить с самим автоматом за внимание не должна. */
.lot-hint {
  font-size: var(--fs-12-5);
  font-weight: 600;
  color: rgba(42,26,64,0.42);
  letter-spacing: 0.01em;
  text-align: center;
}

/* ── Конфетти (ui/lib/confetti.js) ─────────────────────────────────────────────
   Слой лежит ПОД картинкой автомата (z-index 0 против 1) и событий не ловит:
   бумажки вылетают из-за автомата, а не закрывают кнопку, по которой нажали.
   Разлёт каждой бумажки приезжает из скрипта переменными --cf-*, кадры при этом
   одни на всех — тридцать разных анимаций браузер считал бы тридцатью. */
.cf-layer {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: visible;
  pointer-events: none;
}
.cf-piece {
  position: absolute;
  left: 50%;
  /* Откуда хлопает — от слоя (--cf-y, его ставит confetti.js): у лототрона это
     стеклянный купол с шариками, а он выше середины кнопки. */
  top: var(--cf-y, 50%);
  /* Крупнее прежнего (было 12×16): бумажка должна читаться бумажкой и на
     телефоне, где залп мельче вместе с автоматом. Дальность разлёта живёт не
     здесь, а в ui/lib/confetti.js — она считается от ширины хозяина. */
  width: calc(15px * var(--ui-scale));
  height: calc(20px * var(--ui-scale));
  border-radius: calc(4px * var(--ui-scale));
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(5px * var(--ui-scale)) rgba(42,26,64,0.22);
  opacity: 0;
  animation: cf-fly 1.1s cubic-bezier(0.15, 0.6, 0.35, 1) var(--cf-delay, 0s) forwards;
}
@keyframes cf-fly {
  0%   { transform: translate(-50%, -50%) scale(0.4) rotate(0deg); opacity: 0; }
  12%  { opacity: 1; }
  100% {
    transform: translate(calc(-50% + var(--cf-dx, 0px)), calc(-50% + var(--cf-dy, 0px)))
               scale(1) rotate(var(--cf-rot, 0deg));
    opacity: 0;
  }
}

/* Тесный экран: РАСКЛАДКА ТА ЖЕ, ЧТО НА БОЛЬШОМ, — часы слева, автомат ровно
   посередине, кнопка под ним. Мельчают только размеры.
   Раньше здесь всё складывалось в одну колонку и плашка часов уезжала ПОД
   кнопку — на телефоне страница выглядела другой игрой. Высоту у автомата
   плашка не отнимает: она стоит в своей колонке сбоку, а не в стопке с ним.
   Это тот же порог «узкой адаптации», что у панели заданий. */
@media (max-width: 1100px), (max-height: 660px) and (orientation: landscape) {
  .lot-stage {
    /* minmax(0,…) вместо 1fr: колонке с плашкой разрешено ужаться, иначе на
       самом узком экране она распёрла бы сетку и уехала за край. */
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    gap: calc(8px * var(--ui-space));
    padding: 0 calc(10px * var(--ui-space)) calc(8px * var(--ui-space));
  }
  /* Отступ от края мельче вместе со всем остальным. */
  .lot-side { padding-left: calc(10px * var(--ui-space)); }

  /* ЗДЕСЬ РАЗМЕРЫ НАРОЧНО БЕЗ --ui-scale, В ЧИСТЫХ ПИКСЕЛЯХ.
     На телефоне в ландшафте --ui-scale равен 0.62–0.84, и общий множитель,
     который на планшете просто уплотняет вёрстку, здесь превращал подпись в
     8 px, а время на плашке — в 13 px: физически экран уже маленький, и
     уменьшать на нём ещё раз нечего. Этот блок и так работает только на
     тесных экранах, поэтому абсолютные размеры тут предсказуемы. */
  .lot-clock {
    gap: 10px;
    padding: 9px 15px;
    border-radius: 16px;
  }
  .lot-clock-ico  { width: 42px; height: 42px; }
  .lot-clock-cap  { font-size: calc(12.5px * var(--fs-scale)); }
  .lot-clock-time { font-size: calc(21px * var(--fs-scale)); }

  /* Автомат считаем от ОСТАТКА высоты, а не долей экрана: над ним шапка, под
     ним подсказка и кнопка, и на низком ландшафте (Fold — 280 px) доля в vh
     выдавила бы кнопку за край. 150px — это как раз шапка + подсказка +
     кнопка + отступы в их новых размерах. */
  .lot-machine {
    width: min(320px, 52vw, calc(100vh - 150px));
    height: min(320px, 52vw, calc(100vh - 150px));
  }

  .lot-play {
    gap: 10px;
    padding: 11px 30px;
    font-size: calc(19px * var(--fs-scale));
  }
  .lot-play-free  { font-size: calc(15px * var(--fs-scale)); padding: 3px 11px; }
  .lot-play-price { font-size: calc(15px * var(--fs-scale)); padding: 3px 11px; gap: 6px; }
  .lot-play-coin  { width: 19px; height: 19px; }

  /* Подсказку не прячем даже здесь: она объясняет, что автомат — это кнопка,
     и другой такой строки на странице больше нет. */
  .lot-hint { font-size: calc(13px * var(--fs-scale)); }
}

@media (prefers-reduced-motion: reduce) {
  .lot-machine--pop { animation: none; }
  .lot-prize--in .lot-prize-card { animation: none; }
  /* Конфетти не отменяем совсем — это ответ на нажатие, без него автомат
     кажется сломанным; но летит оно один раз и без кувырков. */
  .cf-piece { animation-duration: 0.6s; --cf-rot: 0deg; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ВЫИГРЫШ — окно поверх страницы (ui/modals/PrizeReveal.js)
   ------------------------------------------------------------------------------
   Тёмная подложка, золотой заголовок, карточка приза посреди экрана и подпись
   внизу. Тёмная она не для мрачности: выигрыш — единственное, что в этот миг
   должно быть видно, а пастельная страница за полупрозрачным белым продолжала бы
   спорить с карточкой. По той же причине карточка одна и крупная.

   Два цвета карточки делят призы на «деньги» и «вещи»: золотая — драже, опыт и
   жизнь, сиреневая — мармелад и бустеры. Это те же два цвета, которыми в игре
   разведены валюты.
   ══════════════════════════════════════════════════════════════════════════════ */

.pr-overlay {
  position: absolute;
  inset: 0;
  z-index: 90;               /* выше страницы (.screen — 20), ниже тостов (100) */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(18px * var(--ui-space));
  padding: calc(16px * var(--ui-space));
  box-sizing: border-box;
  /* Почти непрозрачная: сквозь более светлую подложку читались подписи страницы
     и спорили с заголовком. В этот миг на экране должна быть только награда. */
  background: rgba(28, 16, 46, 0.94);
  opacity: 0;
  transition: opacity 0.2s ease;
  cursor: pointer;           /* окно закрывается щелчком в любом месте */
  /* Фокус окно забирает себе (см. PrizeReveal), но рисовать вокруг подложки
     рамку браузеру незачем: она во весь экран, и рамка легла бы по его краю. */
  outline: none;
}
.pr-overlay--in { opacity: 1; }

.pr-title {
  font-size: var(--fs-28);
  font-weight: 900;
  letter-spacing: 0.02em;
  color: #ffd34d;
  text-shadow: 0 calc(3px * var(--ui-scale)) 0 rgba(120,70,0,0.55),
               0 calc(8px * var(--ui-scale)) calc(20px * var(--ui-scale)) rgba(255,180,40,0.35);
  text-align: center;
}

/* Гнездо карточки: держит её по середине остатка высоты. Конфетти здесь не
   летит — залп принадлежит автомату (.cf-layer в лототроне). */
.pr-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
}

.pr-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(10px * var(--ui-space));
  width: min(calc(250px * var(--ui-scale)), 46vw, 46vh);
  aspect-ratio: 1 / 1;
  padding: calc(18px * var(--ui-space));
  box-sizing: border-box;
  border-radius: calc(22px * var(--ui-scale));
  box-shadow: 0 calc(14px * var(--ui-scale)) calc(34px * var(--ui-scale)) rgba(0,0,0,0.45),
              inset 0 calc(2px * var(--ui-scale)) 0 rgba(255,255,255,0.55);
  transform: scale(0.6);
  opacity: 0;
}
.pr-overlay--in .pr-card {
  animation: pr-card-pop 0.5s cubic-bezier(0.2, 1.4, 0.4, 1) forwards;
}
@keyframes pr-card-pop {
  0%   { transform: scale(0.6) rotate(-6deg); opacity: 0; }
  60%  { transform: scale(1.06) rotate(2deg); opacity: 1; }
  100% { transform: scale(1) rotate(0deg); opacity: 1; }
}

.pr-card--gold  { background: linear-gradient(180deg, #ffe08a, #e8a13a); }
.pr-card--lilac { background: linear-gradient(180deg, #cdbcff, #8f74d8); }

.pr-card-ico {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 62%;
  height: 52%;
}
.pr-card-ico img {
  filter: drop-shadow(0 calc(6px * var(--ui-scale)) calc(12px * var(--ui-scale)) rgba(60,30,0,0.35));
}
.pr-card-val {
  font-size: var(--fs-20);
  font-weight: 900;
  color: #ffffff;
  text-align: center;
  text-shadow: 0 calc(2px * var(--ui-scale)) calc(4px * var(--ui-scale)) rgba(60,30,0,0.5);
}

/* Приз, который придёт письмом (фантик, подарок от игры). Строка стоит между
   карточкой и подписью «нажмите, чтобы закрыть» и заметно ярче её: это не
   пояснение к окну, а часть самой награды — где её забирать. */
.pr-mail {
  font-size: var(--fs-15);
  font-weight: 800;
  color: #ffe08a;
  text-align: center;
  text-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(60,30,0,0.55);
}

.pr-hint {
  font-size: var(--fs-13);
  font-weight: 700;
  color: rgba(255,255,255,0.62);
  text-align: center;
}

/* Тесный экран. Размеры здесь, как и на самой странице лототрона, НАРОЧНО без
   --ui-scale: на телефоне он равен 0.62–0.84, и общий множитель делал из
   заголовка 14 px, а из подписи на карточке — 11 px. Экран и так маленький,
   уменьшать на нём второй раз нечего.
   Окно обязано влезать целиком — прокрутки у него нет и быть не должно, — но
   держит это не уменьшение всего подряд, а высота карточки: она считается от
   ОСТАТКА (100vh минус заголовок, подпись, строка про письмо и отступы), а
   карточка квадратная, поэтому та же величина годится и в ширину. */
@media (max-width: 1100px), (max-height: 660px) and (orientation: landscape) {
  .pr-overlay {
    gap: 12px;
    padding: 12px;
  }
  .pr-title { font-size: calc(22px * var(--fs-scale)); }
  /* 145px — это заголовок + подпись + строка «письмо уже в почте» + отступы. */
  .pr-card { width: min(250px, 46vw, calc(100vh - 145px)); }
  .pr-card-val { font-size: calc(18px * var(--fs-scale)); }
  .pr-mail { font-size: calc(15px * var(--fs-scale)); }
  .pr-hint { font-size: calc(13px * var(--fs-scale)); }
}

@media (prefers-reduced-motion: reduce) {
  .pr-overlay--in .pr-card { animation: none; transform: scale(1); opacity: 1; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ДРУГИЕ ПРОЕКТЫ — страница с рекламой соседних игр автора
   (ui/panels/ProjectsPanel.js)
   ------------------------------------------------------------------------------
   Список карточек в столбик, карточка — «арт слева, слово справа». Ландшафт даёт
   ширину, а не высоту: в ряд помещается и картинка, и описание, и кнопка, — тогда
   как плитками в сетке (как в магазине) описание пришлось бы обрезать, а оно
   здесь и есть весь смысл страницы.

   Содержимое карточки целиком из БД (таблица other_projects): заголовок, текст,
   арт, надпись на кнопке и лента-ярлычок. Поэтому все размеры считаются от
   содержимого, а не от числа проектов: их может быть один, а может быть десяток.

   КАРТИНКА — ТА ЖЕ КНОПКА, и это должно быть ВИДНО: у неё курсор-рука, наведение
   приподнимает карточку и подсвечивает кнопку. Иначе арт читается как украшение,
   и половина нажатий уходит в пустоту.

   Шапка взята у магазина (.sp2-topbar): страница открывается из меню и
   закрывается тем же крестиком, что и все остальные.
   ══════════════════════════════════════════════════════════════════════════════ */

.projects-panel {
  padding: 0;
  gap: 0;
  overflow: hidden;
  justify-content: flex-start;
}

.proj-topbar {
  width: 100%;
  padding: calc(10px * var(--ui-space)) calc(26px * var(--ui-space))
           calc(10px * var(--ui-space)) calc(42px * var(--ui-space));
  box-sizing: border-box;
}
/* Заголовок слева, крестик — прижат к правому краю: между ними на этой странице
   ничего нет (кошелька здесь не показывают — покупать тут нечего). */
.proj-topbar .sp2-close-btn { margin-left: auto; }

.proj-note {
  margin-bottom: calc(6px * var(--ui-space));
}

/* Лента карточек. Прокрутка вертикальная и только здесь: шапка и подсказка
   остаются на месте, уезжает список.

   ПОЛОСА ПРОКРУТКИ — СВОЯ, А НЕ БРАУЗЕРНАЯ. Серый системный ползунок посреди
   пастельной страницы читается как чужая деталь, поэтому он одет так же, как в
   профиле и на карточке входа: прозрачная сиреневая канавка и ползунок-капсула
   сиренево-розовым градиентом. Одеваются обе половины мира — `scrollbar-*` для
   Firefox и ::-webkit-scrollbar для остальных: в игре есть и то, и другое (в
   оболочке Android это WebView на Chromium).

   Курсор тянет список сам (ui/shared/dragScroll.js) — отсюда `grab`/`grabbing`;
   палец прокручивает нативно, ему хватает touch-action: pan-y. */
.proj-list {
  flex: 1;
  width: 100%;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;   /* докрутили до конца — страница за спиной не едет */
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(14px * var(--ui-space));
  padding: calc(6px * var(--ui-space)) calc(22px * var(--ui-space))
           calc(18px * var(--ui-space));
  box-sizing: border-box;
  touch-action: pan-y;
  cursor: grab;
  scrollbar-width: thin;
  scrollbar-color: #d2bcff rgba(155,111,200,0.12);
}
.proj-list--drag { cursor: grabbing; }

.proj-list::-webkit-scrollbar {
  width: calc(10px * var(--ui-scale));
}
.proj-list::-webkit-scrollbar-track {
  background: rgba(155,111,200,0.12);
  border-radius: 999px;
  /* Канавка не доходит до самых краёв — иначе она упирается в шапку и в низ
     экрана и читается как рамка страницы, а не как полоса списка. */
  margin: calc(6px * var(--ui-scale)) 0;
}
.proj-list::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, #d9c8ff, #ffd6eb);
  border-radius: 999px;
  /* Прозрачная рамка + background-clip дают ползунку поля внутри канавки:
     капсула становится уже полосы, как в профиле. */
  border: calc(2px * var(--ui-scale)) solid transparent;
  background-clip: padding-box;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.55);
}
.proj-list::-webkit-scrollbar-thumb:hover {
  filter: brightness(1.06);
}

.proj-empty {
  margin: auto;
  font-size: var(--fs-15);
  font-weight: 700;
  color: #7b3fbe;
  text-align: center;
  opacity: 0.75;
}

/* ── Карточка проекта ─────────────────────────────────────────────────────── */
.proj-card {
  display: flex;
  align-items: stretch;
  gap: calc(16px * var(--ui-space));
  width: min(100%, calc(760px * var(--ui-scale)));
  padding: calc(12px * var(--ui-space));
  box-sizing: border-box;
  background: linear-gradient(160deg, #ffffff, #f7edff);
  border: calc(2px * var(--ui-scale)) solid rgba(155,111,200,0.28);
  border-radius: calc(22px * var(--ui-scale));
  box-shadow: 0 calc(4px * var(--ui-scale)) calc(14px * var(--ui-scale)) rgba(155,111,200,0.18);
  /* Карточка не ужимается по высоте: в низком ландшафте описание иначе
     схлопнулось бы в полоску, а прокрутка у списка для того и есть. */
  flex-shrink: 0;
  transition: transform 0.14s, box-shadow 0.14s;
}
.proj-card:hover {
  transform: translateY(calc(-2px * var(--ui-scale)));
  box-shadow: 0 calc(8px * var(--ui-scale)) calc(20px * var(--ui-scale)) rgba(155,111,200,0.3);
}

/* Арт — первая из двух кнопок карточки (вторая внизу, справа). */
.proj-card-art {
  position: relative;
  display: block;
  flex-shrink: 0;
  width: calc(180px * var(--ui-scale));
  aspect-ratio: 1 / 1;
  border-radius: calc(16px * var(--ui-scale));
  overflow: hidden;
  background: rgba(155,111,200,0.12);
  cursor: pointer;
  transition: transform 0.14s, filter 0.14s;
  filter: drop-shadow(0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(155,111,200,0.35));
}
.proj-card-art:hover  { transform: scale(1.03); }
.proj-card-art:active { transform: scale(0.97); }
/* Адрес в базе не годится для ссылки (пустой или не http) — арт остаётся
   картинкой: ни руки-курсора, ни отклика на наведение, обещать нечего. */
.proj-card-art--off { cursor: default; }
.proj-card-art--off:hover { transform: none; }

.proj-card-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Строка в базе есть, а файла арта нет — вместо картинки ровная плашка, чтобы
   карточка не разъезжалась. */
.proj-card-noart {
  display: block;
  width: 100%;
  height: 100%;
}

/* Лента-ярлычок («Новинка», «Бета») — текст из БД, поэтому ширина по содержимому. */
.proj-card-badge {
  position: absolute;
  top: calc(8px * var(--ui-scale));
  left: calc(8px * var(--ui-scale));
  max-width: calc(100% - 16px * var(--ui-scale));
  padding: calc(3px * var(--ui-space)) calc(10px * var(--ui-space));
  border-radius: 999px;
  background: linear-gradient(135deg, #ffb347, #e07020);
  color: #fff;
  font-size: var(--fs-11-5);
  font-weight: 900;
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  box-shadow: 0 calc(2px * var(--ui-scale)) calc(6px * var(--ui-scale)) rgba(224,112,32,0.45);
}

.proj-card-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: calc(6px * var(--ui-space));
  padding: calc(4px * var(--ui-space)) 0;
}

.proj-card-title {
  margin: 0;
  font-size: var(--fs-19);
  font-weight: 900;
  color: #2a1a40;
  line-height: 1.2;
}

.proj-card-text {
  margin: 0;
  font-size: var(--fs-13);
  font-weight: 600;
  color: #55407a;
  line-height: 1.4;
}

/* Кнопка внизу карточки — та же оранжевая капсула, что «ИГРАТЬ» в лототроне:
   в игре это цвет действия, которое уводит игрока дальше. margin-top:auto
   прижимает её к низу, поэтому у карточек с описанием и без него кнопки стоят
   на одной линии. */
.proj-card-btn {
  align-self: flex-start;
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: calc(8px * var(--ui-space)) calc(26px * var(--ui-space));
  border-radius: 999px;
  background: linear-gradient(135deg, #ffb347, #e07020);
  color: #fff;
  font-size: var(--fs-15);
  font-weight: 900;
  letter-spacing: 0.03em;
  text-decoration: none;
  cursor: pointer;
  box-shadow: 0 calc(4px * var(--ui-scale)) calc(12px * var(--ui-scale)) rgba(224,112,32,0.45);
  transition: transform 0.12s, filter 0.15s;
}
.proj-card-btn:hover  { transform: scale(1.05); filter: brightness(1.06); }
.proj-card-btn:active { transform: scale(0.96); }
/* Без годного адреса кнопка ничего не обещает: серая и без отклика. */
.proj-card-btn--off {
  background: linear-gradient(135deg, #cfc4e0, #a99cc0);
  box-shadow: none;
  cursor: default;
}
.proj-card-btn--off:hover  { transform: none; filter: none; }
.proj-card-btn--off:active { transform: none; }

/* Тесный экран — тот же компактный брейкпоинт, что у остальных страниц игры.
   Арт ужимается вдвое, отступы поджимаются: карточка обязана оставаться строкой,
   иначе на телефоне в ландшафте в список поместится ровно одна. */
@media (max-width: 1100px), (max-height: 660px) and (orientation: landscape) {
  .proj-topbar {
    padding: calc(6px * var(--ui-space)) calc(14px * var(--ui-space));
  }
  .proj-list {
    gap: calc(10px * var(--ui-space));
    padding: calc(4px * var(--ui-space)) calc(12px * var(--ui-space))
             calc(12px * var(--ui-space));
  }
  .proj-card {
    gap: calc(12px * var(--ui-space));
    padding: calc(9px * var(--ui-space));
    border-radius: calc(18px * var(--ui-scale));
  }
  .proj-card-art { width: calc(112px * var(--ui-scale)); }
  .proj-card-btn { padding: calc(6px * var(--ui-space)) calc(18px * var(--ui-space)); }
  /* Полоса потоньше: на телефоне каждый пиксель ширины уходит карточке. */
  .proj-list::-webkit-scrollbar { width: calc(7px * var(--ui-scale)); }
}
