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.
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
@@ -8,18 +8,18 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="pause-screen" id="pauseScreen">
|
||||
<!-- Map background -->
|
||||
<div class="map-layer" aria-hidden="true"></div>
|
||||
<div class="map-overlay" aria-hidden="true"></div>
|
||||
|
||||
<!-- Subtle multiplayer markers on the map -->
|
||||
<div class="map-markers" aria-hidden="true">
|
||||
<span class="marker marker--player" style="left: 58%; top: 42%;"></span>
|
||||
<span class="marker marker--ally" style="left: 64%; top: 38%;"></span>
|
||||
<span class="marker marker--ally" style="left: 52%; top: 48%;"></span>
|
||||
<span class="marker marker--ally" style="left: 71%; top: 55%;"></span>
|
||||
<span class="marker marker--ally" style="left: 45%; top: 36%;"></span>
|
||||
<!-- Map + markers share one filter so blur/unblur stays in lockstep -->
|
||||
<div class="map-world" id="mapWorld" aria-hidden="true">
|
||||
<div class="map-layer"></div>
|
||||
<div class="map-markers">
|
||||
<span class="marker marker--player" style="left: 58%; top: 42%;"></span>
|
||||
<span class="marker marker--ally" style="left: 64%; top: 38%;"></span>
|
||||
<span class="marker marker--ally" style="left: 52%; top: 48%;"></span>
|
||||
<span class="marker marker--ally" style="left: 71%; top: 55%;"></span>
|
||||
<span class="marker marker--ally" style="left: 45%; top: 36%;"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="map-overlay" aria-hidden="true"></div>
|
||||
|
||||
<!-- CRT / HUD texture overlays -->
|
||||
<div class="screen-effects" aria-hidden="true"></div>
|
||||
@@ -85,22 +85,52 @@
|
||||
<p class="server-panel__players">12 / 24</p>
|
||||
</section>
|
||||
|
||||
<!-- Bottom controller prompts -->
|
||||
<footer class="prompt-bar" aria-label="Controller prompts">
|
||||
<!-- Bottom controller prompts (pause menu) -->
|
||||
<footer class="prompt-bar" id="pausePromptBar" aria-label="Controller prompts">
|
||||
<div class="prompt">
|
||||
<span class="prompt__glyph" aria-hidden="true">☰</span>
|
||||
<span class="prompt__label">MOVE</span>
|
||||
</div>
|
||||
<div class="prompt">
|
||||
<span class="prompt__glyph prompt__glyph--rs" aria-hidden="true">RS</span>
|
||||
<span class="prompt__label">ZOOM</span>
|
||||
</div>
|
||||
<div class="prompt">
|
||||
<span class="prompt__glyph prompt__glyph--round" aria-hidden="true">A</span>
|
||||
<span class="prompt__glyph prompt__glyph--icon" aria-hidden="true">
|
||||
<img class="prompt__glyph-img" data-glyph-src="./assets/icons/Xbox/T_X_A_White_Alt.png" src="./assets/icons/Xbox/T_X_A_White_Alt.png" alt="" draggable="false">
|
||||
</span>
|
||||
<span class="prompt__label">SELECT</span>
|
||||
</div>
|
||||
<div class="prompt">
|
||||
<span class="prompt__glyph prompt__glyph--round" aria-hidden="true">B</span>
|
||||
<span class="prompt__glyph prompt__glyph--icon" aria-hidden="true">
|
||||
<img class="prompt__glyph-img" data-glyph-src="./assets/icons/Xbox/T_X_B_White_Alt.png" src="./assets/icons/Xbox/T_X_B_White_Alt.png" alt="" draggable="false">
|
||||
</span>
|
||||
<span class="prompt__label">BACK</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- PC back button (map mode only) -->
|
||||
<button type="button" class="map-pc-back" id="mapBackButton" aria-hidden="true">
|
||||
<span class="map-pc-back__key" aria-hidden="true">ESC</span>
|
||||
<span class="map-pc-back__label">BACK</span>
|
||||
</button>
|
||||
|
||||
<!-- Map mode prompt bar (controller: LS MOVE / RS ZOOM / A SELECT / B BACK) -->
|
||||
<footer class="prompt-bar prompt-bar--map-mode" id="mapPromptBar" aria-label="Map mode prompts" hidden>
|
||||
<div class="prompt">
|
||||
<span class="prompt__glyph prompt__glyph--icon prompt__glyph--icon-stick" aria-hidden="true">
|
||||
<img class="prompt__glyph-img" data-glyph-src="./assets/icons/Xbox/T_X_L_2D_Alt.png" src="./assets/icons/Xbox/T_X_L_2D_Alt.png" alt="" draggable="false">
|
||||
</span>
|
||||
<span class="prompt__label">MOVE</span>
|
||||
</div>
|
||||
<div class="prompt">
|
||||
<span class="prompt__glyph prompt__glyph--icon prompt__glyph--icon-stick" aria-hidden="true">
|
||||
<img class="prompt__glyph-img" data-glyph-src="./assets/icons/Xbox/T_X_R_Y_Alt.png" src="./assets/icons/Xbox/T_X_R_Y_Alt.png" alt="" draggable="false">
|
||||
</span>
|
||||
<span class="prompt__label">ZOOM</span>
|
||||
</div>
|
||||
<div class="prompt">
|
||||
<span class="prompt__glyph prompt__glyph--icon" aria-hidden="true">
|
||||
<img class="prompt__glyph-img" data-glyph-src="./assets/icons/Xbox/T_X_A_White_Alt.png" src="./assets/icons/Xbox/T_X_A_White_Alt.png" alt="" draggable="false">
|
||||
</span>
|
||||
<span class="prompt__label">SELECT</span>
|
||||
</div>
|
||||
<div class="prompt">
|
||||
<span class="prompt__glyph prompt__glyph--icon" aria-hidden="true">
|
||||
<img class="prompt__glyph-img" data-glyph-src="./assets/icons/Xbox/T_X_B_White_Alt.png" src="./assets/icons/Xbox/T_X_B_White_Alt.png" alt="" draggable="false">
|
||||
</span>
|
||||
<span class="prompt__label">BACK</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -21,6 +21,120 @@
|
||||
updateScale();
|
||||
window.addEventListener("resize", updateScale);
|
||||
|
||||
// ── Tint Xbox prompt glyphs to pause-menu amber (same approach as browser) ──
|
||||
// White pixels become --co-amber; black stays black; transparent stays transparent.
|
||||
var GLYPH_WHITE_THRESHOLD = 200;
|
||||
var GLYPH_BLACK_THRESHOLD = 40;
|
||||
var glyphTintCache = {};
|
||||
|
||||
function getAmberTint() {
|
||||
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 {
|
||||
r: parseInt(hex.slice(0, 2), 16) || 201,
|
||||
g: parseInt(hex.slice(2, 4), 16) || 168,
|
||||
b: parseInt(hex.slice(4, 6), 16) || 74
|
||||
};
|
||||
}
|
||||
|
||||
function classifyGlyphPixel(r, g, b) {
|
||||
if (r >= GLYPH_WHITE_THRESHOLD && g >= GLYPH_WHITE_THRESHOLD && b >= GLYPH_WHITE_THRESHOLD) {
|
||||
return "white";
|
||||
}
|
||||
if (r <= GLYPH_BLACK_THRESHOLD && g <= GLYPH_BLACK_THRESHOLD && b <= GLYPH_BLACK_THRESHOLD) {
|
||||
return "black";
|
||||
}
|
||||
return "edge";
|
||||
}
|
||||
|
||||
function tintGlyphImageData(imageData, color) {
|
||||
var data = imageData.data;
|
||||
for (var i = 0; i < data.length; i += 4) {
|
||||
if (data[i + 3] < 4) {
|
||||
data[i + 3] = 0;
|
||||
continue;
|
||||
}
|
||||
var kind = classifyGlyphPixel(data[i], data[i + 1], data[i + 2]);
|
||||
if (kind === "white") {
|
||||
data[i] = color.r;
|
||||
data[i + 1] = color.g;
|
||||
data[i + 2] = color.b;
|
||||
} else if (kind === "black") {
|
||||
data[i] = 0;
|
||||
data[i + 1] = 0;
|
||||
data[i + 2] = 0;
|
||||
} else {
|
||||
var lum = (data[i] + data[i + 1] + data[i + 2]) / (3 * 255);
|
||||
data[i] = Math.round(lum * color.r);
|
||||
data[i + 1] = Math.round(lum * color.g);
|
||||
data[i + 2] = Math.round(lum * color.b);
|
||||
}
|
||||
}
|
||||
return imageData;
|
||||
}
|
||||
|
||||
function tintGlyphImage(url, color, done) {
|
||||
var key = url + "|" + color.r + "," + color.g + "," + color.b;
|
||||
if (glyphTintCache[key]) {
|
||||
done(glyphTintCache[key]);
|
||||
return;
|
||||
}
|
||||
var img = new Image();
|
||||
img.onload = function () {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = img.naturalWidth;
|
||||
canvas.height = img.naturalHeight;
|
||||
var ctx = canvas.getContext("2d");
|
||||
if (!ctx) {
|
||||
done(null);
|
||||
return;
|
||||
}
|
||||
ctx.drawImage(img, 0, 0);
|
||||
try {
|
||||
ctx.putImageData(
|
||||
tintGlyphImageData(ctx.getImageData(0, 0, canvas.width, canvas.height), color),
|
||||
0,
|
||||
0
|
||||
);
|
||||
} catch (err) {
|
||||
// file:// or cross-origin can taint the canvas; keep the original white glyph.
|
||||
done(null);
|
||||
return;
|
||||
}
|
||||
var dataUrl = canvas.toDataURL("image/png");
|
||||
glyphTintCache[key] = dataUrl;
|
||||
done(dataUrl);
|
||||
};
|
||||
img.onerror = function () {
|
||||
done(null);
|
||||
};
|
||||
img.src = url;
|
||||
}
|
||||
|
||||
function hydratePromptGlyphs() {
|
||||
var color = getAmberTint();
|
||||
var imgs = document.querySelectorAll(".prompt__glyph-img[data-glyph-src]");
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
(function (img) {
|
||||
var src = img.getAttribute("data-glyph-src");
|
||||
if (!src) {
|
||||
return;
|
||||
}
|
||||
tintGlyphImage(src, color, function (dataUrl) {
|
||||
if (dataUrl) {
|
||||
img.src = dataUrl;
|
||||
}
|
||||
});
|
||||
})(imgs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
hydratePromptGlyphs();
|
||||
|
||||
var menu = document.getElementById("menu");
|
||||
if (!menu) {
|
||||
return;
|
||||
@@ -30,11 +144,11 @@
|
||||
var selectedIndex = -1; // No default selection
|
||||
|
||||
function setSelected(index) {
|
||||
if (index < 0 || index >= items.length) {
|
||||
if (index >= items.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
selectedIndex = index;
|
||||
selectedIndex = index < 0 ? -1 : index;
|
||||
|
||||
items.forEach(function (item, i) {
|
||||
var isSelected = i === selectedIndex;
|
||||
@@ -55,8 +169,12 @@
|
||||
|
||||
if (action === "resume") {
|
||||
console.log("[CO Pause Menu] Resume game (concept)");
|
||||
setSelected(-1);
|
||||
} else if (action === "map") {
|
||||
enterMapMode();
|
||||
} else if (action === "quit") {
|
||||
console.log("[CO Pause Menu] Quit to main menu (concept)");
|
||||
setSelected(-1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +212,7 @@
|
||||
break;
|
||||
case "Escape":
|
||||
event.preventDefault();
|
||||
console.log("[CO Pause Menu] Back / close pause menu (concept)");
|
||||
exitMapMode();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -105,13 +223,88 @@
|
||||
setSelected(selectedIndex);
|
||||
}
|
||||
|
||||
// ── Map mode state management ───────────────────────────────────
|
||||
var isMapMode = false;
|
||||
|
||||
function enterMapMode() {
|
||||
isMapMode = true;
|
||||
console.log("[CO Pause Menu] Entering map mode");
|
||||
|
||||
var leftPanel = document.querySelector(".left-panel");
|
||||
var mapWorld = document.getElementById("mapWorld");
|
||||
var pausePromptBar = document.getElementById("pausePromptBar");
|
||||
var mapPromptBar = document.getElementById("mapPromptBar");
|
||||
var mapBackButton = document.getElementById("mapBackButton");
|
||||
var serverPanel = document.querySelector(".server-panel");
|
||||
|
||||
setSelected(-1);
|
||||
if (leftPanel) leftPanel.classList.add("is-hidden");
|
||||
if (serverPanel) serverPanel.style.display = "none";
|
||||
if (mapWorld) {
|
||||
mapWorld.classList.remove("is-blurred");
|
||||
mapWorld.classList.add("is-interactive");
|
||||
}
|
||||
if (pausePromptBar) pausePromptBar.hidden = true;
|
||||
if (mapPromptBar) mapPromptBar.hidden = false;
|
||||
if (mapBackButton) {
|
||||
mapBackButton.classList.add("is-visible");
|
||||
mapBackButton.setAttribute("aria-hidden", "false");
|
||||
}
|
||||
}
|
||||
|
||||
function exitMapMode() {
|
||||
if (!isMapMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
isMapMode = false;
|
||||
console.log("[CO Pause Menu] Exiting map mode");
|
||||
|
||||
var leftPanel = document.querySelector(".left-panel");
|
||||
var mapWorld = document.getElementById("mapWorld");
|
||||
var pausePromptBar = document.getElementById("pausePromptBar");
|
||||
var mapPromptBar = document.getElementById("mapPromptBar");
|
||||
var mapBackButton = document.getElementById("mapBackButton");
|
||||
var serverPanel = document.querySelector(".server-panel");
|
||||
|
||||
if (mapBackButton) {
|
||||
mapBackButton.classList.remove("is-visible");
|
||||
mapBackButton.setAttribute("aria-hidden", "true");
|
||||
}
|
||||
if (leftPanel) leftPanel.classList.remove("is-hidden");
|
||||
if (serverPanel) serverPanel.style.display = "block";
|
||||
if (mapWorld) {
|
||||
mapWorld.classList.add("is-blurred");
|
||||
mapWorld.classList.remove("is-interactive");
|
||||
}
|
||||
if (pausePromptBar) pausePromptBar.hidden = false;
|
||||
if (mapPromptBar) mapPromptBar.hidden = true;
|
||||
|
||||
setSelected(-1);
|
||||
}
|
||||
|
||||
// ── Blur map initially ────────────────────────────────────────
|
||||
var initialMapWorld = document.getElementById("mapWorld");
|
||||
if (initialMapWorld) {
|
||||
initialMapWorld.classList.add("is-blurred");
|
||||
}
|
||||
|
||||
// ── Map mode PC back button handler ───────────────────────────
|
||||
var mapBackButton = document.getElementById("mapBackButton");
|
||||
if (mapBackButton) {
|
||||
mapBackButton.addEventListener("click", function (event) {
|
||||
event.stopPropagation();
|
||||
exitMapMode();
|
||||
});
|
||||
}
|
||||
|
||||
// ── Map pan/zoom (concept preview of future Fallout 76-style navigation) ──
|
||||
// Scroll to zoom, click-drag to pan once zoomed in. Real implementation
|
||||
// will eventually read controller right-stick input via F4SE instead.
|
||||
var pauseScreen = document.getElementById("pauseScreen");
|
||||
var mapLayer = document.querySelector(".map-layer");
|
||||
var mapWorld = document.getElementById("mapWorld");
|
||||
|
||||
if (pauseScreen && mapLayer) {
|
||||
if (pauseScreen && mapWorld) {
|
||||
var MAX_ZOOM = 4;
|
||||
var ZOOM_STEP = 0.18;
|
||||
var zoom = 1;
|
||||
@@ -201,7 +394,7 @@
|
||||
panY = Math.max(-maxPanY, Math.min(maxPanY, panY));
|
||||
}
|
||||
|
||||
mapLayer.addEventListener(
|
||||
mapWorld.addEventListener(
|
||||
"wheel",
|
||||
function (event) {
|
||||
event.preventDefault();
|
||||
@@ -218,7 +411,7 @@
|
||||
{ passive: false }
|
||||
);
|
||||
|
||||
mapLayer.addEventListener("mousedown", function (event) {
|
||||
mapWorld.addEventListener("mousedown", function (event) {
|
||||
if (zoom <= MIN_ZOOM) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,12 +69,37 @@ body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ── Map layers ──────────────────────────────────────────────── */
|
||||
/* ── 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;
|
||||
z-index: 1;
|
||||
/*
|
||||
* "contain" keeps the whole regional map visible (Fallout 76-style full
|
||||
* overview) instead of "cover" cropping it down to a tight, zoomed-in
|
||||
@@ -84,12 +109,6 @@ body {
|
||||
background:
|
||||
url("assets/map.png") center center / contain no-repeat;
|
||||
background-color: #0b100c;
|
||||
filter: brightness(0.74) contrast(1.04) saturate(0.55);
|
||||
transform: translate(var(--map-pan-x, 0px), var(--map-pan-y, 0px))
|
||||
scale(var(--map-zoom, 1));
|
||||
transform-origin: center center;
|
||||
transition: transform 160ms ease-out;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.map-overlay {
|
||||
@@ -109,24 +128,12 @@ body {
|
||||
}
|
||||
|
||||
/* ── Map markers ───────────────────────────────────────────── */
|
||||
/* Shares the same pan/zoom transform (inherited custom properties) as
|
||||
.map-layer so markers stay pinned to their map position while navigating. */
|
||||
/* Inside .map-world so they share the same filter and transform as the map. */
|
||||
|
||||
.map-markers {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 3;
|
||||
pointer-events: none;
|
||||
transform: translate(var(--map-pan-x, 0px), var(--map-pan-y, 0px))
|
||||
scale(var(--map-zoom, 1));
|
||||
transform-origin: center center;
|
||||
transition: transform 160ms ease-out;
|
||||
}
|
||||
|
||||
.pause-screen.is-panning .map-layer,
|
||||
.pause-screen.is-panning .map-markers {
|
||||
transition: none;
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.marker {
|
||||
@@ -243,6 +250,12 @@ body {
|
||||
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 {
|
||||
@@ -321,11 +334,11 @@ body {
|
||||
box-shadow: 0 0 12px rgba(196, 168, 75, 0.25);
|
||||
}
|
||||
|
||||
.menu-item:hover:not(.is-selected) {
|
||||
.menu-item:hover {
|
||||
color: var(--co-text-pale);
|
||||
}
|
||||
|
||||
.menu-item:hover:not(.is-selected) .menu-item__bar {
|
||||
.menu-item:hover .menu-item__bar {
|
||||
opacity: 1;
|
||||
transform: translateY(-50%) scaleX(1);
|
||||
}
|
||||
@@ -431,6 +444,16 @@ body {
|
||||
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 {
|
||||
@@ -454,15 +477,30 @@ body {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.prompt__glyph--rs {
|
||||
border-radius: 4px;
|
||||
font-size: calc(9px * var(--co-ui-scale));
|
||||
letter-spacing: 0.02em;
|
||||
min-width: calc(26px * var(--co-ui-scale));
|
||||
/* 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;
|
||||
}
|
||||
|
||||
.prompt__glyph--round {
|
||||
font-size: calc(10px * var(--co-ui-scale));
|
||||
/* 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 {
|
||||
@@ -473,6 +511,96 @@ body {
|
||||
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
|
||||
|
||||