Persistent sidebar, nav & flat theme overhaul

Introduce a persistent left sidebar, update navigation to support regions, and convert the UI to a flat/no-blur visual style.

Key changes:
- index.html: add a persistent sidebar markup with nav items, user area and main app layout.
- src/core/nav.js: improve candidate scoring to use element bounding centers and overlap penalty; include extra focus roots; add region metadata handling, helpers for resolving default content/sidebar indices, and special-case movements between sidebar and content; respect contract.useNebulaNavigation flag.
- src/main.js: manage sidebar visibility for full-screen flows (lock/onboarding), update sidebar active state on view changes, include sidebar as an extraFocusRoot when appropriate, and handle sidebar item activation on accept to navigate views.
- src/styles/*: major visual/theme updates to remove blur/glow effects (Zero-Blur policy), add flat sidebar styles, update components to solid borders and simpler focus styling, adjust theme variables (palette, spacing, durations), and redesign the home view layout and controls.

Rationale: provide a persistent, keyboard/controller-friendly sidebar for quick navigation while simplifying visuals to a flat, performance-friendly theme and refining focus/navigation behavior across sidebar and content regions.
This commit is contained in:
2026-05-15 23:13:31 +12:00
parent 5261a82115
commit 38be2f43f1
8 changed files with 1302 additions and 454 deletions
+512 -70
View File
@@ -1,90 +1,532 @@
/* ════════════════════════════════════════════════════════
HOME VIEW — Sci-fi dashboard layout
════════════════════════════════════════════════════════ */
.home-view {
justify-content: flex-start;
gap: var(--nebula-spacing-xl);
display: flex;
flex-direction: column;
height: 100%;
padding: 0;
gap: 0;
overflow: hidden;
}
/* ── Top status bar ──────────────────────────────────── */
.home-topbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 24px 12px;
flex-shrink: 0;
border-bottom: 1px solid var(--nebula-color-border);
}
.home-time {
font-size: clamp(36px, 4vw, 52px);
font-weight: 800;
letter-spacing: -0.03em;
color: var(--nebula-color-text);
line-height: 1;
}
.home-status-icons {
display: flex;
align-items: center;
gap: 14px;
color: var(--nebula-color-muted);
}
.home-status-icon {
display: flex;
align-items: center;
justify-content: center;
}
/* ── Body: two columns ────────────────────────────────── */
.home-body {
flex: 1;
display: grid;
grid-template-columns: 1fr 310px;
gap: 16px;
padding: 14px 20px 0;
min-height: 0;
overflow: hidden;
}
/* ── Center column ───────────────────────────────────── */
.home-center {
display: flex;
flex-direction: column;
gap: 12px;
min-height: 0;
overflow: hidden;
}
/* ── Category tabs ───────────────────────────────────── */
.home-tabs {
display: flex;
align-items: center;
gap: 20px;
flex-shrink: 0;
border-bottom: 1px solid var(--nebula-color-border);
padding-bottom: 10px;
}
.home-tab {
background: none;
color: var(--nebula-color-muted);
font-size: 16px;
font-weight: 700;
padding: 0 2px 8px;
border: none;
border-bottom: 2px solid transparent;
border-radius: 0;
cursor: pointer;
transition:
color var(--nebula-duration-fast) var(--nebula-ease-standard),
border-bottom-color var(--nebula-duration-fast) var(--nebula-ease-standard);
transform: none;
}
.home-tab.is-active {
color: var(--nebula-color-text);
border-bottom-color: var(--nebula-color-accent);
}
.home-tab.is-focused {
color: var(--nebula-color-accent);
border-bottom-color: var(--nebula-color-accent);
transform: none;
border-radius: 0;
}
.tab-hint {
margin-left: auto;
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 13px;
color: var(--nebula-color-muted);
}
/* ── Hero card ───────────────────────────────────────── */
.hero-card {
flex: 1;
position: relative;
border-radius: var(--nebula-radius-lg);
overflow: hidden;
min-height: 0;
border: 2px solid var(--nebula-color-border);
transition: border-color var(--nebula-duration-nav) var(--nebula-ease-console);
transform: none;
}
.hero-card.is-focused {
border-color: var(--nebula-color-accent);
transform: none;
}
/* Game art layers */
.hero-art {
position: absolute;
inset: 0;
overflow: hidden;
}
.hero-art-bg {
position: absolute;
inset: 0;
background:
linear-gradient(165deg,
#0d0e00 0%,
#1a1600 20%,
#2a2200 40%,
#3a3000 60%,
rgba(180, 150, 0, 0.25) 80%,
rgba(220, 180, 0, 0.15) 100%
);
}
.hero-art-mid {
position: absolute;
inset: 0;
background:
radial-gradient(ellipse at 65% 50%, rgba(255, 200, 0, 0.18) 0%, transparent 55%),
radial-gradient(ellipse at 30% 80%, rgba(0, 80, 180, 0.2) 0%, transparent 45%);
}
/* Stylised "character" area */
.hero-art-character {
position: absolute;
bottom: 0;
right: 10%;
width: 42%;
height: 90%;
background:
linear-gradient(180deg,
transparent 0%,
rgba(60, 50, 0, 0.4) 30%,
rgba(100, 90, 0, 0.6) 60%,
rgba(30, 25, 0, 0.9) 100%
);
clip-path: polygon(15% 0%, 85% 0%, 100% 100%, 0% 100%);
}
.hero-title-watermark {
position: absolute;
bottom: 110px;
right: 5%;
font-size: clamp(32px, 5vw, 64px);
font-weight: 900;
color: rgba(255, 220, 0, 0.85);
letter-spacing: -0.03em;
line-height: 0.95;
text-align: right;
text-transform: uppercase;
pointer-events: none;
font-style: italic;
}
/* Controller overlay */
.hero-ctrl-overlay {
position: absolute;
top: 20px;
left: 20px;
display: flex;
gap: 14px;
align-items: center;
opacity: 0.55;
}
.ctrl-glyph {
display: block;
}
.hero-l-badge {
width: 22px;
height: 22px;
border-radius: var(--nebula-radius-sm);
background: rgba(255, 255, 255, 0.15);
border: 1px solid rgba(255, 255, 255, 0.25);
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 800;
color: rgba(255, 255, 255, 0.7);
}
/* Gradient overlay + info */
.hero-overlay {
position: absolute;
inset: 0;
background: linear-gradient(
to top,
rgba(7, 10, 20, 0.98) 0%,
rgba(7, 10, 20, 0.7) 36%,
transparent 65%
);
display: flex;
flex-direction: column;
justify-content: flex-end;
padding: 20px 24px;
}
.hero-info {
display: flex;
flex-direction: column;
gap: 14px;
}
.hero-game-title {
margin: 0;
font-size: clamp(26px, 3.2vw, 42px);
font-weight: 800;
letter-spacing: -0.02em;
color: #fff;
line-height: 1.1;
}
.hero-actions {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.hero-btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 9px 18px;
border-radius: var(--nebula-radius-sm);
font-size: 14px;
font-weight: 700;
cursor: pointer;
background: rgba(255, 255, 255, 0.08);
border: 1.5px solid rgba(255, 255, 255, 0.2);
color: #fff;
transition:
background var(--nebula-duration-fast) var(--nebula-ease-standard),
border-color var(--nebula-duration-fast) var(--nebula-ease-standard),
transform var(--nebula-duration-fast) var(--nebula-ease-console);
transform: none;
}
.hero-btn-primary {
background: var(--nebula-color-accent);
border-color: transparent;
color: #070a14;
}
.hero-btn.is-focused {
border-color: var(--nebula-color-accent);
transform: translateY(-1px);
}
.hero-btn-primary.is-focused {
border-color: #fff;
transform: translateY(-1px);
}
.hero-dots {
display: flex;
align-items: center;
gap: 6px;
margin-top: 10px;
}
.hero-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.28);
transition: all var(--nebula-duration-fast) var(--nebula-ease-standard);
}
.hero-dot.is-active {
width: 22px;
border-radius: 3px;
background: var(--nebula-color-accent);
}
/* ── Featured strip ──────────────────────────────────── */
.featured-strip {
flex-shrink: 0;
padding-bottom: 12px;
}
.section-label {
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--nebula-color-muted);
margin: 0 0 10px;
}
.featured-row {
display: flex;
gap: 10px;
}
.featured-thumb {
flex: 1;
height: 68px;
border-radius: var(--nebula-radius-md);
background: linear-gradient(135deg, var(--thumb-a, #1a1a2e), var(--thumb-b, #2a1050));
border: 2px solid var(--nebula-color-border);
cursor: pointer;
transition: border-color var(--nebula-duration-fast);
overflow: hidden;
padding: 0;
}
.featured-thumb.is-focused {
border-color: var(--nebula-color-accent);
transform: translateY(-2px);
}
/* ── Right panel ─────────────────────────────────────── */
.home-right-panel {
display: flex;
flex-direction: column;
gap: 12px;
overflow: hidden;
min-height: 0;
padding-bottom: 12px;
}
.panel-header-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
.panel-heading {
font-size: 15px;
font-weight: 700;
color: var(--nebula-color-text);
margin: 0;
text-transform: uppercase;
letter-spacing: 0.06em;
}
.panel-heading-sm {
font-size: 13px;
font-weight: 700;
color: var(--nebula-color-text);
margin: 0 0 8px;
text-transform: uppercase;
letter-spacing: 0.06em;
}
/* ── Quick launch grid ───────────────────────────────── */
.quick-launch {
flex-shrink: 0;
}
.quick-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
.quick-tile {
position: relative;
border-radius: var(--nebula-radius-md);
overflow: hidden;
background: var(--nebula-color-panel);
border: 2px solid var(--nebula-color-border);
cursor: pointer;
padding: 0;
text-align: left;
color: var(--nebula-color-text);
transition:
border-color var(--nebula-duration-fast) var(--nebula-ease-console),
transform var(--nebula-duration-fast) var(--nebula-ease-console);
transform: translateZ(0);
}
.quick-tile.is-focused {
border-color: var(--nebula-color-accent);
transform: scale(1.04) translateZ(0);
}
.quick-tile-art {
height: 70px;
background: linear-gradient(135deg, var(--ta, #1a1a2e), var(--tb, #2a2050));
position: relative;
overflow: hidden;
}
.tile-badge {
position: absolute;
bottom: 4px;
right: 4px;
font-size: 12px;
line-height: 1;
}
.quick-tile-footer {
padding: 6px 8px 7px;
}
.quick-tile-name {
margin: 0;
font-size: 11px;
font-weight: 700;
color: var(--nebula-color-text);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.3;
}
.quick-tile-meta {
margin: 3px 0 0;
font-size: 10px;
color: var(--nebula-color-muted);
line-height: 1.3;
}
/* Solid progress bar */
.quick-tile-bar {
position: relative;
padding-left: 0;
}
.home-hero {
.quick-tile-bar::before {
content: "";
display: block;
height: 2px;
background: var(--nebula-color-border);
border-radius: 1px;
margin-bottom: 3px;
}
.quick-tile-bar::after {
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
width: var(--pct, 0%);
height: 2px;
background: var(--nebula-color-accent);
border-radius: 1px;
}
/* ── Bottom side panels ──────────────────────────────── */
.side-bottom-panels {
display: grid;
gap: var(--nebula-spacing-xs);
padding-left: var(--nebula-spacing-xl);
grid-template-columns: 1fr 1fr;
gap: 10px;
flex-shrink: 0;
}
.home-hero .muted {
margin: 0;
text-transform: uppercase;
letter-spacing: 0.14em;
font-size: 14px;
font-weight: 600;
opacity: 0.72;
.friends-panel,
.activity-panel {
background: var(--nebula-color-panel);
border: 1px solid var(--nebula-color-border);
border-radius: var(--nebula-radius-md);
padding: 12px;
}
.home-hero .view-title {
font-size: clamp(32px, 3.2vw, 44px);
font-weight: 700;
letter-spacing: -0.02em;
}
.tile-rail {
.friends-avatars {
display: flex;
gap: var(--nebula-spacing-lg);
overflow-x: auto;
overflow-y: hidden;
padding: 10px var(--nebula-spacing-xl) 18px;
scroll-behavior: smooth;
scrollbar-width: none;
transform: translate3d(var(--home-parallax-x, 0px), 0, 0);
transition: transform var(--nebula-duration-slow) var(--nebula-ease-console);
gap: 6px;
flex-wrap: wrap;
}
.tile-rail::-webkit-scrollbar {
display: none;
.friend-avatar {
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--fc, var(--nebula-color-accent));
opacity: 0.85;
border: 1.5px solid rgba(255, 255, 255, 0.12);
}
.dashboard-tile {
flex: 0 0 clamp(280px, 22vw, 340px);
min-height: clamp(200px, 18vh, 240px);
position: relative;
overflow: visible;
}
.dashboard-tile.tile-large {
flex: 0 0 clamp(360px, 28vw, 440px);
min-height: clamp(240px, 22vh, 300px);
}
.tile-content {
.activity-row {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
height: 100%;
gap: var(--nebula-spacing-md);
position: relative;
z-index: 2;
margin-bottom: 4px;
}
.tile-text {
display: flex;
flex-direction: column;
.activity-label {
font-size: 17px;
font-weight: 800;
color: var(--nebula-color-text);
line-height: 1;
}
.activity-hint {
margin: 0;
font-size: 11px;
color: var(--nebula-color-muted);
display: inline-flex;
align-items: center;
gap: 4px;
}
.tile-accent-bar {
position: absolute;
left: 0;
bottom: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, var(--nebula-color-accent), transparent);
opacity: 0;
transform: scaleX(0);
transform-origin: left center;
transition:
opacity var(--nebula-duration-nav) var(--nebula-ease-console),
transform var(--nebula-duration-nav) var(--nebula-ease-console);
}
.dashboard-tile.is-focused .tile-accent-bar {
opacity: 1;
transform: scaleX(1);
}