ui/gamesetup.razor.scss
@import "Theme.scss";
// Full-screen pre-game setup menu (host only). A blurred scrim over the table with a centred sheet:
// game title, the table settings, and Start / Back. Mirrors the launcher's look so it reads as a real menu.
GameSetup
{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
flex-direction: column; // stack the header above the sheet
align-items: center;
justify-content: center;
gap: 14px;
pointer-events: all;
backdrop-filter: blur(15px);
background-color: rgba(0, 0, 0, .45);
// Only fade the full-screen scrim - scaling it would pull its edges in and reveal the table behind.
animation: cg-setup-fade .35s ease-out;
// Title sits above the card, left-aligned to its edge (same width keeps the text flush left). The
// lobby's card is much wider than the plain settings sheet, so .wide matches that width instead.
.head
{
flex-direction: column;
align-items: flex-start;
gap: 4px;
width: 540px;
max-width: 90%;
animation: cg-setup-pop .35s ease-out;
&.wide
{
width: 92%;
max-width: 1180px;
}
.title
{
font-family: $serif;
font-size: 38px;
font-weight: 700;
color: $text;
}
}
.sheet
{
flex-direction: column;
align-items: stretch;
gap: 20px;
// The card itself does the zoom-in.
transform-origin: 50% 50%;
animation: cg-setup-pop .35s ease-out;
width: 540px;
max-width: 90%;
padding: 30px 32px;
background-color: $panel;
border: 0.15px solid $line;
border-radius: $r-lg;
// Blend the embedded settings panel into the sheet - it provides the rows, not its own card chrome.
.game-settings
{
background-color: transparent;
border-width: 0;
border-radius: 0;
padding: 0;
max-width: unset;
box-shadow: none;
// The sheet already has a "Table setup" header; drop the panel's own duplicate heading.
.head { display: none; }
}
// The tutorial (?) sits hard left; the spacer pushes Back / Start to the right.
.actions
{
flex-direction: row;
align-items: center;
gap: 10px;
margin-top: 4px;
.spacer { flex-grow: 1; }
}
}
// --- Lobby (multiplayer games) --------------------------------------------
// A wide card: title + status up top, the seat grid and settings side by side, actions along the
// bottom. Same pop-in as .sheet above - it carries no backdrop-filter of its own, so scaling the
// whole card is safe (only the full-screen scrim needs the fade-only treatment).
.lobby
{
flex-direction: column;
align-items: stretch;
gap: 22px;
transform-origin: 50% 50%;
animation: cg-setup-pop .35s ease-out;
width: 92%;
max-width: 1180px;
padding: 32px 36px;
background-color: $panel;
border: 0.15px solid $line;
border-radius: $r-lg;
.body
{
flex-direction: row;
align-items: flex-start;
gap: 28px;
}
.table-col
{
flex-grow: 1;
min-width: 0;
flex-direction: column;
align-items: stretch;
gap: 14px;
}
.seats
{
flex-direction: row;
flex-wrap: wrap;
gap: 14px;
}
.seat-tile
{
width: 200px;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10px;
min-height: 152px; // open seats have no badge row - pin a floor so every tile matches height
padding: 18px 14px;
background-color: $panel-2;
border: 0.15px solid $line;
border-radius: $r-md;
cursor: pointer;
pointer-events: all;
transition: all .12s ease;
// A seated player's card - click through to their Steam profile.
&:hover
{
border-color: $line-soft;
filter: brightness(1.15);
}
&:active
{
filter: brightness(0.85);
transform: translateY(1px);
}
// A bot has no profile to show - same card, just not clickable.
&.disabled
{
cursor: default;
pointer-events: none;
}
.avatar-wrap
{
align-items: center;
justify-content: center;
}
.avatar
{
width: 56px;
height: 56px;
border-radius: 50%;
align-items: center;
justify-content: center;
font-family: $sans;
font-size: 18px;
font-weight: 800;
color: $on-gold;
object-fit: cover;
// A small, fixed palette so fallback discs read as distinct people, not a wall of gold.
&.c0 { background-color: $gold; }
&.c1 { background-color: #5b9bd5; color: $text; }
&.c2 { background-color: #9d7fd1; color: $text; }
&.c3 { background-color: $green; color: $felt-edge; }
}
.name
{
font-family: $sans;
font-size: 14px;
font-weight: 700;
color: $text;
text-align: center;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 100%;
}
.seat-badge
{
&.host
{
background-color: $gold;
color: $on-gold;
}
&.ready
{
background-color: rgba(111, 211, 154, .15);
color: $green;
}
&.cpu
{
background-color: rgba(236, 230, 214, .1);
color: $text-mut;
}
}
// An unfilled seat - no chrome, just a faint placeholder (s&box borders are solid-only, no
// border-style keyword, so this leans on a fainter line colour instead of a dashed one).
// Clickable - an open seat doubles as the invite prompt (same stub as the old Invite Friends button).
&.open
{
background-color: transparent;
border-color: $line-soft;
cursor: pointer;
pointer-events: all;
transition: all .12s ease;
.avatar-wrap
{
width: 56px;
height: 56px;
border-radius: 50%;
border: 0.15px solid $line-soft;
align-items: center;
justify-content: center;
.ico
{
font-family: "Material Icons";
font-size: 22px;
color: $text-faint;
}
}
.name
{
color: $text-faint;
font-weight: 500;
}
&:hover
{
border-color: $gold;
background-color: rgba(216, 181, 107, .06);
.avatar-wrap { border-color: $gold; }
.avatar-wrap .ico,
.name { color: $gold-soft; }
}
&:active
{
filter: brightness(0.85);
transform: translateY(1px);
}
// Not the host - same tile, just not yours to act on. Not a .cg-btn, so it doesn't pick up
// the shared .cg-btn.disabled rule - pointer-events has to be turned off here directly.
&.disabled
{
cursor: default;
pointer-events: none;
&:hover, &:active { border-color: $line-soft; background-color: transparent; filter: none; transform: none; }
}
}
}
.settings-col
{
width: 340px;
flex-shrink: 0;
// Blend the embedded settings panel into the lobby card - it provides the rows, not its own chrome.
.game-settings
{
background-color: transparent;
border-width: 0;
border-radius: 0;
padding: 0;
max-width: unset;
box-shadow: none;
}
}
.actions
{
flex-direction: row;
align-items: center;
gap: 10px;
.spacer { flex-grow: 1; }
}
}
}
@keyframes cg-setup-fade
{
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes cg-setup-pop
{
from { opacity: 0; transform: scale(0.92) translateY(8px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}