diff --git a/lib/public/css/explorer.css b/lib/public/css/explorer.css
index 6bbec04d..8e1bdadf 100644
--- a/lib/public/css/explorer.css
+++ b/lib/public/css/explorer.css
@@ -1880,3 +1880,51 @@
}
}
+
+/* ── Light theme overrides ─────────────────────── */
+
+[data-theme="light"] .sidebar-tab {
+ color: var(--text-muted);
+}
+
+[data-theme="light"] .sidebar-tab:hover {
+ color: var(--text-bright);
+}
+
+[data-theme="light"] .sidebar-tab.active {
+ color: #0e7490;
+ background: rgba(8, 145, 178, 0.1);
+}
+
+[data-theme="light"] .file-viewer-protected-banner {
+ background: rgba(234, 179, 8, 0.12);
+}
+
+[data-theme="light"] .file-viewer-protected-banner-text {
+ color: #92400e;
+}
+
+[data-theme="light"] .file-viewer-protected-banner-unlocked {
+ color: #a16207;
+}
+
+[data-theme="light"] .file-viewer-protected-banner.is-locked {
+ background: rgba(220, 38, 38, 0.1);
+}
+
+[data-theme="light"] .file-viewer-protected-banner.is-locked .file-viewer-protected-banner-text {
+ color: #b91c1c;
+}
+
+[data-theme="light"] .file-viewer-protected-banner.is-locked .file-viewer-protected-banner-icon {
+ color: #dc2626;
+}
+
+[data-theme="light"] .file-viewer-diff-banner {
+ background: rgba(59, 130, 246, 0.08);
+}
+
+[data-theme="light"] .file-viewer-diff-banner .file-viewer-protected-banner-text,
+[data-theme="light"] .file-viewer-diff-banner {
+ color: #1d4ed8;
+}
diff --git a/lib/public/css/shell.css b/lib/public/css/shell.css
index de8315d5..76162a91 100644
--- a/lib/public/css/shell.css
+++ b/lib/public/css/shell.css
@@ -491,3 +491,152 @@
pointer-events: auto;
}
}
+
+/* ── Theme toggle dropdown ────────────────────── */
+
+.theme-toggle-menu {
+ position: relative;
+ display: inline-flex;
+}
+
+.theme-toggle-trigger {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 24px;
+ height: 24px;
+ border-radius: 6px;
+ border: none;
+ background: transparent;
+ color: var(--text-dim);
+ cursor: pointer;
+ transition: color 0.15s, background 0.15s;
+}
+
+.theme-toggle-trigger:hover {
+ color: var(--text-muted);
+ background: var(--bg-hover);
+}
+
+.theme-toggle-dropdown {
+ position: absolute;
+ top: calc(100% + 4px);
+ right: 0;
+ min-width: 120px;
+ padding: 4px;
+ background: var(--bg-content);
+ border: 1px solid var(--border);
+ border-radius: 8px;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
+ z-index: 50;
+ display: flex;
+ flex-direction: column;
+}
+
+[data-theme="light"] .theme-toggle-dropdown {
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
+}
+
+.theme-toggle-option {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ width: 100%;
+ padding: 6px 10px;
+ border: none;
+ border-radius: 5px;
+ background: transparent;
+ color: var(--text-muted);
+ font-size: 12px;
+ font-family: inherit;
+ cursor: pointer;
+ transition: color 0.15s, background 0.15s;
+}
+
+.theme-toggle-option:hover {
+ background: var(--bg-hover);
+ color: var(--text);
+}
+
+.theme-toggle-option.active {
+ color: var(--accent);
+}
+
+/* ── Light theme overrides ─────────────────────── */
+
+[data-theme="light"] .app-sidebar {
+ background:
+ linear-gradient(180deg, rgba(0, 0, 0, 0.02) 0%, rgba(0, 0, 0, 0.04) 100%),
+ var(--bg-sidebar);
+ border-right-color: rgba(0, 0, 0, 0.1);
+}
+
+[data-theme="light"] .sidebar-brand {
+ color: var(--text);
+}
+
+[data-theme="light"] .sidebar-label {
+ color: var(--text-muted);
+}
+
+[data-theme="light"] .sidebar-nav a {
+ color: var(--text);
+}
+
+[data-theme="light"] .sidebar-nav a:hover {
+ background: rgba(0, 0, 0, 0.06);
+ color: var(--text-bright);
+}
+
+[data-theme="light"] .sidebar-nav a.active {
+ background: rgba(8, 145, 178, 0.1);
+ color: #0e7490;
+}
+
+[data-theme="light"] .sidebar-nav a.active::before {
+ background: #0e7490;
+}
+
+[data-theme="light"] .brand-dropdown {
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
+}
+
+[data-theme="light"] .global-restart-banner__content {
+ background: rgba(254, 243, 199, 0.97);
+ border: 1px solid rgba(202, 138, 4, 0.5);
+ box-shadow: 0 18px 46px rgba(0, 0, 0, 0.12);
+}
+
+[data-theme="light"] .global-restart-banner__text {
+ color: #78350f;
+}
+
+[data-theme="light"] .global-restart-banner__dismiss {
+ color: #78350f;
+}
+
+[data-theme="light"] .global-restart-banner__dismiss:hover {
+ color: #451a03;
+}
+
+[data-theme="light"] .sidebar-update-btn {
+ border-color: rgba(202, 138, 4, 0.3);
+ color: #a16207;
+ background: rgba(202, 138, 4, 0.06);
+}
+
+[data-theme="light"] .sidebar-update-btn:hover {
+ background: rgba(202, 138, 4, 0.1);
+ border-color: rgba(202, 138, 4, 0.4);
+}
+
+[data-theme="light"] .sidebar-resizer:hover::after,
+[data-theme="light"] .sidebar-resizer.is-resizing::after {
+ background: rgba(8, 145, 178, 0.55);
+}
+
+@media (max-width: 768px) {
+ [data-theme="light"] .app-sidebar {
+ box-shadow: 0 8px 28px rgba(0, 0, 0, 0.15);
+ }
+}
diff --git a/lib/public/css/theme.css b/lib/public/css/theme.css
index 7cc526bc..73d76014 100644
--- a/lib/public/css/theme.css
+++ b/lib/public/css/theme.css
@@ -52,6 +52,52 @@
--status-info-border: rgba(14, 116, 144, 0.8);
}
+/* ── Light theme ─────────────────────────────────── */
+[data-theme="light"] {
+ --bg: #f8f9fb;
+ --bg-sidebar: #f0f2f5;
+ --bg-content: #ffffff;
+ --bg-hover: rgba(0, 0, 0, 0.04);
+ --bg-active: rgba(8, 145, 178, 0.08);
+ --border: rgba(0, 0, 0, 0.08);
+ --border-strong: rgba(0, 0, 0, 0.15);
+ --text: #1f2937;
+ --text-muted: #6b7280;
+ --text-dim: #9ca3af;
+ --text-bright: #111827;
+ --card-label-bright: #1f2937;
+ --accent: #0891b2;
+ --accent-dim: rgba(8, 145, 178, 0.3);
+ --accent-link: #0e7490;
+ --orange: #c2410c;
+ --comment: #9ca3af;
+ --keyword: #dc2626;
+ --string: #2563eb;
+ --number: #0284c7;
+ --panel-bg-contrast: rgba(0, 0, 0, 0.02);
+ --panel-border-contrast: rgba(0, 0, 0, 0.1);
+ --field-bg-contrast: rgba(0, 0, 0, 0.04);
+ --field-border-contrast: rgba(0, 0, 0, 0.15);
+ --overlay: rgba(0, 0, 0, 0.5);
+
+ --status-error: #dc2626;
+ --status-error-muted: #ef4444;
+ --status-error-bg: rgba(254, 226, 226, 0.95);
+ --status-error-border: rgba(252, 165, 165, 0.8);
+ --status-warning: #a16207;
+ --status-warning-muted: #854d0e;
+ --status-warning-bg: rgba(254, 249, 195, 0.95);
+ --status-warning-border: rgba(202, 138, 4, 0.5);
+ --status-success: #16a34a;
+ --status-success-muted: #22c55e;
+ --status-success-bg: rgba(220, 252, 231, 0.95);
+ --status-success-border: rgba(134, 239, 172, 0.8);
+ --status-info: #0891b2;
+ --status-info-muted: #06b6d4;
+ --status-info-bg: rgba(207, 250, 254, 0.95);
+ --status-info-border: rgba(103, 232, 249, 0.8);
+}
+
html, body { height: 100%; }
body {
@@ -62,6 +108,20 @@ body {
line-height: 1.6;
}
+.ac-logo-mark {
+ display: inline-block;
+ flex: 0 0 auto;
+ width: var(--ac-logo-width, 20px);
+ height: var(--ac-logo-height, 20px);
+ background: #00efff;
+ -webkit-mask: url("../img/logo.svg") center / contain no-repeat;
+ mask: url("../img/logo.svg") center / contain no-repeat;
+}
+
+[data-theme="light"] .ac-logo-mark {
+ background: var(--accent);
+}
+
/* Subtle grid texture overlay */
body::before {
content: '';
@@ -738,3 +798,208 @@ textarea:focus {
overflow-y: auto !important;
}
+/* ── Light theme overrides for hardcoded dark patterns ── */
+
+[data-theme="light"] body::before {
+ background-image:
+ linear-gradient(rgba(0, 0, 0, 0.03) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(0, 0, 0, 0.03) 1px, transparent 1px);
+}
+
+[data-theme="light"] .ac-history-item {
+ background: rgba(0, 0, 0, 0.02);
+}
+
+[data-theme="light"] .ac-history-summary {
+ color: var(--text);
+}
+
+[data-theme="light"] .ac-history-item[open] > .ac-history-summary .ac-history-toggle {
+ color: var(--text);
+}
+
+[data-theme="light"] .ac-surface-inset {
+ background: rgba(0, 0, 0, 0.02);
+}
+
+[data-theme="light"] .snippet-collapse-fade {
+ background: linear-gradient(to bottom, transparent 0%, rgba(255, 255, 255, 0.85) 70%);
+}
+
+[data-theme="light"] input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):focus,
+[data-theme="light"] select:focus,
+[data-theme="light"] textarea:focus {
+ border-color: rgba(0, 0, 0, 0.35);
+}
+
+[data-theme="light"] ::-webkit-scrollbar-thumb {
+ background: rgba(0, 0, 0, 0.12);
+}
+
+[data-theme="light"] .scope-btn { background: rgba(0, 0, 0, 0.03); }
+[data-theme="light"] .scope-btn-read.active,
+[data-theme="light"] .scope-btn-write.active {
+ background: rgba(0, 0, 0, 0.03);
+ color: var(--text-bright);
+ border-color: rgba(0, 0, 0, 0.35);
+}
+
+[data-theme="light"] .ac-btn-cyan {
+ border: 1px solid var(--accent-dim);
+ background: linear-gradient(180deg, rgba(8, 145, 178, 0.1) 0%, rgba(8, 145, 178, 0.05) 100%);
+ color: var(--accent);
+ box-shadow: inset 0 0 0 1px rgba(8, 145, 178, 0.08);
+}
+
+[data-theme="light"] .ac-btn-cyan:hover:not(:disabled) {
+ border-color: rgba(8, 145, 178, 0.6);
+ background: linear-gradient(180deg, rgba(8, 145, 178, 0.16) 0%, rgba(8, 145, 178, 0.08) 100%);
+ color: #065666;
+ box-shadow: inset 0 0 0 1px rgba(8, 145, 178, 0.15), 0 0 12px rgba(8, 145, 178, 0.1);
+}
+
+[data-theme="light"] .ac-btn-cyan-ghost {
+ border: 1px solid var(--accent-dim);
+ color: var(--accent);
+ background: rgba(8, 145, 178, 0.04);
+}
+
+[data-theme="light"] .ac-btn-cyan-ghost:hover {
+ border-color: rgba(8, 145, 178, 0.5);
+ color: #065666;
+ background: rgba(8, 145, 178, 0.08);
+}
+
+[data-theme="light"] .ac-btn-secondary {
+ color: var(--text);
+ background: rgba(0, 0, 0, 0.02);
+}
+
+[data-theme="light"] .ac-btn-secondary:hover:not(:disabled) {
+ border-color: rgba(0, 0, 0, 0.25);
+ color: var(--text-bright);
+ background: rgba(0, 0, 0, 0.04);
+}
+
+[data-theme="light"] .ac-btn-ghost:hover:not(:disabled) {
+ color: var(--text-bright);
+}
+
+[data-theme="light"] .ac-btn-danger {
+ border: 1px solid rgba(220, 38, 38, 0.3);
+ background: rgba(220, 38, 38, 0.06);
+ color: #dc2626;
+}
+
+[data-theme="light"] .ac-btn-danger:hover:not(:disabled) {
+ border-color: rgba(220, 38, 38, 0.5);
+ background: rgba(220, 38, 38, 0.1);
+ color: #b91c1c;
+}
+
+[data-theme="light"] .ac-btn-green {
+ border: 1px solid rgba(22, 163, 74, 0.3);
+ background: linear-gradient(180deg, rgba(22, 163, 74, 0.1) 0%, rgba(22, 163, 74, 0.05) 100%);
+ color: #16a34a;
+ box-shadow: inset 0 0 0 1px rgba(22, 163, 74, 0.08);
+}
+
+[data-theme="light"] .ac-btn-green:hover:not(:disabled) {
+ border-color: rgba(22, 163, 74, 0.5);
+ background: linear-gradient(180deg, rgba(22, 163, 74, 0.16) 0%, rgba(22, 163, 74, 0.08) 100%);
+ color: #15803d;
+ box-shadow: inset 0 0 0 1px rgba(22, 163, 74, 0.15), 0 0 12px rgba(22, 163, 74, 0.08);
+}
+
+[data-theme="light"] .ac-toggle-track {
+ background: rgba(0, 0, 0, 0.1);
+}
+
+[data-theme="light"] .ac-toggle-thumb {
+ background: #9ca3af;
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
+}
+
+[data-theme="light"] .ac-toggle-input:checked + .ac-toggle-track {
+ border-color: rgba(8, 145, 178, 0.6);
+ background: rgba(8, 145, 178, 0.12);
+ box-shadow: inset 0 0 0 1px rgba(8, 145, 178, 0.15);
+}
+
+[data-theme="light"] .ac-toggle-input:checked + .ac-toggle-track .ac-toggle-thumb {
+ background: #0891b2;
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
+}
+
+[data-theme="light"] .ac-toggle-label {
+ color: var(--text);
+}
+
+[data-theme="light"] .ac-path-card {
+ background: rgba(0, 0, 0, 0.02);
+}
+
+[data-theme="light"] .ac-path-card:hover {
+ border-color: rgba(8, 145, 178, 0.4);
+ background: rgba(8, 145, 178, 0.04);
+ box-shadow: inset 0 0 0 1px rgba(8, 145, 178, 0.08), 0 0 12px rgba(8, 145, 178, 0.06);
+}
+
+[data-theme="light"] .ac-path-card:hover .ac-path-title {
+ color: #065666;
+}
+
+[data-theme="light"] .ac-path-card:hover .ac-path-desc {
+ color: var(--text-muted);
+}
+
+[data-theme="light"] .ac-segmented-control {
+ background: rgba(0, 0, 0, 0.02);
+ border-color: rgba(0, 0, 0, 0.12);
+}
+
+[data-theme="light"] .ac-segmented-control-button:hover {
+ background: rgba(0, 0, 0, 0.04);
+}
+
+[data-theme="light"] .ac-segmented-control-button.active {
+ background: rgba(8, 145, 178, 0.12);
+ color: #0e7490;
+}
+
+[data-theme="light"] .ac-segmented-control-dark {
+ background: rgba(0, 0, 0, 0.04);
+}
+
+/* Modal and link overrides for light mode */
+[data-theme="light"] .bg-modal {
+ background: #ffffff;
+}
+
+[data-theme="light"] a[style*="color: rgba(99, 235, 255"] {
+ color: #0e7490 !important;
+}
+
+[data-theme="light"] a[style*="color: rgba(99, 235, 255"]:hover {
+ color: var(--text-bright) !important;
+}
+
+[data-theme="light"] .text-cyan-400 {
+ color: #0e7490 !important;
+}
+
+[data-theme="light"] .text-cyan-300 {
+ color: #0e7490 !important;
+}
+
+[data-theme="light"] .text-blue-400 {
+ color: #1d4ed8 !important;
+}
+
+[data-theme="light"] .text-indigo-300 {
+ color: #4338ca !important;
+}
+
+[data-theme="light"] .text-purple-400 {
+ color: #7e22ce !important;
+}
diff --git a/lib/public/js/app.js b/lib/public/js/app.js
index 3b5ecfe9..7a703b7e 100644
--- a/lib/public/js/app.js
+++ b/lib/public/js/app.js
@@ -9,6 +9,7 @@ import {
} from "wouter-preact";
import { logout } from "./lib/api.js";
import { Welcome } from "./components/welcome/index.js";
+import { ThemeToggle } from "./components/theme-toggle.js";
import { ToastContainer } from "./components/toast.js";
import { GlobalRestartBanner } from "./components/global-restart-banner.js";
import { LoadingSpinner } from "./components/loading-spinner.js";
@@ -160,6 +161,9 @@ const App = () => {
class="min-h-screen flex flex-col items-center pt-12 pb-8 px-4"
style="position: relative; z-index: 1"
>
+
+ <${ThemeToggle} />
+
<${Welcome}
onComplete=${controllerActions.handleOnboardingComplete}
acVersion=${controllerState.acVersion}
diff --git a/lib/public/js/components/icons.js b/lib/public/js/components/icons.js
index 05500ccd..abe691d1 100644
--- a/lib/public/js/components/icons.js
+++ b/lib/public/js/components/icons.js
@@ -508,6 +508,44 @@ export const EyeLineIcon = ({ className = "" }) => html`
`;
+export const SunIcon = ({ className = "" }) => html`
+
+`;
+
+export const MoonIcon = ({ className = "" }) => html`
+
+`;
+
export const FullscreenLineIcon = ({ className = "" }) => html`