/* The deal, on top of template.html: the deck-list strip and the card
 * sections on every deck page. build_deck_html.py links it on any page with
 * a strip or a card scan.
 *
 * deal.js wraps every scan in a two-faced card, and these rules are what
 * make the faces a card: the front and the back sit on the same spot, the
 * back is pre-turned, and whichever faces away from the viewer is hidden.
 * Everything that moves is moved by the script, except what eases here:
 * the hover tilt, the strip's height, the gold frame, the price, and the
 * $$$.
 *
 * Three states ride on the strip's data-deal attribute:
 *   stacked  every card is face down on the pile, waiting for the pile to
 *            scroll into view
 *   dealing  cards are in the air, or turning
 *   done     the page as it was before the script ran, plus the hover
 *
 * And one on the root: data-showing="bling" while the Bling Deck is up.
 * The strip's data-gold runs ahead of it: it is set the moment the $$$ asks
 * for the bling deck, so the gold frame fades in on the press.
 */

:root {
	/* the rise off the table. one soft shadow, since in the pile two dozen
	   of them stack up and anything heavier reads as a smudge. */
	--deal-shadow: 0 1px 3px rgb(0 0 0 / 0.35);
	--deal-lift:   0 14px 26px rgb(0 0 0 / 0.32), 0 4px 8px rgb(0 0 0 / 0.22);
	--deal-gild:   400ms;   /* the bling frame and price fading in and out */
	--deal-resize: 450ms;   /* the strip easing to the other deck's height */
	--deal-depth:  900px;

	/* the cents on the switch while the bling deck is up. a true silver is
	   too pale to read on the light theme's white, so it is a shade down
	   there and the real thing on the dark one. */
	--deal-silver: #858a92;
}

@media (prefers-color-scheme: dark) {
:root {
	--deal-silver: #c4c8cf;
}
}

/* ---------------------------------------------------------------------
   which deck is up. a page with a Bling Deck carries both: every element
   that belongs to one tags data-print, and only the deck that is up shows.
   without the script nothing sets data-showing, so the regular deck is the
   page, as it was. */

:root:not([data-showing="bling"]) [data-print="bling"],
:root[data-showing="bling"] [data-print="regular"] {
	display: none;
}

/* ---------------------------------------------------------------------
   the card: two faces, one turned away */

[data-card] {
	display: block;
	position: relative;
	aspect-ratio: 5 / 7;
	transform-style: preserve-3d;
}

[data-face] {
	display: block;
	position: absolute;
	inset: 0;
	border-radius: var(--card-round);
	backface-visibility: hidden;
	-webkit-backface-visibility: hidden;
}

/* said out loud, since Safari has been known to show a back through a
   front that has no transform of its own */
[data-face="front"] {
	transform: rotateY(0deg);
}

[data-face="back"] {
	transform: rotateY(180deg);
}

/* a card face down. a turn animates away from this, and the script drops
   the attribute as the turn ends, so the base state and the animation's
   last frame agree and nothing snaps. */
[data-card][data-down] {
	transform: rotateY(180deg);
}

/* a card section's scan: the link that opens it full size is what turns
   it, so the link carries the vanishing point */
[data-flip] {
	perspective: var(--deal-depth);
}

/* ---------------------------------------------------------------------
   before the script. a page that will run it should never show a front
   first and then turn it away, so with scripting on, the strip and its
   $$$ wait unseen and each scan shows the back. the script lifts them as
   it takes over. if it never arrives, they lift on their own after a few
   seconds. */

@media (scripting: enabled) {
	[data-decklist][data-deal-back]:not([data-deal]) figure {
		visibility: hidden;
		animation: deal-show 0s 3s forwards;
	}

	h3 [data-bling]:not([data-fade]) {
		opacity: 0;
		animation: deal-reveal 0s 3s forwards;
	}

	article > aside > [data-art]:not([data-flip]) {
		background: url("../card-back.png") center / contain no-repeat;

		img {
			opacity: 0;
			animation: deal-reveal 0s 3s forwards;
		}
	}
}

@keyframes deal-show {
	to { visibility: visible; }
}

@keyframes deal-reveal {
	to { opacity: 1; }
}

/* ---------------------------------------------------------------------
   the strip */

[data-deal] {
	/* the pile and the flights leave the box. nothing may clip them. */
	overflow: visible;
	position: relative;
	/* the script holds the height at the old deck's and lets it go to the
	   new one's, so the strip eases open or closed as the decks swap */
	transition:
		border-radius var(--deal-gild) ease-out,
		height var(--deal-resize) ease-in-out;

	/* the empty box over the waiting pile that the script watches, so the
	   shuffle starts once the whole pile is on screen. the script places
	   and sizes it; it draws nothing and catches nothing. */
	[data-deal-pile] {
		position: absolute;
		pointer-events: none;
	}

	/* the mover: the link, or a span standing in for one. its transform is
	   the flight, so it carries the vanishing point for the card inside it,
	   and each card gets a vanishing point of its own rather than one
	   shared across the strip, which skews the cards at the edges. */
	[data-mover] {
		display: block;
		position: relative;
		perspective: var(--deal-depth);
	}

	[data-face] {
		box-shadow: var(--deal-shadow);
		transition: box-shadow 220ms ease-out;
	}

	/* the card the shuffle's cut picks up and lays on top of the stack. the
	   deeper shadow is what says it went over the others rather than
	   across them; it eases back down as the card lands. */
	figure[data-lift] [data-face] {
		box-shadow: var(--deal-lift);
	}

	/* the count is ours, not the card's. it sits flat on the slot, outside
	   the card that flies, turns, and tilts, and it is invisible until the
	   deal is over: then every badge fades in together, and they all fade
	   out again before anything takes the cards away. */
	[data-count] {
		opacity: 0;
		transition: opacity var(--deal-fade, 240ms) ease-out;
		pointer-events: none;
	}

	&[data-counts] [data-count] {
		opacity: 1;
	}
}

/* layers are promoted only while something is moving. promoted all the
   time, two dozen cards with two faces each is a lot of texture memory on
   a phone for a strip that is standing still. */
[data-deal="stacked"],
[data-deal="dealing"] {
	[data-mover],
	[data-card] {
		will-change: transform;
	}
}

/* once dealt, a card tilts toward the pointer. the script sets the angle;
   this is the easing, and the lifted card riding over its neighbours. */
[data-deal="done"] {
	[data-card] {
		transition: transform 160ms ease-out;
	}

	figure:hover {
		z-index: 1;
	}
}

/* ---------------------------------------------------------------------
   the Bling Deck */

/* the strip wearing the rare prints gets a gold frame, so the state reads
   even on a card whose two prints look alike.

   the frame is a layer of its own over the strip's edge rather than a
   border on the strip. a real 10px border narrows the strip by 20px, which
   can drop a card off every row, and it arrives mid-deal, with every
   card's flight already measured against the old grid. so the strip's box
   never changes, and the frame sits in its padding, which is wider than
   the frame at every size.

   the gold is two radial gradients across the frame's whole box, with the
   strip's own colour laid over everything inside the border so only the
   border shows them. the cards are positioned, so they paint over that. */
[data-deal]::before {
	content: "";
	position: absolute;
	inset: 0;
	border: 10px solid transparent;
	border-radius: 15px;
	background:
		linear-gradient(var(--bg), var(--bg)) padding-box,
		radial-gradient(ellipse farthest-corner at right bottom,
			#fedb37 0%, #fdb931 8%, #8a6e2f 40%, transparent 80%) border-box,
		radial-gradient(ellipse farthest-corner at left top,
			#ffffff 0%, #ffffac 8%, #d1b464 25%, #5d4a1f 62.5%, #5d4a1f 100%) border-box;
	opacity: 0;
	transition: opacity var(--deal-gild) ease-out;
	pointer-events: none;
}

/* on from the moment the $$$ asks for the bling deck, off from the moment
   it asks for the regular one, so the frame answers the press itself
   rather than the swap a shuffle later. the strip's own corners follow the
   frame's, or its colour shows in the corners outside the gold. */
[data-deal][data-gold] {
	border-radius: 15px;

	&::before {
		opacity: 1;
	}
}

/* the price of the Bling Deck and where to check it, under the strip. it
   is always in the page, collapsed: a one-row grid going from 0fr to 1fr
   eases its height open without anyone measuring it, and the inner box
   clips what has not opened yet. */
[data-cost] {
	display: grid;
	grid-template-rows: 0fr;
	opacity: 0;
	transition:
		grid-template-rows var(--deal-resize) ease-in-out,
		opacity var(--deal-gild) ease-out;

	> div {
		overflow: hidden;
		min-height: 0;
	}
}

:root[data-showing="bling"] [data-cost] {
	grid-template-rows: 1fr;
	opacity: 1;
}

/* the $$$ in the corner of the Deck List heading: a switch, so a button,
   in the clothes of the link it used to be. the template's [data-bling]
   rule parks it in the corner; this takes the button chrome off. it says
   where it goes: a gold $$$ up to the bling deck, and silver cents back
   down, which the script writes the moment it is pressed. it is never the
   purple of a link, pressed or not.

   it shows only while a press would deal: in once the deal is over, out
   on the press, a little quicker. each state carries the transition that
   arrives at it, so the two ways take their own time. */
h3 [data-bling] {
	background: none;
	border: 0;
	padding: 0;
	color: var(--gold);
	font: inherit;
	font-weight: 700;
	line-height: 1;
	cursor: pointer;

	&[aria-pressed="true"] {
		color: var(--deal-silver);
	}

	&[data-fade="out"] {
		opacity: 0;
		pointer-events: none;
		transition: opacity var(--deal-sink, 220ms) ease-in;
	}

	&[data-fade="in"] {
		opacity: 1;
		transition: opacity var(--deal-rise, 360ms) ease-out;
	}

	&:focus-visible {
		outline: 2px solid var(--accent);
		outline-offset: 2px;
	}
}

/* the empty span beside the $$$ that a link ending in #bling lands on,
   under the page's top padding. a span, because a browser focuses a
   target it can focus, and on the button that drew a focus ring as the
   page opened. */
#bling {
	scroll-margin-top: var(--pad);
}

/* ---------------------------------------------------------------------
   print. the page as it was: fronts up, nothing in flight, in whichever
   deck is up. */

@media print {
	[data-mover],
	[data-card] {
		transform: none !important;
	}

	[data-face="back"] {
		display: none;
	}

	[data-deal] {
		[data-count] {
			opacity: 1;
		}

		/* the frame is painted gradients, which print drops, and its fill
		   of the strip's colour would print as nothing over nothing */
		&::before {
			display: none;
		}
	}
}
