/* ---------- the pack openings (js/open) ---------- */
/* Layers of the room, back to front: .reveal-black (the room faded to one colour), the rays and
   the dim, #fx-back (stage lights), the stamp, then the stage: .reveal-set (set pieces behind
   the pack), the pack, the cards, .reveal-set.front. The #fx canvas is over everything. */
.reveal-black { position: absolute; inset: 0; background: #000; opacity: 0; pointer-events: none; }
#fx-back { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.reveal-set { position: absolute; inset: 0; pointer-events: none; }
.reveal-set.front { z-index: 3; }
/* d.black() takes the room's own light out with it: the ceiling light and the pool on the table */
.reveal-stage::before, .reveal-pack::after { opacity: var(--room-light, 1); transition: opacity var(--room-ms, 0ms) ease; }
.reveal-flash { background: radial-gradient(circle, #fff, color-mix(in srgb, var(--flash-color, #fff0c8) 70%, transparent) 40%, transparent 78%); }

/* street fair: the wrapper drops away and the cards slide up out of it */
.pack.o-street-drop { animation: o-street-drop .5s cubic-bezier(.5, 0, .9, .4) forwards; }
@keyframes o-street-drop { to { transform: translateY(70vh) rotate(calc(var(--dir, 1) * 9deg)); opacity: 0; } }
.reveal-slot.deal-street { animation: o-street-deal .56s cubic-bezier(.2, .8, .3, 1) both; }
@keyframes o-street-deal {
  0% { transform: translate(calc(var(--i) * -1 * (100% + var(--gap))), 2vh) scale(.82); opacity: 0; }
  25% { opacity: 1; }
  100% { transform: none; opacity: 1; }
}

/* auction house: a gavel knocks three times on its block ("going once, going twice, sold"),
   the wrapper bursts on the third and the cards slide in like lots (js/open/auction.js) */

/* the sound block and the gavel, both in front of the pack */
.o-auction-block { position: absolute; opacity: 0; transform-origin: 50% 80%; }
.o-auction-block svg, .o-auction-gavel svg { display: block; width: 100%; height: auto; overflow: visible; }
.o-auction-block.in { opacity: 1; animation: o-auction-block-in .3s cubic-bezier(.4, 0, .7, .5) .05s backwards; }
@keyframes o-auction-block-in {
  0% { transform: translateY(-70%); opacity: 0; }
  62% { transform: translateY(0) scale(1.05, .9); opacity: 1; }
  82% { transform: translateY(-7%); }
  100% { transform: none; }
}
.o-auction-block.in.hit { animation: o-auction-block-hit .2s ease-out; }
@keyframes o-auction-block-hit { 0% { transform: scale(1.06, .86); } 55% { transform: scale(.99, 1.03); } 100% { transform: none; } }
.o-auction-block.in.out { animation: none; opacity: 0; transform: translateY(22%) scale(.92); transition: opacity .22s ease-in .06s, transform .3s ease-in; }
.o-auction-gavel { position: absolute; left: 0; top: 0; will-change: transform; filter: drop-shadow(0 .5em .5em rgba(0, 0, 0, .55)); }
.o-auction-gavel svg { transform-origin: 14.76% 94.7%; } /* the striking face: the head squashes onto it */

/* the pack jumps when the table is struck: the side nearest the block kicks up first */
.pack.o-auction-hop { animation: o-auction-hop .34s cubic-bezier(.3, 0, .5, 1); }
@keyframes o-auction-hop {
  0% { transform: none; }
  32% { transform: translateY(calc(var(--o-auction-hop, 4%) * -1)) rotate(-1.6deg); animation-timing-function: cubic-bezier(.5, 0, .9, .5); }
  70% { transform: translateY(0) rotate(.5deg) scale(1.03, .97); }
  100% { transform: none; }
}

/* the torn strip always falls to the left, away from the gavel (a faded strip behind the head reads
   as a smear), and it is gone before the first call is written there */
.pack.o-auction-pack.torn .pack-strip { --dir: -1; animation-duration: .7s; }

/* The crack runs further down with every knock. It is uncovered from the top by a clip, because
   the kit's dash offset draws it in broken pieces in Chrome (see kitNotes in the hand-off). */
.pack.o-auction-pack .pack-cracks polyline { stroke-dasharray: none; }
.pack.o-auction-pack .pack-cracks { clip-path: inset(-5% -5% calc(var(--crack, 1) * 100%) -5%); transition: clip-path .3s cubic-bezier(.2, .8, .3, 1); }

/* the light out of the mouth starts as a leak and grows with every knock */
#reveal.o-auction-k1 .reveal-beam.on { transform: translate(-50%, -100%) scale(.5, .22); opacity: .75; }
#reveal.o-auction-k2 .reveal-beam.on { transform: translate(-50%, -100%) scale(.8, .5); transition-duration: .3s, .15s; }
#reveal.o-auction-rise .reveal-beam.on { transform: translate(-50%, -100%) scale(1.15, 1); transition: transform 1s cubic-bezier(.5, 0, .9, .6), opacity .15s; }
#reveal.o-auction-k1 .reveal-glow.on { opacity: .26; }
#reveal.o-auction-k2 .reveal-glow.on { opacity: .5; }
#reveal.o-auction-rise .reveal-glow.on { opacity: .8; transition: opacity 1s; }
/* once the wrapper is gone the shaft has no mouth to stand on, so it is put out faster than the kit does */
#reveal.o-auction-gone .reveal-beam.out { transition: transform .2s ease-in, opacity .11s ease-in; }

/* the auctioneer's call, and the word that sells the lot: written like the tier stamp */
.o-auction-call, .o-auction-sold { position: absolute; white-space: nowrap; pointer-events: none; opacity: 0; line-height: 1; font-weight: 700; color: var(--beam); }
.o-auction-call { font-size: clamp(2rem, 5vw, 4rem); transform: translate(-50%, -50%) rotate(-5deg); }
.o-auction-call.go { opacity: .24; animation: o-auction-call .8s cubic-bezier(.15, .9, .2, 1) backwards; }
@keyframes o-auction-call { 0% { scale: 1.5; opacity: 0; } 13% { scale: 1; opacity: .9; } 55% { opacity: .55; } 100% { scale: 1.03; opacity: .24; } }
/* "Sold" is the stamp with a finish: the light colour, a little paler along the top of the letters
   and deeper at their feet, with a shadow under it so it holds against the burst behind */
.o-auction-sold {
  left: 0; right: 0; text-align: center; transform: rotate(-7deg); padding: .14em 0; margin-top: -.14em; color: transparent;
  background: linear-gradient(180deg, color-mix(in srgb, var(--beam) 76%, #fff) 26%, var(--beam) 48%, color-mix(in srgb, var(--beam) 74%, #000) 80%);
  -webkit-background-clip: text; background-clip: text; filter: drop-shadow(0 .03em .045em rgba(0, 0, 0, .55));
}
.o-auction-sold.o-auction-all { /* the Mona Lisa: every colour, across the word */
  background: linear-gradient(180deg, rgba(255, 255, 255, .24) 26%, transparent 52%, rgba(0, 0, 0, .14) 80%),
    linear-gradient(100deg, #ff7ab8 4%, #ffd86b 26%, #7dffb0 46%, #6bd0ff 64%, #b98cff 82%, #ff7ab8 98%) center / 2.3em 100% no-repeat;
  -webkit-background-clip: text; background-clip: text;
}
.o-auction-sold.go { animation: o-auction-sold 1.14s cubic-bezier(.15, .9, .2, 1) both; }
@keyframes o-auction-sold { /* slams down where the lot stood, lifts clear of the cards, and is gone once they are in */
  0% { translate: 0 var(--o-auction-drop); scale: 3.2; opacity: 0; animation-timing-function: cubic-bezier(.6, 0, 1, .6); }
  9% { translate: 0 var(--o-auction-drop); scale: .96; opacity: 1; }
  13% { translate: 0 var(--o-auction-drop); scale: 1.05; }
  17% { translate: 0 var(--o-auction-drop); scale: 1; }
  24% { translate: 0 var(--o-auction-drop); scale: 1; opacity: 1; animation-timing-function: cubic-bezier(.5, 0, .2, 1); }
  42% { translate: 0 0; scale: var(--o-auction-small); opacity: .9; }
  62% { opacity: .5; }
  82% { opacity: .18; }
  100% { translate: 0 0; scale: var(--o-auction-small); opacity: 0; }
}

/* the lots: each card slides in from the right and stops dead in its place */
.reveal-slot.o-auction-lot { animation: o-auction-lot .42s cubic-bezier(.1, .6, .25, 1) both; }
@keyframes o-auction-lot {
  0% { transform: translateX(115vw) skewX(-12deg); opacity: 1; }
  64% { transform: translateX(-3%) skewX(-4deg); animation-timing-function: ease-out; }
  74% { transform: translateX(-4.5%) skewX(5deg); }
  88% { transform: translateX(1%) skewX(-1.2deg); }
  100% { transform: none; opacity: 1; }
}

/* museum pack opening: The Starry Night comes alive (js/open/museum.js) */
/* The show turns the floating pack itself, a frame at a time. */
.pack.o-museum-fly { will-change: transform; transform-style: preserve-3d; }
.pack.o-museum-fly .pack-tilt { -webkit-backface-visibility: hidden; backface-visibility: hidden; }
.pack.o-museum-fly::after { /* the back of the wrapper, with its seam: seen when the pack spins round */
  content: 'M'; position: absolute; inset: 0; transform: rotateY(180deg); -webkit-backface-visibility: hidden; backface-visibility: hidden; clip-path: var(--clip-main);
  /* a seal over the seam with the game's monogram, where the medal sits on the front */
  display: flex; align-items: center; justify-content: center; box-sizing: border-box; padding-top: 25%;
  font-size: 2.3em; font-weight: 700; line-height: 1; color: var(--p3); text-shadow: 0 .04em .1em rgba(0, 0, 0, .9);
  background:
    radial-gradient(circle at 50% 58%, #120b03 0 .86em, var(--p3) .9em .95em, rgba(0, 0, 0, .55) .99em 1.03em, transparent 1.07em),
    linear-gradient(90deg, transparent 48.6%, rgba(0, 0, 0, .4) 48.6% 49.3%, rgba(255, 255, 255, .28) 49.3% 51%, rgba(0, 0, 0, .25) 51% 51.5%, transparent 51.5%),
    linear-gradient(180deg, transparent 92.5%, rgba(255, 255, 255, .3) 92.5% 93.1%, rgba(0, 0, 0, .4) 93.1% 93.8%, transparent 93.8%),
    linear-gradient(90deg, rgba(0, 0, 0, .55), rgba(0, 0, 0, 0) 13%, rgba(255, 255, 255, .17) 31%, rgba(255, 255, 255, 0) 50%, rgba(0, 0, 0, 0) 80%, rgba(0, 0, 0, .6)),
    var(--foil-bg);
}

/* the cards drift down out of the night sky in a slow curve and land softly */
.reveal-slot.o-museum-deal { animation: o-museum-deal .9s both; }
@keyframes o-museum-deal {
  0% { transform: translate(calc(var(--i) * -62% + 20%), -80vh) rotate(calc(var(--i) * 9deg - 15deg)) scale(.74); opacity: 0; animation-timing-function: cubic-bezier(.25, .2, .45, 1); }
  10% { opacity: 1; }
  54% { transform: translate(calc(var(--i) * 9% - 8%), -13vh) rotate(calc(var(--i) * -4deg + 6deg)) scale(1.04); animation-timing-function: cubic-bezier(.3, .2, .3, 1); }
  90% { transform: translate(0, 0) rotate(0deg) scale(1); }
  100% { transform: none; opacity: 1; }
}

/* the room's ceiling light goes out for the night and comes back with the room */
#reveal.o-museum-night .reveal-stage::before { opacity: 0; transition: opacity .5s; }
#reveal.o-museum-dawn .reveal-stage::before { transition: opacity .7s; }
/* and the pool of light on the table is gone while the pack is afloat in the sky */
#reveal.o-museum-night .reveal-pack::after { transition: opacity .16s; }
#reveal.o-museum-sky .reveal-pack::after { opacity: 0; transition: opacity .45s; }

/* royal pack opening: coronation by lightning (js/open/royal.js) */

/* The pack arrives in state: lowered down a shaft of light, slowing as it comes, and it settles. */
.pack.o-royal-enter { animation: o-royal-enter .9s linear both; }
@keyframes o-royal-enter {
  0% { transform: translateY(-115vh) scale(.92); animation-timing-function: cubic-bezier(.25, .46, .45, .94); }
  78% { transform: translateY(0) scale(1.03, .97); animation-timing-function: ease-out; }
  90% { transform: translateY(-1.2%) scale(.995, 1.01); animation-timing-function: ease-in; }
  100% { transform: none; }
}

/* The pose the pack is lifted into. Its scale is a property of its own, so it composes with the
   slow turn (and with the tremble, which lives on .pack-tilt inside). */
.pack.o-royal-up {
  scale: var(--o-royal-s, 1); translate: 0 var(--o-royal-y, 0px); transition: scale 1.25s cubic-bezier(.3, 0, .2, 1), translate 1.25s cubic-bezier(.3, 0, .2, 1);
  animation: o-royal-turn-in 1.3s ease-in-out both, o-royal-turn 4.6s ease-in-out 1.3s infinite;
}
.pack.o-royal-up.o-royal-in { transition: scale .66s cubic-bezier(.5, 0, .9, .5); }
.pack.o-royal-up .pack-cracks { display: none; } /* the lightning leaves its own scar (below) */
@keyframes o-royal-turn-in { from { rotate: y 0deg; } to { rotate: y 15deg; } }
@keyframes o-royal-turn { 0%, 100% { rotate: y 15deg; } 50% { rotate: y -15deg; } }

/* The room's lights are set pieces behind the pack, not canvas drawing: they stay sharp on any
   screen and only ever change transform and opacity. royal.js moves them every frame.
   --o-royal-c is the colour of the light (purple, then the colour of each strike). */
.o-royal-room { position: absolute; inset: 0; --o-royal-c: #9a5cf2; --o-royal-core: #e2d2ff; --o-royal-hc: #f1cf7a; }
.o-royal-room > div { position: absolute; opacity: 0; will-change: transform, opacity; }
/* storm clouds along the top; the second copy is the same clouds lit from inside by a strike */
.o-royal-clouds {
  left: -12%; right: -12%; top: -8vh; height: 58vh; --o-royal-k: #9a5cf2;
  background:
    radial-gradient(ellipse 24% 58% at 4% 10%, color-mix(in srgb, var(--o-royal-k) 56%, transparent), transparent 72%),
    radial-gradient(ellipse 20% 46% at 20% 2%, color-mix(in srgb, var(--o-royal-k) 46%, transparent), transparent 72%),
    radial-gradient(ellipse 22% 66% at 36% 6%, color-mix(in srgb, var(--o-royal-k) 38%, transparent), transparent 72%),
    radial-gradient(ellipse 26% 50% at 52% 0%, color-mix(in srgb, var(--o-royal-k) 52%, transparent), transparent 72%),
    radial-gradient(ellipse 22% 68% at 67% 8%, color-mix(in srgb, var(--o-royal-k) 38%, transparent), transparent 72%),
    radial-gradient(ellipse 20% 46% at 82% 2%, color-mix(in srgb, var(--o-royal-k) 46%, transparent), transparent 72%),
    radial-gradient(ellipse 24% 58% at 97% 10%, color-mix(in srgb, var(--o-royal-k) 56%, transparent), transparent 72%);
  background-repeat: no-repeat; /* or the bright top row wraps round and shows as a hairline along the bottom edge */
  animation: o-royal-drift 6s ease-in-out infinite alternate;
}
.o-royal-clouds.o-royal-lit { --o-royal-k: var(--o-royal-c); }
@keyframes o-royal-drift { from { translate: -3% 0; } to { translate: 3% 0; } }
/* The two glows that fill the room (.o-royal-boom behind the pack, .o-royal-flash in front) are no
   bigger than the screen plus a margin for the shake; royal.js says where their middle is. */
.o-royal-boom, .o-royal-flash, .o-royal-hush { position: absolute; inset: -6vh -6vw -24vh; opacity: 0; }
.o-royal-boom { background: radial-gradient(circle var(--o-royal-r) at var(--o-royal-x) var(--o-royal-y), var(--o-royal-c), color-mix(in srgb, var(--o-royal-c) 36%, transparent) 40%, transparent); }
.o-royal-halo, .o-royal-floor { border-radius: 50%; }
.o-royal-halo { background: radial-gradient(closest-side, var(--o-royal-hc), color-mix(in srgb, var(--o-royal-hc) 36%, transparent) 40%, transparent); }
.o-royal-floor { background: radial-gradient(closest-side, color-mix(in srgb, var(--o-royal-c) 80%, transparent), color-mix(in srgb, var(--o-royal-c) 28%, transparent) 42%, transparent); }
/* the pillar: a tube of light around the pack (a bright rim, a dimmer inside, a soft core) */
.o-royal-pillar {
  top: -12vh; height: 124vh;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--o-royal-c) 10%, transparent) 8%, color-mix(in srgb, var(--o-royal-c) 44%, transparent) 16%,
    color-mix(in srgb, var(--o-royal-c) 20%, transparent) 27%, color-mix(in srgb, var(--o-royal-c) 26%, transparent) 42%, color-mix(in srgb, var(--o-royal-core) 60%, transparent) 50%,
    color-mix(in srgb, var(--o-royal-c) 26%, transparent) 58%, color-mix(in srgb, var(--o-royal-c) 20%, transparent) 73%, color-mix(in srgb, var(--o-royal-c) 44%, transparent) 84%,
    color-mix(in srgb, var(--o-royal-c) 10%, transparent) 92%, transparent);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 14%); mask-image: linear-gradient(180deg, transparent, #000 14%);
}
/* the Mona Lisa: every colour at once, in the glow behind the pack, on the floor, in the clouds and up the pillar */
.o-royal-rainbow .o-royal-boom {
  background: conic-gradient(from 20deg at var(--o-royal-x) var(--o-royal-y), #ff7ab8, #ffd86b, #7dffb0, #6bd0ff, #b98cff, #ff7ab8);
  -webkit-mask-image: radial-gradient(circle var(--o-royal-r) at var(--o-royal-x) var(--o-royal-y), #000, rgba(0, 0, 0, .4) 40%, transparent);
  mask-image: radial-gradient(circle var(--o-royal-r) at var(--o-royal-x) var(--o-royal-y), #000, rgba(0, 0, 0, .4) 40%, transparent);
}
.o-royal-rainbow .o-royal-floor {
  background: linear-gradient(90deg, #ff7ab8, #ffd86b, #7dffb0, #6bd0ff, #b98cff);
  -webkit-mask-image: radial-gradient(closest-side, rgba(0, 0, 0, .8), rgba(0, 0, 0, .28) 42%, transparent); mask-image: radial-gradient(closest-side, rgba(0, 0, 0, .8), rgba(0, 0, 0, .28) 42%, transparent);
}
.o-royal-rainbow .o-royal-lit {
  background:
    radial-gradient(ellipse 24% 58% at 4% 10%, rgba(255, 122, 184, .56), transparent 72%), radial-gradient(ellipse 20% 46% at 20% 2%, rgba(255, 216, 107, .46), transparent 72%),
    radial-gradient(ellipse 22% 66% at 36% 6%, rgba(125, 255, 176, .38), transparent 72%), radial-gradient(ellipse 26% 50% at 52% 0%, rgba(107, 208, 255, .52), transparent 72%),
    radial-gradient(ellipse 22% 68% at 67% 8%, rgba(185, 140, 255, .38), transparent 72%), radial-gradient(ellipse 20% 46% at 82% 2%, rgba(255, 122, 184, .46), transparent 72%),
    radial-gradient(ellipse 24% 58% at 97% 10%, rgba(255, 216, 107, .56), transparent 72%);
}
.o-royal-rainbow .o-royal-pillar {
  background: linear-gradient(90deg, transparent, rgba(255, 122, 184, .12) 8%, rgba(255, 122, 184, .5) 16%, rgba(255, 216, 107, .3) 29%, rgba(125, 255, 176, .3) 41%,
    rgba(255, 255, 255, .62) 50%, rgba(107, 208, 255, .3) 59%, rgba(185, 140, 255, .3) 71%, rgba(185, 140, 255, .5) 84%, rgba(185, 140, 255, .12) 92%, transparent);
}
/* a beam of light: a soft wedge out of the middle of its left edge, which it turns about */
.o-royal-lamp {
  transform-origin: 0 50%; --o-royal-lc: #f1cf7a;
  background: conic-gradient(from 81deg at 0 50%, transparent 0deg, color-mix(in srgb, var(--o-royal-lc) 20%, transparent) 4deg, color-mix(in srgb, var(--o-royal-lc) 70%, transparent) 9deg,
    color-mix(in srgb, var(--o-royal-lc) 20%, transparent) 14deg, transparent 18deg, transparent 360deg);
  -webkit-mask-image: radial-gradient(circle farthest-side at 0 50%, #000, rgba(0, 0, 0, .85) 50%, rgba(0, 0, 0, .5) 80%, transparent); mask-image: radial-gradient(circle farthest-side at 0 50%, #000, rgba(0, 0, 0, .85) 50%, rgba(0, 0, 0, .5) 80%, transparent);
}
.o-royal-shaft.o-royal-on { animation: o-royal-fade var(--o-royal-ms, .5s) ease-out both; }
.o-royal-col { /* the light a card falls down */
  top: -10vh; background: linear-gradient(90deg, transparent, rgba(241, 207, 122, .3) 30%, rgba(255, 244, 200, .9) 50%, rgba(241, 207, 122, .3) 70%, transparent);
  animation: o-royal-fade .5s ease-out both;
}
@keyframes o-royal-fade { from { opacity: .8; } to { opacity: 0; } }

/* The crown: an SVG drawn stroke by stroke, then filled. royal.js moves it every frame. */
.o-royal-crown { position: absolute; left: 0; top: 0; opacity: 0; transform-origin: 50% 82%; will-change: transform, opacity; --o-royal-c: #f1cf7a; }
.o-royal-crown svg { display: block; width: 100%; height: 100%; overflow: visible; filter: drop-shadow(0 0 5px var(--o-royal-c)) drop-shadow(0 0 16px var(--o-royal-c)); }
.o-royal-crown.o-royal-rainbow { animation: o-royal-hue 1.1s linear infinite; }
@keyframes o-royal-hue { from { filter: hue-rotate(0deg); } to { filter: hue-rotate(360deg); } }
.o-royal-ink { fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1 2; stroke-dashoffset: 1; }
.o-royal-draw .o-royal-ink { animation: o-royal-ink .85s cubic-bezier(.45, 0, .2, 1) forwards; }
@keyframes o-royal-ink { to { stroke-dashoffset: 0; } }
.o-royal-soft .o-royal-ink { stroke: var(--o-royal-c); stroke-width: 7; opacity: .3; }
.o-royal-line .o-royal-ink { stroke: #fff6d8; stroke-width: 2.3; }
.o-royal-fill { fill: url(#o-royal-gold); opacity: 0; transition: opacity .5s ease-out; }
.o-royal-lit .o-royal-fill { opacity: calc(.4 + var(--o-royal-blaze, 0) * .6); }
.o-royal-white { fill: #fff; opacity: calc(var(--o-royal-blaze, 0) * .92); } /* white hot when it is struck */
.o-royal-orb, .o-royal-gem { transform-box: fill-box; transform-origin: center; scale: 0; }
.o-royal-orb { fill: #fff6d8; stroke: var(--o-royal-c); stroke-width: 1.4; }
.o-royal-gem { fill: #2a0f4e; stroke: #f1cf7a; stroke-width: 1.3; stroke-linejoin: round; }
.o-royal-draw .o-royal-orb, .o-royal-draw .o-royal-gem { animation: o-royal-pop .32s cubic-bezier(.2, 1.7, .4, 1) forwards; }
@keyframes o-royal-pop { from { scale: 0; } to { scale: 1; } }
.o-royal-draw .o-royal-gem.o-royal-on { fill: var(--o-royal-gem, #fff); stroke: #fff; animation: o-royal-gem-on .5s ease-out forwards; }
@keyframes o-royal-gem-on { from { scale: 2.2; } to { scale: 1; } }

/* The scar the lightning leaves on the wrapper. It sits inside .pack-main, so the torn edge clips it. */
.o-royal-scar { position: absolute; inset: 0; z-index: 8; pointer-events: none; --o-royal-sc: #ffd24a; }
.o-royal-scar.o-royal-rainbow { animation: o-royal-hue 1.1s linear infinite; }
.o-royal-scar svg { display: block; width: 100%; height: 100%; }
.o-royal-scar polyline { fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1 2; stroke-dashoffset: 1; }
.o-royal-scar polyline.o-royal-on { animation: o-royal-ink .28s ease-out forwards; }
.o-royal-scar-glow polyline { stroke: var(--o-royal-sc); stroke-width: 7; opacity: .5; }
.o-royal-scar-core polyline { stroke: #fff; stroke-width: 1.8; }

/* A strike lights the room in flickers, the way lightning does. */
.o-royal-flash { background: radial-gradient(circle var(--o-royal-r) at var(--o-royal-x) var(--o-royal-y), #fff, color-mix(in srgb, var(--o-royal-fc, #fff) 70%, transparent) 22%, transparent); }
.o-royal-flash.o-royal-on { animation: o-royal-flicker .5s linear both; }
@keyframes o-royal-flicker {
  0% { opacity: var(--o-royal-fo); } 9% { opacity: calc(var(--o-royal-fo) * .25); } 18% { opacity: calc(var(--o-royal-fo) * .9); }
  32% { opacity: calc(var(--o-royal-fo) * .2); } 44% { opacity: calc(var(--o-royal-fo) * .55); } 100% { opacity: 0; }
}

/* The held breath: everything on the stage goes dark for a moment. */
.o-royal-hush { background: #050109; transition: opacity .12s linear; }
.o-royal-hush.o-royal-on { opacity: .92; }

/* The wrapper torn to shreds: six clipped copies of the pack, each flung its own way. */
.pack.o-royal-shred {
  pointer-events: none; scale: var(--o-royal-s, 1); translate: 0 var(--o-royal-y, 0px);
  animation: o-royal-shred .8s cubic-bezier(.1, .7, .3, 1) forwards;
}
.pack.o-royal-shred .pack-tilt { animation: none; transform: none; filter: none; clip-path: var(--o-royal-clip); }
.pack.o-royal-shred .o-royal-scar polyline { animation: none; stroke-dashoffset: 0; } /* a copy would draw its scar all over again */
.pack.o-royal-shred .pack-strip, .pack.o-royal-shred .pack-cracks, .pack.o-royal-shred .pack-light, .pack.o-royal-shred .pack-sheen, .pack.o-royal-shred .foil::after { display: none; }
@keyframes o-royal-shred {
  0% { transform: none; opacity: 1; }
  55% { opacity: 1; }
  100% { transform: translate3d(var(--o-royal-dx), var(--o-royal-dy), 0) rotate3d(var(--o-royal-ax), var(--o-royal-ay), .35, var(--o-royal-rot)) scale(.75); opacity: 0; }
}

/* The deal: each card drops from above and slams. */
.reveal-slot.o-royal-deal { transform-origin: 50% 78%; animation: o-royal-deal .48s linear both; }
@keyframes o-royal-deal {
  0% { transform: translateY(-118vh) scale(1.06); opacity: 1; animation-timing-function: cubic-bezier(.32, 0, .67, 0); }
  60% { transform: translateY(0) scale(1.08, .9); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  78% { transform: translateY(-1.5vh) scale(.985, 1.02); animation-timing-function: ease-in; }
  100% { transform: none; opacity: 1; }
}

/* ---------- Louvre vault pack opening (js/open/vault.js) ---------- */
/* The house lights are off for the whole show and stay off for the flips: no warm light from
   above the stage, no pool of light on the table. */
#reveal.o-vault-room .reveal-stage::before { opacity: 0; }
#reveal.o-vault-room .reveal-pack::after { opacity: 0; }

/* the entrance: the pack is lowered slowly into the spotlight and settles on the table */
.pack.o-vault-lower { animation: o-vault-lower 1.9s cubic-bezier(.2, .55, .3, 1) both; }
@keyframes o-vault-lower {
  0% { transform: translateY(-105vh) rotate(-2.5deg); }
  86% { transform: translateY(0) rotate(0deg) scale(1.012, .988); }
  100% { transform: none; }
}

/* the pack in the dark: a shade over the wrapper, and coloured light down both of its sides.
   The cracks sit above both. */
.pack.o-vault-pack { will-change: transform; }
.pack.o-vault-pack .pack-tilt { filter: none; } /* its drop shadow cannot be seen in a black room */
.pack.o-vault-pack .pack-strip { filter: brightness(.05); }
.pack.o-vault-pack .pack-light { transform-origin: 50% 0; transform: scaleY(.34); }
.o-vault-shade { /* it stops short of the mouth of the pack, so the light in the seal burns at full strength */
  position: absolute; inset: 0; z-index: 7; pointer-events: none; opacity: var(--o-vault-shade, 1); transition: opacity .45s ease;
  background: linear-gradient(90deg, rgba(0, 0, 0, .86), #000 20%, #000 80%, rgba(0, 0, 0, .86));
  -webkit-mask-image: linear-gradient(180deg, transparent 10.5%, #000 15.5%); mask-image: linear-gradient(180deg, transparent 10.5%, #000 15.5%);
}
.o-vault-gel {
  position: absolute; inset: 0; z-index: 8; pointer-events: none; mix-blend-mode: screen; opacity: var(--o-vault-gel, 0); transition: opacity .45s ease;
  background: linear-gradient(90deg, var(--o-vault-l, #ff2bd6), color-mix(in srgb, var(--o-vault-l, #ff2bd6) 42%, transparent) 11%, transparent 32%,
    transparent 68%, color-mix(in srgb, var(--o-vault-r, #12e2ff) 42%, transparent) 89%, var(--o-vault-r, #12e2ff));
  animation: o-vault-hue 2.6s steps(40) infinite; /* stepped: the wrapper is repainted 15 times a second, not 60 */
}
.pack.o-vault-pack .pack-cracks { z-index: 9; }
@keyframes o-vault-hue { from { filter: hue-rotate(0deg); } to { filter: hue-rotate(360deg); } }
.pack.o-vault-tell .o-vault-gel { animation: none; }
.pack.o-vault-wild .o-vault-gel { animation-duration: .7s; animation-timing-function: steps(14); }

/* the deal: each card drops out of the dark above the screen and lands with weight */
.reveal-slot.o-vault-deal { animation: o-vault-deal .64s both; transform-origin: 50% 75%; }
@keyframes o-vault-deal {
  0% { transform: translateY(-120vh); opacity: 1; animation-timing-function: cubic-bezier(.45, 0, .9, .6); }
  70% { transform: translateY(0) scale(1.05, .93); animation-timing-function: ease-out; }
  85% { transform: translateY(-1.5vh) scale(.985, 1.02); animation-timing-function: ease-in; }
  100% { transform: none; opacity: 1; }
}

/* ---------- the six packs between the old ones: attic, antique shop, studio, Paris salon,
   collector, cathedral. Each show is a little bigger than the pack below it. ---------- */

/* attic: the wrapper tips over in a cloud of dust and the cards slide out across the floor */
.pack.o-attic-tip { transform-origin: calc(50% + var(--dir, 1) * 50%) 100%; animation: o-attic-tip .5s cubic-bezier(.5, 0, .85, .45) forwards; }
@keyframes o-attic-tip {
  60% { opacity: 1; }
  100% { transform: rotate(calc(var(--dir, 1) * 86deg)) translateY(6%); opacity: 0; }
}
.reveal-slot.o-attic-deal { animation: o-attic-deal .62s cubic-bezier(.2, .8, .3, 1) both; }
@keyframes o-attic-deal {
  0% { transform: translate(calc(var(--i) * -1 * (100% + var(--gap)) + 30%), 6vh) rotate(14deg) scale(.8); opacity: 0; }
  30% { opacity: 1; }
  100% { transform: none; opacity: 1; }
}

/* studio: three loaded brush strokes cross the wall behind the pack (js/open/studio.js).
   --from is the inset that hides the stroke, so it is painted on from the side it starts at. */
.o-studio-stroke {
  position: absolute; border-radius: 46% 54% 50% 50% / 60% 40% 60% 40%; opacity: .92; clip-path: inset(var(--from));
  background:
    repeating-linear-gradient(180deg, rgba(255, 255, 255, .16) 0 3%, rgba(0, 0, 0, .14) 3% 7%, transparent 7% 13%),
    linear-gradient(180deg, color-mix(in srgb, var(--c) 70%, #fff), var(--c) 45%, color-mix(in srgb, var(--c) 62%, #000));
}
.o-studio-stroke.rainbow {
  background:
    repeating-linear-gradient(180deg, rgba(255, 255, 255, .16) 0 3%, rgba(0, 0, 0, .14) 3% 7%, transparent 7% 13%),
    linear-gradient(90deg, #ff7ab8, #ffd86b, #7dffb0, #6bd0ff, #b98cff);
}
.o-studio-stroke.on { clip-path: inset(0 0 0 0); transition: clip-path .26s cubic-bezier(.3, .7, .2, 1); }
.o-studio-stroke.out { opacity: 0; transition: opacity .5s ease-out; }

/* Paris salon: velvet curtains draw in behind the pack and fly open on the burst (js/open/salon.js) */
.o-salon-drape { position: absolute; inset: -4% -6%; overflow: hidden; }
.o-salon-drape i {
  position: absolute; top: 0; bottom: 0; width: 56%;
  background:
    linear-gradient(180deg, rgba(0, 0, 0, .55), transparent 18%, transparent 78%, rgba(0, 0, 0, .6)),
    repeating-linear-gradient(90deg, var(--v1) 0, var(--v2) 4.5%, var(--v1) 9%, color-mix(in srgb, var(--v1) 60%, #000) 12%);
  box-shadow: 0 0 3em rgba(0, 0, 0, .7);
  transition: transform .42s cubic-bezier(.3, .8, .3, 1);
}
.o-salon-drape i:first-child { left: 0; transform: translateX(-104%); }
.o-salon-drape i:last-child { right: 0; transform: translateX(104%); }
.o-salon-drape.in i:first-child { transform: translateX(-10%); } /* they stop just short of meeting behind the pack */
.o-salon-drape.in i:last-child { transform: translateX(10%); }
.o-salon-drape.open i { opacity: 0; transition: transform .5s cubic-bezier(.5, 0, .3, 1), opacity .4s .12s; }
.o-salon-drape.open i:first-child { transform: translateX(-112%) skewX(6deg); }
.o-salon-drape.open i:last-child { transform: translateX(112%) skewX(-6deg); }

/* collector: a magnifying glass goes over the wrapper (js/open/collector.js). Its font size is
   set to a twelfth of its width, so the em sizes here follow the glass. */
.o-collector-loupe {
  position: absolute; left: 0; top: 0; border-radius: 50%; opacity: 0; scale: 1.25;
  border: .62em solid #d8b35a;
  box-shadow: 0 0 0 .14em #5d3f0b, inset 0 0 0 .14em #5d3f0b, inset .8em 1em 2em rgba(255, 255, 255, .34), inset -.6em -.8em 1.8em rgba(0, 0, 0, .3), 0 1em 2.2em rgba(0, 0, 0, .55);
  background: radial-gradient(circle at 32% 28%, rgba(255, 255, 255, .5), rgba(255, 255, 255, .08) 34%, rgba(190, 240, 255, .1) 70%, rgba(255, 255, 255, .2));
  -webkit-backdrop-filter: brightness(1.35) saturate(1.4); backdrop-filter: brightness(1.35) saturate(1.4);
}
.o-collector-loupe::after { /* the handle */
  content: ''; position: absolute; left: 86%; top: 86%; width: 66%; height: 16%; border-radius: .8em;
  transform-origin: 0 50%; rotate: 45deg;
  background: linear-gradient(180deg, #2a1208, #8a4d2a 30%, #c58257 45%, #6a371c 70%, #1a0904);
  box-shadow: 0 .6em 1.2em rgba(0, 0, 0, .5);
}
.o-collector-loupe.in { opacity: 1; scale: 1; }
.o-collector-loupe.glint { animation: o-collector-glint .3s ease-out; }
@keyframes o-collector-glint { 0% { filter: brightness(2.2); scale: 1.12; } 100% { filter: brightness(1); scale: 1; } }
.o-collector-loupe.in.away { opacity: 0; scale: 1.6; }

/* cathedral: a rose window over the pack (js/open/cathedral.js). --lit is how bright the glass is,
   --tint the colour of the light behind it. Its font size is a fourteenth of its width. */
.o-cathedral-rose {
  position: absolute; border-radius: 50%; opacity: 0; scale: .9; --lit: .4; --tint: #ffd98a;
  background:
    radial-gradient(circle closest-side, #0a0410 0 7%, transparent 7.6%),
    repeating-conic-gradient(from 0deg, #0a0410 0 1.4deg, transparent 1.7deg 28.3deg, #0a0410 28.6deg 30deg),
    radial-gradient(circle closest-side, transparent 0 21%, #0a0410 21.6% 24.4%, transparent 25% 46%, #0a0410 46.6% 49.4%, transparent 50% 88%, #0a0410 88.6%),
    conic-gradient(from 0deg, #e23b4a, #f6b93b, #2f6fdf, #27c08a, #b23bd0, #f6b93b, #2f6fdf, #e23b4a, #27c08a, #2f6fdf, #f6b93b, #e23b4a);
  box-shadow: 0 0 0 .5em #120a18, 0 0 0 .64em rgba(255, 224, 163, .35), 0 0 calc(var(--lit) * 5em) color-mix(in srgb, var(--tint) 70%, transparent);
  filter: brightness(calc(.35 + var(--lit) * 1.3)) saturate(1.25);
  transition: opacity .45s ease, scale .6s cubic-bezier(.2, .8, .3, 1), filter .3s ease, box-shadow .3s ease;
}
.o-cathedral-rose i { position: absolute; inset: 0; border-radius: 50%; mix-blend-mode: soft-light; background: var(--tint); opacity: calc(var(--lit) * .7); transition: opacity .3s, background .3s; }
.o-cathedral-rose.on { opacity: 1; scale: 1; }
.o-cathedral-rose.toll { animation: o-cathedral-toll .7s ease-out; }
@keyframes o-cathedral-toll { 0% { scale: 1.07; } 100% { scale: 1; } }
.o-cathedral-rose.blaze { --lit: 1.25; }
.o-cathedral-rose.on.out { opacity: 0; scale: 1.25; transition: opacity .7s ease, scale .9s ease-out; }
/* the cards come down out of the light */
.reveal-slot.o-cathedral-deal { animation: o-cathedral-deal .9s both; }
@keyframes o-cathedral-deal {
  0% { transform: translate(calc(var(--i) * -.8 * (100% + var(--gap))), -62vh) scale(.6); opacity: 0; filter: brightness(2.4); animation-timing-function: cubic-bezier(.3, .1, .4, 1); }
  14% { opacity: 1; }
  80% { transform: translate(0, 1.2vh) scale(1.02); filter: brightness(1.15); animation-timing-function: ease-out; }
  100% { transform: none; opacity: 1; filter: none; }
}
