/* FROZEN — компоненты витрины. Токены в brand.css. */
*{box-sizing:border-box}

/* ── ШКАЛА НАБОРА, СКРУГЛЕНИЙ И ПОВЕРХНОСТЕЙ ───────────────────────────
   Замер живого DOM давал семнадцать кеглей, девять из них между 10.5 и 14.5.
   Шаг в полпикселя не читается как иерархия — он только гарантирует, что
   ничто ни с чем не выровняется. Здесь их семь, и у каждого своя работа.

   Объявлены ЗДЕСЬ, а не в brand.css, и это не прихоть: палитру магазина
   сервер вклеивает в голову страницы ПОСЛЕ файлов стилей, и одноимённый
   токен из brands/<магазин>/brand.json перебил бы шкалу молча. Имена новые —
   в палитрах заказчиков их нет, и перебивать нечего. */
:root{
  --fs-cap:11px;    /* ярлык, единица, микроподпись — обычно в верхнем регистре */
  --fs-sm:12px;     /* подпись под строкой, второстепенное мелкое */
  --fs-md:13px;     /* второстепенный текст и пункты списка */
  --fs-base:15px;   /* основной текст, кнопки, цена в карточке */
  --fs-lg:18px;     /* заголовок раздела, крупное число */
  --fs-xl:22px;     /* заголовок экрана */
  --fs-xxl:28px;    /* цена на кассе и выдача: крупнее заголовка только они */
  /* ПОЛЕ ВВОДА — ровно 16, и это не ступень шкалы, а требование Safari: в
     поле мельче шестнадцати айфон приближает страницу, а вернуть масштаб
     мини-апп не даёт. */
  --fs-field:16px;
  --lh-tight:1.2;   /* заголовки и подписи в одну-две строки */
  --lh-text:1.5;    /* всё, что читают строками */
  /* Скруглений в живом DOM было десять, и одно понятие «карточка» имело
     радиус 13 на каталоге, 20 на главной и 12 в корзине. Здесь три. */
  --r-card:12px;    /* карточка, панель, лист, поле */
  --r-in:10px;      /* кнопка и значок ВНУТРИ карточки */
  --r-pill:999px;   /* пилюля */
  /* Поверхности. У карточки стояло `0 10px 24px -14px`: растяжение почти
     гасило тень, и карточка читалась заливкой, а не предметом над фоном. */
  --sh-card:0 8px 20px -12px rgba(0,0,0,.6);
  --sh-lift:0 14px 30px -14px rgba(0,0,0,.66);
  /* Фокус — не ошибка. Сплошная краска остаётся ошибке, фокусу достаётся та
     же краска вполсилы плюс свечение: «я здесь печатаю» и «здесь ошибка»
     обязаны различаться с одного взгляда. */
  --fo-line:color-mix(in oklab, var(--lamp) 45%, transparent);
  --fo-ring:0 0 0 3px color-mix(in oklab, var(--lamp) 18%, transparent);
}

html{-webkit-text-size-adjust:100%; scroll-behavior:smooth}
body{margin:0; color:var(--cream); font-family:var(--font); font-size:var(--fs-base);
  line-height:var(--lh-text); -webkit-font-smoothing:antialiased; min-height:100vh}
.hidden{display:none!important}
button{font:inherit; color:inherit; border:0; background:none; cursor:pointer}
a{color:inherit; text-decoration:none}
img{display:block}

/* Кольцо фокуса одно на весь сайт: клавиатурному человеку должно быть видно,
   мышиному — не мешать. */
button,.ore,.act,a{-webkit-tap-highlight-color:transparent; touch-action:manipulation;
  -webkit-user-select:none; user-select:none}
:focus-visible{outline:2px solid var(--fo-line); outline-offset:2px;
  border-radius:var(--r-in)}
:focus:not(:focus-visible){outline:none}

/* Страховка на весь сайт: svg без явных размеров браузер разворачивает
   в 300×150 и рвёт вёрстку. Один раз здесь — и эта ошибка больше не повторится. */
svg{width:1em; height:1em}
.ic{width:17px; height:17px; flex:none}
.ic-lg{width:30px; height:30px}

/* ── шапка ───────────────────────────────────────────────────────────── */
.top{position:sticky; top:0; z-index:40; display:flex; align-items:center; gap:14px;
  padding:13px 22px; background:color-mix(in oklab, var(--deep) 72%, transparent);
  backdrop-filter:blur(24px) saturate(180%); -webkit-backdrop-filter:blur(24px) saturate(180%)}
/* не линейка снизу, а растворение — граница чувствуется, но не режет */
.top::after{content:""; position:absolute; left:0; right:0; bottom:-20px; height:20px;
  background:linear-gradient(180deg, color-mix(in oklab, var(--deep) 55%, transparent),
    transparent); pointer-events:none}
.logo{display:flex; align-items:center; gap:10px; color:var(--lamp-hi);
  transition:color var(--t-hover) ease, transform var(--t-press) var(--ease-out)}
.logo b{font-size:var(--fs-base); font-weight:700; letter-spacing:.22em; text-transform:uppercase;
  color:var(--cream)}
.logo:active{transform:scale(.98)}
@media (hover:hover) and (pointer:fine){ .logo:hover{color:var(--lamp)} }
.top .sp{flex:1}
.top-say{display:flex; align-items:center; gap:8px; font-size:var(--fs-sm); color:var(--sand-dim)}
.top-say .ic{opacity:.7}
@media (max-width:620px){ .top-say span{display:none} }

/* ── забой: полоса породы со светом лампы ────────────────────────────── */
/* Шапка — отдельная сцена под гузлика. Собственный непрозрачный фон:
   фотография шахты остаётся ниже, на витрине, и сюда не заходит. */
.face{position:relative; z-index:1;
  /* Низ шапки полупрозрачный: фотография шахты проступает снизу постепенно,
     и граница с витриной растворяется. Раньше здесь был ровный обрез — шапка
     обрывалась о контент линией. */
  background:
    radial-gradient(72% 116% at 62% -14%,
    color-mix(in oklab, var(--lamp) 16%, transparent) 0%, transparent 54%),
    linear-gradient(180deg, var(--rock) 0%, var(--deep) 30%,
    color-mix(in oklab, var(--rock) 94%, transparent) 56%,
      color-mix(in oklab, var(--deep) 78%, transparent) 76%,
      color-mix(in oklab, var(--deep) 38%, transparent) 92%,
      color-mix(in oklab, var(--deep) 0%, transparent) 100%)}

/* Угли во всю ширину: полоса склеена из куска и его зеркала, поэтому
   повторяется без стыков. Тянем её по нижнему краю — гузлик садится
   на неё, а не висит рядом со своей отдельной кучкой. */
.face::before{
  content:""; position:absolute; left:0; right:0; bottom:-64px; height:196px; z-index:0;
  background:url("img/embers-band.jpg?v=c955c4a7") repeat-x bottom 64px center / auto 112px;
  opacity:.72; pointer-events:none;
  /* Растворение ДОЛГОЕ и в три ступени. Короткая маска давала горизонт:
     силуэты углей обрывались на одной высоте, и шапка читалась поделённой
     пополам. Теперь верх грядки почти не виден и набирает плотность
     постепенно — линии не остаётся. */
  -webkit-mask-image:linear-gradient(180deg, transparent 0%, rgba(0,0,0,.12) 30%,
    rgba(0,0,0,.48) 52%, rgba(0,0,0,.9) 70%, #000 78%, rgba(0,0,0,.5) 92%, transparent 100%);
  mask-image:linear-gradient(180deg, transparent 0%, rgba(0,0,0,.12) 30%,
    rgba(0,0,0,.48) 52%, rgba(0,0,0,.9) 70%, #000 78%, rgba(0,0,0,.5) 92%, transparent 100%)}

/* Второй слой той же полосы, крупнее и тише: даже длинный период всё равно
   ловится глазом, а два ритма друг друга сбивают. */
.face-embers{position:absolute; left:0; right:0; bottom:-64px; height:250px; z-index:0;
  pointer-events:none; opacity:.2; mix-blend-mode:screen; filter:blur(4px);
  background:url("img/embers-band.jpg?v=c955c4a7") repeat-x bottom 64px left -180px / auto 165px;
  -webkit-mask-image:linear-gradient(180deg, transparent 0%, rgba(0,0,0,.26) 44%,
    #000 76%, rgba(0,0,0,.4) 94%, transparent 100%);
  mask-image:linear-gradient(180deg, transparent 0%, rgba(0,0,0,.26) 44%,
    #000 76%, rgba(0,0,0,.4) 94%, transparent 100%)}

/* Жар от углей поднимается в шапку и гаснет к тексту. */
.face::after{
  /* Тепло идёт ОДНИМ непрерывным нарастанием от самого верха шапки и гаснет
     уже на витрине. Ни одной точки, где «начинается» — поэтому и делить
     шапку пополам становится нечему. */
  content:""; position:absolute; left:0; right:0; top:0; bottom:-70px; z-index:0;
  pointer-events:none;
  background:linear-gradient(180deg,
    color-mix(in oklab, var(--zhar) 0%, transparent) 0%,
    color-mix(in oklab, var(--zhar) 1.8%, transparent) 18%,
    color-mix(in oklab, var(--zhar) 4.5%, transparent) 34%,
    color-mix(in oklab, var(--zhar) 8.5%, transparent) 48%,
    color-mix(in oklab, var(--zhar) 13%, transparent) 62%,
    color-mix(in oklab, var(--zhar) 17%, transparent) 74%,
    color-mix(in oklab, var(--zhar) 19%, transparent) 84%,
    color-mix(in oklab, var(--zhar) 11%, transparent) 93%, transparent 100%)}
.face-in{position:relative; z-index:1; max-width:1140px; margin:0 auto;
  padding:56px 22px 96px; display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,360px); gap:20px; align-items:center}
.face-text{max-width:600px}

.eyebrow{display:inline-flex; align-items:center; gap:8px; margin-bottom:16px;
  font-size:var(--fs-sm); font-weight:600; letter-spacing:.17em; text-transform:uppercase;
  color:var(--lamp)}
/* крупный кегль: трекинг отрицательный, интерлиньяж тесный — иначе разъезжается */
.face h1{margin:0 0 12px; font-size:clamp(32px,5.6vw,52px); line-height:var(--lh-tight);
  letter-spacing:-.035em; font-weight:800}
.gild{background:linear-gradient(120deg,var(--lamp-hi) 0%, var(--lamp) 46%, var(--lamp-lo) 100%);
  -webkit-background-clip:text; background-clip:text; color:transparent}
.face p{margin:0; color:var(--sand); font-size:var(--fs-lg); max-width:44ch; line-height:var(--lh-text)}

.vows{display:flex; flex-wrap:wrap; gap:10px; list-style:none; margin:26px 0 0; padding:0}
.vows li{display:flex; align-items:center; gap:10px; padding:10px 14px 10px 12px;
  border-radius:var(--r-card); border:1px solid color-mix(in oklab, var(--seam) 90%, transparent);
  background:color-mix(in oklab, var(--rock) 55%, transparent); backdrop-filter:blur(8px)}
.vows .ic{color:var(--lamp); opacity:.85}
.vows b{display:block; font-size:var(--fs-md); font-weight:600}
.vows span{display:block; font-size:var(--fs-sm); color:var(--sand-dim)}
/* Гузлик на груде углей и золота. У картинки собственная прозрачность
   (scripts/cutout.py), поэтому ни масок, ни подгонки яркости больше нет:
   раньше ими прятали прямоугольный фон кадра, а прятать стало нечего.
   Осталась тень — она сажает его на породу. */
.face-guzlik{position:relative; z-index:2; width:100%; height:auto; justify-self:end;
  /* садим его НА полосу углей: низ картинки должен уходить в неё, а не
     заканчиваться в воздухе */
  margin-bottom:-38px;
  filter:drop-shadow(0 18px 30px rgba(0,0,0,.7))}

@media (max-width:860px){
  .face-in{grid-template-columns:1fr; padding:36px 18px 34px}
  .face-guzlik{max-width:250px; justify-self:end; margin:0 -10px -34px 0}
  .face-glow{width:64%; height:56%}
}

/* ── пол шахты ───────────────────────────────────────────────────────── */
.wrap{max-width:1140px; margin:0 auto; padding:74px 22px 76px}
.floor{display:grid; grid-template-columns:1fr 330px; gap:26px; align-items:start}
/* Колонкам РАЗРЕШЕНО быть уже своего содержимого. Без этого колонка 1fr
   упирается в неделимую ширину того, что внутри, и на телефоне разносит
   страницу вбок: полоса разделов прокручивается сама (overflow-x:auto),
   но её содержимое всё равно считается нижним пределом колонки, и <main>
   раздувался до 384 пикселей в колонке шириной 331. Ширину экрана это
   не меняет нигде, где содержимое и так влезает, — то есть на десктопе. */
.floor > *{min-width:0}
@media (max-width:940px){ .floor{grid-template-columns:1fr} }

.seam-title{display:flex; align-items:center; gap:9px; margin:0 0 15px;
  font-size:var(--fs-sm); font-weight:600; letter-spacing:.15em; text-transform:uppercase;
  color:var(--sand-dim)}
.seam-title .ic{width:15px;height:15px;color:var(--lamp-lo)}
.seam-title em{font-style:normal; color:var(--seam-2); letter-spacing:0; font-size:var(--fs-sm)}

/* ── номиналы ────────────────────────────────────────────────────────── */
.grid{position:relative; display:grid;
  grid-template-columns:repeat(auto-fill,minmax(160px,1fr)); gap:11px;
  /* Слой света шире сетки, чтобы свечение не обрезалось у края. Насколько
     шире — держим ОДНИМ числом: координаты приходят от левого верхнего угла
     сетки, а рисуются внутри слоя, и без этой поправки пятно уезжает
     от курсора ровно на величину припуска. */
  --bleed:34px}
/* Координаты света объявляем через @property — тогда браузер умеет их
   ПЛАВНО менять сам. Раньше плавность считал JS в requestAnimationFrame,
   и на вкладке без фокуса кадры не приходили вовсе: свет замирал. */
@property --mx{syntax:"<length>"; inherits:true; initial-value:-999px}
@property --my{syntax:"<length>"; inherits:true; initial-value:-999px}

/* Фонарь шахтёра. Слой ОДИН на всю сетку, а не по карточке: один композитный
   слой вместо дюжины, и карточки перестают быть плитками — по ним идёт свет.
   Пятно узкое и яркое: широкое и тусклое читается как подсветка фона,
   а узкое — как луч в руке. Отставание в 110 мс даёт лампе вес. */
.grid::before{content:""; position:absolute; inset:calc(-1 * var(--bleed)); z-index:2;
  pointer-events:none; opacity:0; mix-blend-mode:screen;
  /* Размытие снимает резкую кромку: у лампы в шахте свет мягкий, с ореолом,
     а не пятно от лазерной указки. Радиусы при этом широкие — иначе после
     размытия от пятна ничего не остаётся. */
  filter:blur(26px);
  transition:opacity 240ms var(--ease-out), --mx 110ms linear, --my 110ms linear;
  background:
    radial-gradient(96px 96px at calc(var(--mx) + var(--bleed)) calc(var(--my) + var(--bleed)),
      color-mix(in oklab, var(--lamp-top) 40%, transparent) 0%,
      color-mix(in oklab, var(--lamp-hi) 20%, transparent) 50%, transparent 78%),
    radial-gradient(220px 220px at calc(var(--mx) + var(--bleed)) calc(var(--my) + var(--bleed)),
      color-mix(in oklab, var(--lamp) 15%, transparent) 0%,
      color-mix(in oklab, var(--lamp) 5%, transparent) 46%, transparent 74%)}
@media (hover:hover) and (pointer:fine){ .grid:hover::before{opacity:1} }
@media (prefers-reduced-motion:reduce){ .grid::before{display:none} }
/* Телефонная раскладка сетки стояла ЗДЕСЬ и не работала: ниже по файлу, в
   разделе «три в ряд», ту же .grid переписывали без медиазапроса, и обычное
   правило перебивало этот @media — вес у них одинаковый, а побеждает
   последнее. Правило переехало туда, где его уже никто не перебивает; см.
   «три в ряд». Здесь оставлена только пометка, чтобы его снова сюда
   не вернули. */

.ore{position:relative; text-align:left; padding:17px 15px 14px; border-radius:var(--r-card);
  border:1px solid var(--seam); overflow:hidden;
  background:linear-gradient(168deg, var(--stone) 0%, var(--stone-deep) 100%);
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--lamp-hi) 8%, transparent);
  font-variant-numeric:tabular-nums;
  /* Появление — по translate, нажатие — по scale. Разные свойства намеренно:
     animation с forwards держит своё свойство навсегда и перебила бы :active,
     и карточка перестала бы отвечать на палец. */
  transition:scale var(--t-press) var(--ease-out), border-color 200ms var(--ease-out);
  opacity:0; translate:0 8px;
  animation:rise 260ms var(--ease-out) forwards}
@keyframes rise{to{opacity:1; translate:0 0}}
/* самоцвет в породе: слабый блик из угла, разгорается под курсором */
.ore::before{content:""; position:absolute; inset:-1px; pointer-events:none; opacity:0;
  background:radial-gradient(70% 90% at 88% 6%,
    color-mix(in oklab, var(--lamp) 16%, transparent), transparent 62%);
  transition:opacity var(--t-hover) ease}
.ore:not(.spent):active{scale:.972; transition-duration:60ms}
.ore::after{content:""; position:absolute; inset:-1px; border-radius:inherit;
  pointer-events:none; opacity:0; transition:opacity 200ms var(--ease-out);
  box-shadow:0 0 0 1px color-mix(in oklab, var(--lamp) 10%, transparent),
    0 16px 36px -24px color-mix(in oklab, var(--lamp) 60%, transparent)}
@media (hover:hover) and (pointer:fine){
  .ore:not(.spent):hover::after{opacity:1}
  .ore:not(.spent):hover::before{opacity:1}
}
/* Выбранный номинал загорается изнутри, а не обводится маркером: одно кольцо
   вместо двух полупрозрачных встык, и порода отзывается движением. */
.ore.picked{border-color:transparent; outline:1px solid var(--lamp-lo); outline-offset:-1px;
  background:linear-gradient(168deg,var(--stone-2) 0%,var(--rock) 100%);
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--lamp-hi) 18%, transparent),
    0 16px 40px -24px color-mix(in oklab, var(--lamp) 50%, transparent);
  translate:0 -2px}
.ore.picked::before{opacity:1}
/* Прозрачность на тёмном фоне не приглушает, а превращает в грязь —
   гасим цветом и насыщенностью, текст остаётся читаемым. */
.ore.spent{opacity:1; cursor:default; background:var(--deep);
  border-color:color-mix(in oklab, var(--seam) 55%, transparent); filter:saturate(.2)}
.ore.spent .qty b,.ore.spent .cost{color:var(--sand-dim)}


.ore .qty{position:relative; display:flex; align-items:baseline; gap:5px; letter-spacing:-.025em}
.ore .qty b{font-size:var(--fs-xxl); font-weight:800; line-height:1; letter-spacing:-.03em}
.ore .qty u{text-decoration:none; font-size:var(--fs-sm); font-weight:700; color:var(--lamp);
  letter-spacing:.08em}
.ore .cost{position:relative; margin-top:12px; font-size:var(--fs-base); font-weight:500;
  color:var(--sand)}
.ore.picked .cost{color:var(--cream)}
/* Ярлык живёт СТРОКОЙ над номиналом, а не поверх него: наложение всегда
   рано или поздно сталкивается с текстом на узкой карточке. Строка есть
   всегда, даже пустая, — иначе карточки в ряду разной высоты. */
.ore .tagline{position:relative; height:17px; margin-bottom:9px}
.ore .mark,.ore .gone{display:inline-flex; align-items:center; gap:4px;
  padding:3px 7px; border-radius:var(--r-in); font-size:var(--fs-cap); font-weight:700;
  letter-spacing:.07em; text-transform:uppercase; white-space:nowrap}
/* Грань самоцвета: резкий перелом посередине вместо ровной заливки.
   Читается даже на 9 пикселях и не стоит ни одного лишнего кадра. */
.ore .mark{color:var(--on-lamp);
  background:linear-gradient(140deg,var(--lamp-top) 0%, var(--lamp-hi) 46%, var(--lamp-mid) 47%, var(--lamp) 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.5),
    0 3px 8px -3px color-mix(in oklab, var(--lamp) 70%, transparent)}
.ore .mark .ic{width:9px; height:9px}
.ore .gone{background:color-mix(in oklab, var(--seam) 90%, transparent); color:var(--sand-dim)}

/* ── вагонетка ───────────────────────────────────────────────────────── */
.cart{position:sticky; top:86px}
.panel{border-radius:var(--r-card); border:1px solid var(--seam); overflow:hidden;
  background:linear-gradient(180deg, color-mix(in oklab, var(--stone) 90%, transparent) 0%,
    color-mix(in oklab, var(--rock) 95%, transparent) 100%);
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--lamp-hi) 8%, transparent),
    0 1px 2px rgba(0,0,0,.5),
             0 22px 48px -32px #000}
.panel-top{position:relative; height:104px; overflow:hidden}
.panel-top img{width:100%; height:100%; object-fit:cover; object-position:52% 42%;
  opacity:.62}
.panel-top::after{content:""; position:absolute; inset:0;
  background:linear-gradient(180deg, color-mix(in oklab, var(--rock) 15%, transparent) 0%,
    color-mix(in oklab, var(--rock) 98%, transparent) 92%)}
.panel-top-in{position:absolute; left:16px; right:16px; bottom:11px; z-index:1;
  font-size:var(--fs-md); color:var(--sand); letter-spacing:.01em}
.panel-body{padding:16px 18px 18px}

.blank{color:var(--sand-dim); font-size:var(--fs-md); line-height:var(--lh-text)}
.lines{margin:0 0 4px}
.line{display:flex; justify-content:space-between; align-items:baseline; gap:14px;
  padding:9px 0; font-size:var(--fs-base)}
.line + .line{border-top:0; background:linear-gradient(90deg,transparent,
  color-mix(in oklab, var(--seam-2) 85%, transparent) 12%,
    color-mix(in oklab, var(--seam-2) 85%, transparent) 88%,
    transparent) top/100% 1px no-repeat}
.line dt{color:var(--sand-dim); margin:0}
.line dd{margin:0; text-align:right; word-break:break-word; font-weight:500}
.line dd{font-variant-numeric:tabular-nums}
.line.pay dd{font-size:var(--fs-xl); font-weight:800; color:var(--lamp-hi); letter-spacing:-.025em}

.field{margin-top:14px}
.field label{display:block; font-size:var(--fs-sm); color:var(--sand-dim); margin-bottom:7px;
  letter-spacing:.04em}
.field input{width:100%; font:inherit; font-size:var(--fs-base); color:var(--cream);
  background:color-mix(in oklab, var(--deep) 66%, transparent);
    border:1px solid var(--seam); border-radius:var(--r-in);
  padding:12px 13px; outline:none;
  transition:border-color var(--t-hover) ease, box-shadow var(--t-hover) ease}
.field input::placeholder{color:var(--sand-dim)}
.field input:-webkit-autofill,
.field input:-webkit-autofill:hover,
.field input:-webkit-autofill:focus{
  -webkit-text-fill-color:var(--cream); caret-color:var(--lamp);
  -webkit-box-shadow:0 0 0 100px color-mix(in oklab, var(--deep) 98%, transparent) inset;
  transition:background-color 0s 600000s}
.field input:focus{border-color:var(--fo-line); box-shadow:var(--fo-ring)}
.field input.wrong{border-color:var(--rust);
  box-shadow:0 0 0 3px color-mix(in oklab, var(--rust) 12%, transparent)}
.field .say{margin-top:7px; font-size:var(--fs-sm); color:var(--sand-dim); line-height:var(--lh-text)}
.oops{margin-top:10px; font-size:var(--fs-md); color:var(--rust); line-height:var(--lh-text); min-height:0}

/* ── кнопки ──────────────────────────────────────────────────────────── */
.act{position:relative; font-variant-numeric:tabular-nums; width:100%; margin-top:16px; padding:14px 18px;
  border-radius:var(--r-in); font-size:var(--fs-base); font-weight:650; letter-spacing:-.01em;
  background:linear-gradient(140deg,var(--lamp-hi) 0%, var(--lamp) 52%, var(--lamp-mid) 100%);
  color:var(--on-lamp);
    box-shadow:0 12px 28px -16px color-mix(in oklab, var(--lamp) 85%, transparent),
    inset 0 1px 0 rgba(255,255,255,.28);
  transition:transform var(--t-press) var(--ease-out), filter var(--t-hover) ease,
             opacity var(--t-hover) ease, box-shadow var(--t-hover) ease;
  overflow:hidden}
.act:active{transform:scale(.972)}
.act:disabled{cursor:default}
.act:disabled:not(.busy){opacity:.4; box-shadow:none}
@media (hover:hover) and (pointer:fine){
  .act:not(:disabled):hover{filter:brightness(1.07);
    box-shadow:0 14px 32px -14px color-mix(in oklab, var(--lamp) 95%, transparent),
    inset 0 1px 0 rgba(255,255,255,.34)}
}
/* Две подписи в одной кнопке. Меняются размытием, а не подменой текста:
   при обычном крестфейде видно два слоя сразу, размытие их склеивает. */
.act-face,.act-work{display:flex; align-items:center; justify-content:center; gap:8px;
  transition:opacity 200ms ease, filter 200ms ease, transform 200ms var(--ease-out)}
.act-work{position:absolute; inset:0; opacity:0; filter:blur(3px)}
.act.busy .act-face{opacity:0; filter:blur(3px); transform:scale(.97)}
.act.busy .act-work{opacity:1; filter:none}
.act.quiet{background:transparent; color:var(--cream); border:1px solid var(--seam-2);
  box-shadow:none; font-weight:600}
@media (hover:hover) and (pointer:fine){
  .act.quiet:not(:disabled):hover{background:var(--stone-2); filter:none; box-shadow:none}
}
.pair{display:flex; gap:9px}
.pair .act{flex:1}

/* ── ход заказа ──────────────────────────────────────────────────────── */
.trail{list-style:none; margin:0; padding:0; counter-reset:none}
.trail li{position:relative; display:flex; gap:12px; padding:9px 0; font-size:var(--fs-md);
  color:var(--sand-dim); transition:color var(--t-panel) ease}
/* нитка между шагами: путь читается как путь, а не как четыре строки */
.trail li:not(:last-child)::before{content:""; position:absolute; left:9px; top:29px;
  bottom:-2px; width:1px; background:var(--seam)}
.trail li.was:not(:last-child)::before{background:color-mix(in oklab, var(--ore) 35%, transparent)}
.trail .pip{width:19px; height:19px; border-radius:50%; flex:none; margin-top:1px;
  border:1px solid var(--seam-2); display:grid; place-items:center; font-size:var(--fs-cap);
  background:var(--deep); z-index:1;
  transition:background var(--t-panel) ease, border-color var(--t-panel) ease,
             color var(--t-panel) ease}
.trail b{display:block; font-weight:600}
.trail span{display:block; opacity:.85}
.trail li.now{color:var(--cream)}
.trail li.now .pip{border-color:var(--lamp); color:var(--lamp)}
.trail li.was{color:var(--sand)}
.trail li.was .pip{background:var(--ore); border-color:var(--ore); color:var(--on-ore)}
.trail li.lost{color:var(--rust)}
.trail li.lost .pip{background:var(--rust); border-color:var(--rust); color:var(--on-rust)}

.lamp-spin{display:inline-block; width:12px; height:12px; border-radius:50%;
  vertical-align:-1px; border:1.5px solid currentColor; border-top-color:transparent;
  animation:turn .68s linear infinite}
@keyframes turn{to{transform:rotate(360deg)}}
@keyframes pulse{50%{opacity:.3}}
.trail .lamp-spin{color:var(--lamp)}

.told{margin-top:14px; padding:13px 14px; border-radius:var(--r-card); font-size:var(--fs-md);
  line-height:var(--lh-text); border:1px solid var(--seam);
    background:color-mix(in oklab, var(--deep) 55%, transparent);
  opacity:0; transform:translateY(5px);
  animation:rise 320ms var(--ease-out) forwards}
/* Успеху — свой вход: он длиннее и идёт с большего расстояния, чем у отказа.
   Это единственная награда на странице, она должна отличаться. */
.told.good{border-color:color-mix(in oklab, var(--ore) 30%, transparent);
  background:color-mix(in oklab, var(--on-ore) 34%, transparent);
  animation-duration:340ms}
.told.good{--from:12px}
.told.bad{border-color:color-mix(in oklab, var(--rust) 32%, transparent);
  background:color-mix(in oklab, var(--on-rust) 34%, transparent)}
.told code{position:relative; overflow:hidden; display:block; margin-top:10px;
  padding:9px 11px; border-radius:var(--r-in); background:rgba(0,0,0,.35); font-size:var(--fs-base);
  letter-spacing:.07em; word-break:break-all; color:var(--lamp-hi)}
/* Один-единственный проход блика за весь сеанс — ровно там, ради чего
   человек пришёл и заплатил. */
.told.good code::before{content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(100deg, transparent 40%,
    color-mix(in oklab, var(--lamp-hi) 38%, transparent) 50%,
    transparent 60%) 0/300% 100%;
  animation:sheen 760ms linear 1 240ms}
@media (prefers-reduced-motion:reduce){ .told.good code::before{display:none} }

.sig{margin-top:16px; text-align:center; font-size:var(--fs-cap); color:var(--sand-dim);
  line-height:var(--lh-text); opacity:.75}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms!important; animation-iteration-count:1!important;
    transition-duration:.01ms!important}
  .ore,.told{opacity:1; transform:none}
  /* вращение убираем, но «идёт работа» человек должен видеть: мигание
     яркостью не вестибулярно и остаётся понятным */
  .lamp-spin{border-top-color:currentColor; animation:pulse 1.6s ease-in-out infinite!important;
    animation-duration:1.6s!important; animation-iteration-count:infinite!important}
}


/* ── пока грузится каталог ───────────────────────────────────────────── */
/* Пустой экран читается как сломанный сайт. Порода под лампой мерцает —
   видно, что идёт работа, и сетка не прыгает, когда придут данные. */
.skel{height:118px; border-radius:var(--r-card); border:1px solid var(--seam);
  background:linear-gradient(100deg,var(--stone-deep) 42%,var(--stone) 50%,var(--stone-deep) 58%) 0/300% 100%;
  animation:sheen 1.4s linear infinite}
@keyframes sheen{to{background-position:-300% 0}}
@media (prefers-reduced-motion:reduce){ .skel{animation:none} }

/* выданный код — то, ради чего человек платил: даём забрать в один тап */
.told code{cursor:copy; -webkit-user-select:all; user-select:all; position:relative}
.told code::after{content:"нажмите, чтобы скопировать"; display:block; margin-top:6px;
  font-size:var(--fs-cap); letter-spacing:.04em; color:var(--sand-dim);
  transition:color 160ms var(--ease-out)}
.told code[data-copied]::after{content:"скопировано"; color:var(--ore)}

/* ── как идёт добыча ─────────────────────────────────────────────────── */
.how,.asks{margin-top:52px}
.steps{list-style:none; margin:0; padding:0; display:grid;
  grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:11px}
.steps li{position:relative; padding:20px 18px 18px; border-radius:var(--r-card);
  border:1px solid var(--seam); background:linear-gradient(168deg,var(--stone),var(--stone-deep));
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--lamp-hi) 8%, transparent)}
/* Нитка между шагами: путь читается как путь, а не как три отдельные плитки. */
@media (min-width:760px){
  .steps li:not(:last-child)::after{content:""; position:absolute; top:34px; right:-11px;
    width:11px; height:1px; background:var(--seam-2)}
}
.step-n{display:grid; place-items:center; width:26px; height:26px; border-radius:50%;
  margin-bottom:6px; font-size:var(--fs-sm); font-weight:700; color:var(--lamp);
  border:1px solid var(--lamp-lo); background:color-mix(in oklab, var(--lamp) 7%, transparent)}
.steps b{display:block; font-size:var(--fs-base); font-weight:600; margin-bottom:10px;
  letter-spacing:-.01em}
.steps p{margin:0; font-size:var(--fs-md); color:var(--sand-dim); line-height:var(--lh-text)}

/* ── частые вопросы ──────────────────────────────────────────────────── */
.asks-grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); gap:9px}
.asks details{border:1px solid var(--seam); border-radius:var(--r-card);
  background:color-mix(in oklab, var(--rock) 60%, transparent); overflow:hidden;
  transition:border-color 200ms var(--ease-out)}
.asks details[open]{border-color:var(--seam-2)}
.asks summary{display:flex; align-items:center; gap:11px; padding:15px 17px;
  font-size:var(--fs-base); font-weight:500; cursor:pointer; list-style:none;
  -webkit-tap-highlight-color:transparent; user-select:none;
  transition:color 180ms var(--ease-out)}
.asks summary::-webkit-details-marker{display:none}
/* Знак раскрытия рисуем сами: системный треугольник выпадает из набора. */
.asks summary::after{content:""; flex:none; margin-left:auto; width:9px; height:9px;
  border-right:1.6px solid var(--sand-dim); border-bottom:1.6px solid var(--sand-dim);
  border-radius:1px; rotate:45deg; translate:0 -2px;
  transition:rotate 220ms var(--ease-out), border-color 180ms var(--ease-out)}
.asks details[open] summary::after{rotate:225deg; translate:0 2px;
  border-color:var(--lamp)}
.asks details[open] summary{color:var(--cream)}
@media (hover:hover) and (pointer:fine){ .asks summary:hover{color:var(--cream)} }
.asks summary:active{scale:.995}
.asks p{margin:0; padding:0 17px 16px; font-size:var(--fs-md); color:var(--sand);
  line-height:var(--lh-text); max-width:62ch}
.asks p b{color:var(--cream); font-weight:600}


/* ── строки вагонетки ────────────────────────────────────────────────── */
.cart-lines{display:flex; flex-direction:column; gap:7px; margin-bottom:12px}
.cart-line{display:flex; align-items:center; gap:10px; padding:9px 10px;
  border-radius:var(--r-in); border:1px solid var(--seam);
    background:color-mix(in oklab, var(--deep) 45%, transparent)}
.cart-line b{flex:1; font-size:var(--fs-md); font-weight:600; letter-spacing:-.01em;
  font-variant-numeric:tabular-nums}
.cart-line .sum{font-size:var(--fs-md); color:var(--sand); font-variant-numeric:tabular-nums;
  min-width:62px; text-align:right}
/* Шаговый счётчик. Кнопки крупнее подписи: попасть пальцем важнее,
   чем сэкономить четыре пикселя. */
.stepper{display:flex; align-items:center; gap:2px; flex:none}
.stepper button{width:26px; height:26px; border-radius:var(--r-in); display:grid;
  place-items:center; font-size:var(--fs-base); line-height:var(--lh-tight); color:var(--sand);
  border:1px solid var(--seam); background:color-mix(in oklab, var(--stone) 80%, transparent);
  transition:scale var(--t-press) var(--ease-out), color 160ms var(--ease-out),
             border-color 160ms var(--ease-out)}
.stepper button:active{scale:.9}
@media (hover:hover) and (pointer:fine){
  .stepper button:hover{color:var(--lamp); border-color:var(--seam-2)}
}
.stepper .n{min-width:20px; text-align:center; font-size:var(--fs-md); font-weight:600;
  font-variant-numeric:tabular-nums}

/* счётчик на карточке — видно, что уже в вагонетке */
.ore .count{position:absolute; top:11px; right:11px; z-index:1; min-width:20px; height:20px;
  padding:0 6px; border-radius:var(--r-pill); display:grid; place-items:center;
  font-size:var(--fs-cap); font-weight:700; color:var(--on-lamp);
  background:linear-gradient(140deg,var(--lamp-hi),var(--lamp));
  box-shadow:0 3px 10px -3px color-mix(in oklab, var(--lamp) 80%, transparent)}
.ore.incart{border-color:var(--lamp-lo)}

/* ══ телефон: настоящее приложение, а не страница ═════════════════════ */
/* Полоса корзины внизу — приём, который на телефоне работает лучше боковой
   панели: сумма и кнопка всегда под большим пальцем, а не «где-то там внизу
   страницы». Форма заказа при этом переезжает в шторку. */
.dock{position:fixed; left:0; right:0; bottom:0; z-index:60; display:none;
  padding:10px 12px calc(10px + env(safe-area-inset-bottom));
  background:linear-gradient(180deg, color-mix(in oklab, var(--deep) 72%, transparent) 0%,
    color-mix(in oklab, var(--deep) 96%, transparent) 42%, var(--deep) 100%);
  backdrop-filter:blur(18px) saturate(160%); -webkit-backdrop-filter:blur(18px) saturate(160%)}
.dock-in{display:flex; align-items:center; gap:11px; max-width:640px; margin:0 auto;
  padding:9px 12px; border-radius:var(--r-card); border:1px solid var(--seam);
  background:linear-gradient(180deg, color-mix(in oklab, var(--stone-2) 94%, transparent),
    color-mix(in oklab, var(--rock) 96%, transparent));
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--lamp-hi) 8%, transparent),
    0 14px 34px -20px #000}
.dock-in > .ic{color:var(--lamp); width:19px; height:19px}
.dock-sum{flex:1; min-width:0; line-height:var(--lh-tight)}
.dock-sum b{display:block; font-size:var(--fs-lg); font-weight:800; letter-spacing:-.02em;
  color:var(--lamp-hi); font-variant-numeric:tabular-nums}
.dock-sum span{display:block; font-size:var(--fs-sm); color:var(--sand-dim)}
.dock .act{width:auto; flex:none; margin:0; padding:11px 16px; font-size:var(--fs-base)}

.grabber{display:none}

@media (max-width:940px){
  .dock{display:block}
  /* Витрине нужен воздух снизу, иначе полоса накрывает последние номиналы. */
  .wrap{padding-bottom:120px}

  /* Панель заказа становится шторкой: снизу, с ручкой, поверх витрины. */
  .cart{position:fixed; left:0; right:0; bottom:0; top:auto; z-index:70;
    max-height:88vh; overflow:auto; -webkit-overflow-scrolling:touch;
    padding:0 12px calc(18px + env(safe-area-inset-bottom));
    background:linear-gradient(180deg, color-mix(in oklab, var(--stone) 99%, transparent),
    color-mix(in oklab, var(--deep) 100%, transparent));
    border-radius:var(--r-card) var(--r-card) 0 0;
    border-top:1px solid var(--seam-2);
    box-shadow:0 -20px 60px -30px #000;
    translate:0 100%; visibility:hidden;
    transition:translate 320ms var(--ease-drawer), visibility 320ms}
  .cart.open{translate:0 0; visibility:visible}
  .cart .seam-title{padding-top:4px}
  .cart .panel{border:0; background:none; box-shadow:none; backdrop-filter:none}
  .cart .panel-top{display:none}
  .cart .panel-body{padding:0}
  .cart .sig{padding-bottom:4px}

  /* Ручка: и подсказка, что шторку можно утянуть вниз, и сама мишень. */
  .grabber{display:block; width:100%; padding:12px 0 8px; border:0; background:none;
    cursor:grab; touch-action:none}
  .grabber::before{content:""; display:block; width:44px; height:4px; margin:0 auto;
    border-radius:var(--r-pill); background:var(--seam-2)}

  /* Затемнение под шторкой — чтобы витрина ушла на второй план. */
  .scrim{position:fixed; inset:0; z-index:65;
    background:color-mix(in oklab, var(--deep) 62%, transparent);
    opacity:0; pointer-events:none; transition:opacity 300ms var(--ease-out)}
  .scrim.on{opacity:1; pointer-events:auto}
}

/* Кнопка выбора прямо на карточке: на тач-экране явная мишень понятнее,
   чем «нажмите куда-нибудь по плитке». */
.ore .take{display:block; margin-top:12px; width:100%; padding:9px; border-radius:var(--r-in); font-size:var(--fs-sm);
  font-weight:650; letter-spacing:.01em; border:1px solid var(--seam-2);
  color:var(--sand); background:color-mix(in oklab, var(--stone) 70%, transparent);
  transition:background 180ms var(--ease-out), color 180ms var(--ease-out),
             border-color 180ms var(--ease-out)}
.ore.incart .take{border-color:transparent; color:var(--on-lamp);
  background:linear-gradient(140deg,var(--lamp-hi),var(--lamp))}
@media (hover:hover) and (pointer:fine){
  .ore:not(.spent):hover .take{color:var(--cream); border-color:var(--lamp-lo)}
  .ore.incart:hover .take{color:var(--on-lamp)}
}
.ore.spent .take{opacity:.5}

/* ── пыль в свете лампы ──────────────────────────────────────────────── */
/* В настоящей шахте пыль не падает ровными рядами — её носит сквозняком:
   одни крупинки идут вверх, другие сносит вбок, третьи почти висят. Поэтому
   траекторий несколько, и каждая крупинка берёт свою. Одна траектория на всех
   давала снегопад. Только transform и opacity — анимация идёт мимо потока. */
.motes{position:fixed; inset:0; overflow:hidden; pointer-events:none; z-index:0}
.motes i{position:absolute; width:var(--s); height:var(--s); border-radius:50%;
  background:var(--lamp-hi); opacity:0; will-change:transform, opacity;
  box-shadow:0 0 calc(var(--s) * 2.2) color-mix(in oklab, var(--lamp-hi) 65%, transparent);
  animation:var(--path) var(--t) var(--ease, linear) var(--delay) infinite}

/* вверх со сносом вправо, к середине разворачивает */
@keyframes drift-a{
  0%  {transform:translate3d(0,0,0) scale(.85);                    opacity:0}
  10% {opacity:var(--o)}
  35% {transform:translate3d(calc(var(--sway) * 1), -32vh, 0) scale(1)}
  70% {transform:translate3d(calc(var(--sway) * -.4), -68vh, 0) scale(.95)}
  90% {opacity:calc(var(--o) * .5)}
  100%{transform:translate3d(calc(var(--sway) * .6), -108vh, 0) scale(.8); opacity:0}
}
/* вверх со сносом влево и подрагиванием */
@keyframes drift-b{
  0%  {transform:translate3d(0,0,0) scale(.9);                     opacity:0}
  14% {opacity:var(--o)}
  40% {transform:translate3d(calc(var(--sway) * -1.2), -38vh, 0) scale(1.05)}
  62% {transform:translate3d(calc(var(--sway) * -.3), -58vh, 0) scale(.9)}
  86% {opacity:calc(var(--o) * .6)}
  100%{transform:translate3d(calc(var(--sway) * -1.6), -104vh, 0) scale(.85); opacity:0}
}
/* почти висит: медленно всплывает, сильно качает — самые мелкие крупинки */
@keyframes drift-c{
  0%  {transform:translate3d(0,0,0);                               opacity:0}
  18% {opacity:var(--o)}
  30% {transform:translate3d(var(--sway), -18vh, 0)}
  55% {transform:translate3d(calc(var(--sway) * -1), -40vh, 0)}
  80% {transform:translate3d(var(--sway), -64vh, 0); opacity:calc(var(--o) * .7)}
  100%{transform:translate3d(0, -96vh, 0);                         opacity:0}
}
@media (prefers-reduced-motion:reduce){ .motes{display:none} }

/* ── жила на карточке ────────────────────────────────────────────────── */
/* У конкурента номиналы различаются картинкой стопки монет — и это работает:
   размер видно, не читая цифру. У нас своя метафора: чем крупнее номинал,
   тем больше самоцветов в жиле. Рисуем знаком из набора, без единой картинки. */
.vein{display:flex; align-items:flex-end; gap:3px; height:26px; margin-bottom:4px;
  color:var(--lamp)}
/* Ширину задаём ЯВНО вместе с высотой: у svg без width браузер берёт
   собственный размер в 300px и разносит сетку. Эта ловушка тут уже была. */
.vein svg{flex:none; opacity:.9}
.vein svg:nth-child(1){width:14px; height:14px}
.vein svg:nth-child(2){width:21px; height:21px}
.vein svg:nth-child(3){width:15px; height:15px; opacity:.72}
.vein svg:nth-child(4){width:24px; height:24px}
.vein svg:nth-child(5){width:18px; height:18px; opacity:.8}
.ore.spent .vein{color:var(--sand-dim); opacity:.6}
.ore.incart .vein svg{filter:drop-shadow(0 0 6px color-mix(in oklab, var(--lamp) 55%, transparent))}


/* ─── получатель ─────────────────────────────────────────────────────────
   Кому уходят UC — знание более важное, чем цена, поэтому оно стоит выше
   витрины и не прячется в оформлении заказа. */
.who-chip{display:flex; align-items:center; gap:8px; width:100%;
  margin:0 0 12px; padding:10px 12px; border-radius:var(--r-card);
  border:1px solid color-mix(in oklab, var(--lamp) 26%, transparent);
  background:color-mix(in oklab, var(--lamp) 9%, rgba(0,0,0,.34));
  color:var(--cream); font:inherit; text-align:left; cursor:pointer;
  transition:background .2s var(--ease-out)}
.who-chip:active{background:color-mix(in oklab, var(--lamp) 15%, rgba(0,0,0,.34))}
.who-chip.hidden{display:none}
.who-chip > svg{width:15px; height:15px; flex:none; color:var(--lamp)}
.who-txt{flex:1; min-width:0; font-size:var(--fs-md); color:var(--sand-dim);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.who-txt b{color:var(--cream); font-weight:650}
.who-txt u{display:block; text-decoration:none; font-size:var(--fs-cap); opacity:.6;
  font-variant-numeric:tabular-nums}
.who-edit{flex:none; font-size:var(--fs-sm); color:var(--lamp); opacity:.85}

/* Ответ проверки — под самим полем: там его ищет глаз, который только что
   допечатал цифры. */
.who-state{display:flex; align-items:center; gap:7px; margin-top:7px;
  font-size:var(--fs-sm); line-height:var(--lh-tight); animation:who-in .22s var(--ease-out)}
.who-state svg{width:13px; height:13px; flex:none}
.who-state b{font-weight:650}
.who-state.ok{color:var(--ore)}
.who-state.bad{color:var(--rust)}
.who-state.hmm,.who-state.wait{color:var(--sand-dim)}
.who-state .lamp-spin{width:12px; height:12px; flex:none}
@keyframes who-in{from{opacity:0; transform:translateY(-3px)} to{opacity:1; transform:none}}

/* ─── счётчик прямо на карточке ──────────────────────────────────────────
   Второй номинал набирают чаще, чем кажется, а лезть за этим в корзину —
   лишний экран на каждое нажатие. */
.take.picked{display:flex; align-items:center; justify-content:space-between;
  gap:6px; padding-left:6px; padding-right:6px}
.take.picked i{flex:none; width:26px; height:26px; display:grid; place-items:center;
  border-radius:var(--r-in); font-style:normal; font-size:var(--fs-lg); line-height:var(--lh-tight);
  background:rgba(0,0,0,.28); transition:background .15s var(--ease-out)}
.take.picked i:active{background:rgba(0,0,0,.5)}
.take.picked b{font-variant-numeric:tabular-nums; font-weight:700}

/* ─── мои заказы ─────────────────────────────────────────────────────── */
.ord-list{display:grid; gap:8px; padding:0 16px 28px}
.ord{display:grid; grid-template-columns:auto 1fr auto; gap:2px 10px;
  align-items:center; width:100%; padding:12px 14px; border-radius:var(--r-card);
  border:1px solid var(--seam); background:var(--stone); color:var(--cream);
  font:inherit; text-align:left; cursor:pointer}
.ord:active{background:color-mix(in oklab, var(--lamp) 8%, var(--stone))}
.ord-n{font-size:var(--fs-sm); color:var(--sand-dim); font-variant-numeric:tabular-nums}
.ord-what{font-size:var(--fs-sm); color:var(--sand-dim); text-align:right;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ord-sum{grid-column:1; font-size:var(--fs-base); font-weight:700}
.ord-st{grid-column:3; justify-self:end; font-size:var(--fs-sm); padding:3px 9px;
  border-radius:var(--r-pill); background:rgba(255,255,255,.07); color:var(--sand-dim)}
.ord-st.s-done{background:color-mix(in oklab, var(--ore) 16%, transparent); color:var(--ore)}
.ord-st.s-failed,
  .ord-st.s-canceled{background:color-mix(in oklab, var(--rust) 16%, transparent);
  color:var(--rust)}
.empty{padding:22px 4px; color:var(--sand-dim); font-size:var(--fs-md); text-align:center}
.menu-tag{margin-left:auto; min-width:20px; padding:1px 7px; border-radius:var(--r-pill);
  font-size:var(--fs-sm); background:color-mix(in oklab, var(--lamp) 22%, transparent);
  color:var(--lamp)}
.menu-tag.hidden{display:none}

/* На сайте список заказов — обычные ссылки: их можно открыть в новой вкладке
   и переслать себе, а это и есть способ вернуться к заказу с другого места. */
.mine{margin-top:30px}
.ord{text-decoration:none}
.ord:hover{border-color:var(--seam-2)}
.who-chip{max-width:520px}


/* ─── карточка номинала: три в ряд ───────────────────────────────────────
   Узкая плитка показывает разом весь ряд цен — глазу не нужно листать,
   чтобы сравнить. Всё лишнее с неё убрано: монета, число, цена, кнопка. */
.grid{grid-template-columns:repeat(3, 1fr); gap:7px}
.ore{padding:9px 8px 8px; border-radius:var(--r-card); overflow:hidden}
.ore .qty{display:flex; align-items:center; gap:5px; letter-spacing:-.02em}
.ore .qty b{font-size:var(--fs-base); font-weight:700}
.ore .uc{width:17px; height:17px; flex:none}
.ore .cost{margin-top:3px; font-size:var(--fs-sm); font-weight:600; color:var(--sand)}
/* Высота кнопки фиксирована: со счётчиком она иначе выше, и ряд карточек
   подпрыгивает на каждый выбор. */
.ore .take{margin-top:8px; height:30px; display:grid; place-items:center;
  padding:0 4px; font-size:var(--fs-sm); border-radius:var(--r-in)}
.take.picked{display:flex; padding-left:2px; padding-right:2px}
.take.picked i{width:22px; height:22px; border-radius:var(--r-in); font-size:var(--fs-base)}
/* Ярлык — уголком, чтобы не съедать строку под цифру */
.ore .mark,.ore .gone{position:absolute; top:0; right:0; padding:2.5px 5px;
  border-radius:0 var(--r-card) 0 var(--r-in); font-size:var(--fs-cap); font-weight:800; letter-spacing:.08em;
  line-height:var(--lh-tight); white-space:nowrap}
.ore .tagline{display:none}

/* ─── а на телефоне — две в ряд ──────────────────────────────────────────
   Три в ряд считались по месту, а не по содержимому. На 375 под карточку
   остаётся 110 пикселей, а её собственная неделимая ширина зависит от
   заказанной гарнитуры: на узкой выходило 106 и проносило, на широкой 123 —
   и сетка распирала страницу на 65 пикселей вбок (на 360 — на 80). Колонка
   1fr от этого не спасает: её нижний предел равен содержимому. Отсюда и
   порог 430: две колонки берём там, где третьей уже не из чего сложиться,
   а не «на всякий случай».

   ТА ЖЕ ПРАВКА БЫЛА ЗАПИСАНА ВЫШЕ, рядом с объявлением .grid, и не
   работала: этот раздел идёт по файлу позже и переписывал её без всякого
   медиазапроса. Вес у правил одинаковый — побеждает последнее.

   Слой света при этом гасим по ширине, а не выключаем: он шире сетки на
   --bleed, и на телефоне эти 34 пикселя уезжали за правый край страницы.
   У магазина, которому карточки и так влезали, ровно они и составляли весь
   разъезд — 12 пикселей. Видно слой всё равно не было: лампа загорается
   только под курсором (hover:hover и pointer:fine), а на телефоне его нет. */
@media (max-width:430px){
  .grid{grid-template-columns:repeat(2, minmax(0, 1fr)); gap:9px; --bleed:0px}
}

@media (min-width: 620px){
  .grid{grid-template-columns:repeat(4, 1fr); gap:9px}
  .ore{padding:11px 10px 10px}
  .ore .qty b{font-size:var(--fs-base)}
  .ore .uc{width:19px; height:19px}
  .ore .cost{font-size:var(--fs-md)}
}


/* ─── вкладки разделов ─────────────────────────────────────────────────── */
.tabs{display:flex; gap:6px; margin:14px 0 2px; overflow-x:auto;
  scrollbar-width:none; -webkit-overflow-scrolling:touch}
.tabs::-webkit-scrollbar{display:none}
.tabs.hidden{display:none}
.tab{flex:none; padding:8px 14px; border-radius:var(--r-pill); font-size:var(--fs-md); font-weight:600;
  color:var(--sand); border:1px solid var(--seam); background:rgba(0,0,0,.25);
  transition:color 180ms var(--ease-out), border-color 180ms var(--ease-out),
             background 180ms var(--ease-out)}
.tab.on{color:var(--on-lamp); border-color:transparent;
  background:var(--metal)}
.tab:not(.on):active{background:color-mix(in oklab, var(--lamp) 10%, transparent)}

/* ─── карточка вещи ────────────────────────────────────────────────────── */
.ore.item{padding:0 0 8px}
.ore.item .pic{display:block; aspect-ratio:1/1; overflow:hidden; border-radius:var(--r-card) var(--r-card) 0 0;
  background:radial-gradient(120% 90% at 50% 15%,
    color-mix(in oklab, var(--lamp) 14%, transparent), rgba(0,0,0,.35))}
.ore.item .pic img{width:100%; height:100%; object-fit:cover; display:block}
.pic-none{display:grid; place-items:center; width:100%; height:100%; color:var(--lamp-lo)}
.pic-none svg{width:26px; height:26px}
.ore.item .name{display:block; margin:7px 8px 0; font-size:var(--fs-sm); font-weight:650;
  line-height:var(--lh-tight); overflow:hidden; display:-webkit-box; -webkit-line-clamp:2;
  -webkit-box-orient:vertical}
.ore.item .cost{margin:3px 8px 0}
.ore.item .take{margin:7px 8px 0}
/* Спрос — три деления: «часто берут» видно, не читая цифр */
.heat{display:flex; gap:2px; margin:5px 8px 0; align-items:center}
.heat i,.heat u{display:block; width:9px; height:3px; border-radius:2px}
.heat i{background:var(--lamp)}
.heat u{background:var(--seam-2)}


/* ─── полоса сверху ─────────────────────────────────────────────────────
   Разделы слева, имя по центру, заказы справа. Кнопка-иконка в углу была не
   видна вовсе: она ничего не обещала. Теперь это подписанная плашка под
   большим пальцем — и лежит там же, где её ищут. */
/* Полоса тянется от края до края. Своими полями .app обрезала её на 14
   пикселей с каждой стороны, и на светлом фоне это читалось так, будто окно
   приложения обрезано справа. */
.bar{position:sticky; top:0; z-index:20; display:flex; align-items:center;
  justify-content:space-between; gap:8px;
  margin:0 -14px; padding:9px 14px 10px;
  background:linear-gradient(180deg, var(--deep) 74%, transparent)}
.pill{display:inline-flex; align-items:center; gap:6px; padding:8px 12px;
  border-radius:var(--r-pill); font-size:var(--fs-sm); font-weight:650; white-space:nowrap;
  color:var(--on-lamp); border:1px solid transparent;
  background:var(--metal);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.45),
    0 4px 12px -6px color-mix(in oklab, var(--lamp) 80%, transparent);
  transition:scale var(--t-press) var(--ease-out)}
.pill:active{scale:.95}
.pill .ic{width:14px; height:14px}
.pill.ghost{color:var(--sand); background:rgba(0,0,0,.3); border-color:var(--seam);
  box-shadow:none}
.logo{display:flex; align-items:center; gap:6px; color:var(--sand);
  font-size:var(--fs-cap); font-weight:800; letter-spacing:.16em}
.logo svg{width:20px; height:20px; color:var(--lamp)}

/* Гузлик остаётся лицом, но перестал занимать пол-экрана до первой цены */

/* ─── карточка: номинал и цена одной строкой ───────────────────────────── */
.line1{display:block; text-align:center; letter-spacing:-.01em}
.line1 b{display:block; font-size:var(--fs-sm); font-weight:700; white-space:nowrap;
  color:var(--cream)}
.line1 span{display:block; margin-top:1px; font-size:var(--fs-cap); font-weight:700;
  white-space:nowrap; color:var(--lamp)}



/* ─── шапка: постель из углей ────────────────────────────────────────────
   Раньше Гузлик висел вырезкой в пустоте и жил отдельно от страницы. Теперь
   его угли продолжены во всю ширину, и он лежит на них — шапка стала одной
   вещью, а не картинкой поверх фона. Свет от углей уходит вниз, на витрину:
   постель не обрывается, а освещает то, что под ней. */
/* Кадрируем по высоте, а не по ширине: растянутая на всю ширину лента
   становится полоской, и Гузлик превращается в точку. */
.crown{position:relative; z-index:1; height:230px; overflow:hidden}
/* Сцена держит слои в одних координатах: три картинки одного размера лежат
   друг на друге, поэтому «где язык» считается в процентах от картинки, а не
   вымеряется руками. Лишнюю ширину углей срезает overflow шапки. */
.stage{position:absolute; left:50%; bottom:0; translate:-50% 0;
  height:100%; aspect-ratio:2000/640}
.stage img{position:absolute; inset:0; width:100%; height:100%; display:block}
/* Порядок слоёв повторяет исходник: угли лежат ПЕРЕД брюхом и лапами.
   Поэтому его горка идёт над телом — и заодно прячет линию разреза. Язык
   выше горки: в исходнике он свисает перед углями. */
.stage .bed{z-index:1}
.stage .fan{z-index:2}
.stage .guz{z-index:3}
/* Разжигание. Свечение поверх углей — это плёнка; чтобы угли действительно
   разгорались, поверх постели кладётся она же в режиме screen, через маску
   справа. Там, где маска открыта, яркость складывается сама с собой — горит
   не «подсветка», а сами угли. Картинка та же, значит грузить нечего. */
.stage .blow{z-index:2; mix-blend-mode:screen; opacity:0; will-change:opacity;
  -webkit-mask-image:radial-gradient(40% 125% at 72% 100%, #000 4%, transparent 68%);
  mask-image:radial-gradient(40% 125% at 72% 100%, #000 4%, transparent 68%);
  animation:blow 4.2s linear infinite}
.stage .pile{z-index:4}
.stage .guz:last-of-type{z-index:5}
.stage .zzz{z-index:6}

/* Гузлик спит: медленный вдох раздувает бок, выдох сдувает чуть ниже
   исходного — так дыхание не выглядит ровным насосом. Язык лежит внутри
   этого же блока, поэтому дышит вместе с ним, а сверху добавляет свой
   трепет на выдохе. */
.guz{position:absolute; inset:0; transform-origin:50% 100%; will-change:transform;
  animation:breathe 4.2s linear infinite,
            twitch 11.7s var(--ease-out) infinite}

/* Ось — там, где язык уходит в рот. Цикл вдвое длиннее дыхания: на первом
   вдохе язык просто ходит, на втором чмокает — подбирает и вываливает
   дальше прежнего. Одинаковые вдохи выдают петлю, разные — нет. */
.stage .tongue{transform-origin:63.7% 60.3%; will-change:transform;
  animation:loll 8.4s linear infinite}

/* Угли раздуваются от его выдоха — это то, что связывает Гузлика с постелью:
   видно, что он на них дышит, а не просто лежит поверх картинки. */
.fan{position:absolute; left:0; right:0; bottom:0; height:74%; pointer-events:none;
  mix-blend-mode:screen;
  background:
    radial-gradient(13% 52% at 69% 100%,
      color-mix(in oklab, var(--lamp-hi) 82%, transparent), transparent 66%),
    radial-gradient(26% 92% at 70% 100%,
      color-mix(in oklab, var(--lamp) 78%, transparent), transparent 70%),
    radial-gradient(54% 140% at 74% 100%,
      color-mix(in oklab, var(--rust) 80%, transparent), transparent 76%);
  animation:fan 4.2s linear infinite}
/* Разгорается справа — там, куда смотрит морда, — и на выдохе жар уходит
   вдоль постели, как от струи воздуха. Пик приходится на выдох, а не на
   вдох: раздувает угли выдох. */

/* Храп. Без «Z» дыхание читается как что угодно; с ними — сразу понятно. */
/* Стартуют у самой морды и поднимаются недалеко: шапка низкая, и «Z» с
   большим подъёмом просто улетает за её край и обрезается. */
.zzz{position:absolute; left:66%; top:32%; pointer-events:none}
.zzz i{position:absolute; font-style:normal; font-weight:800; line-height:1;
  color:var(--lamp-hi); opacity:0; text-shadow:0 2px 10px rgba(0,0,0,.85);
  animation:zzz 4.2s var(--ease-out) infinite}
.zzz i:nth-child(1){font-size:var(--fs-sm); animation-delay:.1s}
.zzz i:nth-child(2){font-size:var(--fs-base); animation-delay:1.4s}
.zzz i:nth-child(3){font-size:var(--fs-lg); animation-delay:2.8s}
@keyframes zzz{
  0%  {opacity:0;   translate:0 0;       rotate:-10deg; scale:.7}
  18% {opacity:.9;                       scale:1}
  70% {opacity:.42}
  100%{opacity:0;   translate:26px -44px; rotate:14deg;  scale:1.1}
}

/* Редкое подёргивание во сне. Крутится только rotate — дыхание занимает
   scale и translate, и наложи мы их ещё раз, одно затёрло бы другое. */
@keyframes twitch{
  0%,86%,100%{rotate:0deg}
  89%{rotate:.65deg}
  92%{rotate:-.5deg}
  96%{rotate:.2deg}
}

/* Тёплый выдох у морды — виден именно как выдох, а не как свечение */
.puff{position:absolute; left:59%; top:50%; width:12%; height:9%; z-index:5;
  pointer-events:none; border-radius:50%; opacity:0;
  background:radial-gradient(closest-side,
    color-mix(in oklab, var(--lamp-top) 26%, transparent), transparent 74%);
  filter:blur(5px); animation:puff 8.4s var(--ease-out) infinite}
@keyframes puff{
  0%,22%{opacity:0;  translate:0 0;    scale:.5 .5}
  31%   {opacity:.45; scale:1 1}
  45%   {opacity:0;  translate:14px 5px; scale:1.5 1.3}
  46%,68%{opacity:0; translate:0 0;    scale:.5 .5}
  77%   {opacity:.7;  scale:1.2 1.1}
  93%   {opacity:0;  translate:20px 7px; scale:1.9 1.5}
  100%  {opacity:0}
}

/* Искры от углей: постель горячая, и это должно быть видно без слов */
.sparks{position:absolute; inset:0; z-index:4; pointer-events:none}
.sparks i{position:absolute; bottom:16%; width:3px; height:3px; border-radius:50%;
  background:var(--lamp-hi);
    box-shadow:0 0 7px color-mix(in oklab, var(--lamp-hi) 85%, transparent); opacity:0;
  animation:spark 5.4s linear infinite}
.sparks i:nth-child(1){left:24%; animation-delay:0s}
.sparks i:nth-child(2){left:41%; animation-delay:1.7s; animation-duration:6.6s}
.sparks i:nth-child(3){left:57%; animation-delay:3.1s; animation-duration:4.8s}
.sparks i:nth-child(4){left:72%; animation-delay:.9s;  animation-duration:6.1s}
.sparks i:nth-child(5){left:86%; animation-delay:4.2s; animation-duration:5.7s}
@keyframes spark{
  0%  {opacity:0;  translate:0 0;        scale:.6}
  12% {opacity:.9}
  70% {opacity:.35}
  100%{opacity:0;  translate:13px -70px; scale:.25}
}

@media (prefers-reduced-motion: reduce){
  .guz, .stage .tongue, .fan, .stage .blow, .zzz i, .puff, .sparks i{animation:none !important}
  .zzz, .puff, .sparks{display:none}
}
@media (min-width:820px){ .crown{height:320px} }
.crown::after{content:""; position:absolute; left:0; right:0; bottom:-46px; height:92px;
  background:radial-gradient(58% 100% at 50% 0,
    color-mix(in oklab, var(--rust) 26%, transparent), transparent 72%);
  pointer-events:none}
@media (prefers-reduced-motion: no-preference){
  .crown img{animation:crown-in 620ms var(--ease-out) both}
}
@keyframes crown-in{from{opacity:0; translate:0 10px} to{opacity:1; translate:0 0}}

.line.cut dt{color:var(--lamp)}
.line.cut dd{color:var(--lamp); font-weight:700}
.note-card.gold{text-align:left; width:230px;
  background:linear-gradient(140deg, color-mix(in oklab, var(--lamp) 30%, transparent),
    color-mix(in oklab, var(--lamp) 8%, transparent));
  border-color:color-mix(in oklab, var(--lamp-hi) 42%, transparent)}
.note-card.gold:active{scale:.98}

/* Привязка — первое, что видно на экране уровней: без неё всё остальное
   там абстракция. Поэтому у неё своё поле, а не отсылка в оформление заказа. */
.bindbox{margin-top:12px; padding:16px 16px 15px; border-radius:var(--r-card);
  background:linear-gradient(180deg,
    color-mix(in oklab, var(--stone-deep) 92%, transparent),
    color-mix(in oklab, var(--deep) 95%, transparent));
  border:1px solid color-mix(in oklab, var(--lamp-hi) 20%, transparent)}
.bindbox h2{margin:0 0 5px; font-size:var(--fs-base); letter-spacing:-.01em}
.bindbox p{margin:0 0 12px; font-size:var(--fs-sm); line-height:var(--lh-text); color:var(--sand-dim);
  text-wrap:pretty}
.bindrow{display:flex; gap:8px}
.bindrow input{flex:1; min-width:0; font:var(--fs-field)/var(--lh-text) var(--font); font-weight:550;
  color:var(--cream); background:color-mix(in oklab, var(--cream) 7%, transparent);
  border:1px solid color-mix(in oklab, var(--lamp-hi) 20%, transparent); border-radius:var(--r-in);
    padding:12px 13px;
  outline:none; transition:border-color var(--t-hover) ease, background var(--t-hover) ease}
.bindrow input:focus{border-color:var(--fo-line);
  background:color-mix(in oklab, var(--cream) 12%, transparent);
  box-shadow:var(--fo-ring)}
.bindbox .who-state{margin-top:9px}
/* Только прямой ребёнок: иначе правило ловит и «Проверить» внутри строки,
   и та растягивается на всю ширину, сплющивая поле ввода. */
.bindbox > .act.mini{width:100%; margin-top:11px}
.bindrow .act.mini{flex:none; white-space:nowrap}
.act.mini.ghost{color:var(--sand); background:color-mix(in oklab, var(--cream) 8%, transparent);
  border:1px solid color-mix(in oklab, var(--lamp-hi) 18%, transparent); box-shadow:none}
.act.mini[disabled]{opacity:.55}

/* Привязка — предложение, а не требование: без неё магазин работает так же,
   поэтому блок спокойный и стоит после статуса, а не перед ним. */
.bind{display:flex; align-items:center; gap:12px; margin-top:12px;
  padding:14px 15px; border-radius:var(--r-card);
  background:color-mix(in oklab, var(--cream) 6%, transparent);
    border:1px solid color-mix(in oklab, var(--lamp-hi) 16%, transparent)}
.bind div{flex:1}
.bind b{display:block; font-size:var(--fs-md)}
.bind span{display:block; margin-top:3px; font-size:var(--fs-sm); line-height:var(--lh-text);
  color:var(--sand-dim)}
.bind .ic{width:20px; height:20px; color:var(--ore); flex:none}
.bind.done{border-color:color-mix(in oklab, var(--ore) 34%, transparent);
  background:color-mix(in oklab, var(--ore) 9%, transparent)}
.act.mini{width:auto; margin:0; flex:none; padding:10px 14px; font-size:var(--fs-sm)}

/* ─── уровни ─────────────────────────────────────────────────────────────
   Экран должен продавать статус, а не отчитываться о нём. Поэтому сверху
   крупно — кто вы сейчас и сколько до следующего, и только потом таблица. */
.vip-now{display:grid; justify-items:center; gap:6px; text-align:center;
  margin-top:6px; padding:26px 18px 22px; border-radius:var(--r-card);
  background:linear-gradient(168deg, color-mix(in oklab, var(--lamp) 16%, transparent),
    color-mix(in oklab, var(--stone-deep) 94%, transparent));
  border:1px solid color-mix(in oklab, var(--lamp-hi) 28%, transparent);
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--cream) 24%, transparent),
    var(--sh-lift)}
.vip-now .ic{width:34px; height:34px; color:var(--lamp);
  filter:drop-shadow(0 3px 7px rgba(0,0,0,.5))}
.vip-now b{font-size:var(--fs-xl); letter-spacing:-.02em}
.vip-now > span{font-size:var(--fs-sm); color:var(--sand-dim)}
.vip-now em{margin-top:2px; padding:5px 12px; border-radius:var(--r-pill); font-style:normal;
  font-size:var(--fs-sm); font-weight:700; color:var(--on-lamp);
  background:var(--metal)}
.vip-bar{width:100%; max-width:260px; height:6px; margin-top:12px; border-radius:var(--r-pill);
  background:rgba(0,0,0,.45); overflow:hidden}
.vip-bar i{display:block; height:100%; border-radius:var(--r-pill);
  background:linear-gradient(90deg, var(--lamp-lo), var(--lamp-hi));
  transition:width 800ms var(--ease-out)}
.vip-left{font-size:var(--fs-sm); color:var(--sand); text-wrap:balance}
.vip-now.empty-id{background:linear-gradient(168deg,
  color-mix(in oklab, var(--cream) 7%, transparent),
  color-mix(in oklab, var(--stone-deep) 94%, transparent));
  border-color:color-mix(in oklab, var(--lamp-hi) 16%, transparent)}

/* Полторы сотни слов поверх фотографии шахты не читаются — уводим на
   плотную подложку, как юридические тексты. */
.vip-sheet{margin:18px 0 26px; padding:18px 16px 20px; border-radius:var(--r-card);
  background:linear-gradient(180deg,
    color-mix(in oklab, var(--stone-deep) 93%, transparent),
    color-mix(in oklab, var(--deep) 96%, transparent));
  border:1px solid var(--seam)}
.vip-h{margin:2px 0 8px; font-size:var(--fs-lg); letter-spacing:-.01em}
.vip-p{margin:0 0 12px; font-size:var(--fs-md); line-height:var(--lh-text); color:var(--sand);
  text-wrap:pretty}
.vip-p.small{font-size:var(--fs-sm); color:var(--sand-dim); margin-top:14px}
.vip-p b{color:var(--cream)}

.vip-table{display:grid; gap:7px; margin:14px 0 4px}
.vip-row{display:grid; grid-template-columns:auto auto 1fr; gap:2px 10px;
  padding:13px 14px; border-radius:var(--r-card);
  background:color-mix(in oklab, var(--cream) 5%, transparent);
    border:1px solid color-mix(in oklab, var(--lamp-hi) 12%, transparent)}
.vip-row b{font-size:var(--fs-base)}
.vip-row u{justify-self:start; text-decoration:none; font-size:var(--fs-sm); color:var(--sand-dim)}
.vip-row span{grid-column:3; grid-row:1; justify-self:end; font-size:var(--fs-base);
  font-weight:700; color:var(--lamp)}
.vip-row em{grid-column:1 / -1; font-style:normal; font-size:var(--fs-sm); line-height:var(--lh-text);
  color:var(--sand-dim); margin-top:4px}
/* Текущий уровень выделен, но не кричит: это опора, а не главное на экране */
.vip-row.on{border-color:color-mix(in oklab, var(--lamp-hi) 40%, transparent);
  background:color-mix(in oklab, var(--lamp) 12%, transparent);
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--cream) 20%, transparent)}
.vip-row.on b::after{content:" — вы здесь"; font-weight:500; font-size:var(--fs-sm);
  color:var(--sand-dim)}

/* ─── документы ──────────────────────────────────────────────────────────
   Ссылки в подвале нарочно приглушены: они обязаны быть, но забирать на себя
   внимание им незачем — за ними идут не покупать. */
.fine{display:flex; flex-direction:column; gap:6px; align-items:center;
  margin:26px 0 10px; padding-bottom:8px}
.fine button{font-size:var(--fs-cap); color:var(--sand-dim); opacity:.5;
  text-decoration:underline; text-underline-offset:3px;
  text-decoration-color:color-mix(in oklab, var(--sand-dim) 40%, transparent);
  transition:opacity 180ms var(--ease-out)}
.fine button:active{opacity:.85}

/* Длинный текст обязан лежать на плотной подложке: полторы тысячи слов
   поверх фотографии шахты не читаются, сколько ни осветляй. */
.legal-body{padding:18px 16px 26px; margin-bottom:26px; border-radius:var(--r-card);
  font-size:var(--fs-base); line-height:var(--lh-text); color:var(--sand);
  background:linear-gradient(180deg,
    color-mix(in oklab, var(--stone-deep) 93%, transparent),
    color-mix(in oklab, var(--deep) 96%, transparent));
  border:1px solid var(--seam)}
.legal-body h1{margin:10px 0 6px; font-size:var(--fs-xl); line-height:var(--lh-tight);
  letter-spacing:-.02em; color:var(--cream)}
.legal-body h2{margin:26px 0 8px; font-size:var(--fs-lg); letter-spacing:-.01em; color:var(--cream)}
.legal-body h3{margin:18px 0 6px; font-size:var(--fs-base); color:var(--cream)}
.legal-body p{margin:0 0 11px; text-wrap:pretty}
.legal-body ul,.legal-body ol{margin:0 0 12px; padding-left:20px}
.legal-body li{margin-bottom:6px}
.legal-body .legal-note{font-size:var(--fs-sm); color:var(--sand-dim);
  border-left:2px solid var(--seam-2); padding-left:11px; margin:14px 0}

/* ─── забой вместо полоски загрузки ──────────────────────────────────────
   Полоска ничего не сообщает: она одинакова и когда всё идёт хорошо, и когда
   всё встало. Гузлик с киркой честнее — по нему видно, что работа идёт, а
   подпись рядом говорит, на каком мы шаге и сколько ещё ждать. */
/* Экран ожидания — плотная плашка, а не стекло: тут длинные подписи, а
   стеклянная карточка поверх освещённой шахты их топит. */
.digger{display:grid; justify-items:center; gap:5px; margin-top:6px;
  padding:24px 16px 20px; border-radius:var(--r-card); text-align:center;
  background:linear-gradient(180deg, color-mix(in oklab, var(--stone) 93%, transparent),
    color-mix(in oklab, var(--deep) 96%, transparent));
  border:1px solid color-mix(in oklab, var(--lamp-hi) 18%, transparent);
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--cream) 14%, transparent),
    0 16px 34px -20px #000}
.digger.hidden{display:none}
.digger b{font-size:var(--fs-base); letter-spacing:-.01em}
.digger > span{max-width:280px; font-size:var(--fs-sm); line-height:var(--lh-text);
  color:var(--sand); text-wrap:balance}
/* Кирка больше не бьёт в воздух: справа лежит порода, и удар приходится в неё.
   Раскладку сменили с grid-центра на абсолютную — при центрировании кирка
   стоит посреди площадки и породу ставить попросту некуда. Ключевые кадры
   swing и точка опоры не тронуты: качание осталось прежним, к нему добавилась
   только цель. */
.digger-face{position:relative; width:146px; height:82px; margin-bottom:4px}
/* Ось у рукояти, а не в середине: кирка должна ходить как кирка */
/* Кирка — рендер из Blender вместо плоского значка. Качание оставлено ровно
   тем же: та же дорожка swing, та же длительность. Изменилась только точка
   опоры — она посчитана по самой модели: низ рукояти лёг в 35.8% по ширине и
   98.5% по высоте обрезанного кадра. Значение на глаз промахнулось бы мимо
   хвата, и кирка вертелась бы вокруг пустого места. */
.pick{position:absolute; left:6px; top:9px;
  width:66px; height:58px; transform-origin:36% 98%;
  background:url("img/pickaxe.webp?v=4f21361e") center / contain no-repeat;
  filter:drop-shadow(0 3px 6px rgba(0,0,0,.5));
  animation:swing 1.15s var(--ease-in-out) infinite}
.pick > *{display:none}
@keyframes swing{
  0%  {rotate:-48deg}
  34% {rotate:12deg}
  40% {rotate:16deg}
  48% {rotate:6deg}
  100%{rotate:-48deg}
}
/* Осколки вылетают ровно в момент удара, иначе связь не читается */
/* Точка удара не на глаз: остриё правого рога на 34–40% дорожки swing
   приходит в (75, 45) от угла площадки — это посчитано по самой дорожке и по
   точке опоры. Оттуда и летят осколки, туда же подведена жила породы. */
.chips{position:absolute; left:75px; bottom:37px; width:0; height:0}
.chips i{position:absolute; width:4px; height:4px; border-radius:1px;
  background:var(--lamp-hi);
    box-shadow:0 0 6px color-mix(in oklab, var(--lamp-hi) 80%, transparent); opacity:0;
  animation:chip 1.15s var(--ease-out) infinite}
.chips i:nth-child(1){--dx:-24px; --dy:-28px}
.chips i:nth-child(2){--dx:-13px; --dy:-34px; animation-delay:.03s}
.chips i:nth-child(3){--dx:4px;   --dy:-31px; animation-delay:.06s}
.chips i:nth-child(4){--dx:-30px; --dy:-14px; animation-delay:.02s}
.chips i:nth-child(5){--dx:14px;  --dy:-20px; animation-delay:.05s}
@keyframes chip{
  0%,34%{opacity:0; translate:0 0; scale:.5}
  40%   {opacity:1; scale:1}
  72%   {opacity:.45}
  100%  {opacity:0; translate:var(--dx) var(--dy); scale:.25}
}
/* Порода — рендер из Blender: тёмный скол с золотой жилой на том боку, куда
   приходит остриё. Вздрагивает ровно в момент удара, той же длительностью
   1.15s, поэтому связь «удар — отдача» читается без объяснений. */
.rock{position:absolute; right:6px; bottom:2px; width:74px; height:44px;
  background:url("img/rock.webp?v=52e62344") center / contain no-repeat;
  filter:drop-shadow(0 4px 6px rgba(0,0,0,.6));
  animation:rock-hit 1.15s var(--ease-out) infinite}
@keyframes rock-hit{
  0%,33%{translate:0 0; scale:1}
  36%   {translate:1px 2px; scale:1.035 .955}
  45%   {translate:0 0; scale:1}
  100%  {translate:0 0; scale:1}
}
.digger-bar{width:100%; max-width:230px; height:5px; margin-top:10px;
  border-radius:var(--r-pill); background:rgba(0,0,0,.42); overflow:hidden}
.digger-bar i{display:block; height:100%; width:10%; border-radius:var(--r-pill);
  background:linear-gradient(90deg, var(--lamp-lo), var(--lamp-hi));
  transition:width 700ms var(--ease-out)}
.digger.done .pick,.digger.done .chips i,.digger.done .rock,
.digger.bad .rock{animation:none}
.digger.done .pick{rotate:-14deg; color:var(--ore)}
.digger.bad .pick{animation:none; rotate:24deg; color:var(--rust)}

/* Шаги под забоем — теперь опись, а не главный экран */
.trail{margin-top:12px; padding:8px 16px; border-radius:var(--r-card);
  background:linear-gradient(180deg,
    color-mix(in oklab, var(--stone-deep) 90%, transparent),
    color-mix(in oklab, var(--deep) 94%, transparent));
  border:1px solid var(--seam)}
.trail li div b{display:block; font-size:var(--fs-md); color:inherit}
.trail li div span{display:block; margin-top:1px; font-size:var(--fs-sm); color:var(--sand-dim)}

/* Вне экрана шапка замирает целиком — включая пыль и искры внутри неё */
.crown.still *{animation-play-state:paused !important}

/* ─── навигация ──────────────────────────────────────────────────────────
   Меню выезжает колонкой слева, а не листом снизу: разделов стало много, в
   столбце они читаются списком и остаются на виду целиком. */
.menu{position:fixed; inset:0; z-index:80}
.menu-scrim{position:absolute; inset:0;
  background:color-mix(in oklab, var(--deep) 62%, transparent);
  backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px);
  animation:scrim-in 240ms var(--ease-out) both}
@keyframes scrim-in{from{opacity:0} to{opacity:1}}
.menu-card{position:absolute; left:0; top:0; bottom:0; width:min(80%, 306px);
  display:flex; flex-direction:column; gap:3px; padding:14px 12px;
  background:linear-gradient(180deg, var(--stone) 0%, var(--deep) 100%);
  border-right:1px solid var(--seam); box-shadow:22px 0 46px -20px rgba(0,0,0,.9);
  animation:drawer-in 280ms var(--ease-drawer) both; overflow-y:auto}
@keyframes drawer-in{from{translate:-100% 0} to{translate:0 0}}
.menu-head{display:flex; align-items:center; gap:9px; padding:6px 8px 16px;
  color:var(--sand); font-size:var(--fs-cap); font-weight:800; letter-spacing:.16em}
.menu-head svg{width:22px; height:22px; color:var(--lamp)}
.menu-head b{flex:1}
.menu-x{width:32px; height:32px; border-radius:50%; font-size:var(--fs-base); color:var(--sand-dim);
  background:color-mix(in oklab, var(--cream) 7%, transparent)}
.menu-item{display:flex; align-items:center; gap:11px; width:100%; padding:13px 12px;
  border-radius:var(--r-card); font-size:var(--fs-base); font-weight:600; color:var(--cream);
  text-align:left; transition:background 160ms var(--ease-out)}
.menu-item .ic{width:17px; height:17px; color:var(--lamp); flex:none}
.menu-item:active{background:color-mix(in oklab, var(--cream) 9%, transparent)}
.menu-item.on{background:color-mix(in oklab, var(--lamp) 14%, transparent)}

.menu-sep{margin:16px 8px 8px; font-size:var(--fs-cap); font-weight:800; letter-spacing:.16em;
  text-transform:uppercase; color:var(--sand-dim)}
.menu-item.game{gap:10px}
.menu-item.game .dot{width:9px; height:9px; border-radius:50%; flex:none;
  box-shadow:0 0 8px -1px currentColor}
.menu-item.game span{flex:1; font-weight:600}
.menu-item.game em{font-style:normal; font-size:var(--fs-cap); color:var(--sand-dim)}
.menu-item.soon{opacity:.42; cursor:default}
.menu-item.soon em{color:var(--lamp-lo)}

/* Стрелка назад стоит в каждом разделе. Родная кнопка телеграма есть не
   везде и не у всех, а выход из экрана нужен всегда. */
.back{display:inline-flex; align-items:center; gap:6px; margin:12px 0 8px;
  padding:8px 13px 8px 9px; border-radius:var(--r-pill); font-size:var(--fs-md); font-weight:600;
  color:var(--sand); background:color-mix(in oklab, var(--cream) 7%, transparent);
  border:1px solid color-mix(in oklab, var(--lamp-hi) 16%, transparent);
  transition:scale var(--t-press) var(--ease-out), background 160ms var(--ease-out)}
.back .ic{width:16px; height:16px}
.back:active{scale:.955; background:color-mix(in oklab, var(--cream) 12%, transparent)}

/* Полоса подразделов — липкая под шапкой, всегда на виду */
.tabs{position:sticky; top:52px; z-index:15; margin:12px -14px 2px; padding:2px 14px 8px;
  background:linear-gradient(180deg, var(--deep) 58%, transparent)}
.tab{display:inline-flex; align-items:center; gap:6px}
.tab .ic{width:14px; height:14px}

/* Главная и пустой экран живут внутри той же трёхколоночной сетки, что и
   карточки, — без этого они занимают ОДНУ колонку и всё внутри сплющивается
   до трети ширины. Растягиваем на весь ряд. */
.grid > .home,.grid > .empty{grid-column:1 / -1}

/* ─── главная ─────────────────────────────────────────────────────────── */
.home{display:grid; gap:22px}
.promises{display:grid; grid-template-columns:repeat(3, 1fr); gap:8px}
.promises > div{padding:13px 10px; border-radius:var(--r-card); text-align:center;
  background:color-mix(in oklab, var(--cream) 6%, transparent);
    border:1px solid color-mix(in oklab, var(--lamp-hi) 13%, transparent);
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--cream) 10%, transparent)}
.promises .ic{width:17px; height:17px; color:var(--lamp); margin-bottom:7px}
.promises b{display:block; font-size:var(--fs-sm); line-height:var(--lh-tight); text-wrap:balance}
.promises span{display:block; font-size:var(--fs-cap); color:var(--sand-dim); margin-top:3px;
  line-height:var(--lh-tight); text-wrap:balance}

/* Лента объявлений — горизонтальная, как у конкурента снизу, но у нас сверху
   и в своей палитре. Место под акции, которых пока нет: пусть будет то, что
   покупателю и правда важно знать. */
.notes{display:flex; gap:8px; overflow-x:auto; margin:0 -14px; padding:0 14px 2px;
  scrollbar-width:none}
.notes::-webkit-scrollbar{display:none}
.note-card{flex:none; width:230px; padding:13px 14px; border-radius:var(--r-card);
  background:linear-gradient(140deg, color-mix(in oklab, var(--lamp) 16%, transparent),
    color-mix(in oklab, var(--cream) 5%, transparent));
  border:1px solid color-mix(in oklab, var(--lamp-hi) 20%, transparent);
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--cream) 16%, transparent)}
.note-card b{display:block; font-size:var(--fs-md); margin-bottom:3px}
.note-card span{display:block; font-size:var(--fs-sm); color:var(--sand-dim); line-height:var(--lh-text)}

.row h3{display:flex; align-items:center; gap:8px; margin:0 0 10px;
  font-size:var(--fs-base); font-weight:700; letter-spacing:-.01em}
.row h3 .ic{width:15px; height:15px; color:var(--lamp)}
.row .more{margin-left:auto; padding:5px 10px; border-radius:var(--r-pill);
  font-size:var(--fs-sm); font-weight:600; color:var(--lamp);
  background:color-mix(in oklab, var(--lamp) 12%, transparent)}
.row .more:active{background:color-mix(in oklab, var(--lamp) 22%, transparent)}
.row-in{display:grid; grid-template-columns:repeat(3, 1fr); gap:7px}

/* ─── поля заказа ────────────────────────────────────────────────────────
   Это последний экран перед деньгами: здесь глаз должен видеть, куда писать,
   без прищуривания. Раньше поля были бледнее фона и терялись — теперь у них
   своя плашка, подпись контрастная, а фокус подсвечивает всё поле, а не одну
   рамку. */
.field{margin-bottom:16px}
.field label{display:block; font-size:var(--fs-sm); font-weight:600; letter-spacing:.01em;
  color:var(--sand); margin-bottom:8px}
.field input{width:100%; font:var(--fs-field)/var(--lh-text) var(--font); font-weight:550; color:var(--cream);
  background:color-mix(in oklab, var(--cream) 7%, transparent);
  border:1px solid color-mix(in oklab, var(--lamp-hi) 20%, transparent); border-radius:var(--r-in);
  padding:14px 14px; outline:none;
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--cream) 10%, transparent),
    inset 0 -1px 0 rgba(0,0,0,.3);
  transition:border-color var(--t-hover) ease, background var(--t-hover) ease,
             box-shadow var(--t-hover) ease}
.field input::placeholder{color:var(--sand-dim)}
.field input:hover{background:color-mix(in oklab, var(--cream) 10%, transparent)}
.field input:focus{border-color:var(--fo-line);
  background:color-mix(in oklab, var(--cream) 12%, transparent);
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--cream) 16%, transparent),
             var(--fo-ring)}
.field input.bad,.field input.wrong{border-color:var(--rust);
  box-shadow:0 0 0 3px color-mix(in oklab, var(--rust) 20%, transparent)}
.field .say,.say{color:var(--sand-dim)}
.field input:-webkit-autofill,.field input:-webkit-autofill:focus{
  -webkit-box-shadow:0 0 0 100px var(--stone) inset}

/* Свод по заказу — та же плашка, что у карточек: экран не должен
   распадаться на разные материалы */
.lines{background:color-mix(in oklab, var(--cream) 5.5%, transparent);
  border:1px solid color-mix(in oklab, var(--lamp-hi) 14%, transparent);
  border-radius:var(--r-card); padding:12px 14px; margin:0 0 16px}

/* ─── жидкое стекло ──────────────────────────────────────────────────────
   Карточка перестаёт быть серой плашкой и становится материалом: сквозь неё
   видно угли, а не закрашенный прямоугольник. По правилам Apple вес материала
   задаёт иерархию — карточка тяжелее и темнее (это структура), кнопка на ней
   легче и светлее (это действие). Светлое на светлое не кладём: читаемость
   от этого рассыпается, поэтому под кнопкой всегда тёмное стекло карточки.

   Блюр умеренный: двадцать три карточки с backdrop-filter — уже нагрузка,
   и на телефоне разница между 12 и 24 пикселями радиуса не стоит кадров. */
.ore{
  border:1px solid color-mix(in oklab, var(--lamp-hi) 13%, transparent);
  /* Плашку держит НАЛОЖЕНИЕ БЕЛЫМ, а не блюр. У конкурента кнопки вообще не
     прозрачные — сплошной rgb(48,48,48) поверх тёмного фона, и «стекло» там
     оптическая иллюзия. Такой приём работает везде, включая вебвью телеграма,
     где backdrop-filter может быть отключён. Блюр оставляем сверху бонусом:
     есть — красивее, нет — плашка всё равно на месте. Наша чуть темнее его:
     .055 белого поверх нашего фона даёт примерно 34 против его 48. */
  /* Без backdrop-filter намеренно. Двадцать три размытия подложки на одном
     экране — самая дорогая вещь во всей витрине, а даёт она почти ничего:
     плашку держит наложение белым, и у конкурента блюра нет вовсе. */
  background:linear-gradient(168deg, color-mix(in oklab, var(--cream) 7.5%, transparent) 0%,
    color-mix(in oklab, var(--cream) 3.5%, transparent) 100%);
  /* Верхняя грань ловит свет, нижняя уходит в тень — так стекло получает
     толщину. Без этих двух линий полупрозрачный блок читается как дырка. */
  box-shadow:
    inset 0 1px 0 color-mix(in oklab, var(--cream) 17%, transparent),
    inset 0 -1px 0 rgba(0,0,0,.4),
    var(--sh-card);
}
.ore.spent{background:linear-gradient(168deg,
  color-mix(in oklab, var(--rock) 50%, transparent),
  color-mix(in oklab, var(--deep) 62%, transparent));
  border-color:color-mix(in oklab, var(--seam) 40%, transparent);
    box-shadow:inset 0 1px 0 color-mix(in oklab, var(--cream) 8%, transparent)}
.ore.incart{border-color:color-mix(in oklab, var(--lamp) 42%, transparent);
  background:linear-gradient(168deg,
    color-mix(in oklab, var(--lamp) 13%, transparent) 0%,
    color-mix(in oklab, var(--deep) 55%, transparent) 100%);
  box-shadow:
    inset 0 1px 0 color-mix(in oklab, var(--cream) 30%, transparent),
    inset 0 -1px 0 rgba(0,0,0,.4),
    0 12px 28px -14px color-mix(in oklab, var(--lamp) 35%, transparent)}

/* Кнопка — материал полегче: она зовёт нажать, а карточка только держит */
.ore .take{
  border:1px solid color-mix(in oklab, var(--lamp-hi) 20%, transparent);
  background:linear-gradient(180deg, color-mix(in oklab, var(--cream) 13%, transparent),
    color-mix(in oklab, var(--cream) 6%, transparent));
  color:var(--cream);
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--cream) 26%, transparent),
    0 3px 9px -6px rgba(0,0,0,.7);
  transition:background 180ms var(--ease-out), border-color 180ms var(--ease-out)}
.ore:not(.spent):active .take{background:linear-gradient(180deg,
  color-mix(in oklab, var(--lamp-hi) 26%, transparent),
    color-mix(in oklab, var(--lamp-hi) 10%, transparent))}
.ore.spent .take{background:rgba(0,0,0,.22);
  border-color:color-mix(in oklab, var(--seam) 50%, transparent);
  box-shadow:none; opacity:.55}

/* Вкладки и чип получателя — то же стекло, чтобы шапка не распадалась
   на разные материалы */
.tab:not(.on){background:color-mix(in oklab, var(--cream) 7.5%, transparent);
  border-color:color-mix(in oklab, var(--lamp-hi) 12%, transparent);
  box-shadow:inset 0 1px 0 color-mix(in oklab, var(--cream) 12%, transparent)}
.who-chip{box-shadow:inset 0 1px 0 color-mix(in oklab, var(--cream) 14%, transparent)}

/* Стекло — украшение, а не условие читаемости. Кому прозрачность мешает,
   тот получает плотный фон и ни одного блюра. */
@media (prefers-reduced-transparency: reduce){
  .ore, .ore.incart, .tab:not(.on), .who-chip{
    backdrop-filter:none; -webkit-backdrop-filter:none}
  .ore{background:linear-gradient(168deg, var(--stone) 0%, var(--stone-deep) 100%)}
  .ore.incart{background:linear-gradient(168deg, var(--stone-2) 0%, var(--rock) 100%)}
  .tab:not(.on){background:var(--stone)}
  .who-chip{background:var(--stone)}
}

/* ─── куча монет ─────────────────────────────────────────────────────────
   Позиция монеты в куче задаётся translate, а вращение и наведение — rotate,
   scale и transform. Это разные свойства CSS, поэтому они складываются и не
   затирают друг друга: раскладка держится, пока монета крутится. */
/* Именно block: .pile — это <span>, а строчному элементу высота не
   назначается, и куча вылезает за карточку. */
/* perspective обязательна: без неё rotateY даёт плоское сжатие круга, а не
   переворот — монета выглядит смятой, а не повёрнутой. */
.pile{display:block; position:relative; height:44px; margin-bottom:5px;
  perspective:300px}
.pile .uc{position:absolute; left:50%; bottom:0; flex:none;
  translate:calc(-50% + var(--x)) var(--y);
  filter:drop-shadow(0 2px 3px rgba(0,0,0,.55));
  transition:scale 300ms var(--ease-out), rotate 300ms var(--ease-out),
             filter 300ms var(--ease-out);
  transition-delay:calc(var(--c) * 22ms)}
/* Чем больше куча, тем мельче монета — иначе она не влезает в карточку */
.pile.lvl1 .uc{width:24px; height:24px}
.pile.lvl2 .uc{width:18px; height:18px}
.pile.lvl3 .uc{width:15px; height:15px}
.pile.lvl4 .uc{width:13px; height:13px}

@media (hover:hover){
  .ore:not(.spent):hover .pile .uc{scale:1.12;
    filter:drop-shadow(0 5px 7px rgba(0,0,0,.7)) brightness(1.12)}
  .ore:not(.spent):hover .pile .uc:nth-child(odd){rotate:-9deg}
  .ore:not(.spent):hover .pile .uc:nth-child(even){rotate:9deg}
}
.ore:not(.spent):active .pile .uc{scale:.96; rotate:0deg; transition-duration:70ms;
  transition-delay:0ms}

/* Кладём — волна снизу вверх. Снимаем — сверху вниз и в обратную сторону:
   одно и то же движение, прочитанное задом наперёд. */
.pile.clink .uc{animation:coin-flip 620ms linear both;
  animation-delay:calc(var(--c) * 42ms)}
.pile.unclink .uc{animation:coin-back 560ms linear both;
  animation-delay:calc((var(--n) - 1 - var(--c)) * 36ms)}
.pile.wave .uc{animation:coin-flip 560ms linear both;
  animation-delay:calc(var(--d, 0) * 30ms + var(--c, 0) * 42ms)}

@media (prefers-reduced-motion: reduce){
  .pile .uc, .pile.clink .uc, .pile.unclink .uc, .pile.wave .uc{
    animation:none !important; transition:none !important; scale:1; rotate:0deg}
}

/* Кадры ниже собраны scripts/make_keyframes.py и вставлены целиком — править
   их руками бессмысленно, меняются опорные значения в том скрипте. Тайминг
   у всех троих linear: форму задаёт плотность кадров, а ease-in-out между
   редкими позами и создаёт то самое перещёлкивание. */
@keyframes breathe{
  0%{scale:1.0000 1.0000; translate:0 0.00px}
  4%{scale:1.0012 1.0026; translate:0 -0.40px}
  8%{scale:1.0028 1.0060; translate:0 -0.92px}
  12%{scale:1.0045 1.0098; translate:0 -1.50px}
  16%{scale:1.0064 1.0138; translate:0 -2.12px}
  20%{scale:1.0083 1.0178; translate:0 -2.73px}
  24%{scale:1.0101 1.0217; translate:0 -3.32px}
  28%{scale:1.0117 1.0250; translate:0 -3.83px}
  32%{scale:1.0129 1.0277; translate:0 -4.24px}
  36%{scale:1.0137 1.0294; translate:0 -4.51px}
  40%{scale:1.0140 1.0300; translate:0 -4.60px}
  44%{scale:1.0138 1.0297; translate:0 -4.56px}
  48%{scale:1.0134 1.0288; translate:0 -4.43px}
  52%{scale:1.0126 1.0272; translate:0 -4.18px}
  56%{scale:1.0112 1.0243; translate:0 -3.74px}
  60%{scale:1.0089 1.0193; translate:0 -2.97px}
  64%{scale:1.0059 1.0127; translate:0 -1.96px}
  68%{scale:1.0027 1.0057; translate:0 -0.87px}
  72%{scale:0.9997 0.9991; translate:0 0.16px}
  76%{scale:0.9973 0.9938; translate:0 0.96px}
  80%{scale:0.9960 0.9910; translate:0 1.40px}
  84%{scale:0.9959 0.9907; translate:0 1.44px}
  88%{scale:0.9965 0.9922; translate:0 1.22px}
  92%{scale:0.9976 0.9946; translate:0 0.84px}
  96%{scale:0.9988 0.9974; translate:0 0.40px}
  100%{scale:1.0000 1.0000; translate:0 0.00px}
}

@keyframes loll{
  0%{rotate:0.00deg; scale:1.0000 1.0000; translate:0.00px 0.00px}
  4%{rotate:-1.50deg; scale:0.9880 0.9705; translate:-0.13px 0.13px}
  8%{rotate:-2.65deg; scale:0.9770 0.9449; translate:-0.47px 0.47px}
  12%{rotate:-0.97deg; scale:0.9888 0.9722; translate:-0.95px 0.95px}
  16%{rotate:2.85deg; scale:1.0174 1.0388; translate:-1.48px 1.48px}
  20%{rotate:5.00deg; scale:1.0330 1.0770; translate:-2.01px 2.01px}
  24%{rotate:3.08deg; scale:1.0176 1.0463; translate:-2.45px 2.45px}
  28%{rotate:1.00deg; scale:1.0000 1.0110; translate:-2.73px 2.73px}
  32%{rotate:2.23deg; scale:1.0038 1.0251; translate:-2.77px 2.77px}
  36%{rotate:3.70deg; scale:1.0110 1.0440; translate:-2.50px 2.50px}
  40%{rotate:3.14deg; scale:1.0142 1.0389; translate:-1.86px 1.86px}
  44%{rotate:1.48deg; scale:1.0101 1.0178; translate:-0.75px 0.75px}
  48%{rotate:-1.02deg; scale:0.9801 0.9727; translate:0.94px -0.94px}
  52%{rotate:-4.60deg; scale:0.9231 0.9004; translate:3.12px -3.12px}
  56%{rotate:-7.06deg; scale:0.8827 0.8511; translate:4.73px -4.73px}
  60%{rotate:-8.11deg; scale:0.8655 0.8320; translate:5.62px -5.66px}
  64%{rotate:-2.80deg; scale:0.9301 0.9340; translate:3.40px -3.05px}
  68%{rotate:6.56deg; scale:1.0476 1.1127; translate:-0.94px 1.92px}
  72%{rotate:7.97deg; scale:1.0697 1.1384; translate:-2.35px 3.34px}
  76%{rotate:3.19deg; scale:1.0170 1.0439; translate:-1.00px 1.40px}
  80%{rotate:4.15deg; scale:1.0223 1.0511; translate:0.16px -0.23px}
  84%{rotate:6.60deg; scale:1.0440 1.0880; translate:0.50px -0.74px}
  88%{rotate:3.79deg; scale:1.0202 1.0467; translate:0.50px -0.75px}
  92%{rotate:0.89deg; scale:0.9973 1.0057; translate:0.32px -0.48px}
  96%{rotate:0.33deg; scale:0.9981 1.0025; translate:0.11px -0.16px}
  100%{rotate:0.00deg; scale:1.0000 1.0000; translate:0.00px 0.00px}
}

@keyframes fan{
  0%{opacity:0.130; translate:0.00px 0; scale:1.0000 1.0000}
  4%{opacity:0.087; translate:-2.75px 0; scale:0.9706 0.9873}
  8%{opacity:0.076; translate:-4.80px 0; scale:0.9494 0.9788}
  12%{opacity:0.087; translate:-6.21px 0; scale:0.9359 0.9742}
  16%{opacity:0.113; translate:-6.99px 0; scale:0.9294 0.9731}
  20%{opacity:0.143; translate:-7.19px 0; scale:0.9296 0.9750}
  24%{opacity:0.170; translate:-6.84px 0; scale:0.9359 0.9797}
  28%{opacity:0.191; translate:-5.97px 0; scale:0.9477 0.9867}
  32%{opacity:0.215; translate:-4.61px 0; scale:0.9645 0.9956}
  36%{opacity:0.245; translate:-2.81px 0; scale:0.9859 1.0060}
  40%{opacity:0.285; translate:-0.60px 0; scale:1.0112 1.0176}
  44%{opacity:0.340; translate:2.00px 0; scale:1.0400 1.0300}
  48%{opacity:0.432; translate:5.89px 0; scale:1.0825 1.0474}
  52%{opacity:0.563; translate:11.37px 0; scale:1.1423 1.0716}
  56%{opacity:0.711; translate:17.49px 0; scale:1.2087 1.0982}
  60%{opacity:0.850; translate:23.27px 0; scale:1.2711 1.1231}
  64%{opacity:0.956; translate:27.77px 0; scale:1.3189 1.1421}
  68%{opacity:1.005; translate:30.02px 0; scale:1.3415 1.1508}
  72%{opacity:0.978; translate:29.20px 0; scale:1.3297 1.1457}
  76%{opacity:0.898; translate:26.07px 0; scale:1.2915 1.1300}
  80%{opacity:0.785; translate:21.99px 0; scale:1.2431 1.1099}
  84%{opacity:0.643; translate:17.97px 0; scale:1.1969 1.0898}
  88%{opacity:0.460; translate:13.33px 0; scale:1.1451 1.0665}
  92%{opacity:0.300; translate:8.39px 0; scale:1.0910 1.0416}
  96%{opacity:0.200; translate:3.75px 0; scale:1.0406 1.0184}
  100%{opacity:0.130; translate:0.00px 0; scale:1.0000 1.0000}
}

@keyframes blow{
  0%{opacity:0.000}
  4%{opacity:0.000}
  8%{opacity:0.000}
  12%{opacity:0.000}
  16%{opacity:0.000}
  20%{opacity:0.000}
  24%{opacity:0.027}
  28%{opacity:0.051}
  32%{opacity:0.072}
  36%{opacity:0.098}
  40%{opacity:0.133}
  44%{opacity:0.186}
  48%{opacity:0.267}
  52%{opacity:0.407}
  56%{opacity:0.578}
  60%{opacity:0.749}
  64%{opacity:0.885}
  68%{opacity:0.952}
  72%{opacity:0.924}
  76%{opacity:0.824}
  80%{opacity:0.690}
  84%{opacity:0.545}
  88%{opacity:0.375}
  92%{opacity:0.220}
  96%{opacity:0.098}
  100%{opacity:0.000}
}

@keyframes coin-flip{
  0%{transform:rotateY(0.0deg) translateY(0.00px)}
  4%{transform:rotateY(-9.6deg) translateY(-1.36px)}
  8%{transform:rotateY(44.2deg) translateY(-3.45px)}
  12%{transform:rotateY(96.0deg) translateY(-5.69px)}
  16%{transform:rotateY(123.1deg) translateY(-7.50px)}
  20%{transform:rotateY(147.4deg) translateY(-8.92px)}
  24%{transform:rotateY(170.4deg) translateY(-10.16px)}
  28%{transform:rotateY(193.2deg) translateY(-10.91px)}
  32%{transform:rotateY(217.0deg) translateY(-10.84px)}
  36%{transform:rotateY(240.9deg) translateY(-9.87px)}
  40%{transform:rotateY(264.7deg) translateY(-8.37px)}
  44%{transform:rotateY(288.3deg) translateY(-6.74px)}
  48%{transform:rotateY(312.7deg) translateY(-5.20px)}
  52%{transform:rotateY(341.4deg) translateY(-3.20px)}
  56%{transform:rotateY(368.8deg) translateY(-1.26px)}
  60%{transform:rotateY(387.8deg) translateY(-0.08px)}
  64%{transform:rotateY(391.9deg) translateY(-0.41px)}
  68%{transform:rotateY(383.3deg) translateY(-2.13px)}
  72%{transform:rotateY(372.0deg) translateY(-3.40px)}
  76%{transform:rotateY(360.9deg) translateY(-3.07px)}
  80%{transform:rotateY(352.0deg) translateY(-1.96px)}
  84%{transform:rotateY(368.6deg) translateY(-1.00px)}
  88%{transform:rotateY(377.7deg) translateY(-0.37px)}
  92%{transform:rotateY(301.5deg) translateY(0.19px)}
  96%{transform:rotateY(131.1deg) translateY(0.41px)}
  100%{transform:rotateY(0.0deg) translateY(0.00px)}
}

@keyframes coin-back{
  0%{transform:rotateY(0.0deg) translateY(0.00px)}
  4%{transform:rotateY(9.6deg) translateY(0.79px)}
  8%{transform:rotateY(-44.2deg) translateY(2.03px)}
  12%{transform:rotateY(-96.0deg) translateY(3.37px)}
  16%{transform:rotateY(-123.1deg) translateY(4.50px)}
  20%{transform:rotateY(-147.4deg) translateY(5.45px)}
  24%{transform:rotateY(-170.4deg) translateY(6.33px)}
  28%{transform:rotateY(-193.2deg) translateY(6.91px)}
  32%{transform:rotateY(-217.0deg) translateY(6.93px)}
  36%{transform:rotateY(-240.9deg) translateY(6.38px)}
  40%{transform:rotateY(-264.7deg) translateY(5.47px)}
  44%{transform:rotateY(-288.3deg) translateY(4.47px)}
  48%{transform:rotateY(-312.7deg) translateY(3.48px)}
  52%{transform:rotateY(-341.4deg) translateY(2.17px)}
  56%{transform:rotateY(-368.8deg) translateY(0.87px)}
  60%{transform:rotateY(-387.8deg) translateY(0.06px)}
  64%{transform:rotateY(-391.9deg) translateY(0.26px)}
  68%{transform:rotateY(-383.3deg) translateY(1.37px)}
  72%{transform:rotateY(-372.0deg) translateY(2.20px)}
  76%{transform:rotateY(-360.9deg) translateY(2.03px)}
  80%{transform:rotateY(-352.0deg) translateY(1.38px)}
  84%{transform:rotateY(-368.6deg) translateY(0.80px)}
  88%{transform:rotateY(-377.7deg) translateY(0.39px)}
  92%{transform:rotateY(-301.5deg) translateY(-0.01px)}
  96%{transform:rotateY(-131.1deg) translateY(-0.20px)}
  100%{transform:rotateY(0.0deg) translateY(0.00px)}
}


/* ─── монета из Blender ──────────────────────────────────────────────────
   Из Blender взята САМА МОНЕТА, а не движение. Спрайтовая лента, которую я
   пробовал, крутила её вокруг вертикали кадра — получалось вращение в
   плоскости, то есть рулетка, а не переворот. Оборот остаётся прежний,
   на rotateY: плоский круг сжимается в ребро и разворачивается обратно —
   именно так выглядит брошенная монета.

   Одна картинка на все монеты: браузер грузит её раз и переиспользует.

   КАКАЯ картинка — решает витрина, а не эти стили: адрес приезжает в --cur
   по открытому разделу. Пока монета была вписана сюда, магазин по Mobile
   Legends продавал алмазы под золотой монетой UC. Запасной вариант в url()
   оставлен на случай, если переменную не успели проставить. */
.pile .uc{
  background:var(--cur, url("img/coin.webp?v=760d2990")) center / contain no-repeat;
  filter:drop-shadow(0 2px 3px rgba(0,0,0,.55))}
.pile .uc > *{display:none}          /* внутренний svg больше не нужен */

/* ─── КЛАД: ступень номинала КАМЕНЬ ЗА КАМНЕМ ───────────────────────────
   Кучка из одинаковых предметов говорит о размере покупки ровно до тех пор,
   пока предметы можно пересчитать. На площадке в 44 пикселя шесть самоцветов
   от десяти не отличить — 1 765, 2 975 и 6 000 алмазов стояли под одной и той
   же пирамидкой. Там, где ступени нарисованы (`i-klad-<слаг>-<ступень>`,
   см. scripts/znak_klad.py), карточка выкладывает свою: один камень,
   горстка, россыпь, груда. Мини-апп делает ровно то же, см. skin.css.

   ЗЕМЛЯ ОДНОЙ ССЫЛКОЙ, КАМНИ — ПООТДЕЛЬНОСТИ. Свет и тени под кучей
   принадлежат ВСЕЙ груде, а не камню: они приезжают символом, одним `<use>`.
   А камни витрина выкладывает по одному, из таблицы `data-камни` при том же
   символе. Иначе было нельзя: внутрь `<use>` стили не дотягиваются — там
   теневое дерево, — и груда, вставленная одной ссылкой, получала ОДНУ
   задержку на всех. Так и вышло однажды: вместо звона горсти подскакивала
   вся картинка разом.

   Предмет тут НЕ фоновая картинка, а вклеенный символ, поэтому отменяем оба
   общих правила кучи: и сдвиг на полширины, и подстановку `--cur` фоном.
   Символ вклеен ради цвета: сам камень синий, в цвете товара, а `color`
   отдаёт лампу магазина свечению ПОД кладом. */
.pile.клад .uc{position:static; translate:0; width:100%; height:100%;
  background:none; color:var(--lamp); overflow:visible; filter:none}
.pile.клад .uc > *{display:inline}   /* общее правило кучи прячет вклейку */
/* filter:none — ОТМЕНА общей тени кучи, и отмена намеренная. Пока клад был
   одной картинкой, drop-shadow на нём стоил одного размытия: картинка ехала
   целиком, слоем. Теперь внутри шевелится дюжина камней, и браузеру пришлось
   бы пересчитывать размытие всей площадки на каждом кадре — ровно та статья
   расхода, на которой витрина уже дважды роняла кадры на телефоне.
   Отдаёт тень при этом почти ничего: у камня свой жирный тёмный контур, а
   под кучей лежат три эллипса земли из самого символа. Сличал обе картинки
   рядом — разницы на плитке не видно. */

/* МЕСТО КАМНЯ В КУЧЕ — `translate`, ДВИЖЕНИЕ — `transform`. Это разные
   свойства CSS: они складываются и не затирают друг друга, поэтому раскладка
   держится, пока камень летает. Крен и размер камня лежат в атрибуте у
   `<use>` внутри — их CSS не трогает вовсе.

   Начало отсчёта нужно НУЛЕВОЕ. По умолчанию поворот идёт вокруг середины
   поля 64 × 48, и камень не кувыркается на месте, а облетает кучу по кругу.
   У нуля же начало координат приходится ровно на середину камня: туда камень
   поставил `translate`, а `<use>` внутри сдвинут на свой центр (-10 -9). */
.pile.клад .кам{transform-box:view-box; transform-origin:0 0;
  translate:var(--x) var(--y);
  transition:scale 300ms var(--ease-out), rotate 300ms var(--ease-out);
  transition-delay:calc(var(--c) * 22ms)}

/* Наведение кренит камни в РАЗНЫЕ стороны — чётные вправо, нечётные влево, —
   и куча шевелится. Пока клад был одним рисунком, крен доставался ему целиком
   и от мыши наклонялась вся картинка разом, как открытка; тогда здесь
   оставался один подрост. Камни поотдельности — разнобой вернулся.

   Первой строкой СНИМАЕМ наведение с самой картинки. Общее правило кучи
   кренит и растит `.uc`, а `.uc` у клада один на всю груду — и крен опять
   достался бы открытке. Заодно снимаем оттуда тень: на наведении она
   возвращалась фильтром, а размытие живой площадки мы как раз убрали. */
@media (hover:hover){
  .ore:not(.spent):hover .pile.клад .uc{rotate:0deg; scale:1; filter:none}
  .ore:not(.spent):hover .pile.клад .кам{scale:1.08}
  .ore:not(.spent):hover .pile.клад .кам:nth-of-type(odd){rotate:-7deg}
  .ore:not(.spent):hover .pile.клад .кам:nth-of-type(even){rotate:7deg}
}
/* Нажатие приседает ВСЕЙ кучей — это общее правило `.uc`, и оно клад
   устраивает. Камням остаётся отпустить крен наведения, иначе на мыши
   нажатая куча так и стоит раскоряченной. */
.ore:not(.spent):active .pile.клад .кам{scale:1; rotate:0deg;
  transition-duration:70ms; transition-delay:0ms}

/* ЗВОН ГОРСТИ. Кладём — камни подбрасывает волной СНИЗУ ВВЕРХ: раскладка
   уложена сверху вниз (дальние ряды первыми), поэтому задержка считается от
   конца, и ближний нижний ряд уходит первым — как от удара снизу. Снимаем —
   волна идёт обратно, сверху вниз, и само движение читается задом наперёд
   (`reverse`): камень не подброшен, а уложен на место.

   Таймингом linear: форму задаёт плотность кадров, а не сглаживание
   (см. scripts/make_keyframes.py). Кадры ниже собраны им и вставлены целиком
   — править их руками бессмысленно, меняются опорные значения в скрипте. */
/* САМА КАРТИНКА НЕ КУВЫРКАЕТСЯ. Общее правило кучи включает монетный кувырок
   всякому `.uc`, а `.uc` у клада один на всю груду: вокруг вертикали
   поворачивалась бы вся картинка разом — та самая открытка, из-за которой
   кувырок кладу и не подошёл. Пока клад был одним рисунком, это правило
   перебивал «звяк»; камни же живут этажом ниже, и перебивать стало нечем —
   гасим явно. Кувырок остаётся монете, кладу достаётся подброс по камням. */
.pile.клад.clink .uc,.pile.клад.unclink .uc,.pile.клад.wave .uc{animation:none}

.pile.клад.clink .кам{animation:подброс 600ms linear both;
  animation-delay:calc((var(--n) - 1 - var(--c)) * 26ms)}
.pile.клад.unclink .кам{animation:подброс 520ms linear both reverse;
  animation-delay:calc(var(--c) * 22ms)}
.pile.клад.wave .кам{animation:подброс 600ms linear both;
  animation-delay:calc(var(--d, 0) * 30ms + (var(--n) - 1 - var(--c)) * 26ms)}

@media (prefers-reduced-motion: reduce){
  .pile.клад .кам{animation:none !important; transition:none !important;
    scale:1; rotate:0deg}
}
@keyframes подброс{
  0%{transform:translate(calc(var(--o) * 0.00px),0.00px) rotate(calc(var(--k) * 0.0deg)) scale(1.0000,1.0000)}
  4%{transform:translate(calc(var(--o) * -0.23px),0.87px) rotate(calc(var(--k) * -9.0deg)) scale(1.0332,0.9602)}
  8%{transform:translate(calc(var(--o) * -0.43px),1.40px) rotate(calc(var(--k) * -18.3deg)) scale(1.0600,0.9300)}
  12%{transform:translate(calc(var(--o) * -0.23px),-0.02px) rotate(calc(var(--k) * -6.1deg)) scale(1.0306,0.9671)}
  16%{transform:translate(calc(var(--o) * 0.44px),-2.85px) rotate(calc(var(--k) * 30.8deg)) scale(0.9731,1.0410)}
  20%{transform:translate(calc(var(--o) * 1.35px),-6.01px) rotate(calc(var(--k) * 77.3deg)) scale(0.9400,1.1000)}
  24%{transform:translate(calc(var(--o) * 2.24px),-8.40px) rotate(calc(var(--k) * 118.0deg)) scale(0.9628,1.1234)}
  28%{transform:translate(calc(var(--o) * 2.92px),-9.91px) rotate(calc(var(--k) * 148.2deg)) scale(1.0193,1.1294)}
  32%{transform:translate(calc(var(--o) * 3.56px),-11.02px) rotate(calc(var(--k) * 174.8deg)) scale(1.0811,1.1258)}
  36%{transform:translate(calc(var(--o) * 4.10px),-11.50px) rotate(calc(var(--k) * 198.9deg)) scale(1.1200,1.1200)}
  40%{transform:translate(calc(var(--o) * 4.40px),-11.21px) rotate(calc(var(--k) * 222.0deg)) scale(1.1208,1.1159)}
  44%{transform:translate(calc(var(--o) * 4.37px),-10.25px) rotate(calc(var(--k) * 243.7deg)) scale(1.0976,1.1096)}
  48%{transform:translate(calc(var(--o) * 4.09px),-8.83px) rotate(calc(var(--k) * 263.5deg)) scale(1.0661,1.0974)}
  52%{transform:translate(calc(var(--o) * 3.66px),-7.03px) rotate(calc(var(--k) * 282.6deg)) scale(1.0417,1.0755)}
  56%{transform:translate(calc(var(--o) * 3.20px),-4.61px) rotate(calc(var(--k) * 302.0deg)) scale(1.0400,1.0400)}
  60%{transform:translate(calc(var(--o) * 2.66px),-2.10px) rotate(calc(var(--k) * 323.9deg)) scale(1.0751,0.9736)}
  64%{transform:translate(calc(var(--o) * 2.03px),0.13px) rotate(calc(var(--k) * 346.7deg)) scale(1.1226,0.8963)}
  68%{transform:translate(calc(var(--o) * 1.44px),1.80px) rotate(calc(var(--k) * 365.5deg)) scale(1.1400,0.8600)}
  72%{transform:translate(calc(var(--o) * 1.00px),0.24px) rotate(calc(var(--k) * 376.5deg)) scale(1.0945,0.9065)}
  76%{transform:translate(calc(var(--o) * 0.66px),-2.58px) rotate(calc(var(--k) * 381.3deg)) scale(1.0191,0.9941)}
  80%{transform:translate(calc(var(--o) * 0.40px),-2.92px) rotate(calc(var(--k) * 381.2deg)) scale(0.9700,1.0500)}
  84%{transform:translate(calc(var(--o) * 0.20px),-0.99px) rotate(calc(var(--k) * 375.4deg)) scale(0.9765,1.0369)}
  88%{transform:translate(calc(var(--o) * 0.09px),0.70px) rotate(calc(var(--k) * 368.0deg)) scale(1.0026,1.0007)}
  92%{transform:translate(calc(var(--o) * 0.07px),0.78px) rotate(calc(var(--k) * 359.7deg)) scale(1.0097,0.9893)}
  96%{transform:translate(calc(var(--o) * 0.06px),0.20px) rotate(calc(var(--k) * 357.3deg)) scale(0.9996,1.0004)}
  100%{transform:translate(calc(var(--o) * 0.00px),0.00px) rotate(calc(var(--k) * 360.0deg)) scale(1.0000,1.0000)}
}
