ui/leaderboardrow.razor.scss
// Shared leaderboard row content (rank / avatar / name / time / character / blocks / score / replay).
// Self-styled because s&box stylesheets don't cascade into a child component; the host provides the
// outer positioned/selected row box. Sizes match the original High Scores rows.
@import "Theme.scss";
$yellow: #dddd99;
LeaderboardRow {
position: relative; // stay in normal flow (footer stacks rows in a column; host row fills its box)
flex-direction: row;
align-items: center;
width: 100%;
padding: 0 24px 0 14px;
color: $white;
// Non-interactive so hover/click fall through to the host's row (selection); only the replay
// button and the avatar's profile link opt back in.
pointer-events: none;
.rank-column {
width: 70px;
flex-shrink: 0;
align-items: center;
MedalIcon, TrophyIcon { margin-left: -11px; }
}
.rank {
font-size: 34px;
font-family: $font-mono;
color: #6b7385;
}
// 50px face comes from the component's Size.
SteamAvatar {
margin-right: 18px;
}
.name {
flex-grow: 1;
flex-basis: 0; // size from available space, not content
min-width: 0; // allow shrink so ellipsis is deterministic on first layout
font-size: 30px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&.own { color: $player-name; }
}
// Fixed lane for the time so the name width stays stable before the async payload loads.
.time-col {
position: relative; // anchor for the absolutely-placed ms
width: 85px;
margin-right: 32px; // room for the ms to hang into
flex-direction: row;
align-items: center;
justify-content: flex-end; // mm:ss pinned to the right edge, same x every row
.time {
font-size: 32px;
font-family: $font-mono;
color: $white;
}
.ms {
position: absolute;
left: 100%;
margin-left: 2px;
font-size: 22px;
font-family: $font-mono;
color: rgba( 248, 245, 230, 0.4 );
white-space: nowrap;
}
}
// Character preview, one tally-block wide, in a fixed lane (stable name width before load).
.char-col {
position: relative;
width: 40px;
height: 40px;
flex-shrink: 0;
margin-left: 8px;
.icon-glow {
position: absolute;
left: -61%;
top: -60.5%;
width: 222%;
height: 221%;
z-index: 0;
pointer-events: none;
opacity: 0.3;
background-image: url( "sprites/ui/icon_glow.png" );
background-repeat: no-repeat;
background-size: 100% 100%;
}
.character {
position: absolute;
z-index: 1;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
image-rendering: pixelated;
// Paired (twins) icon: partner behind up-right and slightly smaller, character in
// front down-left — same composition as the picker's twins icon.
&.rear {
transform: translate( 11%, -9% ) scale( 0.94 );
}
&.front {
transform: translate( -11%, 9% );
}
}
}
// Fixed lane for the block-tally graphic (appears async, so keep the layout stable).
.blocks-col {
width: 220px;
flex-shrink: 0;
flex-direction: row;
align-items: center;
margin-left: 16px;
margin-right: 16px;
}
.score {
width: 70px;
font-size: 34px;
font-family: $font-mono;
color: $score-victory;
text-align: left;
&.non-victory { color: $score-non-victory; }
}
// Always reserve the replay lane, including while data loads or is missing/unusable.
// Unavailable replays stay grey and inert; hover shows why.
.replay {
width: 44px;
height: 44px;
flex-shrink: 0;
margin-left: 16px;
align-items: center;
justify-content: center;
font-size: 24px;
color: $black;
background-color: $white;
pointer-events: all;
cursor: blank-hand;
&:hover {
background-color: $yellow;
}
&.stale {
color: #3a3f4c;
background-color: #6b7385;
cursor: blank-arrow;
&:hover {
background-color: #6b7385;
}
}
}
}