.bj-table {
	/* Card size. NOT scaled by hand count (the row slides instead), but it DOES scale
	   to the window height so the whole table -- including the bet/Deal bar beneath it
	   -- fits on screen. Two 7-card reserves (5 * card-width) plus ~480px of fixed
	   chrome must fit in the viewport, hence (100vh - 480px) / 5. Capped at 5rem on
	   tall screens, floored at 2.25rem so cards stay legible on short ones. */
	--card-width: clamp(2.25rem, calc((100vh - 480px) / 5), 5rem);

	/* Vertical space reserved for each side's fan, sized for a full 7-card hand
	   (height = card-width * 1.4 * (1 + 6 * stack-y), stack-y = 0.13 -> ~2.49). Both
	   the dealer and the player row claim this much, so the table height never
	   changes as hands fill -- only a rare 8th+ card on a non-bust hand overflows. */
	--reserve: calc(var(--card-width) * 2.5);

	/* Horizontal distance between adjacent hand centers on the carousel. Wider than a
	   typical 2-3 card hand so neighbors don't overlap; hands past the edges clip. */
	--hand-step: calc(var(--card-width) * 2.4);

	/* Room under each hand for its outcome badge + label. */
	--caption: 3rem;

	width: min(92vw, 1100px);
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 2rem;
	padding: 1.5rem 0;
}

.bj-table__dealer {
	width: 100%;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.75rem;
}

/* The dealer claims a full 7-card height up front and fans DOWNWARD into it off a
   top-pinned first card, so the label above never moves and the cards grow toward
   the players. The up-card is centered on the table's mid-line (see .hand below) so
   it sits directly above the active hand's first card. */
.bj-table__dealer-area {
	position: relative;
	width: 100%;
	height: var(--reserve);
}
.bj-table__dealer-area .hand {
	position: absolute;
	top: 0;
	/* Center the *first* card (the up-card) on the mid-line: shift the hand left by
	   half a card so its left edge lands half a card left of center. */
	left: 50%;
	transform: translateX(calc(var(--card-width) / -2));
}

/* The carousel window. Hands live on one strip, full size; the strip slides so the
   focused hand is centered. Anything off the sides is clipped. */
.bj-table__viewport {
	position: relative;
	width: 100%;
	/* Reserved fan height (cards grow up) plus room for the caption beneath. */
	height: calc(var(--reserve) + var(--caption));
	/* Hands slid past the sides drop off the table rather than spilling into the
	   page; the reserved height contains the fan, so the rare 8th card clips too. */
	overflow: hidden;
}

/* One hand. Pinned by its first card a caption's-height up from the floor and
   centered on the window, then slid horizontally by its distance from the focused
   hand. The fan grows UPWARD off that pinned card; the caption hangs just below. */
.bj-spot {
	position: absolute;
	left: 50%;
	bottom: var(--caption);
	/* Anchor the FIRST card on the mid-line, then slide by this hand's distance from
	   the focused one. Anchoring the first card (not the box center) keeps already-
	   dealt cards still when you hit -- the new card just fans out to the right. */
	transform: translateX(calc(var(--offset) * var(--hand-step) - var(--card-width) / 2));
	/* Hands nearer the center sit on top of those sliding away behind them. */
	z-index: calc(10 - max(var(--offset), -1 * var(--offset)));
}

/* The hand currently being played -- lift it and give it a soft halo so it reads as
   the live one even before any per-card highlight. */
.bj-spot--active {
	z-index: 20;
}
.bj-spot--active .hand {
	filter: drop-shadow(0 0 0.6rem rgba(255, 255, 255, 0.35));
}

.bj-spot__caption {
	position: absolute;
	top: 100%;
	/* Sit under the first card (the pinned anchor), so the badge stays put as the
	   hand fans rather than drifting with the box center. */
	left: calc(var(--card-width) / 2);
	transform: translateX(-50%);
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.3rem;
	white-space: nowrap;
}
