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;
}
}
}
}
}