Files
Commonwealth-Online-Public/ui/views/CommonwealthOnline/browser/styles.css
T
andrew 7efe407421 Add responsive UI scaling for server browser
Introduce resolution-aware UI scaling to keep fonts, glyphs, and panel chrome readable and aligned above 1920×1080. Adds a new components/layout.js that sets --co-ui-scale (baseline 1920×1080) on load/resize and exposes CO_Layout.update; index.html now loads it and app.js triggers updates onBrowserShown and on window resize. styles.css converts many fixed px values to calc()/em driven by --co-ui-scale, removes the old pixel-floor media queries and clamp caps, and scales borders, spacing, and font sizes. controller-glyphs.js multiplies glyph dimensions by the UI scale so controller icons grow correctly. Changes address small/drifting server browser content on high-res and ultrawide displays.
2026-06-18 15:51:42 +12:00

725 lines
16 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.
@font-face {
font-family: "Roboto Condensed";
src: url("./assets/fonts/RobotoCondensed-SemiBold.ttf") format("truetype");
font-weight: 600 700;
font-style: normal;
font-display: block;
}
:root {
/* RGB components — overridden at runtime from Fallout4Prefs.ini via plugin. */
--co-r: 18;
--co-g: 255;
--co-b: 21;
--co-bg-r: 0;
--co-bg-g: 10;
--co-bg-b: 0;
--co-green: rgb(var(--co-r), var(--co-g), var(--co-b));
--co-green-soft: rgb(var(--co-r), var(--co-g), var(--co-b));
--co-green-dim: rgba(var(--co-r), var(--co-g), var(--co-b), 0.22);
--co-bg: rgba(var(--co-bg-r), var(--co-bg-g), var(--co-bg-b), 0.62);
--co-bg-dark: rgba(var(--co-bg-r), var(--co-bg-g), var(--co-bg-b), 0.72);
--co-bg-list: transparent;
--co-selected: rgb(var(--co-r), var(--co-g), var(--co-b));
--co-selected-text: rgb(
calc(var(--co-r) * 0.05),
calc(var(--co-g) * 0.05),
calc(var(--co-b) * 0.05)
);
--co-border: rgb(var(--co-r), var(--co-g), var(--co-b));
--co-text-dim: rgba(var(--co-r), var(--co-g), var(--co-b), 0.5);
--co-ping-good: rgb(var(--co-r), var(--co-g), var(--co-b));
--co-ping-mid: #c8ff28;
--co-ping-bad: #ffd428;
--co-danger: #ff6a6a;
--co-font: "Roboto Condensed", "Bahnschrift", "Arial Narrow", Arial, sans-serif;
--co-transition: 80ms linear;
/*
* UI scale: 1920×1080 is the design baseline (scale 1). Higher resolutions scale up
* so text and chrome stay readable and aligned with the native Scaleform menu.
* layout.js also sets --co-ui-scale on resize for Ultralight.
*/
--co-ui-scale: max(1, min(calc(100vw / 1920), calc(100vh / 1080)));
--co-border-stroke: calc(5px * var(--co-ui-scale));
--co-border-strip-height: calc(11px * var(--co-ui-scale));
--co-border-cap: calc(10px * var(--co-ui-scale));
--co-border-edge: calc(4px * var(--co-ui-scale));
/*
* Fallout 4 submenu alignment (1280×720 reference, expressed as viewport %):
* Left — tight gap, no overlap (~454px @ 1280)
* Top — MULTIPLAYER row (~286px @ 720)
* Bottom — main menu box bottom (~146px inset @ 720)
*/
--co-panel-left: 35.6vw;
--co-panel-right: 2vw;
--co-panel-top: 39.5vh;
--co-panel-bottom: 20.5vh;
--co-font-xs: calc(11px * var(--co-ui-scale));
--co-font-sm: calc(12px * var(--co-ui-scale));
--co-font-md: calc(16px * var(--co-ui-scale));
--co-font-lg: calc(20px * var(--co-ui-scale));
--co-nav-width: calc(196px * var(--co-ui-scale));
/*
* In-game cursor is rendered by PrismaUI_F4 from Data/PrismaUI_F4/misc/cursor.png
* (deployed from assets/F4MouseCursor.png). CSS cursor only applies in a browser.
*/
--co-cursor: url("./assets/F4MouseCursor.png") 1 1, default;
}
* {
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-green);
background: transparent;
user-select: none;
-webkit-font-smoothing: antialiased;
cursor: var(--co-cursor);
}
.co-root.co-gamepad-mode,
.co-root.co-gamepad-mode * {
cursor: none !important;
}
.co-root {
position: relative;
width: 100vw;
height: 100vh;
pointer-events: none;
background: transparent;
}
/* Submenu panel — SVG border overlay + translucent fill. */
.co-panel {
position: absolute;
left: var(--co-panel-left);
right: var(--co-panel-right);
top: var(--co-panel-top);
bottom: var(--co-panel-bottom);
min-height: 0;
display: flex;
flex-direction: column;
border: none;
background: var(--co-bg);
pointer-events: auto;
transition: opacity var(--co-transition);
padding: var(--co-border-cap) var(--co-border-edge);
overflow: visible;
font-size: calc(16px * var(--co-ui-scale));
}
.co-panel.co-loading {
opacity: 0.85;
}
/*
* Top/bottom border strips (from assets/MenuBoarder.svg).
* Split so each edge anchors correctly — a single stretched SVG misaligns in Ultralight.
*/
.co-panel-border {
position: absolute;
left: 0;
width: 100%;
height: var(--co-border-strip-height);
pointer-events: none;
z-index: 10;
}
.co-panel-border-top {
top: 0;
}
.co-panel-border-bottom {
bottom: 0;
}
.co-panel-border-line {
fill: none;
stroke: var(--co-border);
stroke-width: var(--co-border-stroke);
stroke-miterlimit: 10;
vector-effect: non-scaling-stroke;
}
.co-subpanel {
flex: 1;
min-height: 0;
display: flex;
overflow: hidden;
}
/* Left nav — mirrors Settings / Load category list. */
.co-nav-list {
flex: 0 0 var(--co-nav-width);
display: flex;
flex-direction: column;
padding: 0.375em 0;
border-right: 0.0625em solid var(--co-green-dim);
overflow-y: auto;
}
.co-nav-item {
appearance: none;
border: none;
background: transparent;
color: var(--co-green-soft);
font: inherit;
font-size: var(--co-font-md);
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
text-align: left;
padding: 0.625em 1em;
cursor: var(--co-cursor);
transition: background var(--co-transition), color var(--co-transition);
}
.co-nav-item:hover:not(.active),
.co-nav-item.hovered:not(.active) {
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.08);
}
.co-nav-item.active.hovered {
filter: brightness(1.08);
}
.co-nav-item.active {
background: var(--co-selected);
color: var(--co-selected-text);
}
.co-nav-item.focused:not(.active) {
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.12);
}
.co-nav-list.focused .co-nav-item.focused:not(.active) {
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.12);
}
/* Right content */
.co-subpanel-content {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
overflow: hidden;
}
.co-tab-content {
flex: 1;
min-height: 0;
overflow: hidden;
}
.co-tab-pane {
display: none;
flex-direction: column;
height: 100%;
min-height: 0;
}
.co-tab-pane.active {
display: flex;
}
.co-subpanel-header {
flex-shrink: 0;
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 1em;
padding: 0.625em 1em 0.5em;
}
.co-subpanel-title {
font-size: var(--co-font-sm);
font-weight: 700;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--co-text-dim);
}
.co-subpanel-meta {
display: flex;
gap: 0.625em;
font-size: var(--co-font-xs);
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--co-text-dim);
white-space: nowrap;
}
.co-subpanel-meta .co-count {
color: var(--co-green-soft);
}
/* Preview — Load-menu thumbnail (favorites / recent only). */
.co-preview-area {
flex-shrink: 0;
margin: 0 0.75em 0.5em;
border: 0.0625em solid var(--co-green-dim);
background: var(--co-bg-dark);
overflow: hidden;
}
.co-preview-area:empty,
.co-preview-area.co-preview-hidden {
display: none;
}
.co-preview {
width: 100%;
height: calc(120px * var(--co-ui-scale));
display: flex;
align-items: center;
justify-content: center;
color: var(--co-text-dim);
font-size: var(--co-font-sm);
letter-spacing: 0.1em;
text-transform: uppercase;
overflow: hidden;
}
.co-preview img {
width: 100%;
height: 100%;
object-fit: cover;
}
.co-preview-caption {
padding: 0.375em 0.625em;
border-top: 0.0625em solid var(--co-green-dim);
font-size: var(--co-font-xs);
letter-spacing: 0.08em;
text-transform: uppercase;
line-height: 1.35;
}
.co-preview-caption .co-preview-name {
font-size: var(--co-font-sm);
font-weight: 700;
color: var(--co-green);
}
.co-preview-caption .co-preview-stats {
color: var(--co-text-dim);
}
/* Filters */
.co-filters {
flex-shrink: 0;
padding: 0 0.75em 0.625em;
display: flex;
flex-direction: column;
gap: 0.375em;
}
.co-filters.focused .co-filter-row.focused .co-filter-input,
.co-filters.focused .co-filter-row.focused .co-filter-select,
.co-filters.focused .co-filter-row.focused .co-checkbox {
outline: 0.0625em solid var(--co-green);
outline-offset: 0;
}
.co-filters-row {
display: flex;
flex-wrap: wrap;
align-items: flex-end;
gap: 0.375em 0.625em;
}
.co-filters-row-selects .co-filter-row {
flex: 1 1 5.625em;
min-width: 5em;
}
.co-filters-row-options {
align-items: center;
}
.co-filter-row {
display: flex;
flex-direction: column;
gap: 0.1875em;
min-width: 0;
}
.co-filter-row[data-filter-index="0"] {
width: 100%;
}
.co-filter-row.co-filter-checks {
flex-direction: row;
align-items: center;
gap: 0.3125em;
flex: 0 0 auto;
}
.co-filter-label {
font-size: var(--co-font-xs);
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--co-text-dim);
}
.co-filter-input,
.co-filter-select {
width: 100%;
background: var(--co-bg-dark);
border: 0.0625em solid var(--co-green-dim);
color: var(--co-green);
font: inherit;
font-size: var(--co-font-sm);
font-weight: 600;
padding: 0.3125em 0.5em;
border-radius: 0;
cursor: var(--co-cursor);
transition: border-color var(--co-transition);
}
.co-filter-input::placeholder {
color: var(--co-text-dim);
}
.co-filter-input:hover,
.co-filter-input.hovered,
.co-filter-select:hover,
.co-filter-select.hovered {
border-color: rgba(var(--co-r), var(--co-g), var(--co-b), 0.45);
}
.co-filter-input:focus,
.co-filter-select:focus {
border-color: var(--co-border);
outline: none;
}
.co-checkbox-row {
display: flex;
align-items: center;
gap: 0.3125em;
font-size: var(--co-font-xs);
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
cursor: var(--co-cursor);
transition: background var(--co-transition), border-color var(--co-transition);
}
.co-checkbox-row:hover,
.co-checkbox-row.hovered {
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.06);
}
.co-checkbox {
width: calc(13px * var(--co-ui-scale));
height: calc(13px * var(--co-ui-scale));
border: 0.0625em solid var(--co-border);
background: transparent;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.co-checkbox.checked::after {
content: "X";
font-size: calc(9px * var(--co-ui-scale));
font-weight: 700;
color: var(--co-green);
line-height: 1;
}
.co-btn {
appearance: none;
border: 0.0625em solid var(--co-green-dim);
background: transparent;
color: var(--co-green);
font: inherit;
font-size: var(--co-font-xs);
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
padding: 0.3125em 0.625em;
cursor: var(--co-cursor);
margin-left: auto;
flex-shrink: 0;
transition: background var(--co-transition), border-color var(--co-transition);
}
.co-btn:hover,
.co-btn.hovered {
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.1);
border-color: rgba(var(--co-r), var(--co-g), var(--co-b), 0.45);
}
.co-btn.focused {
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.18);
outline: 0.0625em solid var(--co-green);
}
/* Server list — save-file style rows */
.co-server-list-wrap {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
position: relative;
}
.co-server-list-wrap.focused {
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.03);
}
.co-server-list {
flex: 1;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: var(--co-green-dim) transparent;
padding: 0 0.25em;
}
.co-server-list::-webkit-scrollbar {
width: calc(4px * var(--co-ui-scale));
}
.co-server-list::-webkit-scrollbar-thumb {
background: var(--co-green-dim);
}
.co-server-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1em;
padding: 0.5em 0.75em;
font-size: var(--co-font-md);
line-height: 1.2;
cursor: var(--co-cursor);
transition: background var(--co-transition), color var(--co-transition);
}
.co-server-row:hover:not(.selected),
.co-server-row.hovered:not(.selected) {
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.06);
}
.co-server-row.selected {
background: var(--co-selected);
color: var(--co-selected-text);
}
.co-server-row-left {
display: flex;
align-items: center;
gap: 0.625em;
min-width: 0;
flex: 1;
}
.co-server-row-name {
font-size: var(--co-font-lg);
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.co-server-row-right {
display: flex;
align-items: center;
gap: 1.25em;
flex-shrink: 0;
font-size: var(--co-font-md);
font-weight: 700;
letter-spacing: 0.04em;
}
.co-server-row.selected .co-server-row-right,
.co-server-row.selected .co-fav,
.co-server-row.selected .co-ping {
color: var(--co-selected-text);
}
.co-fav {
color: var(--co-text-dim);
font-size: calc(15px * var(--co-ui-scale));
flex-shrink: 0;
}
.co-fav.on {
color: var(--co-green);
}
.co-server-row.selected .co-fav.on {
color: var(--co-selected-text);
}
.co-ping-good { color: var(--co-ping-good); }
.co-ping-mid { color: var(--co-ping-mid); }
.co-ping-bad { color: var(--co-ping-bad); }
.co-server-row.selected .co-ping-good,
.co-server-row.selected .co-ping-mid,
.co-server-row.selected .co-ping-bad {
color: var(--co-selected-text);
}
.co-scroll-indicator {
flex-shrink: 0;
text-align: center;
padding: 0.125em 0 0.25em;
font-size: var(--co-font-xs);
letter-spacing: 0.15em;
color: var(--co-text-dim);
}
.co-scroll-indicator.hidden {
display: none;
}
/* Footer prompts */
.co-action-bar {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 0.375em 0.875em 0.5em;
border-top: 0.0625em solid var(--co-green-dim);
}
.co-prompts {
display: flex;
gap: 1em;
flex-wrap: wrap;
justify-content: flex-end;
}
.co-prompt {
display: flex;
align-items: center;
gap: 0.375em;
font-size: var(--co-font-xs);
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--co-green-soft);
}
.co-prompt-key {
min-width: calc(18px * var(--co-ui-scale));
height: calc(18px * var(--co-ui-scale));
border: 0.0625em solid var(--co-border);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: calc(8px * var(--co-ui-scale));
font-weight: 700;
padding: 0 calc(3px * var(--co-ui-scale));
}
.co-prompt-key--glyph {
position: relative;
display: inline-block;
min-width: 0;
border: none;
border-radius: 0;
padding: 0;
flex-shrink: 0;
vertical-align: middle;
}
.co-prompt-key--glyph .co-glyph-img {
width: 100%;
height: 100%;
display: block;
}
.co-direct-connect {
padding: 1em 1.25em;
max-width: calc(480px * var(--co-ui-scale));
}
.co-direct-row {
margin-bottom: 0.75em;
}
.co-direct-row.focused .co-filter-input {
outline: 0.0625em solid var(--co-green);
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.08);
}
.co-direct-row label {
display: block;
font-size: var(--co-font-xs);
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--co-text-dim);
margin-bottom: 0.25em;
}
.co-empty {
padding: 1.5em 1em;
text-align: center;
color: var(--co-text-dim);
font-size: var(--co-font-md);
letter-spacing: 0.08em;
text-transform: uppercase;
}
.co-join-overlay {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.75);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 10;
pointer-events: auto;
}
.co-join-overlay.hidden {
display: none;
}
.co-join-overlay p {
font-size: var(--co-font-md);
letter-spacing: 0.1em;
text-transform: uppercase;
margin-top: 0.875em;
}
.co-join-overlay.co-error p {
color: var(--co-danger);
}
.co-spinner {
width: calc(22px * var(--co-ui-scale));
height: calc(22px * var(--co-ui-scale));
border: calc(2px * var(--co-ui-scale)) solid var(--co-green-dim);
border-top-color: var(--co-green);
border-radius: 50%;
animation: co-spin 0.8s linear infinite;
}
@keyframes co-spin {
to { transform: rotate(360deg); }
}