/*
 * The gameplay screen.
 *
 * Sizes come from a 1180px-wide capture of the original, expressed as
 * percentages of the frame so everything scales together. The board's own
 * measurements: cell pitch 161px, ball and empty dot both 76px (47.1% of a
 * cell), next-queue ball 92px.
 *
 * A ball is a circle drawn entirely out of its border, so the middle is
 * genuinely transparent and the grey dot shows through when the ring opens --
 * which is what the original does. Border widths are in container units of the
 * board, so the ring scales with the window and no JavaScript measures anything.
 */

.game-scene {
	/* cqw below is 1% of this element's content box, so it carries no
	   horizontal padding -- the numbers taken off the original are fractions
	   of the full screen width. The board insets itself instead. */
	container-type: inline-size;
	align-items: center;
	padding-top: calc(10px + env(safe-area-inset-top));
	padding-bottom: calc(6px + env(safe-area-inset-bottom));
	padding-left: 0;
	padding-right: 0;
}

/* ---------------------------------------------------------- score block */

.score-block {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 2.6cqw;
	margin-top: 8%;
}

.score-crown {
	width: 10.4cqw;
	height: 7.9cqw;
	object-fit: contain;
}

.score-value {
	font-size: 8.8cqw;
	line-height: 1;
	letter-spacing: 0.02em;
}

/* ------------------------------------------------------------ next queue */

.next-pill {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 5.8cqw;
	margin-top: 4%;
	padding: 1.1cqw 1.3cqw;
	background: var(--panel);
	border-radius: 999px;
}

.next-ball {
	display: block;
	width: 7.8cqw;
	height: 7.8cqw;
	border-radius: 50%;
	background: var(--ball-color, var(--panel-line));
	border: 3.9cqw solid var(--ball-color, var(--panel-line));
	box-sizing: border-box;
}

.next-ball.ring-in { background: transparent; }

.next-ball.ring-in {
	animation: ring-in 0.28s ease-out both;
}

/* Materialises as a thin ring that grows and fills in. */
@keyframes ring-in {
	0%   { transform: scale(0.18); border-width: 0.5cqw; }
	40%  { transform: scale(0.55); border-width: 1.1cqw; }
	70%  { transform: scale(0.82); border-width: 2.2cqw; }
	100% { transform: scale(1);    border-width: 3.9cqw; }
}

/* ---------------------------------------------------------------- board */

.board-wrap {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 1;
	/* The board runs almost the full width -- 1127 of 1180 in the original. */
	width: 95.5%;
	min-height: 0;
}

.board {
	container-type: size;
	position: relative;
	width: 100%;
	max-width: 100%;
	/* max-height plus aspect-ratio is what keeps the board square on a short
	   window: the height caps first and the width follows it down. */
	max-height: 100%;
	aspect-ratio: 1;
}

.board.shake {
	animation: board-shake 0.28s ease;
}

@keyframes board-shake {
	0%, 100% { transform: translateX(0); }
	20%      { transform: translateX(-7px); }
	40%      { transform: translateX(6px); }
	60%      { transform: translateX(-4px); }
	80%      { transform: translateX(3px); }
}

.cells {
	position: absolute;
	inset: 0;
	display: grid;
	grid-template-columns: repeat(7, 1fr);
	grid-template-rows: repeat(7, 1fr);
}

.cell {
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
}

/* 47.1% of a cell -- the same diameter as a ball at rest. */
.cell-dot {
	width: 47.1%;
	aspect-ratio: 1;
	border-radius: 50%;
	background: var(--panel);
}

.ball-layer,
.fx-layer {
	position: absolute;
	inset: 0;
	pointer-events: none;
}

.fx-layer { overflow: hidden; }

/* ---------------------------------------------------------------- balls */

/*
 * --d is the rest diameter: 47.1% of a cell, and a cell is 1/7 of the board,
 * so 6.73% of the board width. A border of --d/2 closes the circle completely,
 * which is the solid state; shrinking the border opens the hole.
 */
.ball {
	--d: 6.73cqw;
	position: absolute;
	width: var(--d);
	height: var(--d);
	box-sizing: border-box;
	border-radius: 50%;
	/* Filled as well as bordered: a border of exactly half the width can leave
	   a sub-pixel gap where the four edges meet, and the fill covers it. The
	   ring states drop the fill, and they are not transitioned, so the hole
	   appears the instant the border starts shrinking. */
	background: var(--ball-color);
	border: calc(var(--d) / 2) solid var(--ball-color);
	transform: translate(-50%, -50%) scale(1);
	transition: transform 0.28s ease-in-out, border-width 0.28s ease-in-out;
	will-change: left, top, transform, border-width;
}

/*
 * Selected: opens into a ring only slightly wider than the empty dot and holds
 * there until the player moves it or taps it again.
 *
 * The capture of the original swells to 1.5x; this is deliberately smaller at
 * 1.2x outer / 0.6x hole, which reads better on a screen the size of a browser
 * window. The easing is still the measured one -- an ease-in-out over 0.28s.
 */
.ball.selected {
	transform: translate(-50%, -50%) scale(1.2);
	border-width: calc(var(--d) * 0.25);
	background: transparent;
	z-index: 2;
}

/* Grows in solid, no hole. */
.ball.appearing {
	animation: ball-appear 0.28s linear both;
}

@keyframes ball-appear {
	0%   { transform: translate(-50%, -50%) scale(0); }
	25%  { transform: translate(-50%, -50%) scale(0.25); }
	50%  { transform: translate(-50%, -50%) scale(0.50); }
	75%  { transform: translate(-50%, -50%) scale(0.78); }
	90%  { transform: translate(-50%, -50%) scale(1.02); }
	100% { transform: translate(-50%, -50%) scale(1); }
}

/*
 * Popping follows the same opening curve as selection but keeps going: the
 * hole overruns the ring until the stroke thins to nothing.
 */
.ball.popping {
	animation: ball-pop 0.32s linear both;
	background: transparent;
	transition: none;
	z-index: 1;
}

@keyframes ball-pop {
	0%   { transform: translate(-50%, -50%) scale(1);    border-width: calc(var(--d) * 0.5); }
	22%  { transform: translate(-50%, -50%) scale(1.10); border-width: calc(var(--d) * 0.466); }
	44%  { transform: translate(-50%, -50%) scale(1.25); border-width: calc(var(--d) * 0.360); }
	66%  { transform: translate(-50%, -50%) scale(1.45); border-width: calc(var(--d) * 0.241); }
	88%  { transform: translate(-50%, -50%) scale(1.50); border-width: calc(var(--d) * 0.117); }
	100% { transform: translate(-50%, -50%) scale(1.55); border-width: 0; }
}

/* ----------------------------------------------------------------- pause */

.pause-button {
	display: flex;
	align-items: center;
	gap: 1.7cqw;
	margin-top: 3.5%;
	padding: 2.4cqw;
	border: none;
	background: transparent;
	cursor: pointer;
}

.pause-button span {
	display: block;
	width: 3.3cqw;
	height: 8.3cqw;
	border-radius: 1px;
	background: var(--panel);
}

.pause-button:active span { background: var(--panel-line); }

.speed-timer {
	margin-top: 1.5%;
	font-size: 4.4cqw;
	letter-spacing: 0.14em;
	color: var(--orange);
}

/* --------------------------------------------------------- floating fx */

.floating {
	position: absolute;
	transform: translate(-50%, -50%);
	white-space: nowrap;
	pointer-events: none;
}

/* Swells and fades roughly in place, the way the original's does. */
.floating-score {
	font-size: 11cqw;
	color: #4a4a4a;
	animation: float-score 1.1s ease-out both;
}

.floating-text {
	font-size: 8cqw;
	letter-spacing: 0.2em;
	color: var(--orange);
	animation: float-banner 1.4s ease-out both;
}

.floating-coin {
	display: flex;
	align-items: center;
	gap: 2cqw;
	font-size: 8cqw;
	color: var(--orange);
	animation: float-banner 1.4s ease-out both;
}

.floating-coin img {
	width: 9cqw;
	height: 9cqw;
}

@keyframes float-score {
	0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.75); }
	18%  { opacity: 1; transform: translate(-50%, -52%) scale(1); }
	100% { opacity: 0; transform: translate(-50%, -66%) scale(1.7); }
}

@keyframes float-banner {
	0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.7); }
	20%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
	75%  { opacity: 1; transform: translate(-50%, -70%) scale(1); }
	100% { opacity: 0; transform: translate(-50%, -95%) scale(1); }
}

/* -------------------------------------------------------------- confetti */

.confetti {
	position: absolute;
	top: -12px;
	width: 7px;
	height: 12px;
	border-radius: 1px;
	animation-name: confetti-fall;
	animation-timing-function: linear;
	animation-fill-mode: both;
}

@keyframes confetti-fall {
	0% {
		opacity: 1;
		transform: translate(0, 0) rotate(0deg);
	}
	100% {
		opacity: 0;
		transform: translate(var(--drift, 0), 420px) rotate(540deg);
	}
}

@media (prefers-reduced-motion: reduce) {
	.confetti,
	.preloader-crown,
	.preloader-loading {
		animation: none;
	}
}
