feat: add midnight theme and fix theme locations

Adds midnight dark theme, fixes broken theme variable locations, adds
clean-unused-theme-vars script, and updates RainbowThemeProvider and
related theme constants.
This commit is contained in:
EthanHealy01
2026-05-27 11:37:49 +01:00
parent 18cd2baec0
commit 7bb3024dc9
16 changed files with 1019 additions and 295 deletions
+2 -5
View File
@@ -55,10 +55,6 @@ app/core/src/main/resources/static/pdfjs/
app/core/src/main/resources/static/vendor/
# Note: Keep backend-managed files like fonts/, css/, js/, pdfjs/, etc.
# Tauri build artifacts
frontend/src-tauri/target/
frontend/editor/src-tauri/target/
# Gradle
.gradle
.gradle-home
@@ -162,6 +158,8 @@ common/build
proprietary/build
stirling-pdf/build
frontend/src-tauri/provisioner/target
frontend/src-tauri/target
frontend/src-tauri/runtime/
# Byte-compiled / optimized / DLL files
__pycache__/
@@ -178,7 +176,6 @@ venv.bak/
# Env files (secrets / local overrides). Subproject .gitignore files whitelist any committed defaults.
.env*
!.env.saas.example
# VS Code
/.vscode/**/*
+15
View File
@@ -257,6 +257,7 @@ tasks:
- task: lint
- task: format:check
- task: test
- task: theme:check-unused-vars
check:all:
desc: "Full CI quality gate"
@@ -298,3 +299,17 @@ tasks:
deps: [install]
cmds:
- node editor/scripts/generate-licenses.js
theme:clean-unused-vars:
desc: "Remove unused CSS variables from theme.css"
deps: [install]
vars:
REMOVE: '{{.REMOVE | default "false"}}'
cmds:
- node editor/scripts/clean-unused-theme-vars.js{{if eq .REMOVE "true"}} --remove{{end}} {{.CLI_ARGS}}
theme:check-unused-vars:
desc: "Fail if theme.css contains unused CSS variables"
deps: [install]
cmds:
- node editor/scripts/clean-unused-theme-vars.js --check
@@ -6905,6 +6905,7 @@ theme = "Theme"
themeDark = "Dark"
themeDescription = "Switch between light and dark mode"
themeLight = "Light"
themeMidnight = "Midnight"
title = "General"
user = "User"
@@ -0,0 +1,217 @@
#!/usr/bin/env node
/**
* Finds and optionally removes unused CSS custom properties from theme.css.
*
* Usage:
* node scripts/clean-unused-theme-vars.js # dry run: report only
* node scripts/clean-unused-theme-vars.js --check # CI mode: exit 1 if any unused
* node scripts/clean-unused-theme-vars.js --remove # remove unused declarations
* node scripts/clean-unused-theme-vars.js --verbose # show all usage counts
*/
const fs = require("fs");
const path = require("path");
const REMOVE = process.argv.includes("--remove");
const CHECK = process.argv.includes("--check");
const VERBOSE =
process.argv.includes("--verbose") || process.argv.includes("-v");
const EDITOR_ROOT = path.join(__dirname, "..");
const THEME_CSS_PATH = path.join(EDITOR_ROOT, "src/core/styles/theme.css");
const SCAN_EXTENSIONS = new Set([
".ts",
".tsx",
".css",
".js",
".jsx",
".mts",
".mjs",
]);
const SKIP_DIRS = new Set([
"node_modules",
"dist",
".git",
"target",
"coverage",
".turbo",
]);
// ─── Parse declarations ───────────────────────────────────────────────────────
function parseDeclarations(content) {
const lines = content.split("\n");
// Map from varName -> array of 0-based line indices where it is declared
const declarations = new Map();
for (let i = 0; i < lines.length; i++) {
const match = lines[i].match(/^\s*(--[\w-]+)\s*:/);
if (match) {
const name = match[1];
if (!declarations.has(name)) declarations.set(name, []);
declarations.get(name).push(i);
}
}
return declarations;
}
// ─── Scan for usages ─────────────────────────────────────────────────────────
const VAR_USAGE_RE = /var\((--[\w-]+)/g;
function collectUsagesInFile(filePath, used) {
let content;
try {
content = fs.readFileSync(filePath, "utf8");
} catch {
return;
}
VAR_USAGE_RE.lastIndex = 0;
let match;
while ((match = VAR_USAGE_RE.exec(content)) !== null) {
used.add(match[1]);
}
}
function scanDir(dir, used) {
let entries;
try {
entries = fs.readdirSync(dir, { withFileTypes: true });
} catch {
return;
}
for (const entry of entries) {
if (entry.name.startsWith(".") || SKIP_DIRS.has(entry.name)) continue;
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
scanDir(fullPath, used);
} else if (SCAN_EXTENSIONS.has(path.extname(entry.name))) {
collectUsagesInFile(fullPath, used);
}
}
}
// ─── Remove unused declarations ───────────────────────────────────────────────
function removeDeclarations(content, unusedNames) {
const lines = content.split("\n");
const filtered = [];
let skipping = false;
for (const line of lines) {
if (skipping) {
// Still consuming a multi-line value — stop when we hit the terminating semicolon
if (line.includes(";")) skipping = false;
continue;
}
const match = line.match(/^\s*(--[\w-]+)\s*:/);
if (match && unusedNames.has(match[1])) {
// If the value doesn't end on this line, skip subsequent lines too
if (!line.includes(";")) skipping = true;
continue;
}
filtered.push(line);
}
// Collapse runs of 3+ blank lines down to 2 (avoids gaps from removed blocks)
const collapsed = [];
let blankRun = 0;
for (const line of filtered) {
if (line.trim() === "") {
blankRun++;
if (blankRun <= 2) collapsed.push(line);
} else {
blankRun = 0;
collapsed.push(line);
}
}
return collapsed.join("\n");
}
// ─── Main ─────────────────────────────────────────────────────────────────────
function main() {
if (!fs.existsSync(THEME_CSS_PATH)) {
console.error("theme.css not found at:", THEME_CSS_PATH);
process.exit(1);
}
const themeCss = fs.readFileSync(THEME_CSS_PATH, "utf8");
const declarations = parseDeclarations(themeCss);
console.log(`Found ${declarations.size} declared CSS variables in theme.css`);
console.log("Scanning source files for usages...");
const used = new Set();
scanDir(EDITOR_ROOT, used);
const unused = new Set();
for (const name of declarations.keys()) {
if (!used.has(name)) unused.add(name);
}
if (VERBOSE) {
const allNames = [...declarations.keys()].sort();
for (const name of allNames) {
const status = used.has(name) ? "used " : "UNUSED";
console.log(` ${status} ${name}`);
}
console.log();
}
if (unused.size === 0) {
console.log("No unused CSS variables found.");
return;
}
const sortedUnused = [...unused].sort();
console.log(`\nUnused variables (${unused.size}):`);
for (const name of sortedUnused) {
const lineNums = declarations
.get(name)
.map((i) => i + 1)
.join(", ");
console.log(
` ${name} (line${declarations.get(name).length > 1 ? "s" : ""} ${lineNums})`,
);
}
if (CHECK) {
console.error(
"\ntheme.css has unused CSS variables. Run the following to fix:",
);
console.error("\n task frontend:theme:clean-unused-vars REMOVE=true\n");
process.exit(1);
}
if (!REMOVE) {
console.log(
"\nDry run — no changes written. Re-run with --remove to delete unused declarations.",
);
return;
}
const updated = removeDeclarations(themeCss, unused);
fs.writeFileSync(THEME_CSS_PATH, updated, "utf8");
// Count declarations removed
const declsRemoved = [...unused].reduce(
(sum, name) => sum + declarations.get(name).length,
0,
);
console.log(
`\nRemoved ${declsRemoved} declaration${declsRemoved !== 1 ? "s" : ""} (${unused.size} unique variable${unused.size !== 1 ? "s" : ""}) from theme.css`,
);
}
main();
@@ -75,7 +75,7 @@
box-shadow: var(--shadow-md);
overflow: hidden;
position: relative;
background: var(--bg-surface);
background: white;
transition:
box-shadow 0.15s ease,
transform 0.2s ease;
@@ -1,4 +1,4 @@
import { createContext, useContext, ReactNode } from "react";
import { createContext, useContext, ReactNode, useEffect } from "react";
import { MantineProvider } from "@mantine/core";
import { useRainbowTheme } from "@app/hooks/useRainbowTheme";
import { mantineTheme } from "@app/theme/mantineTheme";
@@ -36,9 +36,20 @@ interface RainbowThemeProviderProps {
export function RainbowThemeProvider({ children }: RainbowThemeProviderProps) {
const rainbowTheme = useRainbowTheme();
// Determine the Mantine color scheme
// Determine the Mantine color scheme (midnight and rainbow both use Mantine dark)
const mantineColorScheme =
rainbowTheme.themeMode === "rainbow" ? "dark" : rainbowTheme.themeMode;
rainbowTheme.themeMode === "rainbow" ||
rainbowTheme.themeMode === "midnight"
? "dark"
: rainbowTheme.themeMode;
// Apply data-color-scheme attribute to html element for CSS midnight overrides
useEffect(() => {
document.documentElement.setAttribute(
"data-color-scheme",
rainbowTheme.themeMode,
);
}, [rainbowTheme.themeMode]);
return (
<RainbowThemeContext.Provider value={rainbowTheme}>
@@ -49,7 +49,7 @@ const GeneralSection: React.FC<GeneralSectionProps> = ({
const { t } = useTranslation();
const { preferences, updatePreference } = usePreferences();
const { config } = useAppConfig();
const { toggleTheme, themeMode } = useRainbowThemeContext();
const { themeMode } = useRainbowThemeContext();
const [fileLimitInput, setFileLimitInput] = useState<number | string>(
preferences.autoUnzipFileLimit,
);
@@ -380,10 +380,10 @@ const GeneralSection: React.FC<GeneralSectionProps> = ({
</Text>
</div>
<SegmentedControl
value={themeMode === "rainbow" ? "dark" : themeMode}
onChange={(val) => {
if ((themeMode === "dark") !== (val === "dark")) toggleTheme();
}}
value={themeMode === "rainbow" ? "dark" : (themeMode as string)}
onChange={(val) =>
updatePreference("theme", val as "light" | "dark" | "midnight")
}
data={[
{
label: t("settings.general.themeLight", "Light"),
@@ -393,6 +393,10 @@ const GeneralSection: React.FC<GeneralSectionProps> = ({
label: t("settings.general.themeDark", "Dark"),
value: "dark",
},
{
label: t("settings.general.themeMidnight", "Midnight"),
value: "midnight",
},
]}
/>
</div>
@@ -295,6 +295,11 @@
flex-shrink: 0;
}
[data-mantine-color-scheme="dark"] .tool-panel__active-tool-pill {
background: transparent;
border-color: var(--border-subtle);
}
[data-mantine-color-scheme="dark"] .tool-panel__active-tool-pill-icon {
background: color-mix(
in srgb,
@@ -17,17 +17,13 @@ function CopyButton({ text }: { text: string }) {
position: "absolute",
top: 8,
right: 8,
background: copied
? "var(--mantine-color-green-0)"
: "var(--mantine-color-gray-0)",
border: "1px solid var(--mantine-color-gray-3)",
background: copied ? "var(--color-green-100)" : "var(--bg-muted)",
border: "1px solid var(--border-default)",
borderRadius: 3,
cursor: "pointer",
fontSize: "0.7em",
padding: "2px 8px",
color: copied
? "var(--mantine-color-green-7)"
: "var(--mantine-color-gray-7)",
color: copied ? "var(--color-green-700)" : "var(--text-secondary)",
}}
>
{copied ? "✓ Copied" : "Copy"}
@@ -36,6 +32,183 @@ function CopyButton({ text }: { text: string }) {
}
const components: Components = {
h1: ({ children }) => (
<h1
style={{
color: "var(--text-primary)",
borderBottom: "1px solid var(--border-default)",
paddingBottom: "0.3em",
marginTop: "1.2em",
marginBottom: "0.6em",
}}
>
{children}
</h1>
),
h2: ({ children }) => (
<h2
style={{
color: "var(--text-primary)",
borderBottom: "1px solid var(--border-subtle)",
paddingBottom: "0.2em",
marginTop: "1.1em",
marginBottom: "0.5em",
}}
>
{children}
</h2>
),
h3: ({ children }) => (
<h3
style={{
color: "var(--text-primary)",
marginTop: "1em",
marginBottom: "0.4em",
}}
>
{children}
</h3>
),
h4: ({ children }) => (
<h4
style={{
color: "var(--text-primary)",
marginTop: "0.8em",
marginBottom: "0.3em",
}}
>
{children}
</h4>
),
h5: ({ children }) => (
<h5
style={{
color: "var(--text-secondary)",
marginTop: "0.8em",
marginBottom: "0.3em",
}}
>
{children}
</h5>
),
h6: ({ children }) => (
<h6
style={{
color: "var(--text-muted)",
marginTop: "0.8em",
marginBottom: "0.3em",
}}
>
{children}
</h6>
),
p: ({ children }) => (
<p
style={{
color: "var(--text-primary)",
lineHeight: 1.7,
marginBottom: "0.75em",
}}
>
{children}
</p>
),
a: ({ children, href }) => (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
style={{
color: "var(--accent-interactive)",
textDecoration: "underline",
}}
>
{children}
</a>
),
strong: ({ children }) => (
<strong style={{ color: "var(--text-primary)", fontWeight: 600 }}>
{children}
</strong>
),
em: ({ children }) => (
<em style={{ color: "var(--text-secondary)" }}>{children}</em>
),
blockquote: ({ children }) => (
<blockquote
style={{
borderLeft: "3px solid var(--border-strong)",
margin: "0.75em 0",
padding: "4px 16px",
color: "var(--text-secondary)",
background: "var(--bg-muted)",
borderRadius: "0 4px 4px 0",
}}
>
{children}
</blockquote>
),
hr: () => (
<hr
style={{
border: "none",
borderTop: "1px solid var(--border-default)",
margin: "1.2em 0",
}}
/>
),
ul: ({ children }) => (
<ul
style={{
color: "var(--text-primary)",
paddingLeft: "1.5em",
marginBottom: "0.75em",
}}
>
{children}
</ul>
),
ol: ({ children }) => (
<ol
style={{
color: "var(--text-primary)",
paddingLeft: "1.5em",
marginBottom: "0.75em",
}}
>
{children}
</ol>
),
li: ({ children }) => (
<li
style={{
color: "var(--text-primary)",
lineHeight: 1.6,
marginBottom: "0.2em",
}}
>
{children}
</li>
),
code: ({ children, className }) => {
const isBlock = className?.startsWith("language-");
if (isBlock) return <code className={className}>{children}</code>;
return (
<code
style={{
background: "var(--bg-muted)",
color: "var(--code-kw-color)",
border: "1px solid var(--border-subtle)",
borderRadius: 3,
padding: "1px 5px",
fontSize: "0.85em",
fontFamily: "monospace",
}}
>
{children}
</code>
);
},
pre: ({ children }) => {
const codeText = React.isValidElement(children)
? String((children.props as { children?: unknown }).children ?? "")
@@ -44,12 +217,15 @@ const components: Components = {
<div style={{ position: "relative", margin: "8px 0" }}>
<pre
style={{
background: "var(--mantine-color-gray-1)",
background: "var(--bg-muted)",
color: "var(--text-primary)",
border: "1px solid var(--border-default)",
padding: "10px 52px 10px 14px",
borderRadius: 4,
overflowX: "auto",
fontSize: "0.85em",
margin: 0,
fontFamily: "monospace",
}}
>
{children}
@@ -65,18 +241,33 @@ const components: Components = {
borderCollapse: "collapse",
width: "100%",
fontSize: "0.85em",
color: "var(--text-primary)",
}}
>
{children}
</table>
</div>
),
thead: ({ children }) => (
<thead style={{ background: "var(--bg-muted)" }}>{children}</thead>
),
tbody: ({ children }) => <tbody>{children}</tbody>,
tr: ({ children }) => (
<tr
style={{
borderBottom: "1px solid var(--border-default)",
}}
>
{children}
</tr>
),
th: ({ children, style }) => (
<th
style={{
border: "1px solid var(--mantine-color-gray-3)",
border: "1px solid var(--border-default)",
padding: "6px 10px",
background: "var(--mantine-color-gray-1)",
background: "var(--bg-raised)",
color: "var(--text-primary)",
textAlign: "left",
fontWeight: 600,
whiteSpace: "nowrap",
@@ -89,8 +280,9 @@ const components: Components = {
td: ({ children, style }) => (
<td
style={{
border: "1px solid var(--mantine-color-gray-3)",
border: "1px solid var(--border-default)",
padding: "5px 10px",
color: "var(--text-primary)",
...style,
}}
>
@@ -92,8 +92,10 @@ export function TextViewer({ file, isMarkdown }: TextViewerProps) {
maxWidth: 800,
margin: "0 auto",
padding: "20px 28px",
background: "#ffffff",
background: "var(--bg-surface)",
color: "var(--text-primary)",
borderRadius: 6,
border: "1px solid var(--border-subtle)",
}}
>
{renderedMarkdown}
+1 -1
View File
@@ -1,6 +1,6 @@
// Theme constants and utilities
export type ThemeMode = "light" | "dark" | "rainbow";
export type ThemeMode = "light" | "dark" | "midnight" | "rainbow";
// Detect OS theme preference
export function getSystemTheme(): "light" | "dark" {
@@ -175,9 +175,13 @@ export function useRainbowTheme(): RainbowThemeHook {
return;
}
// Normal theme switching
const nextTheme = themeMode === "light" ? "dark" : "light";
updatePreference("theme", nextTheme);
// Normal theme switching: light → dark → midnight → light
const cycle: Record<string, ThemeMode> = {
light: "dark",
dark: "midnight",
midnight: "light",
};
updatePreference("theme", cycle[themeMode] ?? "light");
}, [themeMode, updatePreference]);
const activateRainbow = useCallback(() => {
+314 -219
View File
@@ -14,12 +14,6 @@
--spdf-compare-inline-added-bg: rgba(52, 199, 89, 0.25);
/* File Manager active file colors */
--file-active-bg: rgba(
59,
130,
246,
0.1
); /* Transparent blue for active file background */
--file-active-badge-bg: rgba(
34,
197,
@@ -43,9 +37,7 @@
--fullscreen-anim-duration-out: 0.22s;
/* Z-index constants (added in this PR) */
--z-over-fullscreen-surface: 1400;
--z-fullscreen-surface: 1200;
--z-fullscreen-favorite-star: 2;
--z-fullscreen-icon-svg: 1;
--z-toolpicker-star: 1;
@@ -162,10 +154,8 @@
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1);
/* Font weights */
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;
/* Light theme semantic colors */
--bg-surface: #ffffff;
@@ -192,22 +182,9 @@
/* Icon colors for light mode */
--icon-user-bg: #9ca3af;
--icon-user-color: #ffffff;
--icon-notifications-bg: #9ca3af;
--icon-notifications-color: #ffffff;
--icon-tools-bg: #1e88e5;
--icon-tools-color: #ffffff;
--icon-read-bg: #4caf50;
--icon-read-color: #ffffff;
--icon-sign-bg: #3ba99c;
--icon-sign-color: #ffffff;
--icon-automate-bg: #a576e3;
--icon-automate-color: #ffffff;
--icon-files-bg: #d3e7f7;
--icon-files-color: #0a8bff;
--icon-activity-bg: #d3e7f7;
--icon-activity-color: #0a8bff;
--icon-config-bg: #9ca3af;
--icon-config-color: #ffffff;
/* Colors for tooltips */
--tooltip-title-bg: #dbefff;
@@ -224,7 +201,6 @@
--tools-text-and-icon-color: var(--text-primary);
/* Tool picker sticky header variables (light mode) */
--tool-header-bg: #dbefff;
--tool-header-border: #bee2ff;
--tool-header-text: #1e88e5;
--tool-header-badge-bg: #c0ddff;
@@ -235,7 +211,6 @@
--tool-subcategory-rule-color: #e5e7eb; /* doubly lighter rule line */
--accent-interactive: #4a90e2;
--text-instruction: #4a90e2;
--text-brand: var(--color-gray-700);
--text-brand-accent: #dc2626;
/* PDF text selection colors */
@@ -251,16 +226,13 @@
--tool-panel-search-border-bottom: #eff1f4;
/* container */
--landing-paper-bg: var(--bg-surface);
--landing-inner-paper-bg: #eef8ff;
--landing-inner-paper-border: #cdeaff;
--landing-button-bg: var(--bg-surface);
--landing-button-color: var(--icon-tools-bg);
--landing-button-border: #e0f2f7;
--landing-button-hover-bg: rgb(251, 251, 251);
/* drop state */
--landing-drop-paper-bg: #e3f2fd;
--landing-drop-inner-paper-bg: #bbdefb;
--landing-drop-inner-paper-border: #90caf9;
@@ -268,36 +240,15 @@
--landing-hero-gradient: linear-gradient(135deg, #4c8bf5 0%, #3a7be8 100%);
--landing-stack-w: 224px;
--landing-stack-h: 176px;
--landing-stack-glow-bg: radial-gradient(
circle,
rgba(74, 144, 226, 0.18) 0%,
transparent 70%
);
/* landing doc stack shadows */
--landing-doc-shadow-back-idle:
0 4px 20px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.04);
--landing-doc-shadow-back-hover:
0 12px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.08);
--landing-doc-shadow-front-idle:
0 8px 30px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.06),
0 0 0 1px rgba(0, 0, 0, 0.02);
--landing-doc-shadow-front-hover:
0 18px 48px rgba(0, 0, 0, 0.18), 0 8px 20px rgba(0, 0, 0, 0.1),
0 0 0 1px rgba(0, 0, 0, 0.04);
/* landing action button shadows */
--landing-action-transition:
transform 0.28s cubic-bezier(0.4, 0, 0.2, 1),
box-shadow 0.32s cubic-bezier(0.4, 0, 0.2, 1);
--landing-action-shadow-idle:
0 6px 18px rgba(0, 0, 0, 0), 0 2px 6px rgba(0, 0, 0, 0);
--landing-action-shadow-hover:
0 6px 18px rgba(0, 0, 0, 0.14), 0 2px 6px rgba(0, 0, 0, 0.08);
--landing-action-primary-shadow-idle:
0 10px 26px rgba(58, 123, 232, 0), 0 4px 12px rgba(0, 0, 0, 0);
--landing-action-primary-shadow-hover:
0 10px 26px rgba(58, 123, 232, 0.42), 0 4px 12px rgba(0, 0, 0, 0.1);
/* selected file header colors */
--header-selected-bg: #1e88e5; /* light mode selected header matches dark */
@@ -306,18 +257,10 @@
--accordion-item-bg: #e8eaed; /* accordion item background - more distinguishable */
/* shadows */
--drop-shadow-color: rgba(0, 0, 0, 0.08);
--drop-shadow-color-strong: rgba(0, 0, 0, 0.04);
--drop-shadow-filter: drop-shadow(0 0.2rem 0.4rem rgba(0, 0, 0, 0.08))
drop-shadow(0 0.6rem 0.6rem rgba(0, 0, 0, 0.06))
drop-shadow(0 1.2rem 1rem rgba(0, 0, 0, 0.04));
/* Light mode card hover and selection */
--header-hover-bg: #3b4b6e; /* same family as selected, a touch muted for hover */
--card-selected-border: #3fafff; /* slightly more blue than dark mode header */
--checkbox-border: #2f83bf;
--checkbox-checked-bg: #3fafff;
--checkbox-tick: #ffffff;
--information-text-bg: #eaeaea;
--information-text-color: #5e5e5e;
@@ -348,15 +291,9 @@
--api-keys-button-color: #333333;
/* PDF Report Colors (always light) */
--pdf-light-header-bg: 239 246 255;
--pdf-light-accent: 59 130 246;
--pdf-light-text-primary: 30 41 59;
--pdf-light-text-muted: 100 116 139;
--pdf-light-box-bg: 248 250 252;
--pdf-light-box-border: 226 232 240;
--pdf-light-warning: 234 179 8;
--pdf-light-danger: 248 113 113;
--pdf-light-success: 34 197 94;
--pdf-light-neutral: 148 163 184;
--pdf-light-status-valid-bg: 209 250 229;
--pdf-light-status-valid-text: 6 95 70;
@@ -366,8 +303,6 @@
--pdf-light-status-invalid-text: 153 27 27;
--pdf-light-status-neutral-bg: 229 231 235;
--pdf-light-status-neutral-text: 55 65 81;
--pdf-light-report-container-bg: 249 250 251;
--pdf-light-simulated-page-bg: 255 255 255;
--pdf-light-simulated-page-text: 15 23 42;
/* Code token colors (light mode) */
@@ -376,11 +311,6 @@
--code-num-color: #4338ca; /* indigo-700 */
--code-com-color: #6b7280; /* gray-500 */
/* Compare tool specific colors - only for colors that don't have existing theme pairs */
--compare-upload-dropzone-bg: rgba(241, 245, 249, 0.45);
--compare-upload-dropzone-border: rgba(148, 163, 184, 0.6);
--compare-upload-icon-bg: rgba(148, 163, 184, 0.2);
--compare-upload-icon-color: rgba(17, 24, 39, 0.75);
--compare-upload-divider: rgba(148, 163, 184, 0.5);
/* Compare page label chip (light mode): slightly lighter than surrounding rows */
--compare-page-label-bg: var(--bg-muted);
@@ -420,12 +350,12 @@
}
[data-mantine-color-scheme="dark"] {
/* Dark theme gray scale (inverted) */
--gray-50: 17 24 39;
--gray-100: 31 35 41;
--gray-200: 42 47 54;
--gray-300: 55 65 81;
--gray-400: 75 85 99;
/* Dark theme gray scale — very dark, near-black */
--gray-50: 7 10 14;
--gray-100: 10 13 18;
--gray-200: 15 19 24;
--gray-300: 22 28 36;
--gray-400: 36 44 58;
--gray-500: 107 114 128;
--gray-600: 156 163 175;
--gray-700: 209 213 219;
@@ -433,9 +363,9 @@
--gray-900: 243 244 246;
/* Dark semantic colors for Tailwind */
--surface: 31 35 41;
--background: 42 47 54;
--border: 55 65 81;
--surface: 15 19 24;
--background: 10 13 18;
--border: 22 28 36;
/* Dark theme Mantine colors */
--color-red-50: #2d1b1b;
@@ -449,11 +379,11 @@
--color-red-800: #991b1b;
--color-red-900: #7f1d1d;
--color-gray-50: #111827;
--color-gray-100: #1f2329;
--color-gray-200: #2a2f36;
--color-gray-300: #374151;
--color-gray-400: #4b5563;
--color-gray-50: #070a0e;
--color-gray-100: #0a0d12;
--color-gray-200: #0f1318;
--color-gray-300: #161c24;
--color-gray-400: #242c3a;
--color-gray-500: #6b7280;
--color-gray-600: #9ca3af;
--color-gray-700: #d1d5db;
@@ -461,20 +391,20 @@
--color-gray-900: #f3f4f6;
/* Category colors - same as light mode for consistency */
--category-color-removal: #ef4444; /* Red for removal tools */
--category-color-security: #f59e0b; /* Orange for security tools */
--category-color-formatting: #8b5cf6; /* Purple for formatting tools */
--category-color-extraction: #06b6d4; /* Cyan for extraction tools */
--category-color-signing: #10b981; /* Green for signing tools */
--category-color-general: #3b82f6; /* Blue for general tools */
--category-color-verification: #f97316; /* Orange for verification tools */
--category-color-automation: #ec4899; /* Pink for automation tools */
--category-color-developer: #6b7280; /* Gray for developer tools */
--category-color-default: #6b7280; /* Default gray */
--category-color-removal: #ef4444;
--category-color-security: #f59e0b;
--category-color-formatting: #8b5cf6;
--category-color-extraction: #06b6d4;
--category-color-signing: #10b981;
--category-color-general: #3b82f6;
--category-color-verification: #f97316;
--category-color-automation: #ec4899;
--category-color-developer: #6b7280;
--category-color-default: #6b7280;
/* Special section colors - same as light mode for consistency */
--special-color-favorites: #ffc107; /* Yellow/gold for favorites */
--special-color-recommended: #1bb1d4; /* Cyan for recommended */
--special-color-favorites: #ffc107;
--special-color-recommended: #1bb1d4;
/* Success (green) - dark */
--color-green-50: #052e16;
@@ -501,53 +431,39 @@
--color-yellow-900: #fef9c3;
/* Dark theme semantic colors */
--bg-surface: #2a2f36;
--bg-raised: #1f2329;
--bg-muted: #1f2329;
--bg-background: #2a2f36;
--bg-toolbar: #1f2329;
--bg-file-manager: #1f2329;
--bg-file-list: #2a2f36;
--bg-surface: #0f1318;
--bg-raised: #0a0d12;
--bg-muted: #0a0d12;
--bg-background: #0a0d12;
--bg-toolbar: #0a0d12;
--bg-file-manager: #0a0d12;
--bg-file-list: #0f1318;
--btn-open-file: #0a8bff;
--text-primary: #f9fafb;
--text-secondary: #d1d5db;
--text-muted: #9ca3af;
/* Always-dark text (for use on light backgrounds like alerts) - does not change in dark mode */
--text-primary: #f0f2f5;
--text-secondary: #c5ccd6;
--text-muted: #8b96a3;
--text-always-dark: #1f2937;
--text-always-dark-muted: #6b7280;
--border-subtle: #2a2f36;
--border-default: #3a4047;
--border-strong: #4b5563;
--hover-bg: #374151;
--active-bg: #4b5563;
--border-subtle: #0f1318;
--border-default: #161c24;
--border-strong: #242c3a;
--hover-bg: #13181f;
--active-bg: #1a2030;
--automation-entry-hover-bg: var(--color-gray-200);
/* Icon colors for dark mode */
--icon-user-bg: #2a2f36;
--icon-user-color: #6e7581;
--icon-notifications-bg: #2a2f36;
--icon-notifications-color: #6e7581;
--icon-tools-bg: #4b525a;
--icon-tools-color: #eaeaea;
--icon-read-bg: #4b525a;
--icon-read-color: #eaeaea;
--icon-sign-bg: #4b525a;
--icon-sign-color: #eaeaea;
--icon-automate-bg: #4b525a;
--icon-automate-color: #eaeaea;
--icon-files-bg: #4b525a;
--icon-files-color: #eaeaea;
--icon-activity-bg: #4b525a;
--icon-activity-color: #eaeaea;
--icon-config-bg: #4b525a;
--icon-config-color: #eaeaea;
--icon-user-bg: #0f1318;
--icon-user-color: #5a6475;
--icon-tools-bg: #161c24;
--icon-tools-color: #d8dce4;
--icon-files-color: #d8dce4;
/* Inactive icon colors for dark mode */
--icon-inactive-bg: #2a2f36;
--icon-inactive-color: #6e7581;
--icon-inactive-bg: #0f1318;
--icon-inactive-color: #5a6475;
/* Dark mode tooltip colors */
--tooltip-title-bg: #4b525a;
--tooltip-title-bg: #161c24;
--tooltip-title-color: #fff;
--tooltip-header-bg: var(--bg-raised);
--tooltip-header-color: var(--text-primary);
@@ -555,7 +471,6 @@
--accent-interactive: #ffffff;
--text-instruction: #ffffff;
--text-brand: var(--color-gray-800);
--text-brand-accent: #ef4444;
/* Compare badge text colors (dark mode): lighter for readability */
@@ -563,62 +478,41 @@
--spdf-compare-added-badge-fg: var(--color-green-500);
/* container */
--landing-paper-bg: #171a1f;
--landing-inner-paper-bg: var(--bg-raised);
--landing-inner-paper-border: #2d3237;
--landing-inner-paper-border: #161c24;
/* landing dark overrides */
--landing-stack-glow-bg: radial-gradient(
circle,
rgba(30, 136, 229, 0.22) 0%,
transparent 70%
);
--landing-doc-shadow-back-idle:
0 4px 20px rgba(0, 0, 0, 0.35), 0 1px 3px rgba(0, 0, 0, 0.25);
--landing-doc-shadow-back-hover:
0 14px 44px rgba(0, 0, 0, 0.55), 0 6px 16px rgba(0, 0, 0, 0.35);
0 4px 20px rgba(0, 0, 0, 0.6), 0 1px 3px rgba(0, 0, 0, 0.4);
--landing-doc-shadow-front-idle:
0 8px 30px rgba(0, 0, 0, 0.45), 0 4px 12px rgba(0, 0, 0, 0.3),
0 8px 30px rgba(0, 0, 0, 0.7), 0 4px 12px rgba(0, 0, 0, 0.5),
0 0 0 1px rgba(255, 255, 255, 0.04);
--landing-doc-shadow-front-hover:
0 20px 52px rgba(0, 0, 0, 0.6), 0 10px 24px rgba(0, 0, 0, 0.4),
0 0 0 1px rgba(255, 255, 255, 0.06);
--landing-button-color: #ffffff;
--landing-button-hover-bg: var(--bg-raised);
/* selected file header colors for dark */
--header-selected-bg: #1e88e5;
--header-selected-fg: #ffffff;
/* file card background (dark) */
--file-card-bg: #1f2329;
--accordion-item-bg: #373d45; /* accordion item background - more distinguishable */
/* shadows */
--drop-shadow-color: rgba(255, 255, 255, 0.08);
--drop-shadow-color-strong: rgba(255, 255, 255, 0.04);
--drop-shadow-filter: drop-shadow(0 0.2rem 0.4rem rgba(200, 200, 200, 0.08))
drop-shadow(0 0.6rem 0.6rem rgba(200, 200, 200, 0.06))
drop-shadow(0 1.2rem 1rem rgba(200, 200, 200, 0.04));
--file-card-bg: #0a0d12;
--accordion-item-bg: #13181f;
/* Adjust shadows for dark mode */
--shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.4);
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.4);
--shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.5);
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.6);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.6);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.6);
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.6);
--tools-text-and-icon-color: var(--text-primary);
/* Tool picker sticky header variables (dark mode) */
--tool-header-bg: #2a2f36;
--tool-header-border: #3a4047;
--tool-header-text: #d0d6dc;
--tool-header-badge-bg: #4b525a;
--tool-header-badge-text: #ffffff;
--tool-header-border: #161c24;
--tool-header-text: #c5ccd6;
--tool-header-badge-bg: #161c24;
--tool-header-badge-text: #f0f2f5;
/* Subcategory title styling (dark mode) */
--tool-subcategory-text-color: #9ca3af; /* lighter text in dark mode as well */
--tool-subcategory-rule-color: #3a4047; /* doubly lighter (relative) line in dark */
--tool-subcategory-text-color: #8b96a3;
--tool-subcategory-rule-color: #161c24;
/* PDF text selection colors (dark mode) */
--pdf-selection-bg: rgba(96, 165, 250, 0.25);
@@ -626,74 +520,67 @@
/* Placeholder text colors (dark mode) */
--search-text-and-icon-color: #ffffff !important;
--input-bg: #4b525a;
--input-bg: #161c24;
/* Tool panel search bar background colors (dark mode) */
--tool-panel-search-bg: #1f2329;
--tool-panel-search-border-bottom: #4b525a;
--tool-panel-search-bg: #0a0d12;
--tool-panel-search-border-bottom: #242c3a;
--information-text-bg: #292e34;
--information-text-color: #ececec;
--information-text-bg: #0a0d12;
--information-text-color: #d8dce4;
/* Bulk selection panel specific colors (dark mode) */
--bulk-panel-bg: var(--bg-raised); /* dark background for parent container */
--bulk-card-bg: var(--bg-raised); /* dark background for cards */
--bulk-card-border: var(
--border-default
); /* default border for cards and buttons */
--bulk-card-hover-border: var(--border-strong); /* stronger border on hover */
--unsupported-bar-bg: #1f2329;
--unsupported-bar-border: #4b525a;
--bulk-panel-bg: var(--bg-raised);
--bulk-card-bg: var(--bg-raised);
--bulk-card-border: var(--border-default);
--bulk-card-hover-border: var(--border-strong);
--unsupported-bar-bg: #0a0d12;
--unsupported-bar-border: #242c3a;
/* Config Modal colors (dark mode) */
--modal-nav-bg: #1f2329;
--modal-nav-section-title: #9ca3af;
--modal-nav-item: #d0d6dc;
--modal-nav-bg: #0a0d12;
--modal-nav-section-title: #8b96a3;
--modal-nav-item: #c5ccd6;
--modal-nav-item-active: #0a8bff;
--modal-nav-item-active-bg: rgba(10, 139, 255, 0.15);
--modal-content-bg: #2a2f36;
--modal-content-bg: #0f1318;
--modal-header-border: rgba(255, 255, 255, 0.08);
/* Onboarding (dark mode) */
--onboarding-title: #f9fafb;
--onboarding-body: #d1d5db;
--onboarding-title: #f0f2f5;
--onboarding-body: #c5ccd6;
--onboarding-primary-button-bg: #ffffff;
--onboarding-primary-button-text: #0b1220;
--onboarding-primary-button-text: #0a0d12;
--onboarding-secondary-button-bg: transparent;
--onboarding-secondary-button-text: #e5e7eb;
--onboarding-secondary-button-border: #3a4047;
--onboarding-step-active: #e5e7eb;
--onboarding-step-inactive: #4b5563;
--onboarding-secondary-button-text: #d8dce4;
--onboarding-secondary-button-border: #161c24;
--onboarding-step-active: #d8dce4;
--onboarding-step-inactive: #242c3a;
/* API Keys section colors (dark mode) */
--api-keys-card-bg: #2a2f36;
--api-keys-card-border: #3a4047;
--api-keys-card-bg: #0f1318;
--api-keys-card-border: #161c24;
--api-keys-card-shadow: none;
--api-keys-input-bg: #1f2329;
--api-keys-input-border: #3a4047;
--api-keys-button-bg: #3a4047;
--api-keys-button-color: #d0d6dc;
--api-keys-input-bg: #0a0d12;
--api-keys-input-border: #161c24;
--api-keys-button-bg: #161c24;
--api-keys-button-color: #c5ccd6;
/* Code token colors (dark mode - Cursor-like) */
--code-kw-color: #c792ea; /* purple */
--code-str-color: #c3e88d; /* green */
--code-num-color: #f78c6c; /* orange */
--code-com-color: #697098; /* muted gray-blue */
/* Compare tool specific colors (dark mode) - only for colors that don't have existing theme pairs */
--compare-upload-dropzone-bg: rgba(31, 35, 41, 0.45);
--compare-upload-dropzone-border: rgba(75, 85, 99, 0.6);
--compare-upload-icon-bg: rgba(75, 85, 99, 0.2);
--compare-upload-icon-color: rgba(243, 244, 246, 0.75);
--compare-upload-divider: rgba(75, 85, 99, 0.5);
--code-kw-color: #c792ea;
--code-str-color: #c3e88d;
--code-num-color: #f78c6c;
--code-com-color: #697098;
/* Compare page label chip (dark mode): slightly darker than surrounding rows */
--compare-page-label-bg: #1f2329;
/* Compare page label chip (dark mode) */
--compare-page-label-bg: #0a0d12;
--compare-page-label-fg: var(--text-secondary);
/* Status indicator dot ring shadow (dark) */
--status-dot-ring: 0 0 0 2px rgba(255, 255, 255, 0.18);
/* Input element styling (dark) */
--input-bg: #4b525a;
--input-bg: #161c24;
/* Select/dropdown placeholder state (dark) */
--select-placeholder-bg: var(--mantine-color-dark-5);
@@ -709,6 +596,195 @@
--dropdown-group-label: var(--mantine-color-dark-2);
}
/* ── Midnight theme — blue-tinted dark workbench ── */
/* Applied on top of dark mode: html has both data-mantine-color-scheme="dark"
and data-color-scheme="midnight" */
[data-color-scheme="midnight"] {
--gray-50: 21 26 38;
--gray-100: 30 36 52;
--gray-200: 45 50 72;
--gray-300: 58 65 90;
--gray-400: 75 85 99;
--gray-500: 107 114 128;
--gray-600: 156 163 175;
--gray-700: 209 213 219;
--gray-800: 229 231 235;
--gray-900: 243 244 246;
--surface: 30 36 52;
--background: 21 26 38;
--border: 58 65 90;
--color-gray-50: #151a24;
--color-gray-100: #1a2030;
--color-gray-200: #1e2435;
--color-gray-300: #252836;
--color-gray-400: #2d3340;
--color-gray-500: #6b7280;
--color-gray-600: #9ca3af;
--color-gray-700: #d1d5db;
--color-gray-800: #e5e7eb;
--color-gray-900: #f3f4f6;
--category-color-general: #4b77e6;
--bg-surface: #1e2435;
--bg-raised: #1a2030;
--bg-muted: #1a2030;
--bg-background: #151a24;
--bg-toolbar: #1e2435;
--bg-file-manager: #1a2030;
--bg-file-list: #1e2435;
--btn-open-file: #4b77e6;
--text-primary: #f1f5f9;
--text-secondary: #cbd5e1;
--text-muted: #94a3b8;
--text-always-dark: #1f2937;
--text-always-dark-muted: #6b7280;
--border-subtle: #2d3340;
--border-default: #3a4152;
--border-strong: #4a5568;
--hover-bg: #252836;
--active-bg: #2d3340;
--automation-entry-hover-bg: var(--color-gray-200);
--icon-user-bg: #1e2435;
--icon-user-color: #6b7280;
--icon-tools-bg: #2d3340;
--icon-tools-color: #cbd5e1;
--icon-files-color: #4b77e6;
--icon-inactive-bg: #1e2435;
--icon-inactive-color: #6b7280;
--tooltip-title-bg: #252836;
--tooltip-title-color: #f1f5f9;
--tooltip-header-bg: #1a2030;
--tooltip-header-color: #f1f5f9;
--tooltip-border: var(--border-default);
--accent-interactive: #4b77e6;
--text-instruction: #4b77e6;
--text-brand-accent: #60a5fa;
--spdf-compare-removed-badge-fg: var(--color-red-500);
--spdf-compare-added-badge-fg: var(--color-green-500);
--landing-inner-paper-bg: #1a2030;
--landing-inner-paper-border: #3a4152;
--landing-button-bg: #252836;
--landing-button-color: #f1f5f9;
--landing-button-border: #3a4152;
--landing-drop-inner-paper-bg: #1e2435;
--landing-drop-inner-paper-border: #3a4152;
--landing-doc-shadow-back-idle:
0 4px 20px rgba(0, 0, 0, 0.45), 0 1px 3px rgba(0, 0, 0, 0.3);
--landing-doc-shadow-front-idle:
0 8px 30px rgba(0, 0, 0, 0.55), 0 4px 12px rgba(0, 0, 0, 0.4),
0 0 0 1px rgba(75, 119, 230, 0.08);
--header-selected-bg: #4b77e6;
--header-selected-fg: #ffffff;
--file-card-bg: #1a2030;
--accordion-item-bg: #252836;
--card-selected-border: #4b77e6;
--checkbox-checked-bg: #4b77e6;
--shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.5);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.5);
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.5);
--tools-text-and-icon-color: #cbd5e1;
--tool-header-border: #3a4152;
--tool-header-text: #cbd5e1;
--tool-header-badge-bg: #252836;
--tool-header-badge-text: #f1f5f9;
--tool-subcategory-text-color: #94a3b8;
--tool-subcategory-rule-color: #3a4152;
--pdf-selection-bg: rgba(75, 119, 230, 0.25);
--pdf-selection-ring: rgba(75, 119, 230, 0.28);
--search-text-and-icon-color: #f1f5f9 !important;
--input-bg: #252836;
--tool-panel-search-bg: #1a2030;
--tool-panel-search-border-bottom: #3a4152;
--information-text-bg: #1e2435;
--information-text-color: #cbd5e1;
--bulk-panel-bg: var(--bg-raised);
--bulk-card-bg: var(--bg-raised);
--bulk-card-border: var(--border-default);
--bulk-card-hover-border: var(--border-strong);
--unsupported-bar-bg: #1a2030;
--unsupported-bar-border: #3a4152;
--modal-nav-bg: #1a2030;
--modal-nav-section-title: #94a3b8;
--modal-nav-item: #cbd5e1;
--modal-nav-item-active: #4b77e6;
--modal-nav-item-active-bg: rgba(75, 119, 230, 0.18);
--modal-content-bg: #1e2435;
--modal-header-border: rgba(255, 255, 255, 0.08);
--onboarding-title: #f1f5f9;
--onboarding-body: #cbd5e1;
--onboarding-primary-button-bg: #4b77e6;
--onboarding-primary-button-text: #ffffff;
--onboarding-secondary-button-bg: transparent;
--onboarding-secondary-button-text: #cbd5e1;
--onboarding-secondary-button-border: #3a4152;
--onboarding-step-active: #cbd5e1;
--onboarding-step-inactive: #3a4152;
--api-keys-card-bg: #1e2435;
--api-keys-card-border: #3a4152;
--api-keys-card-shadow: none;
--api-keys-input-bg: #1a2030;
--api-keys-input-border: #3a4152;
--api-keys-button-bg: #252836;
--api-keys-button-color: #cbd5e1;
--code-kw-color: #7aa2f7;
--code-str-color: #9ece6a;
--code-num-color: #ff9e64;
--code-com-color: #565f89;
--compare-page-label-bg: #1a2030;
--compare-page-label-fg: var(--text-secondary);
--status-dot-ring: 0 0 0 2px rgba(75, 119, 230, 0.25);
--select-placeholder-bg: var(--mantine-color-dark-5);
--select-placeholder-text: var(--mantine-color-dark-2);
--dropdown-trigger-bg: var(--mantine-color-dark-6);
--dropdown-trigger-text: var(--mantine-color-dark-0);
--dropdown-trigger-text-disabled: var(--mantine-color-dark-1);
--dropdown-trigger-icon: var(--mantine-color-dark-2);
--dropdown-panel-bg: var(--mantine-color-dark-7);
--dropdown-panel-border: var(--mantine-color-dark-4);
--dropdown-group-label: var(--mantine-color-dark-2);
--link-hover-bg: rgba(75, 119, 230, 0.06);
--link-hover-border: rgba(75, 119, 230, 0.2);
--link-hover-shadow:
0 0 0 0.5px rgba(75, 119, 230, 0.1), 0 1px 3px rgba(75, 119, 230, 0.08);
--link-focus-ring: rgba(75, 119, 230, 0.35);
--link-toolbar-bg: rgba(21, 26, 36, 0.94);
--link-toolbar-border: rgba(255, 255, 255, 0.1);
--link-toolbar-shadow:
0 12px 40px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.3),
0 0 0 0.5px rgba(75, 119, 230, 0.08);
}
/* Dropzone drop state styling */
[data-accept] .dropzone-inner {
background-color: var(--landing-drop-inner-paper-bg) !important;
@@ -717,7 +793,6 @@
/* Plan section card borders - only override in dark mode */
[data-mantine-color-scheme="dark"] .plan-card {
--paper-border-color: rgb(158, 158, 158) !important;
}
[data-mantine-color-scheme="dark"] .plan-card [data-size="sm"] {
@@ -739,6 +814,19 @@
background-color: #1c598e !important;
}
[data-color-scheme="midnight"]
.plan-button:not(:disabled):not([data-disabled]) {
background-color: #4b77e6 !important;
}
/* Override Mantine's internal body/surface colors for midnight */
[data-color-scheme="midnight"] {
--mantine-color-body: #151a24;
--mantine-color-dark-6: #1e2435;
--mantine-color-dark-7: #151a24;
--mantine-color-dark-9: #0f1318;
}
/* Lighter grey for disabled plan buttons */
.plan-button:disabled,
.plan-button[data-disabled] {
@@ -787,12 +875,14 @@
border-radius: 8px;
}
/* Smooth transitions for theme switching */
/* Smooth transitions for theme switching - backgrounds and borders only.
Color (text) is intentionally excluded: Mantine applies the color scheme
after the first paint, so a color transition would cause text to visibly
crawl from the wrong colour on every page load. */
* {
transition:
background-color 0.2s ease,
border-color 0.2s ease,
color 0.2s ease;
border-color 0.2s ease;
}
/* ── PDF Link Overlay (viewer) ── */
:root {
@@ -992,10 +1082,15 @@
--shadow-color: rgba(15, 23, 42, 0.55);
}
[data-theme="dark"] {
[data-theme="dark"],
[data-color-scheme="dark"] {
--shadow-color: rgba(0, 0, 0, 0.75);
}
[data-color-scheme="midnight"] {
--shadow-color: rgba(0, 0, 0, 0.85);
}
/* ---- Wordmark light/dark switching (use instead of JS colorScheme checks) ---- */
.wordmark-dark-only {
display: none;
@@ -53,6 +53,19 @@ const gray: MantineColorsTuple = [
"var(--color-gray-900)",
];
const dark: MantineColorsTuple = [
"#c4c9d2",
"#9aa3b0",
"#9ca3af",
"#6b7280",
"#242c3a",
"#161c24",
"#0f1318",
"#0a0d12",
"#070a0e",
"#040507",
];
export const mantineTheme = createTheme({
// Primary color
primaryColor: "primary",
@@ -63,6 +76,7 @@ export const mantineTheme = createTheme({
green,
yellow,
gray,
dark,
},
// Spacing system - uses CSS variables
@@ -25,19 +25,9 @@
display: block;
width: 100%;
padding: 0.75rem;
border: 1px solid
color-mix(in srgb, var(--mantine-color-blue-5) 40%, var(--border-subtle));
border: 1px solid var(--border-subtle);
border-radius: 0.625rem;
background: linear-gradient(
135deg,
color-mix(
in srgb,
var(--mantine-color-blue-6) 6%,
var(--mantine-color-body)
)
0%,
var(--mantine-color-body) 100%
);
background: var(--mantine-color-body);
transition:
background 150ms ease-out,
border-color 150ms ease-out;
@@ -46,19 +36,10 @@
.agent-button:hover {
border-color: color-mix(
in srgb,
var(--mantine-color-blue-5) 65%,
var(--mantine-color-gray-4) 60%,
var(--border-subtle)
);
background: linear-gradient(
135deg,
color-mix(
in srgb,
var(--mantine-color-blue-6) 12%,
var(--mantine-color-default-hover)
)
0%,
var(--mantine-color-default-hover) 100%
);
background: var(--mantine-color-default-hover);
}
.agent-button__logo {
@@ -156,34 +137,17 @@
}
[data-mantine-color-scheme="dark"] .agent-button {
background: transparent;
border-color: color-mix(
in srgb,
var(--mantine-color-blue-7) 55%,
var(--border-subtle)
);
background: linear-gradient(
135deg,
color-mix(in srgb, var(--mantine-color-blue-9) 35%, transparent) 0%,
transparent 100%
var(--mantine-color-dark-4) 60%,
transparent
);
}
[data-mantine-color-scheme="dark"] .agent-button:hover {
border-color: color-mix(
in srgb,
var(--mantine-color-blue-5) 60%,
var(--border-subtle)
);
background: linear-gradient(
135deg,
color-mix(
in srgb,
var(--mantine-color-blue-8) 45%,
rgba(255, 255, 255, 0.04)
)
0%,
rgba(255, 255, 255, 0.04) 100%
);
border-color: var(--mantine-color-dark-3);
background: var(--mantine-color-dark-6);
}
[data-mantine-color-scheme="dark"] .agent-button__logo {
+204 -1
View File
@@ -2,7 +2,210 @@
// This file is automatically generated by scripts/generate-icons.js
// Do not edit manually - changes will be overwritten
export type MaterialSymbolIcon = '123-rounded' | 'account-circle' | 'add' | 'add-comment' | 'add-photo-alternate' | 'add-rounded' | 'admin-panel-settings' | 'admin-panel-settings-rounded' | 'analytics' | 'analytics-rounded' | 'api-rounded' | 'approval-outline-rounded' | 'arrow-back' | 'arrow-back-rounded' | 'arrow-forward' | 'article-outline-rounded' | 'assignment-outline-rounded' | 'attachment-rounded' | 'auto-awesome-rounded' | 'automation-outline' | 'backup' | 'bookmark-add-rounded' | 'branding-watermark-outline-rounded' | 'brush' | 'build-outline-rounded' | 'change-history' | 'check' | 'check-circle' | 'check-circle-outline-rounded' | 'check-circle-rounded' | 'chevron-left' | 'chevron-left-rounded' | 'chevron-right-rounded' | 'cleaning-services-outline-rounded' | 'close' | 'close-rounded' | 'cloud-upload' | 'comment' | 'compare-rounded' | 'compress' | 'content-copy' | 'content-copy-rounded' | 'content-cut-rounded' | 'content-paste-rounded' | 'credit-card' | 'crop-free-rounded' | 'crop-rounded' | 'crop-square' | 'crop-square-outline' | 'dashboard-customize-outline-rounded' | 'dashboard-customize-rounded' | 'dashboard-outline-rounded' | 'delete' | 'delete-outline-rounded' | 'delete-rounded' | 'description' | 'desktop-cloud-rounded' | 'download' | 'download-rounded' | 'edit' | 'edit-outline-rounded' | 'edit-rounded' | 'edit-square-outline-rounded' | 'edit-square-rounded' | 'error' | 'error-outline-rounded' | 'error-rounded' | 'expand-more-rounded' | 'explore-rounded' | 'extension-rounded' | 'fact-check-outline-rounded' | 'fact-check-rounded' | 'find-replace' | 'folder-rounded' | 'format-align-center' | 'format-align-left' | 'format-align-right' | 'format-color-fill-rounded' | 'format-underlined' | 'gavel-rounded' | 'gpp-maybe-outline-rounded' | 'group' | 'group-add' | 'group-rounded' | 'groups-rounded' | 'help-rounded' | 'highlight' | 'image-outline-rounded' | 'info' | 'info-outline-rounded' | 'info-rounded' | 'javascript-rounded' | 'key' | 'key-rounded' | 'keyboard-arrow-down' | 'keyboard-arrow-up' | 'keyboard-rounded' | 'language' | 'layers-clear-outline-rounded' | 'layers-outline-rounded' | 'library-add-outline-rounded' | 'link' | 'link-rounded' | 'lock' | 'lock-open' | 'lock-open-right-outline-rounded' | 'lock-outline' | 'login' | 'logout' | 'logout-rounded' | 'looks-one-outline-rounded' | 'mail-rounded' | 'match-word-rounded' | 'material-symbols:pause-rounded' | 'material-symbols:play-arrow-rounded' | 'menu-book-outline-rounded' | 'menu-book-rounded' | 'more-vert' | 'move-down-rounded' | 'opacity' | 'open-in-new-rounded' | 'palette-outline' | 'pan-tool-rounded' | 'password-rounded' | 'pause-rounded' | 'person' | 'person-add' | 'person-add-rounded' | 'person-check' | 'person-off' | 'person-remove' | 'person-rounded' | 'photo-library-outline-rounded' | 'picture-as-pdf-rounded' | 'pin-end' | 'play-arrow-rounded' | 'play-circle' | 'preview-off-rounded' | 'qr-code-rounded' | 'quick-reference-all-outline-rounded' | 'radio-button-unchecked' | 'redo' | 'refresh' | 'refresh-rounded' | 'remove-moderator-outline-rounded' | 'remove-selection-rounded' | 'rocket-launch' | 'rotate-left' | 'rotate-right' | 'rotate-right-rounded' | 'save' | 'save-rounded' | 'scan-delete-outline-rounded' | 'scan-delete-rounded' | 'scanner-outline-rounded' | 'schedule-outline-rounded' | 'search' | 'search-rounded' | 'security' | 'select-all' | 'send-rounded' | 'settings-rounded' | 'shield-lock' | 'shield-rounded' | 'show-chart' | 'signature-rounded' | 'speed' | 'star' | 'star-rounded' | 'sticky-note-2' | 'storage-rounded' | 'strikethrough-s' | 'subdirectory-arrow-right-rounded' | 'swap-horiz' | 'sync-alt-rounded' | 'system-update-alt-rounded' | 'text-fields' | 'text-fields-rounded' | 'thread-unread-rounded' | 'toc-rounded' | 'touch-app-rounded' | 'tune-rounded' | 'undo' | 'unfold-less' | 'unfold-more' | 'upload-file-rounded' | 'upload-rounded' | 'verified-outline-rounded' | 'verified-user-outline' | 'verified-user-rounded' | 'view-carousel-rounded' | 'view-list' | 'visibility' | 'visibility-off-outline-rounded' | 'visibility-rounded' | 'vital-signs-rounded' | 'warning' | 'warning-rounded' | 'workspace-premium-outline-rounded' | 'workspace-premium-rounded' | 'zoom-in' | 'zoom-in-map-rounded' | 'zoom-out';
export type MaterialSymbolIcon =
| "123-rounded"
| "account-circle"
| "add"
| "add-comment"
| "add-photo-alternate"
| "add-rounded"
| "admin-panel-settings"
| "admin-panel-settings-rounded"
| "analytics"
| "analytics-rounded"
| "api-rounded"
| "approval-outline-rounded"
| "arrow-back"
| "arrow-back-rounded"
| "arrow-forward"
| "article-outline-rounded"
| "assignment-outline-rounded"
| "attachment-rounded"
| "auto-awesome-rounded"
| "automation-outline"
| "backup"
| "bookmark-add-rounded"
| "branding-watermark-outline-rounded"
| "brush"
| "build-outline-rounded"
| "change-history"
| "check"
| "check-circle"
| "check-circle-outline-rounded"
| "check-circle-rounded"
| "chevron-left"
| "chevron-left-rounded"
| "chevron-right-rounded"
| "cleaning-services-outline-rounded"
| "close"
| "close-rounded"
| "cloud-upload"
| "comment"
| "compare-rounded"
| "compress"
| "content-copy"
| "content-copy-rounded"
| "content-cut-rounded"
| "content-paste-rounded"
| "credit-card"
| "crop-free-rounded"
| "crop-rounded"
| "crop-square"
| "crop-square-outline"
| "dashboard-customize-outline-rounded"
| "dashboard-customize-rounded"
| "dashboard-outline-rounded"
| "delete"
| "delete-outline-rounded"
| "delete-rounded"
| "description"
| "desktop-cloud-rounded"
| "download"
| "download-rounded"
| "edit"
| "edit-outline-rounded"
| "edit-rounded"
| "edit-square-outline-rounded"
| "edit-square-rounded"
| "error"
| "error-outline-rounded"
| "error-rounded"
| "expand-more-rounded"
| "explore-rounded"
| "extension-rounded"
| "fact-check-outline-rounded"
| "fact-check-rounded"
| "find-replace"
| "folder-rounded"
| "format-align-center"
| "format-align-left"
| "format-align-right"
| "format-color-fill-rounded"
| "format-underlined"
| "gavel-rounded"
| "gpp-maybe-outline-rounded"
| "group"
| "group-add"
| "group-rounded"
| "groups-rounded"
| "help-rounded"
| "highlight"
| "image-outline-rounded"
| "info"
| "info-outline-rounded"
| "info-rounded"
| "javascript-rounded"
| "key"
| "key-rounded"
| "keyboard-arrow-down"
| "keyboard-arrow-up"
| "keyboard-rounded"
| "language"
| "layers-clear-outline-rounded"
| "layers-outline-rounded"
| "library-add-outline-rounded"
| "link"
| "link-rounded"
| "lock"
| "lock-open"
| "lock-open-right-outline-rounded"
| "lock-outline"
| "login"
| "logout"
| "logout-rounded"
| "looks-one-outline-rounded"
| "mail-rounded"
| "match-word-rounded"
| "material-symbols:pause-rounded"
| "material-symbols:play-arrow-rounded"
| "menu-book-outline-rounded"
| "menu-book-rounded"
| "more-vert"
| "move-down-rounded"
| "opacity"
| "open-in-new-rounded"
| "palette-outline"
| "pan-tool-rounded"
| "password-rounded"
| "pause-rounded"
| "person"
| "person-add"
| "person-add-rounded"
| "person-check"
| "person-off"
| "person-remove"
| "person-rounded"
| "photo-library-outline-rounded"
| "picture-as-pdf-rounded"
| "pin-end"
| "play-arrow-rounded"
| "play-circle"
| "preview-off-rounded"
| "qr-code-rounded"
| "quick-reference-all-outline-rounded"
| "radio-button-unchecked"
| "redo"
| "refresh"
| "refresh-rounded"
| "remove-moderator-outline-rounded"
| "remove-selection-rounded"
| "rocket-launch"
| "rotate-left"
| "rotate-right"
| "rotate-right-rounded"
| "save"
| "save-rounded"
| "scan-delete-outline-rounded"
| "scan-delete-rounded"
| "scanner-outline-rounded"
| "schedule-outline-rounded"
| "search"
| "search-rounded"
| "security"
| "select-all"
| "send-rounded"
| "settings-rounded"
| "shield-lock"
| "shield-rounded"
| "show-chart"
| "signature-rounded"
| "speed"
| "star"
| "star-rounded"
| "sticky-note-2"
| "storage-rounded"
| "strikethrough-s"
| "subdirectory-arrow-right-rounded"
| "swap-horiz"
| "sync-alt-rounded"
| "system-update-alt-rounded"
| "text-fields"
| "text-fields-rounded"
| "thread-unread-rounded"
| "toc-rounded"
| "touch-app-rounded"
| "tune-rounded"
| "undo"
| "unfold-less"
| "unfold-more"
| "upload-file-rounded"
| "upload-rounded"
| "verified-outline-rounded"
| "verified-user-outline"
| "verified-user-rounded"
| "view-carousel-rounded"
| "view-list"
| "visibility"
| "visibility-off-outline-rounded"
| "visibility-rounded"
| "vital-signs-rounded"
| "warning"
| "warning-rounded"
| "workspace-premium-outline-rounded"
| "workspace-premium-rounded"
| "zoom-in"
| "zoom-in-map-rounded"
| "zoom-out";
export interface IconSet {
prefix: string;