/* The Card Stage: the card, presented the way pulling it feels.
 *
 * The public card page's (web/pages.py); the tier and motif come from
 * web/rarity.py.
 *
 * Three rules shape this file:
 *
 * 1. The un-animated styles ARE the settled stage. What a reader with
 *    reduced motion, or without JavaScript, sees is the finished picture -
 *    ambient art glow, halo, rays, floor light, foil - not a stripped-down
 *    one. `rv-*` keyframes play the reveal on top of it from first paint,
 *    `amb-*` keyframes keep the settled stage alive afterwards.
 * 2. The reveal is a performance in three acts, timed by `--reveal` (the
 *    moment of arrival, per tier): anticipation (the card waits in shadow
 *    while light gathers behind it), arrival (a flash, shockwave rings and an
 *    anamorphic streak as the card lights up) and afterglow (a slow, living
 *    loop). A Common simply settles; a Special Illustration Rare gets the
 *    whole show. card-stage.js adds particles and a nebula on the same clock.
 * 3. Spectacle ends at the stage's soft edge. These pigments (--sa/--sb/
 *    --sc/--sd) never touch --pos, --neg or any research colour, and the
 *    research beside the stage stays exactly as calm as it was.
 *
 * The card is never hidden (it is the page's LCP image): during the
 * anticipation it is visible but dim, and it "powers up" on arrival.
 */

/* -------------------------------------------------------------- dials --- */

.card-stage {
  /* motif pigments - pearl by default */
  --sa: #d7e0ee; --sb: #8e9fc6; --sc: #f6ecd6; --sd: #b9c7e6;
  /* the card */
  --cw: 272px;
  /* tier dials (tier 0: a quiet, lit presentation, no show) */
  --reveal: 0s;        /* moment of arrival */
  --dim: .82;          /* card brightness while it waits */
  --pop: 1.1;          /* how brightly it lights up on arrival */
  --arrive: .8s;       /* how long the card takes to power up */
  --amb-o: .30;        /* the art's own coloured glow */
  --halo-o: 0; --rays-o: 0; --pool-o: .55; --dust-o: 0;
  --core-o: 0; --flash-o: 0; --ring-o: 0; --streak-o: 0;
  --rim: 0px; --foil-o: .16;
  --glint-every: 11s;
  /* pointer and parallax, written by card-stage.js */
  --rx: 0deg; --ry: 0deg; --px: 0; --py: 0; --fx: 0; --fy: 0;

  position: relative; isolation: isolate;
  width: 100%; height: calc(var(--cw) * 1.72);
  display: grid; place-items: center;
  perspective: 1200px;
  -webkit-tap-highlight-color: transparent;
}

.card-stage[data-tier="1"] {
  --pop: 1.3; --reveal: .45s; --dim: .6; --arrive: 1s;
  --amb-o: .42; --halo-o: .22; --pool-o: .62; --dust-o: .35;
  --rim: 18px; --foil-o: .2; --glint-every: 10s;
}
.card-stage[data-tier="2"] {
  --pop: 1.5; --reveal: .8s; --dim: .45; --arrive: 1.1s;
  --amb-o: .5; --halo-o: .34; --rays-o: .22; --pool-o: .7; --dust-o: .5;
  --core-o: .45; --flash-o: .35; --ring-o: .5;
  --rim: 26px; --foil-o: .26; --glint-every: 9s;
}
.card-stage[data-tier="3"] {
  --edge-o: .55; --pop: 1.75; --reveal: 1.25s; --dim: .34; --arrive: 1.2s;
  --amb-o: .58; --halo-o: .5; --rays-o: .3; --pool-o: .78; --dust-o: .65;
  --core-o: .7; --flash-o: .55; --ring-o: .7; --streak-o: .45;
  --rim: 34px; --foil-o: .3; --glint-every: 8s;
}
.card-stage[data-tier="4"] {
  --edge-o: .8; --edge-t: 11s; --pop: 2; --reveal: 1.7s; --dim: .26; --arrive: 1.35s;
  --amb-o: .66; --halo-o: .62; --rays-o: .38; --pool-o: .85; --dust-o: .8;
  --core-o: .85; --flash-o: .72; --ring-o: .85; --streak-o: .7;
  --rim: 42px; --foil-o: .34; --glint-every: 7.5s;
}
.card-stage[data-tier="5"] {
  --edge-o: 1; --pop: 2.35; --reveal: 2.2s; --dim: .18; --arrive: 1.5s;
  --amb-o: .74; --halo-o: .78; --rays-o: .48; --pool-o: .95; --dust-o: 1;
  --core-o: 1; --flash-o: .9; --ring-o: 1; --streak-o: .95;
  --rim: 54px; --foil-o: .38; --glint-every: 7s;
}

[data-motif="gold"] { --sa: #ffcf5c; --sb: #d0801f; --sc: #fff2c2; --sd: #ffe08a; }
[data-motif="prismatic"] { --sa: #a08cff; --sb: #3fe0cf; --sc: #ff8ccd; --sd: #ffe27a; }
[data-motif="aurora"] { --sa: #6ff0bd; --sb: #8f7bff; --sc: #ffc08a; --sd: #7fd8ff; }
[data-motif="starfield"] { --sa: #bfe4ff; --sb: #8f97ff; --sc: #ffffff; --sd: #d8c8ff; }
[data-motif="sunburst"] { --sa: #ffd36e; --sb: #ff7f50; --sc: #fff1c2; --sd: #ffb347; }
[data-motif="tech"] { --sa: #ff5fc8; --sb: #8a52ff; --sc: #ffd3f0; --sd: #5fd2ff; }

/* --------------------------------------------------------- the layers --- */

/* Behind the card. The light reaches a little past the column (into the
   gap, never the text) and its soft elliptical mask is the stage's only
   edge: nothing here is ever a box. */
.stage-back, .stage-fx {
  position: absolute; inset: -64px -40px -28px; pointer-events: none; overflow: hidden;
  -webkit-mask-image: radial-gradient(closest-side, #000 70%, transparent 100%);
  mask-image: radial-gradient(closest-side, #000 70%, transparent 100%);
}
.stage-back { z-index: 0; }
.stage-fx { z-index: 2; }
.stage-back > *, .stage-fx > * {
  position: absolute; left: 50%; top: 50%;
  translate: -50% -50%; pointer-events: none;
}

/* The art's own colours, blurred into light: every card glows in its own
   palette, which no fixed motif could match. */
.stage-ambient {
  width: calc(var(--cw) * 1.06); height: calc(var(--cw) * 1.48);
  background: var(--art, none) center / cover no-repeat;
  filter: blur(46px) saturate(1.9) brightness(1.15);
  opacity: var(--amb-o); border-radius: 30%;
}
/* The motif's halo: a slowly turning ring of coloured light. */
.stage-halo {
  width: calc(var(--cw) * 1.62); aspect-ratio: 1;
  border-radius: 50%; opacity: var(--halo-o);
  background: conic-gradient(from 0deg, var(--sa), var(--sb) 22%, transparent 36%,
    var(--sc) 52%, var(--sd) 66%, transparent 80%, var(--sa));
  -webkit-mask-image: radial-gradient(closest-side, transparent 42%, #000 60%, transparent 96%);
  mask-image: radial-gradient(closest-side, transparent 42%, #000 60%, transparent 96%);
  filter: blur(22px);
}
/* God-rays: two counter-rotating fans with different ray counts, so the
   light shimmers where they cross instead of turning like a wheel. */
.stage-rays {
  width: calc(var(--cw) * 3.4); aspect-ratio: 1; opacity: var(--rays-o);
  background: repeating-conic-gradient(from 8deg, transparent 0deg 6.5deg,
    color-mix(in srgb, var(--sc) 90%, transparent) 9deg, transparent 12.5deg 22.5deg);
  -webkit-mask-image: radial-gradient(closest-side, #000 18%, rgba(0,0,0,.7) 42%, transparent 78%);
  mask-image: radial-gradient(closest-side, #000 18%, rgba(0,0,0,.7) 42%, transparent 78%);
  mix-blend-mode: screen;
}
.stage-rays + .stage-rays {
  opacity: calc(var(--rays-o) * .7);
  background: repeating-conic-gradient(from 0deg, transparent 0deg 11deg,
    color-mix(in srgb, var(--sa) 75%, transparent) 13.5deg, transparent 16deg 32.7deg);
}
.card-stage[data-motif="sunburst"] .stage-rays {
  background: repeating-conic-gradient(from 0deg, transparent 0deg 4deg,
    color-mix(in srgb, var(--sc) 85%, transparent) 6deg, transparent 8deg 15deg);
}
/* Light gathering behind the card before it arrives. */
.stage-core {           /* shaped like the card, larger: light leaking round it */
  width: calc(var(--cw) * 2.05); height: calc(var(--cw) * 2.7);
  border-radius: 50%; opacity: 0;
  background: radial-gradient(closest-side, var(--sc) 0 48%,
    color-mix(in srgb, var(--sa) 88%, transparent) 60%,
    color-mix(in srgb, var(--sb) 40%, transparent) 73%, transparent 88%);
  mix-blend-mode: screen;
}
/* Shockwaves: three staggered rings leaving the card on arrival. */
.stage-ring {
  width: calc(var(--cw) * 1.2); aspect-ratio: 1; border-radius: 50%; opacity: 0;
  border: 2px solid var(--sc);
  box-shadow: 0 0 22px 2px var(--sa), inset 0 0 22px 2px var(--sa);
}
/* Floor light the card stands on. */
.stage-pool {
  top: calc(50% + var(--cw) * .78);
  width: calc(var(--cw) * 1.7); height: calc(var(--cw) * .34);
  border-radius: 50%; opacity: var(--pool-o);
  background: radial-gradient(closest-side, color-mix(in srgb, var(--sc) 55%, transparent),
    color-mix(in srgb, var(--sa) 25%, transparent) 55%, transparent);
  filter: blur(10px);
}
/* A painted sparkle field: the still picture's stand-in for the particles
   card-stage.js draws (hidden once they run). */
.stage-dust {
  width: 100%; height: 100%; opacity: var(--dust-o);
  background:
    radial-gradient(circle at 14% 30%, var(--sc) 0 1.2px, transparent 2.6px),
    radial-gradient(circle at 86% 62%, var(--sa) 0 1.4px, transparent 3px),
    radial-gradient(circle at 9% 72%, var(--sb) 0 1px, transparent 2.4px),
    radial-gradient(circle at 91% 28%, var(--sc) 0 1.6px, transparent 3.2px),
    radial-gradient(circle at 22% 88%, var(--sd) 0 1.1px, transparent 2.6px),
    radial-gradient(circle at 78% 14%, var(--sc) 0 1.2px, transparent 2.8px),
    radial-gradient(circle at 70% 90%, var(--sa) 0 1px, transparent 2.4px),
    radial-gradient(circle at 30% 10%, var(--sd) 0 1.3px, transparent 2.8px),
    radial-gradient(circle at 5% 48%, var(--sc) 0 .9px, transparent 2.2px),
    radial-gradient(circle at 95% 84%, var(--sd) 0 1.1px, transparent 2.6px);
}
.stage-live .stage-dust { display: none; }
/* Canvases added by card-stage.js. */
.stage-nebula { width: 100%; height: 100%; mix-blend-mode: screen; }
.stage-particles, .stage-front { width: 100%; height: 100%; }
.stage-nebula, .stage-particles {
  translate: calc(-50% + var(--px) * -10px) calc(-50% + var(--py) * -8px);
}
.stage-front { translate: calc(-50% + var(--px) * 16px) calc(-50% + var(--py) * 12px); }

/* In front of the card: the arrival flash and the lens streak. */
.stage-flash {
  width: calc(var(--cw) * 2.6); aspect-ratio: 1; border-radius: 50%; opacity: 0;
  background: radial-gradient(closest-side, #fff 0%, color-mix(in srgb, var(--sc) 90%, transparent) 16%,
    color-mix(in srgb, var(--sa) 45%, transparent) 42%, transparent 70%);
  mix-blend-mode: screen;
}
.stage-streak {
  width: calc(var(--cw) * 3.6); height: calc(var(--cw) * .12); opacity: 0;
  border-radius: 50%;
  background: radial-gradient(closest-side, #fff 0%, var(--sc) 20%,
    color-mix(in srgb, var(--sa) 60%, transparent) 50%, transparent 100%);
  filter: blur(3px); mix-blend-mode: screen;
}

/* ----------------------------------------------------------- the card --- */

/* Light running round the card's edge - the frame a legendary card gets.
   A conic gradient on a square that turns (a compositor-only rotation, no
   repaint), clipped to a hairline just outside the card; its twin, blurred,
   is the glow. Tiers 3-5 only. */
.stage-edge {
  position: absolute; inset: -2px; z-index: 0; pointer-events: none;
  border-radius: 5.2% / 3.8%; overflow: hidden; opacity: var(--edge-o, 0);
  animation: rv-hide var(--reveal) linear, rv-fade-in 1.4s ease-out var(--reveal);
}
.stage-edge.stage-edge-glow { inset: -14px; border-radius: 11%; filter: blur(15px); }
.stage-edge::before {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 180%; aspect-ratio: 1; translate: -50% -50%;
  background: conic-gradient(from 0deg, transparent 0 56%,
    color-mix(in srgb, var(--sa) 70%, transparent) 70%, var(--sc) 77%,
    var(--sb) 82%, transparent 92%);
  animation: amb-spin var(--edge-t, 13s) linear infinite;
}
.card-stage[data-tier="5"] .stage-edge::before {
  background: conic-gradient(from 0deg, transparent 0 14%,
    color-mix(in srgb, var(--sa) 70%, transparent) 24%, var(--sc) 30%, var(--sb) 35%,
    transparent 45% 64%, color-mix(in srgb, var(--sd) 70%, transparent) 74%,
    var(--sc) 80%, var(--sa) 85%, transparent 95%);
  animation-duration: 16s;
}
.card-stage:is([data-tier="0"], [data-tier="1"], [data-tier="2"]) .stage-edge { display: none; }
@keyframes rv-fade-in { from { opacity: 0; } }

.stage-tilt {
  position: relative; z-index: 1; isolation: isolate;
  transform-style: preserve-3d;
  transform: rotateX(var(--rx)) rotateY(var(--ry));
}
.stage-card {
  position: relative; z-index: 1; width: var(--cw); aspect-ratio: 200 / 278;
  border-radius: 4.6% / 3.3%; overflow: hidden;
  background: #1b1714;
  box-shadow:
    0 34px 60px -22px #000, 0 12px 24px -8px rgba(0, 0, 0, .7),
    0 0 var(--rim) calc(var(--rim) * -.35) color-mix(in srgb, var(--sa) 60%, transparent);
}
.stage-card::after {       /* the card's edge catching the light */
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .1),
    inset 0 1px 0 rgba(255, 255, 255, .22);
  pointer-events: none; z-index: 3;
}
.stage-card > .pv-art, .stage-card > .art {
  display: block; width: 100% !important; max-width: none; height: 100%;
  aspect-ratio: auto; border-radius: 0; margin: 0; box-shadow: none;
}
.stage-card > .pv-art-none { height: 100%; }
.stage-card img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Holographic foil, for foil printings: a rainbow band that slides with
   the light (the pointer, or a slow drift) and a glitter field, in the
   motif's palette, plus a soft highlight where the light falls. Both move by
   `translate` - the compositor's job, no repaint - and `color-dodge` lifts
   the art's own highlights instead of painting over it. */
.stage-foil {
  position: absolute; inset: 0; z-index: 1; pointer-events: none; overflow: hidden;
  display: none; opacity: var(--foil-o); mix-blend-mode: color-dodge;
}
.stage-foil::before {
  content: ""; position: absolute; inset: -60%;
  background: repeating-linear-gradient(115deg,
    color-mix(in srgb, var(--sa) 80%, #000) 0%, color-mix(in srgb, var(--sb) 80%, #000) 4%,
    color-mix(in srgb, var(--sc) 80%, #000) 8%, color-mix(in srgb, var(--sd) 80%, #000) 12%,
    color-mix(in srgb, var(--sa) 80%, #000) 16%);
  translate: calc(var(--fx) * 22%) calc(var(--fy) * 22%);
  will-change: translate;
}
.stage-foil::after {        /* glitter */
  content: ""; position: absolute; inset: 0; opacity: .55; mix-blend-mode: overlay;
  background:
    radial-gradient(circle at 20% 30%, #fff 0 .6px, transparent 1.2px),
    radial-gradient(circle at 70% 60%, #fff 0 .6px, transparent 1.2px),
    radial-gradient(circle at 40% 80%, #fff 0 .5px, transparent 1.1px),
    radial-gradient(circle at 85% 20%, #fff 0 .6px, transparent 1.2px);
  background-size: 23px 29px, 31px 37px, 19px 17px, 41px 43px;
}
.card-stage[data-foil="true"] .stage-foil { display: block; }
.card-stage[data-motif="starfield"] .stage-foil::after { opacity: .9; }
.stage-shine {              /* where the light falls on the card */
  position: absolute; left: 50%; top: 50%; z-index: 2; pointer-events: none;
  width: 130%; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 255, 255, .34),
    rgba(255, 255, 255, .08) 45%, transparent);
  mix-blend-mode: soft-light;
  translate: calc(-50% + var(--fx) * 38%) calc(-50% + var(--fy) * 38%);
  will-change: translate;
}
/* A glint sweeping across the card now and then. */
.stage-glint {
  position: absolute; inset: -40%; z-index: 2; pointer-events: none; opacity: 0;
  background: linear-gradient(105deg, transparent 40%, rgba(255, 255, 255, .06) 45%,
    rgba(255, 255, 255, .5) 50%, rgba(255, 255, 255, .06) 55%, transparent 60%);
  mix-blend-mode: soft-light;
  translate: -60% 0;
}
.card-stage[data-tier="0"] .stage-glint { display: none; }
.card-stage[data-tier="0"]:not([data-foil="true"]) .stage-shine { opacity: .5; }
.card-stage:not([data-tier="0"]) { cursor: pointer; }   /* a tap replays it */

/* What a tier does not have, it does not paint. */
.card-stage[data-tier="0"] :is(.stage-halo, .stage-rays, .stage-core, .stage-ring,
  .stage-flash, .stage-streak, .stage-dust),
.card-stage[data-tier="1"] :is(.stage-rays, .stage-core, .stage-ring, .stage-flash, .stage-streak),
.card-stage[data-tier="2"] :is(.stage-rays + .stage-rays, .stage-ring ~ .stage-ring, .stage-streak),
.card-stage[data-tier="3"] :is(.stage-ring ~ .stage-ring ~ .stage-ring) { display: none; }
.card-stage:not([style*="--art"]) .stage-ambient { display: none; }

/* ------------------------------------------------------------- reveal --- */

/* Act one - anticipation: the card waits, dim and a little low. */
.stage-card { animation: rv-wait var(--reveal) linear,
  rv-arrive var(--arrive) cubic-bezier(.2, .7, .15, 1) var(--reveal); }
/* The ambient layers stay dark until the card arrives, then flare past their
   settled level and ease back into it. */
.stage-ambient, .stage-halo, .stage-pool {
  animation: rv-hide var(--reveal) linear,
    rv-bloom 2.4s cubic-bezier(.16, .8, .2, 1) var(--reveal);
}
.stage-ambient { animation: rv-glow-wait var(--reveal) ease-in,
  rv-bloom 2.4s cubic-bezier(.16, .8, .2, 1) var(--reveal),
  amb-breathe 8s ease-in-out calc(var(--reveal) + 2.4s) infinite alternate; }
.stage-halo { animation: rv-hide var(--reveal) linear,
  rv-bloom 2.6s cubic-bezier(.16, .8, .2, 1) var(--reveal),
  amb-spin 46s linear var(--reveal) infinite; }
.stage-rays { animation: rv-hide var(--reveal) linear,
  rv-rays 2.2s cubic-bezier(.12, .85, .2, 1) var(--reveal),
  amb-spin 150s linear infinite; }
.stage-rays + .stage-rays { animation: rv-hide var(--reveal) linear,
  rv-rays 2.6s cubic-bezier(.12, .85, .2, 1) var(--reveal),
  amb-spin-back 210s linear infinite; }
.stage-core { animation: rv-charge var(--reveal) cubic-bezier(.5, 0, .9, .6),
  rv-release .7s ease-out var(--reveal); }
.stage-ring { animation: rv-ring 1.9s cubic-bezier(.1, .7, .25, 1) var(--reveal) backwards; }
.stage-ring + .stage-ring { animation-delay: calc(var(--reveal) + .16s); animation-duration: 2.1s; }
.stage-ring + .stage-ring + .stage-ring { animation-delay: calc(var(--reveal) + .36s); animation-duration: 2.4s; }
.stage-flash { animation: rv-flash 1.1s cubic-bezier(.1, .6, .3, 1) var(--reveal) backwards; }
.stage-streak { animation: rv-streak 1.4s cubic-bezier(.1, .7, .2, 1) var(--reveal) backwards; }
.stage-glint { animation: amb-glint var(--glint-every) ease-in-out
  calc(var(--reveal) + var(--arrive) + .2s) infinite; }
.stage-dust { animation: rv-hide var(--reveal) linear,
  amb-twinkle 5s ease-in-out var(--reveal) infinite alternate; }

@keyframes rv-wait {
  from, to { filter: brightness(var(--dim)) saturate(.45) contrast(1.06);
             transform: translateY(9px) scale(.97); }
}
@keyframes rv-arrive {
  0% { filter: brightness(var(--pop)) saturate(1.5); transform: translateY(0) scale(1.05); }
  30% { filter: brightness(1.18) saturate(1.15); transform: scale(.992); }
  62% { filter: brightness(1.03); transform: scale(1.004); }
  100% { filter: none; transform: none; }
}
.card-stage[data-tier="0"] .stage-card {
  animation: rv-settle .9s cubic-bezier(.2, .7, .2, 1) backwards;
}
@keyframes rv-settle {
  from { filter: brightness(.8); transform: translateY(14px) scale(.975); }
}
@keyframes rv-hide { from, to { opacity: 0; } }
@keyframes rv-glow-wait {
  from { opacity: 0; }
  to { opacity: calc(var(--amb-o) * .35); }
}
@keyframes rv-bloom {
  0% { opacity: 0; scale: .78; }
  14% { opacity: 1; scale: 1.08; }
  100% { scale: 1; }
}
@keyframes rv-rays {
  0% { opacity: 0; scale: .35; }
  18% { opacity: calc(var(--rays-o) * 2.4); }
  100% { scale: 1; }
}
/* Charging up: a pulse that quickens, like a heartbeat before a jump. */
@keyframes rv-charge {
  0% { opacity: 0; scale: .2; }
  30% { opacity: calc(var(--core-o) * .28); scale: .55; }
  42% { opacity: calc(var(--core-o) * .18); }
  54% { opacity: calc(var(--core-o) * .5); scale: .72; }
  63% { opacity: calc(var(--core-o) * .3); }
  72% { opacity: calc(var(--core-o) * .72); scale: .86; }
  79% { opacity: calc(var(--core-o) * .48); }
  86% { opacity: calc(var(--core-o) * .9); scale: .97; }
  91% { opacity: calc(var(--core-o) * .7); }
  96% { opacity: var(--core-o); scale: 1.06; }
  100% { opacity: var(--core-o); scale: 1.12; }
}
@keyframes rv-release {
  from { opacity: var(--core-o); scale: 1.12; }
  to { opacity: 0; scale: 1.9; }
}
@keyframes rv-ring {
  0% { opacity: var(--ring-o); scale: .5; border-width: 3px; }
  100% { opacity: 0; scale: 2.6; border-width: 1px; }
}
@keyframes rv-flash {
  0% { opacity: 0; scale: .6; }
  6% { opacity: var(--flash-o); scale: 1; }
  100% { opacity: 0; scale: 1.25; }
}
@keyframes rv-streak {
  0% { opacity: 0; scale: .08 1; }
  8% { opacity: var(--streak-o); scale: 1 1; }
  100% { opacity: 0; scale: 1.5 .4; }
}
@keyframes amb-spin { to { rotate: 360deg; } }
@keyframes amb-spin-back { to { rotate: -360deg; } }
@keyframes amb-breathe {
  from { scale: 1; }
  to { scale: 1.07; }
}
@keyframes amb-twinkle {
  from { opacity: calc(var(--dust-o) * .55); }
  to { opacity: var(--dust-o); }
}
@keyframes amb-glint {
  0% { opacity: 0; translate: -60% 0; }
  3% { opacity: 1; }
  17% { opacity: 1; translate: 60% 0; }
  20%, 100% { opacity: 0; translate: 60% 0; }
}

/* A card opened again without leaving it (an app refresh) is already lit:
   every reveal is finished, every loop already running. */
.stage-settled, .stage-settled * { animation-delay: -120s !important; }
/* Replaying: every animation off for one style pass (card-stage.js). */
.stage-restart, .stage-restart * { animation: none !important; }
/* card-stage.js holds the show until the artwork has decoded. */
.stage-holding, .stage-holding * { animation-play-state: paused !important; }
.stage-paused, .stage-paused * { animation-play-state: paused !important; }

/* -------------------------------------------------- column and button --- */

.stage-column { min-width: 0; width: 380px; max-width: 100%; flex: 0 0 380px; }
.stage-buy {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  margin-top: -4px; text-align: center; position: relative; z-index: 3;
}
.stage-buy :is(.pv-buy-note, .note) { display: block; font-size: var(--fs-small); color: var(--fg-muted); }
.stage-buy .note { font-size: var(--fs-micro); max-width: 320px; line-height: 1.5; }

/* The one action: the site's own primary button, with weight to it. It
   catches a single sweep of the card's light after the reveal, then rests -
   prominent, never shouting. */
.stage-buy :is(.pv-btn-primary, .btn.primary) {
  position: relative; overflow: hidden; isolation: isolate;
  min-width: 240px; min-height: 46px; padding: 11px 28px;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-size: 15px; font-weight: 600; border-radius: var(--r-md);
  box-shadow: 0 8px 22px -10px color-mix(in srgb, var(--accent) 80%, transparent),
    inset 0 1px 0 rgba(255, 255, 255, .22);
  transition: transform 200ms var(--ease), box-shadow 200ms var(--ease), background 200ms;
}
.stage-buy :is(.pv-btn-primary, .btn.primary)::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, .45) 50%, transparent 70%);
  translate: -120% 0;
  animation: cta-sweep 1.3s cubic-bezier(.3, .1, .2, 1) var(--cta-at, 1s) 1 backwards;
}
/* The sweep follows the card's arrival (the button sits in the stage's
   column in the app, under the trophy on the public page). */
:is(.stage-column, .pv-trophy):has(.card-stage[data-tier="1"]) { --cta-at: 1.6s; }
:is(.stage-column, .pv-trophy):has(.card-stage[data-tier="2"]) { --cta-at: 2.1s; }
:is(.stage-column, .pv-trophy):has(.card-stage[data-tier="3"]) { --cta-at: 2.7s; }
:is(.stage-column, .pv-trophy):has(.card-stage[data-tier="4"]) { --cta-at: 3.3s; }
:is(.stage-column, .pv-trophy):has(.card-stage[data-tier="5"]) { --cta-at: 3.9s; }
:is(.stage-column, .pv-trophy):has(.card-stage.stage-settled) .stage-buy :is(.pv-btn-primary, .btn.primary)::after { animation: none; }
.stage-buy :is(.pv-btn-primary, .btn.primary):hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 30px -12px color-mix(in srgb, var(--accent) 95%, transparent),
    inset 0 1px 0 rgba(255, 255, 255, .28);
}
.stage-buy :is(.pv-btn-primary, .btn.primary):active { transform: translateY(0) scale(.985); }
.stage-buy :is(.pv-ext, .btn.primary svg) { display: inline-block; transition: transform 200ms var(--ease); }
.stage-buy :is(.pv-btn-primary, .btn.primary):hover :is(.pv-ext, svg) { transform: translate(2px, -2px); }
@keyframes cta-sweep { from { translate: -120% 0; } to { translate: 120% 0; } }

/* ------------------------------------------------------------ the app --- */

.report-hero .stage-column { align-self: flex-start; }

/* -------------------------------------------------------------- sizes --- */

@media (max-width: 1000px) {
  .report-hero { flex-direction: column; }
  .report-hero .stage-column { align-self: center; flex-basis: auto; }
}
@media (max-width: 600px) {
  .stage-column { align-self: center; width: 100%; flex-basis: auto; }
  .card-stage { --cw: 236px; }
  .stage-back, .stage-fx { inset: -48px 0 -24px; }   /* never wider than the screen */
}

/* ----------------------------------------------------- reduced motion --- */

/* The settled stage, still: every layer at rest, nothing moving. (The
   site-wide rule in theme.css shortens animations; this one removes them,
   so nothing here can flicker through a reveal in a hundredth of a second.) */
@media (prefers-reduced-motion: reduce) {
  .card-stage, .card-stage *, .card-stage *::after,
  .stage-buy :is(.pv-btn-primary, .btn.primary)::after {
    animation: none !important; transition: none !important;
  }
  .card-stage { --rx: 0deg !important; --ry: 0deg !important; cursor: default; }
}
