Follow-up: colour token migration (compat → --c-*, hardcoded hex) (#7011)

Follow-up to #7009, which built the theme token layer (`primitives` →
`colors` → `compat`). This PR moves the whole app onto it, removes
hardcoded colours, turns on enforcement so they can't come back, and
adds a user-selectable accent.

## What this does
- **Semantic tokens everywhere** — legacy colour aliases and raw hex are
rewritten to `--c-*` tokens (`--c-surface*`, `--c-text*`, `--c-primary`,
…). Straight rename, no visual change. Genuine literals (brand/OAuth,
colour pickers, data-viz) are left as-is.
- **Fixes missing colours** — some tokens the migration referenced were
never defined, so a few surfaces (login button, auth banners, badges,
procurement view) silently lost their colour. All defined now, and they
adapt to light/dark and the accent automatically.
- **Blocking colour lint** — CI now fails on hardcoded colours,
undefined tokens, or unreadable low-contrast status colours.
- **User-selectable accent** — light and dark each get their own accent
from Settings → Appearance, contrast-clamped so text stays legible.
"Default" keeps the standard blue.

## Still to come
Remaining inline-style hex, the legacy token-definition files
(`theme.css`, `tokens.css`), and folding `zIndex.ts` onto the dimension
tokens.

## Testing
`task frontend:check:all` green; light/dark and accent switching
spot-checked.
This commit is contained in:
EthanHealy01
2026-07-23 09:05:56 +00:00
committed by GitHub
parent 8de94ff152
commit 67e10138b5
280 changed files with 4030 additions and 3474 deletions
+5 -1
View File
@@ -207,10 +207,14 @@ tasks:
- task: lint:colors - task: lint:colors
lint:colors: lint:colors:
desc: "Enforce theme tokens — colours in core/theme route through the palette" desc: "Enforce theme tokens — no hardcoded colours or raw primitives in components"
aliases: [lint:colours]
deps: [install] deps: [install]
cmds: cmds:
- node editor/scripts/lint/theme-lint.mjs - node editor/scripts/lint/theme-lint.mjs
- node editor/scripts/lint/theme-lint.mjs css-colors
- node editor/scripts/lint/theme-lint.mjs code-colors
- node editor/scripts/lint/theme-lint.mjs no-primitives
contrast: contrast:
desc: "Report low-contrast theme token pairs (warning only, never blocks)" desc: "Report low-contrast theme token pairs (warning only, never blocks)"
+2 -2
View File
@@ -226,8 +226,8 @@ const preview: Preview = {
backgrounds: { backgrounds: {
default: "app", default: "app",
values: [ values: [
{ name: "app", value: "var(--color-bg)" }, { name: "app", value: "var(--c-bg)" },
{ name: "surface", value: "var(--color-surface)" }, { name: "surface", value: "var(--c-surface)" },
], ],
}, },
a11y: { a11y: {
+638 -99
View File
@@ -1,19 +1,24 @@
#!/usr/bin/env node #!/usr/bin/env node
// Theme colour lint — guards the theme SYSTEM (core/theme/). Two modes: // Theme colour lint — guards the theme system + app-wide colour hygiene. Modes:
// //
// node theme-lint.mjs enforce: literal colours live ONLY in // node theme-lint.mjs enforce: literal colours live ONLY in
// primitives.css; colors/compat/dimensions must // primitives.css; core/theme references tokens;
// reference tokens; no duplicate primitives. // no duplicate primitives; every referenced
// (blocking) // --p-*/--c-* token resolves. (blocking)
// node theme-lint.mjs contrast warn-only WCAG contrast report (never blocks) // node theme-lint.mjs css-colors enforce: NO hardcoded colour in any source
// // .css (primitives.css + generated output.css
// Scope is deliberately just core/theme/ — the palette + token layer this PR // exempt). Scope: all editor/src. (blocking)
// owns, which is clean, so no baseline file is needed. Enforcing "no hardcoded // node theme-lint.mjs code-colors enforce: no hardcoded colour in TS/TSX DOM
// colours" across the whole app (260+ existing sites) is a separate migration. // code (default-deny with layered exemptions;
// `// theme-allow-color` opt-out). (blocking)
// node theme-lint.mjs contrast warn-only WCAG report — fixed --c-* pairs +
// status-tone text/fill pairs. (The tone gate
// below 1.6:1 is enforced in the default run.)
// //
// Structural black / white / transparent (shadows, scrims) are always allowed. // Structural black / white / transparent (shadows, scrims) are always allowed.
import { readFileSync, readdirSync } from "node:fs"; import { readFileSync, readdirSync } from "node:fs";
import { execSync } from "node:child_process";
import { relative, resolve, join } from "node:path"; import { relative, resolve, join } from "node:path";
const THEME = resolve(process.cwd(), "editor/src/core/theme"); const THEME = resolve(process.cwd(), "editor/src/core/theme");
@@ -26,7 +31,6 @@ const PRIMITIVES = "editor/src/core/theme/primitives.css";
const THEME_FILES = [ const THEME_FILES = [
"primitives.css", "primitives.css",
"colors.css", "colors.css",
"compat.css",
"dimensions.css", "dimensions.css",
"index.css", "index.css",
]; ];
@@ -34,8 +38,156 @@ const THEME_FILES = [
// ── colour helpers ───────────────────────────────────────────────────────── // ── colour helpers ─────────────────────────────────────────────────────────
const HEX_RE = /#[0-9a-fA-F]{3,8}\b/g; const HEX_RE = /#[0-9a-fA-F]{3,8}\b/g;
const FUNC_RE = /\b(?:rgba?|hsla?)\(\s*[^)]*\)/g; const FUNC_RE = /\b(?:rgba?|hsla?)\(\s*[^)]*\)/g;
const NAMED_RE = // CSS named colours (structural white/black/transparent handled separately).
/\b(?:white|black|red|green|blue|orange|yellow|purple|gray|grey|silver|transparent)\b/g; // Kept broad so `color: teal`/`navy`/`crimson`/`cyan` can't slip past the gate.
const NAMED_COLORS = [
"aliceblue",
"antiquewhite",
"aqua",
"aquamarine",
"azure",
"beige",
"bisque",
"blanchedalmond",
"blue",
"blueviolet",
"brown",
"burlywood",
"cadetblue",
"chartreuse",
"chocolate",
"coral",
"cornflowerblue",
"cornsilk",
"crimson",
"cyan",
"darkblue",
"darkcyan",
"darkgoldenrod",
"darkgray",
"darkgreen",
"darkgrey",
"darkkhaki",
"darkmagenta",
"darkolivegreen",
"darkorange",
"darkorchid",
"darkred",
"darksalmon",
"darkseagreen",
"darkslateblue",
"darkslategray",
"darkslategrey",
"darkturquoise",
"darkviolet",
"deeppink",
"deepskyblue",
"dimgray",
"dimgrey",
"dodgerblue",
"firebrick",
"floralwhite",
"forestgreen",
"fuchsia",
"gainsboro",
"ghostwhite",
"gold",
"goldenrod",
"gray",
"green",
"greenyellow",
"grey",
"honeydew",
"hotpink",
"indianred",
"indigo",
"ivory",
"khaki",
"lavender",
"lavenderblush",
"lawngreen",
"lemonchiffon",
"lightblue",
"lightcoral",
"lightcyan",
"lightgoldenrodyellow",
"lightgray",
"lightgreen",
"lightgrey",
"lightpink",
"lightsalmon",
"lightseagreen",
"lightskyblue",
"lightslategray",
"lightslategrey",
"lightsteelblue",
"lightyellow",
"lime",
"limegreen",
"linen",
"magenta",
"maroon",
"mediumaquamarine",
"mediumblue",
"mediumorchid",
"mediumpurple",
"mediumseagreen",
"mediumslateblue",
"mediumspringgreen",
"mediumturquoise",
"mediumvioletred",
"midnightblue",
"mintcream",
"mistyrose",
"moccasin",
"navajowhite",
"navy",
"oldlace",
"olive",
"olivedrab",
"orange",
"orangered",
"orchid",
"palegoldenrod",
"palegreen",
"paleturquoise",
"palevioletred",
"papayawhip",
"peachpuff",
"peru",
"pink",
"plum",
"powderblue",
"purple",
"rebeccapurple",
"red",
"rosybrown",
"royalblue",
"saddlebrown",
"salmon",
"sandybrown",
"seagreen",
"seashell",
"sienna",
"silver",
"skyblue",
"slateblue",
"slategray",
"slategrey",
"snow",
"springgreen",
"steelblue",
"tan",
"teal",
"thistle",
"tomato",
"turquoise",
"violet",
"wheat",
"yellow",
"yellowgreen",
];
const NAMED_RE = new RegExp(`\\b(?:${NAMED_COLORS.join("|")})\\b`, "g");
function expandHex(hex) { function expandHex(hex) {
let h = hex.slice(1).toLowerCase(); let h = hex.slice(1).toLowerCase();
@@ -66,6 +218,98 @@ function stripComments(text) {
return text.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " ")); return text.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "));
} }
// ── shared colour math + token resolution (used by contrast report + tone guard)
function readPrimitives(css) {
const primitives = {};
for (const m of css.matchAll(
/(--p-[a-z0-9-]+)\s*:\s*(#[0-9a-fA-F]{3,8})\s*;/g,
))
primitives[m[1]] = m[2];
return primitives;
}
function hexToRgb(hex) {
// expandHex normalises 3/4-digit shorthand to 6/8; parse alpha from 8-digit.
const h = expandHex(hex.startsWith("#") ? hex : "#" + hex).slice(1);
return {
r: parseInt(h.slice(0, 2), 16),
g: parseInt(h.slice(2, 4), 16),
b: parseInt(h.slice(4, 6), 16),
a: h.length >= 8 ? parseInt(h.slice(6, 8), 16) / 255 : 1,
};
}
const over = (f, b) => ({
r: f.r * f.a + b.r * (1 - f.a),
g: f.g * f.a + b.g * (1 - f.a),
b: f.b * f.a + b.b * (1 - f.a),
a: 1,
});
const mix = (a, b, p) => ({
r: (a.r * p + b.r * (100 - p)) / 100,
g: (a.g * p + b.g * (100 - p)) / 100,
b: (a.b * p + b.b * (100 - p)) / 100,
a: 1,
});
// Resolve any token value: hex, rgb(a), var(--x[, fallback]) (--p-* → palette,
// else the theme map), or color-mix(in srgb, A n%, B|transparent).
function resolveColorValue(v, t, primitives, seen) {
if (v == null) return null;
// Collapse internal whitespace so multi-line values (e.g. a color-mix() split
// across lines in tokens.css) match the single-line grammars below.
v = v.replace(/\s+/g, " ").trim();
let m;
if (v.startsWith("#")) return hexToRgb(v);
if ((m = v.match(/^rgba?\(([^)]+)\)$/))) {
const n = m[1]
.split(/[,/\s]+/)
.map(Number)
.filter((x) => !Number.isNaN(x));
return { r: n[0], g: n[1], b: n[2], a: n[3] ?? 1 };
}
if ((m = v.match(/^var\(\s*(--[a-z0-9-]+)\s*(?:,\s*([\s\S]+))?\)$/))) {
return resolveColorVar(m[1], m[2], t, primitives, seen);
}
if (
(m = v.match(
/^color-mix\(\s*in srgb\s*,\s*(.+?)\s+(\d+)%\s*,\s*(.+?)\s*\)$/,
))
) {
const a = resolveColorValue(m[1], t, primitives, seen);
if (!a) return null;
if (m[3].trim() === "transparent") return { ...a, a: +m[2] / 100 };
const b = resolveColorValue(m[3].trim(), t, primitives, seen);
return b ? mix(a, b, +m[2]) : null;
}
return null;
}
function resolveColorVar(name, fallback, t, primitives, seen) {
if (name.startsWith("--p-")) {
return primitives[name]
? hexToRgb(primitives[name])
: fallback
? resolveColorValue(fallback, t, primitives, seen)
: null;
}
if (!seen.has(name) && t[name] !== undefined) {
const next = new Set(seen).add(name);
const r = resolveColorValue(t[name], t, primitives, next);
if (r) return r;
}
return fallback ? resolveColorValue(fallback, t, primitives, seen) : null;
}
const relativeLuminance = ({ r, g, b }) => {
const f = (v) => {
v /= 255;
return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
};
return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
};
const contrastRatio = (a, b) => {
const [hi, lo] = [relativeLuminance(a), relativeLuminance(b)].sort(
(x, y) => y - x,
);
return (hi + 0.05) / (lo + 0.05);
};
// ── enforce: literals only in primitives.css, no duplicate primitives ──────── // ── enforce: literals only in primitives.css, no duplicate primitives ────────
function check() { function check() {
const violations = []; const violations = [];
@@ -149,11 +393,7 @@ function check() {
function reportContrast() { function reportContrast() {
const primitivesCss = readFileSync(join(THEME, "primitives.css"), "utf8"); const primitivesCss = readFileSync(join(THEME, "primitives.css"), "utf8");
const colorsCss = readFileSync(join(THEME, "colors.css"), "utf8"); const colorsCss = readFileSync(join(THEME, "colors.css"), "utf8");
const primitives = {}; const primitives = readPrimitives(primitivesCss);
for (const m of primitivesCss.matchAll(
/(--p-[a-z0-9-]+)\s*:\s*(#[0-9a-fA-F]{3,8})\s*;/g,
))
primitives[m[1]] = m[2];
const blocks = []; const blocks = [];
for (const m of colorsCss.matchAll(/([^{}]+)\{([^}]*)\}/g)) { for (const m of colorsCss.matchAll(/([^{}]+)\{([^}]*)\}/g)) {
const decls = {}; const decls = {};
@@ -189,82 +429,8 @@ function reportContrast() {
}; };
const flatten = (list) => const flatten = (list) =>
Object.assign({ ...SEED }, ...list.map((b) => b.decls)); Object.assign({ ...SEED }, ...list.map((b) => b.decls));
const hexToRgb = (h) => {
h = h.replace("#", "");
if (h.length === 3)
h = h
.split("")
.map((c) => c + c)
.join("");
return {
r: parseInt(h.slice(0, 2), 16),
g: parseInt(h.slice(2, 4), 16),
b: parseInt(h.slice(4, 6), 16),
a: 1,
};
};
const over = (f, b) => ({
r: f.r * f.a + b.r * (1 - f.a),
g: f.g * f.a + b.g * (1 - f.a),
b: f.b * f.a + b.b * (1 - f.a),
a: 1,
});
const mix = (a, b, p) => ({
r: (a.r * p + b.r * (100 - p)) / 100,
g: (a.g * p + b.g * (100 - p)) / 100,
b: (a.b * p + b.b * (100 - p)) / 100,
a: 1,
});
// Resolve any token value: hex, rgb(a), var(--x[, fallback]) (--p-* → palette,
// else the theme map/seed), or color-mix(in srgb, A n%, B|transparent).
function resolveValue(v, t, seen) {
if (v == null) return null;
v = v.trim();
let m;
if (v.startsWith("#")) return hexToRgb(v);
if ((m = v.match(/^rgba?\(([^)]+)\)$/))) {
const n = m[1]
.split(/[,/\s]+/)
.map(Number)
.filter((x) => !Number.isNaN(x));
return { r: n[0], g: n[1], b: n[2], a: n[3] ?? 1 };
}
if ((m = v.match(/^var\(\s*(--[a-z0-9-]+)\s*(?:,\s*([\s\S]+))?\)$/))) {
return resolveVar(m[1], m[2], t, seen);
}
if ((m = v.match(/^color-mix\(in srgb,\s*(.+?)\s+(\d+)%\s*,\s*(.+)\)$/))) {
const a = resolveValue(m[1], t, seen);
if (!a) return null;
if (m[3].trim() === "transparent") return { ...a, a: +m[2] / 100 };
const b = resolveValue(m[3].trim(), t, seen);
return b ? mix(a, b, +m[2]) : null;
}
return null;
}
function resolveVar(name, fallback, t, seen) {
if (name.startsWith("--p-")) {
return primitives[name]
? hexToRgb(primitives[name])
: fallback
? resolveValue(fallback, t, seen)
: null;
}
if (!seen.has(name) && t[name] !== undefined) {
const next = new Set(seen).add(name);
const r = resolveValue(t[name], t, next);
if (r) return r;
}
return fallback ? resolveValue(fallback, t, seen) : null;
}
const resolve = (token, t) => const resolve = (token, t) =>
resolveValue(t[token] ?? null, t, new Set([token])); resolveColorValue(t[token] ?? null, t, primitives, new Set([token]));
const lum = ({ r, g, b }) => {
const f = (v) => {
v /= 255;
return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
};
return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
};
const contrast = (t1, t2, t) => { const contrast = (t1, t2, t) => {
const surface = resolve("--c-surface", t); const surface = resolve("--c-surface", t);
let a = resolve(t1, t); let a = resolve(t1, t);
@@ -272,8 +438,7 @@ function reportContrast() {
if (!a || !b || !surface) return null; if (!a || !b || !surface) return null;
if (a.a < 1) a = over(a, surface); if (a.a < 1) a = over(a, surface);
if (b.a < 1) b = over(b, surface); if (b.a < 1) b = over(b, surface);
const [hi, lo] = [lum(a), lum(b)].sort((x, y) => y - x); return contrastRatio(a, b);
return (hi + 0.05) / (lo + 0.05);
}; };
const PAIRS = [ const PAIRS = [
["--c-text", "--c-surface", 4.5], ["--c-text", "--c-surface", 4.5],
@@ -307,23 +472,397 @@ function reportContrast() {
); );
} }
// ── status-tone text on its own fill ─────────────────────────────────────────
// Checks --color-{hue} text against its --color-{hue}-light fill, per theme.
// Below TONE_INVISIBLE blocks the build; TONE_FLOOR (WCAG AA) is advisory.
const TOKENS_CSS = resolve(process.cwd(), "editor/src/core/tokens/tokens.css");
const TONE_FLOOR = 3.0;
const TONE_INVISIBLE = 1.6;
// Compute the contrast of every --color-{hue} text on its own --color-{hue}-light
// fill, per theme. Returns [{ theme, base, fill, ratio|null }] — no printing, so
// both the warn-only report and the blocking guard can share it.
function toneContrastResults() {
const primitives = readPrimitives(
readFileSync(join(THEME, "primitives.css"), "utf8"),
);
// Strip comments first: a selector's captured prefix can otherwise include a
// preceding comment that mentions data-theme="dark", misclassifying the block.
const css = stripComments(readFileSync(TOKENS_CSS, "utf8"));
const isDark = (sel) => /data-theme="dark"|color-scheme="dark"/.test(sel);
const lightTones = {};
const darkTones = {};
for (const m of css.matchAll(/([^{}]+)\{([^}]*)\}/g)) {
const target = isDark(m[1]) ? darkTones : lightTones;
for (const d of m[2].matchAll(/(--color-[a-z0-9-]+)\s*:\s*([^;]+);/g))
target[d[1]] = d[2].trim();
}
// Dark only overrides the tones it redefines; unspecified ones inherit light.
const themes = { light: lightTones, dark: { ...lightTones, ...darkTones } };
const white = { r: 255, g: 255, b: 255, a: 1 };
const results = [];
for (const [theme, t] of Object.entries(themes)) {
const bases = Object.keys(t)
.map((k) => /^(--color-[a-z]+)-light$/.exec(k)?.[1])
.filter((base) => base && t[base] !== undefined);
for (const base of bases) {
const fill = `${base}-light`;
const fg = resolveColorValue(t[base], t, primitives, new Set([base]));
const bg = resolveColorValue(t[fill], t, primitives, new Set([fill]));
const ratio =
fg && bg
? contrastRatio(
fg.a < 1 ? over(fg, bg) : fg,
bg.a < 1 ? over(bg, white) : bg,
)
: null;
results.push({ theme, base, fill, ratio });
}
}
return results;
}
function reportToneContrast() {
const results = toneContrastResults();
let warnings = 0;
let invisible = 0;
console.log("tone-contrast report: text on its own -light fill\n");
let theme = "";
for (const { theme: th, base, fill, ratio } of results) {
if (th !== theme) {
theme = th;
console.log(` ${theme}`);
}
if (ratio == null) {
console.log(` ? ${base} on ${fill} (unresolved)`);
continue;
}
// ✖ = near-invisible (blocks CI), ⚠ = below the WCAG floor (warn only).
const mark =
ratio < TONE_INVISIBLE ? "✖ " : ratio < TONE_FLOOR ? "⚠ " : " ";
if (ratio < TONE_INVISIBLE) invisible++;
else if (ratio < TONE_FLOOR) warnings++;
console.log(
` ${mark}${ratio.toFixed(2).padStart(5)} (floor ${TONE_FLOOR}, blocks <${TONE_INVISIBLE}) ${base} on ${fill}`,
);
}
const parts = [];
if (invisible)
parts.push(`${invisible} near-invisible (<${TONE_INVISIBLE}:1)`);
if (warnings) parts.push(`${warnings} below the ${TONE_FLOOR} floor`);
console.log(
parts.length
? `\n${parts.join(", ")}. ✖ blocks the build; ⚠ is advisory.\n`
: "\n✓ all tones clear the floor.\n",
);
}
// ── css-colors (blocking): no hardcoded colour in ANY source .css ────────────
// App-wide guard that source CSS routes every colour through the palette. File
// list from `git ls-files` (a VCS query, never a directory walk feeding a read).
// primitives.css (the literal home) and generated output.css are exempt.
function checkAppCss() {
const EXEMPT = /(?:^|\/)(?:primitives\.css|output\.css)$/;
const listed = execSync("git ls-files -- editor/src", { encoding: "utf8" })
.split("\n")
.map((l) => l.trim())
.filter((l) => l && l.endsWith(".css") && !EXEMPT.test(l));
const violations = [];
const lineOf = (text, index) => text.slice(0, index).split("\n").length;
for (const rel of listed) {
const text = stripComments(readFileSync(rel, "utf8"));
for (const re of [HEX_RE, FUNC_RE]) {
re.lastIndex = 0;
let m;
while ((m = re.exec(text)) !== null) {
if (/var\(/i.test(m[0])) continue; // rgb()/color-mix wrapping a token
const norm = normalizeColor(m[0]);
if (isStructuralColor(norm)) continue;
violations.push({
file: rel,
line: lineOf(text, m.index),
msg: `raw colour ${m[0]} — define it in primitives.css and use var(--p-…)`,
});
}
}
text.split("\n").forEach((line, i) => {
const colon = line.indexOf(":");
if (colon < 0 || /[{}]/.test(line)) return;
if (!/^\s*(?:--)?[a-z][a-z0-9-]*\s*$/i.test(line.slice(0, colon))) return;
const value = line
.slice(colon + 1)
.replace(/--[a-z0-9-]+/gi, " ")
.replace(/url\([^)]*\)/g, " ")
.replace(/["'][^"']*["']/g, " ");
for (const nm of value.match(NAMED_RE) || []) {
if (isStructuralName(nm)) continue;
violations.push({
file: rel,
line: i + 1,
msg: `named colour "${nm}" — define it in primitives.css and use var(--p-…)`,
});
}
});
}
return violations;
}
// ── code-colors (blocking): no hardcoded colour in TS/TSX DOM code ───────────
// Default-deny with layered exemptions: structural black/white/transparent;
// safe contexts on the line (var() fallback, canvas/pdf-lib rgb, an explicit
// `// theme-allow-color` opt-out); and exempt PATHS where colour literals are
// inherent (rendering/vendor/config/tests/stories).
const CODE_EXEMPT_PATH = [
/Thumbnail|Overlay|DrawingCanvas|PageEditor|MobileScannerPage/,
// PDF rendering/drawing surfaces that legitimately carry colour literals —
// scoped to specific tool paths, not a blanket "pdf" substring (which used to
// exempt most of the app in a PDF product).
/pdfTextEditor|pixelCompare|\/compare\.ts$|customPrimary|accentColors/,
/validateSignature\/outputtedPDFSections|CenteredMessageSection|StatusBadgeSection/,
/\/viewer\/|Annotation|useViewerReadAloud|CommentsSidebar|\/constants\/search\.ts$|SignaturePreview/,
/ColorPicker|ColorControl|WatchedFolderManagementModal|watchedFolderPresets|fileColors|unifiedBackground|folder\.ts$|policyFolders/,
/OAuthButtons|oauthCallbackHtml/,
/mantineTheme|\/theme\.ts$|toolsTaxonomy|LayoutPreview|PageNumberPreview|CloudStorageIcons/,
/\/onboarding\//,
/addStamp|addWatermark|\/tooltips\//,
/UpgradeBanner|AdminPlanSection/,
/\.test\.[jt]sx?$|\.stories\.[jt]sx?$|\/types\//,
];
const CODE_HEX =
/#(?:[0-9a-fA-F]{8}|[0-9a-fA-F]{6}|[0-9a-fA-F]{4}|[0-9a-fA-F]{3})(?![0-9a-fA-F])/g;
const CODE_RGB = /rgba?\(([^)]*)\)/gi;
const CODE_HSL = /hsla?\(([^)]*)\)/gi;
// NOTE: bare named colours (e.g. 'blue') are intentionally NOT flagged in
// TS/TSX — they are dominated by legitimate Mantine palette props (`c="red"`,
// `color="blue"`, which are theme-routed) and provider names ('azure'), so a
// string match produces mostly false positives. hsl()/hex/rgb() are unambiguous.
const codeStructuralHex = (h) =>
/^#(?:000|fff|000f|ffff|000000|ffffff|00000000|ffffffff)$/i.test(h);
// Line-level skips for contexts where a colour literal is inherent (canvas /
// pdf-lib drawing, computed-style reads) or explicitly opted out. NOTE: a
// `var(--x, #hex)` literal fallback is deliberately NOT skipped — the hex in the
// fallback is still a hardcoded colour and must route through a token.
const CODE_SKIP_LINE =
/theme-allow-color|readColor\(|getPropertyValue|\.colors\.[a-z]+\?\.\[|fillStyle|strokeStyle|shadowColor|addColorStop|createLinearGradient|ctx\.|getContext/i;
function codeStripNonCode(text) {
return text
.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "))
.replace(
/(^|[^:])\/\/[^\n]*/g,
(m, p) => p + m.slice(p.length).replace(/[^\n]/g, " "),
)
.replace(/&#\d+;/g, " ");
}
function codeRgbIsColour(inner) {
if (/var\(/.test(inner)) return false;
const p = inner
.split(/[, /]+/)
.map((x) => x.trim())
.filter(Boolean);
if (!/^\d/.test(p[0] || "")) return false;
const nums = p.slice(0, 3).map(Number);
if (nums.some((n) => Number.isNaN(n))) return false;
if (nums.every((n) => n <= 1)) return false; // pdf-lib rgb(0..1)
const k = `${nums[0]},${nums[1]},${nums[2]}`;
return k !== "0,0,0" && k !== "255,255,255";
}
function checkCodeColors() {
const files = execSync("git ls-files -- editor/src", { encoding: "utf8" })
.split("\n")
.map((l) => l.trim())
.filter(
(l) =>
/\.(ts|tsx)$/.test(l) && !CODE_EXEMPT_PATH.some((re) => re.test(l)),
);
const violations = [];
for (const rel of files) {
const raw = readFileSync(rel, "utf8");
const rawLines = raw.split("\n");
const text = codeStripNonCode(raw);
text.split("\n").forEach((line, i) => {
if (/theme-allow-color/.test(rawLines[i] || "")) return;
if (CODE_SKIP_LINE.test(line)) return;
const hits = [];
for (const h of line.match(CODE_HEX) || [])
if (!codeStructuralHex(h)) hits.push(h);
for (const m of line.match(CODE_RGB) || [])
if (codeRgbIsColour(m.replace(/rgba?\(|\)/gi, ""))) hits.push(m);
for (const m of line.match(CODE_HSL) || [])
if (!/var\(/.test(m)) hits.push(m);
for (const h of hits)
violations.push({
file: rel,
line: i + 1,
msg: `hardcoded colour ${h} — use a var(--c-*/--p-*) token, or add \`// theme-allow-color <reason>\` if it must be a literal`,
});
});
}
return violations;
}
// ── token-resolution (blocking): every referenced --p-*/--c-* must resolve ────
// A `var(--p-…)`/`var(--c-…)` with no fallback silently computes to the initial
// value (transparent/inherited) when the token is undefined, so the colour just
// disappears — invisible to the literal checks above. Assert every such
// reference has a definition somewhere (any source .css/.ts/.tsx) or a fallback.
// Runtime-injected families (--user-*, --mantine-*, --accent-*) are out of scope.
function checkTokenResolution() {
const files = execSync("git ls-files -- editor/src", { encoding: "utf8" })
.split("\n")
.map((l) => l.trim())
.filter((l) => /\.(css|ts|tsx)$/.test(l));
const DEF_RE = /(--[a-z0-9-]+)\s*:/gi;
// Capture the token and the char that follows it (`,` ⇒ has a fallback).
const REF_RE = /var\(\s*(--[a-z0-9-]+)\s*(,|\))/gi;
const defined = new Set();
const refs = [];
const lineOf = (text, index) => text.slice(0, index).split("\n").length;
for (const rel of files) {
const text = stripComments(readFileSync(rel, "utf8"));
for (const m of text.matchAll(DEF_RE)) defined.add(m[1]);
for (const m of text.matchAll(REF_RE)) {
const [token, next] = [m[1], m[2]];
if (!/^--[pc]-/.test(token)) continue; // only our theme tokens
if (next === ",") continue; // has a fallback → degrades safely
refs.push({ file: rel, line: lineOf(text, m.index), token });
}
}
return refs.filter((r) => !defined.has(r.token));
}
// ── no-primitives (blocking): components must reference --c-* SEMANTIC tokens,
// not raw --p-* palette primitives — otherwise a colour-scheme change to the
// semantic layer won't reach them. --p-* is allowed ONLY in the token-definition
// layer (primitives/colors/dimensions + legacy vocab files + accents).
const PRIMITIVE_LAYER = [
/^editor\/src\/core\/theme\//,
/^editor\/src\/core\/styles\/theme\.css$/,
/^editor\/src\/core\/tokens\/tokens\.css$/,
/^editor\/src\/saas\/styles\/saas-theme\.css$/,
/^editor\/src\/proprietary\/auth\/ui\/auth-theme\.css$/,
/^editor\/src\/core\/ui\/accents\.css$/,
];
function checkNoPrimitives() {
const files = execSync("git ls-files -- editor/src", { encoding: "utf8" })
.split("\n")
.map((l) => l.trim())
.filter(
(l) =>
/\.(css|scss|ts|tsx)$/.test(l) &&
!PRIMITIVE_LAYER.some((re) => re.test(l)),
);
const REF = /var\(\s*(--p-[a-z0-9-]+)/g;
const violations = [];
const lineOf = (text, index) => text.slice(0, index).split("\n").length;
for (const rel of files) {
const text = stripComments(readFileSync(rel, "utf8"));
for (const m of text.matchAll(REF))
violations.push({ file: rel, line: lineOf(text, m.index), token: m[1] });
}
return violations;
}
// ── CLI ────────────────────────────────────────────────────────────────────── // ── CLI ──────────────────────────────────────────────────────────────────────
if (process.argv.includes("no-primitives")) {
const v = checkNoPrimitives();
if (v.length) {
console.error(
`\n✖ theme-lint no-primitives: ${v.length} raw --p-* primitive ref(s) in components — use a --c-* semantic token so colour-scheme changes propagate:\n`,
);
for (const x of v) console.error(` ${x.file}:${x.line} var(${x.token})`);
console.error("");
process.exit(1);
}
console.log(
"✓ theme-lint no-primitives: components reference --c-* semantic tokens (no raw --p-*)",
);
process.exit(0);
}
if (process.argv.includes("contrast")) { if (process.argv.includes("contrast")) {
reportContrast(); reportContrast();
reportToneContrast();
process.exit(0); // never blocks process.exit(0); // never blocks
} }
if (process.argv.includes("css-colors")) {
const v = checkAppCss();
if (v.length) {
console.error(
`\n✖ theme-lint css-colors: ${v.length} hardcoded colour(s) in source CSS:\n`,
);
for (const x of v) console.error(` ${x.file}:${x.line} ${x.msg}`);
console.error(
`\nDefine every colour once in core/theme/primitives.css and reference it with var(--p-…).\n`,
);
process.exit(1);
}
console.log(
"✓ theme-lint css-colors: source CSS is free of hardcoded colour",
);
process.exit(0);
}
if (process.argv.includes("code-colors")) {
const v = checkCodeColors();
if (v.length) {
console.error(
`\n✖ theme-lint code-colors: ${v.length} hardcoded colour(s) in TS/TSX:\n`,
);
for (const x of v) console.error(` ${x.file}:${x.line} ${x.msg}`);
console.error("");
process.exit(1);
}
console.log(
"✓ theme-lint code-colors: no hardcoded colour in TS/TSX DOM code (rendering/vendor/config areas exempt)",
);
process.exit(0);
}
const violations = check(); const violations = check();
if (violations.length) { // Block near-invisible status tones (< TONE_INVISIBLE) in either theme.
const toneViolations = toneContrastResults().filter(
(r) => r.ratio != null && r.ratio < TONE_INVISIBLE,
);
// Block references to --p-*/--c-* tokens that are defined nowhere (no fallback).
const unresolvedTokens = checkTokenResolution();
if (unresolvedTokens.length) {
console.error( console.error(
`\n✖ theme-lint: ${violations.length} raw/duplicate colour(s) in core/theme/:\n`, `\n✖ theme-lint: ${unresolvedTokens.length} reference(s) to undefined --p-*/--c-* token(s) (colour silently drops to transparent/inherited):\n`,
); );
for (const v of violations) console.error(` ${v.file}:${v.line} ${v.msg}`); for (const r of unresolvedTokens)
console.error(
` ${r.file}:${r.line} var(${r.token}) — not defined anywhere`,
);
console.error( console.error(
`\nDefine every colour once in core/theme/primitives.css and reference it with var(--p-…).\n`, `\nDefine the token (primitive in primitives.css, semantic in colors.css) or give the var() a fallback.\n`,
); );
}
if (violations.length || toneViolations.length || unresolvedTokens.length) {
if (violations.length) {
console.error(
`\n✖ theme-lint: ${violations.length} raw/duplicate colour(s) in core/theme/:\n`,
);
for (const v of violations)
console.error(` ${v.file}:${v.line} ${v.msg}`);
console.error(
`\nDefine every colour once in core/theme/primitives.css and reference it with var(--p-…).\n`,
);
}
if (toneViolations.length) {
console.error(
`\n✖ theme-lint: ${toneViolations.length} status tone(s) below the ${TONE_INVISIBLE}:1 legibility floor (text nearly invisible on its own fill):\n`,
);
for (const v of toneViolations)
console.error(
` ${v.base} on ${v.fill}${v.ratio.toFixed(2)}:1 in ${v.theme} theme`,
);
console.error(
`\nGive --color-{hue}-light a paler/darker tint in core/tokens/tokens.css so the label is legible.\n`,
);
}
process.exit(1); process.exit(1);
} }
console.log( console.log(
"✓ theme-lint: core/theme colours all route through the primitive palette", "✓ theme-lint: core/theme colours route through the primitive palette; status tones clear the legibility floor",
); );
@@ -8,7 +8,7 @@
} }
.freeHighlight { .freeHighlight {
background: linear-gradient(135deg, #6366f1, #ec4899); background: linear-gradient(135deg, var(--c-hue-indigo), var(--c-hue-pink));
-webkit-background-clip: text; -webkit-background-clip: text;
background-clip: text; background-clip: text;
color: transparent; color: transparent;
@@ -36,7 +36,7 @@
flex-direction: column; flex-direction: column;
max-height: 200px; max-height: 200px;
overflow-y: auto; overflow-y: auto;
border: 1px solid var(--border-default, #d1d5db); border: 1px solid var(--c-border);
border-radius: 12px; border-radius: 12px;
margin-bottom: 12px; margin-bottom: 12px;
} }
@@ -49,7 +49,7 @@
} }
.memberRow + .memberRow { .memberRow + .memberRow {
border-top: 1px solid var(--border-subtle, #e5e7eb); border-top: 1px solid var(--c-border-subtle);
} }
.memberIdentity { .memberIdentity {
@@ -62,7 +62,7 @@
.memberName { .memberName {
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
color: var(--onboarding-title, #111827); color: var(--c-text);
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@@ -70,7 +70,7 @@
.memberEmail { .memberEmail {
font-size: 12px; font-size: 12px;
color: var(--onboarding-body, #6b7280); color: var(--c-text-muted);
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@@ -87,7 +87,7 @@ export function FreeLimitReachedModal({ onClose }: FreeLimitReachedModalProps) {
content: { content: {
overflow: "hidden", overflow: "hidden",
border: "none", border: "none",
background: "var(--bg-surface)", background: "var(--c-surface)",
maxHeight: "90vh", maxHeight: "90vh",
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
@@ -87,7 +87,7 @@ export function SpendCapReachedModal({ onClose }: SpendCapReachedModalProps) {
content: { content: {
overflow: "hidden", overflow: "hidden",
border: "none", border: "none",
background: "var(--bg-surface)", background: "var(--c-surface)",
maxHeight: "90vh", maxHeight: "90vh",
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
@@ -2,25 +2,22 @@
Uses the app's semantic theme tokens (theme.css) so it tracks light/dark. */ Uses the app's semantic theme tokens (theme.css) so it tracks light/dark. */
.payg { .payg {
--payg-accent: #0a8bff; --payg-accent: var(--c-primary);
--payg-accent-soft: rgba(10, 139, 255, 0.1); --payg-accent-soft: color-mix(in srgb, var(--c-primary) 10%, transparent);
--payg-radius: 14px; --payg-radius: 14px;
--payg-gap: 20px; --payg-gap: 20px;
/* Cards sit ON the modal content bg; in light that's white-on-white so we /* Cards sit ON the modal content bg; in light that's white-on-white so we
lean on border + shadow. Tokens are overridden per scheme below. */ lean on border + shadow. Tokens are overridden per scheme below. */
--payg-card-bg: var(--bg-surface); --payg-card-bg: var(--c-surface);
--payg-card-border: var(--border-default); --payg-card-border: var(--c-border);
--payg-inset-bg: var(--bg-raised); --payg-inset-bg: var(--c-surface-raised);
--payg-divider: var(--border-subtle); --payg-divider: var(--c-border-subtle);
} }
/* Dark mode: modal content bg is #131729 (--bg-surface), so lift cards above it */ /* Dark mode: surfaces/borders track the neutral --c-* tokens (set on the base
rule); only the brand-azure accent tint is tuned brighter for dark. */
[data-mantine-color-scheme="dark"] .payg { [data-mantine-color-scheme="dark"] .payg {
--payg-card-bg: #1c2340; --payg-accent-soft: color-mix(in srgb, var(--c-primary) 16%, transparent);
--payg-card-border: #2d3560;
--payg-inset-bg: #0d1020;
--payg-accent-soft: rgba(79, 142, 245, 0.16);
--payg-divider: #2d3560;
} }
/* ── Header ─────────────────────────────────────────────────────────── */ /* ── Header ─────────────────────────────────────────────────────────── */
@@ -29,12 +26,12 @@
font-size: 1.35rem; font-size: 1.35rem;
font-weight: 700; font-weight: 700;
letter-spacing: -0.01em; letter-spacing: -0.01em;
color: var(--text-primary); color: var(--c-text);
} }
.payg-header__subtitle { .payg-header__subtitle {
margin-top: 4px; margin-top: 4px;
font-size: 0.875rem; font-size: 0.875rem;
color: var(--text-muted); color: var(--c-text-subtle);
} }
.payg-role-pill { .payg-role-pill {
display: inline-flex; display: inline-flex;
@@ -49,12 +46,12 @@
.payg-role-pill[data-leader="true"] { .payg-role-pill[data-leader="true"] {
background: var(--payg-accent-soft); background: var(--payg-accent-soft);
color: var(--payg-accent); color: var(--payg-accent);
border: 1px solid rgba(10, 139, 255, 0.25); border: 1px solid color-mix(in srgb, var(--c-primary) 25%, transparent);
} }
.payg-role-pill[data-leader="false"] { .payg-role-pill[data-leader="false"] {
background: var(--bg-muted); background: var(--c-surface-sunken);
color: var(--text-muted); color: var(--c-text-subtle);
border: 1px solid var(--border-default); border: 1px solid var(--c-border);
} }
/* ── Plan header: free-vs-metered split (shared by free + subscribed) ──── */ /* ── Plan header: free-vs-metered split (shared by free + subscribed) ──── */
@@ -73,7 +70,7 @@
} }
.payg-planhead__eyebrow { .payg-planhead__eyebrow {
font-size: 0.78rem; font-size: 0.78rem;
color: var(--text-muted); color: var(--c-text-subtle);
} }
.payg-planhead__split { .payg-planhead__split {
display: grid; display: grid;
@@ -98,7 +95,7 @@
margin-bottom: 8px; margin-bottom: 8px;
} }
.payg-planhead__lbl--free { .payg-planhead__lbl--free {
color: #10b981; color: var(--c-success);
} }
.payg-planhead__lbl--meter { .payg-planhead__lbl--meter {
color: var(--payg-accent); color: var(--payg-accent);
@@ -110,14 +107,14 @@
margin: 0; margin: 0;
font-size: 1.05rem; font-size: 1.05rem;
font-weight: 700; font-weight: 700;
color: var(--text-primary); color: var(--c-text);
letter-spacing: -0.01em; letter-spacing: -0.01em;
line-height: 1.25; line-height: 1.25;
} }
.payg-planhead__body { .payg-planhead__body {
margin: 5px 0 0; margin: 5px 0 0;
font-size: 0.85rem; font-size: 0.85rem;
color: var(--text-muted); color: var(--c-text-subtle);
line-height: 1.5; line-height: 1.5;
} }
@media (max-width: 640px) { @media (max-width: 640px) {
@@ -147,11 +144,11 @@
.payg-card__title { .payg-card__title {
font-size: 0.95rem; font-size: 0.95rem;
font-weight: 650; font-weight: 650;
color: var(--text-primary); color: var(--c-text);
} }
.payg-card__subtitle { .payg-card__subtitle {
font-size: 0.8125rem; font-size: 0.8125rem;
color: var(--text-muted); color: var(--c-text-subtle);
margin-top: 2px; margin-top: 2px;
} }
@@ -175,22 +172,22 @@
.payg-hero[data-state="FULL"]::before { .payg-hero[data-state="FULL"]::before {
background: linear-gradient( background: linear-gradient(
135deg, 135deg,
rgba(10, 139, 255, 0.12) 0%, color-mix(in srgb, var(--c-primary) 12%, transparent) 0%,
rgba(10, 139, 255, 0) 55% color-mix(in srgb, var(--c-primary) 0%, transparent) 55%
); );
} }
.payg-hero[data-state="WARNED"]::before { .payg-hero[data-state="WARNED"]::before {
background: linear-gradient( background: linear-gradient(
135deg, 135deg,
rgba(234, 179, 8, 0.16) 0%, color-mix(in srgb, var(--c-warning) 16%, transparent) 0%,
rgba(234, 179, 8, 0) 55% color-mix(in srgb, var(--c-warning) 0%, transparent) 55%
); );
} }
.payg-hero[data-state="DEGRADED"]::before { .payg-hero[data-state="DEGRADED"]::before {
background: linear-gradient( background: linear-gradient(
135deg, 135deg,
rgba(239, 68, 68, 0.16) 0%, color-mix(in srgb, var(--c-danger) 16%, transparent) 0%,
rgba(239, 68, 68, 0) 55% color-mix(in srgb, var(--c-danger) 0%, transparent) 55%
); );
} }
.payg-hero__inner { .payg-hero__inner {
@@ -202,7 +199,7 @@
font-weight: 700; font-weight: 700;
letter-spacing: 0.08em; letter-spacing: 0.08em;
text-transform: uppercase; text-transform: uppercase;
color: var(--text-muted); color: var(--c-text-subtle);
} }
.payg-hero__figure { .payg-hero__figure {
display: flex; display: flex;
@@ -215,12 +212,12 @@
font-weight: 750; font-weight: 750;
line-height: 1; line-height: 1;
letter-spacing: -0.03em; letter-spacing: -0.03em;
color: var(--text-primary); color: var(--c-text);
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
.payg-hero__cap { .payg-hero__cap {
font-size: 1rem; font-size: 1rem;
color: var(--text-muted); color: var(--c-text-subtle);
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
.payg-hero__meta { .payg-hero__meta {
@@ -229,10 +226,10 @@
flex-wrap: wrap; flex-wrap: wrap;
gap: 6px 18px; gap: 6px 18px;
font-size: 0.8125rem; font-size: 0.8125rem;
color: var(--text-secondary); color: var(--c-text-muted);
} }
.payg-hero__meta-dot { .payg-hero__meta-dot {
color: var(--border-strong); color: var(--c-border-strong);
} }
.payg-hero__credit { .payg-hero__credit {
display: inline-flex; display: inline-flex;
@@ -242,11 +239,11 @@
font-size: 0.75rem; font-size: 0.75rem;
font-weight: 600; font-weight: 600;
color: var(--color-green-700); color: var(--color-green-700);
background: rgba(34, 197, 94, 0.14); background: color-mix(in srgb, var(--c-success) 14%, transparent);
} }
[data-mantine-color-scheme="dark"] .payg-hero__credit { [data-mantine-color-scheme="dark"] .payg-hero__credit {
color: #4ade80; color: var(--c-success);
background: rgba(34, 197, 94, 0.18); background: color-mix(in srgb, var(--c-success) 18%, transparent);
} }
/* Make Mantine default-variant buttons read clearly on the lifted cards in /* Make Mantine default-variant buttons read clearly on the lifted cards in
@@ -257,16 +254,24 @@
/* Dark mode: the stock default button is a flat slab that disappears into the /* Dark mode: the stock default button is a flat slab that disappears into the
card. Lift it with a soft top-down gradient + brighter border, and warm the card. Lift it with a soft top-down gradient + brighter border, and warm the
hover so the buttons feel tactile against --payg-card-bg (#1c2340). Driven hover so the buttons feel tactile against the card surface. Driven through
through Mantine's --button-* vars. The same rule covers disabled buttons Mantine's --button-* vars. The same rule covers disabled buttons
(Cancel/Update cap before the form is dirty) so they read identically to the (Cancel/Update cap before the form is dirty) so they read identically to the
always-enabled ones — Mantine only fades them via opacity. */ always-enabled ones — Mantine only fades them via opacity. */
[data-mantine-color-scheme="dark"] [data-mantine-color-scheme="dark"]
.payg .payg
.mantine-Button-root[data-variant="default"] { .mantine-Button-root[data-variant="default"] {
--button-bg: linear-gradient(180deg, #232a50 0%, #1c2340 100%); --button-bg: linear-gradient(
--button-hover: linear-gradient(180deg, #2d3560 0%, #232a50 100%); 180deg,
--button-bd: 1px solid #2d3560; var(--c-surface-raised) 0%,
var(--c-surface) 100%
);
--button-hover: linear-gradient(
180deg,
var(--c-border) 0%,
var(--c-surface-raised) 100%
);
--button-bd: 1px solid var(--c-border);
--button-color: var(--mantine-color-white); --button-color: var(--mantine-color-white);
box-shadow: box-shadow:
0 1px 0 rgba(255, 255, 255, 0.04) inset, 0 1px 0 rgba(255, 255, 255, 0.04) inset,
@@ -307,7 +312,7 @@
} }
.payg-status[data-state="FULL"] .payg-status__dot { .payg-status[data-state="FULL"] .payg-status__dot {
background: var(--color-green-500); background: var(--color-green-500);
box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.18); box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-success) 18%, transparent);
} }
.payg-status[data-state="WARNED"] { .payg-status[data-state="WARNED"] {
background: var(--color-yellow-100); background: var(--color-yellow-100);
@@ -315,7 +320,7 @@
} }
.payg-status[data-state="WARNED"] .payg-status__dot { .payg-status[data-state="WARNED"] .payg-status__dot {
background: var(--color-yellow-500); background: var(--color-yellow-500);
box-shadow: 0 0 0 3px rgba(234, 179, 8, 0.2); box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-warning) 20%, transparent);
} }
.payg-status[data-state="DEGRADED"] { .payg-status[data-state="DEGRADED"] {
background: var(--color-red-100); background: var(--color-red-100);
@@ -323,7 +328,7 @@
} }
.payg-status[data-state="DEGRADED"] .payg-status__dot { .payg-status[data-state="DEGRADED"] .payg-status__dot {
background: var(--color-red-500); background: var(--color-red-500);
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2); box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-danger) 20%, transparent);
} }
/* Segmented usage bar */ /* Segmented usage bar */
@@ -331,7 +336,7 @@
margin-top: 18px; margin-top: 18px;
height: 10px; height: 10px;
border-radius: 999px; border-radius: 999px;
background: var(--bg-muted); background: var(--c-surface-sunken);
overflow: hidden; overflow: hidden;
position: relative; position: relative;
} }
@@ -341,13 +346,13 @@
transition: width 0.5s cubic-bezier(0.16, 1, 0.3, 1); transition: width 0.5s cubic-bezier(0.16, 1, 0.3, 1);
} }
.payg-bar__fill[data-state="FULL"] { .payg-bar__fill[data-state="FULL"] {
background: linear-gradient(90deg, #0a8bff, #38bdf8); background: var(--c-primary);
} }
.payg-bar__fill[data-state="WARNED"] { .payg-bar__fill[data-state="WARNED"] {
background: linear-gradient(90deg, #f59e0b, #fbbf24); background: var(--c-warning);
} }
.payg-bar__fill[data-state="DEGRADED"] { .payg-bar__fill[data-state="DEGRADED"] {
background: linear-gradient(90deg, #dc2626, #f87171); background: var(--c-danger);
} }
/* ── "What counts as a document?" expandable help ───────────────────── */ /* ── "What counts as a document?" expandable help ───────────────────── */
@@ -365,10 +370,10 @@
font: inherit; font: inherit;
font-size: 0.8125rem; font-size: 0.8125rem;
font-weight: 600; font-weight: 600;
color: var(--text-secondary); color: var(--c-text-muted);
} }
.payg-help__toggle:hover { .payg-help__toggle:hover {
color: var(--text-primary); color: var(--c-text);
} }
.payg-help__chevron { .payg-help__chevron {
transition: transform 0.15s ease; transition: transform 0.15s ease;
@@ -381,10 +386,10 @@
padding: 12px 14px; padding: 12px 14px;
border-radius: 10px; border-radius: 10px;
border: 1px solid var(--payg-card-border); border: 1px solid var(--payg-card-border);
background: var(--bg-muted); background: var(--c-surface-sunken);
font-size: 0.8125rem; font-size: 0.8125rem;
line-height: 1.45; line-height: 1.45;
color: var(--text-secondary); color: var(--c-text-muted);
} }
.payg-help__panel ul { .payg-help__panel ul {
margin: 0; margin: 0;
@@ -401,7 +406,7 @@
padding: 13px 16px; padding: 13px 16px;
border-radius: 10px; border-radius: 10px;
background: var(--payg-accent-soft); background: var(--payg-accent-soft);
border: 1px solid rgba(10, 139, 255, 0.2); border: 1px solid color-mix(in srgb, var(--c-primary) 20%, transparent);
} }
.payg-preview__icon { .payg-preview__icon {
color: var(--payg-accent); color: var(--payg-accent);
@@ -409,12 +414,12 @@
} }
.payg-preview__main { .payg-preview__main {
font-size: 0.875rem; font-size: 0.875rem;
color: var(--text-primary); color: var(--c-text);
font-weight: 550; font-weight: 550;
} }
.payg-preview__note { .payg-preview__note {
font-size: 0.75rem; font-size: 0.75rem;
color: var(--text-muted); color: var(--c-text-subtle);
margin-top: 1px; margin-top: 1px;
} }
@@ -453,17 +458,17 @@
flex-shrink: 0; flex-shrink: 0;
} }
.payg-gate[data-enabled="true"] .payg-gate__chip { .payg-gate[data-enabled="true"] .payg-gate__chip {
background: rgba(34, 197, 94, 0.16); background: color-mix(in srgb, var(--c-success) 16%, transparent);
color: #22c55e; color: var(--c-success);
} }
.payg-gate[data-enabled="false"] .payg-gate__chip { .payg-gate[data-enabled="false"] .payg-gate__chip {
background: rgba(239, 68, 68, 0.16); background: color-mix(in srgb, var(--c-danger) 16%, transparent);
color: #f87171; color: var(--c-danger);
} }
.payg-gate__label { .payg-gate__label {
font-size: 0.8125rem; font-size: 0.8125rem;
line-height: 1.35; line-height: 1.35;
color: var(--text-primary); color: var(--c-text);
flex: 1; flex: 1;
} }
.payg-gate__tag { .payg-gate__tag {
@@ -477,16 +482,16 @@
white-space: nowrap; white-space: nowrap;
} }
.payg-gate__tag[data-variant="on"] { .payg-gate__tag[data-variant="on"] {
color: var(--text-muted); color: var(--c-text-subtle);
background: var(--bg-muted); background: var(--c-surface-sunken);
} }
.payg-gate__tag[data-variant="pause"] { .payg-gate__tag[data-variant="pause"] {
color: #dc2626; color: var(--c-danger);
background: rgba(239, 68, 68, 0.12); background: color-mix(in srgb, var(--c-danger) 12%, transparent);
} }
[data-mantine-color-scheme="dark"] .payg-gate__tag[data-variant="pause"] { [data-mantine-color-scheme="dark"] .payg-gate__tag[data-variant="pause"] {
color: #f87171; color: var(--c-danger);
background: rgba(239, 68, 68, 0.18); background: color-mix(in srgb, var(--c-danger) 18%, transparent);
} }
/* ── Member rows ────────────────────────────────────────────────────── */ /* ── Member rows ────────────────────────────────────────────────────── */
@@ -509,17 +514,17 @@
justify-content: center; justify-content: center;
font-size: 0.8125rem; font-size: 0.8125rem;
font-weight: 650; font-weight: 650;
color: #fff; color: var(--c-text-on-primary);
flex-shrink: 0; flex-shrink: 0;
} }
.payg-member__name { .payg-member__name {
font-size: 0.875rem; font-size: 0.875rem;
font-weight: 550; font-weight: 550;
color: var(--text-primary); color: var(--c-text);
} }
.payg-member__email { .payg-member__email {
font-size: 0.75rem; font-size: 0.75rem;
color: var(--text-muted); color: var(--c-text-subtle);
} }
.payg-member__usage { .payg-member__usage {
text-align: right; text-align: right;
@@ -527,7 +532,7 @@
} }
.payg-member__usage-num { .payg-member__usage-num {
font-size: 0.8125rem; font-size: 0.8125rem;
color: var(--text-primary); color: var(--c-text);
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
.payg-member__minibar { .payg-member__minibar {
@@ -570,27 +575,27 @@
} }
.payg-activity__label { .payg-activity__label {
font-size: 0.8438rem; font-size: 0.8438rem;
color: var(--text-primary); color: var(--c-text);
flex: 1; flex: 1;
} }
.payg-activity__ts { .payg-activity__ts {
font-size: 0.75rem; font-size: 0.75rem;
color: var(--text-muted); color: var(--c-text-subtle);
} }
.payg-activity__kind { .payg-activity__kind {
font-size: 0.625rem; font-size: 0.625rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.05em; letter-spacing: 0.05em;
text-transform: uppercase; text-transform: uppercase;
color: var(--text-muted); color: var(--c-text-subtle);
background: var(--bg-muted); background: var(--c-surface-sunken);
padding: 2px 8px; padding: 2px 8px;
border-radius: 999px; border-radius: 999px;
} }
.payg-activity__units { .payg-activity__units {
font-size: 0.8125rem; font-size: 0.8125rem;
font-weight: 650; font-weight: 650;
color: var(--text-primary); color: var(--c-text);
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
min-width: 58px; min-width: 58px;
text-align: right; text-align: right;
@@ -604,20 +609,20 @@
gap: 16px; gap: 16px;
padding: 20px 24px; padding: 20px 24px;
border-radius: var(--payg-radius); border-radius: var(--payg-radius);
border: 1px solid rgba(99, 91, 255, 0.28); border: 1px solid color-mix(in srgb, var(--c-accent-stripe) 28%, transparent);
background: linear-gradient( background: linear-gradient(
135deg, 135deg,
rgba(99, 91, 255, 0.1) 0%, color-mix(in srgb, var(--c-accent-stripe) 10%, transparent) 0%,
rgba(99, 91, 255, 0.02) 100% color-mix(in srgb, var(--c-accent-stripe) 2%, transparent) 100%
); );
} }
.payg-stripe__title { .payg-stripe__title {
font-size: 0.9375rem; font-size: 0.9375rem;
font-weight: 650; font-weight: 650;
color: var(--text-primary); color: var(--c-text);
} }
.payg-stripe__subtitle { .payg-stripe__subtitle {
font-size: 0.8125rem; font-size: 0.8125rem;
color: var(--text-muted); color: var(--c-text-subtle);
margin-top: 2px; margin-top: 2px;
} }
@@ -60,12 +60,12 @@ interface PaygProps {
// Stable-ish avatar colour from a string. // Stable-ish avatar colour from a string.
const AVATAR_COLORS = [ const AVATAR_COLORS = [
"#0a8bff", "var(--c-avatar-1)",
"#8b5cf6", "var(--c-avatar-2)",
"#ec4899", "var(--c-avatar-3)",
"#10b981", "var(--c-avatar-4)",
"#f59e0b", "var(--c-avatar-5)",
"#06b6d4", "var(--c-avatar-6)",
]; ];
function avatarColor(seed: string): string { function avatarColor(seed: string): string {
let h = 0; let h = 0;
@@ -70,11 +70,11 @@
gap: 8px; gap: 8px;
font-size: 0.8rem; font-size: 0.8rem;
line-height: 1.45; line-height: 1.45;
color: var(--text-muted); color: var(--c-text-subtle);
} }
.paygf-proc__membernote-icon { .paygf-proc__membernote-icon {
flex-shrink: 0; flex-shrink: 0;
color: var(--text-muted); color: var(--c-text-subtle);
font-size: 1.1rem !important; font-size: 1.1rem !important;
margin-top: 1px; margin-top: 1px;
} }
@@ -113,12 +113,12 @@
font-weight: 750; font-weight: 750;
line-height: 1; line-height: 1;
letter-spacing: -0.02em; letter-spacing: -0.02em;
color: var(--text-primary); color: var(--c-text);
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
.paygf-meter__cap { .paygf-meter__cap {
font-size: 0.85rem; font-size: 0.85rem;
color: var(--text-muted); color: var(--c-text-subtle);
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
.paygf-meter .payg-bar { .paygf-meter .payg-bar {
@@ -131,7 +131,7 @@
align-items: center; align-items: center;
gap: 6px 10px; gap: 6px 10px;
font-size: 0.78rem; font-size: 0.78rem;
color: var(--text-secondary); color: var(--c-text-muted);
} }
/* ── Leader CTA card ──────────────────────────────────────────────────── */ /* ── Leader CTA card ──────────────────────────────────────────────────── */
@@ -145,8 +145,10 @@
border: 1.5px solid transparent; border: 1.5px solid transparent;
background: background:
linear-gradient(var(--payg-card-bg), var(--payg-card-bg)) padding-box, linear-gradient(var(--payg-card-bg), var(--payg-card-bg)) padding-box,
linear-gradient(135deg, var(--payg-accent) 0%, #6c5ce7 100%) border-box; linear-gradient(135deg, var(--payg-accent) 0%, var(--c-hue-purple) 100%)
box-shadow: 0 10px 28px -18px rgba(10, 139, 255, 0.4); border-box;
box-shadow: 0 10px 28px -18px
color-mix(in srgb, var(--c-primary) 40%, transparent);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16px; gap: 16px;
@@ -161,8 +163,12 @@
flex-shrink: 0; flex-shrink: 0;
padding: 10px; padding: 10px;
border-radius: 12px; border-radius: 12px;
background: linear-gradient(135deg, var(--payg-accent) 0%, #6c5ce7 100%); background: linear-gradient(
color: white !important; 135deg,
var(--payg-accent) 0%,
var(--c-hue-purple) 100%
);
color: var(--c-text-on-primary) !important;
font-size: 1.7rem !important; font-size: 1.7rem !important;
} }
.paygf-cta__heading-text { .paygf-cta__heading-text {
@@ -172,14 +178,14 @@
margin: 0; margin: 0;
font-size: 1.2rem; font-size: 1.2rem;
font-weight: 700; font-weight: 700;
color: var(--text-primary); color: var(--c-text);
letter-spacing: -0.01em; letter-spacing: -0.01em;
line-height: 1.25; line-height: 1.25;
} }
.paygf-cta__subtitle { .paygf-cta__subtitle {
margin: 4px 0 0; margin: 4px 0 0;
font-size: 0.9rem; font-size: 0.9rem;
color: var(--text-muted); color: var(--c-text-subtle);
line-height: 1.5; line-height: 1.5;
} }
@@ -196,7 +202,7 @@
align-items: flex-start; align-items: flex-start;
gap: 8px; gap: 8px;
font-size: 0.85rem; font-size: 0.85rem;
color: var(--text-primary); color: var(--c-text);
line-height: 1.45; line-height: 1.45;
} }
.paygf-cta__check { .paygf-cta__check {
@@ -220,7 +226,7 @@
.paygf-cta__reassurance { .paygf-cta__reassurance {
margin: 0; margin: 0;
font-size: 0.78rem; font-size: 0.78rem;
color: var(--text-muted); color: var(--c-text-subtle);
text-align: right; text-align: right;
} }
@@ -237,7 +243,7 @@
} }
.paygf-member-note__icon { .paygf-member-note__icon {
flex-shrink: 0; flex-shrink: 0;
color: var(--text-muted); color: var(--c-text-subtle);
padding: 8px; padding: 8px;
background: var(--payg-card-bg); background: var(--payg-card-bg);
border-radius: 10px; border-radius: 10px;
@@ -247,14 +253,14 @@
margin: 0; margin: 0;
font-size: 1rem; font-size: 1rem;
font-weight: 700; font-weight: 700;
color: var(--text-primary); color: var(--c-text);
letter-spacing: -0.005em; letter-spacing: -0.005em;
line-height: 1.3; line-height: 1.3;
} }
.paygf-member-note__body { .paygf-member-note__body {
margin: 6px 0 0; margin: 6px 0 0;
font-size: 0.875rem; font-size: 0.875rem;
color: var(--text-muted); color: var(--c-text-subtle);
line-height: 1.5; line-height: 1.5;
} }
@@ -285,14 +291,14 @@
font-weight: 700; font-weight: 700;
letter-spacing: 0.06em; letter-spacing: 0.06em;
text-transform: uppercase; text-transform: uppercase;
color: var(--text-muted); color: var(--c-text-subtle);
margin-bottom: 10px; margin-bottom: 10px;
} }
.paygf-explainer__icon { .paygf-explainer__icon {
font-size: 1rem !important; font-size: 1rem !important;
} }
.paygf-explainer__icon--free { .paygf-explainer__icon--free {
color: #10b981; color: var(--c-success);
} }
.paygf-explainer__icon--paid { .paygf-explainer__icon--paid {
color: var(--payg-accent); color: var(--payg-accent);
@@ -300,6 +306,6 @@
.paygf-explainer__text { .paygf-explainer__text {
margin: 0; margin: 0;
font-size: 0.85rem; font-size: 0.85rem;
color: var(--text-primary); color: var(--c-text);
line-height: 1.55; line-height: 1.55;
} }
@@ -9,12 +9,12 @@
Payg.css / UpgradeModal.css treatments the control sits beside. */ Payg.css / UpgradeModal.css treatments the control sits beside. */
.scc { .scc {
--scc-accent: #0a8bff; --scc-accent: var(--c-primary);
--scc-accent-text: #0a8bff; --scc-accent-text: var(--c-primary);
--scc-accent-soft: rgba(10, 139, 255, 0.12); --scc-accent-soft: color-mix(in srgb, var(--c-primary) 12%, transparent);
--scc-accent-border: rgba(10, 139, 255, 0.25); --scc-accent-border: color-mix(in srgb, var(--c-primary) 25%, transparent);
--scc-chip-bg: var(--bg-muted); --scc-chip-bg: var(--c-surface-sunken);
--scc-chip-border: var(--border-default); --scc-chip-border: var(--c-border);
/* Consistent vertical rhythm between the control row, the estimate, and any /* Consistent vertical rhythm between the control row, the estimate, and any
note — without it the blocks sit flush. */ note — without it the blocks sit flush. */
display: flex; display: flex;
@@ -22,10 +22,10 @@
gap: 14px; gap: 14px;
} }
[data-mantine-color-scheme="dark"] .scc { [data-mantine-color-scheme="dark"] .scc {
--scc-accent-text: #7ab4ff; /* Chip surface/border track the neutral --c-* tokens (base rule); only the
--scc-accent-soft: rgba(79, 142, 245, 0.16); brand-azure accent is tuned brighter for dark. */
--scc-chip-bg: #1c2340; --scc-accent-text: var(--c-primary);
--scc-chip-border: #2d3560; --scc-accent-soft: color-mix(in srgb, var(--c-primary) 16%, transparent);
} }
/* ── Inline row: presets · custom · no-cap · (save) ──────────────────── */ /* ── Inline row: presets · custom · no-cap · (save) ──────────────────── */
@@ -47,7 +47,7 @@
border-radius: 999px; border-radius: 999px;
border: 1px solid var(--scc-chip-border); border: 1px solid var(--scc-chip-border);
background: var(--scc-chip-bg); background: var(--scc-chip-bg);
color: var(--text-secondary); color: var(--c-text-muted);
font: inherit; font: inherit;
font-size: 0.85rem; font-size: 0.85rem;
font-weight: 600; font-weight: 600;
@@ -59,8 +59,8 @@
background 0.12s ease; background 0.12s ease;
} }
.scc-chip:hover:not(:disabled) { .scc-chip:hover:not(:disabled) {
color: var(--text-primary); color: var(--c-text);
border-color: var(--border-strong); border-color: var(--c-border-strong);
} }
.scc-chip[data-selected="true"] { .scc-chip[data-selected="true"] {
background: var(--scc-accent-soft); background: var(--scc-accent-soft);
@@ -90,7 +90,7 @@
background 0.12s ease; background 0.12s ease;
} }
.scc-custom:hover { .scc-custom:hover {
border-color: var(--border-strong); border-color: var(--c-border-strong);
} }
.scc-custom[data-active="true"] { .scc-custom[data-active="true"] {
border-style: solid; border-style: solid;
@@ -98,7 +98,7 @@
background: var(--scc-accent-soft); background: var(--scc-accent-soft);
} }
.scc-custom__symbol { .scc-custom__symbol {
color: var(--text-muted); color: var(--c-text-subtle);
font-size: 0.85rem; font-size: 0.85rem;
font-weight: 600; font-weight: 600;
} }
@@ -111,14 +111,14 @@
border: none; border: none;
outline: none; outline: none;
background: transparent; background: transparent;
color: var(--text-primary); color: var(--c-text);
font: inherit; font: inherit;
font-size: 0.85rem; font-size: 0.85rem;
font-weight: 600; font-weight: 600;
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
.scc-custom__input::placeholder { .scc-custom__input::placeholder {
color: var(--text-muted); color: var(--c-text-subtle);
font-weight: 600; font-weight: 600;
} }
.scc-custom:disabled, .scc-custom:disabled,
@@ -148,17 +148,17 @@
.scc-estimate__main { .scc-estimate__main {
font-size: 0.875rem; font-size: 0.875rem;
font-weight: 550; font-weight: 550;
color: var(--text-primary); color: var(--c-text);
} }
.scc-estimate__sub { .scc-estimate__sub {
font-size: 0.75rem; font-size: 0.75rem;
color: var(--text-muted); color: var(--c-text-subtle);
margin-top: 1px; margin-top: 1px;
} }
/* Quiet helper line (e.g. "Shown in USD — change later in your currency"). */ /* Quiet helper line (e.g. "Shown in USD — change later in your currency"). */
.scc-note { .scc-note {
font-size: 0.8125rem; font-size: 0.8125rem;
color: var(--text-muted); color: var(--c-text-subtle);
line-height: 1.45; line-height: 1.45;
} }
@@ -11,6 +11,7 @@ import {
} from "@mantine/core"; } from "@mantine/core";
import { Button } from "@app/ui/Button"; import { Button } from "@app/ui/Button";
import { ActionIcon } from "@app/ui/ActionIcon"; import { ActionIcon } from "@app/ui/ActionIcon";
import { StatusBadge } from "@app/ui/StatusBadge";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useSaaSTeam } from "@app/contexts/SaaSTeamContext"; import { useSaaSTeam } from "@app/contexts/SaaSTeamContext";
import LocalIcon from "@app/components/shared/LocalIcon"; import LocalIcon from "@app/components/shared/LocalIcon";
@@ -265,12 +266,14 @@ const TeamSection: React.FC = () => {
</ActionIcon> </ActionIcon>
)} )}
{isTeamLeader && ( {isTeamLeader && (
<Badge color="blue">{t("team.leader", "LEADER")}</Badge> <StatusBadge tone="info" showDot={false}>
{t("team.leader", "LEADER")}
</StatusBadge>
)} )}
{isPersonalTeam && ( {isPersonalTeam && (
<Badge color="gray" variant="light" size="xs"> <StatusBadge tone="neutral" showDot={false}>
{t("team.personal", "Personal")} {t("team.personal", "Personal")}
</Badge> </StatusBadge>
)} )}
</Group> </Group>
)} )}
@@ -430,8 +433,8 @@ const TeamSection: React.FC = () => {
style={ style={
member.role !== "LEADER" member.role !== "LEADER"
? { ? {
backgroundColor: "var(--tool-header-badge-bg)", backgroundColor: "var(--c-surface-raised)",
color: "var(--tool-header-badge-text)", color: "var(--c-accent-fg)",
} }
: undefined : undefined
} }
@@ -5,22 +5,21 @@
user feels like they're filling out one form, not navigating pages. */ user feels like they're filling out one form, not navigating pages. */
.upm { .upm {
--upm-accent: #0a8bff; --upm-accent: var(--c-primary);
--upm-accent-2: #6c5ce7; --upm-accent-2: var(--c-hue-purple);
--upm-accent-soft: rgba(10, 139, 255, 0.08); --upm-accent-soft: color-mix(in srgb, var(--c-primary) 8%, transparent);
--upm-success: #10b981; --upm-success: var(--c-success);
--upm-radius: 18px; --upm-radius: 18px;
--upm-card-bg: var(--bg-surface); --upm-card-bg: var(--c-surface);
--upm-border: var(--border-default); --upm-border: var(--c-border);
--upm-divider: var(--border-subtle); --upm-divider: var(--c-border-subtle);
--upm-text: var(--text-primary); --upm-text: var(--c-text);
--upm-muted: var(--text-muted); --upm-muted: var(--c-text-subtle);
} }
[data-mantine-color-scheme="dark"] .upm { [data-mantine-color-scheme="dark"] .upm {
--upm-card-bg: #1c2340; /* Card/border/divider track the neutral --c-* tokens (base rule); only the
--upm-border: #2d3560; brand-azure accent tint is tuned for dark. */
--upm-divider: #2d3560; --upm-accent-soft: color-mix(in srgb, var(--c-primary) 14%, transparent);
--upm-accent-soft: rgba(79, 142, 245, 0.14);
} }
/* Backdrop locks the page and centres the modal. z-index matches /* Backdrop locks the page and centres the modal. z-index matches
@@ -150,7 +149,7 @@
.upm-step[data-state="active"] .upm-step__dot { .upm-step[data-state="active"] .upm-step__dot {
background: linear-gradient(135deg, var(--upm-accent), var(--upm-accent-2)); background: linear-gradient(135deg, var(--upm-accent), var(--upm-accent-2));
border-color: transparent; border-color: transparent;
color: white; color: var(--c-text-on-primary);
} }
.upm-step[data-state="done"] { .upm-step[data-state="done"] {
color: var(--upm-success); color: var(--upm-success);
@@ -158,7 +157,7 @@
.upm-step[data-state="done"] .upm-step__dot { .upm-step[data-state="done"] .upm-step__dot {
background: var(--upm-success); background: var(--upm-success);
border-color: transparent; border-color: transparent;
color: white; color: var(--c-text-on-primary);
} }
.upm-step__connector { .upm-step__connector {
flex: 1 1 auto; flex: 1 1 auto;
@@ -254,7 +253,7 @@
border-radius: 6px; border-radius: 6px;
} }
.upm-step__edit:hover { .upm-step__edit:hover {
background: rgba(10, 139, 255, 0.12); background: color-mix(in srgb, var(--c-primary) 12%, transparent);
} }
/* Placeholder card for the loading / error / mock states — a dashed, centered /* Placeholder card for the loading / error / mock states — a dashed, centered
@@ -327,8 +326,10 @@
} }
.upm-confirm__icon { .upm-confirm__icon {
font-size: 64px !important; font-size: 64px !important;
color: #10b981; color: var(--upm-success);
filter: drop-shadow(0 6px 18px rgba(16, 185, 129, 0.35)); filter: drop-shadow(
0 6px 18px color-mix(in srgb, var(--c-success) 35%, transparent)
);
} }
.upm-confirm__title { .upm-confirm__title {
margin: 6px 0 0; margin: 6px 0 0;
@@ -61,7 +61,9 @@ function Swatch({ label, src, onDark, h }: Asset & { h: number }) {
> >
<img src={src} alt={label} style={{ height: h, maxWidth: 200 }} /> <img src={src} alt={label} style={{ height: h, maxWidth: 200 }} />
</div> </div>
<figcaption style={{ fontSize: 12, color: "var(--text-muted, #71717a)" }}> <figcaption
style={{ fontSize: 12, color: "var(--c-text-subtle, #71717a)" }}
>
{label} {label}
</figcaption> </figcaption>
</figure> </figure>
@@ -221,7 +221,7 @@ const FileManager: React.FC<FileManagerProps> = ({ selectedTool }) => {
width: "100%", width: "100%",
border: "none", border: "none",
borderRadius: "var(--radius-md)", borderRadius: "var(--radius-md)",
backgroundColor: "var(--bg-file-manager)", backgroundColor: "var(--c-bg)",
}} }}
styles={{ styles={{
inner: { pointerEvents: "all" }, inner: { pointerEvents: "all" },
@@ -227,7 +227,7 @@ export const TextInputWithFont: React.FC<TextInputWithFontProps> = ({
width: 24, width: 24,
height: 24, height: 24,
backgroundColor: textColor, backgroundColor: textColor,
border: "1px solid #ccc", border: "1px solid var(--c-border)",
borderRadius: 4, borderRadius: 4,
cursor: disabled ? "default" : "pointer", cursor: disabled ? "default" : "pointer",
}} }}
@@ -110,7 +110,7 @@ const AddFileCard = ({
variant="tertiary" variant="tertiary"
style={{ style={{
backgroundColor: "var(--landing-button-bg)", backgroundColor: "var(--landing-button-bg)",
color: "var(--landing-button-color)", color: "var(--c-accent-fg)",
border: "1px solid var(--landing-button-border)", border: "1px solid var(--landing-button-border)",
borderRadius: "2rem", borderRadius: "2rem",
height: "38px", height: "38px",
@@ -129,7 +129,7 @@ const AddFileCard = ({
icon="add" icon="add"
width="1.5rem" width="1.5rem"
height="1.5rem" height="1.5rem"
className="text-[var(--accent-interactive)]" className="text-[var(--c-primary)]"
/> />
<span>{t("landing.addFiles", "Add Files")}</span> <span>{t("landing.addFiles", "Add Files")}</span>
</Button> </Button>
@@ -140,7 +140,7 @@ const AddFileCard = ({
title={terminology.uploadFromComputer} title={terminology.uploadFromComputer}
style={{ style={{
backgroundColor: "var(--landing-button-bg)", backgroundColor: "var(--landing-button-bg)",
color: "var(--landing-button-color)", color: "var(--c-accent-fg)",
border: "1px solid var(--landing-button-border)", border: "1px solid var(--landing-button-border)",
borderRadius: "1rem", borderRadius: "1rem",
height: "38px", height: "38px",
@@ -161,7 +161,7 @@ const AddFileCard = ({
icon={icons.uploadIconName} icon={icons.uploadIconName}
width="1.25rem" width="1.25rem"
height="1.25rem" height="1.25rem"
style={{ color: "var(--accent-interactive)", flexShrink: 0 }} style={{ color: "var(--c-primary)", flexShrink: 0 }}
/> />
{isUploadHover && ( {isUploadHover && (
<span <span
@@ -181,7 +181,7 @@ const AddFileCard = ({
{/* Instruction Text */} {/* Instruction Text */}
<span <span
className="text-[var(--accent-interactive)]" className="text-[var(--c-primary)]"
style={{ style={{
fontSize: ".8rem", fontSize: ".8rem",
textAlign: "center", textAlign: "center",
@@ -3,7 +3,7 @@
========================= */ ========================= */
.card { .card {
background: var(--file-card-bg); background: var(--c-surface-raised);
border-radius: 0.0625rem; border-radius: 0.0625rem;
cursor: pointer; cursor: pointer;
transition: transition:
@@ -28,7 +28,7 @@
/* While dragging */ /* While dragging */
.card.dragging, .card.dragging,
.card:global(.dragging) { .card:global(.dragging) {
outline: 1px solid var(--border-strong); outline: 1px solid var(--c-border-strong);
box-shadow: var(--shadow-md); box-shadow: var(--shadow-md);
transform: none !important; transform: none !important;
} }
@@ -42,15 +42,17 @@
justify-content: space-between; justify-content: space-between;
padding: 0 6px; padding: 0 6px;
user-select: none; user-select: none;
background: var(--bg-toolbar); background: var(--c-bg-raised);
color: var(--text-primary); color: var(--c-text);
border-bottom: 1px solid var(--border-default); border-bottom: 1px solid var(--c-border);
} }
.headerResting { .headerResting {
background: #3b4b6e; /* dark blue for unselected in light mode */ background: var(
color: #ffffff; --c-file-header-resting
border-bottom: 1px solid var(--border-default); ); /* branded navy for unselected files */
color: var(--c-text-on-primary);
border-bottom: 1px solid var(--c-border);
} }
.headerSelected { .headerSelected {
@@ -62,20 +64,20 @@
/* Error highlight (transient) */ /* Error highlight (transient) */
.headerError { .headerError {
background: var(--color-red-200); background: var(--color-red-200);
color: var(--text-primary); color: var(--c-text);
border-bottom: 2px solid var(--color-red-500); border-bottom: 2px solid var(--color-red-500);
} }
/* Unsupported (but not errored) header appearance */ /* Unsupported (but not errored) header appearance */
.headerUnsupported { .headerUnsupported {
background: var(--unsupported-bar-bg); /* neutral gray */ background: var(--c-bg-raised); /* neutral gray */
color: #ffffff; color: var(--c-text-on-primary);
border-bottom: 1px solid var(--unsupported-bar-border); border-bottom: 1px solid var(--c-border);
} }
/* Selected border color in light mode */ /* Selected border color in light mode */
:global([data-mantine-color-scheme="light"]) .card[data-selected="true"] { :global([data-mantine-color-scheme="light"]) .card[data-selected="true"] {
outline-color: var(--card-selected-border); outline-color: var(--c-primary);
} }
/* Reserve space for checkbox instead of logo */ /* Reserve space for checkbox instead of logo */
@@ -106,7 +108,7 @@
} }
.headerIconButton { .headerIconButton {
color: #ffffff !important; color: var(--c-text-on-primary) !important;
} }
/* Menu dropdown */ /* Menu dropdown */
@@ -117,12 +119,12 @@
/* -------- Title / Meta -------- */ /* -------- Title / Meta -------- */
.title { .title {
line-height: 1.2; line-height: 1.2;
color: var(--text-primary); color: var(--c-text);
} }
.meta { .meta {
margin-top: 2px; margin-top: 2px;
color: var(--text-secondary); color: var(--c-text-muted);
} }
/* -------- Preview area -------- */ /* -------- Preview area -------- */
@@ -131,7 +133,7 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
background: var(--file-card-bg); background: var(--c-surface-raised);
} }
.previewPaper { .previewPaper {
@@ -142,7 +144,7 @@
display: grid; display: grid;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
background: var(--file-card-bg); background: var(--c-surface-raised);
} }
/* Thumbnail fallback */ /* Thumbnail fallback */
@@ -152,7 +154,7 @@
inset: 0; inset: 0;
display: grid; display: grid;
place-items: center; place-items: center;
color: var(--text-secondary); color: var(--c-text-muted);
font-weight: 600; font-weight: 600;
font-size: 12px; font-size: 12px;
} }
@@ -162,7 +164,7 @@
position: absolute; position: absolute;
bottom: 6px; bottom: 6px;
right: 6px; right: 6px;
color: var(--text-secondary); color: var(--c-text-muted);
z-index: 1; z-index: 1;
cursor: grab; cursor: grab;
display: inline-flex; display: inline-flex;
@@ -173,12 +175,12 @@
position: absolute; position: absolute;
left: 0; left: 0;
top: 44px; /* just below header */ top: 44px; /* just below header */
background: var(--bg-toolbar); background: var(--c-bg-raised);
border-bottom: 1px solid var(--border-default); border-bottom: 1px solid var(--c-border);
z-index: 20; z-index: 20;
overflow: hidden; overflow: hidden;
animation: slideDown 140ms ease-out; animation: slideDown 140ms ease-out;
color: var(--text-primary); color: var(--c-text);
} }
@keyframes slideDown { @keyframes slideDown {
@@ -200,13 +202,13 @@
padding: 12px 16px; padding: 12px 16px;
background: transparent; background: transparent;
border: none; border: none;
color: var(--text-primary); color: var(--c-text);
cursor: pointer; cursor: pointer;
text-align: left; text-align: left;
} }
.actionRow:hover { .actionRow:hover {
background: var(--hover-bg); background: var(--c-hover);
} }
.actionDanger { .actionDanger {
@@ -215,7 +217,7 @@
.actionsDivider { .actionsDivider {
height: 1px; height: 1px;
background: var(--border-default); background: var(--c-border);
margin: 4px 0; margin: 4px 0;
} }
@@ -229,13 +231,13 @@
} }
.pinned { .pinned {
color: #ffc107 !important; color: var(--c-warning) !important;
} }
/* Unsupported file indicator */ /* Unsupported file indicator */
.unsupportedPill { .unsupportedPill {
margin-left: 1.75rem; margin-left: 1.75rem;
background: #6b7280; background: var(--c-neutral-fill);
color: white; color: white;
padding: 4px 8px; padding: 4px 8px;
border-radius: 12px; border-radius: 12px;
@@ -252,7 +254,7 @@
.errorPill { .errorPill {
margin-left: 1.75rem; margin-left: 1.75rem;
background: var(--color-red-500); background: var(--color-red-500);
color: #ffffff; color: var(--c-text-on-primary);
padding: 4px 8px; padding: 4px 8px;
border-radius: 12px; border-radius: 12px;
font-size: 10px; font-size: 10px;
@@ -291,36 +293,36 @@
DARK MODE OVERRIDES DARK MODE OVERRIDES
========================= */ ========================= */
:global([data-mantine-color-scheme="dark"]) .card { :global([data-mantine-color-scheme="dark"]) .card {
outline-color: #1c2340; /* deselected stroke */ outline-color: var(--c-border); /* deselected stroke */
} }
:global([data-mantine-color-scheme="dark"]) .card[data-selected="true"] { :global([data-mantine-color-scheme="dark"]) .card[data-selected="true"] {
outline-color: #2d3560; /* selected stroke (subtle navy) */ outline-color: var(--c-primary); /* selected stroke (subtle navy) */
} }
:global([data-mantine-color-scheme="dark"]) .headerResting { :global([data-mantine-color-scheme="dark"]) .headerResting {
background: #0d1020; /* requested default unselected color */ /* Background flips via the themed --c-file-header-resting token. */
color: var(--tool-header-text); /* #D0D6DC */ color: var(--c-accent-fg, var(--c-primary));
border-bottom-color: var(--tool-header-border); /* #3A4047 */ border-bottom-color: var(--c-border);
} }
:global([data-mantine-color-scheme="dark"]) .headerSelected { :global([data-mantine-color-scheme="dark"]) .headerSelected {
background: var(--tool-header-border); /* #3A4047 */ background: var(--c-border);
color: var(--tool-header-text); /* #D0D6DC */ color: var(--c-accent-fg, var(--c-primary));
border-bottom-color: var(--tool-header-border); border-bottom-color: var(--c-border);
} }
:global([data-mantine-color-scheme="dark"]) .title { :global([data-mantine-color-scheme="dark"]) .title {
color: #d0d6dc; /* title text */ color: var(--c-text); /* title text */
} }
:global([data-mantine-color-scheme="dark"]) .meta { :global([data-mantine-color-scheme="dark"]) .meta {
color: #6b7280; /* subtitle text */ color: var(--c-text-muted); /* subtitle text */
} }
/* Light mode selected header stroke override */ /* Light mode selected header stroke override */
:global([data-mantine-color-scheme="light"]) .card[data-selected="true"] { :global([data-mantine-color-scheme="light"]) .card[data-selected="true"] {
outline-color: #3b4b6e; outline-color: var(--c-primary);
} }
/* ========================= /* =========================
@@ -333,7 +335,7 @@
height: calc(310px - 0.5rem); height: calc(310px - 0.5rem);
margin: 0.5rem auto 0; margin: 0.5rem auto 0;
background: var(--c-bg); background: var(--c-bg);
border: 1.5px solid var(--border-default); border: 1.5px solid var(--c-border);
border-radius: 12px; border-radius: 12px;
box-shadow: var(--shadow-md); box-shadow: var(--shadow-md);
cursor: pointer; cursor: pointer;
@@ -347,11 +349,11 @@
.addFileCard:hover { .addFileCard:hover {
box-shadow: var(--shadow-lg); box-shadow: var(--shadow-lg);
transform: translateY(-1px); transform: translateY(-1px);
border-color: var(--accent-interactive); border-color: var(--c-primary);
} }
.addFileCard:focus-visible { .addFileCard:focus-visible {
outline: 2px solid var(--accent-interactive); outline: 2px solid var(--c-primary);
outline-offset: 2px; outline-offset: 2px;
} }
@@ -386,7 +388,7 @@
} }
.addFileCard:hover .addFileText { .addFileCard:hover .addFileText {
color: var(--text-primary); color: var(--c-text);
} }
.addFileSubtext { .addFileSubtext {
@@ -75,7 +75,7 @@
box-shadow: var(--shadow-md); box-shadow: var(--shadow-md);
overflow: hidden; overflow: hidden;
position: relative; position: relative;
background: var(--bg-surface); background: var(--c-surface);
transition: transition:
box-shadow 0.15s ease, box-shadow 0.15s ease,
transform 0.2s ease; transform 0.2s ease;
@@ -91,7 +91,7 @@
height: 100%; height: 100%;
object-fit: contain; object-fit: contain;
border-radius: 12px; border-radius: 12px;
background: var(--bg-surface); background: var(--c-surface);
display: block; display: block;
position: relative; position: relative;
z-index: 1; z-index: 1;
@@ -115,7 +115,7 @@
.fileName { .fileName {
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
color: var(--text-primary); color: var(--c-text);
line-height: var(--file-name-line-height); line-height: var(--file-name-line-height);
height: calc(var(--file-name-lines) * var(--file-name-line-height)); height: calc(var(--file-name-lines) * var(--file-name-line-height));
margin: 0; margin: 0;
@@ -149,7 +149,7 @@
.fileMeta { .fileMeta {
font-size: 11px; font-size: 11px;
color: var(--text-secondary); color: var(--c-text-muted);
line-height: var(--file-meta-line-height); line-height: var(--file-meta-line-height);
height: var(--file-meta-line-height); height: var(--file-meta-line-height);
overflow: hidden; overflow: hidden;
@@ -183,7 +183,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: rgba(220, 38, 38, 0.12); background: color-mix(in srgb, var(--c-danger) 12%, transparent);
border-radius: 12px; border-radius: 12px;
z-index: 2; z-index: 2;
pointer-events: none; pointer-events: none;
@@ -191,7 +191,7 @@
.errorPill { .errorPill {
background: var(--mantine-color-red-6); background: var(--mantine-color-red-6);
color: white; color: var(--c-text-on-primary);
border-radius: 12px; border-radius: 12px;
padding: 4px 12px; padding: 4px 12px;
font-size: 12px; font-size: 12px;
@@ -233,7 +233,7 @@
.ownershipBadge { .ownershipBadge {
background: var(--mantine-color-blue-6); background: var(--mantine-color-blue-6);
color: white; color: var(--c-text-on-primary);
border-radius: 6px; border-radius: 6px;
padding: 2px 7px; padding: 2px 7px;
font-size: 10px; font-size: 10px;
@@ -247,14 +247,14 @@
padding: 1px 5px; padding: 1px 5px;
font-size: 10px; font-size: 10px;
font-weight: 700; font-weight: 700;
color: white; color: var(--c-text-on-primary);
line-height: 16px; line-height: 16px;
white-space: nowrap; white-space: nowrap;
} }
.pinnedBadge { .pinnedBadge {
background: var(--mantine-color-yellow-6); background: var(--mantine-color-yellow-6);
color: white; color: var(--c-text-on-primary);
border-radius: 4px; border-radius: 4px;
padding: 2px 4px; padding: 2px 4px;
display: flex; display: flex;
@@ -268,7 +268,7 @@
bottom: 6px; bottom: 6px;
right: 6px; right: 6px;
cursor: grab; cursor: grab;
color: var(--text-secondary); color: var(--c-text-muted);
opacity: 0; opacity: 0;
transition: opacity 0.15s ease; transition: opacity 0.15s ease;
pointer-events: none; pointer-events: none;
@@ -50,7 +50,7 @@ const DesktopLayout: React.FC = () => {
flex: 1, flex: 1,
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
backgroundColor: "var(--bg-file-list)", backgroundColor: "var(--c-surface)",
border: "1px solid var(--mantine-color-gray-2)", border: "1px solid var(--mantine-color-gray-2)",
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)", boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
overflow: "hidden", overflow: "hidden",
@@ -81,8 +81,8 @@ const EmptyFilesState: React.FC = () => {
variant="tertiary" variant="tertiary"
aria-label={t("emptyFilesState.upload", "Upload")} aria-label={t("emptyFilesState.upload", "Upload")}
style={{ style={{
backgroundColor: "var(--bg-file-manager)", backgroundColor: "var(--c-bg)",
color: "var(--landing-button-color)", color: "var(--c-accent-fg)",
border: "1px solid var(--landing-button-border)", border: "1px solid var(--landing-button-border)",
borderRadius: isUploadHover ? "2rem" : "1rem", borderRadius: isUploadHover ? "2rem" : "1rem",
height: "38px", height: "38px",
@@ -103,7 +103,7 @@ const EmptyFilesState: React.FC = () => {
icon={icons.uploadIconName} icon={icons.uploadIconName}
width="1.25rem" width="1.25rem"
height="1.25rem" height="1.25rem"
style={{ color: "var(--accent-interactive)" }} style={{ color: "var(--c-primary)" }}
/> />
{isUploadHover && ( {isUploadHover && (
<span style={{ marginLeft: ".5rem" }}> <span style={{ marginLeft: ".5rem" }}>
@@ -115,7 +115,7 @@ const EmptyFilesState: React.FC = () => {
{/* Instruction Text */} {/* Instruction Text */}
<span <span
className="text-[var(--accent-interactive)]" className="text-[var(--c-primary)]"
style={{ fontSize: ".8rem", textAlign: "center" }} style={{ fontSize: ".8rem", textAlign: "center" }}
> >
{terminology.dropFilesHere} {terminology.dropFilesHere}
@@ -189,7 +189,7 @@ const FileListItem: React.FC<FileListItemProps> = ({
backgroundColor: backgroundColor:
isSelected || shouldShowHovered isSelected || shouldShowHovered
? "var(--mantine-color-gray-1)" ? "var(--mantine-color-gray-1)"
: "var(--bg-file-list)", : "var(--c-surface)",
opacity: 1, opacity: 1,
transition: "background-color 0.15s ease", transition: "background-color 0.15s ease",
userSelect: "none", userSelect: "none",
@@ -47,7 +47,7 @@ const MobileLayout: React.FC = () => {
flex: 1, flex: 1,
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
backgroundColor: "var(--bg-file-list)", backgroundColor: "var(--c-surface)",
borderRadius: "0.5rem", borderRadius: "0.5rem",
border: "1px solid var(--mantine-color-gray-2)", border: "1px solid var(--mantine-color-gray-2)",
overflow: "hidden", overflow: "hidden",
@@ -201,7 +201,7 @@ export function FileDetailsPanel({
<img src={single.thumbnailUrl} alt="" /> <img src={single.thumbnailUrl} alt="" />
) : ( ) : (
<PictureAsPdfIcon <PictureAsPdfIcon
style={{ fontSize: "3rem", color: "var(--text-muted)" }} style={{ fontSize: "3rem", color: "var(--c-text-subtle)" }}
/> />
)} )}
</div> </div>
@@ -499,7 +499,7 @@ function FolderCard({
<div <div
className="files-page-card-thumb" className="files-page-card-thumb"
style={{ style={{
background: `linear-gradient(135deg, color-mix(in srgb, ${folder.color ?? "var(--accent-interactive, #6366f1)"} 18%, var(--bg-surface)), color-mix(in srgb, ${folder.color ?? "var(--accent-interactive, #6366f1)"} 6%, var(--bg-surface)))`, background: `linear-gradient(135deg, color-mix(in srgb, ${folder.color ?? "var(--c-primary)"} 18%, var(--c-surface)), color-mix(in srgb, ${folder.color ?? "var(--c-primary)"} 6%, var(--c-surface)))`,
}} }}
> >
<FolderThumbnail <FolderThumbnail
@@ -845,7 +845,7 @@ export default function FileManagerView() {
fontSize: "0.95rem", fontSize: "0.95rem",
fontWeight: 600, fontWeight: 600,
padding: "0.25rem 0.5rem", padding: "0.25rem 0.5rem",
color: "var(--text-primary)", color: "var(--c-text)",
}} }}
> >
{currentTab === "local" {currentTab === "local"
@@ -991,9 +991,9 @@ export default function FileManagerView() {
style={{ style={{
padding: "0.6rem 1.25rem", padding: "0.6rem 1.25rem",
background: background:
"color-mix(in srgb, var(--mantine-color-red-6, #e03131) 12%, transparent)", "color-mix(in srgb, var(--mantine-color-red-6) 12%, transparent)",
color: "var(--text-primary)", color: "var(--c-text)",
borderBottom: "1px solid var(--border-subtle)", borderBottom: "1px solid var(--c-border-subtle)",
fontSize: "0.85rem", fontSize: "0.85rem",
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "space-between",
@@ -1083,15 +1083,15 @@ export default function FileManagerView() {
style={{ style={{
background: background:
currentTab === tab.id currentTab === tab.id
? "var(--hover-bg)" ? "var(--c-hover)"
: "transparent", : "transparent",
border: "none", border: "none",
borderRadius: "0.3rem", borderRadius: "0.3rem",
padding: "0.2rem 0.6rem", padding: "0.2rem 0.6rem",
color: color:
currentTab === tab.id currentTab === tab.id
? "var(--text-primary)" ? "var(--c-text)"
: "var(--text-muted)", : "var(--c-text-subtle)",
fontWeight: currentTab === tab.id ? 500 : 400, fontWeight: currentTab === tab.id ? 500 : 400,
fontSize: "0.75rem", fontSize: "0.75rem",
cursor: "pointer", cursor: "pointer",
@@ -1662,7 +1662,7 @@ const SearchField = React.forwardRef<
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<div className="files-page-search"> <div className="files-page-search">
<SearchIcon fontSize="small" style={{ color: "var(--text-muted)" }} /> <SearchIcon fontSize="small" style={{ color: "var(--c-text-subtle)" }} />
<input <input
ref={ref} ref={ref}
type="text" type="text"
@@ -27,19 +27,17 @@ const styles = {
lineHeight: 1.2, lineHeight: 1.2,
}, },
local: { local: {
background: background: "color-mix(in srgb, var(--c-text-subtle) 16%, transparent)",
"color-mix(in srgb, var(--text-muted, #6b7280) 16%, transparent)", color: "var(--c-text-muted)",
color: "var(--text-secondary)",
}, },
cloud: { cloud: {
background: background: "color-mix(in srgb, var(--c-primary) 16%, transparent)",
"color-mix(in srgb, var(--accent-interactive, #6366f1) 16%, transparent)", color: "var(--c-primary)",
color: "var(--accent-interactive, #6366f1)",
}, },
shared: { shared: {
background: background:
"color-mix(in srgb, var(--mantine-color-orange-6, #f97316) 16%, transparent)", "color-mix(in srgb, var(--mantine-color-orange-6) 16%, transparent)",
color: "var(--mantine-color-orange-6, #f97316)", color: "var(--mantine-color-orange-6)",
}, },
}; };
@@ -3,8 +3,8 @@
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: var(--bg-background); background: var(--c-bg);
color: var(--text-primary); color: var(--c-text);
overflow: hidden; overflow: hidden;
} }
@@ -22,8 +22,8 @@
gap: 1rem; gap: 1rem;
min-height: 48px; min-height: 48px;
padding: 0 0.75rem; padding: 0 0.75rem;
border-bottom: 1px solid var(--border-subtle); border-bottom: 1px solid var(--c-border-subtle);
background: var(--bg-toolbar); background: var(--c-bg-raised);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -52,7 +52,7 @@
border: none; border: none;
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;
border-radius: 0.375rem; border-radius: 0.375rem;
color: var(--text-secondary); color: var(--c-text-muted);
cursor: pointer; cursor: pointer;
font-size: inherit; font-size: inherit;
font-weight: 500; font-weight: 500;
@@ -64,19 +64,14 @@
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.files-page-breadcrumb:hover,
.files-page-breadcrumb:hover {
background: var(--hover-bg);
color: var(--text-primary);
}
.files-page-breadcrumb.is-current { .files-page-breadcrumb.is-current {
color: var(--text-primary); background: var(--c-hover);
background: var(--hover-bg); color: var(--c-text);
} }
.files-page-breadcrumb-sep { .files-page-breadcrumb-sep {
color: var(--text-muted); color: var(--c-text-subtle);
font-size: 1rem !important; font-size: 1rem !important;
width: 1rem; width: 1rem;
height: 1rem; height: 1rem;
@@ -88,8 +83,8 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.35rem; gap: 0.35rem;
background: var(--bg-surface); background: var(--c-surface);
border: 1px solid var(--border-subtle); border: 1px solid var(--c-border-subtle);
border-radius: 999px; border-radius: 999px;
padding: 0.2rem 0.75rem; padding: 0.2rem 0.75rem;
/* Fills its grid cell; the cell's minmax(...) clamps to a sensible range. */ /* Fills its grid cell; the cell's minmax(...) clamps to a sensible range. */
@@ -102,7 +97,7 @@
border: none; border: none;
outline: none; outline: none;
flex: 1; flex: 1;
color: var(--text-primary); color: var(--c-text);
font-size: 0.9rem; font-size: 0.9rem;
} }
@@ -116,8 +111,8 @@
.files-page-tree { .files-page-tree {
width: 17rem; width: 17rem;
flex-shrink: 0; flex-shrink: 0;
border-right: 1px solid var(--border-subtle); border-right: 1px solid var(--c-border-subtle);
background: var(--bg-toolbar); background: var(--c-bg-raised);
overflow-y: auto; overflow-y: auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -135,7 +130,7 @@
font-size: 0.8rem; font-size: 0.8rem;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
color: var(--text-muted); color: var(--c-text-subtle);
} }
/* Tree node styles moved to FolderTreePanel.css - that's where the /* Tree node styles moved to FolderTreePanel.css - that's where the
@@ -156,8 +151,8 @@
align-items: center; align-items: center;
gap: 0.75rem; gap: 0.75rem;
padding: 0.55rem 1.25rem; padding: 0.55rem 1.25rem;
border-bottom: 1px solid var(--border-subtle); border-bottom: 1px solid var(--c-border-subtle);
background: var(--bg-background); background: var(--c-bg);
flex-shrink: 0; flex-shrink: 0;
flex-wrap: wrap; flex-wrap: wrap;
min-height: 3rem; min-height: 3rem;
@@ -165,7 +160,7 @@
.files-page-toolbar-info { .files-page-toolbar-info {
font-size: 0.85rem; font-size: 0.85rem;
color: var(--text-secondary); color: var(--c-text-muted);
font-weight: 500; font-weight: 500;
} }
@@ -178,7 +173,7 @@
} }
.files-page-toolbar-info span { .files-page-toolbar-info span {
color: var(--text-muted); color: var(--c-text-subtle);
} }
.files-page-toolbar-actions { .files-page-toolbar-actions {
@@ -226,7 +221,7 @@
.files-page-toolbar-divider { .files-page-toolbar-divider {
width: 1px; width: 1px;
height: 1.4rem; height: 1.4rem;
background: var(--border-subtle); background: var(--c-border-subtle);
margin: 0 0.15rem; margin: 0 0.15rem;
} }
@@ -264,7 +259,7 @@
padding: 1.25rem; padding: 1.25rem;
position: relative; position: relative;
scrollbar-width: thin; scrollbar-width: thin;
scrollbar-color: var(--border-subtle) transparent; scrollbar-color: var(--c-border-subtle) transparent;
} }
.files-page-content::-webkit-scrollbar { .files-page-content::-webkit-scrollbar {
@@ -273,14 +268,14 @@
} }
.files-page-content::-webkit-scrollbar-thumb { .files-page-content::-webkit-scrollbar-thumb {
background: var(--border-subtle); background: var(--c-border-subtle);
border-radius: 999px; border-radius: 999px;
border: 2px solid transparent; border: 2px solid transparent;
background-clip: content-box; background-clip: content-box;
} }
.files-page-content::-webkit-scrollbar-thumb:hover { .files-page-content::-webkit-scrollbar-thumb:hover {
background: var(--text-muted); background: var(--c-text-subtle);
background-clip: content-box; background-clip: content-box;
} }
@@ -288,7 +283,7 @@
.folder-tree-panel-inner, .folder-tree-panel-inner,
.files-page-details-body { .files-page-details-body {
scrollbar-width: thin; scrollbar-width: thin;
scrollbar-color: var(--border-subtle) transparent; scrollbar-color: var(--c-border-subtle) transparent;
} }
.files-page-tree-list::-webkit-scrollbar, .files-page-tree-list::-webkit-scrollbar,
@@ -300,7 +295,7 @@
.files-page-tree-list::-webkit-scrollbar-thumb, .files-page-tree-list::-webkit-scrollbar-thumb,
.folder-tree-panel-inner::-webkit-scrollbar-thumb, .folder-tree-panel-inner::-webkit-scrollbar-thumb,
.files-page-details-body::-webkit-scrollbar-thumb { .files-page-details-body::-webkit-scrollbar-thumb {
background: var(--border-subtle); background: var(--c-border-subtle);
border-radius: 999px; border-radius: 999px;
} }
@@ -313,10 +308,10 @@
.files-page-list { .files-page-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
border: 1px solid var(--border-subtle); border: 1px solid var(--c-border-subtle);
border-radius: 0.6rem; border-radius: 0.6rem;
overflow: hidden; overflow: hidden;
background: var(--bg-surface); background: var(--c-surface);
} }
.files-page-list-row { .files-page-list-row {
@@ -325,7 +320,7 @@
gap: 0.5rem; gap: 0.5rem;
align-items: center; align-items: center;
padding: 0.5rem 0.75rem; padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--border-subtle); border-bottom: 1px solid var(--c-border-subtle);
cursor: pointer; cursor: pointer;
font-size: 0.9rem; font-size: 0.9rem;
transition: background-color 0.12s ease; transition: background-color 0.12s ease;
@@ -336,8 +331,8 @@
} }
.files-page-list-row.is-header { .files-page-list-row.is-header {
background: var(--bg-toolbar); background: var(--c-bg-raised);
color: var(--text-muted); color: var(--c-text-subtle);
text-transform: uppercase; text-transform: uppercase;
font-size: 0.72rem; font-size: 0.72rem;
letter-spacing: 0.05em; letter-spacing: 0.05em;
@@ -356,33 +351,25 @@
} }
.files-page-list-row.is-header [data-sortable="true"]:hover { .files-page-list-row.is-header [data-sortable="true"]:hover {
background: var(--hover-bg); background: var(--c-hover);
color: var(--text-primary); color: var(--c-text);
} }
.files-page-list-row:not(.is-header):hover,
.files-page-list-row:not(.is-header):hover {
background: var(--hover-bg);
}
.files-page-list-row.is-selected { .files-page-list-row.is-selected {
background: var(--hover-bg); background: var(--c-hover);
} }
.files-page-list-row.is-drop-target { .files-page-list-row.is-drop-target {
background: color-mix( background: color-mix(in srgb, var(--c-primary) 12%, transparent);
in srgb, box-shadow: inset 0 0 0 1px var(--c-primary);
var(--accent-interactive, #6366f1) 12%,
transparent
);
box-shadow: inset 0 0 0 1px var(--accent-interactive, #6366f1);
} }
.files-page-card { .files-page-card {
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: var(--bg-surface); background: var(--c-surface);
border: 1px solid var(--border-subtle); border: 1px solid var(--c-border-subtle);
border-radius: 0.85rem; border-radius: 0.85rem;
overflow: hidden; overflow: hidden;
cursor: pointer; cursor: pointer;
@@ -397,8 +384,8 @@
transform: translateY(-2px); transform: translateY(-2px);
border-color: color-mix( border-color: color-mix(
in srgb, in srgb,
var(--accent-interactive, #6366f1) 35%, var(--c-primary) 35%,
var(--border-subtle) var(--c-border-subtle)
); );
box-shadow: box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 4px 6px -1px rgba(0, 0, 0, 0.08),
@@ -406,16 +393,15 @@
} }
.files-page-card:focus-visible { .files-page-card:focus-visible {
outline: 2px solid var(--accent-interactive, #6366f1); outline: 2px solid var(--c-primary);
outline-offset: 2px; outline-offset: 2px;
} }
.files-page-card.is-selected { .files-page-card.is-selected {
border-color: var(--accent-interactive, #6366f1); border-color: var(--c-primary);
box-shadow: box-shadow:
0 0 0 2px var(--accent-interactive, #6366f1), 0 0 0 2px var(--c-primary),
0 6px 18px -6px 0 6px 18px -6px color-mix(in srgb, var(--c-primary) 35%, transparent);
color-mix(in srgb, var(--accent-interactive, #6366f1) 35%, transparent);
} }
.files-page-card.is-folder { .files-page-card.is-folder {
@@ -426,8 +412,8 @@
aspect-ratio: 4 / 3; aspect-ratio: 4 / 3;
background: linear-gradient( background: linear-gradient(
180deg, 180deg,
color-mix(in srgb, var(--text-muted) 5%, var(--bg-surface)), color-mix(in srgb, var(--c-text-subtle) 5%, var(--c-surface)),
var(--bg-surface) var(--c-surface)
); );
display: flex; display: flex;
align-items: center; align-items: center;
@@ -452,7 +438,7 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 0.4rem; gap: 0.4rem;
color: var(--text-muted); color: var(--c-text-subtle);
font-size: 0.72rem; font-size: 0.72rem;
font-weight: 600; font-weight: 600;
letter-spacing: 0.04em; letter-spacing: 0.04em;
@@ -472,13 +458,13 @@
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
color: var(--text-primary); color: var(--c-text);
letter-spacing: -0.005em; letter-spacing: -0.005em;
} }
.files-page-card-meta { .files-page-card-meta {
font-size: 0.76rem; font-size: 0.76rem;
color: var(--text-muted); color: var(--c-text-subtle);
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.4rem; gap: 0.4rem;
@@ -488,7 +474,7 @@
the user can tell which folder each hit lives in without navigating. */ the user can tell which folder each hit lives in without navigating. */
.files-page-card-path { .files-page-card-path {
font-size: 0.72rem; font-size: 0.72rem;
color: var(--text-muted); color: var(--c-text-subtle);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -517,8 +503,8 @@
/* Style the Mantine checkbox so it reads as a soft pill rather than a /* Style the Mantine checkbox so it reads as a soft pill rather than a
bare form control. */ bare form control. */
.files-page-card-selector :where(.mantine-Checkbox-input) { .files-page-card-selector :where(.mantine-Checkbox-input) {
background: var(--bg-surface); background: var(--c-surface);
border-color: var(--border-subtle); border-color: var(--c-border-subtle);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
} }
@@ -536,26 +522,26 @@
Use stronger specificity + !important to win over Mantine's Use stronger specificity + !important to win over Mantine's
variant=filled inline styles. */ variant=filled inline styles. */
.files-page-card .files-page-card-actions button.mantine-ActionIcon-root { .files-page-card .files-page-card-actions button.mantine-ActionIcon-root {
background-color: var(--bg-raised, var(--bg-surface)) !important; background-color: var(--c-surface-raised, var(--c-surface)) !important;
color: var(--text-primary) !important; color: var(--c-text) !important;
border: 1px solid var(--border-default, var(--border-subtle)) !important; border: 1px solid var(--c-border, var(--c-border-subtle)) !important;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
backdrop-filter: blur(6px); backdrop-filter: blur(6px);
} }
.files-page-card .files-page-card-actions button.mantine-ActionIcon-root:hover { .files-page-card .files-page-card-actions button.mantine-ActionIcon-root:hover {
background-color: var(--hover-bg) !important; background-color: var(--c-hover) !important;
} }
/* Row-view kebab: same high-contrast treatment so it's readable /* Row-view kebab: same high-contrast treatment so it's readable
against selected (tinted) and in-workspace rows. */ against selected (tinted) and in-workspace rows. */
.files-page-list-row .mantine-ActionIcon-root[aria-label$="actions"] { .files-page-list-row .mantine-ActionIcon-root[aria-label$="actions"] {
color: var(--text-secondary); color: var(--c-text-muted);
} }
.files-page-list-row .mantine-ActionIcon-root[aria-label$="actions"]:hover { .files-page-list-row .mantine-ActionIcon-root[aria-label$="actions"]:hover {
background-color: var(--hover-bg) !important; background-color: var(--c-hover) !important;
color: var(--text-primary); color: var(--c-text);
} }
.files-page-card-origin { .files-page-card-origin {
@@ -578,8 +564,8 @@
gap: 0.35rem; gap: 0.35rem;
padding: 0.22rem 0.55rem; padding: 0.22rem 0.55rem;
border-radius: 999px; border-radius: 999px;
background: var(--mantine-color-teal-6, #10b981); background: var(--mantine-color-teal-6, var(--c-success));
color: #ffffff; color: var(--c-text-on-primary);
font-size: 0.68rem; font-size: 0.68rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.04em; letter-spacing: 0.04em;
@@ -594,7 +580,7 @@
width: 0.45rem; width: 0.45rem;
height: 0.45rem; height: 0.45rem;
border-radius: 50%; border-radius: 50%;
background: #ffffff; background: var(--c-text-on-primary);
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.35); box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.35);
animation: files-page-open-pulse 1.8s ease-in-out infinite; animation: files-page-open-pulse 1.8s ease-in-out infinite;
} }
@@ -614,8 +600,8 @@
.files-page-card.is-in-workspace { .files-page-card.is-in-workspace {
border-color: color-mix( border-color: color-mix(
in srgb, in srgb,
var(--mantine-color-teal-6, #10b981) 35%, var(--mantine-color-teal-6, var(--c-success)) 35%,
var(--border-subtle) var(--c-border-subtle)
); );
} }
@@ -627,7 +613,12 @@
pointer-events: none; pointer-events: none;
background: linear-gradient( background: linear-gradient(
180deg, 180deg,
color-mix(in srgb, var(--mantine-color-teal-6, #10b981) 6%, transparent) 0%, color-mix(
in srgb,
var(--mantine-color-teal-6, var(--c-success)) 6%,
transparent
)
0%,
transparent 40% transparent 40%
); );
z-index: 0; z-index: 0;
@@ -639,8 +630,8 @@
gap: 0.3rem; gap: 0.3rem;
padding: 0.12rem 0.5rem; padding: 0.12rem 0.5rem;
border-radius: 999px; border-radius: 999px;
background: var(--mantine-color-teal-6, #10b981); background: var(--mantine-color-teal-6, var(--c-success));
color: #ffffff; color: var(--c-text-on-primary);
font-size: 0.68rem; font-size: 0.68rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.04em; letter-spacing: 0.04em;
@@ -653,7 +644,7 @@
.files-page-list-row.is-in-workspace { .files-page-list-row.is-in-workspace {
background: color-mix( background: color-mix(
in srgb, in srgb,
var(--mantine-color-teal-6, #10b981) 4%, var(--mantine-color-teal-6, var(--c-success)) 4%,
transparent transparent
); );
} }
@@ -685,13 +676,9 @@
} }
.files-page-card.is-drop-target { .files-page-card.is-drop-target {
background: color-mix( background: color-mix(in srgb, var(--c-primary) 10%, var(--c-surface));
in srgb, box-shadow: 0 0 0 2px var(--c-primary);
var(--accent-interactive, #6366f1) 10%, border-color: var(--c-primary);
var(--bg-surface)
);
box-shadow: 0 0 0 2px var(--accent-interactive, #6366f1);
border-color: var(--accent-interactive, #6366f1);
} }
@keyframes files-page-skeleton-pulse { @keyframes files-page-skeleton-pulse {
@@ -707,9 +694,9 @@
display: block; display: block;
background: linear-gradient( background: linear-gradient(
90deg, 90deg,
color-mix(in srgb, var(--text-muted) 12%, transparent) 25%, color-mix(in srgb, var(--c-text-subtle) 12%, transparent) 25%,
color-mix(in srgb, var(--text-muted) 22%, transparent) 50%, color-mix(in srgb, var(--c-text-subtle) 22%, transparent) 50%,
color-mix(in srgb, var(--text-muted) 12%, transparent) 75% color-mix(in srgb, var(--c-text-subtle) 12%, transparent) 75%
); );
background-size: 200% 100%; background-size: 200% 100%;
animation: files-page-skeleton-pulse 1.4s ease-in-out infinite; animation: files-page-skeleton-pulse 1.4s ease-in-out infinite;
@@ -718,14 +705,14 @@
.files-page-skeleton-card { .files-page-skeleton-card {
pointer-events: none; pointer-events: none;
border-color: var(--border-subtle); border-color: var(--c-border-subtle);
box-shadow: none; box-shadow: none;
} }
.files-page-skeleton-card:hover { .files-page-skeleton-card:hover {
transform: none; transform: none;
box-shadow: none; box-shadow: none;
border-color: var(--border-subtle); border-color: var(--c-border-subtle);
} }
.files-page-skeleton-row { .files-page-skeleton-row {
@@ -743,7 +730,7 @@
justify-content: center; justify-content: center;
height: 100%; height: 100%;
gap: 0.75rem; gap: 0.75rem;
color: var(--text-muted); color: var(--c-text-subtle);
padding: 4rem 1.5rem; padding: 4rem 1.5rem;
text-align: center; text-align: center;
} }
@@ -755,25 +742,21 @@
width: 5rem; width: 5rem;
height: 5rem; height: 5rem;
border-radius: 50%; border-radius: 50%;
background: color-mix( background: color-mix(in srgb, var(--c-primary) 12%, transparent);
in srgb, color: var(--c-primary);
var(--accent-interactive, #6366f1) 12%,
transparent
);
color: var(--accent-interactive, #6366f1);
margin-bottom: 0.25rem; margin-bottom: 0.25rem;
} }
.files-page-empty-title { .files-page-empty-title {
font-size: 1.15rem; font-size: 1.15rem;
color: var(--text-primary); color: var(--c-text);
font-weight: 600; font-weight: 600;
letter-spacing: -0.01em; letter-spacing: -0.01em;
} }
.files-page-empty-hint { .files-page-empty-hint {
font-size: 0.9rem; font-size: 0.9rem;
color: var(--text-muted); color: var(--c-text-subtle);
max-width: 30rem; max-width: 30rem;
line-height: 1.5; line-height: 1.5;
} }
@@ -797,8 +780,8 @@
.files-page-details { .files-page-details {
width: 22rem; width: 22rem;
flex-shrink: 0; flex-shrink: 0;
border-left: 1px solid var(--border-subtle); border-left: 1px solid var(--c-border-subtle);
background: var(--bg-toolbar); background: var(--c-bg-raised);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
@@ -817,7 +800,7 @@
font-size: 0.78rem; font-size: 0.78rem;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em; letter-spacing: 0.06em;
color: var(--text-muted); color: var(--c-text-subtle);
} }
.files-page-details-header strong { .files-page-details-header strong {
@@ -846,8 +829,8 @@
flex-direction: column; flex-direction: column;
gap: 0.4rem; gap: 0.4rem;
padding: 0.6rem 1.1rem; padding: 0.6rem 1.1rem;
border-top: 1px solid var(--border-subtle); border-top: 1px solid var(--c-border-subtle);
background: var(--bg-toolbar); background: var(--c-bg-raised);
} }
/* Collapsible "File info" header (size/type/dates). */ /* Collapsible "File info" header (size/type/dates). */
@@ -857,11 +840,11 @@
justify-content: space-between; justify-content: space-between;
width: 100%; width: 100%;
padding: 0.4rem 0.6rem; padding: 0.4rem 0.6rem;
background: var(--bg-surface); background: var(--c-surface);
border: 1px solid var(--border-subtle); border: 1px solid var(--c-border-subtle);
border-radius: 0.5rem; border-radius: 0.5rem;
cursor: pointer; cursor: pointer;
color: var(--text-secondary, var(--text-primary)); color: var(--c-text-muted, var(--c-text));
font-size: 0.78rem; font-size: 0.78rem;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
@@ -878,8 +861,8 @@
/* Compact fixed height (was a tall 4:3 box that dominated the panel and /* Compact fixed height (was a tall 4:3 box that dominated the panel and
pushed the action buttons off the bottom). */ pushed the action buttons off the bottom). */
height: 6.5rem; height: 6.5rem;
background: var(--bg-surface); background: var(--c-surface);
border: 1px solid var(--border-subtle); border: 1px solid var(--c-border-subtle);
border-radius: 0.6rem; border-radius: 0.6rem;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -911,8 +894,8 @@
gap: 0.55rem; gap: 0.55rem;
font-size: 0.85rem; font-size: 0.85rem;
padding: 0.65rem 0.75rem; padding: 0.65rem 0.75rem;
background: var(--bg-surface); background: var(--c-surface);
border: 1px solid var(--border-subtle); border: 1px solid var(--c-border-subtle);
border-radius: 0.5rem; border-radius: 0.5rem;
} }
@@ -923,12 +906,12 @@
} }
.files-page-details-field-label { .files-page-details-field-label {
color: var(--text-muted); color: var(--c-text-subtle);
font-size: 0.78rem; font-size: 0.78rem;
} }
.files-page-details-field-value { .files-page-details-field-value {
color: var(--text-primary); color: var(--c-text);
text-align: right; text-align: right;
word-break: break-word; word-break: break-word;
font-weight: 500; font-weight: 500;
@@ -939,8 +922,8 @@
flex-direction: column; flex-direction: column;
gap: 0.3rem; gap: 0.3rem;
padding: 0.5rem 0.6rem; padding: 0.5rem 0.6rem;
background: var(--bg-surface); background: var(--c-surface);
border: 1px solid var(--border-subtle); border: 1px solid var(--c-border-subtle);
border-radius: 0.5rem; border-radius: 0.5rem;
} }
@@ -948,7 +931,7 @@
font-size: 0.72rem; font-size: 0.72rem;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
color: var(--text-muted); color: var(--c-text-subtle);
} }
/* Filename chip next to the title - "PDF", "DOCX", etc. /* Filename chip next to the title - "PDF", "DOCX", etc.
@@ -959,9 +942,9 @@
align-items: center; align-items: center;
padding: 0.12rem 0.5rem; padding: 0.12rem 0.5rem;
border-radius: 0.4rem; border-radius: 0.4rem;
background: var(--bg-surface); background: var(--c-surface);
border: 1px solid var(--border-subtle); border: 1px solid var(--c-border-subtle);
color: var(--text-secondary, var(--text-primary)); color: var(--c-text-muted, var(--c-text));
font-size: 0.65rem; font-size: 0.65rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.05em; letter-spacing: 0.05em;
@@ -980,8 +963,8 @@
flex-direction: column; flex-direction: column;
gap: 0.4rem; gap: 0.4rem;
padding: 0.55rem 0.7rem 0.7rem; padding: 0.55rem 0.7rem 0.7rem;
background: var(--bg-surface); background: var(--c-surface);
border: 1px solid var(--border-subtle); border: 1px solid var(--c-border-subtle);
border-radius: 0.5rem; border-radius: 0.5rem;
} }
.files-page-details-version-timeline-label { .files-page-details-version-timeline-label {
@@ -991,12 +974,12 @@
font-size: 0.72rem; font-size: 0.72rem;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
color: var(--text-muted); color: var(--c-text-subtle);
} }
.files-page-details-version-timeline-count { .files-page-details-version-timeline-count {
margin-left: auto; margin-left: auto;
font-weight: 600; font-weight: 600;
color: var(--text-secondary, var(--text-muted)); color: var(--c-text-muted, var(--c-text-subtle));
text-transform: none; text-transform: none;
letter-spacing: 0; letter-spacing: 0;
} }
@@ -1026,27 +1009,26 @@
width: 0.55rem; width: 0.55rem;
height: 0.55rem; height: 0.55rem;
border-radius: 50%; border-radius: 50%;
background: var(--bg-toolbar); background: var(--c-bg-raised);
border: 2px solid var(--border-strong, var(--border-subtle)); border: 2px solid var(--c-border-strong, var(--c-border-subtle));
z-index: 1; z-index: 1;
flex-shrink: 0; flex-shrink: 0;
} }
.files-page-details-version-timeline-rail-dot.is-active { .files-page-details-version-timeline-rail-dot.is-active {
background: var(--accent-interactive, #6366f1); background: var(--c-primary);
border-color: var(--accent-interactive, #6366f1); border-color: var(--c-primary);
box-shadow: 0 0 0 3px box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-primary) 25%, transparent);
color-mix(in srgb, var(--accent-interactive, #6366f1) 25%, transparent);
} }
.files-page-details-version-timeline-rail-dot.is-ellipsis { .files-page-details-version-timeline-rail-dot.is-ellipsis {
width: 0.35rem; width: 0.35rem;
height: 0.35rem; height: 0.35rem;
background: var(--text-muted); background: var(--c-text-subtle);
border-color: transparent; border-color: transparent;
} }
.files-page-details-version-timeline-rail-line { .files-page-details-version-timeline-rail-line {
width: 2px; width: 2px;
flex: 1; flex: 1;
background: var(--border-subtle); background: var(--c-border-subtle);
min-height: 0.6rem; min-height: 0.6rem;
margin-top: 2px; margin-top: 2px;
} }
@@ -1062,11 +1044,7 @@
} }
.files-page-details-version-timeline-row.is-active .files-page-details-version-timeline-row.is-active
.files-page-details-version-timeline-body { .files-page-details-version-timeline-body {
background: color-mix( background: color-mix(in srgb, var(--c-primary) 10%, transparent);
in srgb,
var(--accent-interactive, #6366f1) 10%,
transparent
);
} }
.files-page-details-version-timeline-summary { .files-page-details-version-timeline-summary {
appearance: none; appearance: none;
@@ -1084,11 +1062,11 @@
} }
.files-page-details-version-timeline-summary:hover .files-page-details-version-timeline-summary:hover
.files-page-details-version-timeline-chevron { .files-page-details-version-timeline-chevron {
color: var(--text-primary); color: var(--c-text);
} }
.files-page-details-version-timeline-delta { .files-page-details-version-timeline-delta {
font-size: 0.82rem; font-size: 0.82rem;
color: var(--text-primary); color: var(--c-text);
font-weight: 500; font-weight: 500;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
@@ -1099,30 +1077,30 @@
} }
.files-page-details-version-timeline-delta.is-origin { .files-page-details-version-timeline-delta.is-origin {
font-weight: 400; font-weight: 400;
color: var(--text-muted); color: var(--c-text-subtle);
font-style: italic; font-style: italic;
} }
.files-page-details-version-timeline-delta-plus { .files-page-details-version-timeline-delta-plus {
color: var(--accent-interactive, #6366f1); color: var(--c-primary);
font-weight: 700; font-weight: 700;
} }
.files-page-details-version-timeline-spacer { .files-page-details-version-timeline-spacer {
flex: 1; flex: 1;
} }
.files-page-details-version-timeline-chevron { .files-page-details-version-timeline-chevron {
color: var(--text-muted); color: var(--c-text-subtle);
transition: transform 0.15s ease; transition: transform 0.15s ease;
} }
.files-page-details-version-timeline-chevron.is-expanded { .files-page-details-version-timeline-chevron.is-expanded {
transform: rotate(180deg); transform: rotate(180deg);
color: var(--text-primary); color: var(--c-text);
} }
.files-page-details-version-timeline-meta-line { .files-page-details-version-timeline-meta-line {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.35rem; gap: 0.35rem;
font-size: 0.7rem; font-size: 0.7rem;
color: var(--text-muted); color: var(--c-text-subtle);
} }
.files-page-details-version-timeline-expanded { .files-page-details-version-timeline-expanded {
display: flex; display: flex;
@@ -1130,7 +1108,7 @@
gap: 0.4rem; gap: 0.4rem;
margin-top: 0.45rem; margin-top: 0.45rem;
padding-top: 0.5rem; padding-top: 0.5rem;
border-top: 1px dashed var(--border-subtle); border-top: 1px dashed var(--c-border-subtle);
} }
.files-page-details-version-timeline-toolchain { .files-page-details-version-timeline-toolchain {
display: flex; display: flex;
@@ -1139,7 +1117,7 @@
} }
.files-page-details-version-timeline-toolchain-label { .files-page-details-version-timeline-toolchain-label {
font-size: 0.65rem; font-size: 0.65rem;
color: var(--text-muted); color: var(--c-text-subtle);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
} }
@@ -1147,12 +1125,12 @@
.files-page-details-version-timeline-collapse-btn { .files-page-details-version-timeline-collapse-btn {
appearance: none; appearance: none;
background: none; background: none;
border: 1px dashed var(--border-subtle); border: 1px dashed var(--c-border-subtle);
border-radius: 0.3rem; border-radius: 0.3rem;
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;
margin: 0.1rem 0; margin: 0.1rem 0;
font-size: 0.72rem; font-size: 0.72rem;
color: var(--text-muted); color: var(--c-text-subtle);
cursor: pointer; cursor: pointer;
text-align: left; text-align: left;
transition: transition:
@@ -1161,8 +1139,8 @@
} }
.files-page-details-version-timeline-ellipsis-btn:hover, .files-page-details-version-timeline-ellipsis-btn:hover,
.files-page-details-version-timeline-collapse-btn:hover { .files-page-details-version-timeline-collapse-btn:hover {
color: var(--text-primary); color: var(--c-text);
border-color: var(--border-strong, var(--text-muted)); border-color: var(--c-border-strong, var(--c-text-subtle));
} }
.files-page-details-version-timeline-collapse-btn { .files-page-details-version-timeline-collapse-btn {
align-self: flex-start; align-self: flex-start;
@@ -1172,12 +1150,8 @@
.files-page-drop-overlay { .files-page-drop-overlay {
position: absolute; position: absolute;
inset: 1rem; inset: 1rem;
background: color-mix( background: color-mix(in srgb, var(--c-primary) 14%, var(--c-bg));
in srgb, border: 2px dashed var(--c-primary);
var(--accent-interactive, #6366f1) 14%,
var(--bg-background)
);
border: 2px dashed var(--accent-interactive, #6366f1);
border-radius: 1rem; border-radius: 1rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -1185,7 +1159,7 @@
justify-content: center; justify-content: center;
gap: 1rem; gap: 1rem;
pointer-events: none; pointer-events: none;
color: var(--accent-interactive, #6366f1); color: var(--c-primary);
font-weight: 600; font-weight: 600;
font-size: 1.1rem; font-size: 1.1rem;
z-index: 10; z-index: 10;
@@ -1200,40 +1174,28 @@
width: 4.5rem; width: 4.5rem;
height: 4.5rem; height: 4.5rem;
border-radius: 50%; border-radius: 50%;
background: color-mix( background: color-mix(in srgb, var(--c-primary) 30%, transparent);
in srgb,
var(--accent-interactive, #6366f1) 30%,
transparent
);
} }
.files-page-drop-overlay-icon svg { .files-page-drop-overlay-icon svg {
font-size: 2.5rem !important; font-size: 2.5rem !important;
color: var(--bg-background); color: var(--c-bg);
} }
.files-page-drop-overlay-sub { .files-page-drop-overlay-sub {
font-size: 0.85rem; font-size: 0.85rem;
font-weight: 500; font-weight: 500;
color: color-mix( color: color-mix(in srgb, var(--c-primary) 80%, var(--c-text-muted));
in srgb,
var(--accent-interactive, #6366f1) 80%,
var(--text-secondary)
);
} }
@keyframes files-page-drop-overlay-pulse { @keyframes files-page-drop-overlay-pulse {
0%, 0%,
100% { 100% {
border-color: var(--accent-interactive, #6366f1); border-color: var(--c-primary);
transform: scale(1); transform: scale(1);
} }
50% { 50% {
border-color: color-mix( border-color: color-mix(in srgb, var(--c-primary) 60%, transparent);
in srgb,
var(--accent-interactive, #6366f1) 60%,
transparent
);
transform: scale(1.005); transform: scale(1.005);
} }
} }
@@ -70,7 +70,7 @@ export function FolderAppearancePicker({
borderRadius: "50%", borderRadius: "50%",
border: border:
folder.color === c folder.color === c
? "2px solid var(--text-primary)" ? "2px solid var(--c-text)"
: "2px solid transparent", : "2px solid transparent",
background: c, background: c,
cursor: disabled ? "not-allowed" : "pointer", cursor: disabled ? "not-allowed" : "pointer",
@@ -123,7 +123,7 @@ function Section({
fontSize: "0.7rem", fontSize: "0.7rem",
textTransform: "uppercase", textTransform: "uppercase",
letterSpacing: "0.05em", letterSpacing: "0.05em",
color: "var(--text-muted)", color: "var(--c-text-subtle)",
fontWeight: 600, fontWeight: 600,
}} }}
> >
@@ -163,13 +163,13 @@ function IconButton({
justifyContent: "center", justifyContent: "center",
fontSize: "1.1rem", fontSize: "1.1rem",
borderRadius: "0.4rem", borderRadius: "0.4rem",
background: selected ? "var(--hover-bg)" : "transparent", background: selected ? "var(--c-hover)" : "transparent",
border: selected border: selected
? "1px solid var(--accent-interactive, #6366f1)" ? "1px solid var(--c-primary)"
: "1px solid transparent", : "1px solid transparent",
cursor: disabled ? "not-allowed" : "pointer", cursor: disabled ? "not-allowed" : "pointer",
padding: 0, padding: 0,
color: "var(--text-primary)", color: "var(--c-text)",
}} }}
> >
{icon.glyph || "-"} {icon.glyph || "-"}
@@ -30,7 +30,7 @@ export function FolderThumbnail({
size = "thumb", size = "thumb",
iconGlyph, iconGlyph,
}: FolderThumbnailProps) { }: FolderThumbnailProps) {
const accent = color ?? "var(--accent-interactive, #6366f1)"; const accent = color ?? "var(--c-primary, #6366f1)";
const px = SIZE_PX[size]; const px = SIZE_PX[size];
const showBadge = size === "thumb" && (fileCount ?? 0) > 0; const showBadge = size === "thumb" && (fileCount ?? 0) > 0;
// Per-instance unique ids - `${color}` previously embedded `#` and CSS // Per-instance unique ids - `${color}` previously embedded `#` and CSS
@@ -149,7 +149,7 @@ export function FolderThumbnail({
minWidth: "1.4rem", minWidth: "1.4rem",
height: "1.4rem", height: "1.4rem",
borderRadius: "999px", borderRadius: "999px",
background: "var(--bg-surface, #fff)", background: "var(--c-surface, #fff)",
border: `1px solid ${accent}`, border: `1px solid ${accent}`,
color: accent, color: accent,
fontSize: "0.7rem", fontSize: "0.7rem",
@@ -15,8 +15,8 @@
.folder-tree-panel { .folder-tree-panel {
width: 0; width: 0;
flex-shrink: 0; flex-shrink: 0;
background: var(--bg-toolbar); background: var(--c-bg-raised);
border-right: 0 solid var(--border-subtle); border-right: 0 solid var(--c-border-subtle);
overflow: hidden; overflow: hidden;
height: 100%; height: 100%;
pointer-events: none; pointer-events: none;
@@ -65,11 +65,7 @@
.folder-tree-panel-resizer:hover, .folder-tree-panel-resizer:hover,
.folder-tree-panel-resizer:focus-visible { .folder-tree-panel-resizer:focus-visible {
background: color-mix( background: color-mix(in srgb, var(--c-primary) 35%, transparent);
in srgb,
var(--accent-interactive, #6366f1) 35%,
transparent
);
outline: none; outline: none;
} }
@@ -87,7 +83,7 @@
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
letter-spacing: 0.02em; letter-spacing: 0.02em;
color: var(--text-muted); color: var(--c-text-subtle);
text-transform: uppercase; text-transform: uppercase;
} }
@@ -112,7 +108,7 @@
margin: 0 8px; margin: 0 8px;
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
color: var(--text-secondary); color: var(--c-text-muted);
font-size: 14px; font-size: 14px;
position: relative; position: relative;
transition: background-color 0.15s ease; transition: background-color 0.15s ease;
@@ -120,23 +116,19 @@
} }
.files-page-tree-node:hover { .files-page-tree-node:hover {
background: var(--hover-bg); background: var(--c-hover);
} }
.files-page-tree-node.is-active { .files-page-tree-node.is-active {
background: var(--hover-bg); background: var(--c-hover);
color: var(--text-primary); color: var(--c-text);
font-weight: 500; font-weight: 500;
} }
.files-page-tree-node.is-drop-target { .files-page-tree-node.is-drop-target {
background: color-mix( background: color-mix(in srgb, var(--c-primary) 12%, transparent);
in srgb, box-shadow: inset 0 0 0 1px var(--c-primary);
var(--accent-interactive, #6366f1) 12%, color: var(--c-text);
transparent
);
box-shadow: inset 0 0 0 1px var(--accent-interactive, #6366f1);
color: var(--text-primary);
} }
.files-page-tree-toggle { .files-page-tree-toggle {
@@ -145,7 +137,7 @@
justify-content: center; justify-content: center;
width: 16px; width: 16px;
height: 16px; height: 16px;
color: var(--text-muted); color: var(--c-text-subtle);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -165,7 +157,7 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-shrink: 0; flex-shrink: 0;
color: var(--text-muted); color: var(--c-text-subtle);
margin-left: 8px; margin-left: 8px;
font-size: 18px; font-size: 18px;
} }
@@ -183,7 +175,7 @@
} }
.files-page-tree-count { .files-page-tree-count {
color: var(--text-muted); color: var(--c-text-subtle);
font-size: 12px; font-size: 12px;
flex-shrink: 0; flex-shrink: 0;
margin-left: 8px; margin-left: 8px;
@@ -127,7 +127,7 @@ export function MoveToFolderDialog({
</Text> </Text>
<div <div
style={{ style={{
border: "1px solid var(--border-subtle)", border: "1px solid var(--c-border-subtle)",
borderRadius: "0.5rem", borderRadius: "0.5rem",
maxHeight: "20rem", maxHeight: "20rem",
overflowY: "auto", overflowY: "auto",
@@ -343,8 +343,8 @@ function FolderPick({
opacity: disabled ? 0.45 : 1, opacity: disabled ? 0.45 : 1,
gap: "0.5rem", gap: "0.5rem",
padding: `0.4rem 0.75rem 0.4rem ${0.75 + depth * 0.85}rem`, padding: `0.4rem 0.75rem 0.4rem ${0.75 + depth * 0.85}rem`,
background: isActive ? "var(--hover-bg)" : "transparent", background: isActive ? "var(--c-hover)" : "transparent",
borderBottom: "1px solid var(--border-subtle)", borderBottom: "1px solid var(--c-border-subtle)",
boxSizing: "border-box", boxSizing: "border-box",
fontWeight: isActive ? 600 : 400, fontWeight: isActive ? 600 : 400,
}} }}
@@ -218,7 +218,7 @@ export default function Workbench() {
<Box <Box
className="flex-1 h-full min-w-0 relative flex flex-col" className="flex-1 h-full min-w-0 relative flex flex-col"
data-tour="workbench" data-tour="workbench"
style={{ backgroundColor: "var(--bg-background)", minWidth: 0 }} style={{ backgroundColor: "var(--c-bg)", minWidth: 0 }}
> >
{/* Workbench Bar - animates in/out based on file presence */} {/* Workbench Bar - animates in/out based on file presence */}
{currentView !== "myFiles" && {currentView !== "myFiles" &&
@@ -22,7 +22,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
box-shadow: 0 16px 32px rgba(15, 23, 42, 0.18); box-shadow: 0 16px 32px rgba(0, 0, 0, 0.18);
animation: heroLogoScale 0.25s ease forwards; animation: heroLogoScale 0.25s ease forwards;
} }
@@ -49,10 +49,10 @@
.securityCard { .securityCard {
width: 100%; width: 100%;
max-width: 480px; max-width: 480px;
background: var(--bg-surface, #ffffff); background: var(--c-surface);
border-radius: 16px; border-radius: 16px;
padding: 20px; padding: 20px;
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.12); box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16px; gap: 16px;
@@ -65,7 +65,7 @@
font-weight: 500; font-weight: 500;
font-size: 15px; font-size: 15px;
line-height: 1.5; line-height: 1.5;
color: var(--onboarding-body, #1f2937); color: var(--c-text-muted);
} }
.mfaSlideContent { .mfaSlideContent {
@@ -77,10 +77,10 @@
.mfaCard { .mfaCard {
width: 100%; width: 100%;
max-width: 560px; max-width: 560px;
background: var(--bg-surface, #ffffff); background: var(--c-surface);
border-radius: 16px; border-radius: 16px;
padding: 20px; padding: 20px;
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.12); box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
} }
.mfaSetupGrid { .mfaSetupGrid {
@@ -94,7 +94,7 @@
padding: 12px; padding: 12px;
background: #ffffff; background: #ffffff;
border-radius: 12px; border-radius: 12px;
box-shadow: 0 8px 16px rgba(15, 23, 42, 0.12); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.12);
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
@@ -102,7 +102,7 @@
.mfaSteps { .mfaSteps {
margin: 0; margin: 0;
padding-left: 18px; padding-left: 18px;
color: var(--onboarding-body, #1f2937); color: var(--c-text-muted);
font-size: 14px; font-size: 14px;
line-height: 1.5; line-height: 1.5;
} }
@@ -149,11 +149,7 @@
padding: 4px; padding: 4px;
outline: none; outline: none;
} }
.iconButton:focus,
.iconButton:focus {
outline: none;
}
.iconButton:focus-visible { .iconButton:focus-visible {
outline: none; outline: none;
} }
@@ -194,14 +190,7 @@
text-align: center; text-align: center;
animation: heroLogoEnter 0.25s ease forwards; animation: heroLogoEnter 0.25s ease forwards;
} }
.title,
.title {
text-align: center;
opacity: 0;
transform: translateX(24px);
animation: bodySlideIn 0.25s ease forwards;
}
.bodyCopy { .bodyCopy {
text-align: center; text-align: center;
opacity: 0; opacity: 0;
@@ -273,13 +262,13 @@
opacity: 1; opacity: 1;
border: 1px solid rgba(255, 255, 255, 0.9); border: 1px solid rgba(255, 255, 255, 0.9);
background: rgba(255, 255, 255, 0.9); background: rgba(255, 255, 255, 0.9);
color: #1f2933; color: var(--c-text);
box-shadow: 0 0 8px rgba(255, 255, 255, 0.7); box-shadow: 0 0 8px rgba(255, 255, 255, 0.7);
} }
/* Modal content styles */ /* Modal content styles */
.modalContent { .modalContent {
background: var(--bg-surface); background: var(--c-surface);
position: relative; position: relative;
} }
@@ -299,7 +288,7 @@
sans-serif; sans-serif;
font-weight: 600; font-weight: 600;
font-size: 22px; font-size: 22px;
color: var(--onboarding-title); color: var(--c-text);
} }
/* Body text styles */ /* Body text styles */
@@ -313,7 +302,7 @@
Arial, Arial,
sans-serif; sans-serif;
font-size: 16px; font-size: 16px;
color: var(--onboarding-body); color: var(--c-text-muted);
line-height: 1.5; line-height: 1.5;
} }
@@ -335,8 +324,8 @@
} }
.v2Badge { .v2Badge {
background: #dbefff; background: var(--c-primary-tint);
color: #2a4bff; color: var(--c-accent-fg);
padding: 3px 9px; padding: 3px 9px;
border-radius: 6px; border-radius: 6px;
font-size: 12px; font-size: 12px;
@@ -345,7 +334,7 @@
/* Icon styles */ /* Icon styles */
.heroIcon { .heroIcon {
color: var(--onboarding-title, #0f172a); color: var(--c-text);
} }
/* ===================================================================== */ /* ===================================================================== */
@@ -353,7 +342,7 @@
/* ===================================================================== */ /* ===================================================================== */
.card { .card {
background: var(--bg-surface); background: var(--c-surface);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
@@ -383,7 +372,7 @@
font-size: 17px; font-size: 17px;
font-weight: 700; font-weight: 700;
letter-spacing: -0.01em; letter-spacing: -0.01em;
color: var(--onboarding-title, #0f172a); color: var(--c-text);
} }
.headerRight { .headerRight {
@@ -395,8 +384,8 @@
.stepPill { .stepPill {
font-size: 12px; font-size: 12px;
font-weight: 600; font-weight: 600;
color: var(--onboarding-body, #64748b); color: var(--c-text-muted);
background: var(--bg-muted, #f1f5f9); background: var(--c-surface-sunken);
padding: 5px 11px; padding: 5px 11px;
border-radius: 9999px; border-radius: 9999px;
white-space: nowrap; white-space: nowrap;
@@ -413,17 +402,17 @@
flex: 1; flex: 1;
height: 5px; height: 5px;
border-radius: 9999px; border-radius: 9999px;
background: var(--onboarding-step-inactive, #e2e8f0); background: var(--onboarding-step-inactive, var(--c-border));
transition: background 0.2s ease; transition: background 0.2s ease;
} }
.progressSegDone { .progressSegDone {
background: var(--color-blue, #3b82f6); background: var(--c-primary);
} }
.divider { .divider {
height: 1px; height: 1px;
background: var(--border-subtle, rgba(15, 23, 42, 0.08)); background: var(--c-border-subtle);
} }
/* ---- content ---- */ /* ---- content ---- */
@@ -445,7 +434,7 @@
min-height: 128px; min-height: 128px;
border-radius: 14px; border-radius: 14px;
overflow: hidden; overflow: hidden;
background: linear-gradient(155deg, #eef1fb 0%, #f6f4fc 55%, #fbf4f7 100%); background: var(--c-onboarding-hero);
} }
.heroArt { .heroArt {
@@ -459,18 +448,18 @@
height: 62px; height: 62px;
border-radius: 15px; border-radius: 15px;
object-fit: contain; object-fit: contain;
filter: drop-shadow(0 10px 20px rgba(15, 23, 42, 0.16)); filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.16));
} }
.heroTile { .heroTile {
width: 62px; width: 62px;
height: 62px; height: 62px;
border-radius: 15px; border-radius: 15px;
background: #ffffff; background: var(--c-onboarding-hero-tile);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
box-shadow: 0 10px 22px rgba(15, 23, 42, 0.14); box-shadow: 0 10px 22px rgba(0, 0, 0, 0.14);
} }
/* ---- title + body (left-aligned, clean) ---- */ /* ---- title + body (left-aligned, clean) ---- */
@@ -479,14 +468,14 @@
font-weight: 600; font-weight: 600;
letter-spacing: -0.01em; letter-spacing: -0.01em;
line-height: 1.3; line-height: 1.3;
color: var(--onboarding-title, #0f172a); color: var(--c-text);
text-align: left; text-align: left;
} }
.bodyNew { .bodyNew {
font-size: 14px; font-size: 14px;
line-height: 1.5; line-height: 1.5;
color: var(--onboarding-body, #475569); color: var(--c-text-muted);
text-align: left; text-align: left;
} }
@@ -513,16 +502,9 @@
gap: 12px; gap: 12px;
} }
/* ---- dark theme surface tuning ---- */ /* ---- dark theme surface tuning ----
:global([data-mantine-color-scheme="dark"]) .heroPanel { Hero panel + tile colours flip via the themed --c-onboarding-hero* tokens;
background: linear-gradient(155deg, #1a2236 0%, #171e30 55%, #201a28 100%); only the tile's heavier dark shadow needs a per-scheme override. */
}
:global([data-mantine-color-scheme="dark"]) .heroTile { :global([data-mantine-color-scheme="dark"]) .heroTile {
background: #0f1626;
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.4); box-shadow: 0 12px 28px rgba(0, 0, 0, 0.4);
} }
:global([data-mantine-color-scheme="dark"]) .divider {
background: rgba(255, 255, 255, 0.08);
}
@@ -116,7 +116,7 @@ export default function OnboardingSlideShell({
content: { content: {
overflow: "hidden", overflow: "hidden",
border: "none", border: "none",
background: "var(--bg-surface)", background: "var(--c-surface)",
maxHeight: "90vh", maxHeight: "90vh",
}, },
}} }}
@@ -193,7 +193,7 @@ export default function OnboardingSlideShell({
<div key={`body-${slideKey}`} className={styles.bodyNew}> <div key={`body-${slideKey}`} className={styles.bodyNew}>
{body} {body}
<style>{`.${styles.bodyNew} strong{color: var(--onboarding-title); font-weight: 600;}`}</style> <style>{`.${styles.bodyNew} strong{color: var(--c-text); font-weight: 600;}`}</style>
</div> </div>
<div className={styles.footer}> <div className={styles.footer}>
@@ -13,7 +13,7 @@
box-shadow: box-shadow:
0 0 0 2px var(--mantine-primary-color-filled), 0 0 0 2px var(--mantine-primary-color-filled),
0 0 15px var(--mantine-primary-color-filled), 0 0 15px var(--mantine-primary-color-filled),
inset 0 0 15px rgba(59, 130, 246, 0.1); inset 0 0 15px color-mix(in srgb, var(--c-primary) 10%, transparent);
border-radius: 8px; border-radius: 8px;
} }
@@ -23,13 +23,13 @@
box-shadow: box-shadow:
0 0 0 3px var(--mantine-primary-color-filled), 0 0 0 3px var(--mantine-primary-color-filled),
0 0 20px var(--mantine-primary-color-filled), 0 0 20px var(--mantine-primary-color-filled),
inset 0 0 20px rgba(59, 130, 246, 0.1); inset 0 0 20px color-mix(in srgb, var(--c-primary) 10%, transparent);
} }
50% { 50% {
box-shadow: box-shadow:
0 0 0 3px var(--mantine-primary-color-filled), 0 0 0 3px var(--mantine-primary-color-filled),
0 0 30px var(--mantine-primary-color-filled), 0 0 30px var(--mantine-primary-color-filled),
inset 0 0 30px rgba(59, 130, 246, 0.2); inset 0 0 30px color-mix(in srgb, var(--c-primary) 20%, transparent);
} }
} }
@@ -40,7 +40,7 @@
position: absolute; position: absolute;
border-radius: 50%; border-radius: 50%;
pointer-events: none; pointer-events: none;
box-shadow: 0 18px 36px rgba(15, 23, 42, 0.12); box-shadow: 0 18px 36px rgba(0, 0, 0, 0.12);
animation-name: circleSway; animation-name: circleSway;
animation-timing-function: ease-in-out; animation-timing-function: ease-in-out;
animation-iteration-count: infinite; animation-iteration-count: infinite;
@@ -129,9 +129,9 @@ export const DesktopInstallTitle: React.FC<DesktopInstallTitleProps> = ({
leftSection={iconKey ? <OsIcon os={iconKey} /> : undefined} leftSection={iconKey ? <OsIcon os={iconKey} /> : undefined}
style={{ style={{
backgroundColor: isSelected backgroundColor: isSelected
? "var(--bg-muted, #f1f5f9)" ? "var(--c-surface-sunken, #f1f5f9)"
: "transparent", : "transparent",
color: "var(--onboarding-title, #0f172a)", color: "var(--c-text, #0f172a)",
fontWeight: isSelected ? 600 : 500, fontWeight: isSelected ? 600 : 500,
}} }}
> >
@@ -125,7 +125,7 @@ function FirstLoginForm({
icon="info-rounded" icon="info-rounded"
width={20} width={20}
height={20} height={20}
style={{ color: "#3B82F6", flexShrink: 0 }} style={{ color: "var(--c-primary)", flexShrink: 0 }}
/> />
<span> <span>
{t( {t(
@@ -26,7 +26,7 @@ export default function SecurityCheckSlide({
icon="error" icon="error"
width={20} width={20}
height={20} height={20}
style={{ color: "#F04438", flexShrink: 0 }} style={{ color: "var(--c-danger)", flexShrink: 0 }}
/> />
<span> <span>
{i18n.t( {i18n.t(
@@ -28,15 +28,15 @@
.selectionBox { .selectionBox {
position: absolute; position: absolute;
border: 2px dashed #3b82f6; border: 2px dashed var(--c-primary);
background-color: rgba(59, 130, 246, 0.1); background-color: color-mix(in srgb, var(--c-primary) 10%, transparent);
pointer-events: none; pointer-events: none;
} }
.dropIndicator { .dropIndicator {
position: absolute; position: absolute;
width: 4px; width: 4px;
background-color: rgba(96, 165, 250, 0.8); background-color: color-mix(in srgb, var(--c-primary) 80%, transparent);
border-radius: 2px; border-radius: 2px;
pointer-events: none; pointer-events: none;
} }
@@ -50,8 +50,8 @@
position: absolute; position: absolute;
top: -8px; top: -8px;
right: -8px; right: -8px;
background-color: #3b82f6; background-color: var(--c-primary);
color: #ffffff; color: var(--c-text-on-primary);
border-radius: 50%; border-radius: 50%;
width: 32px; width: 32px;
height: 32px; height: 32px;
@@ -241,7 +241,7 @@ const FileThumbnail = ({
<CheckboxIndicator <CheckboxIndicator
checked={isSelected} checked={isSelected}
onChange={() => onToggleFile(file.id)} onChange={() => onToggleFile(file.id)}
color="var(--checkbox-checked-bg)" color="var(--c-primary)"
/> />
) : ( ) : (
<div className={styles.unsupportedPill}> <div className={styles.unsupportedPill}>
@@ -372,7 +372,7 @@ const FileThumbnail = ({
objectFit: "contain", objectFit: "contain",
borderRadius: 0, borderRadius: 0,
background: "#ffffff", background: "#ffffff",
border: "1px solid var(--border-default)", border: "1px solid var(--c-border)",
display: "block", display: "block",
marginLeft: "auto", marginLeft: "auto",
marginRight: "auto", marginRight: "auto",
@@ -21,13 +21,13 @@
@keyframes pageMovedHighlight { @keyframes pageMovedHighlight {
0% { 0% {
background-color: rgba(59, 130, 246, 0.32); background-color: color-mix(in srgb, var(--c-primary) 32%, transparent);
} }
60% { 60% {
background-color: rgba(59, 130, 246, 0.12); background-color: color-mix(in srgb, var(--c-primary) 12%, transparent);
} }
100% { 100% {
background-color: rgba(59, 130, 246, 0); background-color: color-mix(in srgb, var(--c-primary) 0%, transparent);
} }
} }
@@ -63,7 +63,7 @@
/* Action styles */ /* Action styles */
.actionRow:hover { .actionRow:hover {
background: var(--hover-bg); background: var(--c-hover);
} }
.actionDanger { .actionDanger {
@@ -72,7 +72,7 @@
.actionsDivider { .actionsDivider {
height: 1px; height: 1px;
background: var(--border-default); background: var(--c-border);
margin: 4px 0; margin: 4px 0;
} }
@@ -86,7 +86,7 @@
.unsupportedPill { .unsupportedPill {
margin-left: 1.75rem; margin-left: 1.75rem;
background: #6b7280; background: var(--c-text-subtle);
color: white; color: white;
padding: 4px 8px; padding: 4px 8px;
border-radius: 12px; border-radius: 12px;
@@ -121,8 +121,8 @@ const PageEditorControls = ({
borderBottomLeftRadius: 0, borderBottomLeftRadius: 0,
borderBottomRightRadius: 0, borderBottomRightRadius: 0,
boxShadow: "0 -2px 8px rgba(0,0,0,0.04)", boxShadow: "0 -2px 8px rgba(0,0,0,0.04)",
backgroundColor: "var(--bg-toolbar)", backgroundColor: "var(--c-bg-raised)",
border: "1px solid var(--border-default)", border: "1px solid var(--c-border)",
borderRadius: "16px 16px 0 0", borderRadius: "16px 16px 0 0",
pointerEvents: "auto", pointerEvents: "auto",
minWidth: 360, minWidth: 360,
@@ -31,7 +31,7 @@
.rightCol { .rightCol {
width: 8rem; width: 8rem;
border-left: 0.0625rem solid var(--border-default); border-left: 0.0625rem solid var(--c-border);
padding-left: 0.75rem; padding-left: 0.75rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -47,15 +47,15 @@
width: 100%; width: 100%;
border-radius: 1.25rem; border-radius: 1.25rem;
border: 0.0625rem solid var(--bulk-card-border); border: 0.0625rem solid var(--bulk-card-border);
background-color: var(--bulk-card-bg); background-color: var(--c-surface);
color: var(--text-primary); color: var(--c-text);
transition: all 0.2s ease; transition: all 0.2s ease;
min-height: 2rem; min-height: 2rem;
} }
.operatorChip:hover:not(:disabled) { .operatorChip:hover:not(:disabled) {
border-color: var(--bulk-card-hover-border); border-color: var(--bulk-card-hover-border);
background-color: var(--hover-bg); background-color: var(--c-hover);
transform: translateY(-0.0625rem); transform: translateY(-0.0625rem);
box-shadow: var(--shadow-sm); box-shadow: var(--shadow-sm);
} }
@@ -70,24 +70,12 @@
cursor: not-allowed; cursor: not-allowed;
} }
:global([data-mantine-color-scheme="dark"]) .operatorChip {
background-color: var(--bulk-card-bg);
border-color: var(--bulk-card-border);
color: var(--text-primary);
}
:global([data-mantine-color-scheme="dark"]) .operatorChip:hover:not(:disabled) {
background-color: var(--hover-bg);
border-color: var(--bulk-card-hover-border);
color: var(--text-primary);
}
.dropdownHeader { .dropdownHeader {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 0.75rem; padding: 0.75rem;
border-bottom: 0.0625rem solid var(--border-default); border-bottom: 0.0625rem solid var(--c-border);
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
@@ -111,7 +99,7 @@
} }
.chevron { .chevron {
color: var(--text-muted); color: var(--c-text-subtle);
} }
/* Icon-based chevrons */ /* Icon-based chevrons */
@@ -151,13 +139,13 @@
.selectedList { .selectedList {
max-height: 8rem; max-height: 8rem;
overflow: auto; overflow: auto;
background-color: var(--bg-raised); background-color: var(--c-surface-raised);
border: 0.0625rem solid var(--border-default); border: 0.0625rem solid var(--c-border);
border-radius: 0.75rem; border-radius: 0.75rem;
padding: 0.5rem 0.75rem; padding: 0.5rem 0.75rem;
margin-top: 0.5rem; margin-top: 0.5rem;
min-width: 24rem; min-width: 24rem;
color: var(--text-primary); color: var(--c-text);
} }
.selectedText { .selectedText {
@@ -175,7 +163,7 @@
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 0.75rem; padding: 0.75rem;
border-bottom: 0.0625rem solid var(--border-default); border-bottom: 0.0625rem solid var(--c-border);
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
@@ -193,26 +181,18 @@
} }
.advancedItem:hover { .advancedItem:hover {
background-color: var(--hover-bg); background-color: var(--c-hover);
}
:global([data-mantine-color-scheme="dark"]) .advancedItem:hover {
background-color: var(--hover-bg);
} }
.advancedCard { .advancedCard {
background-color: var(--bulk-card-bg); background-color: var(--c-surface);
border: none; border: none;
border-radius: 0.75rem; border-radius: 0.75rem;
padding: 0.25rem; padding: 0.25rem;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
color: var(--text-primary); color: var(--c-text);
}
:global([data-mantine-color-scheme="dark"]) .advancedCard {
background-color: var(--bulk-card-bg);
} }
.inputGroup { .inputGroup {
@@ -226,24 +206,17 @@
.applyButton { .applyButton {
min-width: 4rem; min-width: 4rem;
flex-shrink: 0; flex-shrink: 0;
} } /* Style inputs and buttons within advanced cards to match bg-raised */
.advancedCard :global(.mantine-NumberInput-input),
/* Style inputs and buttons within advanced cards to match bg-raised */
.advancedCard :global(.mantine-NumberInput-input) {
background-color: var(--bg-raised) !important;
border-color: var(--border-default) !important;
color: var(--text-primary) !important;
}
.advancedCard :global(.mantine-Button-root) { .advancedCard :global(.mantine-Button-root) {
background-color: var(--bg-raised) !important; background-color: var(--c-surface-raised) !important;
border-color: var(--border-default) !important; border-color: var(--c-border) !important;
color: var(--text-primary) !important; color: var(--c-text) !important;
} }
.advancedCard :global(.mantine-Button-root:hover) { .advancedCard :global(.mantine-Button-root:hover) {
background-color: var(--hover-bg) !important; background-color: var(--c-hover) !important;
border-color: var(--border-strong) !important; border-color: var(--c-border-strong) !important;
} }
/* Error helper text above the input */ /* Error helper text above the input */
@@ -254,8 +227,8 @@
/* Compact error container for inline tool settings */ /* Compact error container for inline tool settings */
.errorCompact { .errorCompact {
background-color: var(--bg-raised); background-color: var(--c-surface-raised);
border: 0.0625rem solid var(--border-default); border: 0.0625rem solid var(--c-border);
border-radius: 0.75rem; border-radius: 0.75rem;
padding: 0.5rem 0.75rem; padding: 0.5rem 0.75rem;
margin-top: 0.5rem; margin-top: 0.5rem;
@@ -271,11 +244,6 @@
overflow: hidden; overflow: hidden;
} }
/* Dark-mode adjustments */
:global([data-mantine-color-scheme="dark"]) .selectedList {
background-color: var(--bg-raised);
}
/* Small screens: allow the section to shrink instead of enforcing a large min width */ /* Small screens: allow the section to shrink instead of enforcing a large min width */
@media (max-width: 480px) { @media (max-width: 480px) {
.panelGroup, .panelGroup,
@@ -290,16 +258,16 @@
.panelContainer { .panelContainer {
max-height: 95vh; max-height: 95vh;
overflow: auto; overflow: auto;
background-color: var(--bulk-panel-bg); background-color: var(--c-surface);
color: var(--text-primary); color: var(--c-text);
border-radius: 0.5rem; border-radius: 0.5rem;
} }
/* Override Mantine Popover dropdown background */ /* Override Mantine Popover dropdown background */
:global(.mantine-Popover-dropdown) { :global(.mantine-Popover-dropdown) {
background-color: var(--bulk-panel-bg) !important; background-color: var(--c-surface) !important;
border-color: var(--bulk-card-border) !important; border-color: var(--bulk-card-border) !important;
color: var(--text-primary) !important; color: var(--c-text) !important;
} }
/* Override Mantine Switch outline */ /* Override Mantine Switch outline */
@@ -17,7 +17,7 @@ const OperatorsSection = ({
return ( return (
<div> <div>
<Text size="xs" c="var(--text-muted)" fw={500} mb="xs"> <Text size="xs" c="var(--c-text-subtle)" fw={500} mb="xs">
{t("bulkSelection.keywords.title", "Keywords")}: {t("bulkSelection.keywords.title", "Keywords")}:
</Text> </Text>
<Group gap="sm" wrap="nowrap"> <Group gap="sm" wrap="nowrap">
@@ -44,7 +44,7 @@ const PageSelectionInput = ({
icon="gpp-maybe-outline-rounded" icon="gpp-maybe-outline-rounded"
width="1rem" width="1rem"
height="1rem" height="1rem"
style={{ color: "var(--text-instruction)" }} style={{ color: "var(--c-accent-fg)" }}
/> />
<Text> <Text>
{t("bulkSelection.pageSelection.title", "Page Selection")} {t("bulkSelection.pageSelection.title", "Page Selection")}
@@ -53,7 +53,7 @@ const PageSelectionInput = ({
</Tooltip> </Tooltip>
{typeof advancedOpened === "boolean" && ( {typeof advancedOpened === "boolean" && (
<Flex align="center" gap="xs"> <Flex align="center" gap="xs">
<Text size="sm" c="var(--text-secondary)"> <Text size="sm" c="var(--c-text-muted)">
{t("bulkSelection.advanced.title", "Advanced")} {t("bulkSelection.advanced.title", "Advanced")}
</Text> </Text>
<Switch <Switch
@@ -50,7 +50,7 @@ const SelectPages = ({
return ( return (
<div className={classes.advancedCard}> <div className={classes.advancedCard}>
<Text size="sm" fw={600} c="var(--text-secondary)" mb="xs"> <Text size="sm" fw={600} c="var(--c-text-muted)" mb="xs">
{title} {title}
</Text> </Text>
{error && ( {error && (
@@ -63,7 +63,8 @@
} }
.modal-nav-scroll:hover { .modal-nav-scroll:hover {
scrollbar-color: rgba(128, 128, 128, 0.5) transparent; scrollbar-color: color-mix(in srgb, var(--c-border-strong) 50%, transparent)
transparent;
} }
.modal-nav-scroll::-webkit-scrollbar { .modal-nav-scroll::-webkit-scrollbar {
@@ -81,11 +82,11 @@
} }
.modal-nav-scroll:hover::-webkit-scrollbar-thumb { .modal-nav-scroll:hover::-webkit-scrollbar-thumb {
background-color: rgba(128, 128, 128, 0.5); background-color: color-mix(in srgb, var(--c-border-strong) 50%, transparent);
} }
.modal-nav-scroll::-webkit-scrollbar-thumb:hover { .modal-nav-scroll::-webkit-scrollbar-thumb:hover {
background-color: rgba(128, 128, 128, 0.7); background-color: color-mix(in srgb, var(--c-border-strong) 70%, transparent);
} }
.modal-nav-section { .modal-nav-section {
@@ -131,7 +132,8 @@
} }
.modal-content-scroll:hover { .modal-content-scroll:hover {
scrollbar-color: rgba(128, 128, 128, 0.5) transparent; scrollbar-color: color-mix(in srgb, var(--c-border-strong) 50%, transparent)
transparent;
} }
.modal-content-scroll::-webkit-scrollbar { .modal-content-scroll::-webkit-scrollbar {
@@ -149,11 +151,11 @@
} }
.modal-content-scroll:hover::-webkit-scrollbar-thumb { .modal-content-scroll:hover::-webkit-scrollbar-thumb {
background-color: rgba(128, 128, 128, 0.5); background-color: color-mix(in srgb, var(--c-border-strong) 50%, transparent);
} }
.modal-content-scroll::-webkit-scrollbar-thumb:hover { .modal-content-scroll::-webkit-scrollbar-thumb:hover {
background-color: rgba(128, 128, 128, 0.7); background-color: color-mix(in srgb, var(--c-border-strong) 70%, transparent);
} }
.modal-header { .modal-header {
@@ -212,8 +214,8 @@
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
background: var(--modal-content-bg); background: var(--c-surface);
border-top: 1px solid var(--modal-header-border); border-top: 1px solid var(--c-border-subtle);
padding: 1rem 2rem; padding: 1rem 2rem;
margin: 0 -2rem; margin: 0 -2rem;
margin-bottom: -1rem; margin-bottom: -1rem;
@@ -165,13 +165,13 @@ const AppConfigModalInner: React.FC<AppConfigModalProps> = ({
const colors = useMemo( const colors = useMemo(
() => ({ () => ({
navBg: "var(--modal-nav-bg)", navBg: "var(--c-bg-raised)",
sectionTitle: "var(--modal-nav-section-title)", sectionTitle: "var(--c-text-subtle)",
navItem: "var(--modal-nav-item)", navItem: "var(--modal-nav-item)",
navItemActive: "var(--modal-nav-item-active)", navItemActive: "var(--c-accent-fg)",
navItemActiveBg: "var(--modal-nav-item-active-bg)", navItemActiveBg: "var(--c-primary-subtle)",
contentBg: "var(--modal-content-bg)", contentBg: "var(--c-surface)",
headerBorder: "var(--modal-header-border)", headerBorder: "var(--c-border-subtle)",
}), }),
[], [],
); );
@@ -9,15 +9,15 @@
background: none; background: none;
cursor: pointer; cursor: pointer;
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
color: var(--color-text-4); color: var(--c-text-subtle);
transition: transition:
background var(--motion-fast), background var(--motion-fast),
color var(--motion-fast); color var(--motion-fast);
} }
.app-switch-btn:hover { .app-switch-btn:hover {
background: var(--color-bg-hover); background: var(--c-hover);
color: var(--color-text-2); color: var(--c-text-muted);
} }
.app-switch-icon { .app-switch-icon {
@@ -79,8 +79,8 @@ const Badge: React.FC<BadgeProps> = ({
// Default styling // Default styling
return { return {
background: "var(--tool-header-badge-bg)", background: "var(--c-surface-raised)",
color: "var(--tool-header-badge-text)", color: "var(--c-accent-fg)",
}; };
}; };
@@ -78,7 +78,11 @@ export default function EditableSecretField({
)} )}
{description && ( {description && (
<p <p
style={{ margin: "4px 0 12px 0", fontSize: "0.75rem", color: "#666" }} style={{
margin: "4px 0 12px 0",
fontSize: "0.75rem",
color: "var(--c-text-muted)",
}}
> >
{description} {description}
</p> </p>
@@ -117,7 +117,7 @@ export default class ErrorBoundary extends React.Component<
style={{ style={{
fontSize: "0.75rem", fontSize: "0.75rem",
overflow: "auto", overflow: "auto",
backgroundColor: "#f5f5f5", backgroundColor: "var(--c-surface-sunken)",
padding: "1rem", padding: "1rem",
borderRadius: "4px", borderRadius: "4px",
maxHeight: "300px", maxHeight: "300px",
@@ -74,7 +74,7 @@ const FileCard = ({
<Stack gap={6} align="center"> <Stack gap={6} align="center">
<Box <Box
style={{ style={{
border: "2px solid #e0e0e0", border: "2px solid var(--c-border)",
borderRadius: 8, borderRadius: 8,
width: 90, width: 90,
height: 120, height: 120,
@@ -82,7 +82,7 @@ const FileCard = ({
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
margin: "0 auto", margin: "0 auto",
background: "#fafbfc", background: "var(--c-surface)",
position: "relative", position: "relative",
}} }}
> >
@@ -54,8 +54,8 @@ export const FileDropdownMenu: React.FC<FileDropdownMenuProps> = ({
</Menu.Target> </Menu.Target>
<Menu.Dropdown <Menu.Dropdown
style={{ style={{
backgroundColor: "var(--bg-file-manager)", backgroundColor: "var(--c-bg)",
border: "1px solid var(--border-subtle)", border: "1px solid var(--c-border-subtle)",
borderRadius: "8px", borderRadius: "8px",
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)", boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
maxHeight: "50vh", maxHeight: "50vh",
@@ -1,9 +1,9 @@
/* ── Trigger ─────────────────────────────────────── */ /* ── Trigger ─────────────────────────────────────── */
.trigger { .trigger {
border: 1px solid var(--border-default); border: 1px solid var(--c-border);
border-radius: var(--radius-md); border-radius: var(--radius-md);
padding: 0.5rem 0.75rem; padding: 0.5rem 0.75rem;
background: var(--bg-surface); background: var(--c-surface);
cursor: pointer; cursor: pointer;
flex: 1; flex: 1;
min-width: 0; min-width: 0;
@@ -47,8 +47,8 @@
justify-content: space-between; justify-content: space-between;
padding: 0.3rem 0.45rem; padding: 0.3rem 0.45rem;
gap: 0.4rem; gap: 0.4rem;
border-bottom: 1px solid var(--border-default); border-bottom: 1px solid var(--c-border);
background: var(--bg-surface); background: var(--c-surface);
} }
.tabGroup { .tabGroup {
@@ -66,7 +66,7 @@
min-width: 0; min-width: 0;
min-height: 24px; min-height: 24px;
max-height: 26px; max-height: 26px;
border: 1px solid var(--border-default); border: 1px solid var(--c-border);
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
background: color-mix( background: color-mix(
in srgb, in srgb,
@@ -185,8 +185,8 @@
/* ── Search / filter row ─────────────────────────── */ /* ── Search / filter row ─────────────────────────── */
.searchRow { .searchRow {
padding: 0.3rem 0.45rem; padding: 0.3rem 0.45rem;
border-bottom: 1px solid var(--border-default); border-bottom: 1px solid var(--c-border);
background: var(--bg-surface); background: var(--c-surface);
} }
.searchInput { .searchInput {
@@ -195,7 +195,7 @@
height: 1.625rem; height: 1.625rem;
padding: 0 0.5rem; padding: 0 0.5rem;
font-size: 0.7rem; font-size: 0.7rem;
border: 1px solid var(--border-subtle, var(--border-default)); border: 1px solid var(--c-border-subtle, var(--c-border));
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
background: var(--mantine-color-default-hover); background: var(--mantine-color-default-hover);
color: var(--mantine-color-text); color: var(--mantine-color-text);
@@ -233,7 +233,7 @@
cursor: pointer; cursor: pointer;
background: transparent; background: transparent;
border: none; border: none;
border-top: 1px solid var(--border-default); border-top: 1px solid var(--c-border);
text-align: left; text-align: left;
transition: background 0.08s ease; transition: background 0.08s ease;
} }
@@ -1,8 +1,8 @@
/* ========== FILE SIDEBAR ========== */ /* ========== FILE SIDEBAR ========== */
.file-sidebar { .file-sidebar {
background-color: var(--bg-toolbar); background-color: var(--c-bg-raised);
border-right: 1px solid var(--border-subtle); border-right: 1px solid var(--c-border-subtle);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
@@ -24,7 +24,7 @@
/* ---- Native file drag-and-drop ---- */ /* ---- Native file drag-and-drop ---- */
.file-sidebar[data-file-drag-over] { .file-sidebar[data-file-drag-over] {
outline: 2px dashed var(--mantine-color-blue-6, #3b82f6); outline: 2px dashed var(--mantine-color-blue-6, var(--c-primary));
outline-offset: -4px; outline-offset: -4px;
} }
@@ -42,20 +42,20 @@
pointer-events: none; pointer-events: none;
background-color: color-mix( background-color: color-mix(
in srgb, in srgb,
var(--mantine-color-blue-6, #3b82f6) 12%, var(--mantine-color-blue-6, var(--c-primary)) 12%,
var(--bg-toolbar) var(--c-bg-raised)
); );
} }
.file-sidebar-drop-overlay-icon { .file-sidebar-drop-overlay-icon {
color: var(--mantine-color-blue-6, #3b82f6) !important; color: var(--mantine-color-blue-6, var(--c-primary)) !important;
font-size: 28px !important; font-size: 28px !important;
} }
.file-sidebar-drop-overlay-text { .file-sidebar-drop-overlay-text {
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
color: var(--mantine-color-blue-6, #3b82f6); color: var(--mantine-color-blue-6, var(--c-primary));
} }
/* ---- Header ---- */ /* ---- Header ---- */
@@ -75,11 +75,11 @@
/* Icons stay left-aligned during animation; overflow:hidden on inner clips text naturally */ /* Icons stay left-aligned during animation; overflow:hidden on inner clips text naturally */
.file-sidebar-header:hover { .file-sidebar-header:hover {
background-color: var(--hover-bg); background-color: var(--c-hover);
} }
.file-sidebar-menu-icon { .file-sidebar-menu-icon {
color: var(--text-muted) !important; color: var(--c-text-subtle) !important;
font-size: 18px !important; font-size: 18px !important;
flex-shrink: 0; flex-shrink: 0;
} }
@@ -129,11 +129,11 @@
} }
.file-sidebar-search-row:not(.active):hover { .file-sidebar-search-row:not(.active):hover {
background-color: var(--hover-bg); background-color: var(--c-hover);
} }
.file-sidebar-search-icon { .file-sidebar-search-icon {
color: var(--text-muted) !important; color: var(--c-text-subtle) !important;
font-size: 18px !important; font-size: 18px !important;
flex-shrink: 0; flex-shrink: 0;
} }
@@ -148,19 +148,19 @@
border: none; border: none;
outline: none; outline: none;
font-size: 14px; font-size: 14px;
color: var(--text-primary); color: var(--c-text);
margin-left: 12px; margin-left: 12px;
min-width: 0; min-width: 0;
} }
.file-sidebar-search-input::placeholder { .file-sidebar-search-input::placeholder {
color: var(--text-muted); color: var(--c-text-subtle);
} }
.file-sidebar-search-label { .file-sidebar-search-label {
margin-left: 12px; margin-left: 12px;
font-size: 14px; font-size: 14px;
color: var(--text-secondary); color: var(--c-text-muted);
} }
/* ---- Scrollable content ---- */ /* ---- Scrollable content ---- */
@@ -199,7 +199,7 @@
} }
.file-sidebar-action-row:hover { .file-sidebar-action-row:hover {
background-color: var(--hover-bg); background-color: var(--c-hover);
} }
.file-sidebar-action-row.disabled { .file-sidebar-action-row.disabled {
@@ -212,7 +212,7 @@
} }
.file-sidebar-action-icon { .file-sidebar-action-icon {
color: var(--text-muted) !important; color: var(--c-text-subtle) !important;
font-size: 18px !important; font-size: 18px !important;
flex-shrink: 0; flex-shrink: 0;
display: inline-flex; display: inline-flex;
@@ -234,7 +234,7 @@
.file-sidebar-action-label { .file-sidebar-action-label {
margin-left: 12px; margin-left: 12px;
font-size: 14px; font-size: 14px;
color: var(--text-secondary); color: var(--c-text-muted);
white-space: nowrap; white-space: nowrap;
} }
@@ -253,7 +253,7 @@
} }
.file-sidebar-cloud-row:not(.disabled):hover { .file-sidebar-cloud-row:not(.disabled):hover {
background-color: var(--hover-bg); background-color: var(--c-hover);
} }
.file-sidebar-cloud-row.disabled { .file-sidebar-cloud-row.disabled {
@@ -320,19 +320,19 @@
border: none; border: none;
background: transparent; background: transparent;
cursor: pointer; cursor: pointer;
color: var(--text-default, var(--color-text-1)); color: var(--text-default, var(--c-text));
border-radius: 0; border-radius: 0;
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
text-align: left; text-align: left;
} }
.file-sidebar-group-header:hover { .file-sidebar-group-header:hover {
background: var(--hover-bg, var(--color-bg-hover)); background: var(--c-hover, var(--c-hover));
} }
.file-sidebar-group-icon { .file-sidebar-group-icon {
flex: none; flex: none;
color: var(--text-muted, var(--color-text-3)); color: var(--c-text-subtle, var(--c-text-subtle));
} }
.file-sidebar-group-label { .file-sidebar-group-label {
@@ -347,7 +347,7 @@
flex: none; flex: none;
font-size: 11px; font-size: 11px;
font-weight: 500; font-weight: 500;
color: var(--text-muted, var(--color-text-3)); color: var(--c-text-subtle, var(--c-text-subtle));
} }
/* Full-width, flat rows: no inset, no radius, so the hover/selected highlight /* Full-width, flat rows: no inset, no radius, so the hover/selected highlight
@@ -363,7 +363,7 @@
} }
/* Hover reads neutral (not the default blue tint); selected stays blue. */ /* Hover reads neutral (not the default blue tint); selected stays blue. */
.file-sidebar-group-items .file-sidebar-file-item:hover:not(.selected) { .file-sidebar-group-items .file-sidebar-file-item:hover:not(.selected) {
background-color: var(--color-bg-hover, rgba(120, 120, 120, 0.1)); background-color: var(--c-hover);
} }
/* A plain circle where the selected check sits — on hover, and blue when selected. */ /* A plain circle where the selected check sits — on hover, and blue when selected. */
.file-sidebar-group-items .file-sidebar-file-checkbox-hover, .file-sidebar-group-items .file-sidebar-file-checkbox-hover,
@@ -413,7 +413,7 @@
border: none; border: none;
background: transparent; background: transparent;
cursor: pointer; cursor: pointer;
color: var(--color-blue, #2563eb); color: var(--c-accent-fg, var(--c-primary));
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;
border-radius: 6px; border-radius: 6px;
@@ -424,7 +424,7 @@
display: none; display: none;
} }
.file-sidebar-view-all:hover { .file-sidebar-view-all:hover {
background: var(--color-bg-hover, rgba(120, 120, 120, 0.1)); background: var(--c-hover);
} }
.file-sidebar-file-list::-webkit-scrollbar { .file-sidebar-file-list::-webkit-scrollbar {
@@ -438,11 +438,11 @@
border-radius: 2px; border-radius: 2px;
} }
.file-sidebar-file-list::-webkit-scrollbar-thumb:hover { .file-sidebar-file-list::-webkit-scrollbar-thumb:hover {
background: var(--text-muted); background: var(--c-text-subtle);
} }
.file-sidebar-section-divider { .file-sidebar-section-divider {
border-top: 1px solid var(--border-subtle); border-top: 1px solid var(--c-border-subtle);
margin: 10px 14px 6px 14px; margin: 10px 14px 6px 14px;
} }
@@ -457,7 +457,7 @@
.file-sidebar-section-header { .file-sidebar-section-header {
position: relative; position: relative;
border-top: 1px solid var(--border-subtle); border-top: 1px solid var(--c-border-subtle);
padding-top: 10px; padding-top: 10px;
margin-top: 4px; margin-top: 4px;
flex-shrink: 0; flex-shrink: 0;
@@ -467,7 +467,7 @@
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;
letter-spacing: 0.02em; letter-spacing: 0.02em;
color: var(--text-muted); color: var(--c-text-subtle);
text-transform: uppercase; text-transform: uppercase;
} }
@@ -481,7 +481,7 @@
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
font-size: 11px; font-size: 11px;
color: var(--text-muted); color: var(--c-text-subtle);
margin-bottom: 4px; margin-bottom: 4px;
} }
.file-sidebar-bulk-add-count { .file-sidebar-bulk-add-count {
@@ -490,19 +490,19 @@
.file-sidebar-bulk-add-track { .file-sidebar-bulk-add-track {
height: 3px; height: 3px;
border-radius: 999px; border-radius: 999px;
background: color-mix(in srgb, var(--color-blue, #3b82f6) 15%, transparent); background: color-mix(in srgb, var(--c-primary) 15%, transparent);
overflow: hidden; overflow: hidden;
} }
.file-sidebar-bulk-add-bar { .file-sidebar-bulk-add-bar {
height: 100%; height: 100%;
border-radius: 999px; border-radius: 999px;
background: var(--color-blue, #3b82f6); background: var(--c-primary);
transition: width 0.15s ease-out; transition: width 0.15s ease-out;
} }
.file-sidebar-section-count { .file-sidebar-section-count {
font-size: 11px; font-size: 11px;
color: var(--text-muted); color: var(--c-text-subtle);
} }
.file-sidebar-section-btn { .file-sidebar-section-btn {
@@ -515,7 +515,7 @@
background: transparent; background: transparent;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
color: var(--text-muted); color: var(--c-text-subtle);
padding: 0; padding: 0;
outline: none; outline: none;
transition: transition:
@@ -525,13 +525,13 @@
} }
.file-sidebar-section-btn:focus-visible { .file-sidebar-section-btn:focus-visible {
outline: 2px solid #3b82f6; outline: 2px solid var(--c-primary);
outline-offset: 1px; outline-offset: 1px;
} }
.file-sidebar-section-btn:hover { .file-sidebar-section-btn:hover {
background-color: var(--hover-bg); background-color: var(--c-hover);
color: var(--text-primary); color: var(--c-text);
} }
.file-sidebar-section-btn-external { .file-sidebar-section-btn-external {
@@ -576,7 +576,7 @@
align-items: center; align-items: center;
gap: 8px; gap: 8px;
padding: 8px 10px; padding: 8px 10px;
border-top: 1px solid var(--border-subtle); border-top: 1px solid var(--c-border-subtle);
flex-shrink: 0; flex-shrink: 0;
min-height: 48px; min-height: 48px;
} }
@@ -587,8 +587,8 @@
width: 28px; width: 28px;
height: 28px; height: 28px;
border-radius: 50%; border-radius: 50%;
background-color: var(--mantine-color-blue-6, #3b82f6); background-color: var(--mantine-color-blue-6, var(--c-primary));
color: #fff; color: var(--c-text-on-primary);
font-size: 12px; font-size: 12px;
font-weight: 600; font-weight: 600;
display: flex; display: flex;
@@ -615,7 +615,7 @@
flex: 1; flex: 1;
font-size: 13px; font-size: 13px;
font-weight: 500; font-weight: 500;
color: var(--text-primary); color: var(--c-text);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -623,11 +623,11 @@
} }
.file-sidebar-bottom-bar[role="button"]:hover { .file-sidebar-bottom-bar[role="button"]:hover {
background-color: var(--hover-bg); background-color: var(--c-hover);
} }
.file-sidebar-bottom-bar[role="button"]:focus-visible { .file-sidebar-bottom-bar[role="button"]:focus-visible {
outline: 2px solid #3b82f6; outline: 2px solid var(--c-primary);
outline-offset: -2px; outline-offset: -2px;
} }
@@ -638,7 +638,7 @@
width: 28px; width: 28px;
height: 28px; height: 28px;
border-radius: 6px; border-radius: 6px;
color: var(--text-muted); color: var(--c-text-subtle);
padding: 0; padding: 0;
flex-shrink: 0; flex-shrink: 0;
margin-left: auto; margin-left: auto;
@@ -1114,7 +1114,7 @@ const FileSidebar = forwardRef<HTMLDivElement, FileSidebarProps>(
<div className="file-sidebar-cloud-icon-wrapper"> <div className="file-sidebar-cloud-icon-wrapper">
<GoogleDriveIcon <GoogleDriveIcon
className="file-sidebar-cloud-icon-gray" className="file-sidebar-cloud-icon-gray"
style={{ color: "var(--text-secondary)" }} style={{ color: "var(--c-text-muted)" }}
/> />
{isGoogleDriveEnabled && ( {isGoogleDriveEnabled && (
<GoogleDriveIcon <GoogleDriveIcon
@@ -1145,7 +1145,7 @@ const FileSidebar = forwardRef<HTMLDivElement, FileSidebarProps>(
aria-label={t("watchedFolders.sidebarTitle", "Watched Folders")} aria-label={t("watchedFolders.sidebarTitle", "Watched Folders")}
style={ style={
isWatchedFoldersActive isWatchedFoldersActive
? { backgroundColor: "var(--active-bg)" } ? { backgroundColor: "var(--c-active)" }
: undefined : undefined
} }
> >
@@ -1197,7 +1197,7 @@ const FileSidebar = forwardRef<HTMLDivElement, FileSidebarProps>(
{!stubsLoaded ? ( {!stubsLoaded ? (
<div className="file-sidebar-loading"> <div className="file-sidebar-loading">
<Loader size="sm" color="var(--text-muted)" /> <Loader size="sm" color="var(--c-text-subtle)" />
</div> </div>
) : filteredFileStubs.length > 0 ? ( ) : filteredFileStubs.length > 0 ? (
<div className="file-sidebar-file-list"> <div className="file-sidebar-file-list">
@@ -17,7 +17,7 @@
background: transparent; background: transparent;
} }
.file-sidebar-file-list::-webkit-scrollbar-thumb { .file-sidebar-file-list::-webkit-scrollbar-thumb {
background: rgb(var(--border)); background: var(--c-border);
border-radius: 2px; border-radius: 2px;
} }
@@ -63,15 +63,15 @@
} }
.file-sidebar-file-item:hover:not(.selected) { .file-sidebar-file-item:hover:not(.selected) {
background-color: rgba(59, 130, 246, 0.06); background-color: color-mix(in srgb, var(--c-primary) 6%, transparent);
} }
.file-sidebar-file-item.selected { .file-sidebar-file-item.selected {
background-color: rgba(59, 130, 246, 0.12); background-color: color-mix(in srgb, var(--c-primary) 12%, transparent);
} }
.file-sidebar-file-item.active:not(.selected) { .file-sidebar-file-item.active:not(.selected) {
background-color: rgba(59, 130, 246, 0.06); background-color: color-mix(in srgb, var(--c-primary) 6%, transparent);
} }
/* Icon wrapper */ /* Icon wrapper */
@@ -95,7 +95,7 @@
width: 20px; width: 20px;
height: 20px; height: 20px;
border-radius: 5px; border-radius: 5px;
border: 1.5px solid var(--border-hover, var(--border-strong)); border: 1.5px solid var(--c-border-strong);
} }
.file-sidebar-file-item:hover .file-sidebar-file-checkbox-hover { .file-sidebar-file-item:hover .file-sidebar-file-checkbox-hover {
@@ -116,7 +116,7 @@
width: 20px; width: 20px;
height: 20px; height: 20px;
border-radius: 5px; border-radius: 5px;
background-color: #3b82f6; background-color: var(--c-primary);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -124,7 +124,7 @@
} }
.file-sidebar-check-svg { .file-sidebar-check-svg {
color: white; color: var(--c-text-on-primary);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -179,14 +179,14 @@
display: block; display: block;
font-size: 13px; font-size: 13px;
font-weight: 500; font-weight: 500;
color: var(--text-primary); color: var(--c-text);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.file-sidebar-file-item.selected .file-sidebar-file-name { .file-sidebar-file-item.selected .file-sidebar-file-name {
color: #3b82f6; color: var(--c-accent-fg);
} }
.file-sidebar-file-meta-row { .file-sidebar-file-meta-row {
@@ -199,7 +199,7 @@
.file-sidebar-file-meta { .file-sidebar-file-meta {
font-size: 11px; font-size: 11px;
color: var(--text-muted); color: var(--c-text-subtle);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -211,7 +211,7 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-shrink: 0; flex-shrink: 0;
color: var(--accent-interactive, #6366f1); color: var(--c-primary);
} }
/* ---- Folder membership tags ---- */ /* ---- Folder membership tags ---- */
@@ -250,7 +250,7 @@
font-size: 10px; font-size: 10px;
font-weight: 600; font-weight: 600;
line-height: 1.2; line-height: 1.2;
color: var(--text-secondary); color: var(--c-text-muted);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -260,7 +260,7 @@
font-size: 10px; font-size: 10px;
font-weight: 600; font-weight: 600;
line-height: 1; line-height: 1;
color: var(--text-muted); color: var(--c-text-subtle);
cursor: default; cursor: default;
flex-shrink: 0; flex-shrink: 0;
} }
@@ -277,7 +277,7 @@
background: transparent; background: transparent;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
color: var(--text-muted); color: var(--c-text-subtle);
padding: 0; padding: 0;
opacity: 0; opacity: 0;
transition: transition:
@@ -297,48 +297,45 @@
bottom: 0; bottom: 0;
z-index: 2; z-index: 2;
/* solid base + green tint overlay so content behind doesn't bleed through */ /* solid base + green tint overlay so content behind doesn't bleed through */
background-color: var(--bg-toolbar); background-color: var(--c-bg-raised);
background-image: linear-gradient( background-image: linear-gradient(
rgba(34, 197, 94, 0.1), color-mix(in srgb, var(--c-success) 10%, transparent),
rgba(34, 197, 94, 0.1) color-mix(in srgb, var(--c-success) 10%, transparent)
); );
} }
.file-sidebar-file-item.viewed .file-sidebar-file-name { .file-sidebar-file-item.viewed .file-sidebar-file-name {
color: #22c55e; color: var(--c-success);
} }
.file-sidebar-file-item.viewed .file-sidebar-file-check { .file-sidebar-file-item.viewed .file-sidebar-file-check {
background-color: #22c55e; background-color: var(--c-success);
} }
/* viewed takes precedence over selected */ /* viewed takes precedence over selected */
.file-sidebar-file-item.viewed.selected { .file-sidebar-file-item.viewed.selected {
background-color: var(--bg-toolbar); background-color: var(--c-bg-raised);
background-image: linear-gradient( background-image: linear-gradient(
rgba(34, 197, 94, 0.1), color-mix(in srgb, var(--c-success) 10%, transparent),
rgba(34, 197, 94, 0.1) color-mix(in srgb, var(--c-success) 10%, transparent)
); );
} }
/* Always show eye for the currently viewed file */ /* Always show eye for the currently viewed file */
.file-sidebar-file-item.viewed .file-sidebar-eye-btn { .file-sidebar-file-item.viewed .file-sidebar-eye-btn {
opacity: 1; opacity: 1;
color: #22c55e; color: var(--c-success);
} }
.file-sidebar-eye-btn:hover { .file-sidebar-eye-btn:hover {
color: var(--text-primary); color: var(--c-text);
} }
/* Eye open: shown by default */ /* Eye open: shown by default */
.file-sidebar-eye-open { .file-sidebar-eye-open {
display: block !important; display: block !important;
} }
.file-sidebar-eye-closed { .file-sidebar-eye-closed,
display: none !important;
}
/* On hover over a viewed item: swap to eye-closed */ /* On hover over a viewed item: swap to eye-closed */
.file-sidebar-file-item.viewed:hover .file-sidebar-eye-open { .file-sidebar-file-item.viewed:hover .file-sidebar-eye-open {
display: none !important; display: none !important;
@@ -359,7 +356,7 @@
background: transparent; background: transparent;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
color: var(--text-muted); color: var(--c-text-subtle);
padding: 0; padding: 0;
opacity: 0; opacity: 0;
transition: transition:
@@ -376,14 +373,14 @@
} }
.file-sidebar-kebab-btn:hover { .file-sidebar-kebab-btn:hover {
color: var(--text-primary); color: var(--c-text);
} }
/* ---- Date group headers ---- */ /* ---- Date group headers ---- */
.file-sidebar-date-group-header { .file-sidebar-date-group-header {
font-size: 11px; font-size: 11px;
font-weight: 500; font-weight: 500;
color: var(--text-muted); color: var(--c-text-subtle);
padding: 0 10px 2px 10px; padding: 0 10px 2px 10px;
margin-top: 8px; margin-top: 8px;
user-select: none; user-select: none;
@@ -410,13 +407,13 @@
.file-sidebar-empty-text { .file-sidebar-empty-text {
font-size: 12px; font-size: 12px;
color: var(--text-muted); color: var(--c-text-subtle);
margin: 0 0 2px 0; margin: 0 0 2px 0;
} }
.file-sidebar-empty-hint { .file-sidebar-empty-hint {
font-size: 11px; font-size: 11px;
color: var(--text-muted); color: var(--c-text-subtle);
opacity: 0.7; opacity: 0.7;
margin: 0; margin: 0;
} }
@@ -426,8 +423,8 @@
position: fixed; position: fixed;
z-index: 9999; z-index: 9999;
transform: translateY(-50%); transform: translateY(-50%);
background: var(--bg-surface, #fff); background: var(--c-surface);
border: 1px solid var(--border-subtle); border: 1px solid var(--c-border-subtle);
border-radius: 8px; border-radius: 8px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
padding: 4px; padding: 4px;
@@ -54,8 +54,8 @@ export default function Footer({
<div <div
style={{ style={{
height: "var(--footer-height)", height: "var(--footer-height)",
backgroundColor: "var(--bg-surface)", backgroundColor: "var(--c-surface)",
borderTop: "1px solid var(--border-subtle)", borderTop: "1px solid var(--c-border-subtle)",
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
justifyContent: "center", justifyContent: "center",
@@ -6,8 +6,8 @@
display: flex; display: flex;
gap: 8px; gap: 8px;
align-items: center; align-items: center;
background: var(--bg-toolbar); background: var(--c-bg-raised);
border: 1px solid var(--border-default); border: 1px solid var(--c-border);
padding: 6px 12px; padding: 6px 12px;
border-radius: 20px; border-radius: 20px;
box-shadow: var(--shadow-md); box-shadow: var(--shadow-md);
@@ -70,7 +70,7 @@ const HoverActionMenu: React.FC<HoverActionMenuProps> = ({
disabled={action.disabled} disabled={action.disabled}
onClick={action.onClick} onClick={action.onClick}
aria-label={action.label} aria-label={action.label}
style={{ color: action.color || "var(--text-secondary)" }} style={{ color: action.color || "var(--c-text-muted)" }}
data-tour={action.dataTour} data-tour={action.dataTour}
> >
{action.icon} {action.icon}
@@ -10,7 +10,7 @@
font-size: 2rem; font-size: 2rem;
font-weight: 700; font-weight: 700;
line-height: 1.25; line-height: 1.25;
color: var(--text-primary); color: var(--c-text);
} }
.landing-subtitle { .landing-subtitle {
@@ -20,7 +20,7 @@
font-size: 0.9375rem; font-size: 0.9375rem;
line-height: 1.5; line-height: 1.5;
max-width: 28rem; max-width: 28rem;
color: var(--text-secondary); color: var(--c-text-muted);
} }
/* ── Document stack ──────────────────────────────────────── */ /* ── Document stack ──────────────────────────────────────── */
@@ -49,7 +49,7 @@
width: 128px; width: 128px;
height: 160px; height: 160px;
transform-origin: bottom center; transform-origin: bottom center;
border: 1px solid #e5e7eb; border: 1px solid var(--c-illustration-line);
box-shadow: var(--landing-doc-shadow-back-idle); box-shadow: var(--landing-doc-shadow-back-idle);
} }
@@ -103,10 +103,10 @@
/* Bars — static light colours, never change with theme */ /* Bars — static light colours, never change with theme */
.landing-bar { .landing-bar {
border-radius: 9999px; border-radius: 9999px;
background-color: #e5e7eb; background-color: var(--c-illustration-line);
} }
.landing-bar--strong { .landing-bar--strong {
background-color: #d1d5db; background-color: var(--c-illustration-line-strong);
} }
/* ── Action buttons ──────────────────────────────────────── */ /* ── Action buttons ──────────────────────────────────────── */
@@ -121,27 +121,27 @@
.landing-btn-secondary { .landing-btn-secondary {
border-radius: 0.75rem !important; border-radius: 0.75rem !important;
font-weight: 600 !important; font-weight: 600 !important;
border-color: var(--landing-button-border, var(--border-default)) !important; border-color: var(--landing-button-border, var(--c-border)) !important;
background-color: var(--landing-button-bg, var(--bg-surface)) !important; background-color: var(--landing-button-bg, var(--c-surface)) !important;
color: var(--landing-button-color, var(--text-primary)) !important; color: var(--c-accent-fg, var(--c-text)) !important;
} }
.landing-btn-secondary:hover { .landing-btn-secondary:hover {
background-color: var( background-color: var(
--landing-button-hover-bg, --landing-button-hover-bg,
var(--landing-button-bg, var(--bg-surface)) var(--landing-button-bg, var(--c-surface))
) !important; ) !important;
} }
/* Icon-only variant: accent colour instead of button text colour */ /* Icon-only variant: accent colour instead of button text colour */
.landing-btn-icon { .landing-btn-icon {
color: var(--accent-interactive) !important; color: var(--c-primary) !important;
} }
/* Dropzone accept/reject outlines. Mantine 8 no longer supports nested /* Dropzone accept/reject outlines. Mantine 8 no longer supports nested
* `&[data-accept]` selectors inside the `styles` prop object, so these are * `&[data-accept]` selectors inside the `styles` prop object, so these are
* plain CSS attribute selectors on a class applied to the Dropzone root. */ * plain CSS attribute selectors on a class applied to the Dropzone root. */
.landing-dropzone[data-accept] { .landing-dropzone[data-accept] {
outline: 2px dashed var(--accent-interactive); outline: 2px dashed var(--c-primary);
outline-offset: 4px; outline-offset: 4px;
} }
.landing-dropzone[data-reject] { .landing-dropzone[data-reject] {
@@ -6,7 +6,7 @@
} }
.languageItem { .languageItem {
border-right: 2px solid var(--mantine-color-gray-3); border-right: 2px solid var(--c-border);
} }
.languageItem:nth-child(4n) { .languageItem:nth-child(4n) {
@@ -20,7 +20,7 @@
} }
.languageItem:nth-child(4n) { .languageItem:nth-child(4n) {
border-right: 2px solid var(--mantine-color-gray-3); border-right: 2px solid var(--c-border);
} }
.languageItem:nth-child(2n) { .languageItem:nth-child(2n) {
@@ -34,7 +34,7 @@
} }
.languageItem:nth-child(4n) { .languageItem:nth-child(4n) {
border-right: 2px solid var(--mantine-color-gray-3); border-right: 2px solid var(--c-border);
} }
.languageItem:nth-child(3n) { .languageItem:nth-child(3n) {
@@ -42,23 +42,12 @@
} }
} }
/* Dark theme support */ /* Dark theme: divider colour comes from the adaptive --c-border token on the
[data-mantine-color-scheme="dark"] .languageItem { base rules; only the layout quirk (no right border on 4n) differs. */
border-right-color: var(--mantine-color-dark-3);
}
[data-mantine-color-scheme="dark"] .languageItem:nth-child(4n) { [data-mantine-color-scheme="dark"] .languageItem:nth-child(4n) {
border-right: none; border-right: none;
} }
[data-mantine-color-scheme="dark"] .languageItem:nth-child(2n) {
border-right-color: var(--mantine-color-dark-3);
}
[data-mantine-color-scheme="dark"] .languageItem:nth-child(3n) {
border-right-color: var(--mantine-color-dark-3);
}
/* Responsive text visibility */ /* Responsive text visibility */
.languageText { .languageText {
display: none; display: none;
@@ -91,10 +91,10 @@ const LanguageItem: React.FC<LanguageItemProps> = ({
? "light-dark(var(--mantine-color-blue-1), var(--mantine-color-blue-8))" ? "light-dark(var(--mantine-color-blue-1), var(--mantine-color-blue-8))"
: undefined, : undefined,
color: disabled color: disabled
? "var(--text-muted)" ? "var(--c-text-subtle)"
: isSelected : isSelected
? "light-dark(var(--mantine-color-blue-9), var(--mantine-color-blue-3))" ? "light-dark(var(--mantine-color-blue-9), var(--mantine-color-blue-3))"
: "var(--text-primary)", : "var(--c-text)",
}} }}
> >
{label} {label}
@@ -12,7 +12,7 @@
padding: 16px; padding: 16px;
color: #ffffff; color: #ffffff;
font-weight: 600; font-weight: 600;
background: rgba(16, 18, 27, 0.55); background: rgba(0, 0, 0, 0.55);
backdrop-filter: blur(6px); backdrop-filter: blur(6px);
-webkit-backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
border: 1px solid rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.06);
@@ -197,8 +197,8 @@ export const PageEditorFileDropdown: React.FC<PageEditorFileDropdownProps> = ({
<Menu.Dropdown <Menu.Dropdown
className="ph-no-capture" className="ph-no-capture"
style={{ style={{
backgroundColor: "var(--bg-file-manager)", backgroundColor: "var(--c-bg)",
border: "1px solid var(--border-subtle)", border: "1px solid var(--c-border-subtle)",
borderRadius: "8px", borderRadius: "8px",
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)", boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
maxHeight: "80vh", maxHeight: "80vh",
@@ -231,7 +231,7 @@ export const PageEditorFileDropdown: React.FC<PageEditorFileDropdownProps> = ({
marginTop: "0.5rem", marginTop: "0.5rem",
cursor: "pointer", cursor: "pointer",
backgroundColor: "transparent", backgroundColor: "transparent",
borderTop: "1px solid var(--border-subtle)", borderTop: "1px solid var(--c-border-subtle)",
transition: "background-color 0.15s ease", transition: "background-color 0.15s ease",
}} }}
onMouseEnter={(e) => { onMouseEnter={(e) => {
@@ -17,7 +17,7 @@
width: 15px; width: 15px;
height: 15px; height: 15px;
border-radius: 4px; border-radius: 4px;
color: var(--text-secondary); color: var(--c-text-muted);
background: color-mix(in srgb, currentColor 16%, transparent); background: color-mix(in srgb, currentColor 16%, transparent);
pointer-events: auto; pointer-events: auto;
} }
@@ -14,7 +14,7 @@ interface ToolIconProps {
export const ToolIcon: React.FC<ToolIconProps> = ({ export const ToolIcon: React.FC<ToolIconProps> = ({
icon, icon,
opacity = 1, opacity = 1,
color = "var(--tools-text-and-icon-color)", color = "var(--c-text)",
marginRight = "0.5rem", marginRight = "0.5rem",
}) => { }) => {
return ( return (
@@ -18,7 +18,7 @@
flex: 1; flex: 1;
min-width: 0; min-width: 0;
padding: 0.4rem 0.75rem 0.4rem 0.4rem; padding: 0.4rem 0.75rem 0.4rem 0.4rem;
border: 1px solid var(--border-subtle, var(--mantine-color-default-border)); border: 1px solid var(--c-border-subtle, var(--mantine-color-default-border));
border-radius: 9999px; border-radius: 9999px;
background: var(--mantine-color-body); background: var(--mantine-color-body);
text-align: left; text-align: left;
@@ -70,7 +70,7 @@
so it doesn't read as a clashing lighter card on the dark toolbar. */ so it doesn't read as a clashing lighter card on the dark toolbar. */
[data-mantine-color-scheme="dark"] .sui-panelhdr__bar { [data-mantine-color-scheme="dark"] .sui-panelhdr__bar {
background: transparent; background: transparent;
border-color: var(--border-subtle, var(--mantine-color-default-border)); border-color: var(--c-border-subtle, var(--mantine-color-default-border));
} }
[data-mantine-color-scheme="dark"] .sui-panelhdr__icon { [data-mantine-color-scheme="dark"] .sui-panelhdr__icon {
@@ -383,7 +383,7 @@ export const Tooltip: React.FC<TooltipProps> = ({
zIndex: Z_INDEX_OVER_FULLSCREEN_SURFACE, zIndex: Z_INDEX_OVER_FULLSCREEN_SURFACE,
visibility: positionReady ? "visible" : "hidden", visibility: positionReady ? "visible" : "hidden",
opacity: positionReady ? 1 : 0, opacity: positionReady ? 1 : 0,
color: "var(--text-primary)", color: "var(--c-text)",
...containerStyle, ...containerStyle,
}} }}
className={`${styles["tooltip-container"]} ${isPinned ? styles.pinned : ""}`} className={`${styles["tooltip-container"]} ${isPinned ? styles.pinned : ""}`}
@@ -291,7 +291,7 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
<Box <Box
style={{ style={{
border: border:
"1px solid var(--border-subtle, var(--mantine-color-default-border))", "1px solid var(--c-border-subtle, var(--mantine-color-default-border))",
borderRadius: 12, borderRadius: 12,
padding: "24px 28px", padding: "24px 28px",
background: background:
@@ -493,10 +493,10 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
style={{ style={{
borderTop: borderTop:
idx === 0 idx === 0
? "1px solid var(--border-subtle, var(--mantine-color-default-border))" ? "1px solid var(--c-border-subtle, var(--mantine-color-default-border))"
: undefined, : undefined,
borderBottom: borderBottom:
"1px solid var(--border-subtle, var(--mantine-color-default-border))", "1px solid var(--c-border-subtle, var(--mantine-color-default-border))",
padding: "10px 12px", padding: "10px 12px",
}} }}
> >
@@ -576,10 +576,10 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
style={{ style={{
borderTop: borderTop:
index === 0 index === 0
? "1px solid var(--border-subtle, var(--mantine-color-default-border))" ? "1px solid var(--c-border-subtle, var(--mantine-color-default-border))"
: undefined, : undefined,
borderBottom: borderBottom:
"1px solid var(--border-subtle, var(--mantine-color-default-border))", "1px solid var(--c-border-subtle, var(--mantine-color-default-border))",
}} }}
> >
<Group <Group
@@ -656,7 +656,7 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
pb="sm" pb="sm"
style={{ style={{
borderTop: borderTop:
"1px solid var(--border-subtle, var(--mantine-color-default-border))", "1px solid var(--c-border-subtle, var(--mantine-color-default-border))",
}} }}
> >
<Stack gap="sm" mt="sm"> <Stack gap="sm" mt="sm">
@@ -749,7 +749,7 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
<Box <Box
style={{ style={{
border: border:
"1px solid var(--border-subtle, var(--mantine-color-default-border))", "1px solid var(--c-border-subtle, var(--mantine-color-default-border))",
borderRadius: 12, borderRadius: 12,
padding: "16px 20px", padding: "16px 20px",
}} }}
@@ -834,7 +834,7 @@ const UpdateModal: React.FC<UpdateModalProps> = ({
<Box <Box
style={{ style={{
borderTop: borderTop:
"1px solid var(--border-subtle, var(--mantine-color-default-border))", "1px solid var(--c-border-subtle, var(--mantine-color-default-border))",
padding: "16px 28px", padding: "16px 28px",
flexShrink: 0, flexShrink: 0,
}} }}
@@ -8,8 +8,8 @@
align-content: flex-start; align-content: flex-start;
min-height: 40px; min-height: 40px;
padding: 0 8px; padding: 0 8px;
background-color: var(--bg-toolbar); background-color: var(--c-bg-raised);
border-bottom: 1px solid var(--border-subtle); border-bottom: 1px solid var(--c-border-subtle);
flex-shrink: 0; flex-shrink: 0;
z-index: 50; z-index: 50;
} }
@@ -33,7 +33,7 @@
border: none; border: none;
border-radius: 8px; border-radius: 8px;
background: transparent; background: transparent;
color: var(--text-secondary); color: var(--c-text-muted);
font-size: 13px; font-size: 13px;
font-weight: 500; font-weight: 500;
cursor: pointer; cursor: pointer;
@@ -44,27 +44,23 @@
} }
.workbench-bar-view-btn:hover { .workbench-bar-view-btn:hover {
background-color: var(--hover-bg); background-color: var(--c-hover);
color: var(--text-primary); color: var(--c-text);
} }
.workbench-bar-view-btn.active { .workbench-bar-view-btn.active {
background-color: var(--mantine-color-blue-light, rgba(59, 130, 246, 0.12)); background-color: var(--c-primary-subtle);
color: var(--mantine-color-blue-6, #3b82f6); color: var(--c-accent-fg);
} }
.workbench-bar-view-btn.workbench-bar-back-btn { .workbench-bar-view-btn.workbench-bar-back-btn {
color: var(--text-primary); color: var(--c-text);
font-weight: 600; font-weight: 600;
} }
.workbench-bar-view-btn.workbench-bar-back-btn:hover { .workbench-bar-view-btn.workbench-bar-back-btn:hover {
background-color: color-mix( background-color: color-mix(in srgb, var(--c-primary) 12%, transparent);
in srgb, color: var(--c-accent-fg);
var(--accent-interactive, #4a90e2) 12%,
transparent
);
color: var(--accent-interactive, #4a90e2);
} }
.workbench-bar-view-btn svg { .workbench-bar-view-btn svg {
@@ -106,7 +102,7 @@
flex: 0 0 100%; flex: 0 0 100%;
height: auto; height: auto;
padding: 4px 0; padding: 4px 0;
border-top: 1px solid var(--border-subtle); border-top: 1px solid var(--c-border-subtle);
justify-content: flex-start; justify-content: flex-start;
overflow-x: auto; overflow-x: auto;
overflow-y: hidden; overflow-y: hidden;
@@ -138,7 +134,7 @@
* Tight 24px hit-box and no hover background: these are quiet toolbar icons — * Tight 24px hit-box and no hover background: these are quiet toolbar icons —
* hover feedback comes from the icon colour darkening, not a bg tint. */ * hover feedback comes from the icon colour darkening, not a bg tint. */
.workbench-bar-action-icon { .workbench-bar-action-icon {
color: var(--text-secondary) !important; color: var(--c-text-muted) !important;
/* min-* too: Mantine's ActionIcon sets min-width/min-height from --ai-size /* min-* too: Mantine's ActionIcon sets min-width/min-height from --ai-size
* (36px), which floors the width and defeats the 24px clamp. */ * (36px), which floors the width and defeats the 24px clamp. */
width: 24px !important; width: 24px !important;
@@ -155,17 +151,17 @@
} }
.workbench-bar-action-icon:hover { .workbench-bar-action-icon:hover {
color: var(--text-primary) !important; color: var(--c-text) !important;
} }
.workbench-bar-action-icon[data-variant="filled"] { .workbench-bar-action-icon[data-variant="filled"] {
background: var(--mantine-color-blue-6, #3b82f6) !important; background: var(--c-primary) !important;
color: #fff !important; color: var(--c-text-on-primary) !important;
} }
.workbench-bar-action-icon[data-variant="filled"]:hover { .workbench-bar-action-icon[data-variant="filled"]:hover {
background: var(--mantine-color-blue-7, #2563eb) !important; background: var(--c-primary-hover) !important;
color: #fff !important; color: var(--c-text-on-primary) !important;
} }
.workbench-bar-action-wrapper { .workbench-bar-action-wrapper {
@@ -181,7 +177,7 @@
.workbench-bar-divider { .workbench-bar-divider {
width: 1px; width: 1px;
height: 16px; height: 16px;
background-color: var(--border-subtle); background-color: var(--c-border-subtle);
margin: 0 4px; margin: 0 4px;
} }
@@ -200,7 +196,7 @@
.viewer-inline-controls__page { .viewer-inline-controls__page {
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;
color: var(--text-secondary); color: var(--c-text-muted);
min-width: 3rem; min-width: 3rem;
text-align: center; text-align: center;
white-space: nowrap; white-space: nowrap;
@@ -214,7 +210,7 @@
.viewer-inline-controls__zoom-pct { .viewer-inline-controls__zoom-pct {
font-size: 12px; font-size: 12px;
color: var(--text-muted); color: var(--c-text-subtle);
min-width: 2.5rem; min-width: 2.5rem;
text-align: right; text-align: right;
white-space: nowrap; white-space: nowrap;
@@ -153,7 +153,7 @@ const DocumentThumbnail: React.FC<DocumentThumbnailProps> = ({
fontWeight: 700, fontWeight: 700,
letterSpacing: "0.1em", letterSpacing: "0.1em",
textTransform: "uppercase", textTransform: "uppercase",
color: "var(--text-secondary)", color: "var(--c-text-muted)",
background: "rgb(var(--border))", background: "rgb(var(--border))",
padding: "3px 10px", padding: "3px 10px",
borderRadius: "6px", borderRadius: "6px",
@@ -15,7 +15,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
color: var(--search-text-and-icon-color); color: var(--c-text-subtle);
} }
.input { .input {
@@ -27,12 +27,12 @@
outline: none; outline: none;
box-shadow: none; box-shadow: none;
transition: box-shadow 0.2s ease; transition: box-shadow 0.2s ease;
background-color: var(--input-bg); background-color: var(--c-input-bg);
color: var(--search-text-and-icon-color); color: var(--c-text-subtle);
} }
.input::placeholder { .input::placeholder {
color: var(--search-text-and-icon-color); color: var(--c-text-subtle);
opacity: 1; opacity: 1;
} }
@@ -65,13 +65,9 @@
justify-content: center; justify-content: center;
font-size: 16px; font-size: 16px;
transition: background-color 0.2s ease; transition: background-color 0.2s ease;
color: var(--search-text-and-icon-color); color: var(--c-text-subtle);
} }
.clearButton:hover { .clearButton:hover {
background-color: rgba(0, 0, 0, 0.1); background-color: var(--c-hover);
}
[data-mantine-color-scheme="dark"] .clearButton:hover {
background-color: rgba(255, 255, 255, 0.1);
} }
@@ -1,9 +1,9 @@
/* Tooltip Container */ /* Tooltip Container */
.tooltip-container { .tooltip-container {
position: fixed; position: fixed;
border: 0.0625rem solid var(--border-default); border: 0.0625rem solid var(--c-border);
border-radius: 0.75rem; border-radius: 0.75rem;
background-color: var(--bg-raised); background-color: var(--c-surface-raised);
box-shadow: box-shadow:
0 0.625rem 0.9375rem -0.1875rem rgba(0, 0, 0, 0.1), 0 0.625rem 0.9375rem -0.1875rem rgba(0, 0, 0, 0.1),
0 0.25rem 0.375rem -0.125rem rgba(0, 0, 0, 0.05); 0 0.25rem 0.375rem -0.125rem rgba(0, 0, 0, 0.05);
@@ -15,25 +15,25 @@
transform 100ms ease-out; transform 100ms ease-out;
max-width: 50vh; max-width: 50vh;
max-height: 80vh; max-height: 80vh;
color: var(--text-primary); color: var(--c-text);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
/* Pinned tooltip indicator */ /* Pinned tooltip indicator */
.tooltip-container.pinned { .tooltip-container.pinned {
border-color: var(--primary-color, #3b82f6); border-color: var(--primary-color, var(--c-primary));
box-shadow: box-shadow:
0 0.625rem 0.9375rem -0.1875rem rgba(0, 0, 0, 0.1), 0 0.625rem 0.9375rem -0.1875rem rgba(0, 0, 0, 0.1),
0 0.25rem 0.375rem -0.125rem rgba(0, 0, 0, 0.05), 0 0.25rem 0.375rem -0.125rem rgba(0, 0, 0, 0.05),
0 0 0 0.125rem rgba(59, 130, 246, 0.1); 0 0 0 0.125rem color-mix(in srgb, var(--c-primary) 10%, transparent);
} }
/* Pinned tooltip header */ /* Pinned tooltip header */
.tooltip-container.pinned .tooltip-header { .tooltip-container.pinned .tooltip-header {
background-color: var(--primary-color, #3b82f6); background-color: var(--primary-color, var(--c-primary));
color: white; color: white;
border-color: var(--primary-color, #3b82f6); border-color: var(--primary-color, var(--c-primary));
} }
/* Close button */ /* Close button */
@@ -42,10 +42,10 @@
top: 0.5rem; top: 0.5rem;
right: 0.5rem; right: 0.5rem;
font-size: 0.875rem; font-size: 0.875rem;
background: var(--bg-raised); background: var(--c-surface-raised);
padding: 0.25rem; padding: 0.25rem;
border-radius: 0.25rem; border-radius: 0.25rem;
border: 0.0625rem solid var(--border-default); border: 0.0625rem solid var(--c-border);
cursor: pointer; cursor: pointer;
transition: transition:
background-color 0.2s ease, background-color 0.2s ease,
@@ -64,15 +64,15 @@
} }
.tooltip-pin-button:hover { .tooltip-pin-button:hover {
background-color: #ef4444 !important; background-color: var(--c-danger) !important;
border-color: #ef4444 !important; border-color: var(--c-danger) !important;
} }
.tooltip-pin-button:focus, .tooltip-pin-button:focus,
.tooltip-pin-button:focus-visible { .tooltip-pin-button:focus-visible {
outline: none; outline: none;
border-color: var(--border-default) !important; border-color: var(--c-border) !important;
background-color: var(--bg-raised) !important; background-color: var(--c-surface-raised) !important;
} }
/* Tooltip Header */ /* Tooltip Header */
@@ -107,7 +107,7 @@
/* Tooltip Body */ /* Tooltip Body */
.tooltip-body { .tooltip-body {
padding: 1rem; padding: 1rem;
color: var(--text-primary) !important; color: var(--c-text) !important;
font-size: 0.875rem !important; font-size: 0.875rem !important;
line-height: 1.6 !important; line-height: 1.6 !important;
overflow-y: auto; overflow-y: auto;
@@ -116,47 +116,49 @@
} }
.tooltip-body * { .tooltip-body * {
color: var(--text-primary) !important; color: var(--c-text) !important;
} }
/* Link styling within tooltips */ /* Link styling within tooltips */
.tooltip-body a { .tooltip-body a {
color: var(--link-color, #3b82f6) !important; color: var(--link-color, var(--c-primary)) !important;
text-decoration: underline; text-decoration: underline;
text-decoration-color: var(--link-underline-color, rgba(59, 130, 246, 0.3)); text-decoration-color: var(
--link-underline-color,
color-mix(in srgb, var(--c-primary) 30%, transparent)
);
transition: transition:
color 0.2s ease, color 0.2s ease,
text-decoration-color 0.2s ease; text-decoration-color 0.2s ease;
} }
.tooltip-body a:hover { .tooltip-body a:hover {
color: var(--link-hover-color, #2563eb) !important; color: var(--link-hover-color, var(--c-primary-hover)) !important;
text-decoration-color: var( text-decoration-color: var(
--link-hover-underline-color, --link-hover-underline-color,
rgba(37, 99, 235, 0.5) color-mix(in srgb, var(--c-primary-hover) 50%, transparent)
); );
} }
.tooltip-container .tooltip-body,
.tooltip-container .tooltip-body {
color: var(--text-primary) !important;
}
.tooltip-container .tooltip-body * { .tooltip-container .tooltip-body * {
color: var(--text-primary) !important; color: var(--c-text) !important;
} }
/* Ensure links maintain their styling */ /* Ensure links maintain their styling */
.tooltip-container .tooltip-body a { .tooltip-container .tooltip-body a {
color: var(--link-color, #3b82f6) !important; color: var(--link-color, var(--c-primary)) !important;
text-decoration: underline; text-decoration: underline;
text-decoration-color: var(--link-underline-color, rgba(59, 130, 246, 0.3)); text-decoration-color: var(
--link-underline-color,
color-mix(in srgb, var(--c-primary) 30%, transparent)
);
} }
.tooltip-container .tooltip-body a:hover { .tooltip-container .tooltip-body a:hover {
color: var(--link-hover-color, #2563eb) !important; color: var(--link-hover-color, var(--c-primary-hover)) !important;
text-decoration-color: var( text-decoration-color: var(
--link-hover-underline-color, --link-hover-underline-color,
rgba(37, 99, 235, 0.5) color-mix(in srgb, var(--c-primary-hover) 50%, transparent)
); );
} }
@@ -165,8 +167,8 @@
position: absolute; position: absolute;
width: 0.5rem; width: 0.5rem;
height: 0.5rem; height: 0.5rem;
background: var(--bg-raised); background: var(--c-surface-raised);
border: 0.0625rem solid var(--border-default); border: 0.0625rem solid var(--c-border);
transform: rotate(45deg); transform: rotate(45deg);
} }
@@ -17,13 +17,13 @@ export const TooltipContent: React.FC<TooltipContentProps> = ({
<div <div
className={`${styles["tooltip-body"]}`} className={`${styles["tooltip-body"]}`}
style={{ style={{
color: "var(--text-primary)", color: "var(--c-text)",
padding: `16px ${16 + extraRightPadding}px 16px 16px`, padding: `16px ${16 + extraRightPadding}px 16px 16px`,
fontSize: "14px", fontSize: "14px",
lineHeight: "1.6", lineHeight: "1.6",
}} }}
> >
<div style={{ color: "var(--text-primary)" }}> <div style={{ color: "var(--c-text)" }}>
{tips ? ( {tips ? (
<> <>
{tips.map((tip, index) => ( {tips.map((tip, index) => (
@@ -35,8 +35,8 @@ export const TooltipContent: React.FC<TooltipContentProps> = ({
<div <div
style={{ style={{
display: "inline-block", display: "inline-block",
backgroundColor: "var(--tooltip-title-bg)", backgroundColor: "var(--c-primary-tint)",
color: "var(--tooltip-title-color)", color: "var(--c-text)",
padding: "6px 12px", padding: "6px 12px",
borderRadius: "16px", borderRadius: "16px",
fontSize: "12px", fontSize: "12px",
@@ -51,7 +51,7 @@ export const TooltipContent: React.FC<TooltipContentProps> = ({
<p <p
style={{ style={{
margin: "0 0 12px 0", margin: "0 0 12px 0",
color: "var(--text-secondary)", color: "var(--c-text-muted)",
fontSize: "13px", fontSize: "13px",
}} }}
dangerouslySetInnerHTML={{ __html: tip.description }} dangerouslySetInnerHTML={{ __html: tip.description }}
@@ -62,7 +62,7 @@ export const TooltipContent: React.FC<TooltipContentProps> = ({
style={{ style={{
margin: "0", margin: "0",
paddingLeft: "16px", paddingLeft: "16px",
color: "var(--text-secondary)", color: "var(--c-text-muted)",
fontSize: "13px", fontSize: "13px",
}} }}
> >
@@ -75,26 +75,26 @@
/* Toast Alert Type Colors */ /* Toast Alert Type Colors */
.toast-item--success { .toast-item--success {
background: var(--color-green-100); background: var(--color-green-100);
color: var(--text-primary); color: var(--c-text);
border: 1px solid var(--color-green-400); border: 1px solid var(--color-green-400);
} }
.toast-item--error { .toast-item--error {
background: var(--color-red-100); background: var(--color-red-100);
color: var(--text-primary); color: var(--c-text);
border: 1px solid var(--color-red-400); border: 1px solid var(--color-red-400);
} }
.toast-item--warning { .toast-item--warning {
background: var(--color-yellow-100); background: var(--color-yellow-100);
color: var(--text-primary); color: var(--c-text);
border: 1px solid var(--color-yellow-400); border: 1px solid var(--color-yellow-400);
} }
.toast-item--neutral { .toast-item--neutral {
background: var(--bg-surface); background: var(--c-surface);
color: var(--text-primary); color: var(--c-text);
border: 1px solid var(--border-default); border: 1px solid var(--c-border);
} }
/* Toast Header Row */ /* Toast Header Row */
@@ -146,7 +146,7 @@
border-radius: 999px; border-radius: 999px;
border: none; border: none;
background: transparent; background: transparent;
color: var(--text-secondary); color: var(--c-text-muted);
cursor: pointer; cursor: pointer;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -166,7 +166,7 @@
.toast-progress-container { .toast-progress-container {
margin-top: 8px; margin-top: 8px;
height: 6px; height: 6px;
background: var(--bg-muted); background: var(--c-surface-sunken);
border-radius: 999px; border-radius: 999px;
overflow: hidden; overflow: hidden;
} }
@@ -217,21 +217,21 @@
} }
.toast-action-button--success { .toast-action-button--success {
color: var(--text-primary); color: var(--c-text);
border-color: var(--color-green-400); border-color: var(--color-green-400);
} }
.toast-action-button--error { .toast-action-button--error {
color: var(--text-primary); color: var(--c-text);
border-color: var(--color-red-400); border-color: var(--color-red-400);
} }
.toast-action-button--warning { .toast-action-button--warning {
color: var(--text-primary); color: var(--c-text);
border-color: var(--color-yellow-400); border-color: var(--color-yellow-400);
} }
.toast-action-button--neutral { .toast-action-button--neutral {
color: var(--text-primary); color: var(--c-text);
border-color: var(--border-default); border-color: var(--c-border);
} }
@@ -168,7 +168,7 @@ export default function RightSidebar() {
ref={toolPanelRef} ref={toolPanelRef}
data-sidebar="tool-panel" data-sidebar="tool-panel"
data-tour={fullscreenExpanded ? undefined : "tool-panel"} data-tour={fullscreenExpanded ? undefined : "tool-panel"}
className={`tool-panel flex flex-col ${fullscreenExpanded ? "tool-panel--fullscreen-active" : "overflow-hidden"} bg-[var(--bg-toolbar)] border-l border-[var(--border-subtle)] transition-all duration-300 ease-out ${isMobile ? "h-full border-r-0" : "h-screen"} ${fullscreenExpanded ? "tool-panel--fullscreen" : ""}`} className={`tool-panel flex flex-col ${fullscreenExpanded ? "tool-panel--fullscreen-active" : "overflow-hidden"} bg-[var(--c-bg-raised)] border-l border-[var(--c-border-subtle)] transition-all duration-300 ease-out ${isMobile ? "h-full border-r-0" : "h-screen"} ${fullscreenExpanded ? "tool-panel--fullscreen" : ""}`}
style={{ style={{
width: computedWidth(), width: computedWidth(),
padding: "0", padding: "0",
@@ -4,8 +4,8 @@
align-items: center; align-items: center;
gap: 2px; gap: 2px;
padding: 4px 8px; padding: 4px 8px;
border-bottom: 1px solid var(--border-subtle); border-bottom: 1px solid var(--c-border-subtle);
background-color: var(--bg-toolbar); background-color: var(--c-bg-raised);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -13,115 +13,107 @@
.tool-panel__fullscreen-surface-inner { .tool-panel__fullscreen-surface-inner {
--fullscreen-bg-surface-1: color-mix( --fullscreen-bg-surface-1: color-mix(
in srgb, in srgb,
var(--bg-toolbar) 96%, var(--c-bg-raised) 96%,
transparent transparent
); );
--fullscreen-bg-surface-2: color-mix( --fullscreen-bg-surface-2: color-mix(in srgb, var(--c-bg) 90%, transparent);
in srgb, --fullscreen-bg-header: var(--c-bg-raised);
var(--bg-background) 90%, --fullscreen-bg-controls-1: var(--c-bg-raised);
transparent
);
--fullscreen-bg-header: var(--bg-toolbar);
--fullscreen-bg-controls-1: var(--bg-toolbar);
--fullscreen-bg-controls-2: color-mix( --fullscreen-bg-controls-2: color-mix(
in srgb, in srgb,
var(--bg-toolbar) 95%, var(--c-bg-raised) 95%,
var(--bg-background) var(--c-bg)
);
--fullscreen-bg-body-1: color-mix(
in srgb,
var(--bg-background) 86%,
transparent
); );
--fullscreen-bg-body-1: color-mix(in srgb, var(--c-bg) 86%, transparent);
--fullscreen-bg-body-2: color-mix( --fullscreen-bg-body-2: color-mix(
in srgb, in srgb,
var(--bg-toolbar) 78%, var(--c-bg-raised) 78%,
transparent transparent
); );
--fullscreen-bg-group: color-mix(in srgb, var(--bg-toolbar) 82%, transparent); --fullscreen-bg-group: color-mix(
--fullscreen-bg-item: color-mix(in srgb, var(--bg-toolbar) 88%, transparent); in srgb,
var(--c-bg-raised) 82%,
transparent
);
--fullscreen-bg-item: color-mix(in srgb, var(--c-bg-raised) 88%, transparent);
--fullscreen-bg-list-item: color-mix( --fullscreen-bg-list-item: color-mix(
in srgb, in srgb,
var(--bg-toolbar) 86%, var(--c-bg-raised) 86%,
transparent transparent
); );
--fullscreen-bg-icon-detailed: color-mix( --fullscreen-bg-icon-detailed: color-mix(
in srgb, in srgb,
var(--bg-muted) 75%, var(--c-surface-sunken) 75%,
transparent transparent
); );
--fullscreen-bg-icon-compact: color-mix( --fullscreen-bg-icon-compact: color-mix(
in srgb, in srgb,
var(--bg-muted) 70%, var(--c-surface-sunken) 70%,
transparent transparent
); );
--fullscreen-border-subtle-75: color-mix( --fullscreen-border-subtle-75: color-mix(
in srgb, in srgb,
var(--border-subtle) 75%, var(--c-border-subtle) 75%,
transparent transparent
); );
--fullscreen-border-subtle-70: color-mix( --fullscreen-border-subtle-70: color-mix(
in srgb, in srgb,
var(--border-subtle) 70%, var(--c-border-subtle) 70%,
transparent transparent
); );
--fullscreen-border-subtle-65: color-mix( --fullscreen-border-subtle-65: color-mix(
in srgb, in srgb,
var(--border-subtle) 65%, var(--c-border-subtle) 65%,
transparent transparent
); );
--fullscreen-border-favorites: color-mix( --fullscreen-border-favorites: color-mix(
in srgb, in srgb,
var(--special-color-favorites) 25%, var(--special-color-favorites) 25%,
var(--border-subtle) var(--c-border-subtle)
); );
--fullscreen-border-recommended: color-mix( --fullscreen-border-recommended: color-mix(
in srgb, in srgb,
var(--special-color-recommended) 25%, var(--special-color-recommended) 25%,
var(--border-subtle) var(--c-border-subtle)
); );
--fullscreen-shadow-primary: color-mix( --fullscreen-shadow-primary: color-mix(
in srgb, in srgb,
var(--shadow-color, rgba(15, 23, 42, 0.55)) 25%, var(--shadow-color, color-mix(in srgb, black 55%, transparent)) 25%,
transparent transparent
); );
--fullscreen-shadow-secondary: color-mix( --fullscreen-shadow-secondary: color-mix(
in srgb, in srgb,
var(--shadow-color, rgba(15, 23, 42, 0.35)) 30%, var(--shadow-color, color-mix(in srgb, black 35%, transparent)) 30%,
transparent transparent
); );
--fullscreen-shadow-group: color-mix( --fullscreen-shadow-group: color-mix(
in srgb, in srgb,
var(--shadow-color, rgba(15, 23, 42, 0.45)) 18%, var(--shadow-color, color-mix(in srgb, black 45%, transparent)) 18%,
transparent transparent
); );
--fullscreen-accent-hover: color-mix( --fullscreen-accent-hover: color-mix(
in srgb, in srgb,
var(--text-primary) 20%, var(--c-text) 20%,
var(--border-subtle) var(--c-border-subtle)
); );
--fullscreen-accent-selected: color-mix( --fullscreen-accent-selected: color-mix(
in srgb, in srgb,
var(--text-primary) 30%, var(--c-text) 30%,
var(--border-subtle) var(--c-border-subtle)
);
--fullscreen-accent-ring: color-mix(
in srgb,
var(--text-primary) 15%,
transparent
); );
--fullscreen-accent-ring: color-mix(in srgb, var(--c-text) 15%, transparent);
--fullscreen-accent-list-bg: color-mix( --fullscreen-accent-list-bg: color-mix(
in srgb, in srgb,
var(--text-primary) 8%, var(--c-text) 8%,
var(--bg-toolbar) var(--c-bg-raised)
); );
--fullscreen-accent-list-border: color-mix( --fullscreen-accent-list-border: color-mix(
in srgb, in srgb,
var(--text-primary) 20%, var(--c-text) 20%,
var(--border-subtle) var(--c-border-subtle)
); );
--fullscreen-text-icon: var(--text-primary); --fullscreen-text-icon: var(--c-text);
--fullscreen-text-icon-compact: var(--text-primary); --fullscreen-text-icon-compact: var(--c-text);
} }
.tool-panel { .tool-panel {
@@ -153,7 +145,7 @@
.tool-panel__collapsed-divider { .tool-panel__collapsed-divider {
height: 1px; height: 1px;
background: var(--border-subtle); background: var(--c-border-subtle);
margin: 0 0.5rem 8px; margin: 0 0.5rem 8px;
} }
@@ -178,7 +170,7 @@
border: 1px solid transparent; border: 1px solid transparent;
border-radius: 0.5rem; border-radius: 0.5rem;
background: transparent; background: transparent;
color: var(--tools-text-and-icon-color); color: var(--c-text);
cursor: pointer; cursor: pointer;
transition: transition:
background 120ms ease-out, background 120ms ease-out,
@@ -198,8 +190,8 @@
.tool-panel__expand-btn { .tool-panel__expand-btn {
flex-shrink: 0; flex-shrink: 0;
color: var(--text-secondary) !important; color: var(--c-text-muted) !important;
border-color: var(--border-subtle) !important; border-color: var(--c-border-subtle) !important;
} }
/* The collapse/expand toggle keeps a stable identity across the collapsed strip /* The collapse/expand toggle keeps a stable identity across the collapsed strip
@@ -210,25 +202,25 @@
} }
.tool-panel__expand-btn svg { .tool-panel__expand-btn svg {
color: var(--text-secondary) !important; color: var(--c-text-muted) !important;
} }
.tool-panel__expand-btn:hover { .tool-panel__expand-btn:hover {
color: var(--text-primary) !important; color: var(--c-text) !important;
border-color: var(--border) !important; border-color: var(--border) !important;
} }
.tool-panel__collapsed-search-btn { .tool-panel__collapsed-search-btn {
flex-shrink: 0; flex-shrink: 0;
color: var(--text-secondary) !important; color: var(--c-text-muted) !important;
} }
.tool-panel__collapsed-search-btn svg { .tool-panel__collapsed-search-btn svg {
color: var(--text-secondary) !important; color: var(--c-text-muted) !important;
} }
.tool-panel__collapsed-search-btn:hover { .tool-panel__collapsed-search-btn:hover {
color: var(--text-primary) !important; color: var(--c-text) !important;
} }
.tool-panel__back-btn { .tool-panel__back-btn {
@@ -237,7 +229,7 @@
.tool-panel__back-bar { .tool-panel__back-bar {
flex-shrink: 0; flex-shrink: 0;
border-bottom: 1px solid var(--border-subtle) !important; border-bottom: 1px solid var(--c-border-subtle) !important;
} }
.tool-panel--fullscreen-active { .tool-panel--fullscreen-active {
@@ -282,7 +274,7 @@
/* Search that separates the Policies section from the Tools list below it. */ /* Search that separates the Policies section from the Tools list below it. */
.tool-panel__between-search { .tool-panel__between-search {
padding: 0.5rem 0.75rem 0.25rem; padding: 0.5rem 0.75rem 0.25rem;
border-top: 1px solid var(--border-subtle, var(--color-border)); border-top: 1px solid var(--c-border-subtle, var(--c-border));
} }
.tool-panel__between-search .search-input-container { .tool-panel__between-search .search-input-container {
@@ -292,7 +284,7 @@
/* Slightly recessed search field so it reads as distinct from the panel. */ /* Slightly recessed search field so it reads as distinct from the panel. */
.tool-panel__between-search input { .tool-panel__between-search input {
background-color: var(--bg-muted); background-color: var(--c-surface-sunken);
} }
::view-transition-old(tool-rail) { ::view-transition-old(tool-rail) {
@@ -334,7 +326,7 @@
} }
.tool-panel--fullscreen { .tool-panel--fullscreen {
background: var(--bg-toolbar); background: var(--c-bg-raised);
} }
.tool-panel__placeholder { .tool-panel__placeholder {
@@ -342,7 +334,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
color: var(--text-muted); color: var(--c-text-subtle);
font-size: 0.9rem; font-size: 0.9rem;
padding: 1.5rem; padding: 1.5rem;
text-align: center; text-align: center;
@@ -403,8 +395,8 @@
align-items: center; align-items: center;
gap: 1rem; gap: 1rem;
padding: 0.75rem 1.75rem; padding: 0.75rem 1.75rem;
border-bottom: 1px solid var(--border-subtle); border-bottom: 1px solid var(--c-border-subtle);
background: var(--bg-toolbar); background: var(--c-bg-raised);
} }
.tool-panel__fullscreen-brand { .tool-panel__fullscreen-brand {
@@ -428,8 +420,8 @@
align-items: center; align-items: center;
gap: 1rem; gap: 1rem;
padding: 0.75rem 1.75rem; padding: 0.75rem 1.75rem;
border-bottom: 1px solid var(--tool-panel-search-border-bottom); border-bottom: 1px solid var(--c-border);
background: var(--tool-panel-search-bg); background: var(--c-surface-sunken);
} }
.tool-panel__fullscreen-controls .search-input-container { .tool-panel__fullscreen-controls .search-input-container {
@@ -546,7 +538,10 @@
.tool-panel__fullscreen-item:hover:not([aria-disabled="true"]):not(:disabled) { .tool-panel__fullscreen-item:hover:not([aria-disabled="true"]):not(:disabled) {
transform: translateY(-2px); transform: translateY(-2px);
border-color: var(--fullscreen-accent-hover); border-color: var(--fullscreen-accent-hover);
box-shadow: var(--shadow-xl, 0 18px 34px rgba(15, 23, 42, 0.14)); box-shadow: var(
--shadow-xl,
0 18px 34px color-mix(in srgb, black 14%, transparent)
);
} }
.tool-panel__fullscreen-item--selected { .tool-panel__fullscreen-item--selected {
@@ -619,8 +614,8 @@
inset: 0; inset: 0;
background: linear-gradient( background: linear-gradient(
135deg, 135deg,
color-mix(in srgb, var(--text-primary) 12%, transparent), color-mix(in srgb, var(--c-text) 12%, transparent),
color-mix(in srgb, var(--text-primary) 4%, transparent) color-mix(in srgb, var(--c-text) 4%, transparent)
); );
opacity: 0; opacity: 0;
transition: opacity 0.2s ease; transition: opacity 0.2s ease;
@@ -630,8 +625,7 @@
.tool-panel__fullscreen-item:hover:not([aria-disabled="true"]) .tool-panel__fullscreen-item:hover:not([aria-disabled="true"])
.tool-panel__fullscreen-icon { .tool-panel__fullscreen-icon {
transform: scale(1.08); transform: scale(1.08);
box-shadow: 0 4px 12px box-shadow: 0 4px 12px color-mix(in srgb, var(--c-text) 15%, transparent);
color-mix(in srgb, var(--text-primary) 15%, transparent);
} }
.tool-panel__fullscreen-item:hover:not([aria-disabled="true"]) .tool-panel__fullscreen-item:hover:not([aria-disabled="true"])
@@ -656,7 +650,7 @@
} }
.tool-panel__fullscreen-name { .tool-panel__fullscreen-name {
color: var(--text-primary); color: var(--c-text);
font-size: 13px !important; font-size: 13px !important;
font-weight: 500 !important; font-weight: 500 !important;
} }
@@ -753,8 +747,8 @@
inset: 0; inset: 0;
background: linear-gradient( background: linear-gradient(
135deg, 135deg,
color-mix(in srgb, var(--text-primary) 10%, transparent), color-mix(in srgb, var(--c-text) 10%, transparent),
color-mix(in srgb, var(--text-primary) 3%, transparent) color-mix(in srgb, var(--c-text) 3%, transparent)
); );
opacity: 0; opacity: 0;
transition: opacity 0.2s ease; transition: opacity 0.2s ease;
@@ -764,7 +758,7 @@
.tool-panel__fullscreen-list-item:hover:not([aria-disabled="true"]) .tool-panel__fullscreen-list-item:hover:not([aria-disabled="true"])
.tool-panel__fullscreen-list-icon { .tool-panel__fullscreen-list-icon {
transform: scale(1.06); transform: scale(1.06);
box-shadow: 0 2px 8px color-mix(in srgb, var(--text-primary) 12%, transparent); box-shadow: 0 2px 8px color-mix(in srgb, var(--c-text) 12%, transparent);
} }
.tool-panel__fullscreen-list-item:hover:not([aria-disabled="true"]) .tool-panel__fullscreen-list-item:hover:not([aria-disabled="true"])
@@ -1,10 +1,10 @@
.tool-panel-mode-prompt__modal { .tool-panel-mode-prompt__modal {
background: color-mix(in srgb, var(--bg-toolbar) 94%, transparent); background: color-mix(in srgb, var(--c-bg-raised) 94%, transparent);
border: 1px solid color-mix(in srgb, var(--border-subtle) 70%, transparent); border: 1px solid color-mix(in srgb, var(--c-border-subtle) 70%, transparent);
box-shadow: 0 32px 64px box-shadow: 0 32px 64px
color-mix( color-mix(
in srgb, in srgb,
var(--shadow-color, rgba(15, 23, 42, 0.55)) 20%, var(--shadow-color, color-mix(in srgb, black 55%, transparent)) 20%,
transparent transparent
); );
max-width: min(46rem, 100%); max-width: min(46rem, 100%);
@@ -22,8 +22,8 @@
gap: 1rem; gap: 1rem;
background: linear-gradient( background: linear-gradient(
145deg, 145deg,
color-mix(in srgb, var(--bg-surface) 96%, transparent), color-mix(in srgb, var(--c-surface) 96%, transparent),
color-mix(in srgb, var(--bg-muted) 70%, transparent) color-mix(in srgb, var(--c-surface-sunken) 70%, transparent)
); );
width: 100%; width: 100%;
max-width: 19rem; max-width: 19rem;
@@ -31,28 +31,20 @@
.tool-panel-mode-prompt__card--sidebar { .tool-panel-mode-prompt__card--sidebar {
border: 1px solid border: 1px solid
color-mix( color-mix(in srgb, var(--c-primary) 18%, var(--c-border-subtle));
in srgb,
var(--accent-primary, var(--mantine-color-blue-6, #228be6)) 18%,
var(--border-subtle)
);
background: linear-gradient( background: linear-gradient(
165deg, 165deg,
color-mix(in srgb, var(--bg-surface) 96%, transparent), color-mix(in srgb, var(--c-surface) 96%, transparent),
color-mix( color-mix(in srgb, var(--c-primary) 8%, transparent)
in srgb,
var(--accent-primary, var(--mantine-color-blue-6, #228be6)) 8%,
transparent
)
); );
} }
.tool-panel-mode-prompt__preview { .tool-panel-mode-prompt__preview {
border-radius: 0.9rem; border-radius: 0.9rem;
border: 1px solid color-mix(in srgb, var(--border-subtle) 70%, transparent); border: 1px solid color-mix(in srgb, var(--c-border-subtle) 70%, transparent);
background: linear-gradient( background: linear-gradient(
135deg, 135deg,
color-mix(in srgb, var(--bg-muted) 82%, transparent), color-mix(in srgb, var(--c-surface-sunken) 82%, transparent),
transparent 75% transparent 75%
); );
padding: 0.75rem; padding: 0.75rem;
@@ -76,54 +68,49 @@
gap: 0.45rem; gap: 0.45rem;
background: linear-gradient( background: linear-gradient(
180deg, 180deg,
color-mix(in srgb, var(--bg-muted) 88%, transparent), color-mix(in srgb, var(--c-surface-sunken) 88%, transparent),
color-mix(in srgb, var(--bg-muted) 72%, transparent) color-mix(in srgb, var(--c-surface-sunken) 72%, transparent)
); );
border: 1px solid color-mix(in srgb, var(--border-subtle) 65%, transparent); border: 1px solid color-mix(in srgb, var(--c-border-subtle) 65%, transparent);
} }
.tool-panel-mode-prompt__sidebar-search { .tool-panel-mode-prompt__sidebar-search {
height: 0.5rem; height: 0.5rem;
border-radius: 0.4rem; border-radius: 0.4rem;
background: color-mix(in srgb, var(--bg-background) 90%, transparent); background: color-mix(in srgb, var(--c-bg) 90%, transparent);
border: 1px solid color-mix(in srgb, var(--border-subtle) 60%, transparent); border: 1px solid color-mix(in srgb, var(--c-border-subtle) 60%, transparent);
} }
.tool-panel-mode-prompt__sidebar-item { .tool-panel-mode-prompt__sidebar-item {
height: 0.55rem; height: 0.55rem;
border-radius: 0.35rem; border-radius: 0.35rem;
background: color-mix( background: color-mix(in srgb, var(--c-primary) 32%, var(--c-surface-sunken));
in srgb,
var(--accent-primary, var(--mantine-color-blue-6, #228be6)) 32%,
var(--bg-muted)
);
} }
.tool-panel-mode-prompt__sidebar-item--muted { .tool-panel-mode-prompt__sidebar-item--muted {
background: color-mix(in srgb, var(--bg-background) 88%, transparent); background: color-mix(in srgb, var(--c-bg) 88%, transparent);
} }
.tool-panel-mode-prompt__workspace { .tool-panel-mode-prompt__workspace {
flex: 1; flex: 1;
border-radius: 0.65rem; border-radius: 0.65rem;
border: 1px solid color-mix(in srgb, var(--border-subtle) 65%, transparent); border: 1px solid color-mix(in srgb, var(--c-border-subtle) 65%, transparent);
padding: 0.5rem; padding: 0.5rem;
display: grid; display: grid;
gap: 0.35rem; gap: 0.35rem;
grid-template-rows: 1.4fr 0.6fr; grid-template-rows: 1.4fr 0.6fr;
background: linear-gradient( background: linear-gradient(
160deg, 160deg,
color-mix(in srgb, var(--bg-background) 94%, transparent), color-mix(in srgb, var(--c-bg) 94%, transparent),
color-mix(in srgb, var(--bg-muted) 68%, transparent) color-mix(in srgb, var(--c-surface-sunken) 68%, transparent)
); );
} }
.tool-panel-mode-prompt__workspace-page { .tool-panel-mode-prompt__workspace-page {
border-radius: 0.45rem; border-radius: 0.45rem;
background: color-mix(in srgb, var(--bg-surface) 96%, transparent); background: color-mix(in srgb, var(--c-surface) 96%, transparent);
border: 1px solid color-mix(in srgb, var(--border-subtle) 55%, transparent); border: 1px solid color-mix(in srgb, var(--c-border-subtle) 55%, transparent);
box-shadow: inset 0 0 0 1px box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-bg) 60%, transparent);
color-mix(in srgb, var(--bg-background) 60%, transparent);
} }
.tool-panel-mode-prompt__workspace-page--secondary { .tool-panel-mode-prompt__workspace-page--secondary {
@@ -151,11 +138,11 @@
.tool-panel-mode-prompt__legacy-card { .tool-panel-mode-prompt__legacy-card {
border-radius: 0.45rem; border-radius: 0.45rem;
border: 1px solid color-mix(in srgb, var(--border-subtle) 55%, transparent); border: 1px solid color-mix(in srgb, var(--c-border-subtle) 55%, transparent);
background: linear-gradient( background: linear-gradient(
150deg, 150deg,
color-mix(in srgb, var(--bg-muted) 88%, transparent), color-mix(in srgb, var(--c-surface-sunken) 88%, transparent),
color-mix(in srgb, var(--bg-background) 76%, transparent) color-mix(in srgb, var(--c-bg) 76%, transparent)
); );
height: 1.2rem; height: 1.2rem;
} }
@@ -185,11 +172,11 @@
.tool-panel-mode-prompt__fullscreen-card { .tool-panel-mode-prompt__fullscreen-card {
border-radius: 0.45rem; border-radius: 0.45rem;
border: 1px solid color-mix(in srgb, var(--border-subtle) 55%, transparent); border: 1px solid color-mix(in srgb, var(--c-border-subtle) 55%, transparent);
background: linear-gradient( background: linear-gradient(
150deg, 150deg,
color-mix(in srgb, var(--bg-muted) 88%, transparent), color-mix(in srgb, var(--c-surface-sunken) 88%, transparent),
color-mix(in srgb, var(--bg-background) 76%, transparent) color-mix(in srgb, var(--c-bg) 76%, transparent)
); );
height: 1.2rem; height: 1.2rem;
} }
@@ -210,20 +197,15 @@
} }
.tool-panel-mode-prompt__action:hover { .tool-panel-mode-prompt__action:hover {
box-shadow: 0 10px 18px box-shadow: 0 10px 18px color-mix(in srgb, var(--c-primary) 25%, transparent);
color-mix(
in srgb,
var(--accent-primary, var(--mantine-color-blue-6, #228be6)) 25%,
transparent
);
} }
.tool-panel-mode-prompt__maybe-later { .tool-panel-mode-prompt__maybe-later {
color: color-mix(in srgb, var(--text-secondary) 90%, var(--text-muted)); color: color-mix(in srgb, var(--c-text-muted) 90%, var(--c-text-subtle));
} }
.tool-panel-mode-prompt__maybe-later:hover { .tool-panel-mode-prompt__maybe-later:hover {
background: color-mix(in srgb, var(--bg-muted) 78%, transparent); background: color-mix(in srgb, var(--c-surface-sunken) 78%, transparent);
} }
@media (max-width: 600px) { @media (max-width: 600px) {
@@ -37,7 +37,7 @@ const HEADER_TEXT_STYLE: React.CSSProperties = {
padding: "0.25rem 0 0.35rem 0.5rem", padding: "0.25rem 0 0.35rem 0.5rem",
textTransform: "uppercase", textTransform: "uppercase",
letterSpacing: "0.06em", letterSpacing: "0.06em",
color: "var(--text-muted)", color: "var(--c-text-subtle)",
}; };
const SCROLLABLE_STYLE: React.CSSProperties = { const SCROLLABLE_STYLE: React.CSSProperties = {
flex: 1, flex: 1,
@@ -50,7 +50,7 @@ const SCROLLABLE_STYLE: React.CSSProperties = {
const CONTAINER_STYLE: React.CSSProperties = { const CONTAINER_STYLE: React.CSSProperties = {
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
background: "var(--bg-toolbar)", background: "var(--c-bg-raised)",
}; };
const toTitleCase = (s: string) => const toTitleCase = (s: string) =>
s.replace( s.replace(
@@ -16,7 +16,7 @@
} }
.containerBorder { .containerBorder {
border: 1px solid var(--border-default, #333); border: 1px solid var(--c-border);
} }
/* Page thumbnail styles */ /* Page thumbnail styles */
@@ -105,8 +105,8 @@
.gridTileSelected, .gridTileSelected,
.gridTileHovered { .gridTileHovered {
border: 2px solid var(--mantine-primary-color-filled, #3b82f6); border: 2px solid var(--c-primary);
background-color: rgba(59, 130, 246, 0.2); background-color: color-mix(in srgb, var(--c-primary) 20%, transparent);
} }
/* Preview header */ /* Preview header */
@@ -116,14 +116,14 @@
.divider { .divider {
height: 1px; height: 1px;
background-color: var(--border-default, #333); background-color: var(--c-border);
margin-bottom: 8px; margin-bottom: 8px;
} }
.previewLabel { .previewLabel {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
color: var(--text-primary); color: var(--c-text);
text-align: center; text-align: center;
} }
@@ -220,7 +220,7 @@ export default function PageNumberPreview({
width: "100%", width: "100%",
aspectRatio: `${(pageSize?.widthPts ?? 595.28) / (pageSize?.heightPts ?? 841.89)} / 1`, aspectRatio: `${(pageSize?.widthPts ?? 595.28) / (pageSize?.heightPts ?? 841.89)} / 1`,
backgroundColor: pageThumbnail ? "white" : "rgba(255,255,255,0.03)", backgroundColor: pageThumbnail ? "white" : "rgba(255,255,255,0.03)",
border: "1px solid var(--border-default, #333)", border: "1px solid var(--c-border, #333)",
overflow: "hidden" as const, overflow: "hidden" as const,
}), }),
[pageSize, pageThumbnail], [pageSize, pageThumbnail],
@@ -16,7 +16,7 @@
} }
.containerBorder { .containerBorder {
border: 1px solid var(--border-default, #333); border: 1px solid var(--c-border);
} }
/* Page thumbnail styles */ /* Page thumbnail styles */
@@ -95,7 +95,7 @@
.gridTileSelected, .gridTileSelected,
.gridTileHovered { .gridTileHovered {
border: 2px solid var(--mantine-primary-color-filled, #3b82f6); border: 2px solid var(--c-primary);
} }
/* Preview header */ /* Preview header */
@@ -105,14 +105,14 @@
.divider { .divider {
height: 1px; height: 1px;
background-color: var(--border-default, #333); background-color: var(--c-border);
margin-bottom: 8px; margin-bottom: 8px;
} }
.previewLabel { .previewLabel {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
color: var(--text-primary); color: var(--c-text);
text-align: center; text-align: center;
} }
@@ -127,7 +127,7 @@
/* Information text container */ /* Information text container */
.informationContainer { .informationContainer {
background-color: var(--information-text-bg); background-color: var(--c-surface);
padding: 2px; padding: 2px;
padding-left: 8px; padding-left: 8px;
padding-right: 8px; padding-right: 8px;
@@ -280,7 +280,7 @@ export function computeStampPreviewStyle(
width: "100%", width: "100%",
aspectRatio: `${(pageSize?.widthPts ?? 595.28) / (pageSize?.heightPts ?? 841.89)} / 1`, aspectRatio: `${(pageSize?.widthPts ?? 595.28) / (pageSize?.heightPts ?? 841.89)} / 1`,
backgroundColor: hasPageThumbnail ? "white" : "rgba(255,255,255,0.03)", backgroundColor: hasPageThumbnail ? "white" : "rgba(255,255,255,0.03)",
border: "1px solid var(--border-default, #333)", border: "1px solid var(--c-border, #333)",
overflow: "hidden", overflow: "hidden",
}, },
item: { item: {
@@ -191,11 +191,9 @@ export default function AutomationEntry({
className="tool-button" className="tool-button"
style={{ style={{
borderRadius: 0, borderRadius: 0,
color: "var(--tools-text-and-icon-color)", color: "var(--c-text)",
overflow: "visible", overflow: "visible",
backgroundColor: shouldShowMenu backgroundColor: shouldShowMenu ? "var(--c-hover)" : undefined,
? "var(--automation-entry-hover-bg)"
: undefined,
}} }}
> >
{buttonContent} {buttonContent}
@@ -153,7 +153,7 @@ export default function AutomationRun({
style={{ style={{
width: 16, width: 16,
height: 16, height: 16,
border: "2px solid #ccc", border: "2px solid var(--c-border)",
borderRadius: "50%", borderRadius: "50%",
}} }}
/> />
@@ -148,7 +148,7 @@ export default function ToolList({
borderTop: "none", borderTop: "none",
borderRadius: borderRadius:
"0 0 var(--mantine-radius-lg) var(--mantine-radius-lg)", "0 0 var(--mantine-radius-lg) var(--mantine-radius-lg)",
backgroundColor: "var(--active-bg)", backgroundColor: "var(--c-active)",
padding: "var(--mantine-spacing-xs)", padding: "var(--mantine-spacing-xs)",
}} }}
> >
@@ -75,7 +75,7 @@ const CertificateTypeSettings = ({
if (!hasAlternativeSources) { if (!hasAlternativeSources) {
return ( return (
<Stack gap="md"> <Stack gap="md">
<div style={{ color: "var(--text-muted)", fontSize: "11px" }}> <div style={{ color: "var(--c-text-subtle)", fontSize: "11px" }}>
{t( {t(
"certSign.source.noOtherSources", "certSign.source.noOtherSources",
"No other certificate sources are available.", "No other certificate sources are available.",
@@ -317,9 +317,9 @@ const SignRequestPanel = ({ data }: SignRequestPanelProps) => {
onClick={handleAddToActiveFiles} onClick={handleAddToActiveFiles}
fullWidth fullWidth
style={{ style={{
backgroundColor: "var(--landing-inner-paper-bg)", backgroundColor: "var(--c-surface-raised)",
color: "var(--btn-open-file)", color: "var(--c-primary)",
border: "1px solid var(--landing-inner-paper-border)", border: "1px solid var(--c-border)",
}} }}
> >
{t("certSign.collab.signRequest.addToFiles", "Add to Active Files")} {t("certSign.collab.signRequest.addToFiles", "Add to Active Files")}
@@ -5,19 +5,14 @@
.compare-dropdown-sticky { .compare-dropdown-sticky {
position: sticky; position: sticky;
z-index: 2; z-index: 2;
background: var(--compare-page-label-bg); background: var(--c-surface-sunken);
color: var(--compare-page-label-fg); color: var(--compare-page-label-fg);
font-size: 0.75rem; font-size: 0.75rem;
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;
border-bottom: 1px solid var(--border-subtle); border-bottom: 1px solid var(--c-border-subtle);
pointer-events: none; pointer-events: none;
} }
[data-mantine-color-scheme="dark"] .compare-dropdown-sticky {
background: var(--compare-page-label-bg);
color: var(--compare-page-label-fg);
border-bottom: 1px solid var(--border-default);
}
.compare-workbench { .compare-workbench {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -91,9 +86,9 @@
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 10; z-index: 10;
background: var(--bg-toolbar); background: var(--c-bg-raised);
backdrop-filter: blur(8px); backdrop-filter: blur(8px);
border-bottom: 1px solid var(--border-default); border-bottom: 1px solid var(--c-border);
padding: 0.5rem; padding: 0.5rem;
margin: -0.5rem -0.5rem 0.5rem -0.5rem; margin: -0.5rem -0.5rem 0.5rem -0.5rem;
} }
@@ -164,21 +159,13 @@
margin: 0 !important; margin: 0 !important;
border-top-left-radius: 8px !important; border-top-left-radius: 8px !important;
border-top-right-radius: 8px !important; border-top-right-radius: 8px !important;
} } /* Style the dropdown container */
.compare-changes-select .mantine-Combobox-dropdown,
/* Style the dropdown container */
.compare-changes-select .mantine-Combobox-dropdown {
border: 1px solid var(--border-subtle) !important;
border-radius: 8px !important;
box-shadow: var(--shadow-md) !important;
background-color: var(--bg-surface) !important;
}
.compare-changes-select--comparison .mantine-Combobox-dropdown { .compare-changes-select--comparison .mantine-Combobox-dropdown {
border: 1px solid var(--border-subtle) !important; border: 1px solid var(--c-border-subtle) !important;
border-radius: 8px !important; border-radius: 8px !important;
box-shadow: var(--shadow-md) !important; box-shadow: var(--shadow-md) !important;
background-color: var(--bg-surface) !important; background-color: var(--c-surface) !important;
} }
/* Custom scrollbar for ScrollArea */ /* Custom scrollbar for ScrollArea */
@@ -187,18 +174,18 @@
} }
.compare-changes-select .mantine-ScrollArea-viewport::-webkit-scrollbar-track { .compare-changes-select .mantine-ScrollArea-viewport::-webkit-scrollbar-track {
background: var(--bg-muted) !important; background: var(--c-surface-sunken) !important;
border-radius: 3px !important; border-radius: 3px !important;
} }
.compare-changes-select .mantine-ScrollArea-viewport::-webkit-scrollbar-thumb { .compare-changes-select .mantine-ScrollArea-viewport::-webkit-scrollbar-thumb {
background: var(--border-strong) !important; background: var(--c-border-strong) !important;
border-radius: 3px !important; border-radius: 3px !important;
} }
.compare-changes-select .compare-changes-select
.mantine-ScrollArea-viewport::-webkit-scrollbar-thumb:hover { .mantine-ScrollArea-viewport::-webkit-scrollbar-thumb:hover {
background: var(--text-muted) !important; background: var(--c-text-subtle) !important;
} }
.compare-changes-select--comparison .compare-changes-select--comparison
@@ -208,27 +195,21 @@
.compare-changes-select--comparison .compare-changes-select--comparison
.mantine-ScrollArea-viewport::-webkit-scrollbar-track { .mantine-ScrollArea-viewport::-webkit-scrollbar-track {
background: var(--bg-muted) !important; background: var(--c-surface-sunken) !important;
border-radius: 3px !important; border-radius: 3px !important;
} }
.compare-changes-select--comparison .compare-changes-select--comparison
.mantine-ScrollArea-viewport::-webkit-scrollbar-thumb { .mantine-ScrollArea-viewport::-webkit-scrollbar-thumb {
background: var(--border-strong) !important; background: var(--c-border-strong) !important;
border-radius: 3px !important; border-radius: 3px !important;
} }
.compare-changes-select--comparison .compare-changes-select--comparison
.mantine-ScrollArea-viewport::-webkit-scrollbar-thumb:hover { .mantine-ScrollArea-viewport::-webkit-scrollbar-thumb:hover {
background: var(--text-muted) !important; background: var(--c-text-subtle) !important;
} } /* Style the dropdown options */
.compare-changes-select .mantine-Combobox-option,
/* Style the dropdown options */
.compare-changes-select .mantine-Combobox-option {
font-size: 0.875rem !important;
padding: 8px 12px !important;
}
.compare-changes-select--comparison .mantine-Combobox-option { .compare-changes-select--comparison .mantine-Combobox-option {
font-size: 0.875rem !important; font-size: 0.875rem !important;
padding: 8px 12px !important; padding: 8px 12px !important;
@@ -240,27 +221,16 @@
.compare-changes-select--comparison .mantine-Combobox-option:hover { .compare-changes-select--comparison .mantine-Combobox-option:hover {
background-color: var(--spdf-compare-added-badge-bg) !important; background-color: var(--spdf-compare-added-badge-bg) !important;
} } /* Style the search input */
.compare-changes-select .mantine-Combobox-search,
/* Style the search input */
.compare-changes-select .mantine-Combobox-search {
font-size: 0.875rem !important;
padding: 8px 12px !important;
border-bottom: 1px solid var(--border-subtle) !important;
}
.compare-changes-select--comparison .mantine-Combobox-search { .compare-changes-select--comparison .mantine-Combobox-search {
font-size: 0.875rem !important; font-size: 0.875rem !important;
padding: 8px 12px !important; padding: 8px 12px !important;
border-bottom: 1px solid var(--border-subtle) !important; border-bottom: 1px solid var(--c-border-subtle) !important;
} }
.compare-changes-select .mantine-Combobox-search::placeholder,
.compare-changes-select .mantine-Combobox-search::placeholder {
color: var(--text-muted) !important;
}
.compare-changes-select--comparison .mantine-Combobox-search::placeholder { .compare-changes-select--comparison .mantine-Combobox-search::placeholder {
color: var(--text-muted) !important; color: var(--c-text-subtle) !important;
} }
/* Style the chevron - ensure proper coloring */ /* Style the chevron - ensure proper coloring */
@@ -273,29 +243,49 @@
/* Flash/pulse highlight for navigated change */ /* Flash/pulse highlight for navigated change */
@keyframes compare-flash { @keyframes compare-flash {
0% { 0% {
outline: 4px solid rgba(255, 235, 59, 0); outline: 4px solid color-mix(in srgb, var(--c-highlight) 0%, transparent);
box-shadow: 0 0 0 rgba(255, 235, 59, 0); box-shadow: 0 0 0 color-mix(in srgb, var(--c-highlight) 0%, transparent);
background-color: rgba(255, 235, 59, 0.2) !important; background-color: color-mix(
in srgb,
var(--c-highlight) 20%,
transparent
) !important;
} }
25% { 25% {
outline: 4px solid rgba(255, 235, 59, 1); outline: 4px solid color-mix(in srgb, var(--c-highlight) 100%, transparent);
box-shadow: 0 0 20px rgba(255, 235, 59, 0.8); box-shadow: 0 0 20px color-mix(in srgb, var(--c-highlight) 80%, transparent);
background-color: rgba(255, 235, 59, 0.4) !important; background-color: color-mix(
in srgb,
var(--c-highlight) 40%,
transparent
) !important;
} }
50% { 50% {
outline: 4px solid rgba(255, 235, 59, 1); outline: 4px solid color-mix(in srgb, var(--c-highlight) 100%, transparent);
box-shadow: 0 0 30px rgba(255, 235, 59, 0.9); box-shadow: 0 0 30px color-mix(in srgb, var(--c-highlight) 90%, transparent);
background-color: rgba(255, 235, 59, 0.5) !important; background-color: color-mix(
in srgb,
var(--c-highlight) 50%,
transparent
) !important;
} }
75% { 75% {
outline: 4px solid rgba(255, 235, 59, 0.8); outline: 4px solid color-mix(in srgb, var(--c-highlight) 80%, transparent);
box-shadow: 0 0 15px rgba(255, 235, 59, 0.6); box-shadow: 0 0 15px color-mix(in srgb, var(--c-highlight) 60%, transparent);
background-color: rgba(255, 235, 59, 0.3) !important; background-color: color-mix(
in srgb,
var(--c-highlight) 30%,
transparent
) !important;
} }
100% { 100% {
outline: 4px solid rgba(255, 235, 59, 0); outline: 4px solid color-mix(in srgb, var(--c-highlight) 0%, transparent);
box-shadow: 0 0 0 rgba(255, 235, 59, 0); box-shadow: 0 0 0 color-mix(in srgb, var(--c-highlight) 0%, transparent);
background-color: rgba(255, 235, 59, 0) !important; background-color: color-mix(
in srgb,
var(--c-highlight) 0%,
transparent
) !important;
} }
} }
@@ -304,14 +294,18 @@
z-index: 1000; z-index: 1000;
position: relative; position: relative;
/* Bonus: temporarily override red/green to yellow during flash for clarity */ /* Bonus: temporarily override red/green to yellow during flash for clarity */
background-color: rgba(255, 235, 59, 0.5) !important; background-color: color-mix(
in srgb,
var(--c-highlight) 50%,
transparent
) !important;
} }
/* Union overlay for group flash */ /* Union overlay for group flash */
.compare-diff-flash-overlay { .compare-diff-flash-overlay {
animation: compare-flash 1.5s ease-in-out 1; animation: compare-flash 1.5s ease-in-out 1;
z-index: 999; z-index: 999;
background-color: rgba(255, 235, 59, 0.4); background-color: color-mix(in srgb, var(--c-highlight) 40%, transparent);
pointer-events: none; pointer-events: none;
border-radius: 2px; border-radius: 2px;
} }
@@ -328,7 +322,7 @@
width: 0.75rem; width: 0.75rem;
height: 0.75rem; height: 0.75rem;
border-radius: 999px; border-radius: 999px;
border: 1px solid rgba(15, 23, 42, 0.15); border: 1px solid var(--c-border);
} }
.compare-summary__stats { .compare-summary__stats {
@@ -343,10 +337,10 @@
} }
.compare-summary__segment { .compare-summary__segment {
border: 1px solid var(--mantine-color-gray-3); border: 1px solid var(--c-border);
border-radius: 0.5rem; border-radius: 0.5rem;
padding: 0.75rem; padding: 0.75rem;
background-color: var(--mantine-color-gray-0); background-color: var(--c-surface);
} }
.compare-diff-page { .compare-diff-page {
@@ -357,10 +351,10 @@
.compare-diff-page__canvas { .compare-diff-page__canvas {
position: relative; position: relative;
border: 1px solid var(--border-strong); border: 1px solid var(--c-border-strong);
border-radius: 0.75rem; border-radius: 0.75rem;
overflow: hidden; overflow: hidden;
background-color: var(--bg-surface); background-color: var(--c-surface);
width: 100%; width: 100%;
} }
@@ -381,7 +375,7 @@
margin-right: auto; margin-right: auto;
max-width: 100%; max-width: 100%;
background-color: #fff; /* ensure stable white backing during load */ background-color: #fff; /* ensure stable white backing during load */
border: 1px solid var(--border-subtle); border: 1px solid var(--c-border-subtle);
will-change: transform; will-change: transform;
} }
@@ -403,7 +397,7 @@
display: inline-block; display: inline-block;
padding: 2px 8px; padding: 2px 8px;
border-radius: 8px; border-radius: 8px;
background-color: var(--compare-page-label-bg); background-color: var(--c-surface-sunken);
color: var(--compare-page-label-fg); color: var(--compare-page-label-fg);
} }
@@ -432,7 +426,7 @@
} }
.compare-dropdown-option__page { .compare-dropdown-option__page {
font-size: 0.7rem; font-size: 0.7rem;
color: var(--text-muted); color: var(--c-text-subtle);
} }
.compare-dropdown-option__text { .compare-dropdown-option__text {
display: -webkit-box; display: -webkit-box;
@@ -446,11 +440,11 @@
/* Non-sticky in-flow group headers; sticky handled by floating header */ /* Non-sticky in-flow group headers; sticky handled by floating header */
.compare-dropdown-group { .compare-dropdown-group {
position: static; position: static;
background: var(--compare-page-label-bg); background: var(--c-surface-sunken);
color: var(--compare-page-label-fg); color: var(--compare-page-label-fg);
font-size: 0.75rem; font-size: 0.75rem;
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;
border-bottom: 1px solid var(--border-subtle); border-bottom: 1px solid var(--c-border-subtle);
} }
.compare-dropdown-group.compare-dropdown-group--hidden { .compare-dropdown-group.compare-dropdown-group--hidden {
@@ -461,15 +455,9 @@
overflow: hidden; overflow: hidden;
} }
[data-mantine-color-scheme="dark"] .compare-dropdown-group {
background: var(--compare-page-label-bg);
color: var(--compare-page-label-fg);
border-bottom: 1px solid var(--border-default);
}
/* Light grey rendering flag next to page labels in the dropdown */ /* Light grey rendering flag next to page labels in the dropdown */
.compare-dropdown-rendering-flag { .compare-dropdown-rendering-flag {
color: var(--text-muted); color: var(--c-text-subtle);
margin-left: 0.25rem; margin-left: 0.25rem;
} }
@@ -489,7 +477,7 @@
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 2; z-index: 2;
background: var(--bg-background); background: var(--c-bg);
padding: 0.25rem 0; padding: 0.25rem 0;
} }
@@ -550,7 +538,7 @@
padding-bottom: 32px; padding-bottom: 32px;
} }
.compare-pixel-page { .compare-pixel-page {
border: 1px solid var(--mantine-color-default-border, #dee2e6); border: 1px solid var(--mantine-color-default-border, var(--c-border));
border-radius: 8px; border-radius: 8px;
padding: 12px; padding: 12px;
background: var(--mantine-color-body, #fff); background: var(--mantine-color-body, #fff);
@@ -568,13 +556,13 @@
} }
.compare-pixel-triptych figure img { .compare-pixel-triptych figure img {
display: block; display: block;
border: 1px solid var(--mantine-color-default-border, #dee2e6); border: 1px solid var(--mantine-color-default-border, var(--c-border));
background: #fff; background: #fff;
} }
.compare-pixel-triptych figcaption { .compare-pixel-triptych figcaption {
font-size: 11px; font-size: 11px;
text-align: center; text-align: center;
color: var(--mantine-color-dimmed, #868e96); color: var(--mantine-color-dimmed, var(--c-text-muted));
} }
.compare-pixel-overlay { .compare-pixel-overlay {
position: relative; position: relative;
@@ -583,7 +571,7 @@
.compare-pixel-overlay-img { .compare-pixel-overlay-img {
display: block; display: block;
width: 100%; width: 100%;
border: 1px solid var(--mantine-color-default-border, #dee2e6); border: 1px solid var(--mantine-color-default-border, var(--c-border));
} }
.compare-pixel-overlay-top { .compare-pixel-overlay-top {
position: absolute; position: absolute;
@@ -104,7 +104,7 @@ const GroupedFormatDropdown = ({
cursor: disabled ? "not-allowed" : "pointer", cursor: disabled ? "not-allowed" : "pointer",
width: "100%", width: "100%",
color: disabled color: disabled
? "var(--dropdown-trigger-text-disabled)" ? "var(--c-text-subtle)"
: "var(--dropdown-trigger-text)", : "var(--dropdown-trigger-text)",
}} }}
> >
@@ -219,8 +219,9 @@ export default function BookmarkEditor({
withBorder withBorder
p="md" p="md"
style={{ style={{
borderColor: "var(--border-default)", borderColor: "var(--c-border)",
background: level === 0 ? "var(--bg-surface)" : "var(--bg-muted)", background:
level === 0 ? "var(--c-surface)" : "var(--c-surface-sunken)",
}} }}
> >
<Stack gap="sm"> <Stack gap="sm">
@@ -380,7 +381,7 @@ export default function BookmarkEditor({
<Stack <Stack
gap="sm" gap="sm"
pl="lg" pl="lg"
style={{ borderLeft: "1px solid var(--border-default)" }} style={{ borderLeft: "1px solid var(--c-border)" }}
> >
{bookmark.children.map((child) => ( {bookmark.children.map((child) => (
<Fragment key={child.id}> <Fragment key={child.id}>
@@ -100,7 +100,7 @@ const EditTableOfContentsWorkbenchView = ({
width: "100%", width: "100%",
height: "100%", height: "100%",
overflowY: "auto", overflowY: "auto",
background: "var(--bg-raised)", background: "var(--c-surface-raised)",
}} }}
> >
<Stack gap="xl" maw={1200} mx="auto"> <Stack gap="xl" maw={1200} mx="auto">
@@ -121,8 +121,8 @@ const EditTableOfContentsWorkbenchView = ({
radius="md" radius="md"
p="xl" p="xl"
style={{ style={{
backgroundColor: "var(--bg-surface)", backgroundColor: "var(--c-surface)",
borderColor: "var(--border-default)", borderColor: "var(--c-border)",
boxShadow: "var(--shadow-md)", boxShadow: "var(--shadow-md)",
}} }}
> >
@@ -167,8 +167,8 @@ const EditTableOfContentsWorkbenchView = ({
radius="md" radius="md"
p="xl" p="xl"
style={{ style={{
backgroundColor: "var(--bg-surface)", backgroundColor: "var(--c-surface)",
borderColor: "var(--border-default)", borderColor: "var(--c-border)",
boxShadow: "var(--shadow-md)", boxShadow: "var(--shadow-md)",
}} }}
> >
@@ -125,8 +125,8 @@ const PerPageSection: React.FC<PerPageSectionProps> = ({
<Accordion.Panel> <Accordion.Panel>
<div <div
style={{ style={{
backgroundColor: "var(--bg-raised)", backgroundColor: "var(--c-surface-raised)",
color: "var(--text-primary)", color: "var(--c-text)",
borderRadius: 8, borderRadius: 8,
padding: 12, padding: 12,
}} }}
@@ -32,8 +32,8 @@ const ScrollableCodeBlock: React.FC<ScrollableCodeBlockProps> = ({
block block
style={{ style={{
whiteSpace: "pre-wrap", whiteSpace: "pre-wrap",
backgroundColor: "var(--bg-raised)", backgroundColor: "var(--c-surface-raised)",
color: "var(--text-primary)", color: "var(--c-text)",
maxHeight, maxHeight,
overflowY: "auto", overflowY: "auto",
}} }}
@@ -5,7 +5,7 @@ type AccordionStyles = Partial<Record<AccordionStylesNames, CSSProperties>>;
export const pdfInfoAccordionStyles: AccordionStyles = { export const pdfInfoAccordionStyles: AccordionStyles = {
item: { item: {
backgroundColor: "var(--accordion-item-bg)", backgroundColor: "var(--c-surface-raised)",
}, },
control: { control: {
backgroundColor: "transparent", backgroundColor: "transparent",
@@ -5,9 +5,9 @@
flex-direction: row; flex-direction: row;
align-items: center; /* Center align items vertically */ align-items: center; /* Center align items vertically */
height: 32px; height: 32px;
border: 1px solid var(--border-default); border: 1px solid var(--c-border);
background-color: var(--mantine-color-white); /* Use Mantine color variable */ background-color: var(--c-input-bg);
color: var(--text-secondary); color: var(--c-text-muted);
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
padding: 4px 8px; padding: 4px 8px;
font-size: 13px; font-size: 13px;
@@ -15,25 +15,9 @@
transition: all 0.2s ease; transition: all 0.2s ease;
} }
/* Dark mode background */
[data-mantine-color-scheme="dark"] .languagePicker {
background-color: var(
--mantine-color-dark-6
); /* Use Mantine dark color instead of hardcoded */
}
.languagePicker:hover { .languagePicker:hover {
border-color: var(--border-strong); border-color: var(--c-border-strong);
background-color: var( background-color: var(--c-hover);
--mantine-color-gray-0
); /* Light gray on hover for light mode */
}
/* Dark mode hover */
[data-mantine-color-scheme="dark"] .languagePicker:hover {
background-color: var(
--mantine-color-dark-5
); /* Use Mantine color variable */
} }
.languagePicker:disabled { .languagePicker:disabled {
@@ -43,30 +27,25 @@
.languagePickerIcon { .languagePickerIcon {
font-size: 16px; font-size: 16px;
color: var(--text-muted); color: var(--c-text-subtle);
margin-left: auto; margin-left: auto;
display: flex; display: flex;
align-items: center; /* Center the icon vertically */ align-items: center; /* Center the icon vertically */
} }
.languagePickerDropdown { .languagePickerDropdown {
background-color: var(--mantine-color-white); /* Use Mantine color variable */ background-color: var(--c-surface);
border: 1px solid var(--border-default); border: 1px solid var(--c-border);
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
padding: 4px; padding: 4px;
} }
/* Dark mode dropdown background */
[data-mantine-color-scheme="dark"] .languagePickerDropdown {
background-color: var(--mantine-color-dark-6);
}
.languagePickerOption { .languagePickerOption {
padding: 6px 10px; padding: 6px 10px;
cursor: pointer; cursor: pointer;
border-radius: var(--radius-xs); border-radius: var(--radius-xs);
font-size: 13px; font-size: 13px;
color: var(--text-primary); color: var(--c-text);
transition: background-color 0.2s ease; transition: background-color 0.2s ease;
} }
@@ -81,14 +60,7 @@
} }
.languagePickerOption:hover { .languagePickerOption:hover {
background-color: var( background-color: var(--c-hover);
--mantine-color-gray-0
); /* Light gray on hover for light mode */
}
/* Dark mode option hover */
[data-mantine-color-scheme="dark"] .languagePickerOption:hover {
background-color: var(--mantine-color-dark-5);
} }
/* Additional helper classes for the component */ /* Additional helper classes for the component */
@@ -110,7 +82,7 @@
.languagePickerScrollArea { .languagePickerScrollArea {
max-height: 180px; max-height: 180px;
border-bottom: 1px solid var(--border-default); border-bottom: 1px solid var(--c-border);
padding-bottom: 8px; padding-bottom: 8px;
} }
@@ -121,12 +93,7 @@
} }
.languagePickerLink { .languagePickerLink {
color: var(--mantine-color-blue-6); color: var(--c-accent-fg);
text-decoration: underline; text-decoration: underline;
cursor: pointer; cursor: pointer;
} }
/* Dark mode link */
[data-mantine-color-scheme="dark"] .languagePickerLink {
color: var(--mantine-color-blue-4);
}
@@ -158,7 +158,7 @@ const LanguagePicker: React.FC<LanguagePickerProps> = ({
<Text <Text
size="xs" size="xs"
style={{ style={{
color: "#3b82f6", color: "var(--c-primary)",
cursor: "pointer", cursor: "pointer",
textDecoration: "underline", textDecoration: "underline",
textAlign: "center", textAlign: "center",

Some files were not shown because too many files have changed in this diff Show More