/* Живые персонажи (участок chars): дыхание, моргание, привычки ролей, танец победителей на итогах.
   Обёртки lv-* рисует characters.js. Где оживает: лицо открытой карты (.flip.is-open .portrait),
   герой в комнате (.scene .s-hero), сцена итогов (.end-stage). В маленьких аватарах списков — тишина.
   Только transform и opacity. Пауза: .lv-off (хозяин вне экрана) и html.lv-hidden (вкладка скрыта) —
   их ставит characters.js; при prefers-reduced-motion всё неподвижно.
   Порядок важен: правила ролей — (0,2,0), отмены в конце файла — не ниже (0,2,0). */

:root {
  --ease-sway: cubic-bezier(.45, 0, .55, 1); /* вдох-выдох и покачивание: мягко с обеих сторон */
  --ch-smoke: #E2D7C5;
  --ch-steam: #E2D7C5;
  --ch-glint: #FFF6E2;
  --beat: 1.1s; /* такт танца на итогах */
}
:root[data-theme="light"] { --ch-smoke: #8A7D72; --ch-steam: #FFFCF7; --ch-glint: #FFFCF7; }

/* ── опоры: координаты рисунка 160×160 ── */
.ch .lv { transform-box: view-box; }
.ch .lv-breath { transform-origin: 80px 164px; }
.ch .lv-head { transform-origin: 80px 104px; }
.ch .lv-top { transform-origin: 80px 57px; }
.ch .lv-prop { transform-origin: 80px 120px; }
.ch .lv-rope { transform-origin: 107px 104px; }
.ch .lv-page { transform-origin: 80px 97px; }
.ch :is(.lv-blink, .lv-ring, .lv-glint, .lv-spark, .lv-coin-s, .lv-puff) { transform-box: fill-box; transform-origin: 50% 50%; }
.ch--lover .lv-top { transform-origin: 99px 53px; }
.ch--lawyer .lv-prop { transform-origin: 122px 137px; }
.ch .lv-fx { display: none; }
.ch .fx-smoke { stroke: var(--ch-smoke); }
.ch .fx-puff { fill: var(--ch-steam); }
.ch .fx-glint { fill: var(--ch-glint); }
/* Базовое состояние декоративной анимации — невидимое. */
.ch :is(.lv-ring, .lv-glint, .lv-coin, .lv-puff) { opacity: 0; }

/* Свой ритм у каждой роли: сдвиг фазы и длина вдоха (3,5–4,6 с). */
.ch--civilian { --ph: 0s; --br: 4.2s; }
.ch--don { --ph: -1.7s; --br: 4.4s; --sx: 16px; --sy: -27px; }
.ch--mafia { --ph: -3.1s; --br: 3.9s; --sx: 13px; --sy: -21px; }
.ch--lawyer { --ph: -5.3s; --br: 4.1s; }
.ch--doctor { --ph: -2.4s; --br: 3.8s; }
.ch--commissar { --ph: -6.6s; --br: 4.3s; }
.ch--sergeant { --ph: -8.2s; --br: 3.7s; }
.ch--lover { --ph: -4.4s; --br: 3.6s; }
.ch--bodyguard { --ph: -9.5s; --br: 4.5s; }
.ch--tramp { --ph: -7.3s; --br: 4.6s; }
.ch--lucky { --ph: -10.6s; --br: 3.8s; }
.ch--kamikaze { --ph: -11.8s; --br: 3.5s; }
.ch--suicide { --ph: -.9s; --br: 4.5s; }
.ch--maniac { --ph: -12.4s; --br: 4.2s; }

/* ═════ покой: карта и герой в комнате ═════ */
:where(.flip.is-open .portrait, .scene .s-hero) .lv-breath { animation: lv-breath var(--br) var(--ease-sway) var(--ph) infinite; }
:where(.flip.is-open .portrait, .scene .s-hero) .lv-blink { animation: lv-blink 13s linear var(--ph) infinite; }
:where(.flip.is-open .portrait, .scene .s-hero) .ch .lv-fx { display: inline; }
/* Газета мирного — только днём в спальне. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch--civilian .lv-fx { display: none; }
:where(.scene:not(.is-night) .s-hero-up) .ch--civilian .lv-fx { display: inline; }

/* Вдох короче выдоха; голова поднимается на 1,5 единицы рисунка. */
@keyframes lv-breath { 0%, 100% { transform: none; } 42% { transform: translateY(-.3px) scaleY(1.016); } }
/* 13 с: одиночное, двойное, одиночное — промежутки 3,9–4,6 с, у ролей разная фаза. */
@keyframes lv-blink {
  0%, 9.4%, 11%, 39.4%, 41%, 41.6%, 43.2%, 74.4%, 76%, 100% { transform: none; }
  10%, 40%, 42.4%, 75% { transform: scaleY(.08); }
}

/* ── привычки ролей ── */
/* Дон и мафия: колечки дыма вверх-вправо, мимо лица. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch .lv-ring { animation: lv-ring 5.6s var(--ease-out) infinite; }
:where(.flip.is-open .portrait, .scene .s-hero) .ch .lv-ring2 { animation-delay: .9s; }
@keyframes lv-ring {
  0% { opacity: 0; transform: translate(0, 0) scale(.45); }
  7% { opacity: .9; }
  46%, 100% { opacity: 0; transform: translate(var(--sx), var(--sy)) scale(1.8); }
}

/* Блик: лупа комиссара, зеркало доктора, очки адвоката и телохранителя, нож маньяка. */
@keyframes lv-glint {
  0%, 72%, 100% { opacity: 0; transform: scale(.2) rotate(0deg); }
  77% { opacity: 1; transform: scale(1) rotate(45deg); }
  85% { opacity: 0; transform: scale(.3) rotate(90deg); }
}
:where(.flip.is-open .portrait, .scene .s-hero) .ch--commissar .lv-glint { animation: lv-glint 4.8s var(--ease-out) var(--ph) infinite; }
:where(.flip.is-open .portrait, .scene .s-hero) .ch--commissar .lv-prop { animation: lv-scan 7.4s var(--ease-sway) var(--ph) infinite alternate; }
@keyframes lv-scan { from { transform: translate(-1.2px, .6px); } to { transform: translate(1.2px, -.8px); } }

/* Доктор поправляет зеркало на лбу — и оно блестит. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch--doctor .lv-top { animation: lv-adjust 7s var(--ease-sway) var(--ph) infinite; }
:where(.flip.is-open .portrait, .scene .s-hero) .ch--doctor .lv-glint { animation: lv-glint 7s var(--ease-out) calc(var(--ph) + 1.3s) infinite; }
/* Сержант поправляет фуражку. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch--sergeant .lv-top { animation: lv-adjust 6.6s var(--ease-sway) var(--ph) infinite; }
@keyframes lv-adjust {
  0%, 78%, 100% { transform: none; }
  83% { transform: translateY(-2.4px) rotate(-5deg); }
  89% { transform: translateY(-.4px) rotate(2deg); }
  94% { transform: none; }
}

/* Адвокат постукивает портфелем (на карте) и поблёскивает очками. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch--lawyer .lv-prop { animation: lv-tap 4.6s var(--ease-sway) var(--ph) infinite; }
:where(.flip.is-open .portrait, .scene .s-hero) .ch--lawyer .lv-glint { animation: lv-glint 6.2s var(--ease-out) var(--ph) infinite; }
@keyframes lv-tap {
  0%, 70%, 100% { transform: none; }
  74%, 82% { transform: translateY(-2.5px) rotate(-3deg); }
  78%, 86% { transform: none; }
}

/* Любовница: роза в волосах покачивается. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch--lover .lv-top { animation: lv-rose 3.4s var(--ease-sway) var(--ph) infinite alternate; }
@keyframes lv-rose { from { transform: rotate(-6deg); } to { transform: rotate(5deg); } }

/* Телохранитель оглядывается; очки ловят свет, когда он смотрит в сторону. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch--bodyguard .lv-head { animation: lv-look 8.4s var(--ease-sway) var(--ph) infinite; }
:where(.flip.is-open .portrait, .scene .s-hero) .ch--bodyguard .lv-glint { animation: lv-glint 8.4s var(--ease-out) calc(var(--ph) - 4.1s) infinite; }
@keyframes lv-look {
  0%, 18%, 92%, 100% { transform: none; }
  26%, 42% { transform: translateX(-2.6px) rotate(-1.5deg); }
  52%, 68% { transform: translateX(2.6px) rotate(1.5deg); }
  78% { transform: none; }
}

/* Маньяк медленно склоняет голову; по лезвию пробегает блик. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch--maniac .lv-head { animation: lv-tilt 9s var(--ease-sway) var(--ph) infinite; }
:where(.flip.is-open .portrait, .scene .s-hero) .ch--maniac .lv-glint { animation: lv-blade 5.6s var(--ease-out) var(--ph) infinite; }
@keyframes lv-tilt { 0%, 34%, 100% { transform: none; } 42%, 74% { transform: rotate(4deg) translateX(.6px); } 82% { transform: none; } }
@keyframes lv-blade {
  0%, 72%, 100% { opacity: 0; transform: translate(0, 0) scale(.4); }
  76% { opacity: 1; transform: translate(3px, -9px) scale(1); }
  86% { opacity: 0; transform: translate(10px, -28px) scale(.5); }
}

/* Бомж: пар изо рта на выдохе — тот же ритм, что у дыхания. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch--tramp .lv-puff { animation: lv-puff var(--br) var(--ease-out) var(--ph) infinite; }
@keyframes lv-puff {
  0%, 52% { opacity: 0; transform: translate(0, 0) scale(.5); }
  60% { opacity: .75; transform: translate(-2px, -.5px) scale(.85); }
  96%, 100% { opacity: 0; transform: translate(-10px, -6px) scale(1.3); }
}

/* Счастливчик подкидывает монету: вверх с замедлением, вниз с ускорением, крутится в полёте. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch--lucky .lv-coin { animation: lv-toss 6.4s linear var(--ph) infinite; }
:where(.flip.is-open .portrait, .scene .s-hero) .ch--lucky .lv-coin-s { animation: lv-spin 6.4s linear var(--ph) infinite; }
/* Кривые внутри ключевых кадров — те же, что --ease-out и --ease-in (переменные там не подставляются). */
@keyframes lv-toss {
  0%, 62% { opacity: 0; transform: translateY(0); }
  63% { opacity: 1; transform: translateY(0); animation-timing-function: cubic-bezier(.2, .7, .2, 1); }
  76% { opacity: 1; transform: translateY(-92px); animation-timing-function: cubic-bezier(.5, 0, .75, 0); }
  89% { opacity: 1; transform: translateY(0); }
  90%, 100% { opacity: 0; transform: translateY(0); }
}
@keyframes lv-spin {
  0%, 63%, 69.5%, 76%, 82.5%, 89%, 100% { transform: none; }
  66.25%, 72.75%, 79.25%, 85.75% { transform: scaleY(.14); }
}

/* Камикадзе: фитиль искрит. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch--kamikaze .lv-spark { animation: lv-fuse 1.1s linear infinite; }
@keyframes lv-fuse {
  0%, 100% { transform: scale(1) rotate(0deg); opacity: 1; }
  25% { transform: scale(.82) rotate(14deg); opacity: .8; }
  50% { transform: scale(1.1) rotate(-6deg); opacity: 1; }
  75% { transform: scale(.88) rotate(9deg); opacity: .9; }
}

/* Самоубийца: верёвка покачивается от узла. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch--suicide .lv-rope { animation: lv-rope 5.2s var(--ease-sway) var(--ph) infinite alternate; }
@keyframes lv-rope { from { transform: rotate(-1.2deg); } to { transform: rotate(1.2deg); } }

/* Мирный: на карте задумчиво склоняет голову; днём в спальне читает газету и перелистывает страницу. */
:where(.flip.is-open .portrait, .scene .s-hero) .ch--civilian .lv-head { animation: lv-think 9.6s var(--ease-sway) var(--ph) infinite; }
@keyframes lv-think { 0%, 52%, 100% { transform: none; } 60%, 84% { transform: rotate(-3deg); } }
:where(.scene .s-hero) .ch--civilian .lv-paper { animation: lv-paper 18s var(--ease-sway) infinite; }
:where(.scene .s-hero) .ch--civilian .lv-page { animation: lv-page 18s var(--ease-move) infinite; }
/* Газета поднимается из-за одеяла, чтение с двумя перелистываниями, газета опускается — видно лицо. */
@keyframes lv-paper { 0% { transform: translateY(34px); } 5%, 72% { transform: none; } 78%, 100% { transform: translateY(34px); } }
@keyframes lv-page {
  0%, 30% { transform: scaleX(1); opacity: 1; }
  36% { transform: scaleX(-1); opacity: 1; }
  40% { transform: scaleX(-1); opacity: 0; }
  41%, 52% { transform: scaleX(1); opacity: 0; }
  53%, 58% { transform: scaleX(1); opacity: 1; }
  64% { transform: scaleX(-1); opacity: 1; }
  68% { transform: scaleX(-1); opacity: 0; }
  69%, 100% { transform: scaleX(1); opacity: 0; }
}

/* ═════ итоги: сцена с занавесом — победители танцуют в луче, проигравшие стоят в тени ═════ */
.end-stage {
  --st-back: var(--disc);
  --st-fold: rgba(12, 9, 8, .2);
  --st-top: var(--red-dark);
  --st-floor: var(--raise);
  --st-edge: #2E2829;
  --st-light: rgba(255, 238, 208, .14);
  --st-pool: rgba(255, 238, 208, .2);
  position: relative; isolation: isolate; overflow: hidden;
  width: 100%; aspect-ratio: 16 / 10; margin-bottom: 20px;
  border-radius: 20px; background: var(--st-back);
}
.end-stage.is-mid { aspect-ratio: 16 / 8; }
.end-stage.is-many { aspect-ratio: 16 / 7; }
:root[data-theme="light"] .end-stage {
  --st-fold: rgba(110, 92, 76, .14);
  --st-floor: #8F735C;
  --st-edge: #6E5C4C;
  --st-light: rgba(255, 252, 247, .5);
  --st-pool: rgba(255, 252, 247, .6);
}
.end-stage > * { position: absolute; }
.end-set { inset: 0; width: 100%; height: 100%; }
.end-set .st-fold { fill: var(--st-fold); }
.end-top { inset: 0 0 auto; width: 100%; height: 11%; z-index: 3; }
.end-top .st-top { fill: var(--st-top); }
.end-apron { inset: auto 0 0; height: 13%; z-index: 2; background: var(--st-floor); box-shadow: inset 0 2px 0 var(--st-edge); }

/* Прожектор: конус качается вокруг лампы под ламбрекеном, пятно света — на полу. */
.end-beam { top: -6%; left: 18%; width: 64%; height: 108%; transform-origin: 50% 0; }
.end-beam i { position: absolute; inset: 0; background: var(--st-light); clip-path: polygon(45% 0, 55% 0, 100% 100%, 0 100%); }
.end-beam b { position: absolute; left: 8%; right: 8%; bottom: 8%; height: 13%; border-radius: 50%; background: var(--st-pool); }
.end-stage.is-dance .end-beam { animation: beam-sweep 3.6s var(--ease-sway) infinite alternate; }
.end-beam > * { animation: fade 900ms 200ms ease backwards; }
@keyframes beam-sweep { from { transform: rotate(-13deg); } to { transform: rotate(13deg); } }

/* Ряд: победители в середине, проигравшие по краям — меньше и в тени. Нижний край бюстов прячет авансцена. */
.end-row { inset: auto 2% 8.5% 2%; display: flex; justify-content: center; align-items: flex-end; }
.end-fig {
  position: relative; min-width: 0;
  flex: 0 1 min(30%, calc(150% / var(--n)));
  margin-inline: max(-3.4%, calc(-25% / var(--n)));
  animation: fig-in 560ms var(--ease-enter) backwards; animation-delay: calc(var(--i) * 55ms + 100ms);
}
.end-fig.is-side { flex-basis: min(22%, calc(117% / var(--n))); }
.end-fig.is-me { z-index: 1; }
.end-fig .fig-move { display: block; transform-origin: 50% 100%; }
.end-fig .ch { display: block; width: 100%; height: auto; aspect-ratio: 124 / 158; overflow: visible; }
/* В тени: темнее и тише; фильтр неподвижный — эти фигуры не двигаются. */
.end-fig.is-side .fig-move { filter: brightness(.42) saturate(.5); }
:root[data-theme="light"] .end-fig.is-side .fig-move { filter: grayscale(.85) brightness(.82); opacity: .6; }
@keyframes fig-in { from { opacity: 0; transform: translateY(24%); } }

/* Танец: все в одном такте; соседи качаются зеркально, каждый третий — шимми. Шляпа подпрыгивает с запозданием. */
.end-stage.is-dance .is-up .fig-move { animation: dance var(--beat) linear calc(var(--i) * -0.06s) infinite; }
.end-stage.is-dance .is-up:nth-child(even) .fig-move { animation-direction: reverse; }
.end-stage.is-dance .is-up:nth-child(3n) .fig-move { animation-name: dance-shimmy; }
.end-stage.is-dance .is-up .lv-head { animation: dance-head var(--beat) var(--ease-sway) infinite; }
.end-stage.is-dance .is-up:nth-child(even) .lv-head { animation-direction: reverse; }
.end-stage.is-dance .is-up .lv-top { animation: dance-hat var(--beat) linear infinite; }
/* Кривые прыжка: вверх — как --ease-out, вниз — как --ease-in (в обратном проходе меняются местами сами). */
@keyframes dance {
  0% { transform: translateY(0) rotate(-4deg); animation-timing-function: cubic-bezier(.2, .7, .2, 1); }
  25% { transform: translateY(-6%) rotate(0deg); animation-timing-function: cubic-bezier(.5, 0, .75, 0); }
  50% { transform: translateY(0) rotate(4deg); animation-timing-function: cubic-bezier(.2, .7, .2, 1); }
  75% { transform: translateY(-6%) rotate(0deg); animation-timing-function: cubic-bezier(.5, 0, .75, 0); }
  100% { transform: translateY(0) rotate(-4deg); }
}
@keyframes dance-shimmy {
  0%, 100% { transform: translateX(-4%) rotate(-2deg); }
  25%, 75% { transform: translateY(-5%); }
  50% { transform: translateX(4%) rotate(2deg); }
}
@keyframes dance-head { 0%, 100% { transform: rotate(5deg); } 50% { transform: rotate(-5deg); } }
@keyframes dance-hat {
  0%, 50%, 100% { transform: none; }
  30% { transform: translateY(-6px) rotate(-5deg); }
  80% { transform: translateY(-6px) rotate(5deg); }
}
/* Дон: два прыжка, потом поклон — приподнимает шляпу. */
.end-stage.is-dance .is-up.r-don .fig-move { animation: dance-bow calc(var(--beat) * 4) var(--ease-sway) infinite; }
.end-stage.is-dance .is-up.r-don .lv-head { animation: dance-nod calc(var(--beat) * 4) var(--ease-sway) infinite; }
.end-stage.is-dance .is-up.r-don .lv-top { animation: dance-tip calc(var(--beat) * 4) var(--ease-sway) infinite; }
@keyframes dance-bow {
  0%, 25%, 50%, 94%, 100% { transform: none; }
  12.5%, 37.5% { transform: translateY(-6%); }
  62%, 84% { transform: translateY(5%) scaleY(.95); }
}
@keyframes dance-nod { 0%, 54%, 94%, 100% { transform: none; } 62%, 84% { transform: translateY(4px) scale(.97); } }
@keyframes dance-tip { 0%, 52%, 96%, 100% { transform: none; } 60%, 84% { transform: translate(9px, -15px) rotate(15deg); } }

/* Проигравшие поникли: голова опущена, взгляд в пол, плечи ниже. Без движения. */
.end-fig.is-down .lv-breath { transform: translateY(3px) scaleY(.96); }
.end-fig.is-down .lv-head { transform: translateY(6px) rotate(8deg); }
.end-fig.is-down:nth-child(even) .lv-head { transform: translateY(6px) rotate(-7deg); }
.end-fig.is-down .lv-blink { transform: translateY(1.5px) scaleY(.3); }
.end-fig.is-down .lv-top { transform: translateY(2px); }

/* «Победа» — удар-появление: печать падает и отскакивает. */
.g-end.is-won .display {
  animation: end-stamp 560ms 380ms backwards;
}
@keyframes end-stamp {
  0% { opacity: 0; transform: scale(1.7); animation-timing-function: cubic-bezier(.5, 0, .75, 0); }
  45% { opacity: 1; transform: scale(.93); animation-timing-function: cubic-bezier(.2, .7, .2, 1); }
  70% { transform: scale(1.03); }
  100% { transform: none; }
}
.g-end-list .row.is-me { background: var(--raise-2); }

/* ── итоги кадрами Blender (street.js → stageSprites): полосы dance / idle из webapp/img/chars ──
   Пока ждём манифест и картинки (до 1,6 с), фигур не видно (is-wait); потом выходят на сцену — кадрами или векторные.
   Точка (--x, --y) — ступни в % сцены; --s — cqw ширины сцены на пиксель кадра; кадр — полоса translateX + steps(N). */
.end-stage.is-wait .end-row { visibility: hidden; }
.end-stage.is-spr { container-type: inline-size; aspect-ratio: 16 / 9; }
.end-stage.is-spr .end-row { inset: 0; display: block; z-index: 1; }
.end-stage.is-spr .end-apron { z-index: 0; }
.end-stage.is-spr .end-fig { position: absolute; left: calc(var(--x) * 1%); top: calc(var(--y) * 1%); width: 0; height: 0; margin: 0; flex: none; z-index: var(--z); }
.end-dir, .end-bow { position: absolute; left: 0; top: 0; width: 0; height: 0; }
.end-fig.is-flip .end-dir { transform: scaleX(-1); }
.end-spr {
  position: absolute; overflow: hidden;
  width: calc(var(--fw) * var(--s) * 1cqw); height: calc(var(--fh) * var(--s) * 1cqw);
  left: calc(var(--ax) * var(--s) * -1cqw); top: calc(var(--ay) * var(--s) * -1cqw);
}
.end-strip {
  position: absolute; left: 0; top: 0; height: 100%; width: calc(var(--n) * 100%);
  background-size: 100% 100%; background-repeat: no-repeat;
  animation: spr-play var(--d) steps(var(--n)) var(--dl, 0ms) infinite;
}
.end-strip.is-alt { opacity: 0; }
@keyframes spr-play { from { transform: translateX(0); } to { transform: translateX(-100%); } }
/* Проигравшие — в тени по краям; фильтр неподвижный. */
.end-fig.is-side .end-spr { filter: brightness(.42) saturate(.5); }
:root[data-theme="light"] .end-fig.is-side .end-spr { filter: grayscale(.85) brightness(.82); opacity: .6; }
/* Дон-победитель: два такта танца, потом поклон — кадр покоя и наклон вперёд от ступней. */
.end-fig.is-bow .end-strip.is-main { animation: spr-play var(--d) steps(var(--n)) infinite, bow-a var(--bow) step-end infinite; }
.end-fig.is-bow .end-strip.is-alt { animation: spr-play var(--d) steps(var(--n)) infinite, bow-b var(--bow) step-end infinite; }
.end-fig.is-bow .end-bow { animation: bow var(--bow) var(--ease-sway) infinite; }
@keyframes bow-a { 0% { opacity: 1; } 50% { opacity: 0; } }
@keyframes bow-b { 0% { opacity: 0; } 50% { opacity: 1; } }
@keyframes bow { 0%, 54%, 94%, 100% { transform: none; } 64%, 84% { transform: rotate(9deg) scaleY(.95); } }

/* Кто не поместился на сцену — строкой аватаров: победители ярко, проигравшие приглушены. */
.end-more { display: flex; flex-wrap: wrap; justify-content: center; margin: -6px 0 18px; padding-inline-start: 8px; }
.end-more li { margin-inline-start: -8px; }
.g-end .end-more .ch-avatar { width: 32px; height: 32px; margin: 0; animation: none; box-shadow: 0 0 0 2px var(--bg); }
.end-more li:not(.is-won) .ch-avatar { filter: grayscale(.8); opacity: .7; }
.end-more-n {
  display: grid; place-items: center; min-width: 32px; height: 32px; padding: 0 8px; border-radius: var(--r-pill);
  background: var(--raise-2); color: var(--muted); font: 600 12px/1 var(--font-body); box-shadow: 0 0 0 2px var(--bg);
}

/* ═════ отмены: сон, смерть, сцены событий, пауза, меньше движения ═════ */
/* Спящий дышит медленнее и не моргает (глаза закрыты); привычки спят тоже. */
:where(.scene.is-asleep .s-hero) .ch .lv-breath { animation-duration: 6.4s; }
:where(.scene.is-asleep .s-hero) .ch .lv:not(.lv-breath) { animation: none; }
:where(.scene.is-asleep .s-hero) .ch .lv-fx { display: none; }
/* Выбывший неподвижен; в сцене события играет только сама сцена. */
:where(.scene.is-dead .s-hero, .scene[class*="play-"] .s-hero) .ch .lv { animation: none; }
:where(.scene.is-dead .s-hero, .scene[class*="play-"] .s-hero) .ch .lv-fx { display: none; }
/* Вне экрана и в скрытой вкладке — пауза. */
.lv-off .lv, .lv-hidden .lv, .lv-off .end-fig, .lv-hidden .end-fig { animation-play-state: paused !important; }
.lv-off :is(.end-strip, .end-bow), .lv-hidden :is(.end-strip, .end-bow) { animation-play-state: paused !important; }
.flip:not(.is-open) .lv { animation-play-state: paused !important; }

@media (prefers-reduced-motion: reduce) {
  .ch .lv, .end-stage .lv, .end-stage .lv > *, .end-fig, .g-end.is-won .display { animation: none !important; }
  /* Кадры стоят: танцор — с поднятой рукой, остальные — в покое. */
  .end-strip, .end-bow { animation: none !important; }
  .end-strip.is-main { transform: translateX(calc(-100% * var(--pose, 0) / var(--n))); }
}
