Restyle server browser UI; hide overlay on join
Restyles the server browser to match main-menu/settings (Futura PT Demibold, amber/green palette, yellow selection bars, shared panel chrome), removes SVG border strips, and tweaks modal width/layout. Adds JS + C++ coordination so the custom main-menu overlay hides when a server join begins (C++ invokes onSessionLoading and calls HideMainMenu; CompleteJoinFailure restores the menu/browser). Controller glyph tint now derives from --co-amber. Updates changelog and dev-log; includes compiled Vault109 script update.
This commit is contained in:
@@ -9,8 +9,12 @@ For testing notes, milestone summaries, known issues, and next steps, see [`docs
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Server browser UI restyled to match the main menu and settings panels: Futura PT Demibold typography, amber/green palette, yellow selection bars, and shared panel chrome (replaces the old bright-green HUD terminal look and SVG border strips).
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Main menu left-nav highlight no longer swaps when switching between Multiplayer browser and Settings modals (stale panel-close callbacks were overwriting `setSelected` after the next modal opened).
|
- Main menu left-nav highlight no longer swaps when switching between Multiplayer browser and Settings modals (stale panel-close callbacks were overwriting `setSelected` after the next modal opened).
|
||||||
|
- Custom main menu overlay and open sub-panels (server browser, settings) now hide when a server join begins loading the game, so the overlay no longer obscures or blocks the vanilla loading screen.
|
||||||
- Mouse cursor no longer trampolines back to a centered box in the custom main menu (previously only worked with a gamepad connected). In mouse mode the title-screen engine repositions/clips the OS cursor to a small centered box every frame; with a gamepad active that path never runs, so the pointer was free. Fixed by intercepting `SetCursorPos` and `ClipCursor` in the Fallout4.exe import table (IAT) and making them no-ops while the Commonwealth Online overlay owns the pointer, so the game can no longer move or box in the Windows cursor. Only the game module's imports are patched, leaving PrismaUI's own cursor rendering untouched. Also hooks the `MainMenu` `OnCursorMoveEvent`/`OnMouseMoveEvent` vtable slots and keeps the `MenuCursor` release (`forceOSCursorPos = false`, cleared parallax constraints, widened bounds) as defense-in-depth.
|
- Mouse cursor no longer trampolines back to a centered box in the custom main menu (previously only worked with a gamepad connected). In mouse mode the title-screen engine repositions/clips the OS cursor to a small centered box every frame; with a gamepad active that path never runs, so the pointer was free. Fixed by intercepting `SetCursorPos` and `ClipCursor` in the Fallout4.exe import table (IAT) and making them no-ops while the Commonwealth Online overlay owns the pointer, so the game can no longer move or box in the Windows cursor. Only the game module's imports are patched, leaving PrismaUI's own cursor rendering untouched. Also hooks the `MainMenu` `OnCursorMoveEvent`/`OnMouseMoveEvent` vtable slots and keeps the `MenuCursor` release (`forceOSCursorPos = false`, cleared parallax constraints, widened bounds) as defense-in-depth.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
Binary file not shown.
@@ -9,6 +9,36 @@ failed experiments, successful tests, and next steps.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-07-07 - Fix: Hide Main Menu Overlay During Server Join Load
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
When joining a server from the custom main menu, the PrismaUI overlay (left nav, server browser, settings) stayed visible and interactive while the vanilla loading screen appeared underneath. The overlay now hides as soon as server validation succeeds and game load begins; failed joins restore the main menu and browser with the error overlay.
|
||||||
|
|
||||||
|
### Files Changed
|
||||||
|
- `plugin/src/F4TServerBrowserBridge.cpp`
|
||||||
|
- `ui/views/CommonwealthOnline/main-menu/script.js`
|
||||||
|
- `ui/views/CommonwealthOnline/main-menu/styles.css`
|
||||||
|
- `changelog.md`
|
||||||
|
- `docs/dev-log.md`
|
||||||
|
|
||||||
|
### Details
|
||||||
|
- `JoinServerEntry` invokes `onSessionLoading` in JS, then calls `HideMainMenu()` after the `joinLoading` / "Loading game..." event.
|
||||||
|
- `CompleteJoinFailure` restores the main menu and browser before dispatching `joinFailed` so the error overlay can display.
|
||||||
|
- JS `onSessionLoading` collapses open sub-panels and applies `is-session-loading` (non-interactive) as a same-frame fallback before C++ hides the view.
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
- Not run locally (requires Fallout 4 + built plugin).
|
||||||
|
- Expected: connect from main menu → overlay disappears → loading screen visible and unobstructed.
|
||||||
|
- Expected on failure: overlay returns with join error message in browser.
|
||||||
|
|
||||||
|
### Known Issues
|
||||||
|
- None currently known.
|
||||||
|
|
||||||
|
### Next Steps
|
||||||
|
- In-game verification with two clients after deploy.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 2026-07-07 - Fix: Trampoline Crash on Load (MenuCursor Hook Replaced)
|
## 2026-07-07 - Fix: Trampoline Crash on Load (MenuCursor Hook Replaced)
|
||||||
|
|
||||||
### Summary
|
### Summary
|
||||||
|
|||||||
@@ -212,10 +212,21 @@ namespace F4T::ServerBrowser
|
|||||||
LogInfo(std::format(" Joined server '{}'.", a_entry.name));
|
LogInfo(std::format(" Joined server '{}'.", a_entry.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RestoreMainMenuAfterJoinFailure()
|
||||||
|
{
|
||||||
|
if (F4T::PrismaUI::IsMainMenuVisible()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
F4T::PrismaUI::ShowMainMenu();
|
||||||
|
F4T::PrismaUI::ShowServerBrowser();
|
||||||
|
}
|
||||||
|
|
||||||
void CompleteJoinFailure(const ServerEntry& a_entry, std::string_view a_reason)
|
void CompleteJoinFailure(const ServerEntry& a_entry, std::string_view a_reason)
|
||||||
{
|
{
|
||||||
F4T::Networking::DisconnectFromLocalServer();
|
F4T::Networking::DisconnectFromLocalServer();
|
||||||
PushConnectionStatusEvent();
|
PushConnectionStatusEvent();
|
||||||
|
RestoreMainMenuAfterJoinFailure();
|
||||||
DispatchEvent(nlohmann::json{
|
DispatchEvent(nlohmann::json{
|
||||||
{ "type", "joinFailed" },
|
{ "type", "joinFailed" },
|
||||||
{ "serverId", a_entry.id },
|
{ "serverId", a_entry.id },
|
||||||
@@ -259,6 +270,13 @@ namespace F4T::ServerBrowser
|
|||||||
{ "message", "Loading game..." }
|
{ "message", "Loading game..." }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (g_api && g_view != 0 && g_api->IsValid(g_view)) {
|
||||||
|
g_api->Invoke(g_view, "if(window.onSessionLoading){window.onSessionLoading();}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide the custom main menu overlay before the vanilla loading screen appears.
|
||||||
|
F4T::PrismaUI::HideMainMenu();
|
||||||
|
|
||||||
const auto* taskInterface = F4SE::GetTaskInterface();
|
const auto* taskInterface = F4SE::GetTaskInterface();
|
||||||
if (!taskInterface) {
|
if (!taskInterface) {
|
||||||
a_error = "Game task interface is unavailable.";
|
a_error = "Game task interface is unavailable.";
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
left: calc(50% + 48px * var(--co-ui-scale));
|
left: calc(50% + 48px * var(--co-ui-scale));
|
||||||
transform: translate(-50%, calc(-50% + 10px * var(--co-ui-scale)));
|
transform: translate(-50%, calc(-50% + 10px * var(--co-ui-scale)));
|
||||||
z-index: 11;
|
z-index: 11;
|
||||||
width: min(calc(1080px * var(--co-ui-scale)), calc(100vw - 80px * var(--co-ui-scale)));
|
width: min(calc(920px * var(--co-ui-scale)), calc(100vw - 80px * var(--co-ui-scale)));
|
||||||
height: min(calc(720px * var(--co-ui-scale)), calc(100vh - 120px * var(--co-ui-scale)));
|
height: min(calc(720px * var(--co-ui-scale)), calc(100vh - 120px * var(--co-ui-scale)));
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
|
|||||||
@@ -2,18 +2,13 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function buildMarkup(layout) {
|
function buildMarkup(layout) {
|
||||||
var embeddedClass = layout === "embedded" ? " co-browser--embedded" : "";
|
var layoutClass = layout === "embedded" ? " co-browser--embedded" : " co-browser--standalone";
|
||||||
return (
|
return (
|
||||||
'<div class="co-root' +
|
'<div class="co-root' +
|
||||||
embeddedClass +
|
layoutClass +
|
||||||
'" id="coRoot">' +
|
'" id="coRoot">' +
|
||||||
'<div class="co-panel" id="coPanel">' +
|
'<div class="co-panel" id="coPanel">' +
|
||||||
'<svg class="co-panel-border co-panel-border-top" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1075.97 11" preserveAspectRatio="none" aria-hidden="true">' +
|
'<h1 class="co-panel__heading">MULTIPLAYER</h1>' +
|
||||||
'<polyline class="co-panel-border-line" points="0 10.97 0 0 1075.97 0 1075.97 10.5"/>' +
|
|
||||||
"</svg>" +
|
|
||||||
'<svg class="co-panel-border co-panel-border-bottom" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1075.97 11" preserveAspectRatio="none" aria-hidden="true">' +
|
|
||||||
'<polyline class="co-panel-border-line" points="0 0.47 0 8.91 1075.97 8.97 1075.97 0.47"/>' +
|
|
||||||
"</svg>" +
|
|
||||||
'<div class="co-subpanel">' +
|
'<div class="co-subpanel">' +
|
||||||
'<nav class="co-nav-list"></nav>' +
|
'<nav class="co-nav-list"></nav>' +
|
||||||
'<div class="co-subpanel-content">' +
|
'<div class="co-subpanel-content">' +
|
||||||
|
|||||||
@@ -71,10 +71,15 @@
|
|||||||
|
|
||||||
function getTintColor() {
|
function getTintColor() {
|
||||||
var style = getComputedStyle(document.documentElement);
|
var style = getComputedStyle(document.documentElement);
|
||||||
|
var amber = style.getPropertyValue("--co-amber").trim() || "#c9a84a";
|
||||||
|
var hex = amber.replace("#", "");
|
||||||
|
if (hex.length === 3) {
|
||||||
|
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
r: parseInt(style.getPropertyValue("--co-r"), 10) || 18,
|
r: parseInt(hex.slice(0, 2), 16) || 201,
|
||||||
g: parseInt(style.getPropertyValue("--co-g"), 10) || 255,
|
g: parseInt(hex.slice(2, 4), 16) || 168,
|
||||||
b: parseInt(style.getPropertyValue("--co-b"), 10) || 21
|
b: parseInt(hex.slice(4, 6), 16) || 74
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,16 +5,6 @@
|
|||||||
return Math.max(0, Math.min(255, Math.round(value)));
|
return Math.max(0, Math.min(255, Math.round(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyHudRgb(root, prefix, color) {
|
|
||||||
if (!color) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
root.style.setProperty(prefix + "-r", String(clampByte(color.r)));
|
|
||||||
root.style.setProperty(prefix + "-g", String(clampByte(color.g)));
|
|
||||||
root.style.setProperty(prefix + "-b", String(clampByte(color.b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyCursorTint(root, color) {
|
function applyCursorTint(root, color) {
|
||||||
if (!color) {
|
if (!color) {
|
||||||
return;
|
return;
|
||||||
@@ -41,8 +31,6 @@
|
|||||||
|
|
||||||
var root = document.documentElement;
|
var root = document.documentElement;
|
||||||
var hud = theme.hud || theme;
|
var hud = theme.hud || theme;
|
||||||
applyHudRgb(root, "--co", hud);
|
|
||||||
applyHudRgb(root, "--co-bg", theme.hudBackground);
|
|
||||||
applyCursorTint(root, hud);
|
applyCursorTint(root, hud);
|
||||||
|
|
||||||
if (window.CO_ControllerGlyphs && CO_ControllerGlyphs.onThemeApplied) {
|
if (window.CO_ControllerGlyphs && CO_ControllerGlyphs.onThemeApplied) {
|
||||||
@@ -50,7 +38,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
"[CO] Applied HUD theme rgb(" +
|
"[CO] Applied browser cursor theme rgb(" +
|
||||||
clampByte(hud.r) + "," +
|
clampByte(hud.r) + "," +
|
||||||
clampByte(hud.g) + "," +
|
clampByte(hud.g) + "," +
|
||||||
clampByte(hud.b) + ")"
|
clampByte(hud.b) + ")"
|
||||||
|
|||||||
@@ -1,72 +1,43 @@
|
|||||||
|
/* Commonwealth Online — server browser UI
|
||||||
|
* Expects theme tokens from the host view (main menu / pause menu):
|
||||||
|
* --co-ui-scale, --co-amber, --co-text-pale, --co-text-muted,
|
||||||
|
* --co-select-yellow, --co-select-yellow-bright, --co-select-text,
|
||||||
|
* --co-transition, --co-green, --co-green-dim, --co-amber-muted
|
||||||
|
*/
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Roboto Condensed";
|
font-family: "Futura PT Demibold";
|
||||||
src: url("./assets/fonts/RobotoCondensed-SemiBold.ttf") format("truetype");
|
src: url("../../fonts/futura-pt-demibold.otf") format("opentype");
|
||||||
font-weight: 600 700;
|
font-weight: 600;
|
||||||
font-style: normal;
|
font-display: swap;
|
||||||
font-display: block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
/* RGB components — overridden at runtime from Fallout4Prefs.ini via plugin. */
|
--co-ui-scale: 1;
|
||||||
--co-r: 18;
|
|
||||||
--co-g: 255;
|
/* Standalone fallbacks — match main-menu/styles.css when no host is present */
|
||||||
--co-b: 21;
|
--co-black: #0a0c0a;
|
||||||
--co-bg-r: 0;
|
--co-amber: #c9a84a;
|
||||||
--co-bg-g: 10;
|
--co-amber-muted: rgba(201, 168, 74, 0.55);
|
||||||
--co-bg-b: 0;
|
--co-text-pale: #d8ddd0;
|
||||||
--co-green: rgb(var(--co-r), var(--co-g), var(--co-b));
|
--co-text-muted: #9aa898;
|
||||||
--co-green-soft: rgb(var(--co-r), var(--co-g), var(--co-b));
|
--co-select-yellow: #c4a84b;
|
||||||
--co-green-dim: rgba(var(--co-r), var(--co-g), var(--co-b), 0.22);
|
--co-select-yellow-bright: #d4bc62;
|
||||||
--co-bg: rgba(var(--co-bg-r), var(--co-bg-g), var(--co-bg-b), 0.62);
|
--co-select-text: #1a1c18;
|
||||||
--co-bg-dark: rgba(var(--co-bg-r), var(--co-bg-g), var(--co-bg-b), 0.72);
|
--co-green: #3ecf4a;
|
||||||
--co-bg-list: transparent;
|
--co-green-dim: rgba(62, 207, 74, 0.35);
|
||||||
--co-selected: rgb(var(--co-r), var(--co-g), var(--co-b));
|
--co-transition: 120ms ease-out;
|
||||||
--co-selected-text: rgb(
|
--co-font: "Futura PT Demibold", "Roboto Condensed", "Bahnschrift", "Arial Narrow", Arial, sans-serif;
|
||||||
calc(var(--co-r) * 0.05),
|
--co-ping-good: #3ecf4a;
|
||||||
calc(var(--co-g) * 0.05),
|
--co-ping-mid: #c9a84a;
|
||||||
calc(var(--co-b) * 0.05)
|
--co-ping-bad: #d48a4a;
|
||||||
);
|
--co-danger: #e07070;
|
||||||
--co-border: rgb(var(--co-r), var(--co-g), var(--co-b));
|
--co-cursor: default;
|
||||||
--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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -79,7 +50,7 @@ body {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-family: var(--co-font);
|
font-family: var(--co-font);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--co-green);
|
color: var(--co-text-pale);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
@@ -91,64 +62,103 @@ body {
|
|||||||
cursor: none !important;
|
cursor: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Root layout ─────────────────────────────────────────────── */
|
||||||
|
|
||||||
.co-root {
|
.co-root {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100vw;
|
width: 100%;
|
||||||
height: 100vh;
|
height: 100%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Submenu panel — SVG border overlay + translucent fill. */
|
.co-root.co-browser--standalone {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
pointer-events: auto;
|
||||||
|
background: var(--co-black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.co-root.co-browser--standalone::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
background:
|
||||||
|
radial-gradient(
|
||||||
|
ellipse 80% 60% at 72% 42%,
|
||||||
|
rgba(62, 207, 74, 0.08) 0%,
|
||||||
|
transparent 55%
|
||||||
|
),
|
||||||
|
radial-gradient(
|
||||||
|
ellipse 55% 45% at 35% 70%,
|
||||||
|
rgba(201, 168, 74, 0.06) 0%,
|
||||||
|
transparent 50%
|
||||||
|
),
|
||||||
|
linear-gradient(
|
||||||
|
165deg,
|
||||||
|
#0b120d 0%,
|
||||||
|
#141a12 28%,
|
||||||
|
#1a2218 48%,
|
||||||
|
#121810 72%,
|
||||||
|
#080c08 100%
|
||||||
|
);
|
||||||
|
filter: brightness(0.82) contrast(1.05) saturate(0.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Panel shell (matches .settings-panel) ─────────────────── */
|
||||||
|
|
||||||
.co-panel {
|
.co-panel {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: var(--co-panel-left);
|
left: var(--co-panel-left, 0);
|
||||||
right: var(--co-panel-right);
|
right: var(--co-panel-right, 0);
|
||||||
top: var(--co-panel-top);
|
top: var(--co-panel-top, 0);
|
||||||
bottom: var(--co-panel-bottom);
|
bottom: var(--co-panel-bottom, 0);
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border: none;
|
border: 1px solid rgba(201, 168, 74, 0.28);
|
||||||
background: var(--co-bg);
|
background: rgba(6, 12, 8, 0.78);
|
||||||
|
box-shadow:
|
||||||
|
inset 0 0 28px rgba(0, 0, 0, 0.35),
|
||||||
|
0 2px 16px rgba(0, 0, 0, 0.3);
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
transition: opacity var(--co-transition);
|
transition: opacity var(--co-transition);
|
||||||
padding: var(--co-border-cap) var(--co-border-edge);
|
padding:
|
||||||
overflow: visible;
|
calc(16px * var(--co-ui-scale))
|
||||||
|
calc(20px * var(--co-ui-scale))
|
||||||
|
calc(12px * var(--co-ui-scale));
|
||||||
|
overflow: hidden;
|
||||||
font-size: calc(16px * var(--co-ui-scale));
|
font-size: calc(16px * var(--co-ui-scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.co-root.co-browser--standalone .co-panel {
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
right: auto;
|
||||||
|
bottom: auto;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: min(calc(920px * var(--co-ui-scale)), calc(100vw - 80px * var(--co-ui-scale)));
|
||||||
|
height: min(calc(720px * var(--co-ui-scale)), calc(100vh - 120px * var(--co-ui-scale)));
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.co-panel.co-loading {
|
.co-panel.co-loading {
|
||||||
opacity: 0.85;
|
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 {
|
.co-panel-border {
|
||||||
position: absolute;
|
display: none;
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: var(--co-border-strip-height);
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-panel-border-top {
|
.co-panel__heading {
|
||||||
top: 0;
|
flex-shrink: 0;
|
||||||
}
|
margin-bottom: calc(14px * var(--co-ui-scale));
|
||||||
|
font-size: calc(22px * var(--co-ui-scale));
|
||||||
.co-panel-border-bottom {
|
font-weight: 700;
|
||||||
bottom: 0;
|
letter-spacing: 0.2em;
|
||||||
}
|
color: var(--co-amber);
|
||||||
|
|
||||||
.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 {
|
.co-subpanel {
|
||||||
@@ -156,57 +166,74 @@ body {
|
|||||||
min-height: 0;
|
min-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
gap: calc(12px * var(--co-ui-scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Left nav — mirrors Settings / Load category list. */
|
/* ── Left nav (vertical tab strip) ───────────────────────────── */
|
||||||
|
|
||||||
.co-nav-list {
|
.co-nav-list {
|
||||||
flex: 0 0 var(--co-nav-width);
|
flex: 0 0 calc(168px * var(--co-ui-scale));
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 0.375em 0;
|
gap: calc(4px * var(--co-ui-scale));
|
||||||
border-right: 0.0625em solid var(--co-green-dim);
|
padding: calc(4px * var(--co-ui-scale)) 0;
|
||||||
|
border-right: 1px solid rgba(62, 207, 74, 0.22);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-nav-item {
|
.co-nav-item {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
border: none;
|
position: relative;
|
||||||
background: transparent;
|
border: 1px solid transparent;
|
||||||
color: var(--co-green-soft);
|
background: rgba(4, 10, 6, 0.35);
|
||||||
|
color: var(--co-text-pale);
|
||||||
font: inherit;
|
font: inherit;
|
||||||
font-size: var(--co-font-md);
|
font-size: calc(13px * var(--co-ui-scale));
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.12em;
|
letter-spacing: 0.12em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 0.625em 1em;
|
padding:
|
||||||
|
calc(10px * var(--co-ui-scale))
|
||||||
|
calc(12px * var(--co-ui-scale));
|
||||||
cursor: var(--co-cursor);
|
cursor: var(--co-cursor);
|
||||||
transition: background var(--co-transition), color var(--co-transition);
|
outline: none;
|
||||||
|
transition:
|
||||||
|
color var(--co-transition),
|
||||||
|
background var(--co-transition),
|
||||||
|
border-color var(--co-transition),
|
||||||
|
box-shadow var(--co-transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-nav-item:hover:not(.active),
|
.co-nav-item:hover:not(.active) {
|
||||||
.co-nav-item.hovered:not(.active) {
|
background: rgba(62, 207, 74, 0.08);
|
||||||
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.08);
|
color: var(--co-text-pale);
|
||||||
}
|
|
||||||
|
|
||||||
.co-nav-item.active.hovered {
|
|
||||||
filter: brightness(1.08);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-nav-item.active {
|
.co-nav-item.active {
|
||||||
background: var(--co-selected);
|
color: var(--co-select-text);
|
||||||
color: var(--co-selected-text);
|
background: linear-gradient(
|
||||||
}
|
180deg,
|
||||||
|
var(--co-select-yellow) 0%,
|
||||||
.co-nav-item.focused:not(.active) {
|
var(--co-select-yellow-bright) 100%
|
||||||
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.12);
|
);
|
||||||
|
border-color: rgba(201, 168, 74, 0.55);
|
||||||
|
box-shadow: 0 0 12px rgba(196, 168, 75, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-nav-list.focused .co-nav-item.focused:not(.active) {
|
.co-nav-list.focused .co-nav-item.focused:not(.active) {
|
||||||
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.12);
|
outline: 1px solid rgba(62, 207, 74, 0.35);
|
||||||
|
outline-offset: -1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Right content */
|
.co-nav-list.focused .co-nav-item.active {
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 1px rgba(62, 207, 74, 0.45),
|
||||||
|
0 0 14px rgba(196, 168, 75, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Right content ───────────────────────────────────────────── */
|
||||||
|
|
||||||
.co-subpanel-content {
|
.co-subpanel-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
@@ -238,38 +265,44 @@ body {
|
|||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
padding: 0.625em 1em 0.5em;
|
padding:
|
||||||
|
0
|
||||||
|
calc(4px * var(--co-ui-scale))
|
||||||
|
calc(10px * var(--co-ui-scale));
|
||||||
|
border-bottom: 1px solid rgba(62, 207, 74, 0.15);
|
||||||
|
margin-bottom: calc(8px * var(--co-ui-scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-subpanel-title {
|
.co-subpanel-title {
|
||||||
font-size: var(--co-font-sm);
|
font-size: calc(15px * var(--co-ui-scale));
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.16em;
|
letter-spacing: 0.14em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--co-text-dim);
|
color: var(--co-text-pale);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-subpanel-meta {
|
.co-subpanel-meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.625em;
|
gap: 0.625em;
|
||||||
font-size: var(--co-font-xs);
|
font-size: calc(11px * var(--co-ui-scale));
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.12em;
|
letter-spacing: 0.12em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--co-text-dim);
|
color: var(--co-text-muted);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-subpanel-meta .co-count {
|
.co-subpanel-meta .co-count {
|
||||||
color: var(--co-green-soft);
|
color: var(--co-amber);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Preview — Load-menu thumbnail (favorites / recent only). */
|
/* ── Preview area ────────────────────────────────────────────── */
|
||||||
|
|
||||||
.co-preview-area {
|
.co-preview-area {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin: 0 0.75em 0.5em;
|
margin: 0 0 calc(8px * var(--co-ui-scale));
|
||||||
border: 0.0625em solid var(--co-green-dim);
|
border: 1px solid rgba(201, 168, 74, 0.22);
|
||||||
background: var(--co-bg-dark);
|
background: rgba(4, 10, 6, 0.55);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,8 +317,8 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: var(--co-text-dim);
|
color: var(--co-text-muted);
|
||||||
font-size: var(--co-font-sm);
|
font-size: calc(12px * var(--co-ui-scale));
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -298,37 +331,41 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.co-preview-caption {
|
.co-preview-caption {
|
||||||
padding: 0.375em 0.625em;
|
padding:
|
||||||
border-top: 0.0625em solid var(--co-green-dim);
|
calc(6px * var(--co-ui-scale))
|
||||||
font-size: var(--co-font-xs);
|
calc(10px * var(--co-ui-scale));
|
||||||
|
border-top: 1px solid rgba(201, 168, 74, 0.18);
|
||||||
|
font-size: calc(11px * var(--co-ui-scale));
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-preview-caption .co-preview-name {
|
.co-preview-caption .co-preview-name {
|
||||||
font-size: var(--co-font-sm);
|
font-size: calc(12px * var(--co-ui-scale));
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--co-green);
|
color: var(--co-text-pale);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-preview-caption .co-preview-stats {
|
.co-preview-caption .co-preview-stats {
|
||||||
color: var(--co-text-dim);
|
color: var(--co-text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Filters */
|
/* ── Filters ─────────────────────────────────────────────────── */
|
||||||
|
|
||||||
.co-filters {
|
.co-filters {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding: 0 0.75em 0.625em;
|
padding: 0 0 calc(10px * var(--co-ui-scale));
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.375em;
|
gap: calc(6px * var(--co-ui-scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-filters.focused .co-filter-row.focused .co-filter-input,
|
.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-filter-select,
|
||||||
.co-filters.focused .co-filter-row.focused .co-checkbox {
|
.co-filters.focused .co-filter-row.focused .co-checkbox,
|
||||||
outline: 0.0625em solid var(--co-green);
|
.co-filters.focused .co-filter-row.focused.co-btn {
|
||||||
|
outline: 1px solid rgba(62, 207, 74, 0.45);
|
||||||
outline-offset: 0;
|
outline-offset: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +373,7 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
gap: 0.375em 0.625em;
|
gap: calc(6px * var(--co-ui-scale)) calc(10px * var(--co-ui-scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-filters-row-selects .co-filter-row {
|
.co-filters-row-selects .co-filter-row {
|
||||||
@@ -351,7 +388,7 @@ body {
|
|||||||
.co-filter-row {
|
.co-filter-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.1875em;
|
gap: calc(3px * var(--co-ui-scale));
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,72 +399,76 @@ body {
|
|||||||
.co-filter-row.co-filter-checks {
|
.co-filter-row.co-filter-checks {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.3125em;
|
gap: calc(5px * var(--co-ui-scale));
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-filter-label {
|
.co-filter-label {
|
||||||
font-size: var(--co-font-xs);
|
font-size: calc(11px * var(--co-ui-scale));
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.12em;
|
letter-spacing: 0.12em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--co-text-dim);
|
color: var(--co-amber);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-filter-input,
|
.co-filter-input,
|
||||||
.co-filter-select {
|
.co-filter-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: var(--co-bg-dark);
|
background: rgba(4, 10, 6, 0.55);
|
||||||
border: 0.0625em solid var(--co-green-dim);
|
border: 1px solid rgba(201, 168, 74, 0.28);
|
||||||
color: var(--co-green);
|
color: var(--co-text-pale);
|
||||||
font: inherit;
|
font: inherit;
|
||||||
font-size: var(--co-font-sm);
|
font-size: calc(12px * var(--co-ui-scale));
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
padding: 0.3125em 0.5em;
|
padding:
|
||||||
|
calc(5px * var(--co-ui-scale))
|
||||||
|
calc(8px * var(--co-ui-scale));
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
cursor: var(--co-cursor);
|
cursor: var(--co-cursor);
|
||||||
transition: border-color var(--co-transition);
|
transition: border-color var(--co-transition), background var(--co-transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-filter-input::placeholder {
|
.co-filter-input::placeholder {
|
||||||
color: var(--co-text-dim);
|
color: var(--co-text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-filter-input:hover,
|
.co-filter-input:hover,
|
||||||
.co-filter-input.hovered,
|
.co-filter-input.hovered,
|
||||||
.co-filter-select:hover,
|
.co-filter-select:hover,
|
||||||
.co-filter-select.hovered {
|
.co-filter-select.hovered {
|
||||||
border-color: rgba(var(--co-r), var(--co-g), var(--co-b), 0.45);
|
border-color: rgba(201, 168, 74, 0.45);
|
||||||
|
background: rgba(8, 16, 10, 0.65);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-filter-input:focus,
|
.co-filter-input:focus,
|
||||||
.co-filter-select:focus {
|
.co-filter-select:focus {
|
||||||
border-color: var(--co-border);
|
border-color: rgba(201, 168, 74, 0.55);
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-checkbox-row {
|
.co-checkbox-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.3125em;
|
gap: calc(5px * var(--co-ui-scale));
|
||||||
font-size: var(--co-font-xs);
|
font-size: calc(11px * var(--co-ui-scale));
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.06em;
|
letter-spacing: 0.06em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
color: var(--co-text-muted);
|
||||||
cursor: var(--co-cursor);
|
cursor: var(--co-cursor);
|
||||||
transition: background var(--co-transition), border-color var(--co-transition);
|
transition: background var(--co-transition), color var(--co-transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-checkbox-row:hover,
|
.co-checkbox-row:hover,
|
||||||
.co-checkbox-row.hovered {
|
.co-checkbox-row.hovered {
|
||||||
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.06);
|
color: var(--co-text-pale);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-checkbox {
|
.co-checkbox {
|
||||||
width: calc(13px * var(--co-ui-scale));
|
width: calc(13px * var(--co-ui-scale));
|
||||||
height: calc(13px * var(--co-ui-scale));
|
height: calc(13px * var(--co-ui-scale));
|
||||||
border: 0.0625em solid var(--co-border);
|
border: 1px solid var(--co-amber-muted);
|
||||||
background: transparent;
|
background: rgba(0, 0, 0, 0.35);
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -438,39 +479,57 @@ body {
|
|||||||
content: "X";
|
content: "X";
|
||||||
font-size: calc(9px * var(--co-ui-scale));
|
font-size: calc(9px * var(--co-ui-scale));
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--co-green);
|
color: var(--co-amber);
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-btn {
|
.co-btn {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
border: 0.0625em solid var(--co-green-dim);
|
border: 1px solid rgba(201, 168, 74, 0.45);
|
||||||
background: transparent;
|
background: rgba(8, 16, 10, 0.65);
|
||||||
color: var(--co-green);
|
color: var(--co-text-pale);
|
||||||
font: inherit;
|
font: inherit;
|
||||||
font-size: var(--co-font-xs);
|
font-size: calc(11px * var(--co-ui-scale));
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
padding: 0.3125em 0.625em;
|
padding:
|
||||||
|
calc(6px * var(--co-ui-scale))
|
||||||
|
calc(10px * var(--co-ui-scale));
|
||||||
cursor: var(--co-cursor);
|
cursor: var(--co-cursor);
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
transition: background var(--co-transition), border-color var(--co-transition);
|
transition:
|
||||||
|
color var(--co-transition),
|
||||||
|
background var(--co-transition),
|
||||||
|
border-color var(--co-transition),
|
||||||
|
box-shadow var(--co-transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-btn:hover,
|
.co-btn:hover,
|
||||||
.co-btn.hovered {
|
.co-btn.hovered {
|
||||||
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.1);
|
color: var(--co-select-text);
|
||||||
border-color: rgba(var(--co-r), var(--co-g), var(--co-b), 0.45);
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
var(--co-select-yellow) 0%,
|
||||||
|
var(--co-select-yellow-bright) 100%
|
||||||
|
);
|
||||||
|
border-color: rgba(201, 168, 74, 0.7);
|
||||||
|
box-shadow: 0 0 14px rgba(196, 168, 75, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-btn.focused {
|
.co-btn.focused {
|
||||||
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.18);
|
color: var(--co-select-text);
|
||||||
outline: 0.0625em solid var(--co-green);
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
var(--co-select-yellow) 0%,
|
||||||
|
var(--co-select-yellow-bright) 100%
|
||||||
|
);
|
||||||
|
outline: 1px solid rgba(62, 207, 74, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Server list — save-file style rows */
|
/* ── Server list ─────────────────────────────────────────────── */
|
||||||
|
|
||||||
.co-server-list-wrap {
|
.co-server-list-wrap {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
@@ -480,15 +539,15 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.co-server-list-wrap.focused {
|
.co-server-list-wrap.focused {
|
||||||
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.03);
|
background: rgba(201, 168, 74, 0.03);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-server-list {
|
.co-server-list {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-color: var(--co-green-dim) transparent;
|
scrollbar-color: rgba(201, 168, 74, 0.35) transparent;
|
||||||
padding: 0 0.25em;
|
padding: calc(2px * var(--co-ui-scale)) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-server-list::-webkit-scrollbar {
|
.co-server-list::-webkit-scrollbar {
|
||||||
@@ -496,29 +555,70 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.co-server-list::-webkit-scrollbar-thumb {
|
.co-server-list::-webkit-scrollbar-thumb {
|
||||||
background: var(--co-green-dim);
|
background: rgba(201, 168, 74, 0.35);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-server-row {
|
.co-server-row {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
padding: 0.5em 0.75em;
|
min-height: calc(40px * var(--co-ui-scale));
|
||||||
font-size: var(--co-font-md);
|
padding:
|
||||||
|
calc(8px * var(--co-ui-scale))
|
||||||
|
calc(14px * var(--co-ui-scale));
|
||||||
|
font-size: calc(15px * var(--co-ui-scale));
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
|
color: var(--co-text-pale);
|
||||||
cursor: var(--co-cursor);
|
cursor: var(--co-cursor);
|
||||||
transition: background var(--co-transition), color var(--co-transition);
|
transition: color var(--co-transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-server-row:hover:not(.selected),
|
.co-server-row::before {
|
||||||
.co-server-row.hovered:not(.selected) {
|
content: "";
|
||||||
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.06);
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
var(--co-select-yellow) 0%,
|
||||||
|
var(--co-select-yellow-bright) 100%
|
||||||
|
);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity var(--co-transition);
|
||||||
|
z-index: 0;
|
||||||
|
box-shadow:
|
||||||
|
inset calc(3px * var(--co-ui-scale)) 0 0 0 var(--co-green),
|
||||||
|
0 0 12px rgba(196, 168, 75, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-server-row.selected {
|
.co-server-row:hover:not(.selected) {
|
||||||
background: var(--co-selected);
|
background: rgba(201, 168, 74, 0.08);
|
||||||
color: var(--co-selected-text);
|
}
|
||||||
|
|
||||||
|
.co-server-list-wrap.focused .co-server-row.selected::before {
|
||||||
|
box-shadow:
|
||||||
|
inset calc(3px * var(--co-ui-scale)) 0 0 0 var(--co-green),
|
||||||
|
0 0 0 1px rgba(62, 207, 74, 0.35),
|
||||||
|
0 0 14px rgba(196, 168, 75, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
|
.co-server-row.selected::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.co-server-row.selected,
|
||||||
|
.co-server-row.selected .co-server-row-name,
|
||||||
|
.co-server-row.selected .co-server-row-right,
|
||||||
|
.co-server-row.selected .co-fav,
|
||||||
|
.co-server-row.selected .co-ping {
|
||||||
|
color: var(--co-select-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.co-server-row-left,
|
||||||
|
.co-server-row-right {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-server-row-left {
|
.co-server-row-left {
|
||||||
@@ -530,10 +630,9 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.co-server-row-name {
|
.co-server-row-name {
|
||||||
font-size: var(--co-font-lg);
|
font-size: calc(16px * var(--co-ui-scale));
|
||||||
font-weight: 700;
|
font-weight: 600;
|
||||||
letter-spacing: 0.06em;
|
letter-spacing: 0.03em;
|
||||||
text-transform: uppercase;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -544,29 +643,24 @@ body {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1.25em;
|
gap: 1.25em;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
font-size: var(--co-font-md);
|
font-size: calc(14px * var(--co-ui-scale));
|
||||||
font-weight: 700;
|
font-weight: 600;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
}
|
color: var(--co-text-muted);
|
||||||
|
|
||||||
.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 {
|
.co-fav {
|
||||||
color: var(--co-text-dim);
|
color: var(--co-text-muted);
|
||||||
font-size: calc(15px * var(--co-ui-scale));
|
font-size: calc(15px * var(--co-ui-scale));
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-fav.on {
|
.co-fav.on {
|
||||||
color: var(--co-green);
|
color: var(--co-amber);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-server-row.selected .co-fav.on {
|
.co-server-row.selected .co-fav.on {
|
||||||
color: var(--co-selected-text);
|
color: var(--co-select-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-ping-good { color: var(--co-ping-good); }
|
.co-ping-good { color: var(--co-ping-good); }
|
||||||
@@ -576,35 +670,40 @@ body {
|
|||||||
.co-server-row.selected .co-ping-good,
|
.co-server-row.selected .co-ping-good,
|
||||||
.co-server-row.selected .co-ping-mid,
|
.co-server-row.selected .co-ping-mid,
|
||||||
.co-server-row.selected .co-ping-bad {
|
.co-server-row.selected .co-ping-bad {
|
||||||
color: var(--co-selected-text);
|
color: var(--co-select-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-scroll-indicator {
|
.co-scroll-indicator {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0.125em 0 0.25em;
|
padding: calc(2px * var(--co-ui-scale)) 0 calc(4px * var(--co-ui-scale));
|
||||||
font-size: var(--co-font-xs);
|
font-size: calc(11px * var(--co-ui-scale));
|
||||||
letter-spacing: 0.15em;
|
letter-spacing: 0.15em;
|
||||||
color: var(--co-text-dim);
|
color: var(--co-text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-scroll-indicator.hidden {
|
.co-scroll-indicator.hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Footer prompts */
|
/* ── Footer prompts (matches main-menu .prompt-bar) ─────────── */
|
||||||
|
|
||||||
.co-action-bar {
|
.co-action-bar {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding: 0.375em 0.875em 0.5em;
|
padding:
|
||||||
border-top: 0.0625em solid var(--co-green-dim);
|
calc(10px * var(--co-ui-scale))
|
||||||
|
calc(4px * var(--co-ui-scale))
|
||||||
|
0;
|
||||||
|
border-top: 1px solid rgba(201, 168, 74, 0.18);
|
||||||
|
margin-top: calc(6px * var(--co-ui-scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-prompts {
|
.co-prompts {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1em;
|
gap: calc(28px * var(--co-ui-scale));
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
@@ -612,81 +711,94 @@ body {
|
|||||||
.co-prompt {
|
.co-prompt {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.375em;
|
gap: calc(8px * var(--co-ui-scale));
|
||||||
font-size: var(--co-font-xs);
|
font-size: calc(11px * var(--co-ui-scale));
|
||||||
font-weight: 700;
|
font-weight: 600;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.16em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--co-green-soft);
|
color: var(--co-text-pale);
|
||||||
|
opacity: 0.85;
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-prompt-key {
|
.co-prompt-key {
|
||||||
min-width: calc(18px * var(--co-ui-scale));
|
display: inline-flex;
|
||||||
height: calc(18px * var(--co-ui-scale));
|
|
||||||
border: 0.0625em solid var(--co-border);
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: calc(8px * var(--co-ui-scale));
|
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;
|
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;
|
||||||
padding: 0 calc(3px * var(--co-ui-scale));
|
padding: 0 calc(3px * var(--co-ui-scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-prompt-key--glyph {
|
.co-prompt-key--glyph {
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 0;
|
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
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;
|
padding: 0;
|
||||||
flex-shrink: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-prompt-key--glyph .co-glyph-img {
|
.co-prompt-key--glyph .co-glyph-img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Direct connect ──────────────────────────────────────────── */
|
||||||
|
|
||||||
.co-direct-connect {
|
.co-direct-connect {
|
||||||
padding: 1em 1.25em;
|
padding:
|
||||||
|
calc(12px * var(--co-ui-scale))
|
||||||
|
calc(8px * var(--co-ui-scale));
|
||||||
max-width: calc(480px * var(--co-ui-scale));
|
max-width: calc(480px * var(--co-ui-scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-direct-row {
|
.co-direct-row {
|
||||||
margin-bottom: 0.75em;
|
margin-bottom: calc(12px * var(--co-ui-scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-direct-row.focused .co-filter-input {
|
.co-direct-row.focused .co-filter-input {
|
||||||
outline: 0.0625em solid var(--co-green);
|
outline: 1px solid rgba(62, 207, 74, 0.45);
|
||||||
background: rgba(var(--co-r), var(--co-g), var(--co-b), 0.08);
|
background: rgba(8, 16, 10, 0.65);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-direct-row label {
|
.co-direct-row label {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: var(--co-font-xs);
|
font-size: calc(11px * var(--co-ui-scale));
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.1em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: var(--co-text-dim);
|
color: var(--co-amber);
|
||||||
margin-bottom: 0.25em;
|
margin-bottom: calc(4px * var(--co-ui-scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-empty {
|
.co-empty {
|
||||||
padding: 1.5em 1em;
|
padding:
|
||||||
|
calc(24px * var(--co-ui-scale))
|
||||||
|
calc(16px * var(--co-ui-scale));
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: var(--co-text-dim);
|
color: var(--co-text-muted);
|
||||||
font-size: var(--co-font-md);
|
font-size: calc(14px * var(--co-ui-scale));
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.06em;
|
||||||
text-transform: uppercase;
|
line-height: 1.45;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Join overlay ────────────────────────────────────────────── */
|
||||||
|
|
||||||
.co-join-overlay {
|
.co-join-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
background: rgba(0, 0, 0, 0.75);
|
background: rgba(4, 8, 6, 0.88);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -700,10 +812,11 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.co-join-overlay p {
|
.co-join-overlay p {
|
||||||
font-size: var(--co-font-md);
|
font-size: calc(15px * var(--co-ui-scale));
|
||||||
letter-spacing: 0.1em;
|
letter-spacing: 0.08em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin-top: 0.875em;
|
margin-top: calc(14px * var(--co-ui-scale));
|
||||||
|
color: var(--co-text-pale);
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-join-overlay.co-error p {
|
.co-join-overlay.co-error p {
|
||||||
@@ -713,8 +826,8 @@ body {
|
|||||||
.co-spinner {
|
.co-spinner {
|
||||||
width: calc(22px * var(--co-ui-scale));
|
width: calc(22px * var(--co-ui-scale));
|
||||||
height: 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: calc(2px * var(--co-ui-scale)) solid rgba(201, 168, 74, 0.35);
|
||||||
border-top-color: var(--co-green);
|
border-top-color: var(--co-amber);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
animation: co-spin 0.8s linear infinite;
|
animation: co-spin 0.8s linear infinite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -472,6 +472,39 @@
|
|||||||
exitBrowserMode(true);
|
exitBrowserMode(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.onMainMenuShown = function () {
|
||||||
|
if (mainScreen) {
|
||||||
|
mainScreen.classList.remove("is-session-loading");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onSessionLoading = function () {
|
||||||
|
if (viewMode === "browser") {
|
||||||
|
cancelBrowserPanelHide();
|
||||||
|
browserController.hide();
|
||||||
|
browserPanel.classList.remove("is-open");
|
||||||
|
browserPanel.hidden = true;
|
||||||
|
} else if (viewMode === "settings") {
|
||||||
|
cancelSettingsPanelHide();
|
||||||
|
settingsController.hide();
|
||||||
|
settingsPanel.classList.remove("is-open");
|
||||||
|
settingsPanel.hidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
viewMode = "menu";
|
||||||
|
if (mainScreen) {
|
||||||
|
mainScreen.classList.remove("is-browser-mode", "is-settings-mode");
|
||||||
|
mainScreen.classList.add("is-session-loading");
|
||||||
|
}
|
||||||
|
if (mainPromptBar) {
|
||||||
|
mainPromptBar.hidden = true;
|
||||||
|
}
|
||||||
|
if (settingsPromptBar) {
|
||||||
|
settingsPromptBar.hidden = true;
|
||||||
|
}
|
||||||
|
setSelected(-1);
|
||||||
|
};
|
||||||
|
|
||||||
function enterSettingsMode() {
|
function enterSettingsMode() {
|
||||||
if (viewMode === "browser") {
|
if (viewMode === "browser") {
|
||||||
cancelBrowserPanelHide();
|
cancelBrowserPanelHide();
|
||||||
|
|||||||
@@ -62,6 +62,12 @@ body {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main-screen.is-session-loading {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Title-screen scenic background ──────────────────────────── */
|
/* ── Title-screen scenic background ──────────────────────────── */
|
||||||
|
|
||||||
.scene-layer {
|
.scene-layer {
|
||||||
|
|||||||
Reference in New Issue
Block a user