diff --git a/403.html b/403.html
index 41fab77..5f28ab6 100644
--- a/403.html
+++ b/403.html
@@ -5,9 +5,11 @@
Forbidden · druid520
+
+
Error 403
Forbidden
You don't have access to this page.
diff --git a/404.html b/404.html
index 177e017..38f7a19 100644
--- a/404.html
+++ b/404.html
@@ -5,9 +5,11 @@
Not found · druid520
+
+
Error 404
Not found
There's nothing at this address.
diff --git a/index.html b/index.html
index 966043d..203d1c6 100644
--- a/index.html
+++ b/index.html
@@ -6,9 +6,11 @@
druid520
+
+
druid520
Contact
diff --git a/style.css b/style.css
index fe78d48..5dc56bd 100644
--- a/style.css
+++ b/style.css
@@ -8,8 +8,9 @@
color-scheme: light dark;
}
+/* Dark palette: follows the OS unless the switch pinned a theme (data-theme on ). */
@media (prefers-color-scheme: dark) {
- :root {
+ :root:not([data-theme="light"]) {
--bg: #111;
--fg: #e6e6e6;
--muted: #999;
@@ -19,6 +20,20 @@
}
}
+:root[data-theme="dark"] {
+ --bg: #111;
+ --fg: #e6e6e6;
+ --muted: #999;
+ --line: #333;
+ --code-bg: #1c1c1c;
+ --link: #7ab7ff;
+ color-scheme: dark;
+}
+
+:root[data-theme="light"] { color-scheme: light; }
+
+[hidden] { display: none !important; }
+
* { box-sizing: border-box; }
body {
@@ -47,6 +62,22 @@ h2 {
a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }
+/* Theme switch */
+.topbar { display: flex; justify-content: flex-end; margin: -1.5rem 0 1.5rem; }
+.theme-toggle {
+ padding: .25rem .7rem;
+ background: transparent;
+ color: var(--fg);
+ border: 1px solid var(--line);
+ border-radius: 6px;
+ font-family: inherit;
+ font-size: .85rem;
+ line-height: 1.4;
+ cursor: pointer;
+}
+.theme-toggle:hover { border-color: var(--muted); }
+.theme-toggle:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }
+
/* Contact list */
dl {
display: grid;
diff --git a/theme.js b/theme.js
new file mode 100644
index 0000000..f7d2aea
--- /dev/null
+++ b/theme.js
@@ -0,0 +1,35 @@
+// Light/dark switch. The page follows the OS theme until the button is used;
+// the choice is then remembered in localStorage. Loaded in so a saved
+// theme is applied before the page paints.
+(function () {
+ var root = document.documentElement;
+ var media = window.matchMedia('(prefers-color-scheme: dark)');
+
+ try {
+ var saved = localStorage.getItem('theme');
+ if (saved === 'light' || saved === 'dark') root.dataset.theme = saved;
+ } catch (e) {}
+
+ function current() {
+ return root.dataset.theme || (media.matches ? 'dark' : 'light');
+ }
+
+ function label(btn) {
+ var next = current() === 'dark' ? 'light' : 'dark';
+ btn.textContent = next === 'dark' ? 'Dark mode' : 'Light mode';
+ btn.setAttribute('aria-label', 'Switch to ' + next + ' mode');
+ }
+
+ document.addEventListener('DOMContentLoaded', function () {
+ var btn = document.getElementById('theme-toggle');
+ if (!btn) return;
+ label(btn);
+ btn.hidden = false;
+ btn.addEventListener('click', function () {
+ root.dataset.theme = current() === 'dark' ? 'light' : 'dark';
+ try { localStorage.setItem('theme', root.dataset.theme); } catch (e) {}
+ label(btn);
+ });
+ media.addEventListener('change', function () { label(btn); });
+ });
+})();