diff --git a/apps/skills/extra/plannotator-visual-explainer/SKILL.test.ts b/apps/skills/extra/plannotator-visual-explainer/SKILL.test.ts
new file mode 100644
index 000000000..2786a55b2
--- /dev/null
+++ b/apps/skills/extra/plannotator-visual-explainer/SKILL.test.ts
@@ -0,0 +1,45 @@
+///
+///
+
+import { describe, expect, test } from "bun:test";
+import { readFileSync } from "node:fs";
+import { join } from "node:path";
+
+const themeOverride = readFileSync(
+ join(import.meta.dir, "references/theme-override.md"),
+ "utf-8",
+);
+const mermaidStart = themeOverride.indexOf("## Mermaid theming");
+const mermaidEnd = themeOverride.indexOf("\n## ", mermaidStart + 1);
+const mermaidSection = themeOverride.slice(mermaidStart, mermaidEnd);
+const exampleStart = mermaidSection.indexOf("```javascript");
+const exampleEnd = mermaidSection.indexOf("```", exampleStart + 3);
+const mermaidExample = mermaidSection.slice(exampleStart, exampleEnd);
+
+describe("plannotator-visual-explainer Mermaid theming", () => {
+ test("keeps the Mermaid theming section", () => {
+ expect(mermaidStart).toBeGreaterThan(-1);
+ expect(mermaidEnd).toBeGreaterThan(mermaidStart);
+ expect(exampleStart).toBeGreaterThan(-1);
+ expect(exampleEnd).toBeGreaterThan(exampleStart);
+ });
+
+ test("uses Mermaid-compatible literal colors", () => {
+ const literalColors = mermaidExample.match(/#[0-9a-f]{6}\b/gi) ?? [];
+ expect(mermaidExample).toContain("themeVariables");
+ expect(literalColors.length).toBeGreaterThanOrEqual(10);
+ });
+
+ test("keeps CSS color processing outside Mermaid themeVariables", () => {
+ expect(mermaidSection).not.toMatch(/\boklch\(\s*[^)]/i);
+ expect(mermaidSection).not.toMatch(/\bvar\(\s*[^)]/i);
+ expect(mermaidSection).not.toMatch(/\bcolor-mix\(\s*[^)]/i);
+ });
+
+ test("preserves OKLCH for ordinary page CSS", () => {
+ expect(themeOverride).toMatch(/--background:\s+oklch\(/);
+ expect(themeOverride).toMatch(
+ /@media \(prefers-color-scheme: dark\)[\s\S]*--background:\s+oklch\(/,
+ );
+ });
+});
diff --git a/apps/skills/extra/plannotator-visual-explainer/references/theme-override.md b/apps/skills/extra/plannotator-visual-explainer/references/theme-override.md
index f2d74cf53..4652ad449 100644
--- a/apps/skills/extra/plannotator-visual-explainer/references/theme-override.md
+++ b/apps/skills/extra/plannotator-visual-explainer/references/theme-override.md
@@ -81,18 +81,47 @@ The `--font-display` (serif) is still used for headings to create visual contras
## Mermaid theming
-When visual-explainer instructs you to set `themeVariables` in Mermaid config, use Plannotator tokens:
+Mermaid processes `themeVariables` itself and derives additional colors from them. That color-processing boundary does not accept every color syntax that browsers accept in CSS. Use Mermaid-compatible literal hex colors here instead of copying the semantic CSS token declarations above.
+
+Do not pass OKLCH color functions, CSS custom-property references such as `var()`, or `color-mix()` values directly into `themeVariables`. This restriction applies only to Mermaid's color-processing boundary. Continue using Plannotator's OKLCH custom properties and other modern color functions for ordinary page CSS.
+
+Use the same light/dark state as the page, but keep both Mermaid palettes literal. With the host-theme opt-in, Plannotator synchronizes `color-scheme`; standalone documents fall back to the operating-system preference:
```javascript
+const colorScheme = getComputedStyle(document.documentElement).colorScheme;
+const isDark = colorScheme === 'dark'
+ || (colorScheme === 'normal'
+ && window.matchMedia('(prefers-color-scheme: dark)').matches);
+
+const mermaidThemeVariables = isDark
+ ? {
+ darkMode: true,
+ primaryColor: '#9a9dff',
+ primaryTextColor: '#070b14',
+ primaryBorderColor: '#343b45',
+ lineColor: '#9da5b2',
+ secondaryColor: '#1e242e',
+ secondaryTextColor: '#dadee5',
+ tertiaryColor: '#1e242e',
+ tertiaryTextColor: '#dadee5',
+ background: '#070b14',
+ }
+ : {
+ primaryColor: '#5537eb',
+ primaryTextColor: '#ffffff',
+ primaryBorderColor: '#d4d8de',
+ lineColor: '#414853',
+ secondaryColor: '#e1e5eb',
+ secondaryTextColor: '#414853',
+ tertiaryColor: '#e1e5eb',
+ tertiaryTextColor: '#414853',
+ background: '#f3f5f9',
+ };
+
mermaid.initialize({
theme: 'base',
themeVariables: {
- primaryColor: 'oklch(0.50 0.25 280)', // --primary
- primaryTextColor: 'oklch(1 0 0)', // --primary-foreground
- primaryBorderColor: 'oklch(0.88 0.01 260)', // --border
- lineColor: 'oklch(0.40 0.02 260)', // --muted-foreground
- secondaryColor: 'oklch(0.92 0.01 260)', // --muted
- tertiaryColor: 'oklch(0.92 0.01 260)', // --muted
+ ...mermaidThemeVariables,
fontFamily: "'Inter', system-ui, sans-serif",
fontSize: '14px',
}