/* =============================================================================
   animations/epic.css - The `epic` mode (`data-animation="epic"`).

   The staged version of the choreography: light rays and dust motes around the pack, a
   shockwave and a wider zoom on the flipped card, a real halo for rarities 4 and 5, and a
   light sweep over the summary. Every rule is keyed on `body[data-animation="epic"]`, so this
   mode can never leak into another one. Shared contract and duration defaults:
   `css/animations/defaults.css`.
   ============================================================================= */

/* =============================================================================
   EPIC
   ============================================================================= */

/* --- The pack --------------------------------------------------------------- */

/* Tear: the booster rises out of the frame while the stage flashes with the accent colour. */
body[data-animation="epic"] .booster-3d.is-tearing .booster-3d__viewport,
body[data-animation="epic"] .booster-3d.is-tearing .booster-3d__fallback {
  animation: booster-tear-epic var(--anim-tear-ms) var(--easing-standard) forwards;
}

/* The flash is a pseudo-element of the stage box (which already clips its content), so it can
   never widen the layout. */
body[data-animation="epic"] .booster-3d::after {
  content: '';
  position: absolute;
  inset: -12%;
  opacity: 0;
  pointer-events: none;
  background-image: radial-gradient(circle at 50% 44%, var(--color-accent), transparent 62%);
}

body[data-animation="epic"] .booster-3d.is-tearing::after {
  animation: animation-flash var(--anim-tear-ms) var(--easing-standard) forwards;
}

/* Rays behind the pack: a cone of light the booster is pulled out of. `isolation` makes the
   stage its own stacking context, so the `z-index: -1` below lands behind the canvas and
   behind the hint but in front of the stage background - without touching the canvas at all. */
body[data-animation="epic"] .booster-3d {
  isolation: isolate;
}

body[data-animation="epic"] .booster-3d::before {
  content: '';
  position: absolute;
  inset: -40%;
  z-index: -1;
  opacity: 0;
  pointer-events: none;
  background-image: conic-gradient(
    from 0deg at 50% 50%,
    transparent 0deg,
    var(--color-accent) 6deg,
    transparent 14deg,
    transparent 40deg,
    var(--color-accent) 46deg,
    transparent 54deg,
    transparent 90deg,
    var(--color-accent) 96deg,
    transparent 104deg,
    transparent 140deg,
    var(--color-accent) 146deg,
    transparent 154deg,
    transparent 190deg,
    var(--color-accent) 196deg,
    transparent 204deg,
    transparent 240deg,
    var(--color-accent) 246deg,
    transparent 254deg,
    transparent 290deg,
    var(--color-accent) 296deg,
    transparent 304deg,
    transparent 340deg,
    var(--color-accent) 346deg,
    transparent 354deg
  );
  animation: epic-rays var(--anim-tear-ms) var(--easing-standard) forwards;
}

@keyframes epic-rays {
  0% {
    opacity: 0;
    rotate: -6deg;
    scale: 0.75;
  }
  35% {
    opacity: 0.36;
  }
  100% {
    opacity: 0;
    rotate: 22deg;
    scale: 1.15;
  }
}

/* Dust motes drifting up in the light, behind the cards. Two layers of dots at different speeds:
   cheap, and it never asked the compositor for more than it can give.

   They cover the WHOLE opening screen, not the box of the spotlight card: the ritual is one scene
   from the pack landing to the summary, and light that drifts only around one card made the rest
   of the screen look like it was switched off. The pseudo-element therefore hangs on the SCENE
   (which exists for the whole ritual and is `hidden` on the picker screen), is `fixed` - the scene
   is a plain `position: relative` box, so it really is the viewport - and carries a NEGATIVE
   `z-index`: dots painted in the in-flow layer would end up over the hints and the texts, while a
   negative one stays above the background of the page and below everything the player reads. */
body[data-animation="epic"] .opening__scene::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.4;
  background-image:
    radial-gradient(circle, var(--color-accent) 0 1.5px, transparent 2px),
    radial-gradient(circle, var(--color-accent) 0 1px, transparent 2px);
  background-size: 90px 130px, 140px 90px;
  background-position: 12px 40px, 60px 10px;
  animation: epic-motes 9s linear infinite;
}

@keyframes epic-motes {
  from {
    background-position: 12px 40px, 60px 10px;
  }
  to {
    background-position: 12px -220px, 60px -180px;
  }
}

@keyframes booster-tear-epic {
  0% {
    opacity: 1;
    transform: translateY(0) scale(1) rotate(0deg);
  }
  35% {
    opacity: 1;
    transform: translateY(-6%) scale(1.16) rotate(2deg);
  }
  100% {
    opacity: 0;
    transform: translateY(-34%) scale(1.45) rotate(-6deg);
  }
}

@keyframes animation-flash {
  0% {
    opacity: 0;
  }
  30% {
    opacity: 0.7;
  }
  100% {
    opacity: 0;
  }
}

/* --- The card --------------------------------------------------------------- */

/* Spotlight: the card arrives from further away than in the base flavour, with a stronger tilt. */
body[data-animation="epic"] .opening__stage .card-reveal__card {
  animation: spotlight-rise-epic var(--anim-flip-ms) var(--easing-standard);
}

body[data-animation="epic"] .opening__stage .card-reveal__card.is-entering-next {
  animation:
    spotlight-rise-epic var(--anim-flip-ms) var(--easing-standard),
    spotlight-in-right-epic var(--anim-flip-ms) var(--easing-standard);
}

body[data-animation="epic"] .opening__stage .card-reveal__card.is-entering-prev {
  animation:
    spotlight-rise-epic var(--anim-flip-ms) var(--easing-standard),
    spotlight-in-left-epic var(--anim-flip-ms) var(--easing-standard);
}

@keyframes spotlight-rise-epic {
  from {
    opacity: 0;
    transform: translateY(42px) scale(0.86) rotateX(16deg);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes spotlight-in-right-epic {
  from {
    opacity: 0;
    transform: translateX(120px) rotate(6deg) scale(0.9);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes spotlight-in-left-epic {
  from {
    opacity: 0;
    transform: translateX(-120px) rotate(-6deg) scale(0.9);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Flip: a wider half turn than the base one, and the card ends up a touch closer to the player. */
body[data-animation="epic"] .card-reveal__card.is-flipped {
  animation: card-flip-hero var(--anim-flip-ms) var(--easing-standard) both;
}

@keyframes card-flip-hero {
  0% {
    transform: rotateY(0deg) scale(1);
  }
  50% {
    transform: rotateY(150deg) scale(1.18);
  }
  74% {
    transform: rotateY(198deg) scale(1.06);
  }
  100% {
    transform: rotateY(180deg) scale(1);
  }
}

/* The shockwave: a ring leaving the card as it lands, plus a second, fainter one behind it.
   Same deal as the base halo - it lives on the card element, never inside a face, and an
   outline is used instead of a filter (see the header). */
body[data-animation="epic"] .card-reveal__card.is-flipped::after {
  content: '';
  position: absolute;
  inset: -14%;
  z-index: 1;
  border: 2px solid var(--color-accent);
  border-radius: var(--radius-md);
  opacity: 0;
  pointer-events: none;
  animation: epic-shockwave var(--anim-flip-ms) var(--easing-standard) 90ms;
}

@keyframes epic-shockwave {
  0% {
    opacity: 0.85;
    scale: 0.72;
  }
  100% {
    opacity: 0;
    scale: 1.3;
  }
}

/* Rarities 4 and 5 get a bigger halo in this mode... */
body[data-animation="epic"] .card-reveal__card--r4.is-flipped::after,
body[data-animation="epic"] .card-reveal__card--r5.is-flipped::after {
  border-width: 3px;
  background-image: radial-gradient(circle at 50% 50%, var(--color-accent) 10%, transparent 66%);
}

/* ... and mythics breathe in the spotlight. `card-glow-strong` already runs on the front face;
   this is the whole card leaning in and out of the light.

   The Mine Pick stage is EXCLUDED (`:not(.minepick__card)`), like in `css/components/
   card-reveal.css`: the outline of a card there belongs to the ring of `css/views/minepick.css`
   (rarity colour, then green for the card that was kept), and this rule is MORE specific than
   that one, so a blue `outline-color` would repaint a mythic and hide the green. */
body[data-animation="epic"] .card-reveal__card--r5.is-flipped:not(.minepick__card) {
  outline-color: var(--color-accent);
}

body[data-animation="epic"] .opening__stage .card-reveal__card--r5.is-flipped {
  animation:
    card-flip-hero var(--anim-flip-ms) var(--easing-standard) both,
    epic-breathing 3.4s ease-in-out var(--anim-flip-ms) infinite;
}

@keyframes epic-breathing {
  0%,
  100% {
    outline-color: var(--color-accent);
  }
  50% {
    outline-color: transparent;
  }
}

/* --- The summary ------------------------------------------------------------ */

/* The tiles keep their base pop: what the mode adds is a light sweep crossing the grid. */
body[data-animation="epic"] .card-reveal--summary {
  position: relative;
}

body[data-animation="epic"] .card-reveal--summary::after {
  content: '';
  position: absolute;
  /* Horizontal inset stays at 0: an absolutely positioned box wider than its grid would add a
     scrollbar to the page for a sweep nobody asked to scroll to. */
  inset: -6% 0;
  pointer-events: none;
  background-image: linear-gradient(
    100deg,
    transparent 42%,
    var(--color-surface-alt) 50%,
    transparent 58%
  );
  animation: epic-summary-sweep 1.6s var(--easing-standard) 320ms both;
}

@keyframes epic-summary-sweep {
  0% {
    opacity: 0;
    translate: -40% 0;
  }
  25% {
    opacity: 0.85;
  }
  100% {
    opacity: 0;
    translate: 40% 0;
  }
}

body[data-animation="epic"] .opening__summary {
  animation: summary-stamp 340ms var(--easing-standard) backwards;
  font-weight: 700;
  letter-spacing: 0.05em;
  transform-origin: 50% 50%;
}

@keyframes summary-stamp {
  from {
    opacity: 0;
    transform: scale(0.8);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
