/* ==========================================================================
   epozvanka.sk — VSTUP „OBÁLKA AKO POSTAVA"

   Obálka nie je predmet, ale BYTOSŤ. Pred ťuknutím dýcha a netrpezlivo
   poskočí, po ťuknutí sa prikrčí, roztvorí sa a kartu VYPĽUJE. Karta
   prestrelí, splošti sa a dosadne; obálka ostane dole zmenšená ako postava,
   ktorá sa díva na to, čo vypustila.

   CELÉ CSS ŽIJE POD `.vs[data-vstup="postava"]`. Prototyp mal farby na
   :root — keby sa portol tak, ako je, prepísal by paletu ostatným trom
   animáciám. Farby sem podá motor ako --vs-* priamo na .vs.

   KADENCIA — prototypy mali takmer všetko na steps(1) a zákazník to
   odmietol („vyzerali ako fps0"). Pravidlo, podľa ktorého je prepísaná
   každá partitúra v tomto súbore:
     • náraz, prasknutie, výmena kresby → steps(1), tvrdý skok
     • let a posun cez plochu           → steps(N), N ≈ trvanie[s] × 24
     • pozadie, dýchanie, dokmit        → plynule, bez steps
   Tvrdý skok tak ostal tam, kde nesie informáciu, a zmizol tam, kde bol
   len šum.

   Animuje sa VÝHRADNE transform a opacity. Ani jedno miešanie farieb
   funkciou zo CSS Color 5 — Chrome pod 111 by zahodil celú deklaráciu.

   PREČO SA TU NEANIMUJE z-index: prototyp prehadzoval poradie karty aj
   chlopne cez @keyframes. Namiesto toho sú tu dve kópie chlopne (pred/za)
   a jednosnímková výmena cez opacity, a karta má poradie pevné a objaví
   sa až v snímke, keď vyletí. Vizuálne to isté, ale bez animovania
   vlastnosti, ktorá nie je transform ani opacity.
   ========================================================================== */

/* ── javisko ──────────────────────────────────────────────────────────
   Pevný pomer strán a JEDNA mierka --w. Vďaka tomu sú všetky vnútorné
   rozmery aj typografia jej násobky a kompozícia drží rovnako na 320 px
   mobile aj na monitore — bez media query a bez dopočtu v JS.
   Výška sa berie z --vs-vyska (motor ju meria cez visualViewport), nie
   z vh: na iPhone je vh iná než to, čo je naozaj vidieť. */
.vs[data-vstup="postava"] .vsp {
  --w: min(var(--vs-sirka), 94vw, calc(var(--vs-vyska, 100vh) * 0.62));
  position: relative;
  width: var(--w);
  height: calc(var(--w) * 1.475);
  font-family: var(--vs-serif);
}

.vs[data-vstup="postava"] .vsp__pozadie {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
}

/* ── vrstvy obálky ────────────────────────────────────────────────────
   KRITICKÉ: karta NIE JE potomkom obálky. Keby bola, zmenšenie obálky na
   0,78 by sa s ňou skladalo a karta by z nej nikdy nevyšla. Sú to
   súrodenci a poradie robí z-index:
     1 zadok + otvorená chlopňa → 3 predok → 4 zavretá chlopňa
     → 5 pečať → 6 rachot → 7 výzva → 8 karta                         */
.vs[data-vstup="postava"] .vsp__ob {
  position: absolute;
  left: 8%;
  width: 84%;
  top: 44%;
  aspect-ratio: 290 / 200;
  will-change: transform;
  backface-visibility: hidden;
}
.vs[data-vstup="postava"] .vsp__ob svg {
  width: 100%;
  height: 100%;
  display: block;
}
.vs[data-vstup="postava"] .vsp__ob--zadok { z-index: 1; }
.vs[data-vstup="postava"] .vsp__ob--predok { z-index: 3; }
.vs[data-vstup="postava"] .vsp__ob--pecat { z-index: 5; }

/* Dve kópie chlopne. Zavretá leží nad predkom (4), otvorená za telom (1);
   v snímke, keď je chlopňa hranou k divákovi, sa jedna vypne a druhá
   zapne. Je to ten istý výsledok ako prehodenie z-indexu, len cez
   opacity. */
.vs[data-vstup="postava"] .vsp__ob--chlopna {
  perspective: 900px;
  perspective-origin: 50% 0%;
}
.vs[data-vstup="postava"] .vsp__ob--chlopna-a { z-index: 4; }
.vs[data-vstup="postava"] .vsp__ob--chlopna-b { z-index: 1; opacity: 0; }

.vs[data-vstup="postava"] .vsp__chlopna-list {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  aspect-ratio: 290 / 104;   /* rovnaká mierka jednotiek ako telo obálky */
  transform-origin: 50% 0%;  /* pánt je horná hrana, nie stred */
  transform-style: preserve-3d;
  will-change: transform;
}
.vs[data-vstup="postava"] .vsp__chlopna-list svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  backface-visibility: hidden;
}
/* Rub je zrkadlený cez Y: pri preklopení okolo X-ovej osi tak silueta
   sadne presne na líce a nevznikne diera v jednej snímke. */
.vs[data-vstup="postava"] .vsp__chl-rub { transform: rotateY(180deg); }

.vs[data-vstup="postava"] .vsp__pecat-in {
  position: absolute;
  left: 42%;
  top: 39%;
  width: 16%;
  aspect-ratio: 1;
  will-change: transform;
}
.vs[data-vstup="postava"] .vsp__pecat-in svg { width: 100%; height: 100%; display: block; }

/* ── karta ────────────────────────────────────────────────────────────
   Poradie má pevné (8) a v pokoji je neviditeľná — v zalepenej obálke
   nie je čo vidieť. Že vnútri niečo je, hovorí papierový prúžok v tmavom
   otvore (.vsp__hrana); ten zhasne v tej istej snímke, v ktorej sa karta
   objaví. */
.vs[data-vstup="postava"] .vsp__karta {
  position: absolute;
  left: 11%;
  width: 78%;
  top: 2.5%;
  aspect-ratio: 42 / 49;
  z-index: 8;
  opacity: 0;
  transform: translateY(49.1%) scale(0.46);
  will-change: transform, opacity;
  backface-visibility: hidden;
}

/* Plochý posunutý tieň namiesto box-shadow. Rozostrený tieň sa pri každej
   zmene mierky prekresľuje — to je najdrahšia položka scény a na mobile
   zožerie práve tie snímky, na ktorých záleží. */
.vs[data-vstup="postava"] .vsp__tien {
  position: absolute;
  inset: 0;
  background: var(--vs-ink);
  border-radius: 14px;
  transform: translate(2.4%, 2.2%);
}
.vs[data-vstup="postava"] .vsp__list {
  position: absolute;
  inset: 0;
  background: var(--vs-papier);
  border: 5px solid var(--vs-ink);
  border-radius: 14px;
  overflow: hidden;
}
.vs[data-vstup="postava"] .vsp__telo {
  position: absolute;
  inset: 0;
  padding: 7% 8%;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Vlastný rámec bez vnútorného odsadenia. Sadzba meria práve jeho šírku —
   clientWidth padnutého boxu by odsadenie započítal a mená by pretiekli
   presne o tie dve percentá. */
.vs[data-vstup="postava"] .vsp__obsah {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.vs[data-vstup="postava"] .vsp__ramik {
  position: absolute;
  inset: 4.5%;
  border: 2px solid var(--vs-zlata);
  border-radius: 6px;
  opacity: 0.75;
}
.vs[data-vstup="postava"] .vsp__roh { position: absolute; width: 13%; }
.vs[data-vstup="postava"] .vsp__roh--lh { left: 6%; top: 6%; }
.vs[data-vstup="postava"] .vsp__roh--ph { right: 6%; top: 6%; transform: scaleX(-1); }
.vs[data-vstup="postava"] .vsp__roh--ld { left: 6%; bottom: 6%; transform: scaleY(-1); }
.vs[data-vstup="postava"] .vsp__roh--pd { right: 6%; bottom: 6%; transform: scale(-1); }

/* Veľkosti mien, nadpisu aj dátumu nastavuje JS MERANÍM (scrollWidth),
   nie odhadom podľa počtu znakov — „Alexandra a Bartolomej" aj „Eva a Jan"
   musia sadnúť na tú istú kartu. Tu ostáva len to, čo od merania nezávisí. */
.vs[data-vstup="postava"] .vsp__nadpis {
  letter-spacing: 0.26em;
  text-indent: 0.26em;
  text-transform: uppercase;
  color: var(--vs-zlata2);
  text-align: center;
  margin-bottom: 6%;
  white-space: nowrap;
  font-family: var(--vs-sans);
}
.vs[data-vstup="postava"] .vsp__meno {
  line-height: 0.96;
  letter-spacing: 0.03em;
  text-indent: 0.03em;
  text-transform: uppercase;
  color: var(--vs-ink);
  white-space: nowrap;
  font-weight: 700;
  text-align: center;
}
.vs[data-vstup="postava"] .vsp__spojka {
  font-style: italic;
  color: var(--vs-akcent);
  line-height: 1;
  margin: 2% 0;
}
.vs[data-vstup="postava"] .vsp__linka {
  width: 34%;
  height: 2px;
  background: var(--vs-zlata);
  margin: 7% 0 5%;
  transform-origin: 50% 50%;
}
.vs[data-vstup="postava"] .vsp__datum {
  letter-spacing: 0.1em;
  text-indent: 0.1em;
  color: var(--vs-ink);
  white-space: nowrap;
  text-align: center;
}

.vs[data-vstup="postava"] .vsp__peciatka {
  position: absolute;
  left: 50%;
  bottom: 3.5%;
  width: 15%;
  aspect-ratio: 1;
  margin-left: -7.5%;
  transform-origin: 50% 100%;   /* dosadá spodkom — squash musí ísť do stola */
  opacity: 0;
  will-change: transform, opacity;
}
.vs[data-vstup="postava"] .vsp__peciatka svg { width: 100%; height: 100%; display: block; }

/* Nárazové čiary — kreslený „buch". Osem lúčov povie o náraze viac než
   dvadsať poletujúcich bodiek, takže sú v tejto animácii tým, čím sú inde
   konfety. Preto ich vypína zákazníkov prepínač konfiet (JS ich vtedy
   vôbec nepostaví). */
.vs[data-vstup="postava"] .vsp__rachot {
  position: absolute;
  left: 8%;
  width: 84%;
  top: 44%;
  aspect-ratio: 290 / 200;
  z-index: 6;
  opacity: 0;
  transform-origin: 50% 34%;
  pointer-events: none;
  will-change: transform, opacity;
}
.vs[data-vstup="postava"] .vsp__rachot svg { width: 100%; height: 100%; display: block; }
.vs[data-vstup="postava"] .vsp__rachot2 {
  position: absolute;
  left: 50%;
  bottom: 3.5%;
  width: 15%;
  aspect-ratio: 1;
  margin-left: -7.5%;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
}
.vs[data-vstup="postava"] .vsp__rachot2 svg { width: 100%; height: 100%; display: block; }

.vs[data-vstup="postava"] .vsp__vyzva {
  position: absolute;
  left: 0;
  right: 0;
  top: 88%;
  z-index: 7;
  text-align: center;
  /* Farba výzvy sa neberie z dizajnu, ale z čitateľnosti — motor ju
     dopočíta ako čiernu alebo bielu podľa toho, ktorá je na podklade scény
     lepšie vidieť (--vs-vyzva v js/vstup.js). Predtým tu stála farba
     odvodená od dizajnu a v mnohých dizajnoch splynula s podkladom: výzva
     na obrazovke bola, ale hosť ju nevidel. */
  color: var(--vs-vyzva, var(--vs-zlata));
  font-family: var(--vs-sans);
  font-size: calc(var(--w) * 0.038);
  letter-spacing: 0.22em;
  text-indent: 0.22em;
  text-transform: uppercase;
  will-change: transform, opacity;
}

/* Texty naskakujú až po karte — v pokoji ich niet. */
.vs[data-vstup="postava"] .vsp__nadpis,
.vs[data-vstup="postava"] .vsp__meno,
.vs[data-vstup="postava"] .vsp__spojka,
.vs[data-vstup="postava"] .vsp__linka,
.vs[data-vstup="postava"] .vsp__datum { opacity: 0; }

/* ══════════════════════════════════════════════════════════════════════
   POKOJ — obrazovka nesmie stáť
   Dýchanie je PLYNULÉ (nie je to úder), poskok ostáva na steps(1).
   ══════════════════════════════════════════════════════════════════════ */

/* Dýchanie a poskok sú v JEDNEJ animácii zámerne: keby boli dve,
   potrebovali by dva vnorené elementy (transform sa neskladá) a všetky
   štyri vrstvy obálky by sa museli zdvojiť. Krok dýchania je nad prahom
   viditeľnosti — sub-pixelový pohyb prehliadač zaokrúhli a vznikne z neho
   trhanie namiesto pokoja. */
@keyframes vsp-caka {
  0%   { transform: translateY(0)      scale(1, 1);         animation-timing-function: linear; }
  11%  { transform: translateY(-2.4%)  scale(0.992, 1.016); animation-timing-function: linear; }
  22%  { transform: translateY(0)      scale(1, 1);         animation-timing-function: linear; }
  33%  { transform: translateY(-2.4%)  scale(0.992, 1.016); animation-timing-function: linear; }
  44%  { transform: translateY(0)      scale(1, 1);         animation-timing-function: linear; }
  55%  { transform: translateY(-2.4%)  scale(0.992, 1.016); animation-timing-function: linear; }
  66%  { transform: translateY(0)      scale(1, 1);         animation-timing-function: linear; }
  /* netrpezlivý poskok: nápřah → výskok → dosad so squashom, tvrdo */
  70%  { transform: translateY(1.5%)   scale(1.09, 0.90) rotate(0deg);    animation-timing-function: steps(1); }
  72%  { transform: translateY(-8%)    scale(0.90, 1.12) rotate(-2deg);   animation-timing-function: steps(1); }
  74%  { transform: translateY(-3.5%)  scale(1, 1)       rotate(1.5deg);  animation-timing-function: steps(1); }
  76%  { transform: translateY(0.8%)   scale(1.13, 0.87) rotate(0deg);    animation-timing-function: steps(1); }
  78%  { transform: translateY(0)      scale(0.96, 1.04); animation-timing-function: linear; }
  82%  { transform: translateY(0)      scale(1, 1);       animation-timing-function: linear; }
  /* zvyšok cyklu je HOLD — pauza je súčasť pohybu; bez nej sa scéna zlije
     do kaše a to sa subjektívne číta opäť ako nízke fps */
  100% { transform: translateY(0)      scale(1, 1); }
}
.vs[data-vstup="postava"][data-faza="pokoj"] .vsp__ob {
  animation: vsp-caka 4.2s linear infinite both;
}

/* Obe oči žmurkajú NARAZ. Posun o snímku je skvelý na dva samostatné
   objekty, ale na páre očí sa číta ako chyba, nie ako povaha. */
@keyframes vsp-mrk {
  0%, 90%   { transform: scaleY(1);    animation-timing-function: steps(1); }
  92%       { transform: scaleY(0.12); animation-timing-function: steps(1); }
  94%       { transform: scaleY(1);    animation-timing-function: steps(1); }
  96%       { transform: scaleY(0.12); animation-timing-function: steps(1); }
  98%, 100% { transform: scaleY(1); }
}
.vs[data-vstup="postava"][data-faza="pokoj"] .vsp__oko {
  animation: vsp-mrk 4.2s steps(1) infinite both;
}

/* Pozadie sa podľa pravidla nekrokuje — iskra len tichšie pulzuje. */
@keyframes vsp-iskra {
  0%, 22% { opacity: 0.12; animation-timing-function: linear; }
  30%     { opacity: 1;    animation-timing-function: linear; }
  44%     { opacity: 0.28; animation-timing-function: linear; }
  100%    { opacity: 0.12; }
}
.vs[data-vstup="postava"] .vsp__iskra { animation: vsp-iskra 2.5s linear infinite both; }
.vs[data-vstup="postava"] .vsp__iskra--2 { animation-delay: -0.9s; }
.vs[data-vstup="postava"] .vsp__iskra--3 { animation-delay: -1.7s; }

@keyframes vsp-vyzva-pulz {
  0%, 44%   { transform: translateY(0)   scale(1);    animation-timing-function: linear; }
  52%       { transform: translateY(-6%) scale(1.05); animation-timing-function: linear; }
  60%, 100% { transform: translateY(0)   scale(1); }
}
.vs[data-vstup="postava"][data-faza="pokoj"] .vsp__vyzva {
  animation: vsp-vyzva-pulz 2.4s linear infinite both;
}

/* ══════════════════════════════════════════════════════════════════════
   OTVORENIE — partitúra v snímkach (1 snímka = var(--f1) = 83,33 ms)

     f0      nápřah: obálka sa prikrčí
     f1–f5   pečať sa odtrhne a odletí
     f2–f5   chlopňa sa roztvorí (na f3 výmena kresby pred/za)
     f2–f11  karta: stlačenie, HOLD, výstrel, SMEAR, prestrel, dosad
     f5–f8   nárazové čiary
     f11–f18 mená, každé o snímku neskôr
     f18–f23 pečiatka srdca dopadne
     od f23  obálka ostáva dole a ďalej dýcha (vsp-radost)

   Selektor :not([data-faza="pokoj"]) drží partitúru cez fázu „hraj" AJ
   „koniec". Keby bola viazaná len na „hraj", motor by ju po dobehnutí
   odpojil a hotová scéna by sa v jednej snímke rozpadla späť do pokoja.
   ══════════════════════════════════════════════════════════════════════ */

/* Nápřah je jediný dôvod, prečo rýchla akcia vyzerá plynulejšie než
   pomalá: oko dostane varovanie a stihne hlavný úder spracovať. */
@keyframes vsp-otvorenie {
  0%     { transform: translateY(0)      rotate(0deg)     scale(1, 1);       animation-timing-function: steps(2, jump-none); }
  22.2%  { transform: translateY(3%)     rotate(-2.5deg)  scale(1.10, 0.89); animation-timing-function: steps(1); }  /* PRIKRČENIE */
  44.4%  { transform: translateY(-2%)    rotate(1.5deg)   scale(0.93, 1.09); animation-timing-function: steps(1); }  /* vypľuje kartu */
  55.5%  { transform: translateY(8%)     rotate(-4deg)    scale(1.12, 0.86); animation-timing-function: steps(2); }  /* spätný ráz */
  66.6%  { transform: translateY(25%)    rotate(-5.5deg)  scale(0.74, 0.80); animation-timing-function: linear; }    /* prestrel */
  77.7%  { transform: translateY(17%)    rotate(-2.5deg)  scale(0.81, 0.77); animation-timing-function: linear; }    /* protipohyb */
  88.8%  { transform: translateY(21.5%)  rotate(-4deg)    scale(0.77, 0.79); animation-timing-function: linear; }    /* dokmit */
  100%   { transform: translateY(20%)    rotate(-3.5deg)  scale(0.78, 0.78); }
}
/* Po dosadnutí obálka nezamrzne — ďalej dýcha. Zamrznutý koniec je to isté
   ako zamrznutý začiatok. fill-mode úmyselne chýba, aby počas oneskorenia
   nepremazala koncovú pózu predošlej animácie. */
@keyframes vsp-radost {
  0%, 58% { transform: translateY(20%)   rotate(-3.5deg) scale(0.78); animation-timing-function: linear; }
  66%     { transform: translateY(18.4%) rotate(-3deg)   scale(0.78); animation-timing-function: linear; }
  74%     { transform: translateY(20%)   rotate(-3.5deg) scale(0.78); animation-timing-function: linear; }
  86%     { transform: translateY(18.4%) rotate(-4.1deg) scale(0.78); animation-timing-function: linear; }
  100%    { transform: translateY(20%)   rotate(-3.5deg) scale(0.78); }
}
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__ob {
  animation: vsp-otvorenie calc(9 * var(--f1)) linear both,
             vsp-radost 3.2s linear calc(23 * var(--f1)) infinite;
}

/* Chlopňa: rozlet na dva kroky, dosad na cieľ plynule. Zastaviť presne na
   cieli bez dokmitu je najspoľahlivejší signál „toto je počítač". */
@keyframes vsp-chl-otvor {
  0%    { transform: rotateX(0deg);    animation-timing-function: steps(2); }
  33.3% { transform: rotateX(-96deg);  animation-timing-function: steps(2); }
  66.6% { transform: rotateX(-178deg); animation-timing-function: linear; }
  100%  { transform: rotateX(-163deg); }
}
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__chlopna-list {
  animation: vsp-chl-otvor calc(3 * var(--f1)) linear calc(2 * var(--f1)) both;
}

/* Výmena kresby presne v snímke, keď je chlopňa hranou k divákovi.
   Zavretá zhasne, otvorená sa zapne — a tým sa dostane za telo obálky. */
@keyframes vsp-chl-preber { 0%, 33.2% { opacity: 1; } 33.3%, 100% { opacity: 0; } }
@keyframes vsp-chl-nastup { 0%, 33.2% { opacity: 0; } 33.3%, 100% { opacity: 1; } }
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__ob--chlopna-a {
  animation: vsp-otvorenie calc(9 * var(--f1)) linear both,
             vsp-radost 3.2s linear calc(23 * var(--f1)) infinite,
             vsp-chl-preber calc(3 * var(--f1)) steps(1) calc(2 * var(--f1)) both;
}
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__ob--chlopna-b {
  animation: vsp-otvorenie calc(9 * var(--f1)) linear both,
             vsp-radost 3.2s linear calc(23 * var(--f1)) infinite,
             vsp-chl-nastup calc(3 * var(--f1)) steps(1) calc(2 * var(--f1)) both;
}

/* Pečať to odtrhne hneď pri nápřahu — malý úder navyše, ktorý pripraví oko
   na veľký. Je to LET cez plochu, takže sa krokuje po ~24 fps, nie po 12. */
@keyframes vsp-pecat-odlet {
  0%   { transform: translate(0, 0)          rotate(0deg)    scale(1);          opacity: 1;   animation-timing-function: steps(2); }
  25%  { transform: translate(-6%, -26%)     rotate(-46deg)  scale(1.18, 0.86); opacity: 1;   animation-timing-function: steps(2); }
  50%  { transform: translate(-22%, -118%)   rotate(-150deg) scale(0.62, 1.5);  opacity: 0.9; animation-timing-function: steps(2); }  /* šmuh */
  75%  { transform: translate(-44%, -238%)   rotate(-262deg) scale(0.8);        opacity: 0.55; animation-timing-function: steps(2); }
  100% { transform: translate(-62%, -372%)   rotate(-352deg) scale(0.55);       opacity: 0; }
}
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__pecat-in {
  animation: vsp-pecat-odlet calc(4 * var(--f1)) linear var(--f1) both;
}

/* ── Hlavný úder: karta ───────────────────────────────────────────────
   Trvá 0,75 s, čo je viac než 0,5 s — a je to zámer: nie je to jeden úder,
   ale reťaz troch (nápřah → výlet → prestrel a dokmit). Každý jednotlivý
   je pod hranicou; rozdelenie na tri CSS animácie by len znemožnilo, aby
   na seba pózy presne nadviazali.
   Skok f5→f6 je vyše tretiny výšky karty, preto je tam povinný SMEAR —
   bez neho by oko videlo dve oddelené kópie namiesto jedného pohybu.
   Karta sa objaví (opacity) v tej istej snímke, v ktorej vyráža; dovtedy
   je v obálke a vidno z nej len prúžok .vsp__hrana. */
@keyframes vsp-karta-vylet {
  0%     { transform: translateY(49.1%) scale(0.46, 0.46);                  opacity: 0;    animation-timing-function: steps(1); }
  11.1%  { transform: translateY(51%)   scale(0.51, 0.41);                  opacity: 0;    animation-timing-function: steps(1); }  /* stlačí sa s obálkou */
  22.2%  { transform: translateY(51%)   scale(0.51, 0.41);                  opacity: 0;    animation-timing-function: steps(1); }  /* HOLD — napätie */
  33.3%  { transform: translateY(40%)   scale(0.48, 0.60);                  opacity: 1;    animation-timing-function: steps(2); }  /* štart, naťahuje sa */
  44.4%  { transform: translateY(5%)    scale(0.42, 1.06) skewX(-4deg);     opacity: 0.92; animation-timing-function: steps(1); }  /* SMEAR */
  55.5%  { transform: translateY(-6%)   scale(0.92, 1.14);                  opacity: 1;    animation-timing-function: steps(2); }  /* PRESTREL */
  66.6%  { transform: translateY(3%)    scale(1.13, 0.89);                  opacity: 1;    animation-timing-function: steps(1); }  /* SQUASH — náraz */
  77.7%  { transform: translateY(-2%)   scale(0.96, 1.05);                  opacity: 1;    animation-timing-function: linear; }
  88.8%  { transform: translateY(1%)    scale(1.02, 0.98);                  opacity: 1;    animation-timing-function: linear; }
  100%   { transform: translateY(0)     scale(1, 1);                        opacity: 1; }
}
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__karta {
  animation: vsp-karta-vylet calc(9 * var(--f1)) linear calc(2 * var(--f1)) both;
}

/* Papierový prúžok v tmavom otvore zhasne v tej istej snímke, v ktorej sa
   karta objaví — inak by v obálke ostal ležať aj potom, čo z nej vyšla. */
@keyframes vsp-hrana-prec { 0%, 33.2% { opacity: 1; } 33.3%, 100% { opacity: 0; } }
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__hrana {
  animation: vsp-hrana-prec calc(9 * var(--f1)) steps(1) calc(2 * var(--f1)) both;
}

/* Mená dosadajú po karte, každé o snímku inak. Dve mená, ktoré dosadnú
   naraz, sú tuhý blok; dve s odstupom majú váhu. Prestrel je tvrdý,
   dokmit už plynulý — dosadanie po náraze sa podľa pravidla nekrokuje. */
@keyframes vsp-text-dosad {
  0%   { transform: translateY(38%) scale(0.88, 1.16); opacity: 0; animation-timing-function: steps(1); }
  25%  { transform: translateY(9%)  scale(0.93, 1.09); opacity: 1; animation-timing-function: steps(1); }
  50%  { transform: translateY(-6%) scale(1.11, 0.90); opacity: 1; animation-timing-function: linear; }  /* prestrel */
  75%  { transform: translateY(2%)  scale(0.98, 1.03); opacity: 1; animation-timing-function: linear; }
  /* opacity MUSÍ byť aj v poslednej snímke: chýbajúca vlastnosť sa
     dointerpoluje späť na podkladovú hodnotu (0) a text by zmizol. */
  100% { transform: translateY(0)   scale(1, 1);       opacity: 1; }
}
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__nadpis { animation: vsp-text-dosad calc(4 * var(--f1)) linear calc(11 * var(--f1)) both; }
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__meno--a { animation: vsp-text-dosad calc(4 * var(--f1)) linear calc(12 * var(--f1)) both; }
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__spojka { animation: vsp-text-dosad calc(4 * var(--f1)) linear calc(13 * var(--f1)) both; }
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__meno--b { animation: vsp-text-dosad calc(4 * var(--f1)) linear calc(14 * var(--f1)) both; }
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__linka { animation: vsp-text-dosad calc(4 * var(--f1)) linear calc(15 * var(--f1)) both; }
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__datum { animation: vsp-text-dosad calc(4 * var(--f1)) linear calc(16 * var(--f1)) both; }

/* Posledná bodka: srdce dopadne na papier a na jednu jedinú snímku sa
   sploští. Dve snímky by vyzerali ako chyba, nula ako guma.
   Pád je posun cez plochu → krokuje sa po ~24 fps; náraz je tvrdý;
   dokmit plynulý. */
@keyframes vsp-peciatka-dopad {
  0%   { transform: translateY(-320%) scale(0.62, 1.48); opacity: 0; animation-timing-function: steps(4); }
  40%  { transform: translateY(-40%)  scale(0.86, 1.20); opacity: 1; animation-timing-function: steps(1); }
  52%  { transform: translateY(0)     scale(1.38, 0.68); opacity: 1; animation-timing-function: steps(1); }  /* NÁRAZ */
  68%  { transform: translateY(-16%)  scale(0.92, 1.10); opacity: 1; animation-timing-function: linear; }
  84%  { transform: translateY(0)     scale(1.07, 0.94); opacity: 1; animation-timing-function: linear; }
  100% { transform: translateY(0)     scale(1, 1);       opacity: 1; }
}
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__peciatka {
  animation: vsp-peciatka-dopad calc(5 * var(--f1)) linear calc(18 * var(--f1)) both;
}

@keyframes vsp-rachot-buch {
  0%    { transform: scale(0.34); opacity: 1;   animation-timing-function: steps(1); }
  33.3% { transform: scale(0.78); opacity: 1;   animation-timing-function: steps(1); }
  66.6% { transform: scale(1.1);  opacity: 0.6; animation-timing-function: linear; }
  100%  { transform: scale(1.3);  opacity: 0; }
}
/* forwards, NIE both: pri `both` sa počas oneskorenia vykreslí 0 % snímka
   (opacity 1) a lúče by na scéne stáli od ťuknutia až po náraz. Overené na
   snímke — presne to sa dialo. Po dobehnutí drží 100 % snímku (opacity 0). */
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__rachot {
  animation: vsp-rachot-buch calc(3 * var(--f1)) linear calc(5 * var(--f1)) forwards;
}
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__rachot2 {
  animation: vsp-rachot-buch calc(3 * var(--f1)) linear calc(20.6 * var(--f1)) forwards;
}

@keyframes vsp-vyzva-prec { to { opacity: 0; transform: translateY(30%) scale(0.9); } }
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__vyzva {
  animation: vsp-vyzva-prec var(--f1) steps(1) both;
}

/* Celý herecký oblúk očí v jednej animácii: zavrie pri nápřahu,
   prekvapenie pri výstrele, spokojné prižmúrenie na koniec. */
@keyframes vsp-oko-akcia {
  0%   { transform: scaleY(1);                animation-timing-function: steps(1); }
  6%   { transform: scaleY(0.14);             animation-timing-function: steps(1); }  /* zavrie pri nápřahu */
  18%  { transform: scaleY(1.3) scaleX(1.12); animation-timing-function: linear; }    /* prekvapenie */
  38%  { transform: scaleY(1.1);              animation-timing-function: linear; }
  58%  { transform: scaleY(1);                animation-timing-function: linear; }
  84%  { transform: scaleY(0.3);              animation-timing-function: linear; }    /* spokojné prižmúrenie */
  100% { transform: scaleY(0.3); }
}
.vs[data-vstup="postava"]:not([data-faza="pokoj"]) .vsp__oko {
  animation: vsp-oko-akcia 2s linear both;
}

/* ══════════════════════════════════════════════════════════════════════
   BEZ POHYBU — kto ho má vypnutý, dostane rovno VÝSLEDOK, nie zrýchlenú
   verziu. Motor takej vrstve zabije všetky animácie cez !important, takže
   koncové pózy sa musia nastaviť staticky; inak by hosť videl zalepenú
   obálku a prázdnu kartu.
   ══════════════════════════════════════════════════════════════════════ */
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__ob {
  transform: translateY(20%) rotate(-3.5deg) scale(0.78);
}
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__ob--chlopna-a { opacity: 0; }
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__ob--chlopna-b { opacity: 1; }
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__chlopna-list { transform: rotateX(-163deg); }
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__pecat-in { opacity: 0; }
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__hrana { opacity: 0; }
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__karta { opacity: 1; transform: none; }
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__nadpis,
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__meno,
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__spojka,
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__linka,
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__datum,
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__peciatka { opacity: 1; }
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__vyzva,
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__rachot,
.vs[data-vstup="postava"][data-bez-pohybu="ano"] .vsp__rachot2 { opacity: 0; }
