Files
Commonwealth-Online-Public/ui/views/CommonwealthOnline/pause-menu/styles.css
T
andrew 38b6011de8 Pause menu: shared map blur, PC back, Xbox glyphs
Wrap map art and markers in a new .map-world so blur, pan and zoom animate together; add a PC-facing top-left ESC BACK button and a map-mode prompt bar using Xbox PNG glyphs. Implement JS glyph-tinting, map-mode enter/exit logic, and pan/zoom handlers; update styles for .map-world, markers, prompt bars, and the PC back button. Add Xbox icon assets and update deploy/stage scripts to copy them. Update changelog and dev-log entries to document the changes.
2026-07-04 17:41:29 +12:00

612 lines
15 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) */
@font-face {
font-family: "Futura PT Demibold";
src: url("../../fonts/futura-pt-demibold.otf") format("opentype");
font-weight: 600;
font-display: swap;
}
: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: "Futura PT Demibold", "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 world (map art + markers, one shared blur/pan/zoom) ── */
.map-world {
position: absolute;
inset: 0;
z-index: 1;
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, filter 200ms ease-out;
cursor: grab;
pointer-events: none;
}
.map-world.is-interactive {
pointer-events: auto;
}
.map-world.is-blurred {
filter: brightness(0.74) contrast(1.04) saturate(0.55) blur(12px);
}
.pause-screen.is-panning .map-world {
transition: none;
cursor: grabbing;
}
.map-layer {
position: absolute;
inset: 0;
/*
* "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;
}
.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 ───────────────────────────────────────────── */
/* Inside .map-world so they share the same filter and transform as the map. */
.map-markers {
position: absolute;
inset: 0;
pointer-events: none;
}
.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:
/* 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%
);
transition: opacity 200ms ease-out, visibility 200ms ease-out;
}
.left-panel.is-hidden {
opacity: 0;
visibility: hidden;
}
.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__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 {
color: var(--co-text-pale);
}
.menu-item:hover .menu-item__bar {
opacity: 1;
transform: translateY(-50%) scaleX(1);
}
.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__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);
transition: opacity 200ms ease-out, visibility 200ms ease-out;
}
.prompt-bar[hidden] {
opacity: 0;
visibility: hidden;
}
.prompt-bar--map-mode {
justify-content: center;
}
.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;
}
/* Xbox PNG glyphs (from ui/Icons); white pixels are tinted amber in script.js */
.prompt__glyph--icon {
border: none;
border-radius: 0;
background: transparent;
min-width: calc(28px * var(--co-ui-scale));
width: calc(28px * var(--co-ui-scale));
height: calc(28px * var(--co-ui-scale));
padding: 0;
}
/* Stick glyphs have more detail (arrows/rings) and read better slightly larger */
.prompt__glyph--icon-stick {
min-width: calc(34px * var(--co-ui-scale));
width: calc(34px * var(--co-ui-scale));
height: calc(34px * var(--co-ui-scale));
}
.prompt__glyph-img {
width: 100%;
height: 100%;
display: block;
pointer-events: none;
user-select: none;
}
.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;
}
/* ── Map mode PC back button ─────────────────────────────────── */
/*
* Fades in after the left panel (logo) finishes hiding (200ms), and
* fades out immediately on exit so it never sits on top of the logo.
*/
.map-pc-back {
position: absolute;
top: calc(28px * var(--co-ui-scale));
left: calc(28px * var(--co-ui-scale));
z-index: 12;
display: flex;
align-items: center;
gap: calc(12px * var(--co-ui-scale));
padding:
calc(10px * var(--co-ui-scale))
calc(16px * var(--co-ui-scale));
border: 1px solid var(--co-border);
background: rgba(6, 12, 8, 0.82);
box-shadow:
inset 0 0 16px rgba(0, 0, 0, 0.35),
0 2px 8px rgba(0, 0, 0, 0.35);
color: var(--co-text-pale);
font-family: inherit;
font-size: calc(14px * var(--co-ui-scale));
font-weight: 700;
letter-spacing: 0.16em;
cursor: pointer;
outline: none;
opacity: 0;
visibility: hidden;
pointer-events: none;
transition:
color var(--co-transition),
border-color var(--co-transition),
background var(--co-transition),
opacity 150ms ease-out,
visibility 0ms linear 150ms;
}
.map-pc-back.is-visible {
opacity: 1;
visibility: visible;
pointer-events: auto;
transition:
color var(--co-transition),
border-color var(--co-transition),
background var(--co-transition),
opacity 200ms ease-out 200ms,
visibility 0ms linear 200ms;
}
.map-pc-back__key {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: calc(36px * var(--co-ui-scale));
padding:
calc(3px * var(--co-ui-scale))
calc(8px * var(--co-ui-scale));
border: 1px solid var(--co-amber-muted);
border-radius: 2px;
background: rgba(0, 0, 0, 0.4);
color: var(--co-amber);
font-size: calc(11px * var(--co-ui-scale));
font-weight: 700;
letter-spacing: 0.08em;
line-height: 1.2;
}
.map-pc-back__label {
line-height: 1;
}
.map-pc-back:hover {
color: var(--co-green);
border-color: var(--co-green-dim);
background: rgba(8, 18, 10, 0.9);
}
.map-pc-back:hover .map-pc-back__key {
color: var(--co-green);
border-color: var(--co-green-dim);
}
.map-pc-back:focus-visible {
outline: 1px solid var(--co-green-dim);
outline-offset: 2px;
}
/* ── 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.
*/