/* ============================================================
   КОМПАНЬОНЫ: дроны рядом с плашкой личности.

   Ни одной картинки — только CSS-фигуры. Ограничение то же, что у косметики
   внешности (shared/domain/cosmetics/art.js): ни одного запроса на сторону,
   и каталог остаётся в килобайтах.

   ПРАВИЛО ГРАНИЦ. Здесь нет ни одного селектора, ПЕРЕОПРЕДЕЛЯЮЩЕГО стиль
   арены. Дроны живут в своём слое (#companions), координаты им считает JS по
   рамкам настоящих элементов — как уже сделано для полёта фишек (#fly).
   Прототип пробовал иначе: `.myseat{position:relative}` перебил
   base.css:237 и уронил hero-карты за верхний край экрана.
   Два исключения — ДОБАВОЧНЫЕ классы на узлах арены (`.pet-hit`,
   `.pet-branded`): они ничего не переопределяют, а только дорисовывают
   попадание и клеймо, и оба сняты вместе со сценой.

   ГЕОМЕТРИЯ ОТ `--s`. Все размеры частей — проценты от кадра дрона, поэтому
   один и тот же риг честно живёт и на 18px бейджа соперника, и на 180px в
   «Ангаре». Меняется одна переменная.

   ── ПОЧЕМУ КОНТУР, А НЕ ЗАЛИВКА ────────────────────────────────────────────
   Первая версия рисовала корпус ТЁМНЫМ градиентом (#6d6d8e → #0e0e18) и
   надеялась на однопиксельный блик по верхней кромке. На сукне (#1f7a5c) и
   особенно на фоне стола (#0A0718) это давало нулевой контраст по светлоте:
   на 44px и 22px от дрона оставалась одна светящаяся линза, то есть ВСЕ семь
   корпусов выглядели одинаковым красным пятном. Ради силуэта категория и
   существует — платят за узнаваемость, а её не было.

   Теперь корпус — это КАНТ: `.hull` залит светлым (`--rim`), а его `::after`
   с тем же `clip-path` и отступом `--edge` кладёт сверху тёмное ядро
   (`--core`). Остаётся светящаяся обводка ПО ФОРМЕ, толщиной от размера
   кадра. Так силуэт читается и на светлом сукне (тёмное ядро + тень), и на
   тёмном фоне (светлый кант + свечение) — одним набором правил, без второй
   темы. `clip-path:inherit` у ядра значит, что каждое шасси переопределяет
   форму ОДИН раз, а кант повторяет её сам.

   ── ЯЗЫК ЗНАКОВ ────────────────────────────────────────────────────────────
   На 22px форма корпуса не читается — читается свет. Поэтому у каждого шасси
   своя эмиссивная примета, и она разная по СЧЁТУ И ОСИ, а не по оттенку:

     Скаут    одна точка          ·
     Квадро   четыре кольца       ⁘
     Орбита   горизонтальное кольцо ⊖
     Шеврон   длинная V-линия     ⌄
     Страж    вертикальная щель   |
     Ворон    два косых росчерка  ⫽
     Арбитр   корона из трёх огней ⋔

   Восемь предметов — восемь разных иконок, а не восемь оттенков одной.
   ============================================================ */

/* ── слой ─────────────────────────────────────────────────────────────────── */
/* z-index 44: НАД сукном, местами и раздаваемыми картами (10…42), ПОД
   подписями действий (45), сиянием сцены (46), навигацией (50), шторками (70)
   и тостами (100). Глобальный сканлайн (body::after, 9990) ложится и сюда —
   дрон выглядит частью экрана, а не наклейкой на нём. */
#companions{position:fixed;inset:0;pointer-events:none;z-index:44;overflow:hidden}
#companions .pet{position:absolute}

/* ── каркас дрона ─────────────────────────────────────────────────────────── */
/* `position:relative` — не украшение: все детали рига абсолютны, и без
   позиционированной обёртки они цепляются за первого попавшегося предка.
   В слое компаньонов это перекрывается на absolute (см. выше), а в витрине,
   карточке предмета и профиле дрон обязан быть самодостаточным.

   `perspective` включает настоящий разворот корпуса по Y. Плоские CSS-фигуры
   при `rotateY` ведут себя как жалюзи — и это именно то, что нужно: бочка на
   победе и разворот к сопернику стали объёмными, не прибавив ни одного узла. */
.pet{
  --s:40px; --eye:#FF3B5C; --glowc:rgba(255,59,92,.55);
  /* Кант: холодный металл, к нижней кромке уходящий в цвет краски, —
     отражённый свет от собственной линзы. Именно он отделяет силуэт от фона. */
  --rim:linear-gradient(158deg,#F4F6FF 0 14%,#B6BCE8 34%,#767CAC 60%,#4A4F76 82%,var(--eye));
  --core:linear-gradient(158deg,#3B3C5A 0 16%,#20212F 48%,#0B0B13);
  /* Толщина канта. `max(1px,…)` — потому что на бейдже соперника (18px)
     процент даёт полпикселя, а полпикселя браузер размазывает в ничто. */
  --edge:max(1px,calc(var(--s) * .045));
  /* Направление на участника сцены. `--face` — горизонтальная составляющая
     (−1…1), `--lean` — вертикальная; их ставит JS перед запуском парной сцены
     (`Companion.faceTo`). До этого здесь был только `--dir` (±1), то есть
     зеркало: на круглом столе сосед сверху и сосед справа получали один и тот
     же разворот, и «посмотрел на него» превращалось в «повернулся куда-то».
     `--dir` остался знаком для битов, которым достаточно стороны. */
  --face:0; --lean:0; --dir:1;
  position:relative;width:var(--s);height:var(--s);pointer-events:none;
  perspective:calc(var(--s) * 2.6);
}
.pet .rig{position:absolute;inset:0;transform-style:preserve-3d}
/* Дрон в перелёте: над остальными дронами слоя и заметно ярче. Полёт — это
   ВЫХОД НА СЦЕНУ, и он обязан читаться как смена состояния, а не как сдвиг
   картинки. `will-change` здесь единственный в файле: летит максимум два
   дрона, а вот петли покоя держать в композиторе постоянно незачем. */
.pet.flying{z-index:3;will-change:transform}
.pet.flying .rig{filter:drop-shadow(0 0 calc(var(--s) * .18) var(--glowc))}
/* РАЗМЕР ИДЁТ ЗА СТОЛОМ, А НЕ ЖИВЁТ САМ ПО СЕБЕ.
   У карт три ступени (--hero-w: 52 → 64 → 74px на 1024 и 1720, см.
   styles/desktop.css), и дрон обязан идти теми же ступенями. Пока их было две,
   на широком десктопе он оставался 44px против карты в 104px и выглядел
   значком, а не персонажем — при том, что места там как раз больше всего.

   Пропорция, от которой считаем:
     свой  ≈ 0.65–0.72 высоты своей карты — он стоит РЯДОМ с ней и с ней же
             сравнивается;
     чужой ≈ 0.6–0.65 диаметра аватара места — он висит на его краю.
   Чужой может позволить себе такой размер только потому, что по умолчанию он
   спит и просыпается на 1.9 с (§4, П1). Включите «видны всегда» — и его
   придётся уменьшать обратно. */
.pet.mine{--s:46px}
.pet.opp{--s:26px}

/* Десктоп: карта 64×90, аватар 46. */
@media (min-width:1024px){
  .pet.mine{--s:62px}
  .pet.opp{--s:30px}
}

/* Широкий: карта 74×104, место 92, аватар 58 — стол наконец во всю ширину. */
@media (min-width:1720px){
  .pet.mine{--s:76px}
  .pet.opp{--s:38px}
}

/* ── корпус: кант + ядро ──────────────────────────────────────────────────── */
/* Общая заготовка. Шасси меняет только `clip-path` и рамку — ядро повторяет
   форму само (`clip-path:inherit`), поэтому силуэт описан в ОДНОМ месте. */
.pet .hull{
  position:absolute;left:50%;top:18%;width:46%;height:64%;transform:translateX(-50%);
  clip-path:polygon(50% 0,100% 34%,84% 92%,50% 100%,16% 92%,0 34%);
  background:var(--rim);
  /* Два разных ореола, и оба обязательны: светлый отделяет дрона от тёмного
     фона стола, тёмный — от светлого сукна. Порядок важен, drop-shadow
     считается по альфе clip-path и потому повторяет силуэт. */
  filter:drop-shadow(0 0 calc(var(--s) * .07) var(--glowc))
         drop-shadow(0 calc(var(--s) * .05) calc(var(--s) * .13) rgba(0,0,0,.85));
}
.pet .hull::after{
  content:'';position:absolute;inset:var(--edge);clip-path:inherit;background:var(--core);
}

/* ── эмиссивные приметы ───────────────────────────────────────────────────── */
/* Свечения масштабируются от кадра: на 22px фиксированные 16px гало съедали
   весь силуэт, а на 180px в «Ангаре» их не было видно вовсе. */
.pet .lens{
  position:absolute;left:50%;top:42%;width:20%;height:20%;transform:translateX(-50%);
  border-radius:50%;background:var(--eye);
  box-shadow:0 0 calc(var(--s) * .16) var(--eye),0 0 calc(var(--s) * .38) var(--glowc);
}
.pet .slit{
  position:absolute;left:50%;top:24%;width:8%;height:44%;transform:translateX(-50%);
  border-radius:99px;background:var(--eye);
  box-shadow:0 0 calc(var(--s) * .16) var(--eye),0 0 calc(var(--s) * .36) var(--glowc);
}

/* ── детали корпуса ───────────────────────────────────────────────────────── */
/* Крылья и кили — тоже с кантом: без него они отваливаются от корпуса,
   который стал светлым по контуру, и дрон распадается на части. */
/* Кромка крыла светлее корпуса: после перехода на кант тёмное крыло
   отваливалось от светлого силуэта и дрон распадался на несвязанные пятна. */
.pet .wing{
  position:absolute;top:30%;width:28%;height:34%;
  clip-path:polygon(0 0,100% 36%,58% 100%);
  background:linear-gradient(120deg,#EDEFFF 0 10%,#9096C4 30%,#43486C 62%,#14172400);
  filter:drop-shadow(0 0 calc(var(--s) * .05) var(--glowc))
         drop-shadow(0 3px 6px rgba(0,0,0,.75));
  transition:transform .38s cubic-bezier(.34,1.4,.64,1);
}
.pet .wing.l{left:0;transform:scaleX(-1)}
.pet .wing.r{right:0}
.pet .fin{
  position:absolute;top:42%;width:22%;height:14%;
  clip-path:polygon(0 0,100% 40%,100% 100%,0 60%);
  background:linear-gradient(120deg,#B9BEE4 0 20%,#3A3F60 55%,#171A28);
  transition:transform .38s cubic-bezier(.34,1.4,.64,1);
}
.pet .fin.l{left:-4%;transform:scaleX(-1)}
.pet .fin.r{right:-4%}
/* Сопло — единственная деталь, которой положено мерцать в покое: это признак
   «двигатель работает», и он же превращается в форсаж на рывке. */
.pet .jet{
  position:absolute;left:50%;bottom:2%;width:14%;height:22%;transform:translateX(-50%);
  transform-origin:50% 0;
  background:linear-gradient(180deg,var(--eye),transparent 88%);filter:blur(2px);opacity:.85;
  animation:pet-jet 1.4s ease-in-out infinite;
}
@keyframes pet-jet{0%,100%{opacity:.5;transform:translateX(-50%) scaleY(.75)}
  50%{opacity:.95;transform:translateX(-50%) scaleY(1.15)}}
.pet .hoop{
  position:absolute;left:2%;top:32%;width:96%;height:40%;
  border:2px solid var(--eye);border-radius:50%;transform:rotateX(68deg);opacity:.9;
  box-shadow:0 0 calc(var(--s) * .16) var(--glowc),inset 0 0 calc(var(--s) * .1) var(--glowc);
  animation:pet-hoop 5.5s linear infinite;
}
@keyframes pet-hoop{to{transform:rotateX(68deg) rotate(360deg)}}
/* Роторы светятся кольцом краски: у «Квадро» это и есть его примета —
   четыре огня квадратом, единственный дрон с таким счётом. */
.pet .rotor{
  position:absolute;width:32%;height:32%;border-radius:50%;
  border:1.5px solid var(--eye);
  background:radial-gradient(circle,var(--glowc),transparent 64%);
  box-shadow:0 0 calc(var(--s) * .1) var(--glowc);
  animation:pet-rotor .9s linear infinite;
}
.pet .rotor::after{content:'';position:absolute;inset:32%;border-radius:50%;
  background:linear-gradient(150deg,#9AA0CC,#1A1C2B);}
.pet .rotor.a{left:0;top:16%}.pet .rotor.b{right:0;top:16%}
.pet .rotor.c{left:6%;bottom:6%}.pet .rotor.d{right:6%;bottom:6%}
@keyframes pet-rotor{to{transform:rotate(360deg)}}
/* Гало — ТОНКОЕ кольцо, а не корона лучей. Первая версия рисовала
   `repeating-conic-gradient` (наследство прототипа) и на живом столе читалась
   как мультяшное солнце: лучи забивали силуэт, ради которого шасси и куплено.
   Кольцо даёт тот же «легендарный» сигнал и не спорит с корпусом. */
.pet .halo{
  position:absolute;inset:-4%;border-radius:50%;
  border:1px solid var(--eye);opacity:.55;
  box-shadow:0 0 calc(var(--s) * .14) var(--glowc),inset 0 0 calc(var(--s) * .1) var(--glowc);
  animation:pet-spin 9s linear infinite;
}
@keyframes pet-spin{0%{transform:rotate(0) scale(1)}50%{transform:rotate(180deg) scale(1.04)}
  100%{transform:rotate(360deg) scale(1)}}
/* Герб легендарки: светлый на тёмном корпусе. Тёмный «выгравированный» вариант
   на 22px исчезал полностью — а это единственная деталь, за которую платят. */
.pet .crest{
  position:absolute;left:50%;top:26%;transform:translateX(-50%);
  font-size:calc(var(--s) * .3);line-height:1;color:#fff6d4;
  text-shadow:0 0 calc(var(--s) * .1) var(--eye),0 1px 2px rgba(0,0,0,.9);
}
.pet .crest .emb{font-size:inherit;color:inherit}
/* Метки — выбитые за сессию. Максимум пять: дальше не читается. */
.pet .marks{position:absolute;left:50%;bottom:-6%;transform:translateX(-50%);display:flex;gap:2px}
.pet .marks i{width:2px;height:22%;max-height:7px;border-radius:1px;background:var(--eye);opacity:.9;
  box-shadow:0 0 4px var(--glowc)}

/* ── шасси ────────────────────────────────────────────────────────────────── */
/* Различаются ПРОПОРЦИЕЙ, а не деталями: узкая вертикаль, квадрат огней, шар,
   плоская широкая V, колонна, размах крыла, широкий шестиугольник. Именно
   пропорция — единственное, что выживает на 22 пикселях. */

/* Скаут: компактный дротик остриём ВВЕРХ, одна круглая линза, крылья прижаты.
   Стартовый дрон обязан объяснять категорию за полсекунды, поэтому у него
   самая простая примета в наборе — одна точка. */
.ch-scout .hull{top:18%;width:40%;height:62%;
  clip-path:polygon(50% 0,100% 32%,86% 88%,50% 100%,14% 88%,0 32%)}
.ch-scout .lens{top:38%;width:22%;height:22%}
/* Крылья короткие и опущены назад: любой их вылет за корпус превращает Скаута
   в Ворона, а это два разных предмета в одной витрине. */
.ch-scout .wing{top:40%;width:24%;height:26%}
.ch-scout .wing.l{left:6%}.ch-scout .wing.r{right:6%}

/* Квадро: маленькое ядро и четыре светящихся ротора — «четыре огня». */
.ch-quad .hull{top:38%;width:32%;height:26%;
  clip-path:polygon(50% 0,100% 30%,86% 100%,14% 100%,0 30%)}
.ch-quad .lens{top:44%;width:13%;height:13%}

/* Орбита: шар и кольцо. Свет здесь — само кольцо, линза лишь ядро шара. */
.ch-orbit .hull{top:30%;width:40%;height:40%;clip-path:none;border-radius:50%;
  background:radial-gradient(circle at 34% 26%,#FFFFFF,#C3C8F0 22%,#6A7098 52%,var(--eye) 96%)}
.ch-orbit .hull::after{inset:var(--edge);border-radius:50%;clip-path:none;
  background:radial-gradient(circle at 36% 28%,#5A5F86,#22243A 54%,#0A0A12)}
.ch-orbit .lens{top:44%;width:12%;height:12%}
.ch-orbit .hoop{left:-2%;width:104%;height:44%;border-width:2.5px}

/* Шеврон: широкая плоская V. Свет — длинная линия по всей передней кромке;
   единственный дрон, чья примета горизонтальна во всю ширину кадра. */
.ch-chevron .hull{top:32%;width:94%;height:34%;
  clip-path:polygon(50% 0,100% 58%,88% 100%,50% 44%,12% 100%,0 58%)}
/* Свет висит на `::before`, а не на самой линзе, — и это не стиль, а
   необходимость: свечение сложной формы даётся `drop-shadow`, то есть
   `filter`, а биты (`pet-bright`, `pet-blink`) анимируют ровно `filter` у
   `.lens`. Оставь глоу на линзе — и на каждой вспышке V-линия Шеврона
   гаснет вместо того, чтобы разгораться. Ворон и Арбитр устроены так же. */
.ch-chevron .lens{top:22%;left:50%;width:66%;height:26%;border-radius:0;background:none;
  box-shadow:none}
.ch-chevron .lens::before{
  content:'';position:absolute;inset:0;
  /* Полоса повторяет излом крыла, поэтому свет ложится «по кромке», а не
     плашкой поверх неё. */
  clip-path:polygon(50% 0,100% 58%,92% 82%,50% 26%,8% 82%,0 58%);
  background:linear-gradient(90deg,var(--eye),#fff 50%,var(--eye));
  filter:drop-shadow(0 0 calc(var(--s) * .1) var(--eye))
         drop-shadow(0 0 calc(var(--s) * .26) var(--glowc));
}

/* Страж: вертикальная колонна и щель во всю высоту. */
.ch-sentinel .hull{top:10%;width:40%;height:80%;
  clip-path:polygon(50% 0,100% 14%,88% 90%,50% 100%,12% 90%,0 14%)}
.ch-sentinel .wing{top:20%;width:24%;height:24%}
.ch-sentinel .wing.l{left:-2%}.ch-sentinel .wing.r{right:-2%}
.ch-sentinel .slit{top:22%;height:50%}

/* Ворон: узкое тело и крылья, ПОДНЯТЫЕ вверх-наружу, — силуэт хищника перед
   ударом. Форма намеренно противоположна и Скауту (компактный треугольник
   остриём вверх), и Шеврону (широкая Λ): здесь получается V с телом
   посередине, и на 22px эти три предмета не сливаются.
   Примета — ПАРА огней: два глаза против одного у Скаута. Счёт огней
   различим даже там, где форма уже нет. */
.ch-raven .hull{top:26%;width:30%;height:48%;
  clip-path:polygon(50% 0,100% 24%,78% 100%,22% 100%,0 24%)}
.ch-raven .wing{top:12%;width:44%;height:46%;
  clip-path:polygon(100% 0,100% 32%,0 100%,0 64%)}
.ch-raven .wing.l{left:-2%;transform:scaleX(-1)}
.ch-raven .wing.r{right:-2%}
.ch-raven .lens{top:36%;width:34%;height:13%;background:none;box-shadow:none;border-radius:0}
.ch-raven .lens::before,.ch-raven .lens::after{
  content:'';position:absolute;top:0;width:38%;height:100%;border-radius:50%;background:var(--eye);
  box-shadow:0 0 calc(var(--s) * .14) var(--eye),0 0 calc(var(--s) * .32) var(--glowc);
}
.ch-raven .lens::before{left:0}
.ch-raven .lens::after{right:0}

/* Арбитр: широкий шестиугольник и корона из трёх огней над гербом. */
.ch-arbiter .hull{top:16%;width:64%;height:66%;
  clip-path:polygon(50% 0,100% 24%,88% 90%,50% 100%,12% 90%,0 24%);
  --rim:linear-gradient(158deg,#FFF6D2 0 14%,#E7C879 32%,#9C7B2E 58%,#4A3A12 82%,var(--eye));
  --core:linear-gradient(158deg,#4B3F1C 0 16%,#251E0D 50%,#0B0906)}
.ch-arbiter .lens{top:52%;left:50%;width:52%;height:9%;background:none;box-shadow:none;border-radius:0}
.ch-arbiter .lens::before{
  content:'';position:absolute;inset:0;border-radius:99px;
  /* Три огня одной подложкой: узлов не прибавилось, а корона читается. */
  background:
    radial-gradient(circle at 12% 50%,var(--eye) 0 34%,transparent 38%),
    radial-gradient(circle at 50% 50%,var(--eye) 0 40%,transparent 44%),
    radial-gradient(circle at 88% 50%,var(--eye) 0 34%,transparent 38%);
  filter:drop-shadow(0 0 calc(var(--s) * .12) var(--eye))
         drop-shadow(0 0 calc(var(--s) * .28) var(--glowc));
}

/* Деталь `slit` не добавляет вторую линзу, а ЗАМЕНЯЕТ её. */
.dt-slit .lens{display:none}

/* ── обработка корпуса (слот краски) ──────────────────────────────────────── */
/* Краска красит И кант, И ядро: если менять только ядро, все шасси остаются
   одинаково серебряными по контуру — то есть отличие, за которое заплатили,
   пропадает ровно на той дистанции, где дрона и видят. */
.hl-carbon{
  --rim:linear-gradient(158deg,#D6DAF4 0 12%,#787EA6 34%,#3A3E5C 66%,var(--eye));
  --core:repeating-linear-gradient(45deg,#22233A 0 2px,#171827 2px 4px)}
.hl-chrome{
  --rim:linear-gradient(158deg,#FFFFFF 0 18%,#DDE3FA 34%,#8992BE 58%,#42496E 84%,var(--eye));
  --core:linear-gradient(158deg,#9AA2C6 0 8%,#4E5474 38%,#171A28)}
.hl-enamel{
  --rim:linear-gradient(158deg,#EDEAFF 0 14%,#A79CE4 36%,#5B4E9E 66%,var(--eye));
  --core:linear-gradient(158deg,#4A4270 0 18%,#282246 52%,#0D0A18)}
.hl-foil{
  --rim:linear-gradient(158deg,#FFF7D4 0 14%,#EBCB7C 32%,#A98430 60%,var(--eye));
  --core:linear-gradient(158deg,#57471C 0 16%,#2C2410 50%,#0C0A05)}
.hl-holo{
  --rim:linear-gradient(158deg,#D8FBFF 0 12%,#FFB6E4 32%,#B7A6FF 56%,#5AE8FF 80%,var(--eye));
  --core:linear-gradient(158deg,#2E3A66 0 16%,#3A1F52 52%,#120B24)}

/* ── след ─────────────────────────────────────────────────────────────────── */
.pet .rig::after{content:'';position:absolute;left:50%;bottom:-4%;width:0;height:0;opacity:0}
.tr-spark .rig::after,.tr-smoke .rig::after,.tr-ion .rig::after{
  width:22%;height:34%;margin-left:-11%;border-radius:99px;opacity:.55;
  animation:pet-trail 1.8s ease-in-out infinite;
}
.tr-spark .rig::after{background:linear-gradient(180deg,var(--eye),transparent);filter:blur(1.5px)}
.tr-smoke .rig::after{background:linear-gradient(180deg,rgba(200,200,230,.75),transparent);filter:blur(3px)}
.tr-ion .rig::after{background:linear-gradient(180deg,#a8f0ff,transparent);filter:blur(2px)}
@keyframes pet-trail{0%,100%{opacity:.3;transform:scaleY(.8)}50%{opacity:.7;transform:scaleY(1.25)}}

/* ── аура: единственный слой, читаемый на 22px ────────────────────────────── */
.au-pulse .rig::before,.au-ion .rig::before,.au-halo .rig::before{
  content:'';position:absolute;inset:-16%;border-radius:50%;pointer-events:none;z-index:-1;
  background:radial-gradient(circle,var(--glowc),transparent 64%);
}
.au-pulse .rig::before{animation:pet-aura 2.8s ease-in-out infinite}
.au-ion .rig::before{opacity:.5;animation:pet-aura 4.2s ease-in-out infinite}
.au-halo .rig::before{inset:-20%;animation:pet-aura 3.4s ease-in-out infinite}
@keyframes pet-aura{0%,100%{opacity:.22;transform:scale(.92)}50%{opacity:.5;transform:scale(1.06)}}

/* ── idle: 90% времени игрок видит именно это ─────────────────────────────── */
/* Пять петель, и это пять РАЗНЫХ движений, а не пять длительностей одного.
   Первая версия отличала их только скоростью `translateY`, поэтому характер,
   обещанный в описании предмета («роторы», «кольцо», «покерфейс»), на столе
   не читался вообще: шасси за 400k выглядело как стартовое. Каждая петля
   ниже отвечает своей строчке из каталога. */
.idle-hover .rig{animation:pet-hover 4.4s ease-in-out infinite}
.idle-rotor .rig{animation:pet-vib 2.2s ease-in-out infinite}
.idle-orbit .rig{animation:pet-drift 6.2s ease-in-out infinite}
.idle-scan .rig{animation:pet-yaw 5.4s ease-in-out infinite}
.idle-still .rig{animation:pet-tick 7s cubic-bezier(.2,.9,.3,1) infinite}

/* Дрейф восьмёркой с наклоном по ходу движения: корпус «опирается» на
   встречный поток. Наклон и есть то, что отличает полёт от лифта. */
@keyframes pet-hover{
  0%,100%{transform:translate3d(0,-4%,0) rotate(-2.5deg)}
  25%{transform:translate3d(2.5%,0,0) rotate(1.5deg)}
  50%{transform:translate3d(0,4%,0) rotate(2.5deg)}
  75%{transform:translate3d(-2.5%,0,0) rotate(-1.5deg)}
}
/* Квадрокоптер: высокочастотная мелкая дрожь на медленном подъёме. */
@keyframes pet-vib{
  0%,100%{transform:translate3d(0,-2%,0)}
  12%{transform:translate3d(.8%,-.6%,0)}25%{transform:translate3d(-.8%,1%,0)}
  37%{transform:translate3d(.6%,2%,0)}50%{transform:translate3d(-.6%,2.6%,0)}
  62%{transform:translate3d(.8%,1.6%,0)}75%{transform:translate3d(-.8%,.4%,0)}
  87%{transform:translate3d(.6%,-1.2%,0)}
}
/* Орбита: корпус почти неподвижен по вертикали и медленно смещается по
   эллипсу — работу делает кольцо, а не тушка. */
@keyframes pet-drift{
  0%,100%{transform:translate3d(-3%,1%,0)}
  33%{transform:translate3d(2%,-2.5%,0)}
  66%{transform:translate3d(3%,2%,0)}
}
/* Страж: медленное рыскание — «смотрит по сторонам». Разворот настоящий,
   через rotateY, поэтому корпус в профиль сужается. */
@keyframes pet-yaw{
  0%,100%{transform:rotateY(-24deg) translate3d(-2%,0,0)}
  50%{transform:rotateY(24deg) translate3d(2%,0,0)}
}
/* Шеврон: «покерфейс». Почти неподвижен, но раз в цикл делает короткий сухой
   тик — как камера наблюдения. Неподвижность должна быть НАМЕРЕННОЙ, иначе
   она читается как сломанная анимация. */
@keyframes pet-tick{
  0%,54%{transform:translate3d(0,0,0) rotate(0)}
  58%{transform:translate3d(0,-4%,0) rotate(-3deg)}
  64%{transform:translate3d(0,-1%,0) rotate(1deg)}
  70%,100%{transform:translate3d(0,0,0) rotate(0)}
}
/* Линза дышит всегда — это признак «включён». */
.pet .lens,.pet .slit{animation:pet-lens 2.6s ease-in-out infinite}
@keyframes pet-lens{0%,100%{opacity:.72}50%{opacity:1}}

/* MK: уровень виден размером ауры и яркостью, а не новыми деталями —
   ступень не должна ломать силуэт, который игрок уже узнаёт. */
.pet.mk2{filter:saturate(1.12)}
.pet.mk3{filter:saturate(1.25) drop-shadow(0 0 5px var(--glowc))}

/* ── слово, волна, вспышка ────────────────────────────────────────────────── */
.pet .word{
  position:absolute;left:50%;top:-4%;transform:translate(-50%,0);opacity:0;
  font-family:'Rajdhani',var(--font);font-weight:700;font-size:max(11px,calc(var(--s)*.30));
  letter-spacing:.12em;white-space:nowrap;color:var(--eye);text-shadow:0 2px 8px rgba(0,0,0,.95);
}
.pet .wave{position:absolute;inset:12%;border-radius:50%;border:2px solid var(--eye);opacity:0}
.pet .beam{position:absolute;inset:0;opacity:0}
/* Вспышка искр — восемь точек ОДНОЙ подложкой. Классический путь (восемь
   узлов или анимированный box-shadow) стоил бы либо DOM, либо перерисовки
   на каждом кадре; здесь анимируются только transform и opacity, то есть
   вся сцена уезжает в композитор. */
.pet .burst{
  position:absolute;inset:-26%;border-radius:50%;opacity:0;pointer-events:none;
  background:
    radial-gradient(circle at 50% 4%,var(--eye) 0 5%,transparent 6%),
    radial-gradient(circle at 82% 18%,var(--eye) 0 4%,transparent 5%),
    radial-gradient(circle at 96% 52%,var(--eye) 0 5%,transparent 6%),
    radial-gradient(circle at 80% 84%,var(--eye) 0 4%,transparent 5%),
    radial-gradient(circle at 50% 97%,var(--eye) 0 5%,transparent 6%),
    radial-gradient(circle at 18% 84%,var(--eye) 0 4%,transparent 5%),
    radial-gradient(circle at 3% 50%,var(--eye) 0 5%,transparent 6%),
    radial-gradient(circle at 17% 17%,var(--eye) 0 4%,transparent 5%);
  filter:drop-shadow(0 0 calc(var(--s) * .12) var(--glowc));
}

/* ── биты ─────────────────────────────────────────────────────────────────── */
/* КАЖДЫЙ БИТ АНИМИРУЕТ НЕСКОЛЬКО СЛОЁВ. Первая версия двигала только `.rig`,
   и от этого любое событие выглядело одинаково: корпус подпрыгнул. Теперь у
   бита своя партия у корпуса, своя у света и своя у деталей — роторы
   раскручиваются, кольцо ускоряется, крылья складываются. Это и есть разница
   между «объект сдвинулся» и «существо отреагировало».
   Сам бит остаётся ОДНИМ классом: код по-прежнему ставит `b-<kind>`. */

/* Мой ход: приседание с антиципацией, подъём, две вспышки линзы. */
.pet.b-turn .rig{animation:pet-turn 1s cubic-bezier(.34,1.5,.5,1) 1}
.pet.b-turn .lens,.pet.b-turn .slit{animation:pet-bright .5s ease 2}
.pet.b-turn .jet{animation:pet-jet .5s ease-in-out infinite}

/* Колл/чек: короткий кивок и моргание. Самый тихий бит в наборе — он
   случается чаще всех, и любое лишнее движение здесь превращается в шум. */
.pet.b-call .rig{animation:pet-nod .55s ease-out 1}
.pet.b-call .lens,.pet.b-call .slit{animation:pet-blink .55s ease 1}

/* Ставка: замах вниз → удар вверх со сжатием корпуса, форсаж, кольцо. */
.pet.b-bet .rig{animation:pet-bet .78s cubic-bezier(.3,1.6,.5,1) 1}
.pet.b-bet .lens,.pet.b-bet .slit{animation:pet-bright .4s ease 1}
.pet.b-bet .wave{animation:pet-wave .7s ease-out 1}
.pet.b-bet .jet{animation:pet-boost .78s ease-out 1}

/* Наводка: я целюсь — наклон вперёд и суженный яркий свет. */
.pet.b-aim .rig{animation:pet-aim .8s cubic-bezier(.34,1.5,.5,1) 1}
.pet.b-aim .lens,.pet.b-aim .slit{animation:pet-bright .5s ease 2}
/* Наводка: ткнули в меня — отдача и тряска. */
.pet.b-ping .rig{animation:pet-ping 1.1s cubic-bezier(.36,.07,.19,.97) 1}
.pet.b-ping .lens,.pet.b-ping .slit{animation:pet-blink .3s ease 3}
/* Взгляд на победителя: разворот корпуса и вспышка. */
.pet.b-look .rig{animation:pet-look .7s ease-in-out 1}
.pet.b-look .lens,.pet.b-look .slit{animation:pet-bright .45s ease 1}

/* ── торговля: сцены, которые НЕ ЛЕТАЮТ ────────────────────────────────────
   Пока идёт торговля, экран принадлежит тому, кто принимает решение (правило
   П6), и полёты запрещены (решение §5). Взаимодействие выражается тем, что
   осталось: разворотом на цель, выпадом на месте, лучом и общим кадром. */

/* Ответка на ре-рейз: разворот к прежнему агрессору и двойной выпад в его
   сторону. Направление честное — через `--face`/`--lean`, а не через зеркало. */
.pet.b-counter .rig{animation:pet-counter .76s cubic-bezier(.3,1.6,.5,1) 1}
.pet.b-counter .lens,.pet.b-counter .slit{animation:pet-bright .3s ease 2}
.pet.b-counter .jet{animation:pet-boost .5s ease-out 1}
/* Под выпадом: отклон назад и моргание. Реакция короче выпада — так читается,
   кто здесь действует, а кто отвечает. */
.pet.b-flinch .rig{animation:pet-flinch .6s cubic-bezier(.36,.07,.19,.97) 1}
.pet.b-flinch .lens,.pet.b-flinch .slit{animation:pet-blink .3s ease 2}
/* Стердаун: двое остались вдвоём. Медленный наклон в сторону соперника,
   удерживаемый весь такт внимания. Это единственная парная сцена, у которой
   нет ни контакта, ни движения — только направление и время. */
.pet.b-stare .rig{animation:pet-stare 2.4s cubic-bezier(.4,0,.6,1) 1}
.pet.b-stare .lens,.pet.b-stare .slit{animation:pet-glare 2.4s ease-in-out 1}
.pet.b-stare .jet{animation:pet-jet .9s ease-in-out infinite}
/* Мои карты открылись: свет проходит по линзе поперёк. */
.pet.b-scan .rig{animation:pet-hover 4.4s ease-in-out infinite}
.pet.b-scan .lens,.pet.b-scan .slit{animation:pet-scan .9s ease-in-out 2}
/* Посадка: влёт снизу с перелётом и раскруткой. */
.pet.b-arrive .rig{animation:pet-arrive .9s cubic-bezier(.22,1.5,.4,1) 1}
.pet.b-arrive .burst{animation:pet-burst .7s ease-out 1}
/* Новая рука: все дроны коротко «включаются». Дешёвый бит, но именно он
   делает стол населённым в паузе, когда не происходит ничего. */
.pet.b-deal .rig{animation:pet-deal .7s cubic-bezier(.34,1.5,.5,1) 1}
.pet.b-deal .lens,.pet.b-deal .slit{animation:pet-bright .45s ease 1}

/* Сброс — «залипший» бит: дрон спит до конца руки. Крылья складываются,
   роторы замедляются, сопло гаснет. */
.pet.b-fold .rig{animation:pet-fold .9s cubic-bezier(.4,0,.6,1) forwards}
.pet.b-fold .lens,.pet.b-fold .slit{animation:none;opacity:.28}
.pet.b-fold .halo,.pet.b-fold .hoop{opacity:.18}
.pet.b-fold .jet{animation:none;opacity:.15}
.pet.b-fold .rotor{animation-duration:3.4s;opacity:.4}
.pet.b-fold .wing.l{transform:scaleX(-1) rotate(26deg)}
.pet.b-fold .wing.r{transform:rotate(26deg)}

/* Ва-банк: приседание → пуск вверх → зависание. Две волны вразнобой, форсаж,
   искры и слово. Самая громкая точка раздачи и должна выглядеть как пуск. */
.pet.b-allin .rig{animation:pet-allin 1.25s cubic-bezier(.3,1.5,.4,1) 1}
.pet.b-allin .wave{animation:pet-wave .95s ease-out 2}
.pet.b-allin .burst{animation:pet-burst .8s ease-out 1 .18s}
.pet.b-allin .jet{animation:pet-boost 1.25s ease-out 1}
.pet.b-allin .lens,.pet.b-allin .slit{animation:pet-bright .4s ease 3}
.pet.b-allin .word,.pet.b-bust .word{animation:pet-word 1.6s cubic-bezier(.34,1.56,.64,1) 1}

/* Забор банка: бочка через rotateY с подскоком. Первая версия покачивала
   корпус на ±9° — самый приятный момент игры выглядел как «дрон замёрз». */
.pet.b-win .rig{animation:pet-win 1.35s cubic-bezier(.3,1.35,.45,1) 1}
.pet.b-win .burst{animation:pet-burst .9s ease-out 1 .1s}
.pet.b-win .wave{animation:pet-wave 1s ease-out 1 .12s}
.pet.b-win .lens,.pet.b-win .slit{animation:pet-bright .45s ease 2}
.pet.b-win .rotor{animation-duration:.3s}
.pet.b-win .hoop{animation-duration:1.2s}

/* Бэдбит: срыв в штопор с дымом и восстановлением. Тильт должен читаться как
   потеря управления, а не как ещё одна тряска. */
.pet.b-badbeat .rig{animation:pet-bad 1.5s cubic-bezier(.36,.07,.19,.97) 1}
.pet.b-badbeat .lens,.pet.b-badbeat .slit{animation:pet-flicker 1.5s linear 1}
.pet.b-badbeat .jet{animation:pet-sputter 1.5s linear 1}
.pet.b-badbeat .rotor{animation-duration:2.6s}

/* Дуэль держится до конца ран-аута: снимает её код, а не таймер анимации.
   Дыхание учащённое — пауза и так тянется, и дрон обязан её держать. */
.pet.b-duel .rig{animation:pet-duel 1.15s ease-in-out infinite}
.pet.b-duel .lens,.pet.b-duel .slit{animation:pet-lens .8s ease-in-out infinite}
.pet.b-duel .jet{animation:pet-jet .7s ease-in-out infinite}

/* Выбитый падает и остаётся лежать (forwards) — до начала следующей руки. */
.pet.b-bust .rig{animation:pet-bust 1.3s cubic-bezier(.5,0,.9,.6) 1 forwards}
.pet.b-bust .burst{animation:pet-burst .5s ease-out 1}
.pet.b-bust .jet{animation:pet-sputter .6s linear 1;opacity:0}

/* ── парные сцены паузы (docs/COMPANIONS-INTERACTIONS.md) ─────────────────── */
/* ЗДЕСЬ ТОЛЬКО ТЕЛО, ПУТЬ СЧИТАЕТ JS. Перелёт живёт на внешнем узле (`.pet`,
   `Companion.flyTo`), потому что расстояние между участниками известно лишь в
   рантайме и в пикселях вьюпорта; кейфреймы ниже отвечают за то, ЧТО корпус
   делает по дороге и в момент контакта.
   Раньше эти три сцены пытались выразить и путь тоже — процентами от
   собственного кадра. Потолок такого «полёта» — 12 пикселей у чужого дрона,
   поэтому стычка выглядела дрожью на месте, а облёт чиплидера не доходил до
   чиплидера. */

/* Стычка: замах от соседа (пока JS ещё не тронул дрона), крен по дороге, сжатие
   на контакте и оседание после. Контакт на 46% — ровно там, где режиссёр
   ставит вспышку. */
.pet.b-nudge .rig{animation:pet-charge 1.4s cubic-bezier(.34,1.3,.5,1) 1}
.pet.b-nudge .lens,.pet.b-nudge .slit{animation:pet-bright .35s ease 2}
.pet.b-nudge .jet{animation:pet-boost .9s ease-out 1}
/* Меня толкнули: отброс с закруткой и двойное моргание — «ответный бип». */
.pet.b-nudged .rig{animation:pet-knock .8s cubic-bezier(.24,1.4,.4,1) 1}
.pet.b-nudged .lens,.pet.b-nudged .slit{animation:pet-blink .26s ease 3}

/* Эскорт: крен в поворотах и постоянный форсаж. Путь — три отрезка от JS. */
.pet.b-escort .rig{animation:pet-bank 2.8s cubic-bezier(.45,0,.55,1) 1}
.pet.b-escort .jet{animation:pet-boost 2.8s ease-out 1}

/* Синхрон: зеркальные бочки в одном такте, уже на месте встречи. */
.pet.b-sync .rig{animation:pet-sync 1s cubic-bezier(.3,1.4,.5,1) 1}
.pet.b-sync .burst{animation:pet-burst .7s ease-out 1 .3s}
.pet.b-sync .lens,.pet.b-sync .slit{animation:pet-bright .5s ease 2 .2s}

/* Кулак: вынос корпуса вперёд, удар, отдача. Симметрично у обоих — это
   единственный класс сцен, где симметрия и есть смысл (согласие). */
.pet.b-bump .rig{animation:pet-bump 1.5s cubic-bezier(.3,1.5,.45,1) 1}
.pet.b-bump .lens,.pet.b-bump .slit{animation:pet-bright .4s ease 2 .5s}
.pet.b-bump .wave{animation:pet-wave .7s ease-out 1 .55s}

/* Проводы: наклон в сторону опустевшего места и свет в пол. Дешёвая сцена, а
   стол после неё выглядит так, будто у него есть манеры. */
.pet.b-farewell .rig{animation:pet-farewell .9s ease-in-out 1}
.pet.b-farewell .lens,.pet.b-farewell .slit{animation:pet-dip .9s ease-in-out 1}

/* Проигравший дуэли: отброс назад, крен, серый корпус — и так до новой руки. */
.pet.b-lose .rig{animation:pet-lose 1.2s cubic-bezier(.36,.07,.19,.97) forwards}
.pet.b-lose .lens,.pet.b-lose .slit{animation:pet-flicker 1.2s linear 1;opacity:.3}
.pet.b-lose .jet{animation:pet-sputter .8s linear 1;opacity:.1}

/* ── жесты игрока (§6) ────────────────────────────────────────────────────── */
/* Уважение: глубокий поклон с задержкой внизу. Медленнее всех прочих жестов —
   уважение не бывает быстрым. */
.pet.b-respect .rig{animation:pet-respect 1.1s cubic-bezier(.4,0,.4,1) 1}
.pet.b-respect .lens,.pet.b-respect .slit{animation:pet-dip 1.1s ease-in-out 1}
/* Ответный кивок — короткая версия того же движения. Один жест, две длины:
   так видно, кто начал. */
.pet.b-bow .rig{animation:pet-respect .7s cubic-bezier(.4,0,.4,1) 1}
/* «gg»: подъём с раскрытием и вспышка — под залп монет, который рисует сцена. */
.pet.b-gg .rig{animation:pet-gg 1s cubic-bezier(.3,1.5,.45,1) 1}
.pet.b-gg .lens,.pet.b-gg .slit{animation:pet-bright .4s ease 2}
.pet.b-gg .wave{animation:pet-wave .8s ease-out 1}
/* Поддёвка: тот же двойной выпад, что у ответки, но резче и с форсажем. Форма
   общая намеренно: «я тебя задел» — одно движение, поводы разные. */
.pet.b-taunt .rig{animation:pet-counter .9s cubic-bezier(.28,1.7,.5,1) 1}
.pet.b-taunt .lens,.pet.b-taunt .slit{animation:pet-bright .28s ease 3}
.pet.b-taunt .jet{animation:pet-boost .6s ease-out 1}

/* ── трюки по тапу (§6.2) ─────────────────────────────────────────────────── */
/* Свой дрон — единственный узел слоя, который ПРИНИМАЕТ нажатия (второй —
   кольцо жестов): весь `#companions` прозрачен для мыши, и здесь оно включается
   обратно. Чужие дроны остаются прозрачными намеренно — под ними лежит место
   соперника со своими тапом и долгим нажатием (§6), и перехватывать их
   двадцатью шестью пикселями поверх аватара нельзя.

   `.flying` гасит нажатия на время сцены: летящий дрон возит свою рамку через
   пол-экрана, и клик по нему на середине пути — это клик по случайной точке
   стола. Занятость дрона проверяет и код (`tricks.busy`), но рамка не должна
   мешать даже там, где под ней есть на что нажать. */
#companions .pet.mine{pointer-events:auto;cursor:pointer;touch-action:manipulation;
  -webkit-tap-highlight-color:transparent}
#companions .pet.flying{pointer-events:none}
/* Наведение — единственная подсказка, что дрона можно трогать. Только там, где
   мышь есть: на телефоне `:hover` залипает после тапа. */
@media (hover:hover){
  #companions .pet.mine:hover .rig{filter:drop-shadow(0 0 calc(var(--s) * .16) var(--glowc))}
}

/* Перелёт на другую сторону карт: бочка в пути. Путь — две ноги через точку над
   картами, их ведёт JS; здесь только корпус. */
.pet.b-flip .rig{animation:pet-roll .7s cubic-bezier(.32,.9,.28,1) 1}
.pet.b-flip .lens,.pet.b-flip .slit{animation:pet-bright .4s ease 2}
.pet.b-flip .jet{animation:pet-boost .7s ease-out 1}
/* Облёт парковки: тот же крен, что у эскорта, — форма «иду по кругу» в
   категории одна, и разгадывать её второй раз игрок не должен. */
.pet.b-orbit .rig{animation:pet-bank 1.4s cubic-bezier(.45,0,.55,1) 1}
.pet.b-orbit .jet{animation:pet-boost 1.4s ease-out 1}
/* Нырок: нос вниз на провале, задирается на свече. */
.pet.b-dive .rig{animation:pet-dive .9s cubic-bezier(.36,.07,.19,.97) 1}
.pet.b-dive .lens,.pet.b-dive .slit{animation:pet-bright .35s ease 1 .45s}
.pet.b-dive .jet{animation:pet-boost .9s ease-out 1}
/* Двойная бочка на месте — самый дешёвый ответ на тап и самый частый. */
.pet.b-roll .rig{animation:pet-roll .45s cubic-bezier(.4,0,.6,1) 2}
.pet.b-roll .burst{animation:pet-burst .6s ease-out 1 .3s}
.pet.b-roll .lens,.pet.b-roll .slit{animation:pet-bright .45s ease 2}
/* Радость: два подскока разной высоты и волна. Второй ниже первого — так это
   читается как «подпрыгнул», а не как «повис на пружине». */
.pet.b-cheer .rig{animation:pet-cheer .9s cubic-bezier(.3,1.5,.45,1) 1}
.pet.b-cheer .wave{animation:pet-wave .7s ease-out 1 .1s}
.pet.b-cheer .lens,.pet.b-cheer .slit{animation:pet-bright .4s ease 2}
/* Встряска: частая мелкая дрожь с закруткой — «отряхнулся». Тело у неё общее с
   отдачей от наводки, но короче и без отлёта: тап — не удар. */
.pet.b-shake .rig{animation:pet-shake .6s cubic-bezier(.36,.07,.19,.97) 1}
.pet.b-shake .lens,.pet.b-shake .slit{animation:pet-blink .2s ease 3}
.pet.b-shake .rotor{animation-duration:.4s}

/* ── подписи легендарок ───────────────────────────────────────────────────── */
/* `signature` объявлен в домене и ТРЕБУЕТСЯ бюджетом легендарной ступени
   (art.js), то есть за него заплачено 900 гемов, — а CSS у него не было
   вовсе: `sg-crown` и `sg-lap` доезжали до DOM и не делали ничего.
   Обе сцены заменяют обычный забор банка, поэтому и висят на `.b-win`. */

/* Арбитр: корпус замирает, вокруг раскрывается корона света и бьёт герб. */
.sg-crown.b-win .rig{animation:pet-crown 1.7s cubic-bezier(.25,1.2,.4,1) 1}
.sg-crown.b-win .halo{animation:pet-crown-halo 1.7s cubic-bezier(.2,.9,.3,1) 1}
.sg-crown.b-win .crest{animation:pet-crest 1.7s ease-out 1}
.sg-crown.b-win .burst{animation:pet-burst 1.1s ease-out 1 .22s}
/* Чемпион: круг почёта — настоящий облёт по эллипсу с креном в поворотах. */
.sg-lap.b-win .rig{animation:pet-lap 2.1s cubic-bezier(.4,0,.6,1) 1}
.sg-lap.b-win .jet{animation:pet-boost 2.1s ease-out 1}
.sg-lap.b-win .burst{animation:pet-burst .9s ease-out 1 1.5s}

/* ── ключевые кадры битов ─────────────────────────────────────────────────── */
/* Общее правило хореографии: у любого заметного движения есть ЗАМАХ (кадр в
   противоход) и ПЕРЕЛЁТ (кадр за целевой точкой). Без них движение читается
   механическим — это и было главной претензией к первой версии. */
@keyframes pet-turn{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  18%{transform:translate3d(0,5%,0) scale(1.04,.94)}
  46%{transform:translate3d(0,-16%,0) scale(.96,1.06)}
  70%{transform:translate3d(0,-11%,0) scale(1)}
}
@keyframes pet-nod{
  0%,100%{transform:translate3d(0,0,0) rotate(0)}
  40%{transform:translate3d(0,5%,0) rotate(3deg)}
}
@keyframes pet-bet{
  0%,100%{transform:translate3d(0,0,0) rotate(0) scale(1)}
  16%{transform:translate3d(0,7%,0) rotate(-3deg) scale(1.08,.9)}
  44%{transform:translate3d(0,-22%,0) rotate(4deg) scale(.9,1.14)}
  68%{transform:translate3d(0,-6%,0) rotate(-2deg) scale(1.03,.97)}
}
@keyframes pet-aim{
  0%,100%{transform:translate3d(0,0,0) rotate(0) scale(1)}
  22%{transform:translate3d(0,6%,0) rotate(-4deg) scale(.96)}
  55%{transform:translate3d(0,-12%,0) rotate(6deg) scale(1.1)}
}
@keyframes pet-ping{
  0%,100%{transform:translate3d(0,0,0) rotate(0)}
  14%{transform:translate3d(-9%,-5%,0) rotate(-10deg)}
  32%{transform:translate3d(7%,2%,0) rotate(8deg)}
  50%{transform:translate3d(-5%,-2%,0) rotate(-6deg)}
  70%{transform:translate3d(3%,1%,0) rotate(3deg)}
  85%{transform:translate3d(-1%,0,0) rotate(-1deg)}
}
/* НАПРАВЛЕНИЕ ЧЕСТНОЕ, А НЕ ЗЕРКАЛЬНОЕ. `--face`/`--lean` — составляющие
   единичного вектора на участника сцены; их ставит `Companion.faceTo`. Знак у
   `rotateY` положительный: rotateY(+θ) уводит правую кромку от зрителя, то есть
   корпус разворачивается ВПРАВО, к цели с положительным `--face`. Прежняя
   версия множила на `-38deg` и на `--dir` (+1 = цель справа), то есть
   разворачивала дрона в противоположную от победителя сторону. */
@keyframes pet-look{
  0%,100%{transform:rotateY(0) translate3d(0,0,0)}
  50%{transform:rotateY(calc(38deg * var(--face))) translate3d(calc(5% * var(--face)),-7%,0)}
}
@keyframes pet-deal{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  30%{transform:translate3d(0,-11%,0) scale(1.07)}
  60%{transform:translate3d(0,-2%,0) scale(.99)}
}
@keyframes pet-arrive{
  0%{opacity:0;transform:translate3d(-36%,44%,0) rotate(-24deg) scale(.28)}
  60%{opacity:1;transform:translate3d(3%,-9%,0) rotate(6deg) scale(1.12)}
  100%{opacity:1;transform:translate3d(0,0,0) rotate(0) scale(1)}
}
@keyframes pet-fold{
  0%{transform:translate3d(0,0,0) rotate(0) scale(1)}
  30%{transform:translate3d(0,-3%,0) rotate(2deg)}
  100%{transform:translate3d(0,20%,0) rotate(-9deg) scale(.94)}
}
@keyframes pet-allin{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  14%{transform:translate3d(0,9%,0) scale(1.12,.86)}
  40%{transform:translate3d(0,-34%,0) scale(.88,1.2)}
  58%{transform:translate3d(0,-28%,0) scale(1.12,.92)}
  78%{transform:translate3d(0,-30%,0) scale(1)}
}
/* Бочка: разворот на 360° по Y с подскоком. Плоские фигуры при этом честно
   сжимаются в профиль — за счёт `perspective` на `.pet`. */
@keyframes pet-win{
  0%,100%{transform:translate3d(0,0,0) rotateY(0) scale(1)}
  12%{transform:translate3d(0,7%,0) rotateY(0) scale(1.08,.9)}
  44%{transform:translate3d(0,-26%,0) rotateY(200deg) scale(1.06)}
  72%{transform:translate3d(0,-10%,0) rotateY(360deg) scale(1)}
  88%{transform:translate3d(0,2%,0) rotateY(360deg) scale(1.03,.97)}
}
@keyframes pet-bad{
  0%,100%{transform:translate3d(0,0,0) rotate(0) scale(1)}
  12%{transform:translate3d(-8%,3%,0) rotate(-18deg)}
  26%{transform:translate3d(7%,7%,0) rotate(16deg) scale(.97)}
  42%{transform:translate3d(-6%,11%,0) rotate(-24deg) scale(.94)}
  58%{transform:translate3d(5%,14%,0) rotate(20deg) scale(.92)}
  74%{transform:translate3d(-3%,9%,0) rotate(-10deg) scale(.96)}
  88%{transform:translate3d(1%,3%,0) rotate(4deg)}
}
@keyframes pet-duel{
  0%,100%{transform:translate3d(0,-18%,0) scale(1.06)}
  50%{transform:translate3d(0,-25%,0) scale(1.12)}
}
@keyframes pet-bust{
  0%{transform:translate3d(0,0,0) rotate(0);filter:none;opacity:1}
  18%{transform:translate3d(0,-12%,0) rotate(-8deg) scale(1.06);filter:brightness(1.6)}
  40%{transform:translate3d(4%,-2%,0) rotate(26deg);filter:grayscale(1) brightness(.7)}
  100%{transform:translate3d(10%,54%,0) rotate(128deg) scale(.82);
    filter:grayscale(1) brightness(.25);opacity:0}
}
/* ── тело парных сцен ───────────────────────────────────────────────────────
   Ни один кадр ниже НЕ ВЕЗЁТ дрона к цели — путь считает JS в пикселях
   вьюпорта. Здесь только то, что делает корпус: замах, крен по дороге, удар,
   отдача. Проценты остались процентами собственного кадра, и это правильно:
   тело масштабируется вместе с дроном, а расстояние между игроками — нет. */

/* Разгон и удар. Замах в противоход (22%) успевает сыграть до того, как
   режиссёр включит перелёт; на 46% — контакт со сжатием корпуса, дальше
   оседание. Времена согласованы с `sceneNudge`: замах 170 мс, полёт 380–460. */
@keyframes pet-charge{
  0%,100%{transform:translate3d(0,0,0) rotate(0) scale(1)}
  12%{transform:translate3d(calc(-10% * var(--face)),4%,0) rotate(calc(-6deg * var(--face))) scale(1.06,.94)}
  34%{transform:translate3d(0,-6%,0) rotate(calc(7deg * var(--face))) scale(.95,1.06)}
  46%{transform:translate3d(calc(7% * var(--face)),0,0) rotate(calc(3deg * var(--face))) scale(1.14,.88)}
  62%{transform:translate3d(calc(-3% * var(--face)),-3%,0) rotate(calc(-3deg * var(--face))) scale(.98,1.02)}
}
/* Отброс: уходит ОТ того, кто толкнул (минус `--face`), с закруткой и возвратом
   через перелёт. Резкий вход, мягкий выход — так читается «получил», а не
   «сам решил отодвинуться». */
@keyframes pet-knock{
  0%{transform:translate3d(0,0,0) rotate(0) scale(1)}
  22%{transform:translate3d(calc(-26% * var(--face)),calc(-8% * var(--lean)),0)
    rotate(calc(-16deg * var(--face))) scale(.94,1.05)}
  52%{transform:translate3d(calc(-9% * var(--face)),2%,0) rotate(calc(8deg * var(--face))) scale(1.04,.97)}
  78%{transform:translate3d(calc(3% * var(--face)),0,0) rotate(calc(-3deg * var(--face)))}
  100%{transform:translate3d(0,0,0) rotate(0) scale(1)}
}
/* Крен в поворотах — тело для эскорта. Путь из трёх отрезков ведёт JS, а корпус
   всё это время «опирается» на встречный поток и держит нос по курсу. */
@keyframes pet-bank{
  0%,100%{transform:rotate(0) scale(1)}
  10%{transform:rotate(calc(10deg * var(--face))) scale(1.02)}
  38%{transform:rotate(calc(6deg * var(--face))) scale(1)}
  62%{transform:rotateY(calc(30deg * var(--face))) rotate(calc(-8deg * var(--face)))}
  86%{transform:rotate(calc(-6deg * var(--face)))}
}
/* Кулак: вынос корпуса вперёд, удар на 52% (там же вспышка режиссёра), отдача
   назад и оседание. Ровно один общий кадр — в нём вся сцена. */
@keyframes pet-bump{
  0%,100%{transform:translate3d(0,0,0) rotate(0) scale(1)}
  18%{transform:translate3d(0,5%,0) scale(1.05,.94)}
  40%{transform:translate3d(calc(6% * var(--face)),-4%,0) scale(.96,1.06)}
  52%{transform:translate3d(calc(11% * var(--face)),-2%,0) scale(1.16,.86)}
  68%{transform:translate3d(calc(-7% * var(--face)),-6%,0) rotate(calc(-6deg * var(--face)))}
  84%{transform:translate3d(0,-1%,0) rotate(0) scale(1.02)}
}
/* Проводы: наклон в сторону опустевшего места и медленное выравнивание.
   Единственная сцена без всплеска — в ней смысл именно в отсутствии всплеска. */
@keyframes pet-farewell{
  0%,100%{transform:rotate(0) translate3d(0,0,0)}
  40%{transform:rotate(calc(14deg * var(--face))) translate3d(calc(4% * var(--face)),6%,0)}
  70%{transform:rotate(calc(8deg * var(--face))) translate3d(calc(2% * var(--face)),3%,0)}
}
/* Проигравший дуэли: отброс от банка, крен, потеря цвета. Останавливается
   лежащим (`forwards`) — до начала следующей руки. */
@keyframes pet-lose{
  0%{transform:translate3d(0,0,0) rotate(0) scale(1);filter:none}
  20%{transform:translate3d(calc(-12% * var(--face)),4%,0) rotate(calc(-14deg * var(--face))) scale(.97);
    filter:brightness(1.2)}
  60%{transform:translate3d(calc(-6% * var(--face)),12%,0) rotate(calc(18deg * var(--face))) scale(.93);
    filter:grayscale(.7) brightness(.7)}
  100%{transform:translate3d(0,16%,0) rotate(calc(10deg * var(--face))) scale(.9);
    filter:grayscale(1) brightness(.55)}
}
/* Двойной выпад в сторону цели: замах, выпад, короткий второй, возврат. Общая
   форма для ответки на ре-рейз и для поддёвки — движение одно, поводы разные. */
@keyframes pet-counter{
  0%,100%{transform:translate3d(0,0,0) rotateY(0) scale(1)}
  14%{transform:translate3d(calc(-8% * var(--face)),3%,0) rotateY(calc(14deg * var(--face))) scale(1.05,.95)}
  38%{transform:translate3d(calc(16% * var(--face)),calc(6% * var(--lean)),0)
    rotateY(calc(30deg * var(--face))) scale(.94,1.08)}
  56%{transform:translate3d(calc(4% * var(--face)),0,0) rotateY(calc(22deg * var(--face)))}
  74%{transform:translate3d(calc(12% * var(--face)),calc(4% * var(--lean)),0) rotateY(calc(26deg * var(--face)))}
}
/* Отклон под выпадом: короче и мельче, чем сам выпад. */
@keyframes pet-flinch{
  0%,100%{transform:translate3d(0,0,0) rotate(0)}
  30%{transform:translate3d(calc(-12% * var(--face)),calc(-4% * var(--lean)),0)
    rotate(calc(-9deg * var(--face)))}
  64%{transform:translate3d(calc(3% * var(--face)),1%,0) rotate(calc(3deg * var(--face)))}
}
/* Стердаун: разворот к сопернику, наклон вперёд и УДЕРЖАНИЕ. Почти всё время
   кадра дрон стоит неподвижно развёрнутым — напряжение делает пауза, а не
   движение. */
@keyframes pet-stare{
  0%{transform:rotateY(0) translate3d(0,0,0)}
  16%{transform:rotateY(calc(30deg * var(--face))) translate3d(calc(6% * var(--face)),-6%,0)}
  78%{transform:rotateY(calc(34deg * var(--face))) translate3d(calc(7% * var(--face)),-8%,0) scale(1.03)}
  100%{transform:rotateY(0) translate3d(0,0,0)}
}
/* Поклон: глубокий наклон с задержкой внизу. */
@keyframes pet-respect{
  0%,100%{transform:rotate(0) translate3d(0,0,0)}
  30%{transform:rotate(calc(20deg * var(--face))) translate3d(calc(5% * var(--face)),10%,0) scale(.97)}
  62%{transform:rotate(calc(18deg * var(--face))) translate3d(calc(4% * var(--face)),9%,0) scale(.97)}
}
/* «gg»: подъём с раскрытием — под залп монет, который рисует сцена. */
@keyframes pet-gg{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  22%{transform:translate3d(0,6%,0) scale(1.06,.93)}
  52%{transform:translate3d(0,-20%,0) scale(1.08)}
  78%{transform:translate3d(0,-8%,0) scale(1)}
}
@keyframes pet-sync{
  0%,100%{transform:translate3d(0,0,0) rotateY(0) scale(1)}
  20%{transform:translate3d(0,6%,0) rotateY(0) scale(1.05,.93)}
  55%{transform:translate3d(0,-24%,0) rotateY(180deg) scale(1.08)}
  80%{transform:translate3d(0,-6%,0) rotateY(360deg) scale(1)}
}
/* ── тело трюков (§6.2) ─────────────────────────────────────────────────────
   Как и у парных сцен, путь считает JS: здесь только то, что делает корпус.
   Разница в поводе, а не в устройстве, — и это правильно: игрок должен узнавать
   бочку как бочку, кто бы её ни запустил. */

/* Бочка: разворот на 360° по Y с подскоком и лёгким креном на выходе. Отличие
   от победной (`pet-win`) намеренное: там подскок на четверть кадра и
   торжество, здесь — короткий кувырок, который можно сыграть дважды подряд. */
@keyframes pet-roll{
  0%,100%{transform:translate3d(0,0,0) rotateY(0) rotate(0) scale(1)}
  20%{transform:translate3d(0,-10%,0) rotateY(120deg) scale(1.05)}
  55%{transform:translate3d(0,-14%,0) rotateY(240deg) rotate(4deg) scale(1.04)}
  82%{transform:translate3d(0,-4%,0) rotateY(360deg) rotate(-2deg) scale(1)}
}
/* Нырок: нос вниз на провале, задирается на свече, выравнивается дома. Знак
   крена — по направлению ухода (`--face` ставит `faceTo` перед сценой): дрон,
   ныряющий вправо с креном влево, читается как сбой, а не как манёвр. */
@keyframes pet-dive{
  0%,100%{transform:translate3d(0,0,0) rotate(0) scale(1)}
  18%{transform:translate3d(0,4%,0) rotate(calc(12deg * var(--face))) scale(1.04,.95)}
  46%{transform:translate3d(0,-2%,0) rotate(calc(-14deg * var(--face))) scale(.94,1.08)}
  72%{transform:translate3d(0,-6%,0) rotate(calc(-6deg * var(--face))) scale(1.02)}
}
/* Радость: два подскока, второй ниже первого. */
@keyframes pet-cheer{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  14%{transform:translate3d(0,7%,0) scale(1.08,.9)}
  34%{transform:translate3d(0,-26%,0) scale(.94,1.1)}
  54%{transform:translate3d(0,2%,0) scale(1.06,.94)}
  74%{transform:translate3d(0,-12%,0) scale(.98,1.04)}
  90%{transform:translate3d(0,0,0) scale(1.02,.98)}
}
/* Встряска: частая дрожь по X с мелкой закруткой и без отлёта. */
@keyframes pet-shake{
  0%,100%{transform:translate3d(0,0,0) rotate(0)}
  12%{transform:translate3d(-7%,-2%,0) rotate(-9deg)}
  26%{transform:translate3d(6%,0,0) rotate(8deg)}
  40%{transform:translate3d(-5%,-1%,0) rotate(-7deg)}
  54%{transform:translate3d(4%,1%,0) rotate(5deg)}
  70%{transform:translate3d(-3%,0,0) rotate(-3deg)}
  86%{transform:translate3d(1%,0,0) rotate(1deg)}
}

@keyframes pet-crown{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  22%{transform:translate3d(0,-18%,0) scale(1.14)}
  70%{transform:translate3d(0,-14%,0) scale(1.08)}
}
@keyframes pet-crown-halo{
  0%{opacity:.55;transform:rotate(0) scale(1)}
  30%{opacity:1;transform:rotate(160deg) scale(2.1)}
  100%{opacity:.55;transform:rotate(360deg) scale(1)}
}
@keyframes pet-crest{
  0%,100%{transform:translateX(-50%) scale(1);filter:none}
  30%{transform:translateX(-50%) scale(1.7);filter:brightness(2.2) drop-shadow(0 0 8px var(--eye))}
}
/* Круг почёта: широкий эллипс вокруг своего места, крен по ходу. */
@keyframes pet-lap{
  0%,100%{transform:translate3d(0,0,0) rotate(0) scale(1)}
  20%{transform:translate3d(72%,-34%,0) rotate(16deg) scale(.92)}
  40%{transform:translate3d(112%,4%,0) rotate(4deg) scale(.84)}
  60%{transform:translate3d(64%,34%,0) rotate(-14deg) scale(.92)}
  80%{transform:translate3d(-6%,14%,0) rotate(-8deg) scale(1.02)}
}

/* ── ключевые кадры света и деталей ───────────────────────────────────────── */
@keyframes pet-bright{0%,100%{filter:none}45%{filter:brightness(2.1) drop-shadow(0 0 9px var(--eye))}}
@keyframes pet-blink{0%,100%{opacity:.8}40%{opacity:1;filter:brightness(2)}}
/* Свет в пол — поклон и проводы. Не гаснет совсем: погашенная линза уже занята
   сбросом карт, и путать два состояния нельзя. */
@keyframes pet-dip{0%,100%{opacity:.85}45%{opacity:.4}}
/* Пристальный свет: медленно наливается и держится. Ровно противоположно
   моргánию — там всплеск, здесь давление. */
@keyframes pet-glare{
  0%{opacity:.7;filter:none}
  25%,80%{opacity:1;filter:brightness(1.7) drop-shadow(0 0 8px var(--eye))}
  100%{opacity:.75;filter:none}
}
@keyframes pet-scan{0%,100%{opacity:.7;transform:translateX(-50%) scaleX(1)}
  50%{opacity:1;transform:translateX(-50%) scaleX(1.8)}}
/* Мигание с провалами — свет «коротит». Дискретные шаги нужны намеренно:
   плавное затухание читалось бы как усталость, а не как сбой. */
@keyframes pet-flicker{
  0%,9%,13%,38%,44%,71%,100%{opacity:1}
  10%,12%,40%,42%,72%,80%{opacity:.12}
  50%{opacity:.6}
}
@keyframes pet-wave{0%{opacity:.95;transform:scale(.45)}100%{opacity:0;transform:scale(2.8)}}
@keyframes pet-burst{
  0%{opacity:0;transform:scale(.25)}
  18%{opacity:1;transform:scale(.7)}
  100%{opacity:0;transform:scale(1.85) rotate(28deg)}
}
@keyframes pet-boost{
  0%{opacity:.5;transform:translateX(-50%) scaleY(.7)}
  22%{opacity:1;transform:translateX(-50%) scaleY(2.6)}
  100%{opacity:.5;transform:translateX(-50%) scaleY(.9)}
}
@keyframes pet-sputter{
  0%,100%{opacity:.2;transform:translateX(-50%) scaleY(.5)}
  16%{opacity:.9;transform:translateX(-50%) scaleY(1.6)}
  22%,46%{opacity:0}
  52%{opacity:.7;transform:translateX(-50%) scaleY(1.2)}
  60%,88%{opacity:0}
}
@keyframes pet-word{0%{opacity:0;transform:translate(-50%,40%) scale(.6)}
  22%{opacity:1;transform:translate(-50%,-78%) scale(1.06)}
  74%{opacity:1;transform:translate(-50%,-82%) scale(1)}
  100%{opacity:0;transform:translate(-50%,-118%) scale(1)}}

/* ── право на экран ───────────────────────────────────────────────────────── */
/* Чужой дрон невидим и проявляется только на свой момент. Гасим прозрачностью,
   а не display:none — снятие с потока заставило бы браузер пересчитывать
   раскладку шесть раз за раздачу. */
body[data-pet-mode="proposed"] .pet.opp{opacity:0;transition:opacity .3s ease}
body[data-pet-mode="proposed"] .pet.opp.awake{opacity:1}
body[data-pet-mode="off"] #companions{display:none}

/* ── сцена: снаряд ────────────────────────────────────────────────────────── */
/* Дуга — ключевые кадры с переменными (--dx/--dy/--apex), а не пересчёт на
   каждом кадре: анимация уезжает в композитор и не спорит с рендером стола. */
.shot{
  --shotc:#FF3B5C;
  position:absolute;width:14px;height:5px;margin:-2.5px 0 0 -7px;border-radius:99px;
  background:linear-gradient(90deg,transparent,var(--shotc));
  box-shadow:0 0 8px var(--shotc),0 0 18px var(--shotc);
  animation-name:shot-fly;animation-timing-function:linear;animation-fill-mode:forwards;
}
.shot::after{
  content:'';position:absolute;right:100%;top:50%;width:22px;height:3px;margin-top:-1.5px;
  background:linear-gradient(90deg,transparent,var(--shotc));filter:blur(2px);opacity:.8;
}
.shot-brand{width:10px;height:10px;margin:-5px 0 0 -5px;border-radius:2px;transform:rotate(45deg);
  background:var(--shotc)}
@keyframes shot-fly{
  0%{transform:translate(0,0) rotate(var(--ang)) scale(.5);opacity:0}
  12%{opacity:1}
  50%{transform:translate(calc(var(--dx) * .5),calc(var(--dy) * .5 - var(--apex))) rotate(var(--ang)) scale(1)}
  100%{transform:translate(var(--dx),var(--dy)) rotate(var(--ang)) scale(.9);opacity:1}
}

/* ── сцена: кольца ────────────────────────────────────────────────────────── */
.fxring{
  --shotc:#FF3B5C;
  position:absolute;width:18px;height:18px;margin:-9px 0 0 -9px;border-radius:50%;
  border:2px solid var(--shotc);animation-timing-function:ease-out;animation-fill-mode:forwards;
}
.fxring-aim{animation-name:ring-aim;border-style:dashed}
.fxring-hit{animation-name:ring-hit;box-shadow:0 0 18px var(--shotc)}
.fxring-flare{animation-name:ring-flare;background:radial-gradient(circle,var(--shotc),transparent 62%);border:0}
.fxring-emp{animation-name:ring-emp;border-width:3px}
@keyframes ring-aim{0%{opacity:0;transform:scale(3.4) rotate(0)}
  40%{opacity:1}100%{opacity:.9;transform:scale(1.5) rotate(140deg)}}
@keyframes ring-hit{0%{opacity:1;transform:scale(.3)}100%{opacity:0;transform:scale(2.8)}}
@keyframes ring-flare{0%{opacity:0;transform:scale(.4)}30%{opacity:1;transform:scale(1.8)}
  100%{opacity:0;transform:scale(2.4)}}
@keyframes ring-emp{0%{opacity:.95;transform:scale(.4)}100%{opacity:0;transform:scale(22)}}

/* ── сцена: луч, монеты, слово, затемнение ────────────────────────────────── */
.petbeam{
  --shotc:#2DE2C5;
  position:absolute;height:3px;margin-top:-1.5px;transform-origin:0 50%;
  transform:rotate(var(--ang));border-radius:99px;
  background:linear-gradient(90deg,var(--shotc),transparent);
  box-shadow:0 0 10px var(--shotc);
  animation-name:beam-in;animation-timing-function:ease-out;animation-fill-mode:forwards;
}
.petbeam-aim{height:2px;opacity:.8;background:linear-gradient(90deg,transparent,var(--shotc))}
@keyframes beam-in{0%{opacity:0;transform:rotate(var(--ang)) scaleX(0)}
  25%{opacity:1;transform:rotate(var(--ang)) scaleX(1)}
  100%{opacity:0;transform:rotate(var(--ang)) scaleX(1)}}

.petcoin{
  --shotc:#FFC24B;
  position:absolute;width:8px;height:8px;margin:-4px 0 0 -4px;border-radius:50%;
  background:radial-gradient(circle at 35% 30%,#fff3c9,var(--shotc));
  box-shadow:0 0 6px var(--shotc);
  animation:coin-fly 1s ease-out forwards;
}
@keyframes coin-fly{0%{opacity:0;transform:translate(0,0) scale(.4)}
  20%{opacity:1}
  100%{opacity:0;transform:translate(var(--dx),var(--dy)) rotate(var(--rot)) scale(1)}}

.fxword{
  --shotc:#FF3B5C;
  position:absolute;transform:translate(-50%,0);
  font-family:'Rajdhani',var(--font);font-weight:700;font-size:13px;letter-spacing:.14em;
  white-space:nowrap;color:var(--shotc);text-shadow:0 2px 10px rgba(0,0,0,.95);
  animation:pet-word cubic-bezier(.34,1.56,.64,1) 1 forwards;
}

/* Камеру берёт ТОЛЬКО сцена выбивания и только на широком экране: на телефоне
   затемнение читается как обрыв связи, а не как драматургия (см. stage.dim). */
.petdim{position:absolute;inset:0;background:#05030c;opacity:0;
  animation:pet-dim ease-in-out 1 forwards}
@keyframes pet-dim{0%,100%{opacity:0}18%,72%{opacity:.14}}

/* ── добавочные классы на узлах арены ─────────────────────────────────────── */
/* Тряска места при попадании. Базовый transform места ВОСПРОИЗВЕДЁН в
   ключевых кадрах: `.seat` центрируется через translate(-50%,-50%), и обычный
   translateX сбил бы его позицию. */
.seat.pet-hit{animation:pet-shake-seat .4s ease 1}
@keyframes pet-shake-seat{
  0%,100%{transform:translate(-50%,-50%)}
  20%{transform:translate(-50%,-50%) translateX(calc(var(--shake,3px) * -1))}
  45%{transform:translate(-50%,-50%) translateX(var(--shake,3px))}
  70%{transform:translate(-50%,-50%) translateX(calc(var(--shake,3px) * -.6))}
}
.myseat.pet-hit{animation:pet-shake-my .4s ease 1}
@keyframes pet-shake-my{
  0%,100%{transform:translateX(-50%)}
  20%{transform:translateX(-50%) translateX(calc(var(--shake,3px) * -1))}
  45%{transform:translateX(-50%) translateX(var(--shake,3px))}
  70%{transform:translateX(-50%) translateX(calc(var(--shake,3px) * -.6))}
}

/* Клеймо (`st_brand`): метка на плашке имени жертвы до конца её сессии. */
.info.pet-branded{position:relative}
.info.pet-branded::before{
  content:'';position:absolute;left:-3px;top:-3px;width:7px;height:7px;border-radius:2px;
  background:#FF3B5C;box-shadow:0 0 7px #FF3B5C;transform:rotate(45deg);
  animation:pet-brand 2.4s ease-in-out infinite;
}
@keyframes pet-brand{0%,100%{opacity:.55}50%{opacity:1}}

/* Лазерная точка наводки: живёт на аватаре цели 1.5 с. Обещана проектом
   (§8.3.1) с самого начала и всё это время не существовала — от наводки
   оставался только луч, который гаснет за 0.9 с, и «ткнуть пальцем» не
   оставляло следа ровно там, куда ткнули. */
.petdot{
  position:absolute;left:50%;top:50%;width:9px;height:9px;margin:-4.5px 0 0 -4.5px;
  border-radius:50%;background:var(--shotc,#FF3B5C);pointer-events:none;z-index:13;
  box-shadow:0 0 8px var(--shotc,#FF3B5C),0 0 18px var(--shotc,#FF3B5C);
  animation:pet-dot 1.5s linear 1 forwards;
}
@keyframes pet-dot{
  0%{opacity:0;transform:scale(3.2)}
  14%{opacity:1;transform:scale(1)}
  70%{opacity:1;transform:scale(1)}
  76%{opacity:.35}
  82%{opacity:1}
  100%{opacity:0;transform:scale(.8)}
}

/* ── выбор жеста (§6) ─────────────────────────────────────────────────────── */
/* Единственный узел категории, который ПРИНИМАЕТ нажатия: слой компаньонов
   насквозь прозрачен для мыши (`pointer-events:none`), и здесь оно включается
   обратно — иначе кольцо жестов невозможно нажать. Живёт в слое, а не в
   `#seats`: места пересобираются на каждом снимке стола и унесли бы пикер с
   собой посреди выбора. */
.petpick{
  position:absolute;display:flex;gap:6px;padding:6px 7px;border-radius:999px;
  transform:translate(-50%,-50%);pointer-events:auto;z-index:6;
  background:rgba(8,6,20,.86);border:1px solid var(--bord,rgba(45,226,197,.28));
  backdrop-filter:blur(8px);box-shadow:0 8px 24px rgba(0,0,0,.6);
  animation:pet-pick-in .18s cubic-bezier(.34,1.5,.5,1) 1;
}
.petpick button{
  width:34px;height:34px;border:0;border-radius:50%;cursor:pointer;
  background:rgba(255,255,255,.07);color:#EAF2FF;font-family:'Rajdhani',var(--font);
  font-weight:700;font-size:15px;line-height:1;display:grid;place-items:center;
}
.petpick button:active{transform:scale(.92)}
.petpick button .ti{font-size:17px}
@keyframes pet-pick-in{0%{opacity:0;transform:translate(-50%,-40%) scale(.86)}
  100%{opacity:1;transform:translate(-50%,-50%) scale(1)}}

/* ── доступность ──────────────────────────────────────────────────────────── */
/* «Меньше движения» — не опция категории, а системная настройка человека.
   Дрон остаётся (он часть образа), но перестаёт двигаться; сцены сводятся к
   вспышке и слову — их длительность обнуляет JS, а перелёты не запускаются
   вовсе (`Companion._travel`). */
@media (prefers-reduced-motion:reduce){
  .pet,.pet *,.shot,.fxring,.petbeam,.petcoin,.petdim,.petdot,.petpick,
  .seat.pet-hit,.myseat.pet-hit,.info.pet-branded::before{animation:none!important}
  .pet .lens,.pet .slit{opacity:.9}
  .pet .wing,.pet .fin{transition:none}
  body[data-pet-mode="proposed"] .pet.opp{transition:none}
}
