ui/scorescreen.razor.scss
// Designed in 1080-reference space; floaters/score are absolutely positioned via Project().
@import "Theme.scss";

ScoreScreen {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	pointer-events: all;

	font-family: $font;
	font-smooth: never;

	.score {
		position: absolute;
		transform: translate( -50%, -50% );
		font-size: 64px;
		font-family: $font-mono;
		color: $white;

		&.victory-score { color: $score-victory; }
		&.non-victory { color: $score-non-victory; }
	}

	// The run's character above the score (geometry inline from the razor): the shared
	// glow-behind-sprite badge structure, with the picker's paired composition for the twins.
	.score-character {
		position: absolute;
		pointer-events: none;

		.icon-glow {
			position: absolute;
			left: -61%;
			top: -60.5%;
			width: 222%;
			height: 221%;
			z-index: 0;
			opacity: 0.3;
			background-image: url( "sprites/ui/icon_glow.png" );
			background-repeat: no-repeat;
			background-size: 100% 100%;
		}

		.sprite {
			position: absolute;
			left: 0;
			top: 0;
			width: 100%;
			height: 100%;
			z-index: 1;
			background-repeat: no-repeat;
			background-position: center;
			background-size: contain;
			image-rendering: pixelated;
			opacity: 0.95;
		}

		&.paired {
			.sprite.rear {
				transform: translate( 11%, -9% ) scale( 0.94 );
			}

			.sprite.front {
				transform: translate( -11%, 9% );
			}
		}
	}

	.banner {
		position: absolute;
		transform: translate( -50%, -50% );
		font-size: 40px;
		color: $white;

		// Coin count-out line: coin-coloured (the coin body's YELLOW) so it reads as coins.
		&.coins {
			color: #dddd99;
		}
	}

	// Outcome banner: VICTORY! in bright yellow, YOU DIED in a muted red (OKLCH L≈0.58 / C≈0.09 / H≈25).
	.outcome {
		position: absolute;
		transform: translate( -50%, -50% );
		font-size: 48px;
		text-shadow: 3px 3px 0 $black;

		&.victory { color: #ffd84d; }
		&.died { color: #a9645f; }
	}

	.floater {
		position: absolute;
		transform: translate( -50%, -50% );
		font-size: 34px;
		font-family: $font-mono;
		text-shadow: 2px 2px 0 $black;
	}

	// Daily attempt state ("2/5 ATTEMPTS LEFT" / "UNLIMITED ATTEMPTS"), centred just above the
	// button list so it's read together with the RESTART decision. `bottom` comes inline from the
	// razor (ScoreScreen.AttemptsBottom) — it tracks the list's height so the line stays out of the
	// tally's lower block row. Kept small enough to fit that band, and dead to input: the full-width
	// box lies right against the top button row (see .foot-buttons for the same hazard).
	.attempts {
		position: absolute;
		left: 0;
		width: 100%;
		text-align: center;
		font-size: 22px;
		color: #8a8f9c;
		text-shadow: 2px 2px 0 $black;
		pointer-events: none;
	}

	// Shortcuts out of the finished tally: the level's Steam Workshop page (bottom-left, workshop
	// levels only) / watch this run's replay + open the full leaderboard (bottom-right). Visuals come
	// from the shared .square-btn (Theme.scss); this only places the corner groups against the play
	// square's edges, clear of the centred RESTART / CONTINUE lane.
	.foot-buttons {
		position: absolute;
		bottom: 50px;
		left: 0;
		width: 100%;
		flex-direction: row;
		justify-content: center;
		// pointer-events is INHERITED and the root is `all`, so this row's own box — which lies
		// right on top of the lower RESTART / CONTINUE row at the same bottom — would out-hover the
		// button under it (hover resolves to the topmost containing panel, and the later sibling
		// wins). Only the .square-btn children take events; the boxes around them stay dead.
		pointer-events: none;

		.inner {
			width: 1080px;
			flex-direction: row;
			justify-content: space-between;
			padding: 0 40px;

			.left, .right {
				flex-direction: row;
				gap: 16px;
			}
		}
	}

	// Bottom RESTART / CONTINUE buttons, shown once the tally finishes. A vertical list driven by
	// the same "smiling cube" selector as the menus (see TitleScreen).
	.buttons {
		position: absolute;
		bottom: 50px;
		left: 0;
		width: 100%;
		flex-direction: row;
		justify-content: center;

		// List wrapper is position:relative so the absolutely-positioned selector can slide
		// vertically between the rows. Row pitch = .button height (64) + gap (16) = 80 (ROW_PITCH).
		.list {
			position: relative;
			flex-direction: column;
			gap: 16px;
			// Left lane the selector slides in (mirrors the title's cube-in-left-lane look).
			padding-left: 72px;

			// The smiling-cube selector. `top` and the frame (background-position) are set inline
			// from the stage. The sheet is 7 frames wide, so background-size:700% fills one frame.
			.selector {
				position: absolute;
				left: 0;
				top: 0;
				width: 48px;
				height: 48px;
				background-image: url( "sprites/menu_selector.png" );
				background-repeat: no-repeat;
				background-size: 700% 100%;
				image-rendering: pixelated;
			}

			.button {
				flex-direction: row;
				align-items: center;
				height: 64px;
				pointer-events: all;
				cursor: blank-hand;

				// Label is presentation only: keep it from becoming its own hit target (same
				// reason as Theme.scss's `button > *` rule — down and up must resolve to the
				// same panel).
				> * {
					pointer-events: none;
				}

				.text {
					font-size: 44px;
					// Dimmed against the dark score backdrop ($black IS that backdrop, so it would be
					// invisible); the selected row brightens to full white.
					color: #8a8f9c;
				}

				&.selected .text {
					color: $white;
				}
			}
		}
	}
}