zebra-report: dark/light invert-everything toggle — mirror source

This commit is contained in:
russell@unturf.com 2026-06-01 21:45:25 -04:00
parent ee9b9370d5
commit b20fe5b91e
No known key found for this signature in database

View file

@ -16,6 +16,24 @@
font-family: monospace; background: #fff; color: #000;
padding: 1rem 1.5rem; max-width: none; margin: 0 auto;
}
/* Dark mode = literal invert. CSS filter flips every painted colour on
* the page in one shot, then hue-rotate corrects what would otherwise
* read as cyan instead of orange / magenta instead of green. Re-invert
* the things we want to look RIGHT instead of merely opposite: video
* tiles, the QR canvas, and any inline raster. */
html.theme-dark body { filter: invert(1) hue-rotate(180deg); background: #fff; }
html.theme-dark video,
html.theme-dark canvas,
html.theme-dark img { filter: invert(1) hue-rotate(180deg); }
/* the theme toggle button itself sits inside the inverted area, so
* its own colours flip automatically — no extra rule needed */
.theme-toggle {
position: fixed; top: 0.6rem; right: 0.8rem; z-index: 9999;
background: #fff; color: #000; border: 1px solid #000;
padding: 0.2rem 0.55rem; font-family: monospace; font-size: 0.7rem;
cursor: pointer; line-height: 1;
}
.theme-toggle:hover { background: #f0f0f0; }
/* two-column page on desktop: left = timeline (1fr, takes remaining
* space — hosts screen shares + the running event feed), right =
* controls (kept narrow so the screen share gets maximum pixels).
@ -233,8 +251,18 @@
.mod-actions { padding-left: 5.55rem; }
}
</style>
<script>
/* apply theme before first paint to avoid the brief white flash that
* would happen if we waited for the deferred main script */
try {
if (localStorage.getItem('zebra-spaces-theme-v1') === 'dark'){
document.documentElement.classList.add('theme-dark');
}
} catch(_){}
</script>
</head>
<body>
<button id="btn-theme" class="theme-toggle" type="button" aria-label="toggle dark mode">dark</button>
<div class="page">
@ -433,6 +461,23 @@ const HANDLE_KEY = 'zebra-spaces-handle-v1';
const MUSIC_MODE_KEY = 'zebra-spaces-music-mode-v1';
const MIC_DEV_KEY = 'zebra-spaces-mic-device-v1';
const CAM_DEV_KEY = 'zebra-spaces-cam-device-v1';
const THEME_KEY = 'zebra-spaces-theme-v1';
/* theme toggle. The class is already applied pre-paint by the head
* script, so this just wires the click + keeps the button label in
* sync with the current state. */
function applyThemeLabel(){
const dark = document.documentElement.classList.contains('theme-dark');
const btn = $('btn-theme'); if (btn) btn.textContent = dark ? 'light' : 'dark';
}
applyThemeLabel();
$('btn-theme').addEventListener('click', () => {
const root = document.documentElement;
const goDark = !root.classList.contains('theme-dark');
root.classList.toggle('theme-dark', goDark);
try { localStorage.setItem(THEME_KEY, goDark ? 'dark' : 'light'); } catch(_){}
applyThemeLabel();
});
const VAULT_PREFIX = 'zspc-id-v1|';
const PBKDF2_ITER = 600000;
@ -2073,8 +2118,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');
<footer style="margin:2.2rem auto 0;font-size:0.65rem;color:#999;line-height:1.7;word-break:break-all;font-family:monospace">
<span id="pi-seal" style="color:#777;cursor:default;user-select:none" title="">page integrity</span> &nbsp;·&nbsp; built <span class="stamp-date">2026-06-02</span><br>
md5 <span class="stamp-md5">b968332fc24066fa99f88860638ec179</span><br>
sha256 <span class="stamp-sha">ba484cf6851555630d7fd6c5525d6fda834793f5e146582b8f48dff91300dac6</span><br>
md5 <span class="stamp-md5">c0f614a2ac3011c2c843104ec7d7cb4c</span><br>
sha256 <span class="stamp-sha">d75b0a8a21dcd9d1b3d8b5353283edd1a901b3712e318b9d3b6c8a0dd0cfc30a</span><br>
<span style="color:#bbb">hashes are of this page with these two fields zeroed — to verify, blank them and re-hash</span><br>
<span style="color:#bbb">one self-contained file — <strong>save a copy</strong> and verify against these hashes; point at your own servers with ?signal= and ?turncred=, or <a href="host-your-own.html" style="color:#999">host your own community</a></span>
</footer>