/* One small cut-paper performance. Existing engine phases are the only
   triggers: no extra input lock, game clock, event loop or layout movement.
   The 1.4s loss scene fits inside the engine's existing explosion phase. */
.royale-stage {
  --show-loss: 1400ms;
  --show-bow: 1500ms;
  --show-rest-angle: -4deg;
}

/* A portrait and its coloured backing move as one physical paper cutout.
   These are held poses, not elastic interpolation or a perpetual idle loop. */
.royale-stage[data-phase="exploding"] .zine-character {
  transform-origin: 50% 80%;
  animation: show-host-recoil var(--show-loss) steps(1, end) both;
}
@keyframes show-host-recoil {
  0% { transform: rotate(var(--show-rest-angle)); }
  8% { transform: translate(7%, 2%) rotate(-15deg); }
  38% { transform: translate(7%, 2%) rotate(-15deg); }
  56% { transform: translate(1%, 4%) rotate(3deg); }
  76% { transform: translate(0, 1%) rotate(-7deg); }
  100% { transform: rotate(var(--show-rest-angle)); }
}
.royale-stage[data-phase="exploding"] .character-sprite {
  animation: show-recover-face var(--show-loss) steps(1, end) both;
}
.royale-stage[data-phase="exploding"] .character-backing {
  animation: show-recover-backing var(--show-loss) steps(1, end) both;
}
@keyframes show-recover-face {
  0%, 56% { background-position: 100% 0; }
  76% { background-position: 0 100%; }
  100% { background-position: 0 0; }
}
@keyframes show-recover-backing {
  0%, 56% { mask-position: 100% 0; }
  76% { mask-position: 0 100%; }
  100% { mask-position: 0 0; }
}

/* An ordinary hit recovers its cheeky face; an elimination does not smile
   straight back. Keep the surprised pose through the existing loss scene. */
.royale-stage[data-phase="exploding"][data-result-outcome="elimination"] .character-sprite {
  animation: none; background-position: 100% 0;
}
.royale-stage[data-phase="exploding"][data-result-outcome="elimination"] .character-backing {
  animation: none; mask-position: 100% 0;
}

/* One attentive lean when a larger match becomes a final pair. Its meaning
   appears at the following Start, leaving the previous loss uninterrupted.
   The existing 650ms root anchor clears this cue; no independent clock. */
.royale-stage.bomtafel[data-phase="running"][data-turn-event="start"][data-host-moment="final-two"] .zine-character {
  animation: show-final-two 360ms steps(1, end) 240ms both;
}
.royale-stage.bomtafel[data-phase="running"][data-turn-event="start"][data-host-moment="final-two"] .character-sprite { background-position: 100% 0; }
.royale-stage.bomtafel[data-phase="running"][data-turn-event="start"][data-host-moment="final-two"] .character-backing { mask-position: 100% 0; }
@keyframes show-final-two {
  0% { transform: rotate(var(--show-rest-angle)); }
  25%, 62% { transform: translate(4px, -5px) rotate(calc(var(--show-rest-angle) + 3deg)); }
  100% { transform: rotate(var(--show-rest-angle)); }
}

/* A compact black/orange impact opens into a jagged cut, then leaves.
   It stays inside the bomb's footprint, away from the result and scores. */
.royale-stage[data-phase="exploding"] .bomb-burst {
  animation: show-burst 640ms steps(1, end) both;
}
.royale-stage .bomb-burst::after {
  content: "";
  position: absolute;
  inset: 26% 28% 30% 26%;
  background: var(--paper) var(--stock) 40px 20px / 210px;
  clip-path: polygon(41% 0, 58% 28%, 100% 13%, 77% 49%, 98% 88%, 57% 75%, 34% 100%, 27% 63%, 0 48%, 28% 32%);
}
@keyframes show-burst {
  0% { transform: scale(.56) rotate(-9deg); opacity: 1; }
  18% { transform: scale(1) rotate(3deg); opacity: 1; }
  45% { transform: scale(.91) rotate(-5deg); opacity: 1; }
  72% { transform: scale(.79) rotate(5deg); opacity: 1; }
  100% { transform: scale(.79) rotate(5deg); opacity: 0; }
}

/* Only the struck heart moves, in exactly the same animation in both
   locations. All remaining hearts, name text and tracks stay still. The
   selector persists through roundEnd, so the loss cannot replay then. */
.royale-stage .paper-heart[data-losing="true"] {
  animation: show-heart-loss var(--show-loss) steps(1, end) both;
}
@keyframes show-heart-loss {
  0%, 36% { opacity: 1; transform: none; }
  46% { opacity: .12; transform: none; }
  58%, 68% { opacity: 1; transform: none; }
  82% { opacity: var(--empty-heart, .17); transform: translate(8%, 22%) rotate(12deg); }
  100% { opacity: var(--empty-heart, .17); transform: none; }
}
.royale-stage[data-phase="exploding"] .royale-result > :is(p, h2, .royale-result-hearts) {
  animation: show-result-arrive 280ms steps(1, end) both;
}
@keyframes show-result-arrive {
  0% { opacity: 0; }
  100% { opacity: 1; }
}

/* In C the ink is printed onto the paper: result text and material arrive
   together as one small physical piece. Keep the first 280ms for impact. */
.bomtafel[data-phase="exploding"] .royale-result {
  opacity: 0;
  animation: show-table-result 280ms steps(1, end) 280ms forwards;
}
.bomtafel[data-phase="exploding"] .royale-result > :is(p, h2, .royale-result-hearts) { animation: none; }
@keyframes show-table-result {
  0% { opacity: 1; transform: translateY(4px) rotate(.6deg); }
  50% { opacity: 1; transform: translateY(-1px) rotate(-.2deg); }
  100% { opacity: 1; transform: none; }
}

/* The winner gets a paper title and a crown, not an extra panel. Their name
   remains real, fitted text; the printing underneath does the stamping. */
.royale-stage[data-phase="matchEnd"] #royaleResultName {
  position: relative;
  isolation: isolate;
}
.royale-stage[data-phase="matchEnd"] #royaleResultName::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -9px -12px;
  background: var(--dark) var(--xerox) 36% 21% / 630px;
  clip-path: polygon(1% 8%, 26% 0, 62% 5%, 98% 0, 100% 84%, 96% 100%, 65% 94%, 2% 100%, 0 62%);
  animation: show-winner-print 440ms steps(1, end) both;
}
@keyframes show-winner-print {
  0% { transform: translateY(-8px) rotate(-2deg); opacity: 0; }
  45% { transform: translateY(2px) rotate(1deg); opacity: 1; }
  75% { transform: rotate(-1deg); opacity: 1; }
  100% { transform: none; opacity: 1; }
}
.royale-stage[data-phase="matchEnd"] .royale-result::before {
  background-blend-mode: multiply;
  animation: show-crown-land 860ms steps(1, end) both;
}
@keyframes show-crown-land {
  0%, 20% { transform: translateY(-35px) rotate(-18deg); opacity: 0; }
  32% { transform: translateY(-24px) rotate(-18deg); opacity: 1; }
  50% { transform: translateY(5px) rotate(4deg); opacity: 1; }
  72% { transform: translateY(-3px) rotate(-9deg); opacity: 1; }
  100% { transform: rotate(-6deg); opacity: 1; }
}
.royale-stage[data-phase="matchEnd"] .zine-character {
  transform-origin: 30% 82%;
  animation: show-host-bow var(--show-bow) steps(1, end) both;
}
@keyframes show-host-bow {
  0%, 20% { transform: rotate(var(--show-rest-angle)); }
  34% { transform: translate(3%, 4%) rotate(7deg); }
  48%, 68% { transform: translate(5%, 10%) rotate(17deg); }
  82% { transform: translate(2%, 2%) rotate(4deg); }
  100% { transform: rotate(var(--show-rest-angle)); }
}
.royale-stage[data-phase="matchEnd"] .character-sprite {
  animation: show-bow-face var(--show-bow) steps(1, end) both;
}
.royale-stage[data-phase="matchEnd"] .character-backing {
  animation: show-bow-backing var(--show-bow) steps(1, end) both;
}
@keyframes show-bow-face {
  0% { background-position: 100% 100%; }
  34% { background-position: 0 100%; }
  82%, 100% { background-position: 100% 100%; }
}
@keyframes show-bow-backing {
  0% { mask-position: 100% 100%; }
  34% { mask-position: 0 100%; }
  82%, 100% { mask-position: 100% 100%; }
}

/* The crown belongs to the winning sheet, not an independent animation
   above it. A single restrained landing moves crown, name and paper. */
.bomtafel[data-phase="matchEnd"] .royale-result {
  animation: show-table-victory 600ms steps(1, end) both;
}
.bomtafel[data-phase="matchEnd"] .royale-result::before,
.bomtafel[data-phase="matchEnd"] #royaleResultName::before { animation: none; }
@keyframes show-table-victory {
  0% { transform: translateY(-6px) rotate(-1deg); }
  33% { transform: translateY(2px) rotate(.4deg); }
  66%, 100% { transform: none; }
}
.bomtafel[data-phase="matchEnd"][data-show-settled="true"] .royale-result { animation: none; }

/* Once performed, returning through the game menu shows the held finale.
   This flag is written only by animationend and cleared on a phase change. */
.royale-stage[data-phase="matchEnd"][data-show-settled="true"] :is(.zine-character, .character-sprite, .character-backing),
.royale-stage[data-phase="matchEnd"][data-show-settled="true"] .royale-result::before,
.royale-stage[data-phase="matchEnd"][data-show-settled="true"] #royaleResultName::before { animation: none; }

@media (max-width: 900px) and (orientation: portrait) {
  .royale-stage { --show-rest-angle: 4deg; }
}

/* The desktop finale uses the former bomb column for the large crown.
   This is inside the existing result track: scores/controls never move. */
@media (min-width: 901px) and (min-height: 561px) {
  .royale-stage[data-phase="matchEnd"] .royale-result { padding: 14px 18px; gap: 24px; }
  .royale-stage[data-phase="matchEnd"] .royale-result > * {
    max-width: calc((100% - 18px) * var(--bout-word-share, .72));
  }
  .royale-stage[data-phase="matchEnd"] .royale-result::before {
    left: auto;
    right: 2%;
    top: 50%;
    translate: 0 -50%;
    width: 23%;
    height: auto;
    aspect-ratio: 115 / 72;
  }
}

/* All meaningful outcomes still appear immediately without moving paper.
   Result/heart semantics and the engine's input protection are unchanged. */
@media (prefers-reduced-motion: reduce) {
  .bomtafel[data-phase="exploding"] .royale-result,
  .bomtafel[data-phase="matchEnd"] .royale-result { animation: none !important; opacity: 1; transform: none; }
  .royale-stage :is(.zine-character, .character-sprite, .character-backing,
    .paper-heart[data-losing="true"], .bomb-burst),
  .royale-stage .royale-result > :is(p, h2, .royale-result-hearts),
  .royale-stage .royale-result::before,
  .royale-stage #royaleResultName::before { animation: none !important; }
  .royale-stage[data-phase="exploding"] .bomb-burst { opacity: 1; transform: none; }
}
@media (forced-colors: active) {
  .royale-stage[data-phase="matchEnd"] #royaleResultName::before { background: Canvas; outline: 2px solid CanvasText; }
  .royale-stage[data-phase="matchEnd"] .royale-result::before { background: Highlight; }
  .royale-stage .bomb-burst::after { background: Canvas; }
}
