Files
Commonwealth-Online-Public/ui/views/CommonwealthOnline/browser/styles.css
T
andrew 31406a1275 Add hover sync and CO hover component
Add a hover system to restore :hover-like behavior for custom UI elements in the CommonwealthOnline view. Changes include:

- plugin/src/F4TPrismaUI.cpp: add SyncBrowserHover() which reads the native cursor position, converts it to client coordinates, and invokes a JS update on the server browser view; register a periodic task to call SyncBrowserHover every other tick.
- ui/views/CommonwealthOnline/browser/components/hover.js: new component that tracks pointer position, determines hovered targets using a selector list, and applies/removes a .hovered class; exposes bind(), updateFromPoint(), and clear().
- ui/views/CommonwealthOnline/browser/app.js & index.html: include and bind the new hover component during UI initialization.
- ui/views/CommonwealthOnline/browser/styles.css: add .hovered variants and transitions for nav items, buttons, rows, and filter controls to match hover visuals.
- steam_interfaces.txt: add a list of Steam interface version strings (new file).

Purpose: ensure custom buttons/rows that don't receive native :hover updates from the renderer get visible hover feedback by syncing the native cursor into the web UI and toggling a .hovered class.
2026-06-16 15:55:32 +12:00

711 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.
@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;
--co-border-stroke: 5px;
--co-border-strip-height: 11px;
--co-border-cap: 10px;
--co-border-edge: 4px;
/*
* Fallout 4 submenu alignment (1280×720, like ADD-ONS panel):
* Left — tight gap, no overlap (~454px)
* Top — MULTIPLAYER row (~286px)
* Bottom — main menu box bottom (~146px inset)
*/
--co-panel-left: max(35.6vw, 454px);
--co-panel-right: max(2vw, 24px);
--co-panel-top: max(39.5vh, 286px);
--co-panel-bottom: max(20.5vh, 146px);
--co-font-xs: clamp(9px, 0.75vw, 11px);
--co-font-sm: clamp(10px, 0.85vw, 12px);
--co-font-md: clamp(13px, 1.05vw, 16px);
--co-font-lg: clamp(16px, 1.3vw, 20px);
--co-nav-width: clamp(152px, 14vw, 196px);
/*
* 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 {
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;
}
.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: 6px 0;
border-right: 1px 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: 10px 16px;
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: 16px;
padding: 10px 16px 8px;
}
.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: 10px;
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 12px 8px;
border: 1px 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: clamp(72px, 14vh, 120px);
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: 6px 10px;
border-top: 1px 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 12px 10px;
display: flex;
flex-direction: column;
gap: 6px;
}
.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: 1px solid var(--co-green);
outline-offset: 0;
}
.co-filters-row {
display: flex;
flex-wrap: wrap;
align-items: flex-end;
gap: 6px 10px;
}
.co-filters-row-selects .co-filter-row {
flex: 1 1 90px;
min-width: 80px;
}
.co-filters-row-options {
align-items: center;
}
.co-filter-row {
display: flex;
flex-direction: column;
gap: 3px;
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: 5px;
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: 1px solid var(--co-green-dim);
color: var(--co-green);
font: inherit;
font-size: var(--co-font-sm);
font-weight: 600;
padding: 5px 8px;
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: 5px;
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: 13px;
height: 13px;
border: 1px 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: 9px;
font-weight: 700;
color: var(--co-green);
line-height: 1;
}
.co-btn {
appearance: none;
border: 1px 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: 5px 10px;
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: 1px 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 4px;
}
.co-server-list::-webkit-scrollbar {
width: 4px;
}
.co-server-list::-webkit-scrollbar-thumb {
background: var(--co-green-dim);
}
.co-server-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 8px 12px;
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: 10px;
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: 20px;
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: 15px;
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: 2px 0 4px;
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: 6px 14px 8px;
border-top: 1px solid var(--co-green-dim);
}
.co-prompts {
display: flex;
gap: 16px;
flex-wrap: wrap;
justify-content: flex-end;
}
.co-prompt {
display: flex;
align-items: center;
gap: 6px;
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: 18px;
height: 18px;
border: 1px solid var(--co-border);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 8px;
font-weight: 700;
padding: 0 3px;
}
.co-direct-connect {
padding: 16px 20px;
max-width: 480px;
}
.co-direct-row {
margin-bottom: 12px;
}
.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: 4px;
}
.co-empty {
padding: 24px 16px;
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: 14px;
}
.co-join-overlay.co-error p {
color: var(--co-danger);
}
.co-spinner {
width: 22px;
height: 22px;
border: 2px 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); }
}
@media (max-width: 1280px) {
:root {
--co-panel-left: max(35.8vw, 450px);
--co-panel-right: max(2vw, 16px);
--co-panel-top: max(40vh, 280px);
--co-panel-bottom: max(21vh, 142px);
--co-nav-width: clamp(136px, 15vw, 168px);
}
}
@media (min-width: 2560px) {
:root {
--co-panel-left: max(35.6vw, 908px);
--co-panel-right: max(2.5vw, 48px);
--co-panel-top: max(39.5vh, 572px);
--co-panel-bottom: max(20.5vh, 292px);
}
}