Files
Commonwealth-Online-Public/ui/views/CommonwealthOnline/pause-menu/styles.css
T
andrew db5e50c7fd Add pause menu concept prototype
Adds a standalone Commonwealth Online pause menu mockup with the Fallout-style map, left-side navigation, server info, controller prompts, and keyboard handling. Also includes map zoom/pan behavior, fixes the UI scale custom property so sizes resolve correctly, and updates the changelog and dev log.
2026-07-03 23:04:39 +12:00

504 lines
12 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Commonwealth Online — pause menu concept (1920×1080 baseline) */
:root {
/*
* --co-ui-scale is set by JavaScript (script.js) to a numeric value
* because nested calc()/min()/clamp() in custom properties doesn't
* resolve to a number in all browsers — it stays as a formula string,
* which breaks calc(Npx * var(--co-ui-scale)). The JS computes the
* scale on load and on resize, ensuring it's always a real number.
*/
--co-ui-scale: 1;
--co-black: #0a0c0a;
--co-panel-bg: rgba(8, 14, 10, 0.72);
--co-panel-fade: rgba(8, 14, 10, 0);
--co-green: #3ecf4a;
--co-green-dim: rgba(62, 207, 74, 0.35);
--co-amber: #c9a84a;
--co-amber-muted: rgba(201, 168, 74, 0.55);
--co-text-pale: #d8ddd0;
--co-text-muted: #9aa898;
--co-select-yellow: #c4a84b;
--co-select-yellow-bright: #d4bc62;
--co-select-text: #1a1c18;
--co-border: rgba(201, 168, 74, 0.45);
--co-font: "Roboto Condensed", "Bahnschrift", "Arial Narrow", Arial, sans-serif;
--co-transition: 120ms ease-out;
--co-panel-width: 28%;
--co-menu-size: calc(26px * var(--co-ui-scale));
--co-menu-gap: calc(6px * var(--co-ui-scale));
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
width: 100vw;
height: 100vh;
overflow: hidden;
font-family: var(--co-font);
font-weight: 600;
color: var(--co-text-pale);
background: var(--co-black);
user-select: none;
-webkit-font-smoothing: antialiased;
}
/* ── Root layout ─────────────────────────────────────────────── */
.pause-screen {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
}
/* ── Map layers ──────────────────────────────────────────────── */
.map-layer {
position: absolute;
inset: 0;
z-index: 1;
/*
* "contain" keeps the whole regional map visible (Fallout 76-style full
* overview) instead of "cover" cropping it down to a tight, zoomed-in
* strip. background-color fills the letterboxed edges so they blend
* into the dark UI instead of showing hard bars.
*/
background:
url("assets/map.png") center center / contain no-repeat;
background-color: #0b100c;
filter: brightness(0.74) contrast(1.04) saturate(0.55);
transform: translate(var(--map-pan-x, 0px), var(--map-pan-y, 0px))
scale(var(--map-zoom, 1));
transform-origin: center center;
transition: transform 160ms ease-out;
cursor: grab;
}
.map-overlay {
position: absolute;
inset: 0;
z-index: 2;
pointer-events: none;
background:
linear-gradient(
90deg,
rgba(6, 10, 8, 0.75) 0%,
rgba(6, 10, 8, 0.32) 24%,
rgba(6, 10, 8, 0.1) 55%,
rgba(6, 10, 8, 0.18) 100%
),
rgba(4, 8, 6, 0.18);
}
/* ── Map markers ───────────────────────────────────────────── */
/* Shares the same pan/zoom transform (inherited custom properties) as
.map-layer so markers stay pinned to their map position while navigating. */
.map-markers {
position: absolute;
inset: 0;
z-index: 3;
pointer-events: none;
transform: translate(var(--map-pan-x, 0px), var(--map-pan-y, 0px))
scale(var(--map-zoom, 1));
transform-origin: center center;
transition: transform 160ms ease-out;
}
.pause-screen.is-panning .map-layer,
.pause-screen.is-panning .map-markers {
transition: none;
cursor: grabbing;
}
.marker {
position: absolute;
transform: translate(-50%, -50%);
}
.marker--player {
width: calc(14px * var(--co-ui-scale));
height: calc(14px * var(--co-ui-scale));
background: var(--co-green);
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
filter: drop-shadow(0 0 4px rgba(62, 207, 74, 0.6));
opacity: 0.85;
}
.marker--ally {
width: calc(7px * var(--co-ui-scale));
height: calc(7px * var(--co-ui-scale));
border-radius: 50%;
background: var(--co-amber-muted);
box-shadow: 0 0 6px rgba(201, 168, 74, 0.35);
opacity: 0.7;
}
/* ── Screen effects: vignette, scanlines, HUD grid ─────────── */
.screen-effects {
position: absolute;
inset: 0;
z-index: 4;
pointer-events: none;
}
.screen-effects::before {
content: "";
position: absolute;
inset: 0;
background:
radial-gradient(
ellipse at center,
transparent 40%,
rgba(0, 0, 0, 0.55) 100%
);
opacity: 0.9;
}
.screen-effects::after {
content: "";
position: absolute;
inset: 0;
background:
/* faint HUD circle */
radial-gradient(
circle at 12% 88%,
transparent 58%,
rgba(62, 207, 74, 0.04) 59%,
transparent 62%
),
/* horizontal scanlines */
repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(0, 0, 0, 0.12) 2px,
rgba(0, 0, 0, 0.12) 3px
),
/* subtle grid */
repeating-linear-gradient(
90deg,
transparent,
transparent 79px,
rgba(62, 207, 74, 0.03) 79px,
rgba(62, 207, 74, 0.03) 80px
),
repeating-linear-gradient(
0deg,
transparent,
transparent 79px,
rgba(62, 207, 74, 0.03) 79px,
rgba(62, 207, 74, 0.03) 80px
);
opacity: 0.65;
mix-blend-mode: overlay;
}
/* scratch/grime texture via extra box-shadow on root */
.pause-screen::after {
content: "";
position: absolute;
inset: 0;
z-index: 20;
pointer-events: none;
background:
url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.08'/%3E%3C/svg%3E");
opacity: 0.35;
}
/* ── Left panel ──────────────────────────────────────────────── */
.left-panel {
position: absolute;
top: 0;
left: 0;
bottom: 0;
z-index: 10;
width: var(--co-panel-width);
min-width: calc(280px * var(--co-ui-scale));
max-width: 36%;
display: flex;
flex-direction: column;
padding:
calc(28px * var(--co-ui-scale))
calc(32px * var(--co-ui-scale))
calc(72px * var(--co-ui-scale))
calc(28px * var(--co-ui-scale));
background:
linear-gradient(
90deg,
var(--co-panel-bg) 0%,
rgba(8, 14, 10, 0.55) 70%,
var(--co-panel-fade) 100%
);
}
.brand-logo {
width: calc(200px * var(--co-ui-scale));
height: auto;
margin-bottom: calc(36px * var(--co-ui-scale));
opacity: 0.88;
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}
/* ── Menu list ───────────────────────────────────────────────── */
.menu {
display: flex;
flex-direction: column;
gap: var(--co-menu-gap);
flex: 1;
}
.menu-item {
position: relative;
display: flex;
align-items: center;
gap: calc(14px * var(--co-ui-scale));
width: 100%;
padding:
calc(10px * var(--co-ui-scale))
calc(12px * var(--co-ui-scale));
border: none;
background: transparent;
color: var(--co-text-muted);
font-family: inherit;
font-size: var(--co-menu-size);
font-weight: 700;
letter-spacing: 0.14em;
text-align: left;
cursor: pointer;
transition:
color var(--co-transition),
transform var(--co-transition);
outline: none;
}
.menu-item__icon {
display: flex;
align-items: center;
justify-content: center;
width: calc(22px * var(--co-ui-scale));
height: calc(22px * var(--co-ui-scale));
flex-shrink: 0;
opacity: 0.75;
}
.menu-item__icon svg {
width: 100%;
height: 100%;
fill: currentColor;
}
.menu-item__label {
position: relative;
z-index: 2;
}
/* Yellow selection bar with chevron right edge */
.menu-item__bar {
position: absolute;
left: calc(-28px * var(--co-ui-scale));
top: 50%;
transform: translateY(-50%) scaleX(0);
transform-origin: left center;
width: calc(100% + 80px * var(--co-ui-scale));
height: calc(100% + 4px);
background: linear-gradient(
90deg,
var(--co-select-yellow) 0%,
var(--co-select-yellow-bright) 85%,
#e0cc6e 100%
);
clip-path: polygon(
0 0,
calc(100% - 18px) 0,
100% 50%,
calc(100% - 18px) 100%,
0 100%
);
opacity: 0;
transition:
opacity var(--co-transition),
transform var(--co-transition);
z-index: 1;
box-shadow: 0 0 12px rgba(196, 168, 75, 0.25);
}
.menu-item:hover:not(.is-selected) {
color: var(--co-text-pale);
}
.menu-item:hover:not(.is-selected) .menu-item__icon {
opacity: 0.95;
}
.menu-item:focus-visible {
color: var(--co-text-pale);
outline: 1px solid var(--co-green-dim);
outline-offset: 2px;
}
.menu-item.is-selected {
color: var(--co-select-text);
}
.menu-item.is-selected .menu-item__icon {
opacity: 1;
color: var(--co-select-text);
}
.menu-item.is-selected .menu-item__bar {
opacity: 1;
transform: translateY(-50%) scaleX(1);
}
/* ── Server panel ────────────────────────────────────────────── */
.server-panel {
position: absolute;
top: calc(28px * var(--co-ui-scale));
right: calc(32px * var(--co-ui-scale));
z-index: 10;
min-width: calc(240px * var(--co-ui-scale));
padding:
calc(14px * var(--co-ui-scale))
calc(18px * var(--co-ui-scale));
background: rgba(6, 12, 8, 0.78);
border: 1px solid var(--co-border);
box-shadow:
inset 0 0 20px rgba(0, 0, 0, 0.4),
0 2px 8px rgba(0, 0, 0, 0.35);
}
.server-panel__heading {
font-size: calc(10px * var(--co-ui-scale));
font-weight: 700;
letter-spacing: 0.18em;
color: var(--co-amber);
margin-bottom: calc(4px * var(--co-ui-scale));
}
.server-panel__heading + .server-panel__heading {
margin-top: calc(14px * var(--co-ui-scale));
}
.server-panel__row {
display: flex;
align-items: center;
gap: calc(10px * var(--co-ui-scale));
}
.server-panel__name,
.server-panel__players {
font-size: calc(15px * var(--co-ui-scale));
font-weight: 600;
letter-spacing: 0.04em;
color: var(--co-text-pale);
}
.signal-bars {
display: flex;
align-items: flex-end;
gap: 2px;
height: calc(14px * var(--co-ui-scale));
flex-shrink: 0;
}
.signal-bars span {
display: block;
width: calc(3px * var(--co-ui-scale));
background: var(--co-green);
opacity: 0.85;
}
.signal-bars span:nth-child(1) { height: 35%; }
.signal-bars span:nth-child(2) { height: 55%; }
.signal-bars span:nth-child(3) { height: 75%; }
.signal-bars span:nth-child(4) { height: 100%; }
/* ── Bottom prompt bar ───────────────────────────────────────── */
.prompt-bar {
position: absolute;
left: 0;
right: 0;
bottom: 0;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
gap: calc(40px * var(--co-ui-scale));
padding:
calc(10px * var(--co-ui-scale))
calc(24px * var(--co-ui-scale));
background: linear-gradient(
180deg,
transparent 0%,
rgba(6, 10, 8, 0.75) 30%,
rgba(6, 10, 8, 0.88) 100%
);
border-top: 1px solid rgba(201, 168, 74, 0.15);
}
.prompt {
display: flex;
align-items: center;
gap: calc(8px * var(--co-ui-scale));
}
.prompt__glyph {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: calc(22px * var(--co-ui-scale));
height: calc(22px * var(--co-ui-scale));
font-size: calc(11px * var(--co-ui-scale));
font-weight: 700;
color: var(--co-amber);
border: 1px solid var(--co-amber-muted);
border-radius: 50%;
background: rgba(0, 0, 0, 0.35);
line-height: 1;
}
.prompt__glyph--rs {
border-radius: 4px;
font-size: calc(9px * var(--co-ui-scale));
letter-spacing: 0.02em;
min-width: calc(26px * var(--co-ui-scale));
}
.prompt__glyph--round {
font-size: calc(10px * var(--co-ui-scale));
}
.prompt__label {
font-size: calc(11px * var(--co-ui-scale));
font-weight: 600;
letter-spacing: 0.16em;
color: var(--co-text-pale);
opacity: 0.85;
}
/* ── Responsive tweaks ───────────────────────────────────────── */
/*
* Sizing is already fluid via --co-ui-scale (see :root), which now scales
* down for windows smaller than 1920x1080 instead of only scaling up.
* No breakpoint overrides needed on top of that for panel width or bar
* width; keeping both in sync with one scale avoids them drifting apart
* at arbitrary window sizes.
*/