feat: Add immersive CRT monitor theme

- Fixed viewport CRT frame with scrollable content only
- Realistic 3D bezel with layered gradients and shadows
- Glass barrel distortion with curved edges and vignette
- Chromatic aberration (RGB fringing) at screen edges
- Animated scanlines overlay
- Bottom panel with speaker grille, brand label, power LED
- Phosphor color cycling (cyan/green/amber)
- Responsive design for all screen sizes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Daniele Linguaglossa 2026-01-22 00:45:27 +01:00
parent 5e877e83de
commit 96ad9cf782

View File

@ -21,152 +21,114 @@ Copyright:
// this is a shared object library
#define MAIN_CSS \
CSS_COMMENT("main.css - Intelligence Dossier Theme") \
CSS_COMMENT("main.css - CRT Terminal Theme") \
CSS_NEWLINE() \
CSS_COMMENT("Light mode variables") \
CSS_COMMENT("CRT Color Variables") \
CSS_SELECTOR(":root") \
CSS_PROPERTY("--bg", "#faf9f7") \
CSS_PROPERTY("--bg-surface", "#ffffff") \
CSS_PROPERTY("--bg-elevated", "#f5f3f0") \
CSS_PROPERTY("--text", "#1c1917") \
CSS_PROPERTY("--text-muted", "#78716c") \
CSS_PROPERTY("--accent", "#b45309") \
CSS_PROPERTY("--accent-hover", "#92400e") \
CSS_PROPERTY("--accent-subtle", "rgba(180,83,9,0.08)") \
CSS_PROPERTY("--border", "#e7e5e4") \
CSS_PROPERTY("--border-strong", "#d6d3d1") \
CSS_PROPERTY("--code-bg", "#f5f3f0") \
CSS_PROPERTY("--code-text", "#1c1917") \
CSS_PROPERTY("--strong", "#9a3412") \
CSS_PROPERTY("--heart", "#dc2626") \
CSS_PROPERTY("--shadow", "0 1px 2px rgba(0,0,0,0.04)") \
CSS_PROPERTY("--shadow-lg", "0 4px 12px rgba(0,0,0,0.08)") \
CSS_PROPERTY("--table-header", "#f5f3f0") \
CSS_PROPERTY("--table-row-alt", "#faf9f7") \
CSS_PROPERTY("--table-hover", "#fef3c7") \
CSS_PROPERTY("--scrollbar-bg", "#e7e5e4") \
CSS_PROPERTY("--scrollbar-thumb", "#a8a29e") \
CSS_PROPERTY("--font-display", "\"Playfair Display\", Georgia, \"Times New Roman\", serif") \
CSS_PROPERTY("--font-body", "\"Source Sans 3\", \"Segoe UI\", system-ui, sans-serif") \
CSS_PROPERTY("--font-mono", "\"JetBrains Mono\", \"Fira Code\", \"SF Mono\", monospace") \
CSS_COMMENT("Syntax highlighting - light mode") \
CSS_PROPERTY("--syn-keyword", "#a21caf") \
CSS_PROPERTY("--syn-string", "#15803d") \
CSS_PROPERTY("--syn-comment", "#78716c") \
CSS_PROPERTY("--syn-number", "#0369a1") \
CSS_PROPERTY("--syn-function", "#6d28d9") \
CSS_PROPERTY("--syn-variable", "#c2410c") \
CSS_PROPERTY("--syn-operator", "#57534e") \
CSS_PROPERTY("--syn-type", "#0e7490") \
CSS_PROPERTY("--syn-constant", "#0369a1") \
CSS_PROPERTY("--syn-builtin", "#6d28d9") \
CSS_PROPERTY("--syn-control", "#a21caf") \
CSS_PROPERTY("--syn-char", "#15803d") \
CSS_PROPERTY("--syn-special", "#c2410c") \
CSS_END_SELECTOR() \
CSS_COMMENT("Dark mode variables") \
CSS_SELECTOR("html.dark") \
CSS_PROPERTY("--bg", "#0c0a09") \
CSS_PROPERTY("--bg-surface", "#1c1917") \
CSS_PROPERTY("--bg-elevated", "#292524") \
CSS_PROPERTY("--text", "#fafaf9") \
CSS_PROPERTY("--text-muted", "#a8a29e") \
CSS_PROPERTY("--accent", "#f59e0b") \
CSS_PROPERTY("--accent-hover", "#fbbf24") \
CSS_PROPERTY("--accent-subtle", "rgba(245,158,11,0.1)") \
CSS_PROPERTY("--border", "#292524") \
CSS_PROPERTY("--border-strong", "#44403c") \
CSS_PROPERTY("--code-bg", "#1c1917") \
CSS_PROPERTY("--code-text", "#fafaf9") \
CSS_PROPERTY("--strong", "#fb923c") \
CSS_PROPERTY("--heart", "#f87171") \
CSS_PROPERTY("--shadow", "0 1px 3px rgba(0,0,0,0.4)") \
CSS_PROPERTY("--shadow-lg", "0 4px 20px rgba(0,0,0,0.5)") \
CSS_PROPERTY("--table-header", "#292524") \
CSS_PROPERTY("--table-row-alt", "#1c1917") \
CSS_PROPERTY("--table-hover", "#44403c") \
CSS_PROPERTY("--scrollbar-bg", "#1c1917") \
CSS_PROPERTY("--scrollbar-thumb", "#57534e") \
CSS_COMMENT("Syntax highlighting - dark mode") \
CSS_PROPERTY("--syn-keyword", "#fb923c") \
CSS_PROPERTY("--syn-string", "#a3e635") \
CSS_PROPERTY("--syn-comment", "#78716c") \
CSS_PROPERTY("--syn-number", "#60a5fa") \
CSS_PROPERTY("--syn-function", "#c084fc") \
CSS_PROPERTY("--syn-variable", "#fcd34d") \
CSS_PROPERTY("--syn-operator", "#d6d3d1") \
CSS_PROPERTY("--syn-type", "#22d3ee") \
CSS_PROPERTY("--syn-constant", "#60a5fa") \
CSS_PROPERTY("--syn-builtin", "#c084fc") \
CSS_PROPERTY("--syn-control", "#fb923c") \
CSS_PROPERTY("--syn-char", "#a3e635") \
CSS_PROPERTY("--syn-special", "#fbbf24") \
CSS_END_SELECTOR() \
CSS_COMMENT("Accent theme: Emerald") \
CSS_SELECTOR("html.accent-green") \
CSS_PROPERTY("--accent", "#059669") \
CSS_PROPERTY("--accent-hover", "#047857") \
CSS_PROPERTY("--accent-subtle", "rgba(5,150,105,0.08)") \
CSS_PROPERTY("--table-hover", "#d1fae5") \
CSS_END_SELECTOR() \
CSS_SELECTOR("html.dark.accent-green") \
CSS_PROPERTY("--accent", "#34d399") \
CSS_PROPERTY("--accent-hover", "#6ee7b7") \
CSS_PROPERTY("--accent-subtle", "rgba(52,211,153,0.1)") \
CSS_PROPERTY("--table-hover", "#064e3b") \
CSS_END_SELECTOR() \
CSS_COMMENT("Accent theme: Gold (default)") \
CSS_SELECTOR("html.accent-amber") \
CSS_PROPERTY("--accent", "#d97706") \
CSS_PROPERTY("--accent-hover", "#b45309") \
CSS_PROPERTY("--accent-subtle", "rgba(217,119,6,0.08)") \
CSS_PROPERTY("--table-hover", "#fef3c7") \
CSS_END_SELECTOR() \
CSS_SELECTOR("html.dark.accent-amber") \
CSS_PROPERTY("--bg", "#0a0a0a") \
CSS_PROPERTY("--bg-surface", "#0f0f0f") \
CSS_PROPERTY("--bg-elevated", "#141414") \
CSS_PROPERTY("--text", "#22d3ee") \
CSS_PROPERTY("--text-muted", "#0e7490") \
CSS_PROPERTY("--accent", "#fbbf24") \
CSS_PROPERTY("--accent-hover", "#fcd34d") \
CSS_PROPERTY("--accent-subtle", "rgba(251,191,36,0.1)") \
CSS_PROPERTY("--table-hover", "#451a03") \
CSS_PROPERTY("--border", "#164e63") \
CSS_PROPERTY("--border-strong", "#22d3ee") \
CSS_PROPERTY("--code-bg", "#0a0a0a") \
CSS_PROPERTY("--code-text", "#22d3ee") \
CSS_PROPERTY("--strong", "#fbbf24") \
CSS_PROPERTY("--heart", "#f87171") \
CSS_PROPERTY("--shadow", "0 0 20px rgba(34,211,238,0.15)") \
CSS_PROPERTY("--shadow-lg", "0 0 40px rgba(34,211,238,0.2)") \
CSS_PROPERTY("--glow", "0 0 10px rgba(34,211,238,0.5)") \
CSS_PROPERTY("--glow-strong", "0 0 20px rgba(34,211,238,0.8)") \
CSS_PROPERTY("--table-header", "#0f0f0f") \
CSS_PROPERTY("--table-row-alt", "#0a0a0a") \
CSS_PROPERTY("--table-hover", "#164e63") \
CSS_PROPERTY("--scrollbar-bg", "#0a0a0a") \
CSS_PROPERTY("--scrollbar-thumb", "#164e63") \
CSS_PROPERTY("--bezel", "#1a1a1a") \
CSS_PROPERTY("--bezel-edge", "#2a2a2a") \
CSS_PROPERTY("--screen-curve", "20px") \
CSS_PROPERTY("--font-mono", "\"JetBrains Mono\", \"Fira Code\", \"SF Mono\", Consolas, monospace") \
CSS_COMMENT("Syntax highlighting - CRT phosphor colors") \
CSS_PROPERTY("--syn-keyword", "#f472b6") \
CSS_PROPERTY("--syn-string", "#4ade80") \
CSS_PROPERTY("--syn-comment", "#0e7490") \
CSS_PROPERTY("--syn-number", "#60a5fa") \
CSS_PROPERTY("--syn-function", "#c084fc") \
CSS_PROPERTY("--syn-variable", "#fbbf24") \
CSS_PROPERTY("--syn-operator", "#22d3ee") \
CSS_PROPERTY("--syn-type", "#2dd4bf") \
CSS_PROPERTY("--syn-constant", "#60a5fa") \
CSS_PROPERTY("--syn-builtin", "#c084fc") \
CSS_PROPERTY("--syn-control", "#f472b6") \
CSS_PROPERTY("--syn-char", "#4ade80") \
CSS_PROPERTY("--syn-special", "#fb923c") \
CSS_END_SELECTOR() \
CSS_COMMENT("Accent theme: Sky") \
CSS_SELECTOR("html.accent-cyan") \
CSS_PROPERTY("--accent", "#0284c7") \
CSS_PROPERTY("--accent-hover", "#0369a1") \
CSS_PROPERTY("--accent-subtle", "rgba(2,132,199,0.08)") \
CSS_PROPERTY("--table-hover", "#e0f2fe") \
CSS_COMMENT("Phosphor theme: Green (classic)") \
CSS_SELECTOR("html.phosphor-green") \
CSS_PROPERTY("--text", "#4ade80") \
CSS_PROPERTY("--text-muted", "#166534") \
CSS_PROPERTY("--border", "#166534") \
CSS_PROPERTY("--border-strong", "#4ade80") \
CSS_PROPERTY("--code-text", "#4ade80") \
CSS_PROPERTY("--shadow", "0 0 20px rgba(74,222,128,0.15)") \
CSS_PROPERTY("--shadow-lg", "0 0 40px rgba(74,222,128,0.2)") \
CSS_PROPERTY("--glow", "0 0 10px rgba(74,222,128,0.5)") \
CSS_PROPERTY("--glow-strong", "0 0 20px rgba(74,222,128,0.8)") \
CSS_END_SELECTOR() \
CSS_SELECTOR("html.dark.accent-cyan") \
CSS_PROPERTY("--accent", "#38bdf8") \
CSS_PROPERTY("--accent-hover", "#7dd3fc") \
CSS_PROPERTY("--accent-subtle", "rgba(56,189,248,0.1)") \
CSS_PROPERTY("--table-hover", "#0c4a6e") \
CSS_END_SELECTOR() \
CSS_COMMENT("Accent theme: Rose") \
CSS_SELECTOR("html.accent-rose") \
CSS_PROPERTY("--accent", "#be123c") \
CSS_PROPERTY("--accent-hover", "#9f1239") \
CSS_PROPERTY("--accent-subtle", "rgba(190,18,60,0.08)") \
CSS_PROPERTY("--table-hover", "#ffe4e6") \
CSS_END_SELECTOR() \
CSS_SELECTOR("html.dark.accent-rose") \
CSS_PROPERTY("--accent", "#fb7185") \
CSS_PROPERTY("--accent-hover", "#fda4af") \
CSS_PROPERTY("--accent-subtle", "rgba(251,113,133,0.1)") \
CSS_PROPERTY("--table-hover", "#4c0519") \
CSS_END_SELECTOR() \
CSS_COMMENT("Accent theme: Classic Blue") \
CSS_SELECTOR("html.accent-blue") \
CSS_PROPERTY("--accent", "#2563eb") \
CSS_PROPERTY("--accent-hover", "#1d4ed8") \
CSS_PROPERTY("--accent-subtle", "rgba(37,99,235,0.08)") \
CSS_PROPERTY("--table-hover", "#dbeafe") \
CSS_END_SELECTOR() \
CSS_SELECTOR("html.dark.accent-blue") \
CSS_PROPERTY("--accent", "#60a5fa") \
CSS_PROPERTY("--accent-hover", "#93c5fd") \
CSS_PROPERTY("--accent-subtle", "rgba(96,165,250,0.1)") \
CSS_PROPERTY("--table-hover", "#1e3a5f") \
CSS_COMMENT("Phosphor theme: Amber (warm)") \
CSS_SELECTOR("html.phosphor-amber") \
CSS_PROPERTY("--text", "#fbbf24") \
CSS_PROPERTY("--text-muted", "#92400e") \
CSS_PROPERTY("--accent", "#22d3ee") \
CSS_PROPERTY("--accent-hover", "#67e8f9") \
CSS_PROPERTY("--border", "#92400e") \
CSS_PROPERTY("--border-strong", "#fbbf24") \
CSS_PROPERTY("--code-text", "#fbbf24") \
CSS_PROPERTY("--shadow", "0 0 20px rgba(251,191,36,0.15)") \
CSS_PROPERTY("--shadow-lg", "0 0 40px rgba(251,191,36,0.2)") \
CSS_PROPERTY("--glow", "0 0 10px rgba(251,191,36,0.5)") \
CSS_PROPERTY("--glow-strong", "0 0 20px rgba(251,191,36,0.8)") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Scanline Animation") \
CSS_KEYFRAMES("scanlines") \
CSS_KEYFRAME("0%") \
CSS_KEYFRAME_PROPERTY("background-position", "0 0") \
CSS_KEYFRAME_END() \
CSS_KEYFRAME("100%") \
CSS_KEYFRAME_PROPERTY("background-position", "0 4px") \
CSS_KEYFRAME_END() \
CSS_KEYFRAMES_END() \
CSS_COMMENT("CRT Flicker Animation") \
CSS_KEYFRAMES("flicker") \
CSS_KEYFRAME("0%, 100%") \
CSS_KEYFRAME_PROPERTY("opacity", "1") \
CSS_KEYFRAME_END() \
CSS_KEYFRAME("50%") \
CSS_KEYFRAME_PROPERTY("opacity", "0.98") \
CSS_KEYFRAME_END() \
CSS_KEYFRAMES_END() \
CSS_COMMENT("CRT Glow Pulse Animation") \
CSS_KEYFRAMES("glow-pulse") \
CSS_KEYFRAME("0%, 100%") \
CSS_KEYFRAME_PROPERTY("text-shadow", "0 0 5px currentColor, 0 0 10px currentColor") \
CSS_KEYFRAME_END() \
CSS_KEYFRAME("50%") \
CSS_KEYFRAME_PROPERTY("text-shadow", "0 0 10px currentColor, 0 0 20px currentColor, 0 0 30px currentColor") \
CSS_KEYFRAME_END() \
CSS_KEYFRAMES_END() \
CSS_COMMENT("Cursor Blink Animation") \
CSS_KEYFRAMES("cursor-blink") \
CSS_KEYFRAME("0%, 50%") \
CSS_KEYFRAME_PROPERTY("opacity", "1") \
CSS_KEYFRAME_END() \
CSS_KEYFRAME("51%, 100%") \
CSS_KEYFRAME_PROPERTY("opacity", "0") \
CSS_KEYFRAME_END() \
CSS_KEYFRAMES_END() \
CSS_COMMENT("Base styles") \
CSS_SELECTOR("*, *::before, *::after") \
CSS_PROPERTY("box-sizing", "border-box") \
@ -177,111 +139,248 @@ Copyright:
CSS_PROPERTY("width", "100%") \
CSS_PROPERTY("min-height", "100vh") \
CSS_PROPERTY("scroll-behavior", "smooth") \
CSS_PROPERTY("background", "#000") \
CSS_END_SELECTOR() \
CSS_SELECTOR("body") \
CSS_PROPERTY("margin", "0 auto") \
CSS_PROPERTY("padding", "0 2rem") \
CSS_PROPERTY("padding-top", "4.5rem") \
CSS_PROPERTY("max-width", "clamp(50rem, 75vw, 72rem)") \
CSS_PROPERTY("min-height", "100vh") \
CSS_PROPERTY("font-family", "var(--font-body)") \
CSS_PROPERTY("font-size", "1.0625rem") \
CSS_PROPERTY("line-height", "1.75") \
CSS_PROPERTY("background-color", "var(--bg)") \
CSS_PROPERTY("margin", "0") \
CSS_PROPERTY("padding", "0") \
CSS_PROPERTY("height", "100vh") \
CSS_PROPERTY("overflow", "hidden") \
CSS_PROPERTY("font-family", "var(--font-mono)") \
CSS_PROPERTY("font-size", "1rem") \
CSS_PROPERTY("line-height", "1.7") \
CSS_PROPERTY("background-color", "#000") \
CSS_PROPERTY("color", "var(--text)") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Monitor Frame - Fixed Viewport") \
CSS_SELECTOR(".crt-monitor") \
CSS_PROPERTY("position", "fixed") \
CSS_PROPERTY("inset", "0") \
CSS_PROPERTY("display", "flex") \
CSS_PROPERTY("flex-direction", "column") \
CSS_PROPERTY("transition", "background-color 0.25s ease, color 0.25s ease") \
CSS_PROPERTY("-webkit-font-smoothing", "antialiased") \
CSS_PROPERTY("-moz-osx-font-smoothing", "grayscale") \
CSS_PROPERTY("padding", "clamp(12px, 2vmin, 28px)") \
CSS_COMMENT("Realistic bezel - layered plastic/metal look") \
CSS_PROPERTY("background", "linear-gradient(180deg, #2a2a2a 0%, #1a1a1a 5%, #0f0f0f 50%, #1a1a1a 95%, #252525 100%)") \
CSS_PROPERTY("box-shadow", "inset 0 1px 0 rgba(255,255,255,0.05), inset 0 -1px 0 rgba(0,0,0,0.5), inset 2px 0 4px rgba(0,0,0,0.3), inset -2px 0 4px rgba(0,0,0,0.3)") \
CSS_END_SELECTOR() \
CSS_COMMENT("Top control bar") \
CSS_SELECTOR(".control-bar") \
CSS_PROPERTY("position", "fixed") \
CSS_COMMENT("Bezel top edge highlight") \
CSS_SELECTOR(".crt-monitor::before") \
CSS_PROPERTY("content", "\"\"") \
CSS_PROPERTY("position", "absolute") \
CSS_PROPERTY("top", "0") \
CSS_PROPERTY("left", "0") \
CSS_PROPERTY("right", "0") \
CSS_PROPERTY("height", "3.5rem") \
CSS_PROPERTY("background", "var(--bg-surface)") \
CSS_PROPERTY("border-bottom", "1px solid var(--border)") \
CSS_PROPERTY("height", "3px") \
CSS_PROPERTY("background", "linear-gradient(90deg, transparent 5%, rgba(60,60,60,0.8) 20%, rgba(80,80,80,0.6) 50%, rgba(60,60,60,0.8) 80%, transparent 95%)") \
CSS_PROPERTY("z-index", "10") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Screen Bezel Frame - Recessed effect") \
CSS_SELECTOR(".crt-bezel") \
CSS_PROPERTY("position", "relative") \
CSS_PROPERTY("flex", "1") \
CSS_PROPERTY("border-radius", "8px") \
CSS_PROPERTY("padding", "clamp(6px, 1vmin, 14px)") \
CSS_COMMENT("Inner bezel - recessed frame around screen") \
CSS_PROPERTY("background", "linear-gradient(145deg, #0a0a0a 0%, #151515 50%, #0a0a0a 100%)") \
CSS_PROPERTY("box-shadow", "inset 3px 3px 8px rgba(0,0,0,0.9), inset -2px -2px 6px rgba(40,40,40,0.3), 0 0 0 1px rgba(0,0,0,0.8)") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Screen Container - Curved glass effect") \
CSS_SELECTOR(".crt-screen") \
CSS_PROPERTY("position", "relative") \
CSS_PROPERTY("height", "100%") \
CSS_PROPERTY("background", "var(--bg)") \
CSS_PROPERTY("border-radius", "clamp(16px, 3vmin, 40px) / clamp(12px, 2.5vmin, 32px)") \
CSS_PROPERTY("overflow", "hidden") \
CSS_COMMENT("Barrel distortion simulation - curved shadow edges") \
CSS_PROPERTY("box-shadow", "inset 0 0 80px 20px rgba(0,0,0,0.6), inset 0 0 150px 60px rgba(0,0,0,0.25), 0 0 1px 1px rgba(0,0,0,0.9), 0 2px 8px rgba(0,0,0,0.5)") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Glass Surface - Reflection and curvature") \
CSS_SELECTOR(".crt-screen::before") \
CSS_PROPERTY("content", "\"\"") \
CSS_PROPERTY("position", "absolute") \
CSS_PROPERTY("inset", "0") \
CSS_PROPERTY("border-radius", "inherit") \
CSS_COMMENT("Multi-layer glass reflection - window light + ambient") \
CSS_PROPERTY("background", "linear-gradient(125deg, rgba(255,255,255,0.07) 0%, rgba(255,255,255,0.02) 15%, transparent 40%, transparent 60%, rgba(0,0,0,0.05) 100%), radial-gradient(ellipse 120% 80% at 25% 20%, rgba(255,255,255,0.04) 0%, transparent 50%), radial-gradient(ellipse 100% 60% at 75% 85%, rgba(0,0,0,0.08) 0%, transparent 50%)") \
CSS_PROPERTY("pointer-events", "none") \
CSS_PROPERTY("z-index", "1001") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Scanlines Overlay") \
CSS_SELECTOR(".crt-screen::after") \
CSS_PROPERTY("content", "\"\"") \
CSS_PROPERTY("position", "absolute") \
CSS_PROPERTY("inset", "0") \
CSS_PROPERTY("border-radius", "inherit") \
CSS_PROPERTY("background", "repeating-linear-gradient(0deg, rgba(0,0,0,0.12) 0px, rgba(0,0,0,0.12) 1px, transparent 1px, transparent 3px)") \
CSS_PROPERTY("pointer-events", "none") \
CSS_PROPERTY("z-index", "1000") \
CSS_PROPERTY("animation", "scanlines 0.08s linear infinite") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Curvature Vignette - Barrel distortion edges") \
CSS_SELECTOR(".crt-vignette") \
CSS_PROPERTY("position", "absolute") \
CSS_PROPERTY("inset", "0") \
CSS_PROPERTY("border-radius", "inherit") \
CSS_COMMENT("Strong edge darkening simulates barrel curvature") \
CSS_PROPERTY("background", "radial-gradient(ellipse 85% 80% at center, transparent 0%, transparent 55%, rgba(0,0,0,0.15) 70%, rgba(0,0,0,0.5) 85%, rgba(0,0,0,0.8) 100%)") \
CSS_PROPERTY("pointer-events", "none") \
CSS_PROPERTY("z-index", "999") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Chromatic Aberration Layer") \
CSS_SELECTOR(".crt-aberration") \
CSS_PROPERTY("position", "absolute") \
CSS_PROPERTY("inset", "0") \
CSS_PROPERTY("border-radius", "inherit") \
CSS_COMMENT("RGB split at edges only") \
CSS_PROPERTY("box-shadow", "inset 3px 0 12px -4px rgba(255,0,0,0.12), inset -3px 0 12px -4px rgba(0,255,255,0.12), inset 0 3px 12px -4px rgba(255,0,255,0.08), inset 0 -3px 12px -4px rgba(0,255,0,0.08)") \
CSS_PROPERTY("pointer-events", "none") \
CSS_PROPERTY("z-index", "997") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Content Scroll Container") \
CSS_SELECTOR(".crt-content") \
CSS_PROPERTY("position", "absolute") \
CSS_PROPERTY("inset", "0") \
CSS_PROPERTY("overflow-y", "auto") \
CSS_PROPERTY("overflow-x", "hidden") \
CSS_PROPERTY("scroll-behavior", "smooth") \
CSS_PROPERTY("animation", "flicker 5s infinite") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Content Inner") \
CSS_SELECTOR(".crt-content-inner") \
CSS_PROPERTY("max-width", "clamp(50rem, 85%, 72rem)") \
CSS_PROPERTY("margin", "0 auto") \
CSS_PROPERTY("padding", "2rem 2.5rem") \
CSS_END_SELECTOR() \
CSS_COMMENT("Custom scrollbar for CRT content") \
CSS_SELECTOR(".crt-content::-webkit-scrollbar") \
CSS_PROPERTY("width", "10px") \
CSS_PROPERTY("background", "rgba(0,0,0,0.3)") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".crt-content::-webkit-scrollbar-thumb") \
CSS_PROPERTY("background", "linear-gradient(180deg, var(--border) 0%, var(--border-strong) 50%, var(--border) 100%)") \
CSS_PROPERTY("border-radius", "5px") \
CSS_PROPERTY("border", "2px solid rgba(0,0,0,0.3)") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".crt-content::-webkit-scrollbar-thumb:hover") \
CSS_PROPERTY("background", "var(--text)") \
CSS_PROPERTY("box-shadow", "0 0 8px var(--text)") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Bottom Panel - Brand area") \
CSS_SELECTOR(".crt-bottom") \
CSS_PROPERTY("display", "flex") \
CSS_PROPERTY("align-items", "center") \
CSS_PROPERTY("justify-content", "space-between") \
CSS_PROPERTY("padding", "0 2rem") \
CSS_PROPERTY("z-index", "1000") \
CSS_PROPERTY("transition", "background-color 0.25s ease, border-color 0.25s ease") \
CSS_PROPERTY("padding", "clamp(8px, 1.2vmin, 16px) clamp(16px, 2vmin, 32px)") \
CSS_PROPERTY("margin-top", "clamp(6px, 1vmin, 12px)") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Power LED with realistic glow") \
CSS_SELECTOR(".crt-led") \
CSS_PROPERTY("width", "10px") \
CSS_PROPERTY("height", "10px") \
CSS_PROPERTY("background", "radial-gradient(circle at 30% 30%, #6fff6f 0%, #4ade80 40%, #22c55e 100%)") \
CSS_PROPERTY("border-radius", "50%") \
CSS_PROPERTY("box-shadow", "0 0 4px 1px #4ade80, 0 0 12px 2px rgba(74,222,128,0.6), inset 0 -2px 4px rgba(0,0,0,0.3)") \
CSS_PROPERTY("border", "1px solid rgba(0,0,0,0.5)") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Brand Label with embossed look") \
CSS_SELECTOR(".crt-brand") \
CSS_PROPERTY("font-family", "var(--font-mono)") \
CSS_PROPERTY("font-size", "clamp(0.55rem, 1.2vmin, 0.75rem)") \
CSS_PROPERTY("font-weight", "500") \
CSS_PROPERTY("color", "#3a3a3a") \
CSS_PROPERTY("letter-spacing", "0.25em") \
CSS_PROPERTY("text-transform", "uppercase") \
CSS_PROPERTY("text-shadow", "0 1px 0 rgba(255,255,255,0.05), 0 -1px 0 rgba(0,0,0,0.5)") \
CSS_END_SELECTOR() \
CSS_COMMENT("CRT Speaker Grille") \
CSS_SELECTOR(".crt-speaker") \
CSS_PROPERTY("display", "flex") \
CSS_PROPERTY("gap", "3px") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".crt-speaker span") \
CSS_PROPERTY("width", "3px") \
CSS_PROPERTY("height", "clamp(12px, 2vmin, 20px)") \
CSS_PROPERTY("background", "linear-gradient(180deg, #0a0a0a 0%, #1a1a1a 50%, #0a0a0a 100%)") \
CSS_PROPERTY("border-radius", "1px") \
CSS_PROPERTY("box-shadow", "inset 0 1px 2px rgba(0,0,0,0.8)") \
CSS_END_SELECTOR() \
CSS_COMMENT("Top control bar - Terminal style") \
CSS_SELECTOR(".control-bar") \
CSS_PROPERTY("display", "flex") \
CSS_PROPERTY("align-items", "center") \
CSS_PROPERTY("justify-content", "space-between") \
CSS_PROPERTY("padding", "1rem 0") \
CSS_PROPERTY("margin-bottom", "1.5rem") \
CSS_PROPERTY("border-bottom", "1px solid var(--border)") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".control-bar__brand") \
CSS_PROPERTY("font-family", "var(--font-display)") \
CSS_PROPERTY("font-size", "1.125rem") \
CSS_PROPERTY("font-weight", "600") \
CSS_PROPERTY("color", "var(--text)") \
CSS_PROPERTY("font-family", "var(--font-mono)") \
CSS_PROPERTY("font-size", "1rem") \
CSS_PROPERTY("font-weight", "400") \
CSS_PROPERTY("color", "var(--accent)") \
CSS_PROPERTY("text-decoration", "none") \
CSS_PROPERTY("letter-spacing", "-0.01em") \
CSS_PROPERTY("letter-spacing", "0.05em") \
CSS_PROPERTY("text-shadow", "var(--glow)") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".control-bar__brand::before") \
CSS_PROPERTY("content", "\"> \"") \
CSS_PROPERTY("color", "var(--text)") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".control-bar__brand::after") \
CSS_PROPERTY("content", "\"_\"") \
CSS_PROPERTY("animation", "cursor-blink 1s step-end infinite") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".control-bar__brand:hover") \
CSS_PROPERTY("color", "var(--accent)") \
CSS_PROPERTY("color", "var(--accent-hover)") \
CSS_PROPERTY("text-shadow", "var(--glow-strong)") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".control-bar__actions") \
CSS_PROPERTY("display", "flex") \
CSS_PROPERTY("align-items", "center") \
CSS_PROPERTY("gap", "0.5rem") \
CSS_PROPERTY("gap", "0.75rem") \
CSS_END_SELECTOR() \
CSS_COMMENT("Control buttons") \
CSS_COMMENT("Control buttons - Terminal style") \
CSS_SELECTOR(".ctrl-btn") \
CSS_PROPERTY("width", "2.25rem") \
CSS_PROPERTY("height", "2.25rem") \
CSS_PROPERTY("border-radius", "6px") \
CSS_PROPERTY("padding", "0.25rem 0.75rem") \
CSS_PROPERTY("border-radius", "0") \
CSS_PROPERTY("border", "1px solid var(--border)") \
CSS_PROPERTY("background", "transparent") \
CSS_PROPERTY("color", "var(--text-muted)") \
CSS_PROPERTY("color", "var(--text)") \
CSS_PROPERTY("cursor", "pointer") \
CSS_PROPERTY("display", "flex") \
CSS_PROPERTY("align-items", "center") \
CSS_PROPERTY("justify-content", "center") \
CSS_PROPERTY("font-size", "1rem") \
CSS_PROPERTY("font-family", "var(--font-mono)") \
CSS_PROPERTY("font-size", "0.75rem") \
CSS_PROPERTY("text-transform", "uppercase") \
CSS_PROPERTY("letter-spacing", "0.05em") \
CSS_PROPERTY("transition", "all 0.15s ease") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".ctrl-btn:hover") \
CSS_PROPERTY("background", "var(--accent-subtle)") \
CSS_PROPERTY("background", "var(--text)") \
CSS_PROPERTY("color", "var(--bg)") \
CSS_PROPERTY("box-shadow", "var(--glow)") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".ctrl-btn--accent") \
CSS_PROPERTY("border-color", "var(--accent)") \
CSS_PROPERTY("color", "var(--accent)") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".ctrl-btn--accent") \
CSS_SELECTOR(".ctrl-btn--accent:hover") \
CSS_PROPERTY("background", "var(--accent)") \
CSS_PROPERTY("border-color", "var(--accent)") \
CSS_PROPERTY("color", "var(--bg)") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".ctrl-btn .icon-sun, .ctrl-btn .icon-moon") \
CSS_PROPERTY("line-height", "1") \
CSS_PROPERTY("display", "flex") \
CSS_PROPERTY("align-items", "center") \
CSS_PROPERTY("justify-content", "center") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".ctrl-btn .icon-sun") \
CSS_PROPERTY("display", "flex") \
CSS_END_SELECTOR() \
CSS_SELECTOR(".ctrl-btn .icon-moon") \
CSS_PROPERTY("display", "none") \
CSS_END_SELECTOR() \
CSS_SELECTOR("html.dark .ctrl-btn .icon-sun") \
CSS_PROPERTY("display", "none") \
CSS_END_SELECTOR() \
CSS_SELECTOR("html.dark .ctrl-btn .icon-moon") \
CSS_PROPERTY("display", "flex") \
CSS_END_SELECTOR() \
CSS_COMMENT("Typography") \
CSS_COMMENT("Typography - Terminal style") \
CSS_SELECTOR("h1, h2, h3, h4, h5, h6") \
CSS_PROPERTY("font-family", "var(--font-display)") \
CSS_PROPERTY("font-weight", "700") \
CSS_PROPERTY("line-height", "1.25") \
CSS_PROPERTY("margin-top", "2.5rem") \
CSS_PROPERTY("font-family", "var(--font-mono)") \
CSS_PROPERTY("font-weight", "400") \
CSS_PROPERTY("line-height", "1.3") \
CSS_PROPERTY("margin-top", "2rem") \
CSS_PROPERTY("margin-bottom", "1rem") \
CSS_PROPERTY("color", "var(--text)") \
CSS_PROPERTY("clear", "both") \
CSS_PROPERTY("letter-spacing", "-0.02em") \
CSS_PROPERTY("text-shadow", "var(--glow)") \
CSS_END_SELECTOR() \
CSS_SELECTOR("h1") \
CSS_PROPERTY("font-size", "2.25rem") \
CSS_PROPERTY("font-size", "1.75rem") \
CSS_PROPERTY("text-transform", "uppercase") \
CSS_PROPERTY("letter-spacing", "0.1em") \
CSS_END_SELECTOR() \
CSS_SELECTOR("h2") \
CSS_PROPERTY("font-size", "1.75rem") \
@ -767,42 +866,55 @@ Copyright:
CSS_END_SELECTOR() \
CSS_COMMENT("Responsive - Tablet") \
"@media (max-width: 900px) {\\n" \
" body { padding: 4.5rem 1.5rem 0; }\\n" \
" .control-bar { padding: 0 1.5rem; }\\n" \
" h1.title { font-size: 2.25rem; }\\n" \
" .crt-monitor { padding: clamp(8px, 1.5vmin, 20px); }\\n" \
" .crt-bezel { padding: clamp(4px, 0.8vmin, 10px); }\\n" \
" .crt-content-inner { padding: 1.5rem 1.75rem; }\\n" \
" .crt-bottom { padding: 6px 12px; margin-top: 6px; }\\n" \
" h1.title { font-size: 1.75rem; }\\n" \
" img { max-height: 12rem; }\\n" \
" .zoomable { max-height: 18rem; }\\n" \
"}\\n" \
CSS_COMMENT("Responsive - Mobile") \
"@media (max-width: 640px) {\\n" \
" body { font-size: 1rem; padding: 4rem 1rem 0; }\\n" \
" .control-bar { padding: 0 1rem; height: 3.25rem; }\\n" \
" .control-bar__brand { font-size: 1rem; }\\n" \
" .ctrl-btn { width: 2rem; height: 2rem; font-size: 0.875rem; }\\n" \
" h1 { font-size: 1.75rem; }\\n" \
" h1.title { font-size: 1.75rem; }\\n" \
" h2 { font-size: 1.375rem; padding-right: 0; display: block; }\\n" \
" h3 { font-size: 1.125rem; }\\n" \
" img { float: none; margin: 1.5rem auto; display: block; max-height: 10rem; }\\n" \
" blockquote img { max-height: 16rem; }\\n" \
" .zoomable { max-height: 14rem; max-width: 100%; }\\n" \
" pre { font-size: 0.8125rem; padding: 1rem; }\\n" \
" code { font-size: 0.8125em; }\\n" \
" table { font-size: 0.875rem; }\\n" \
" th, td { padding: 0.625rem 0.875rem; }\\n" \
" footer { margin-top: 3rem; padding: 1.5rem 0; }\\n" \
" #TOC { padding-left: 1rem; }\\n" \
" nav#TOC ul li a { font-size: 0.875rem; }\\n" \
" nav#TOC ul ul li a { font-size: 0.8125rem; }\\n" \
" body { font-size: 0.9375rem; }\\n" \
" .crt-monitor { padding: 6px; }\\n" \
" .crt-bezel { padding: 4px; border-radius: 4px; }\\n" \
" .crt-screen { border-radius: 12px / 10px; }\\n" \
" .crt-content-inner { padding: 1rem 1.25rem; }\\n" \
" .crt-bottom { padding: 4px 8px; margin-top: 4px; }\\n" \
" .crt-led { width: 6px; height: 6px; }\\n" \
" .crt-brand { font-size: 0.5rem; letter-spacing: 0.15em; }\\n" \
" .crt-speaker span { width: 2px; height: 10px; }\\n" \
" .control-bar { padding: 0.5rem 0; margin-bottom: 0.75rem; }\\n" \
" .control-bar__brand { font-size: 0.8125rem; }\\n" \
" .ctrl-btn { padding: 0.15rem 0.4rem; font-size: 0.6rem; }\\n" \
" h1 { font-size: 1.375rem; }\\n" \
" h1.title { font-size: 1.375rem; }\\n" \
" h2 { font-size: 1.125rem; padding-right: 0; display: block; }\\n" \
" h3 { font-size: 1rem; }\\n" \
" img { float: none; margin: 1.25rem auto; display: block; max-height: 10rem; }\\n" \
" blockquote img { max-height: 14rem; }\\n" \
" .zoomable { max-height: 12rem; max-width: 100%; }\\n" \
" pre { font-size: 0.6875rem; padding: 0.75rem; }\\n" \
" code { font-size: 0.7em; }\\n" \
" table { font-size: 0.75rem; }\\n" \
" th, td { padding: 0.4rem 0.6rem; }\\n" \
" footer { margin-top: 1.5rem; padding: 0.75rem 0; font-size: 0.6875rem; }\\n" \
" #TOC { padding-left: 0.5rem; }\\n" \
" nav#TOC ul li a { font-size: 0.75rem; }\\n" \
" nav#TOC ul ul li a { font-size: 0.6875rem; }\\n" \
"}\\n" \
CSS_COMMENT("Responsive - Small mobile") \
"@media (max-width: 380px) {\\n" \
" body { font-size: 0.9375rem; padding: 3.75rem 0.75rem 0; }\\n" \
" .control-bar { padding: 0 0.75rem; height: 3rem; }\\n" \
" .control-bar__brand { font-size: 0.9375rem; }\\n" \
" h1 { font-size: 1.5rem; }\\n" \
" h1.title { font-size: 1.5rem; }\\n" \
" pre { font-size: 0.75rem; }\\n" \
" body { font-size: 0.8125rem; }\\n" \
" .crt-monitor { padding: 4px; }\\n" \
" .crt-bezel { padding: 3px; }\\n" \
" .crt-content-inner { padding: 0.75rem 1rem; }\\n" \
" .crt-bottom { display: none; }\\n" \
" .control-bar__brand { font-size: 0.6875rem; }\\n" \
" h1 { font-size: 1.125rem; }\\n" \
" h1.title { font-size: 1.125rem; }\\n" \
" pre { font-size: 0.625rem; }\\n" \
"}\\n"
#define HEAD_HTML \
@ -810,7 +922,7 @@ Copyright:
HTML_NEWLINE() \
HTML_RAWTEXT("<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>") \
HTML_NEWLINE() \
HTML_RAWTEXT("<link href=\"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Playfair+Display:wght@600;700&family=Source+Sans+3:wght@400;600&display=swap\" rel=\"stylesheet\">") \
HTML_RAWTEXT("<link href=\"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap\" rel=\"stylesheet\">") \
HTML_NEWLINE() \
HTML_RAWTEXT("<link rel=\"icon\" type=\"image/x-icon\" href=\"/favicon.ico\">") \
HTML_NEWLINE() \
@ -826,11 +938,8 @@ Copyright:
HTML_NEWLINE() \
HTML_TAG_OPEN("script", "") \
HTML_RAWTEXT("(function(){") \
HTML_RAWTEXT("var t=localStorage.getItem('theme-preference');") \
HTML_RAWTEXT("var a=localStorage.getItem('accent-preference');") \
HTML_RAWTEXT("if(!t)t=window.matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light';") \
HTML_RAWTEXT("if(t==='dark')document.documentElement.classList.add('dark');") \
HTML_RAWTEXT("if(a)document.documentElement.classList.add('accent-'+a);") \
HTML_RAWTEXT("var p=localStorage.getItem('phosphor-preference');") \
HTML_RAWTEXT("if(p)document.documentElement.classList.add('phosphor-'+p);") \
HTML_RAWTEXT("})();") \
HTML_TAG_CLOSE("script") \
HTML_NEWLINE()
@ -868,89 +977,137 @@ Copyright:
#define MAIN_JS \
HTML_RAWTEXT("(function() {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var THEME_KEY = 'theme-preference';") \
HTML_RAWTEXT(" var PHOSPHOR_KEY = 'phosphor-preference';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var ACCENT_KEY = 'accent-preference';") \
HTML_RAWTEXT(" var PHOSPHORS = ['green', 'amber'];") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var ACCENTS = ['green', 'amber', 'cyan', 'rose', 'blue'];") \
HTML_RAWTEXT(" function getPhosphorPreference() {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" function getThemePreference() {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var stored = localStorage.getItem(THEME_KEY);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" if (stored) return stored;") \
HTML_NEWLINE() \
HTML_RAWTEXT(" return window.matchMedia('(prefers-color-scheme: dark)').matches") \
HTML_NEWLINE() \
HTML_RAWTEXT(" ? 'dark' : 'light';") \
HTML_RAWTEXT(" return localStorage.getItem(PHOSPHOR_KEY);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" }") \
HTML_NEWLINE() \
HTML_RAWTEXT(" function setTheme(theme) {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" document.documentElement.classList.toggle('dark', theme === 'dark');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" localStorage.setItem(THEME_KEY, theme);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" }") \
HTML_NEWLINE() \
HTML_RAWTEXT(" function toggleTheme() {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var isDark = document.documentElement.classList.contains('dark');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" setTheme(isDark ? 'light' : 'dark');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" }") \
HTML_NEWLINE() \
HTML_RAWTEXT(" function getAccentPreference() {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" return localStorage.getItem(ACCENT_KEY);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" }") \
HTML_NEWLINE() \
HTML_RAWTEXT(" function setAccent(accent) {") \
HTML_RAWTEXT(" function setPhosphor(phosphor) {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var html = document.documentElement;") \
HTML_NEWLINE() \
HTML_RAWTEXT(" ACCENTS.forEach(function(a) {") \
HTML_RAWTEXT(" PHOSPHORS.forEach(function(p) {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" html.classList.remove('accent-' + a);") \
HTML_RAWTEXT(" html.classList.remove('phosphor-' + p);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" });") \
HTML_NEWLINE() \
HTML_RAWTEXT(" if (accent) {") \
HTML_RAWTEXT(" if (phosphor) {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" html.classList.add('accent-' + accent);") \
HTML_RAWTEXT(" html.classList.add('phosphor-' + phosphor);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" localStorage.setItem(ACCENT_KEY, accent);") \
HTML_RAWTEXT(" localStorage.setItem(PHOSPHOR_KEY, phosphor);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" } else {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" localStorage.removeItem(ACCENT_KEY);") \
HTML_RAWTEXT(" localStorage.removeItem(PHOSPHOR_KEY);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" }") \
HTML_NEWLINE() \
HTML_RAWTEXT(" }") \
HTML_NEWLINE() \
HTML_RAWTEXT(" function cycleAccent() {") \
HTML_RAWTEXT(" function cyclePhosphor() {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var current = getAccentPreference();") \
HTML_RAWTEXT(" var current = getPhosphorPreference();") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var idx = current ? ACCENTS.indexOf(current) : -1;") \
HTML_RAWTEXT(" var idx = current ? PHOSPHORS.indexOf(current) : -1;") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var nextIdx = (idx + 1) % (ACCENTS.length + 1);") \
HTML_RAWTEXT(" var nextIdx = (idx + 1) % (PHOSPHORS.length + 1);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var next = nextIdx < ACCENTS.length ? ACCENTS[nextIdx] : null;") \
HTML_RAWTEXT(" var next = nextIdx < PHOSPHORS.length ? PHOSPHORS[nextIdx] : null;") \
HTML_NEWLINE() \
HTML_RAWTEXT(" setAccent(next);") \
HTML_RAWTEXT(" setPhosphor(next);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" }") \
HTML_NEWLINE() \
HTML_RAWTEXT(" setTheme(getThemePreference());") \
HTML_RAWTEXT(" var phos = getPhosphorPreference();") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var acc = getAccentPreference();") \
HTML_RAWTEXT(" if (phos) setPhosphor(phos);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" if (acc) setAccent(acc);") \
HTML_RAWTEXT(" function createCRTWrapper() {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var monitor = document.createElement('div');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" monitor.className = 'crt-monitor';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var bezel = document.createElement('div');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" bezel.className = 'crt-bezel';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var screen = document.createElement('div');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" screen.className = 'crt-screen';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var vignette = document.createElement('div');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" vignette.className = 'crt-vignette';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var aberration = document.createElement('div');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" aberration.className = 'crt-aberration';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var content = document.createElement('div');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" content.className = 'crt-content';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var contentInner = document.createElement('div');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" contentInner.className = 'crt-content-inner';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" while (document.body.firstChild) {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" contentInner.appendChild(document.body.firstChild);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" }") \
HTML_NEWLINE() \
HTML_RAWTEXT(" content.appendChild(contentInner);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" screen.appendChild(content);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" screen.appendChild(vignette);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" screen.appendChild(aberration);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" bezel.appendChild(screen);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var bottom = document.createElement('div');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" bottom.className = 'crt-bottom';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var speaker = document.createElement('div');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" speaker.className = 'crt-speaker';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" for (var i = 0; i < 8; i++) speaker.appendChild(document.createElement('span'));") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var brand = document.createElement('div');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" brand.className = 'crt-brand';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" brand.textContent = 'DZONERZY';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var led = document.createElement('div');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" led.className = 'crt-led';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" bottom.appendChild(speaker);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" bottom.appendChild(brand);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" bottom.appendChild(led);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" monitor.appendChild(bezel);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" monitor.appendChild(bottom);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" document.body.appendChild(monitor);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" }") \
HTML_NEWLINE() \
HTML_RAWTEXT(" function createControlBar() {") \
HTML_NEWLINE() \
@ -970,54 +1127,30 @@ Copyright:
HTML_NEWLINE() \
HTML_RAWTEXT(" actions.className = 'control-bar__actions';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var accentBtn = document.createElement('button');") \
HTML_RAWTEXT(" var phosphorBtn = document.createElement('button');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" accentBtn.className = 'ctrl-btn ctrl-btn--accent';") \
HTML_RAWTEXT(" phosphorBtn.className = 'ctrl-btn ctrl-btn--accent';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" accentBtn.setAttribute('aria-label', 'Change accent color');") \
HTML_RAWTEXT(" phosphorBtn.textContent = 'P1';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" accentBtn.setAttribute('title', 'Cycle accent color (Alt+A)');") \
HTML_RAWTEXT(" phosphorBtn.setAttribute('aria-label', 'Cycle phosphor color');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" accentBtn.addEventListener('click', cycleAccent);") \
HTML_RAWTEXT(" phosphorBtn.setAttribute('title', 'Cycle phosphor: Cyan/Green/Amber (Alt+P)');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var themeBtn = document.createElement('button');") \
HTML_RAWTEXT(" phosphorBtn.addEventListener('click', cyclePhosphor);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" themeBtn.className = 'ctrl-btn';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" themeBtn.setAttribute('aria-label', 'Toggle theme');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" themeBtn.setAttribute('title', 'Toggle dark/light mode (Alt+T)');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" themeBtn.innerHTML = '<span class=\"icon-sun\">&#9728;</span>'") \
HTML_NEWLINE() \
HTML_RAWTEXT(" + '<span class=\"icon-moon\">&#9790;</span>';") \
HTML_NEWLINE() \
HTML_RAWTEXT(" themeBtn.addEventListener('click', toggleTheme);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" actions.appendChild(accentBtn);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" actions.appendChild(themeBtn);") \
HTML_RAWTEXT(" actions.appendChild(phosphorBtn);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" bar.appendChild(brand);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" bar.appendChild(actions);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" document.body.insertBefore(bar, document.body.firstChild);") \
HTML_RAWTEXT(" var crtInner = document.querySelector('.crt-content-inner');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" if (crtInner) crtInner.insertBefore(bar, crtInner.firstChild);") \
HTML_NEWLINE() \
HTML_RAWTEXT(" }") \
HTML_NEWLINE() \
HTML_RAWTEXT(" window.matchMedia('(prefers-color-scheme: dark)')") \
HTML_NEWLINE() \
HTML_RAWTEXT(" .addEventListener('change', function(e) {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" if (!localStorage.getItem(THEME_KEY)) {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" setTheme(e.matches ? 'dark' : 'light');") \
HTML_NEWLINE() \
HTML_RAWTEXT(" }") \
HTML_NEWLINE() \
HTML_RAWTEXT(" });") \
HTML_NEWLINE() \
HTML_RAWTEXT(" function setupCollapsibleTOC() {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" var toc = document.getElementById('TOC');") \
@ -1082,14 +1215,14 @@ Copyright:
HTML_NEWLINE() \
HTML_RAWTEXT(" document.addEventListener('keydown', function(e) {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" if (e.altKey && e.key === 't') toggleTheme();") \
HTML_NEWLINE() \
HTML_RAWTEXT(" if (e.altKey && e.key === 'a') cycleAccent();") \
HTML_RAWTEXT(" if (e.altKey && e.key === 'p') cyclePhosphor();") \
HTML_NEWLINE() \
HTML_RAWTEXT(" });") \
HTML_NEWLINE() \
HTML_RAWTEXT(" document.addEventListener('DOMContentLoaded', function() {") \
HTML_NEWLINE() \
HTML_RAWTEXT(" createCRTWrapper();") \
HTML_NEWLINE() \
HTML_RAWTEXT(" createControlBar();") \
HTML_NEWLINE() \
HTML_RAWTEXT(" setupCollapsibleTOC();") \