From eb56b6e3eab3f1402bf5d93f58dbc7a108243487 Mon Sep 17 00:00:00 2001 From: FedG-code Date: Sat, 11 Apr 2026 19:02:54 +0100 Subject: [PATCH 01/12] css: add cross-theme swatch accent constants --- css/shared.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/css/shared.css b/css/shared.css index 3127f53..b436d40 100644 --- a/css/shared.css +++ b/css/shared.css @@ -23,6 +23,12 @@ --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); --radius: 0px; --radius-sm: 0px; + /* Cross-theme swatch accent identities (NEVER overridden per theme) */ + --theme-bold-accent: #ff3d00; + --theme-brutalist-accent: #0000ff; + --theme-retro-accent: #dc322f; + --theme-cinematic-accent: #c9a84c; + --theme-neon-accent: #c9f059; } [data-theme="neon"] { From d3798d85d2f571e49d49032cd796d73ff0bb5d8b Mon Sep 17 00:00:00 2001 From: FedG-code Date: Sat, 11 Apr 2026 19:04:07 +0100 Subject: [PATCH 02/12] css: add right-edge toolbar base styles --- css/shared.css | 151 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/css/shared.css b/css/shared.css index b436d40..80c2e20 100644 --- a/css/shared.css +++ b/css/shared.css @@ -56,6 +56,157 @@ body, .work-card, .approach-card, .about-box, .tidbit, .chip, .btn { transition: background-color 0.3s, color 0.3s, border-color 0.3s; } +/* ========== RIGHT-EDGE TOOLBAR ========== */ +.toolbar { + position: fixed; + right: 0; + top: 50%; + transform: translateY(-50%); + display: flex; + flex-direction: column; + align-items: center; + padding: 20px 10px; + background: var(--bg-card); + border: 1px solid var(--border); + border-right: none; + border-top-left-radius: var(--radius); + border-bottom-left-radius: var(--radius); + border-top-right-radius: 0; + border-bottom-right-radius: 0; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12); + transition: background 0.3s, border-color 0.3s, box-shadow 0.3s, border-radius 0.3s; + z-index: 99; +} + +.toolbar .swatches { + display: flex; + flex-direction: column; + gap: 12px; + align-items: center; +} + +.toolbar .swatch-btn { + border: none; + cursor: pointer; + padding: 0; + background: none; + display: flex; + align-items: center; + justify-content: center; + transition: transform 0.15s; + position: relative; +} +.toolbar .swatch-btn:hover { transform: scale(1.15); } + +.toolbar .swatch-dot { + width: 22px; + height: 22px; + border-radius: 4px; + transition: all 0.2s; +} + +.toolbar .swatch-btn.active .swatch-dot { + width: 26px; + height: 26px; + border-radius: 5px; + box-shadow: 0 0 0 2.5px var(--accent); +} + +/* Individual swatch dot colours (cross-theme constants) */ +.toolbar .swatch-btn[data-theme-id="bold"] .swatch-dot { background: var(--theme-bold-accent); } +.toolbar .swatch-btn[data-theme-id="brutalist"] .swatch-dot { background: var(--theme-brutalist-accent); } +.toolbar .swatch-btn[data-theme-id="retro"] .swatch-dot { background: var(--theme-retro-accent); } +.toolbar .swatch-btn[data-theme-id="cinematic"] .swatch-dot { background: var(--theme-cinematic-accent); } +.toolbar .swatch-btn[data-theme-id="neon"] .swatch-dot { background: var(--theme-neon-accent); } + +.toolbar .divider { + width: 18px; + height: 1px; + background: var(--border); + margin: 14px auto; +} + +.toolbar .plane-btn { + border: none; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + background: transparent; + color: var(--text-secondary); + padding: 8px 10px; + border-radius: 6px; + transition: background 0.2s, color 0.2s; +} +.toolbar .plane-btn svg { width: 22px; height: 22px; transition: color 0.2s; } +.toolbar .plane-btn:hover:not(.active) { color: var(--text-primary); } +.toolbar .plane-btn.active { + background: var(--accent-soft); + color: var(--accent); +} + +/* Preview panel — desktop only (enabled via @media hover below) */ +.toolbar .preview-panel { + position: absolute; + right: calc(100% + 12px); + pointer-events: none; + z-index: 20; + width: 170px; + padding: 12px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: var(--radius); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12); + opacity: 0; + transform: translateX(-8px); + transition: opacity 0.2s, transform 0.2s; + display: none; /* hidden unless desktop hover media matches */ +} +.toolbar .preview-panel.visible { opacity: 1; transform: translateX(0); } +.toolbar .preview-stripe { height: 4px; border-radius: 2px; margin-bottom: 8px; } +.toolbar .preview-name { + font-family: var(--font-mono); + font-size: 10px; + text-transform: uppercase; + letter-spacing: 1.5px; + color: var(--text-primary); + margin-bottom: 2px; +} +.toolbar .preview-sub { + font-family: var(--font-mono); + font-size: 8px; + color: var(--text-secondary); + margin-bottom: 8px; + letter-spacing: 0.5px; +} +.toolbar .preview-chips { display: flex; gap: 4px; } +.toolbar .preview-chip { + width: 16px; + height: 16px; + border-radius: 3px; + border: 1px solid rgba(128, 128, 128, 0.2); +} + +@media (hover: hover) and (pointer: fine) { + .toolbar .preview-panel { display: block; } +} + +@media (prefers-reduced-motion: reduce) { + .toolbar, + .toolbar .swatch-btn, + .toolbar .preview-panel, + .toolbar .plane-btn { transition: none; } +} + +/* Mobile: shrink + hide while dragging a card */ +@media (max-width: 768px) { + .toolbar { padding: 14px 8px; } + .toolbar .swatch-dot { width: 18px; height: 18px; } + .toolbar .swatch-btn.active .swatch-dot { width: 22px; height: 22px; } + .toolbar .plane-btn svg { width: 18px; height: 18px; } + .toolbar .swatches { gap: 10px; } +} + .theme-switcher { position: fixed; top: 4.5rem; From a0541c39c0a012ebd1192d991731658d029d2abe Mon Sep 17 00:00:00 2001 From: FedG-code Date: Sat, 11 Apr 2026 19:06:01 +0100 Subject: [PATCH 03/12] css: per-theme toolbar overrides --- css/shared.css | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/css/shared.css b/css/shared.css index 80c2e20..cdba322 100644 --- a/css/shared.css +++ b/css/shared.css @@ -1039,6 +1039,19 @@ section { padding: 7rem 0; } } } +[data-theme="neon"] .toolbar { + border-radius: 16px 0 0 16px; + border-color: var(--accent); + box-shadow: 0 0 20px var(--accent-glow, rgba(201, 240, 89, 0.15)), + 0 4px 16px rgba(0, 0, 0, 0.4); +} + +[data-theme="neon"] .toolbar .preview-panel { + border-radius: 16px; + border-color: var(--accent); + box-shadow: 0 0 20px var(--accent-glow, rgba(201, 240, 89, 0.15)); +} + /* ========== BOLD THEME OVERRIDES ========== */ /* ── Hero ── */ @@ -1337,6 +1350,10 @@ section { padding: 7rem 0; } } } +[data-theme="bold"] .toolbar { + border-radius: 12px 0 0 12px; +} + /* ========== CINEMATIC THEME OVERRIDES ========== */ [data-theme="cinematic"] { @@ -1657,6 +1674,16 @@ section { padding: 7rem 0; } } } +[data-theme="cinematic"] .toolbar { + border-radius: 14px 0 0 14px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); +} + +[data-theme="cinematic"] .toolbar .preview-panel { + border-radius: 14px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); +} + /* ========== BRUTALIST THEME OVERRIDES ========== */ [data-theme="brutalist"] { @@ -2339,6 +2366,19 @@ section { padding: 7rem 0; } } } +[data-theme="brutalist"] .toolbar { + border-width: 2px; + border-color: var(--border); + border-radius: 0; + box-shadow: 4px 4px 0 var(--border); +} + +[data-theme="brutalist"] .toolbar .preview-panel { + border-width: 2px; + border-radius: 0; + box-shadow: 4px 4px 0 var(--border); +} + /* ========== RETRO THEME OVERRIDES ========== */ [data-theme="retro"] { @@ -2712,6 +2752,29 @@ section { padding: 7rem 0; } font-size: 0.95rem; } +[data-theme="retro"] .toolbar { + border-width: 2px; + border-color: var(--pop); + border-radius: 8px 0 0 8px; + box-shadow: 3px 3px 0 var(--pop); +} + +[data-theme="retro"] .toolbar .swatch-btn.active .swatch-dot { + box-shadow: 0 0 0 2.5px var(--pop); +} + +[data-theme="retro"] .toolbar .plane-btn.active { + color: var(--pop); + background: var(--pop-soft, rgba(26, 92, 82, 0.1)); +} + +[data-theme="retro"] .toolbar .preview-panel { + border-width: 2px; + border-color: var(--pop); + border-radius: 8px; + box-shadow: 3px 3px 0 var(--pop); +} + /* Responsive */ @media (max-width: 900px) { [data-theme="retro"] .hero { From f22546107c93986a2ea6ebb3c6854303133124fe Mon Sep 17 00:00:00 2001 From: FedG-code Date: Sat, 11 Apr 2026 19:07:30 +0100 Subject: [PATCH 04/12] js: add toolbar.js with swatches + hover preview --- js/toolbar.js | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 js/toolbar.js diff --git a/js/toolbar.js b/js/toolbar.js new file mode 100644 index 0000000..6f086f3 --- /dev/null +++ b/js/toolbar.js @@ -0,0 +1,148 @@ +// js/toolbar.js — right-edge toolbar with theme swatches + plane button slot +(function () { + 'use strict'; + + var THEMES = ['bold', 'brutalist', 'retro', 'cinematic', 'neon']; + var LABELS = { + bold: 'Bold', + brutalist: 'Brutalist', + retro: 'Retro', + cinematic: 'Cinematic', + neon: 'Neon' + }; + + // Preview panel content (uses the cross-theme accent constants declared in :root). + // Hex values mirror the CSS vars; kept in JS purely for the preview chips since we + // render them inline for speed. NOTE: if you change a --theme-*-accent in shared.css, + // update the matching entry here. + var PREVIEW = { + bold: { accent: '#ff3d00', bg: '#f4f4f4', text: '#111', sub: '#555', chips: ['#ff3d00', '#ffe100', '#111', '#f4f4f4'] }, + brutalist: { accent: '#0000ff', bg: '#fff', text: '#000', sub: '#333', chips: ['#0000ff', '#ff0000', '#000', '#fff'] }, + retro: { accent: '#dc322f', bg: '#fff8eb', text: '#3b2e1a', sub: '#7a6955', chips: ['#dc322f', '#2aa198', '#3b2e1a', '#fdf6e3'] }, + cinematic: { accent: '#c9a84c', bg: '#16161e', text: '#e8e8ec', sub: '#8888a0', chips: ['#c9a84c', '#e8d5a0', '#e8e8ec', '#0d0d12'] }, + neon: { accent: '#c9f059', bg: '#111118', text: '#e0ffe0', sub: '#7aaa7a', chips: ['#c9f059', '#59b8f0', '#e0ffe0', '#0a0a0f'] } + }; + + function buildToolbar() { + var current = document.documentElement.getAttribute('data-theme') || 'bold'; + + var toolbar = document.createElement('div'); + toolbar.className = 'toolbar'; + toolbar.id = 'toolbar'; + toolbar.setAttribute('role', 'toolbar'); + toolbar.setAttribute('aria-label', 'Site controls'); + + var swatches = document.createElement('div'); + swatches.className = 'swatches'; + toolbar.appendChild(swatches); + + THEMES.forEach(function (t) { + var btn = document.createElement('button'); + btn.type = 'button'; + btn.className = 'swatch-btn' + (t === current ? ' active' : ''); + btn.setAttribute('data-theme-id', t); + btn.setAttribute('aria-label', 'Switch to ' + LABELS[t] + ' theme'); + btn.setAttribute('aria-pressed', t === current ? 'true' : 'false'); + var dot = document.createElement('span'); + dot.className = 'swatch-dot'; + btn.appendChild(dot); + swatches.appendChild(btn); + }); + + var divider = document.createElement('div'); + divider.className = 'divider'; + toolbar.appendChild(divider); + + // Plane button is injected here by plane.js — leave a marker slot. + var slot = document.createElement('div'); + slot.id = 'toolbar-plane-slot'; + toolbar.appendChild(slot); + + // Preview panel (hover, desktop only) + var preview = document.createElement('div'); + preview.className = 'preview-panel'; + preview.id = 'toolbar-preview'; + preview.innerHTML = + '
' + + '
' + + '
Theme preview
' + + '
'; + toolbar.appendChild(preview); + + document.body.appendChild(toolbar); + + wireSwatchClicks(swatches); + wireHoverPreview(toolbar, swatches, preview); + + return toolbar; + } + + function wireSwatchClicks(swatches) { + swatches.addEventListener('click', function (e) { + var btn = e.target.closest('.swatch-btn'); + if (!btn) return; + var t = btn.getAttribute('data-theme-id'); + if (!t) return; + if (typeof window.setTheme === 'function') { + window.setTheme(t); + } + }); + } + + function wireHoverPreview(toolbar, swatches, preview) { + // Only run hover wiring on devices with true hover + fine pointer + var mq = window.matchMedia('(hover: hover) and (pointer: fine)'); + if (!mq.matches) return; + + swatches.addEventListener('mouseover', function (e) { + var btn = e.target.closest('.swatch-btn'); + if (!btn) return; + if (btn.classList.contains('active')) { + preview.classList.remove('visible'); + return; + } + var t = btn.getAttribute('data-theme-id'); + var p = PREVIEW[t]; + if (!p) return; + preview.querySelector('.preview-stripe').style.background = p.accent; + var nameEl = preview.querySelector('.preview-name'); + nameEl.textContent = LABELS[t]; + nameEl.style.color = p.text; + preview.querySelector('.preview-sub').style.color = p.sub; + preview.style.background = p.bg; + preview.querySelector('.preview-chips').innerHTML = + p.chips.map(function (c) { + return ''; + }).join(''); + var tr = toolbar.getBoundingClientRect(); + var br = btn.getBoundingClientRect(); + preview.style.top = Math.max(4, br.top - tr.top + btn.offsetHeight / 2 - 40) + 'px'; + preview.classList.add('visible'); + }); + + swatches.addEventListener('mouseleave', function () { + preview.classList.remove('visible'); + }); + } + + // Called by shared.js after it changes data-theme + function syncActive(themeName) { + document.querySelectorAll('#toolbar .swatch-btn').forEach(function (b) { + var on = b.getAttribute('data-theme-id') === themeName; + b.classList.toggle('active', on); + b.setAttribute('aria-pressed', on ? 'true' : 'false'); + }); + // Hide preview if it was showing the now-active theme + var preview = document.getElementById('toolbar-preview'); + if (preview) preview.classList.remove('visible'); + } + + // Build immediately if body exists, else wait + if (document.body) { + buildToolbar(); + } else { + document.addEventListener('DOMContentLoaded', buildToolbar); + } + + window.Toolbar = { syncActive: syncActive }; +})(); \ No newline at end of file From a7d0becae1bf2ee554a96151d5c54acabfcf52ef Mon Sep 17 00:00:00 2001 From: FedG-code Date: Sat, 11 Apr 2026 19:08:06 +0100 Subject: [PATCH 05/12] js: replace cycling theme switcher with setTheme(name) --- js/shared.js | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/js/shared.js b/js/shared.js index 39c9f97..dfcd8ea 100644 --- a/js/shared.js +++ b/js/shared.js @@ -11,27 +11,17 @@ const observer = new IntersectionObserver((entries) => { window.revealObserver = observer; reveals.forEach(el => observer.observe(el)); -// Theme switcher -const themeSwitcher = document.getElementById('themeSwitcher'); +// Theme switcher (direct-select via toolbar swatches) const themes = ['bold', 'brutalist', 'retro', 'cinematic', 'neon']; -let currentIndex = themes.indexOf(document.documentElement.getAttribute('data-theme') || 'bold'); -if (currentIndex === -1) currentIndex = 0; - -// Update button label to show the *other* theme -const updateLabel = () => { - const next = themes[(currentIndex + 1) % themes.length]; - themeSwitcher.textContent = next.charAt(0).toUpperCase() + next.slice(1); -}; -updateLabel(); - -themeSwitcher.addEventListener('click', () => { - currentIndex = (currentIndex + 1) % themes.length; - document.documentElement.setAttribute('data-theme', themes[currentIndex]); - localStorage.setItem('portfolio-theme', themes[currentIndex]); - updateLabel(); +function setTheme(name) { + if (themes.indexOf(name) === -1) return; + document.documentElement.setAttribute('data-theme', name); + localStorage.setItem('portfolio-theme', name); + if (window.Toolbar && window.Toolbar.syncActive) window.Toolbar.syncActive(name); if (window.TextDestruction) TextDestruction.onThemeChange(); if (window._planeOnThemeChange) window._planeOnThemeChange(); if (window._cardHandOnThemeChange) window._cardHandOnThemeChange(); -}); +} +window.setTheme = setTheme; From ee4f27b69540104e19507e3f9de9a8e24aa7f450 Mon Sep 17 00:00:00 2001 From: FedG-code Date: Sat, 11 Apr 2026 19:10:08 +0100 Subject: [PATCH 06/12] js: retire plane attractor, adopt plane button into toolbar, swap icon --- js/plane.js | 101 +++++++++++++--------------------------------------- 1 file changed, 24 insertions(+), 77 deletions(-) diff --git a/js/plane.js b/js/plane.js index 750de32..2e8367d 100644 --- a/js/plane.js +++ b/js/plane.js @@ -124,91 +124,40 @@ var canvasContainer = document.getElementById('plane-canvas'); var toggleBtn = null; - var crosshairIcon = null; - var labelSpan = null; - var bounceInterval = null; - var bounceTimeout = null; - var bounceDelayId = null; - - function startBounce() { - stopBounce(); - triggerBounce(); - bounceInterval = setInterval(triggerBounce, 3000); - } - function triggerBounce() { - toggleBtn.classList.add('bouncing'); - bounceTimeout = setTimeout(function() { - toggleBtn.classList.remove('bouncing'); - }, 1200); - } - - function stopBounce() { - if (bounceDelayId) clearTimeout(bounceDelayId); - if (bounceInterval) clearInterval(bounceInterval); - if (bounceTimeout) clearTimeout(bounceTimeout); - bounceDelayId = null; - bounceInterval = null; - bounceTimeout = null; - if (toggleBtn) toggleBtn.classList.remove('bouncing'); - } + var planeIcon = + '' + + '' + + ''; // --- Toggle Button --- function createToggleButton() { toggleBtn = document.createElement('button'); - toggleBtn.className = 'plane-toggle'; - toggleBtn.innerHTML = - '' + - '' + - '' + - '' + - '' + - '' + - '' + - ''; - - crosshairIcon = toggleBtn.querySelector('.plane-toggle-icon'); - labelSpan = toggleBtn.querySelector('.plane-toggle-label'); - - if (enabled) { - crosshairIcon.style.display = 'none'; - labelSpan.textContent = 'Stop'; - } else { - labelSpan.textContent = 'Fly'; - if (!sessionStorage.getItem('plane-attractor-seen')) { - toggleBtn.classList.add('attractor'); - bounceDelayId = setTimeout(function() { startBounce(); }, 1500); - } - } - - // If nav is already scroll-hidden (e.g. page reloaded while scrolled), start hidden - var nav = document.querySelector('nav'); - if (nav && nav.classList.contains('scroll-hidden')) { - toggleBtn.classList.add('scroll-hidden'); - } + toggleBtn.type = 'button'; + toggleBtn.className = 'plane-btn'; + toggleBtn.setAttribute('aria-label', 'Toggle paper plane overlay'); + toggleBtn.setAttribute('aria-pressed', enabled ? 'true' : 'false'); + toggleBtn.innerHTML = planeIcon; + if (enabled) toggleBtn.classList.add('active'); toggleBtn.addEventListener('click', toggle); - toggleBtn.addEventListener('pointerenter', function() { - if (toggleBtn.classList.contains('attractor')) { - stopBounce(); - toggleBtn.classList.remove('attractor'); - sessionStorage.setItem('plane-attractor-seen', '1'); - } - }); - - document.body.appendChild(toggleBtn); + // Adopt into toolbar slot (toolbar.js runs first). Fallback: append to body. + var slot = document.getElementById('toolbar-plane-slot'); + if (slot) { + slot.appendChild(toggleBtn); + } else { + document.body.appendChild(toggleBtn); + } } function updateButtonLabel() { if (!toggleBtn) return; - if (enabled) { - crosshairIcon.style.display = 'none'; - labelSpan.textContent = 'Stop'; - } else { - crosshairIcon.style.display = ''; - labelSpan.textContent = 'Fly'; - } + toggleBtn.classList.toggle('active', enabled); + toggleBtn.setAttribute('aria-pressed', enabled ? 'true' : 'false'); } function toggle() { @@ -217,8 +166,6 @@ updateButtonLabel(); if (enabled) { - toggleBtn.classList.remove('attractor'); - stopBounce(); document.documentElement.classList.add('plane-active'); if (!initialized) { init(); @@ -438,7 +385,7 @@ function onMobileMouseDown(e) { if (!running || !planeGroup || !planeGroup.visible) return; if (e.button !== 0) return; - if (e.target.closest('.plane-toggle, nav, .theme-switcher')) return; + if (e.target.closest('.toolbar')) return; var planeScreen = worldToScreen(planeGroup.position.x, planeGroup.position.z); var dx = e.clientX - planeScreen.x; @@ -518,7 +465,7 @@ function onMouseDown(e) { if (!running || !planeGroup || !planeGroup.visible) return; if (e.button !== 0) return; - if (e.target.closest('.plane-toggle, nav, .theme-switcher')) return; + if (e.target.closest('.toolbar')) return; fireProjectiles(); clearInterval(fireIntervalId); fireIntervalId = setInterval(fireProjectiles, FIRE_INTERVAL * 1000); From a412d08fd58794bac5699b1c69fa761aae326274 Mon Sep 17 00:00:00 2001 From: FedG-code Date: Sat, 11 Apr 2026 19:10:50 +0100 Subject: [PATCH 07/12] js: update class references for new toolbar --- js/analytics.js | 4 ++-- js/destruction.js | 2 +- js/page-transition.js | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/js/analytics.js b/js/analytics.js index 6ab6066..44c52fc 100644 --- a/js/analytics.js +++ b/js/analytics.js @@ -8,7 +8,7 @@ // 1. Plane mode toggle. The state read is deferred so plane.js's own click // handler runs first and flips the `plane-active` class on . document.addEventListener('click', function (e) { - if (!e.target.closest('.plane-toggle')) return; + if (!e.target.closest('.toolbar .plane-btn')) return; setTimeout(function () { var on = document.documentElement.classList.contains('plane-active'); gtag('event', 'plane_mode_toggle', { state: on ? 'on' : 'off' }); @@ -17,7 +17,7 @@ // 2. Theme switch. Same deferral so we read the theme after shared.js sets it. document.addEventListener('click', function (e) { - if (!e.target.closest('.theme-switcher')) return; + if (!e.target.closest('.toolbar .swatch-btn')) return; setTimeout(function () { var theme = document.documentElement.getAttribute('data-theme') || 'unknown'; gtag('event', 'theme_change', { theme: theme }); diff --git a/js/destruction.js b/js/destruction.js index 3fe838a..74fdb3d 100644 --- a/js/destruction.js +++ b/js/destruction.js @@ -56,7 +56,7 @@ function splitAllText() { var elements = document.querySelectorAll(DESTRUCTIBLE_SELECTOR); elements.forEach(function(el) { - if (el.closest('.theme-switcher, .plane-toggle, .btn, .work-expand')) return; + if (el.closest('.toolbar, .btn, .work-expand')) return; if (el.offsetParent === null) return; var instance = SplitText.create(el, { diff --git a/js/page-transition.js b/js/page-transition.js index a085f81..476fd4f 100644 --- a/js/page-transition.js +++ b/js/page-transition.js @@ -36,7 +36,7 @@ function extractPageContent(doc) { var clone = body.cloneNode(true); var removeSelectors = [ - 'nav', '.theme-switcher', 'footer', 'script', + 'nav', '.toolbar', 'footer', 'script', '#plane-canvas', '.blur-overlay', '.project-nav', '#handContainer', '#dragBlurOverlay', '#pageContainer', '#perspectiveContainer', '#flyOverlay' @@ -70,7 +70,7 @@ function bootstrapFromProjectPage() { // Collect project content nodes (everything that isn't SPA infrastructure) var infraIds = ['plane-canvas', 'dragBlurOverlay', 'pageContainer', 'handContainer', 'perspectiveContainer', 'flyOverlay', - 'themeSwitcher', 'statusBar']; + 'toolbar', 'statusBar']; var body = document.body; var nodesToMove = []; @@ -78,7 +78,7 @@ function bootstrapFromProjectPage() { var child = body.children[i]; if (child.tagName === 'SCRIPT') continue; if (child.id && infraIds.indexOf(child.id) !== -1) continue; - if (child.tagName === 'BUTTON' && (child.classList.contains('theme-switcher') || child.classList.contains('plane-toggle'))) continue; + if (child.id === 'toolbar') continue; nodesToMove.push(child); } From c6264dc26a827d8c4fd4cae9d2d1c46aaf7f29af Mon Sep 17 00:00:00 2001 From: FedG-code Date: Sat, 11 Apr 2026 19:13:13 +0100 Subject: [PATCH 08/12] css: remove obsolete theme-switcher and plane-toggle rules --- css/shared.css | 226 ------------------------------------------------- 1 file changed, 226 deletions(-) diff --git a/css/shared.css b/css/shared.css index cdba322..03f3880 100644 --- a/css/shared.css +++ b/css/shared.css @@ -207,29 +207,6 @@ body, .work-card, .approach-card, .about-box, .tidbit, .chip, .btn { .toolbar .swatches { gap: 10px; } } -.theme-switcher { - position: fixed; - top: 4.5rem; - right: 1.5rem; - z-index: 99; - font-family: var(--font-mono); - font-size: 0.65rem; - font-weight: 500; - letter-spacing: 0.05em; - padding: 0.4rem 0.9rem; - border-radius: 100px; - border: 1px solid var(--border); - background: var(--cream); - color: var(--text-secondary); - cursor: pointer; - transition: all 0.3s; -} - -.theme-switcher:hover { - border-color: var(--accent); - color: var(--accent); -} - /* ========== PLANE ACTIVE (disable text selection during plane mode) ========== */ html.plane-active { user-select: none; @@ -237,51 +214,6 @@ html.plane-active { scroll-behavior: auto; } -/* ========== PLANE TOGGLE ========== */ -.plane-toggle { - position: fixed; - top: 7rem; - right: 1.5rem; - z-index: 99; - font-family: var(--font-mono); - font-size: 0.65rem; - font-weight: 500; - letter-spacing: 0.05em; - padding: 0.4rem 0.9rem; - border-radius: 100px; - border: 1px solid var(--border); - background: var(--cream); - color: var(--text-secondary); - cursor: pointer; - transition: border-color 0.3s, color 0.3s, background 0.3s; - display: flex; - align-items: center; - gap: 5px; -} - -.plane-toggle:hover { - border-color: var(--accent); - color: var(--accent); -} - -.plane-toggle.attractor { - border-color: var(--accent); - color: var(--accent); - background: var(--cream); - will-change: transform; -} - -.plane-toggle.attractor.bouncing { - animation: nudgeBounce 1.2s ease; -} - -.plane-toggle.attractor:hover { - animation: none; - background: var(--accent-soft); - border-color: var(--accent); - color: var(--accent); -} - html { scroll-behavior: smooth; } body { @@ -868,14 +800,6 @@ section { padding: 7rem 0; } to { opacity: 1; transform: translateY(0); } } -@keyframes nudgeBounce { - 0%, 100% { transform: translateY(0); } - 20% { transform: translateY(-5px); } - 40% { transform: translateY(0); } - 55% { transform: translateY(-3px); } - 70% { transform: translateY(0); } -} - .reveal { opacity: 0; transform: translateY(24px); @@ -942,23 +866,6 @@ section { padding: 7rem 0; } [data-theme="neon"] .tidbit { border-radius: 8px; } [data-theme="neon"] .about-box { border-radius: 8px; } -/* Theme switcher + plane toggle */ -[data-theme="neon"] .theme-switcher { - top: 4.5rem; - border-radius: 4px; - background: var(--bg-card); - border-color: var(--border); -} -[data-theme="neon"] .theme-switcher:hover { - border-color: var(--accent); - color: var(--accent); - box-shadow: 0 0 12px #c9f05940; -} -[data-theme="neon"] .plane-toggle { border-radius: 4px; background: var(--bg-card); border-color: var(--border); } -[data-theme="neon"] .plane-toggle:hover { border-color: var(--accent); color: var(--accent); box-shadow: 0 0 12px #c9f05940; } -[data-theme="neon"] .plane-toggle.attractor { border-radius: 4px; background: var(--bg-card); border-color: var(--accent); color: var(--accent); box-shadow: none; } -[data-theme="neon"] .plane-toggle.attractor:hover { background: var(--bg-card); border-color: var(--accent); color: var(--accent); box-shadow: 0 0 12px #c9f05940; } - /* Grain overlay */ [data-theme="neon"] body::before { content: ''; @@ -1020,23 +927,8 @@ section { padding: 7rem 0; } display: inline; } -@media (max-width: 768px) { - .plane-toggle { - top: 7rem; - right: 1.5rem; - } -} - @media (max-width: 600px) { html { overflow-x: hidden; } - - .plane-toggle { - top: 3.25rem; - } - - [data-theme="neon"] .theme-switcher { - top: 0.75rem; - } } [data-theme="neon"] .toolbar { @@ -1312,17 +1204,6 @@ section { padding: 7rem 0; } box-shadow: none; } -/* ── Theme Switcher & Plane Toggle ── */ -[data-theme="bold"] .theme-switcher { - border-radius: 0; -} -[data-theme="bold"] .plane-toggle { - border-radius: 0; -} -[data-theme="bold"] .plane-toggle.attractor { - border-radius: 0; -} - /* ── Hide neon grid bg / doodles ── */ [data-theme="bold"] .hero::before { display: none; } @@ -1336,9 +1217,6 @@ section { padding: 7rem 0; } } @media (max-width: 600px) { - [data-theme="bold"] .theme-switcher { - top: 0.75rem; - } [data-theme="bold"] .hero-desc { color: #000; } @@ -1615,37 +1493,6 @@ section { padding: 7rem 0; } box-shadow: none; } -/* ── Theme Switcher & Plane Toggle ── */ -[data-theme="cinematic"] .theme-switcher { - border-radius: 0; - background: var(--bg-card); - border-color: var(--border); -} -[data-theme="cinematic"] .theme-switcher:hover { - border-color: var(--accent); - color: var(--accent); -} -[data-theme="cinematic"] .plane-toggle { - border-radius: 0; - background: var(--bg-card); - border-color: var(--border); -} -[data-theme="cinematic"] .plane-toggle:hover { - border-color: var(--accent); - color: var(--accent); -} -[data-theme="cinematic"] .plane-toggle.attractor { - border-radius: 0; - background: var(--bg-card); - border-color: var(--accent); - color: var(--accent); -} -[data-theme="cinematic"] .plane-toggle.attractor:hover { - background: var(--bg-card); - border-color: var(--accent); - color: var(--accent); -} - /* ── Blur overlay ── */ [data-theme="cinematic"] .blur-overlay.active { background: rgba(0, 0, 0, 0.5); @@ -1666,9 +1513,6 @@ section { padding: 7rem 0; } /* ── Responsive ── */ @media (max-width: 600px) { - [data-theme="cinematic"] .theme-switcher { - top: 0.75rem; - } [data-theme="cinematic"] .hero h1 { font-size: clamp(2rem, 10vw, 3rem); } @@ -2270,35 +2114,6 @@ section { padding: 7rem 0; } box-shadow: none; } -[data-theme="brutalist"] .theme-switcher { - border-radius: 0; - border: 2px solid var(--border); - background: var(--bg); -} - -[data-theme="brutalist"] .theme-switcher:hover { - border-color: var(--accent); - color: var(--accent); -} - -[data-theme="brutalist"] .plane-toggle { - border-radius: 0; - border: 2px solid var(--border); - background: var(--bg); -} - -[data-theme="brutalist"] .plane-toggle:hover { - border-color: var(--accent); - color: var(--accent); -} - -[data-theme="brutalist"] .plane-toggle.attractor { - border-radius: 0; - border-color: var(--accent); - color: var(--accent); - background: var(--bg); -} - [data-theme="brutalist"] .work-image-placeholder { border: 1px solid var(--border); } @@ -2361,9 +2176,6 @@ section { padding: 7rem 0; } [data-theme="brutalist"] #page-home { padding-top: 0; /* status bar is now in flow, not fixed */ } - [data-theme="brutalist"] .theme-switcher { - top: 0.75rem; - } } [data-theme="brutalist"] .toolbar { @@ -2654,39 +2466,6 @@ section { padding: 7rem 0; } color: #F0EBE0; } -/* Theme Switcher */ -[data-theme="retro"] .theme-switcher { - border-radius: 0; - border: 2px solid #1A5C52; - background: var(--bg); - color: #1A5C52; -} -[data-theme="retro"] .theme-switcher:hover { - border-color: var(--accent); - color: var(--accent); -} - -/* Plane Toggle */ -[data-theme="retro"] .plane-toggle { - border-radius: 0; - background: var(--bg); - border: 2px solid #1A5C52; - color: #1A5C52; -} -[data-theme="retro"] .plane-toggle:hover { - border-color: var(--accent); - color: var(--accent); -} -[data-theme="retro"] .plane-toggle.attractor { - border-radius: 0; - background: var(--bg); - border-color: var(--accent); - color: var(--accent); -} -[data-theme="retro"] .plane-toggle.attractor:hover { - background: #D9423018; -} - /* Retro teal panel — right side of split hero */ [data-theme="retro"] .hero-panel { display: flex; @@ -2789,8 +2568,3 @@ section { padding: 7rem 0; } } } -@media (max-width: 600px) { - [data-theme="retro"] .theme-switcher { - top: 0.75rem; - } -} From 587fc4fa542d048c4c68092eb022f324ebcc0ce7 Mon Sep 17 00:00:00 2001 From: FedG-code Date: Sat, 11 Apr 2026 19:14:13 +0100 Subject: [PATCH 09/12] html: remove theme-switcher button, load toolbar.js --- casino_games.html | 4 +--- eve_of_destruction.html | 4 +--- index.html | 4 +--- my_games.html | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/casino_games.html b/casino_games.html index 5248902..189e5e2 100644 --- a/casino_games.html +++ b/casino_games.html @@ -40,9 +40,6 @@
- - -
@@ -212,6 +209,7 @@

Fruit Slash

+ diff --git a/eve_of_destruction.html b/eve_of_destruction.html index 5122525..b081121 100644 --- a/eve_of_destruction.html +++ b/eve_of_destruction.html @@ -40,9 +40,6 @@
- - -
@@ -195,6 +192,7 @@

Movement

+ diff --git a/index.html b/index.html index c700902..3b02889 100644 --- a/index.html +++ b/index.html @@ -42,9 +42,6 @@
- - -
STATUS: OPEN TO OPPORTUNITIES @@ -276,6 +273,7 @@

GET IN TOUCH

+ diff --git a/my_games.html b/my_games.html index cb79603..9bb1587 100644 --- a/my_games.html +++ b/my_games.html @@ -40,9 +40,6 @@
- - -
@@ -204,6 +201,7 @@

Calm Before the Storm

+ From 621fe48460fddda0a39b10d63d50cf9bbafc919e Mon Sep 17 00:00:00 2001 From: FedG-code Date: Sat, 11 Apr 2026 19:18:52 +0100 Subject: [PATCH 10/12] docs: update CLAUDE.md for toolbar; remove prototype --- css/CLAUDE.md | 14 ++++++------ js/CLAUDE.md | 60 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/css/CLAUDE.md b/css/CLAUDE.md index e867c5f..8531b85 100644 --- a/css/CLAUDE.md +++ b/css/CLAUDE.md @@ -2,7 +2,7 @@ Brief overview: 3 CSS files totaling ~3,900 lines. Five themes (bold, cinematic, brutalist, retro, neon). Pattern: base component styles followed by theme override blocks. -## shared.css (2576 lines) +## shared.css (2570 lines) ### Section Map @@ -11,10 +11,9 @@ Brief overview: 3 CSS files totaling ~3,900 lines. Five themes (bold, cinematic, | Universal reset + :root variables | 1-26 | --bg, --bg-warm, --bg-card, --border, --border-hover, --text-primary, --text-secondary, --text-muted, --accent, --accent-soft, --accent-mid, --pop, --pop-soft, --cream, --accent-glow, --font-serif, --font-body, --font-mono, --ease-out, --ease-spring, --radius, --radius-sm | | [data-theme="neon"] variables | 28-47 | Dark grays, lime accent (#c9f059), blue pop (#59b8f0), Sora/Space Mono fonts | | Global transitions | 49-51 | body, .work-card, .approach-card transitions | -| .theme-switcher | 53-74 | Fixed positioning, sizing, hover states | -| PLANE ACTIVE | 76-81 | html.plane-active styles (user-select: none) | -| PLANE TOGGLE | 83-127 | .plane-toggle button, attractor state, bounce animation | -| Global html/body/links | 128-148 | Base typography, .container max-width 1140px | +| RIGHT-EDGE TOOLBAR | 59-183 | .toolbar fixed-right container, .swatches stack, .swatch-btn[data-theme-id] dots, .plane-btn active state, .preview-panel (desktop hover only), responsive @768px shrink, prefers-reduced-motion disable | +| PLANE ACTIVE | ~185 | html.plane-active styles (user-select: none) | +| Global html/body/links | ~190 | Base typography, .container max-width 1140px | | HERO | 150-257 | .hero min-height 100vh, .hero-badge fadeUp, .hero h1 clamp(3rem-6.5rem), .hero-body grid, .hero-tidbits | | SECTIONS | 258-279 | section padding 7rem, .section-label, .section-heading | | WORK CARDS | 280-491 | .work-grid, .work-card, .work-card-header, .work-icon, .work-expand, .work-image-placeholder (warm/cool/fresh), .work-details, .work-stats | @@ -22,7 +21,7 @@ Brief overview: 3 CSS files totaling ~3,900 lines. Five themes (bold, cinematic, | APPROACH | 564-608 | .approach-cards grid, .approach-card | | CONTACT | 609-672 | .contact, .btn primary/secondary | | DOODLE DECORATION | 674-707 | .doodle positioning and animation | -| ANIMATIONS | 708-732 | @keyframes: fadeUp, pulse, nudgeBounce | +| ANIMATIONS | ~708 | @keyframes: fadeUp, pulse | | 3D PLANE OVERLAY | 733-740 | #plane-canvas fixed overlay | | THEME LAYOUT TOGGLES | 741-749 | .status-bar, .hero-brutalist, .about-brutalist, .hero-panel display toggles | | NEON THEME OVERRIDES | 750-844 | Font weights 600-700, sharp corners, grain overlay, doodle hidden | @@ -42,6 +41,7 @@ All variables defined in lines 3-26: - `--text-primary`, `--text-secondary`, `--text-muted` -- text colors - `--accent`, `--accent-soft`, `--accent-mid`, `--accent-glow` -- accent color + opacity variants - `--pop`, `--pop-soft` -- pop color (same as accent in bold theme) +- `--theme-bold-accent`, `--theme-brutalist-accent`, `--theme-retro-accent`, `--theme-cinematic-accent`, `--theme-neon-accent` -- cross-theme swatch identity colors (used by `.toolbar .swatch-dot`, never overridden per theme) - `--cream` -- cream background - `--font-serif`, `--font-body`, `--font-mono` -- font stacks - `--ease-out`, `--ease-spring` -- easing functions @@ -57,7 +57,7 @@ All variables defined in lines 3-26: ### Responsive Breakpoints - max-width: 900px -- hero-body 1fr, about-content 1fr -- max-width: 768px -- plane-toggle adjustments +- max-width: 768px -- .toolbar shrink (smaller swatches + plane icon) - max-width: 600px -- overflow-x: hidden ## cards.css (864 lines) diff --git a/js/CLAUDE.md b/js/CLAUDE.md index 1eceae1..48ed1d8 100644 --- a/js/CLAUDE.md +++ b/js/CLAUDE.md @@ -5,7 +5,13 @@ Overview: 6 JS files (~3,100 lines). No build step, no modules — all globals. ## Dependency Graph ``` -shared.js (theme switcher) +toolbar.js (DOM: swatches, plane slot, hover preview) + ├─ wires → window.setTheme(t) on swatch click + └─ exports → window.Toolbar.syncActive(t) + +shared.js (setTheme(name) — direct theme switch) + ├─ called by → toolbar.js swatch click + ├─ fires → window.Toolbar.syncActive(name) ├─ fires → TextDestruction.onThemeChange() ├─ fires → window._planeOnThemeChange() └─ fires → window._cardHandOnThemeChange() @@ -21,25 +27,53 @@ External: GSAP core, SplitText, Physics2DPlugin, Three.js r128, GLTFLoader --- -## shared.js (37 lines) +## shared.js (27 lines) ### Complete Reference | Section | Lines | Notes | |---------|-------|-------| -| Scroll reveal (IntersectionObserver) | 1-11 | threshold 0.1, rootMargin '0px 0px -40px 0px', staggered 60ms delay, unobserves after visible | -| Theme switcher setup | 14-17 | themes = ['bold','brutalist','retro','cinematic','neon'], reads data-theme attr | -| updateLabel() | 21-25 | Shows NEXT theme name on button | -| Click handler | 27-35 | Cycles index, sets data-theme, persists to localStorage('portfolio-theme'), fires 3 callbacks | +| Scroll reveal (IntersectionObserver) | 1-12 | threshold 0.1, rootMargin '0px 0px -40px 0px', staggered 60ms delay, unobserves after visible | +| Theme list | 15 | themes = ['bold','brutalist','retro','cinematic','neon'] | +| setTheme(name) | 17-26 | Validates name, sets data-theme, persists to localStorage('portfolio-theme'), fires Toolbar.syncActive + 3 theme-change callbacks | +| window.setTheme export | 27 | Global accessor invoked by toolbar.js swatch clicks | ### Global Exports -- `window.revealObserver` (line 10) — IntersectionObserver instance +- `window.revealObserver` (line 11) — IntersectionObserver instance +- `window.setTheme(name)` (line 27) — direct theme switch; no cycling logic, name must be in `themes` array + +### Theme Change Hooks Fired (in order, inside setTheme) +1. `window.Toolbar.syncActive(name)` — updates swatch `.active` class + aria-pressed (null-checked) +2. `window.TextDestruction.onThemeChange()` (null-checked) +3. `window._planeOnThemeChange()` (null-checked) +4. `window._cardHandOnThemeChange()` (null-checked) + +--- -### Theme Change Hooks Fired (in order) -1. `window.TextDestruction.onThemeChange()` (line 32) -2. `window._planeOnThemeChange()` (line 33) -3. `window._cardHandOnThemeChange()` (line 34) +## toolbar.js (147 lines) + +### Purpose +Builds the fixed right-edge `.toolbar` element injected into `document.body` on every live page. Contains five theme swatch buttons (direct-select, not cycling), a divider, a `#toolbar-plane-slot` marker div that plane.js adopts its button into, and a hover preview panel (desktop-only via `(hover: hover) and (pointer: fine)` media query). + +### Constants +| Name | Value | Notes | +|------|-------|-------| +| `THEMES` | `['bold','brutalist','retro','cinematic','neon']` | Rendered in this order top-to-bottom | +| `LABELS` | `{bold: 'Bold', ...}` | aria-label + preview panel name | +| `PREVIEW` | Per-theme `{accent, bg, text, sub, chips[4]}` | Inline hex values for preview panel chips — mirrors the `--theme-*-accent` CSS constants (keep in sync if CSS changes) | + +### Functions +| Function | Notes | +|----------|-------| +| `buildToolbar()` | Creates `#toolbar` with role=toolbar, swatches, divider, plane slot, preview panel; wires click + hover; appends to body | +| `wireSwatchClicks(swatches)` | Delegates click on `.swatch-btn`, reads `data-theme-id`, calls `window.setTheme(t)` | +| `wireHoverPreview(...)` | Desktop-only — updates preview panel content on mouseover of non-active swatches, hides on mouseleave | +| `syncActive(name)` | Toggles `.active` class + `aria-pressed` on swatch buttons; hides preview — exported as `window.Toolbar.syncActive` | + +### Global Exports +- `window.Toolbar = { syncActive }` — called by `setTheme()` in shared.js -These are called without null checks — would throw if undefined and script loads before the others. +### Load Order Requirement +Must be loaded **before** `shared.js` (so `window.Toolbar.syncActive` exists when setTheme first fires) **and before** `plane.js` (so `#toolbar-plane-slot` exists when `createToggleButton()` runs). All four live HTML pages load scripts in this order: `toolbar.js` → `shared.js` → `plane.js`. --- @@ -112,7 +146,7 @@ GSAP core, SplitText plugin, Physics2DPlugin (all CDN, no npm) | Mobile detection | 29-35 | isMobile() with _isMobileCached | | State variables | 37-80 | enabled, scene/camera/renderer, plane model, mouse/touch, projectiles[], fire interval | | Iframe avoidance | 82-125 | getAvoidanceTarget() keeps plane outside iframe buffered regions | -| Toggle button UI | 127-214 | createToggleButton(), updateButtonLabel(), attractor bounce | +| Toggle button UI | ~125-161 | `planeIcon` SVG (paper plane), `createToggleButton()` builds `.plane-btn` with aria-label + aria-pressed, adopts into `#toolbar-plane-slot` (body fallback). `updateButtonLabel()` toggles `.active` + aria-pressed on state change. No icon swap — active state is pure CSS recolor via `.plane-btn.active { color: var(--accent); background: var(--accent-soft); }` | | Toggle handler | 216-247 | SessionStorage persist, syncs TextDestruction.init/destroy, plane-active class | | start() / stop() | 249-271 | Control animation loop + canvas visibility | | Dynamic script loading | 273-298 | CDN Three.js r128 + GLTFLoader | From fea66c7c15eb055c3e8b83edd0b1e026c0197a9d Mon Sep 17 00:00:00 2001 From: FedG-code Date: Sat, 11 Apr 2026 19:29:30 +0100 Subject: [PATCH 11/12] scrollbar navigator --- .../lost-satellite copy for games.html | 0 css/shared.css | 4 +- .../2026-04-11-right-edge-toolbar-HANDOFF.md | 91 ++ .../plans/2026-04-11-right-edge-toolbar.md | 1058 +++++++++++++++++ js/toolbar.js | 6 +- 5 files changed, 1154 insertions(+), 5 deletions(-) rename lost-satellite copy for games.html => backup/lost-satellite copy for games.html (100%) create mode 100644 docs/superpowers/plans/2026-04-11-right-edge-toolbar-HANDOFF.md create mode 100644 docs/superpowers/plans/2026-04-11-right-edge-toolbar.md diff --git a/lost-satellite copy for games.html b/backup/lost-satellite copy for games.html similarity index 100% rename from lost-satellite copy for games.html rename to backup/lost-satellite copy for games.html diff --git a/css/shared.css b/css/shared.css index 03f3880..63d11db 100644 --- a/css/shared.css +++ b/css/shared.css @@ -26,8 +26,8 @@ /* Cross-theme swatch accent identities (NEVER overridden per theme) */ --theme-bold-accent: #ff3d00; --theme-brutalist-accent: #0000ff; - --theme-retro-accent: #dc322f; - --theme-cinematic-accent: #c9a84c; + --theme-retro-accent: #1A5C52; + --theme-cinematic-accent: #D6001C; --theme-neon-accent: #c9f059; } diff --git a/docs/superpowers/plans/2026-04-11-right-edge-toolbar-HANDOFF.md b/docs/superpowers/plans/2026-04-11-right-edge-toolbar-HANDOFF.md new file mode 100644 index 0000000..2e83a4f --- /dev/null +++ b/docs/superpowers/plans/2026-04-11-right-edge-toolbar-HANDOFF.md @@ -0,0 +1,91 @@ +# Handoff: Execute Right-Edge Toolbar Plan (Subagent-Driven) + +You are picking up a fully-scoped implementation plan. A prior session did the research, resolved ambiguities with the user, and wrote the plan. Your job is to execute it task-by-task using the subagent-driven-development workflow. + +## What to read first (in this order) + +1. **Invoke the skill:** `superpowers:subagent-driven-development` via the Skill tool. Follow it exactly. This is the workflow. +2. **Read the plan:** `docs/superpowers/plans/2026-04-11-right-edge-toolbar.md`. Read it top-to-bottom once before dispatching any subagent, so you understand cross-task dependencies (especially name consistency: `#toolbar`, `#toolbar-plane-slot`, `.plane-btn`, `.swatch-btn`, `data-theme-id`, `window.setTheme`, `window.Toolbar.syncActive`). +3. **Project conventions:** `CLAUDE.md` at repo root. Two rules matter most for this work: + - Never hardcode colour values in element CSS — use `var(--...)`. The plan already handles this via `--theme-*-accent` constants (Task 2). + - Be surgical with file reads — always use `offset`+`limit`, never read whole files. Pass this instruction to every subagent you dispatch. + +## Ground truth + +- All six ambiguities flagged in the original plan draft have been **resolved** by the user. The plan's "Resolved Decisions" section (top of the file) is authoritative — do not re-ask the user about them. In particular: + - Swatch dots use `--theme-*-accent` constants in `:root` (not hex in element styles). + - Plane icon is paper-plane SVG only. No stop-square swap. Active state is pure CSS recolour via `.plane-btn.active { color: var(--accent); ... }` + SVG `currentColor`. + - Retro `var(--pop)` override applies to the live toolbar chrome only; the hover preview panel still shows each target theme's identity colours via the PREVIEW object in toolbar.js. + - Mobile: shrink only at ≤768px. No hide-on-drag. + - Delete `toolbar-variation-d.html` in the final task. + - `lost-satellite copy for games.html` is in a backup folder, out of scope. + +## Execution rules + +- **One subagent per task.** 12 tasks in the plan. Dispatch each as a fresh subagent via the Agent tool with the `general-purpose` subagent type (or whichever subagent-driven-development recommends). The subagent should implement that one task's steps and commit. +- **Two-stage review between tasks.** After each subagent finishes: + 1. Read the diff yourself (`git diff HEAD~1`) and verify it matches the plan's intent. + 2. Dispatch a fresh `superpowers:code-reviewer` subagent to audit the task against the plan section. Only proceed to the next task if both pass. +- **Line numbers drift.** `css/shared.css` is ~2576 lines and will shrink significantly during Task 9. Any task after Task 3 must re-grep for line numbers before editing. Tell each subagent: "Line numbers in the plan are snapshots from when it was written — re-grep before deleting or inserting." +- **Do NOT batch tasks.** The plan is designed for isolated, sequential, reviewable commits. Resist the urge to combine Tasks 3+4, or 9+10, etc. +- **Verification task (Task 11) is manual + Playwright.** You can dispatch a subagent to run the Playwright commands, but you personally need to look at screenshots and confirm visual correctness across all five themes. Do not claim success without seeing the images. +- **Don't touch out-of-scope systems:** card-hand attractor (separate from the retired plane attractor), the plane overlay's Three.js rendering, destruction.js internals, text-rearrange. The plan only touches specific lines — respect the scope. + +## Subagent prompt template + +When dispatching each task, use a briefing like: + +> You are implementing Task N of the right-edge toolbar plan at `docs/superpowers/plans/2026-04-11-right-edge-toolbar.md`. Read only that task's section (use offset+limit — do not read the whole file). Also read `CLAUDE.md` for the "no hardcoded colours" and "surgical file reads" rules. +> +> Implementation requirements: +> - Follow every step in the task in order. Do not skip steps or batch them. +> - Line numbers in the plan may have drifted — re-grep before deleting/inserting into `css/shared.css`. +> - Use Read with offset+limit for every file access. Never read a full file. +> - Commit when the task says to commit. Use the exact commit message from the plan. +> - If a step's expected result doesn't match (e.g. grep returns zero matches when the plan expected some), STOP and report back instead of improvising. +> +> When done, report: (1) what you changed, (2) what you committed, (3) any deviations from the plan and why. Under 200 words. + +## Order of operations + +1. Task 1 — pre-flight grep sweep (no commits, produces an audit note) +2. Task 2 — `--theme-*-accent` constants → commit +3. Task 3 — `.toolbar` base CSS → commit +4. Task 4 — per-theme overrides → commit +5. Task 5 — `js/toolbar.js` (new file) → commit +6. Task 6 — `js/shared.js` refactor → commit +7. Task 7 — `js/plane.js` rework (drop attractor, new icon, adopt into slot) → commit +8. Task 8 — analytics/destruction/page-transition selector updates → commit +9. Task 9 — delete obsolete CSS (reverse line order, re-grep between deletions) → commit +10. Task 10 — HTML changes across 4 live pages + script tag → commit +11. Task 11 — Playwright verification across all 5 themes + mobile + a11y + cross-page → fix-up commit if needed +12. Task 12 — delete prototype + update CLAUDE.md docs → commit + +**Reviewable checkpoint moments:** After Tasks 5 (new JS), 7 (plane rework), 9 (big CSS deletion), and 11 (verification) — pause and let the user eyeball things before continuing. Everything else can flow through subagent+reviewer without interruption. + +## If something goes wrong + +- **Grep mismatch:** A task expects to find `.theme-switcher` at a line that no longer contains it. STOP. Re-grep with fresh line numbers and update the plan's line references, then resume. +- **Subagent exceeds scope:** Reject its work, reset to `HEAD~1`, and dispatch again with a stricter prompt. +- **A visual in Task 11 looks wrong in one theme:** Do not patch blindly. Identify which per-theme override (Task 4) is wrong and fix it there, so the fix lives in the right section. +- **The user's earlier instructions conflict with the plan:** The user's explicit instructions always win. Pause and ask. + +## Known risks + +- Task 9 (CSS deletion) is the highest-risk task because line numbers shift after every deletion. The plan tells you to delete in reverse line order and re-grep between each — follow that discipline. +- `js/plane.js` has attractor state scattered across several functions (constructor vars, `createToggleButton`, `toggle()`, possibly `pointerenter` handlers). Task 7 lists them, but grep for `attractor` and `plane-attractor-seen` one more time at the end of the task to make sure nothing lingers. +- `page-transition.js` has both a `removeSelectors` list AND an `infraIds` list AND a button-skip check — all three must be updated (Task 8). Missing one will break the SPA navigation when leaving a project page. + +## Success criteria + +- All five themes show a visually distinct, pinned right-edge toolbar with five swatches + plane button +- Clicking a swatch switches themes directly (not cycled) +- Hover preview appears on desktop, not on mobile/touch +- Plane button still toggles the plane overlay; active state is theme-coloured +- Mobile ≤768px: toolbar shrinks, does not visibly collide with card hand +- `role="toolbar"`, `aria-label`s on each swatch and the plane button, `aria-pressed` on plane button +- Zero console errors on all four live pages +- Cross-page SPA navigation still works (card drag from index → project page, theme still switchable there) +- Zero remaining references to `.theme-switcher` / `.plane-toggle` / `themeSwitcher` / `plane-attractor-seen` in `css/`, `js/`, and live HTML (tests and `backup/` are out of scope) + +Good luck. Read the plan first, then invoke `superpowers:subagent-driven-development`, then dispatch Task 1. diff --git a/docs/superpowers/plans/2026-04-11-right-edge-toolbar.md b/docs/superpowers/plans/2026-04-11-right-edge-toolbar.md new file mode 100644 index 0000000..ac803a2 --- /dev/null +++ b/docs/superpowers/plans/2026-04-11-right-edge-toolbar.md @@ -0,0 +1,1058 @@ +# Right-Edge Toolbar Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Replace `.theme-switcher` (cycling button) and `.plane-toggle` (fixed button + attractor) with a single fixed right-edge `.toolbar` component containing direct-select theme swatches, a hover preview panel (desktop only), and a plane toggle, on all four live pages across all five themes. + +**Architecture:** One fixed-position toolbar element injected by JS into each page (mirrors the prototype DOM in `toolbar-variation-d.html`). Base + per-theme styles live in `css/shared.css`. Swatch click wires directly into the existing `setTheme(name)` logic in `js/shared.js`. Plane button reuses the existing `toggle()` function in `js/plane.js` (unchanged behaviour) but is now adopted into the toolbar DOM instead of being appended to `document.body` standalone. All old `.theme-switcher` / `.plane-toggle` CSS, HTML, and the attractor/bounce code are deleted. + +**Tech Stack:** Static HTML/CSS/JS, no build step. CSS custom properties + per-theme `[data-theme="..."]` blocks. `data-theme` lives on ``. + +--- + +## Resolved Decisions (locked in before implementation) + +1. **Swatch dot colours:** use `--theme-*-accent` cross-theme constants in `:root` (Task 2). +2. **Plane button icon:** use the paper-plane SVG only (rest state). Drop the crosshair, drop the `"Fly"/"Stop"` text label, and do NOT swap to a "stop" square when active. The active state is conveyed purely by CSS recolouring the same SVG via `.plane-btn.active` → `color: var(--accent)` (+ `background: var(--accent-soft)`), which picks up a theme-appropriate colour automatically. +3. **Retro `var(--pop)` scope:** applies only to live toolbar chrome (border, box-shadow, active swatch ring, plane-btn active colour). The preview panel's stripe/name/chip colours continue to show the *target* theme's identity colours from the `PREVIEW` object in toolbar.js — they are not affected by the retro override. +4. **Mobile:** shrink only (≤768px padding + swatch + icon size). No hide-on-drag rule. Revisit later if overlap becomes a visual issue. +5. **`toolbar-variation-d.html`:** delete in the final task. +6. **`lost-satellite copy for games.html`:** user has moved it into the backup folder — out of scope. + +--- + +## File Structure + +**Modified:** +- `css/shared.css` — add `.toolbar` base rules + per-theme overrides + responsive rules; delete all `.theme-switcher` and `.plane-toggle` rules (base and per-theme). +- `js/shared.js` — replace the cycling `themeSwitcher` button handler with a `setTheme(name)` function callable from any swatch click. Keep the three theme-change hook calls. +- `js/plane.js` — delete `startBounce/stopBounce/triggerBounce`, delete the attractor class + `sessionStorage('plane-attractor-seen')` logic, change `createToggleButton()` to build a `.plane-btn` element whose parent is the toolbar (not `document.body`), swap crosshair SVG for paper-plane SVG, drop text label. Keep everything else. +- `js/analytics.js` — update selectors from `.plane-toggle` / `.theme-switcher` to `.plane-btn` / `.swatch-btn`. +- `js/destruction.js` — update exclusion selector at L59 from `.theme-switcher, .plane-toggle` to `.toolbar`. +- `js/page-transition.js` — update removeSelectors list (L39) and infraIds list (L73) and button-skip check (L81) from `.theme-switcher` / `.plane-toggle` to `.toolbar` / `#toolbar`. +- `index.html`, `casino_games.html`, `my_games.html`, `eve_of_destruction.html` — delete the `` line. The toolbar is injected by JS (single source of truth), so pages get no new markup. + +**Created:** +- `js/toolbar.js` — new file. Owns toolbar DOM creation, swatch rendering, hover-preview panel, and plane-btn adoption. Loaded before `shared.js` and `plane.js` via a new `` BEFORE the existing `shared.js` script** + +Grep each file for `` immediately above the `shared.js` tag. + +- [ ] **Step 3: Repeat for all four pages** + +Apply identical changes to: +- `index.html` +- `casino_games.html` +- `my_games.html` +- `eve_of_destruction.html` + +Do NOT modify `lost-satellite copy for games.html` (backup file). + +- [ ] **Step 4: Final grep sweep — nothing should reference the old names** + +``` +Grep pattern: theme-switcher → expect only CLAUDE.md, the backup html, plans/*, and tests/* (audit each result) +Grep pattern: plane-toggle → expect only tests/* + plans/* +Grep pattern: themeSwitcher → expect only the backup html +Grep pattern: id="themeSwitcher" → expect only the backup html +``` + +If any live file still references the old names, stop and fix. + +- [ ] **Step 5: Commit** + +``` +git add index.html casino_games.html my_games.html eve_of_destruction.html +git commit -m "html: remove theme-switcher button, load toolbar.js" +``` + +--- + +## Task 11: Verification — load + basic interaction + +**Prerequisite:** start the dev server yourself. + +- [ ] **Step 1: Ensure server is running** + +```bash +curl -s -o /dev/null -w "%{http_code}" http://localhost:8080 +``` + +If 000 / connection refused, start in the background: +```bash +npx http-server -p 8080 -c-1 +``` + +- [ ] **Step 2: Manual smoke test via Playwright** + +```bash +npx playwright-cli open http://localhost:8080/index.html +npx playwright-cli eval "() => document.querySelectorAll('.toolbar .swatch-btn').length" +# Expected: 5 +npx playwright-cli eval "() => document.documentElement.getAttribute('data-theme')" +# Expected: whatever was in localStorage, default 'bold' +``` + +- [ ] **Step 3: Click each swatch in sequence, screenshot each** + +```bash +for theme in bold brutalist retro cinematic neon; do + npx playwright-cli eval "() => window.setTheme('$theme')" + sleep 1 + npx playwright-cli screenshot --filename=toolbar-$theme.png +done +``` + +Open each screenshot visually. For each: toolbar pinned to right edge, vertically centred, five swatches visible, active swatch has accent ring, plane button visible below divider, theme-appropriate colours/radius/border. + +- [ ] **Step 4: Hover preview test (desktop)** + +```bash +npx playwright-cli eval "() => { const b = document.querySelector('.toolbar .swatch-btn:not(.active)'); b.dispatchEvent(new MouseEvent('mouseover', { bubbles: true })); return document.querySelector('.toolbar .preview-panel').classList.contains('visible'); }" +# Expected: true +``` + +- [ ] **Step 5: Plane button test** + +```bash +npx playwright-cli eval "() => document.querySelector('.toolbar .plane-btn').click()" +sleep 1 +npx playwright-cli eval "() => document.documentElement.classList.contains('plane-active')" +# Expected: true +npx playwright-cli screenshot --filename=toolbar-plane-active.png +npx playwright-cli eval "() => document.querySelector('.toolbar .plane-btn').click()" +npx playwright-cli eval "() => document.documentElement.classList.contains('plane-active')" +# Expected: false +``` + +- [ ] **Step 6: Mobile viewport test** + +```bash +# Playwright CLI doesn't set viewport on-the-fly; if needed write a tiny node script using +# playwright directly. For now, use browser devtools emulation via page.setViewportSize in a +# test file tests/toolbar-mobile-test.js if one is introduced. +``` + +For each mobile viewport (375x812, 812x375, 768x1024) manually: +- Toolbar is visible, does not overlap the card hand +- Swatch dots are smaller (18px) +- Plane button icon is 18px + +- [ ] **Step 7: Reduced motion test** + +```bash +# Emulate prefers-reduced-motion: reduce. Verify no transitions on toolbar/swatch/preview. +# Manual check — inspect computed style for .toolbar and confirm transition is 'none'. +``` + +- [ ] **Step 8: Accessibility spot-check** + +```bash +npx playwright-cli eval "() => ({ + role: document.querySelector('.toolbar').getAttribute('role'), + label: document.querySelector('.toolbar').getAttribute('aria-label'), + swatchLabels: Array.from(document.querySelectorAll('.toolbar .swatch-btn')).map(b => b.getAttribute('aria-label')), + planeLabel: document.querySelector('.toolbar .plane-btn').getAttribute('aria-label'), + planePressed: document.querySelector('.toolbar .plane-btn').getAttribute('aria-pressed') +})" +``` +Expected: `role: "toolbar"`, `label: "Site controls"`, five labels of the form "Switch to Foo theme", plane label "Toggle paper plane overlay", plane pressed "true"/"false". + +- [ ] **Step 9: Keyboard navigation** + +Tab into the toolbar, confirm each swatch and the plane button receive focus in DOM order, Enter/Space activates each. If focus outlines are invisible in some themes, add `:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }` on `.toolbar .swatch-btn, .toolbar .plane-btn` in shared.css. + +- [ ] **Step 10: Cross-page test** + +Navigate from `index.html` via a card drag to `casino_games.html`. Confirm: +- Toolbar is still visible and functional on project page +- `setTheme('retro')` on project page switches theme without errors +- Plane button on project page still toggles plane overlay +- Page transition still runs (page-transition.js's toolbar exclusion works) + +Repeat from index → `my_games.html` and index → `eve_of_destruction.html`. + +- [ ] **Step 11: Console clean** + +Open devtools console on each page; zero errors or warnings (aside from pre-existing unrelated messages). + +- [ ] **Step 12: Delete screenshot files** + +```bash +rm toolbar-*.png +``` + +- [ ] **Step 13: Commit if any follow-ups needed** + +Only if Step 9 or 11 turned up small CSS/JS fixes, commit them: +``` +git add -p +git commit -m "fix: toolbar verification follow-ups" +``` + +--- + +## Task 12: Delete the prototype + update CLAUDE.md + +**Files:** +- Delete: `toolbar-variation-d.html` +- Modify: `CLAUDE.md`, `css/CLAUDE.md`, `js/CLAUDE.md` + +- [ ] **Step 1: Delete the prototype** + +```bash +rm toolbar-variation-d.html +``` + +- [ ] **Step 2: Update root `CLAUDE.md`** + +Find the `- **Attractor (drag-me hint)**:` bullet — it describes the **card-hand** attractor and stays. But any reference to the **plane-toggle** attractor must be removed. Grep CLAUDE.md for `plane-attractor` / `plane-toggle` / `theme-switcher`. + +- [ ] **Step 3: Update `css/CLAUDE.md`** + +Remove table rows / bullets for: +- `.theme-switcher` (line 53 reference) +- `.plane-toggle` (line 83 reference) +- Responsive `plane-toggle` mentions + +Add a one-line entry for the new `.toolbar` section. + +- [ ] **Step 4: Update `js/CLAUDE.md`** + +- Under `plane.js`: remove mentions of `startBounce/stopBounce/triggerBounce`, update "Toggle button UI" section, remove attractor-related lines. +- Under `shared.js`: replace the cycling-handler description with the new `setTheme(name)` function signature and `window.setTheme` export. +- Add a new `toolbar.js` section in the dependency graph and section map with constants table + API (`window.Toolbar.syncActive`). + +- [ ] **Step 5: Commit** + +``` +git add CLAUDE.md css/CLAUDE.md js/CLAUDE.md +git rm toolbar-variation-d.html +git commit -m "docs: update CLAUDE.md for toolbar; remove prototype" +``` + +--- + +## Self-Review Checklist (run before handing off) + +- [ ] Every spec requirement mapped to a task? (HTML ✓ T10, CSS base ✓ T3, CSS per-theme ✓ T4, CSS deletion ✓ T9, JS direct-select ✓ T5/T6, JS hover-preview desktop-only ✓ T5, JS plane unchanged ✓ T7 retains toggle(), attractor retired ✓ T7, mobile ✓ T3 Step 1 responsive block, a11y ✓ T5 + T11 Step 8, grep sweep ✓ T1 + T10 Step 4, verification ✓ T11) +- [ ] No placeholders / TODO / "similar to" without code +- [ ] File paths exact, line numbers verified against current shared.css (≈2576 lines) — if the file has shifted since this plan was written, re-grep +- [ ] Type/name consistency: `window.setTheme`, `window.Toolbar.syncActive`, `#toolbar`, `#toolbar-plane-slot`, `.plane-btn`, `.swatch-btn`, `data-theme-id` — all used consistently across tasks +- [ ] Grep pre-check done in T1, grep post-check done in T9 Step 10 and T10 Step 4 +- [ ] Don't touch: card-hand attractor, plane overlay logic, destruction system internals, text-rearrange +- [ ] "No hardcoded hex in element CSS" respected via `--theme-*-accent` constants (T2). The PREVIEW object in toolbar.js is JS data, not element CSS; the prototype pattern is preserved but flagged in T5 comment. diff --git a/js/toolbar.js b/js/toolbar.js index 6f086f3..64844e0 100644 --- a/js/toolbar.js +++ b/js/toolbar.js @@ -18,9 +18,9 @@ var PREVIEW = { bold: { accent: '#ff3d00', bg: '#f4f4f4', text: '#111', sub: '#555', chips: ['#ff3d00', '#ffe100', '#111', '#f4f4f4'] }, brutalist: { accent: '#0000ff', bg: '#fff', text: '#000', sub: '#333', chips: ['#0000ff', '#ff0000', '#000', '#fff'] }, - retro: { accent: '#dc322f', bg: '#fff8eb', text: '#3b2e1a', sub: '#7a6955', chips: ['#dc322f', '#2aa198', '#3b2e1a', '#fdf6e3'] }, - cinematic: { accent: '#c9a84c', bg: '#16161e', text: '#e8e8ec', sub: '#8888a0', chips: ['#c9a84c', '#e8d5a0', '#e8e8ec', '#0d0d12'] }, - neon: { accent: '#c9f059', bg: '#111118', text: '#e0ffe0', sub: '#7aaa7a', chips: ['#c9f059', '#59b8f0', '#e0ffe0', '#0a0a0f'] } + retro: { accent: '#1A5C52', bg: '#FDF6EC', text: '#1A1A16', sub: '#6D6A5E', chips: ['#1A5C52', '#D94230', '#1A1A16', '#FDF6EC'] }, + cinematic: { accent: '#D6001C', bg: '#0A0A0A', text: '#E8E6E1', sub: '#9A9590', chips: ['#D6001C', '#E8E6E1', '#9A9590', '#0A0A0A'] }, + neon: { accent: '#c9f059', bg: '#0a0a0c', text: '#e8e6e3', sub: '#8a8a99', chips: ['#c9f059', '#59b8f0', '#e8e6e3', '#0a0a0c'] } }; function buildToolbar() { From dd814549fd3155c6f4f3780ae78cfb8487d6c092 Mon Sep 17 00:00:00 2001 From: FedG-code Date: Sat, 11 Apr 2026 19:49:50 +0100 Subject: [PATCH 12/12] Some small colour adjustments --- casino_games.html | 3 ++- css/shared.css | 3 ++- eve_of_destruction.html | 3 ++- index.html | 3 ++- js/toolbar.js | 10 +++++++--- my_games.html | 3 ++- 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/casino_games.html b/casino_games.html index 189e5e2..6064cae 100644 --- a/casino_games.html +++ b/casino_games.html @@ -20,7 +20,8 @@ diff --git a/css/shared.css b/css/shared.css index 63d11db..0aea8be 100644 --- a/css/shared.css +++ b/css/shared.css @@ -1629,7 +1629,8 @@ section { padding: 7rem 0; } text-transform: uppercase; font-size: 1.1rem; letter-spacing: -0.02em; - padding: 0.4rem clamp(1.5rem, 5vw, 3.5rem); + /* Extra right padding reserves space for the fixed toolbar (~60px wide, vertically centered) */ + padding: 0.4rem clamp(5rem, 8vw, 6.5rem) 0.4rem clamp(1.5rem, 5vw, 3.5rem); border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; diff --git a/eve_of_destruction.html b/eve_of_destruction.html index b081121..95e2029 100644 --- a/eve_of_destruction.html +++ b/eve_of_destruction.html @@ -20,7 +20,8 @@ diff --git a/index.html b/index.html index 3b02889..4f24d37 100644 --- a/index.html +++ b/index.html @@ -20,7 +20,8 @@ diff --git a/js/toolbar.js b/js/toolbar.js index 64844e0..2e2a62e 100644 --- a/js/toolbar.js +++ b/js/toolbar.js @@ -2,7 +2,11 @@ (function () { 'use strict'; - var THEMES = ['bold', 'brutalist', 'retro', 'cinematic', 'neon']; + // Desktop default is brutalist, mobile default is bold — default theme sits first in the bar. + var IS_MOBILE = window.matchMedia('(max-width: 768px)').matches; + var THEMES = IS_MOBILE + ? ['bold', 'brutalist', 'retro', 'cinematic', 'neon'] + : ['brutalist', 'bold', 'retro', 'cinematic', 'neon']; var LABELS = { bold: 'Bold', brutalist: 'Brutalist', @@ -16,11 +20,11 @@ // render them inline for speed. NOTE: if you change a --theme-*-accent in shared.css, // update the matching entry here. var PREVIEW = { - bold: { accent: '#ff3d00', bg: '#f4f4f4', text: '#111', sub: '#555', chips: ['#ff3d00', '#ffe100', '#111', '#f4f4f4'] }, + bold: { accent: '#ff3d00', bg: '#f4f4f4', text: '#111', sub: '#555', chips: ['#ff3d00', '#111', '#f4f4f4'] }, brutalist: { accent: '#0000ff', bg: '#fff', text: '#000', sub: '#333', chips: ['#0000ff', '#ff0000', '#000', '#fff'] }, retro: { accent: '#1A5C52', bg: '#FDF6EC', text: '#1A1A16', sub: '#6D6A5E', chips: ['#1A5C52', '#D94230', '#1A1A16', '#FDF6EC'] }, cinematic: { accent: '#D6001C', bg: '#0A0A0A', text: '#E8E6E1', sub: '#9A9590', chips: ['#D6001C', '#E8E6E1', '#9A9590', '#0A0A0A'] }, - neon: { accent: '#c9f059', bg: '#0a0a0c', text: '#e8e6e3', sub: '#8a8a99', chips: ['#c9f059', '#59b8f0', '#e8e6e3', '#0a0a0c'] } + neon: { accent: '#c9f059', bg: '#0a0a0c', text: '#e8e6e3', sub: '#8a8a99', chips: ['#c9f059', '#e8e6e3', '#0a0a0c'] } }; function buildToolbar() { diff --git a/my_games.html b/my_games.html index 9bb1587..0463994 100644 --- a/my_games.html +++ b/my_games.html @@ -20,7 +20,8 @@