diff --git a/ui/index.html b/ui/index.html
index ebb774a7b02b..1c62d32cf83e 100644
--- a/ui/index.html
+++ b/ui/index.html
@@ -62,10 +62,10 @@
? "light"
: "dark";
document.documentElement.setAttribute("data-theme", resolved);
- document.documentElement.setAttribute(
- "data-theme-mode",
- resolved.includes("light") ? "light" : "dark",
- );
+ var resolvedMode = resolved.includes("light") ? "light" : "dark";
+ document.documentElement.setAttribute("data-theme-mode", resolvedMode);
+ // Carapace CSS selects on [data-theme-resolved]; keep in lockstep.
+ document.documentElement.setAttribute("data-theme-resolved", resolvedMode);
} catch (e) {}
})();
diff --git a/ui/src/app/bootstrap.ts b/ui/src/app/bootstrap.ts
index f187b8d7994e..928b8cde0bbf 100644
--- a/ui/src/app/bootstrap.ts
+++ b/ui/src/app/bootstrap.ts
@@ -76,7 +76,7 @@ function normalizeInitialApplicationLocation(
};
}
-function applyStartupPresentation(settings: ReturnType): void {
+function applyThemePresentation(settings: ReturnType): void {
if (typeof document === "undefined") {
return;
}
@@ -84,6 +84,9 @@ function applyStartupPresentation(settings: ReturnType): vo
const resolvedTheme = resolveTheme(settings.theme, settings.themeMode);
root.dataset.theme = resolvedTheme;
root.dataset.themeMode = resolvedTheme.endsWith("light") ? "light" : "dark";
+ // Carapace CSS (openclaw/carapace) selects on [data-theme-resolved]; keep it
+ // in lockstep with data-theme-mode so its stylesheets work unmodified here.
+ root.dataset.themeResolved = root.dataset.themeMode;
root.classList.toggle("wa-light", root.dataset.themeMode === "light");
root.classList.toggle("wa-dark", root.dataset.themeMode === "dark");
root.style.colorScheme = root.dataset.themeMode;
@@ -99,7 +102,7 @@ function createApplicationTheme(
const listeners = new Set<() => void>();
const publish = () => {
- applyStartupPresentation(settings);
+ applyThemePresentation(settings);
for (const listener of listeners) {
listener();
}
@@ -328,7 +331,7 @@ export function bootstrapApplication(): ApplicationRuntime {
const webPush = createWebPushCapability(gateway);
const skillWorkshopRevision = createSkillWorkshopRevisionHandoff();
const initialUserMessage = createInitialUserMessageHandoff();
- applyStartupPresentation(settings);
+ applyThemePresentation(settings);
const router = createApplicationRouter();
let pendingGatewayConnection =
startup.pendingGatewayUrl !== null
diff --git a/ui/src/components/mcp-app-theme.test.ts b/ui/src/components/mcp-app-theme.test.ts
index e2b7a9165342..628a12197e37 100644
--- a/ui/src/components/mcp-app-theme.test.ts
+++ b/ui/src/components/mcp-app-theme.test.ts
@@ -66,11 +66,13 @@ describe("collectMcpAppStyleVariables", () => {
);
// Font requests are limited to resource domains the app declares, so a
- // host-led webfont resolves to an arbitrary system face rather than
- // failing visibly. Apps own their sans stack until Control UI can supply
- // a sandbox-safe one.
- expect(variables).not.toHaveProperty("--font-sans");
- expect(variables?.["--font-mono"]).toContain("monospace");
+ // host-led brand face resolves to an arbitrary system face rather than
+ // failing visibly. The published stacks are the carapace embed stacks:
+ // system resolvable, independent of the host's own font tokens.
+ expect(variables?.["--font-sans"]).toMatch(/^system-ui,/);
+ expect(variables?.["--font-sans"]).not.toContain("Inter");
+ expect(variables?.["--font-mono"]).toMatch(/^ui-monospace,/);
+ expect(variables?.["--font-mono"]).not.toContain("JetBrains");
});
it("publishes trimmed, non-empty values", () => {
diff --git a/ui/src/components/mcp-app-theme.ts b/ui/src/components/mcp-app-theme.ts
index f0032cad4f2c..527ab340c3cf 100644
--- a/ui/src/components/mcp-app-theme.ts
+++ b/ui/src/components/mcp-app-theme.ts
@@ -33,17 +33,6 @@ const HOST_TOKEN_SOURCES = {
"--color-border-inverse": "--bg",
"--color-ring-primary": "--ring",
- /*
- * Only the monospace stack is published. Control UI's body font leads with a
- * webfont, and an embedded app cannot load it: the sandbox policy allows
- * font requests only from resource domains the app itself declares. Sending
- * it would resolve to an arbitrary system face instead of failing visibly.
- * The monospace stack degrades correctly because its fallbacks are system
- * faces. Apps supply their own sans stack until Control UI adopts the
- * carapace embed tokens, which define a sandbox-safe one.
- */
- "--font-mono": "--mono",
-
"--font-text-xs-size": "--control-ui-text-xs",
"--font-text-sm-size": "--control-ui-text-sm",
"--font-text-md-size": "--control-ui-text-md",
@@ -61,13 +50,27 @@ const HOST_TOKEN_SOURCES = {
"--shadow-lg": "--shadow-lg",
} as const;
-/** Values with no Control UI source, fixed by the specification's own scale. */
+/**
+ * Values with no Control UI source, fixed by the specification's own scale or
+ * the carapace embed contract.
+ *
+ * The font stacks are the carapace embed stacks (`--oc-font-embed-sans` /
+ * `--oc-font-embed-mono`), sent in place of Control UI's own font tokens. The
+ * sandbox policy allows font requests only from resource domains the app
+ * itself declares, so a stack leading with a brand face would silently
+ * resolve to an arbitrary system font; every family here is system
+ * resolvable. Keep them byte-identical to carapace `candidate/embed.css`.
+ */
const STATIC_VARIABLES = {
"--border-width-regular": "1px",
"--font-weight-normal": "400",
"--font-weight-medium": "500",
"--font-weight-semibold": "600",
"--font-weight-bold": "700",
+ "--font-sans":
+ 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
+ "--font-mono":
+ 'ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace',
} as const;
type StyleVariableKey = keyof typeof HOST_TOKEN_SOURCES | keyof typeof STATIC_VARIABLES;
diff --git a/ui/src/styles/board.css b/ui/src/styles/board.css
index 32469bba6190..3eda4d70035c 100644
--- a/ui/src/styles/board.css
+++ b/ui/src/styles/board.css
@@ -5,8 +5,8 @@ openclaw-board-view {
}
.board-view {
- --board-line: color-mix(in srgb, var(--border, #2c313a) 84%, transparent);
- --board-surface: color-mix(in srgb, var(--panel, #171a20) 94%, transparent);
+ --board-line: color-mix(in srgb, var(--border) 84%, transparent);
+ --board-surface: color-mix(in srgb, var(--panel) 94%, transparent);
display: grid;
gap: 12px;
min-width: 0;
@@ -14,10 +14,10 @@ openclaw-board-view {
}
.board-view__error {
- background: color-mix(in srgb, var(--danger, #ff6b6b) 8%, var(--panel, #171a20));
- border: 1px solid color-mix(in srgb, var(--danger, #ff6b6b) 42%, transparent);
+ background: color-mix(in srgb, var(--danger) 8%, var(--panel));
+ border: 1px solid color-mix(in srgb, var(--danger) 42%, transparent);
border-radius: 9px;
- color: var(--danger, #ff6b6b);
+ color: var(--danger);
font-size: 12px;
padding: 9px 12px;
}
@@ -51,7 +51,7 @@ openclaw-board-view {
}
.board-tabs__tab {
- color: var(--muted, #8a919e);
+ color: var(--muted);
flex: 0 0 auto;
}
@@ -68,18 +68,18 @@ openclaw-board-view {
.board-tabs__tab:hover::part(base),
.board-tabs__tab:focus-visible::part(base) {
- background: color-mix(in srgb, var(--text, #d7dae0) 6%, transparent);
- color: var(--text, #d7dae0);
+ background: color-mix(in srgb, var(--text) 6%, transparent);
+ color: var(--text);
}
.board-tabs__tab--active::part(base) {
- border-bottom-color: var(--accent, #ff5c5c);
- color: var(--text, #d7dae0);
+ border-bottom-color: var(--accent);
+ color: var(--text);
}
.board-tabs__tab--drop::part(base) {
- background: color-mix(in srgb, var(--accent, #ff5c5c) 14%, transparent);
- box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent, #ff5c5c) 70%, transparent);
+ background: color-mix(in srgb, var(--accent) 14%, transparent);
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 70%, transparent);
}
.board-tabs__overflow,
@@ -94,7 +94,7 @@ openclaw-board-view {
background: transparent;
border: 0;
border-radius: 7px;
- color: var(--muted, #8a919e);
+ color: var(--muted);
cursor: pointer;
display: inline-flex;
justify-content: center;
@@ -108,13 +108,13 @@ openclaw-board-view {
.board-tabs__overflow-trigger:hover,
.board-widget__menu-trigger:hover {
- background: color-mix(in srgb, var(--text, #d7dae0) 10%, transparent);
- color: var(--text, #d7dae0);
+ background: color-mix(in srgb, var(--text) 10%, transparent);
+ color: var(--text);
}
.board-tabs__overflow::part(menu),
.board-widget__menu::part(menu) {
- background: var(--panel, #171a20);
+ background: var(--panel);
border: 1px solid var(--board-line);
border-radius: 10px;
box-shadow: 0 18px 48px rgb(0 0 0 / 32%);
@@ -136,7 +136,7 @@ openclaw-board-view {
}
.board-grid__append-zone {
- border-top: 1px dashed color-mix(in srgb, var(--accent, #ff5c5c) 48%, transparent);
+ border-top: 1px dashed color-mix(in srgb, var(--accent) 48%, transparent);
bottom: -42px;
height: 38px;
left: 0;
@@ -167,12 +167,12 @@ openclaw-board-widget-cell {
}
.board-widget:focus-visible {
- box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent, #ff5c5c) 70%, transparent);
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 70%, transparent);
outline: none;
}
.board-widget--dragging {
- border-color: color-mix(in srgb, var(--accent, #ff5c5c) 72%, transparent);
+ border-color: color-mix(in srgb, var(--accent) 72%, transparent);
box-shadow: 0 16px 36px rgb(0 0 0 / 28%);
opacity: 0.88;
transform: scale(0.995);
@@ -181,7 +181,7 @@ openclaw-board-widget-cell {
.board-widget__bar {
align-items: center;
- background: color-mix(in srgb, var(--text, #d7dae0) 3%, transparent);
+ background: color-mix(in srgb, var(--text) 3%, transparent);
border-bottom: 1px solid var(--board-line);
border-radius: 11px 11px 0 0;
display: flex;
@@ -194,7 +194,7 @@ openclaw-board-widget-cell {
.board-widget__resize-handle {
background: transparent;
border: 0;
- color: var(--muted, #8a919e);
+ color: var(--muted);
}
.board-widget__drag-handle {
@@ -211,12 +211,12 @@ openclaw-board-widget-cell {
}
.board-widget__drag-handle:hover {
- background: color-mix(in srgb, var(--text, #d7dae0) 9%, transparent);
- color: var(--text, #d7dae0);
+ background: color-mix(in srgb, var(--text) 9%, transparent);
+ color: var(--text);
}
.board-widget__title {
- color: var(--text, #d7dae0);
+ color: var(--text);
font-size: 12.5px;
font-weight: 590;
min-width: 0;
@@ -228,7 +228,7 @@ openclaw-board-widget-cell {
.board-widget__kind {
border: 1px solid var(--board-line);
border-radius: 999px;
- color: var(--muted, #8a919e);
+ color: var(--muted);
font-size: 8px;
letter-spacing: 0.08em;
line-height: 15px;
@@ -248,7 +248,7 @@ openclaw-board-widget-cell {
}
.board-widget__menu-heading {
- color: var(--muted, #8a919e);
+ color: var(--muted);
font-size: 9px;
letter-spacing: 0.08em;
padding: 7px 9px 3px;
@@ -256,7 +256,7 @@ openclaw-board-widget-cell {
}
.board-widget__menu-empty {
- color: var(--muted, #8a919e);
+ color: var(--muted);
font-size: 11px;
padding: 5px 9px;
}
@@ -271,7 +271,7 @@ openclaw-board-widget-cell {
}
.board-widget__menu-danger {
- color: var(--danger, #ff6b6b);
+ color: var(--danger);
}
.board-widget__body {
@@ -324,9 +324,9 @@ openclaw-board-widget-cell {
}
.observer-widget__current {
- background: color-mix(in srgb, var(--text, #d7dae0) 4%, transparent);
+ background: color-mix(in srgb, var(--text) 4%, transparent);
border: 1px solid var(--board-line);
- border-left: 3px solid var(--muted, #8a919e);
+ border-left: 3px solid var(--muted);
border-radius: 9px;
display: grid;
gap: 8px;
@@ -336,17 +336,17 @@ openclaw-board-widget-cell {
.observer-widget__current[data-health="on-track"],
.observer-widget__current[data-health="done"],
.observer-widget__current[data-health="wrapping-up"] {
- border-left-color: var(--success, #45c486);
+ border-left-color: var(--ok);
}
.observer-widget__current[data-health="grinding"] {
- border-left-color: var(--warning, #e7b85c);
+ border-left-color: var(--warn);
}
.observer-widget__current[data-health="stuck"],
.observer-widget__current[data-health="waiting-on-user"],
.observer-widget__current[data-health="failed"] {
- border-left-color: var(--danger, #ff6b6b);
+ border-left-color: var(--danger);
}
.observer-widget__current-heading {
@@ -365,20 +365,20 @@ openclaw-board-widget-cell {
.observer-widget__eyebrow,
.observer-widget__timeline-title,
.observer-widget__run {
- color: var(--muted, #8a919e);
+ color: var(--muted);
font-size: 9px;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.observer-widget__current-heading strong {
- color: var(--text, #d7dae0);
+ color: var(--text);
font-size: 13px;
line-height: 1.35;
}
.observer-widget__assessment {
- color: var(--muted, #8a919e);
+ color: var(--muted);
font-size: 11px;
line-height: 1.45;
margin: 0 0 0 19px;
@@ -386,7 +386,7 @@ openclaw-board-widget-cell {
.observer-widget__progress {
align-items: center;
- color: var(--muted, #8a919e);
+ color: var(--muted);
display: grid;
font-size: 9px;
gap: 7px;
@@ -395,19 +395,19 @@ openclaw-board-widget-cell {
}
.observer-widget__progress strong {
- color: var(--text, #d7dae0);
+ color: var(--text);
font-weight: 600;
}
.observer-widget__progress-track {
- background: color-mix(in srgb, var(--text, #d7dae0) 9%, transparent);
+ background: color-mix(in srgb, var(--text) 9%, transparent);
border-radius: 999px;
height: 3px;
overflow: hidden;
}
.observer-widget__progress-track > span {
- background: var(--accent, #ff5c5c);
+ background: var(--accent);
display: block;
height: 100%;
}
@@ -438,11 +438,11 @@ openclaw-board-widget-cell {
}
.observer-widget__run[data-current="true"] > span {
- color: var(--text, #d7dae0);
+ color: var(--text);
}
.observer-widget__run code {
- color: var(--muted, #8a919e);
+ color: var(--muted);
font-size: 9px;
letter-spacing: 0;
overflow: hidden;
@@ -462,18 +462,18 @@ openclaw-board-widget-cell {
}
.observer-widget__timeline-row--transition {
- background: color-mix(in srgb, var(--text, #d7dae0) 4%, transparent);
+ background: color-mix(in srgb, var(--text) 4%, transparent);
box-shadow: inset 2px 0 color-mix(in srgb, currentcolor 48%, transparent);
}
.observer-widget__timeline-row > time,
.observer-widget__health-label {
- color: var(--muted, #8a919e);
+ color: var(--muted);
font-size: 9px;
}
.observer-widget__timeline-headline {
- color: var(--text, #d7dae0);
+ color: var(--text);
font-size: 10.5px;
overflow: hidden;
text-overflow: ellipsis;
@@ -481,7 +481,7 @@ openclaw-board-widget-cell {
}
.observer-widget__health-dot {
- background: var(--muted, #8a919e);
+ background: var(--muted);
border-radius: 50%;
height: 8px;
margin-top: 3px;
@@ -491,22 +491,22 @@ openclaw-board-widget-cell {
.observer-widget__health-dot[data-health="on-track"],
.observer-widget__health-dot[data-health="done"],
.observer-widget__health-dot[data-health="wrapping-up"] {
- background: var(--success, #45c486);
+ background: var(--ok);
}
.observer-widget__health-dot[data-health="grinding"] {
- background: var(--warning, #e7b85c);
+ background: var(--warn);
}
.observer-widget__health-dot[data-health="stuck"],
.observer-widget__health-dot[data-health="waiting-on-user"],
.observer-widget__health-dot[data-health="failed"] {
- background: var(--danger, #ff6b6b);
+ background: var(--danger);
}
.observer-widget__unread-boundary {
align-items: center;
- color: var(--accent, #ff5c5c);
+ color: var(--accent);
display: grid;
font-size: 8px;
gap: 8px;
@@ -518,7 +518,7 @@ openclaw-board-widget-cell {
.observer-widget__unread-boundary::before,
.observer-widget__unread-boundary::after {
- border-top: 1px solid color-mix(in srgb, var(--accent, #ff5c5c) 42%, transparent);
+ border-top: 1px solid color-mix(in srgb, var(--accent) 42%, transparent);
content: "";
}
@@ -536,7 +536,7 @@ openclaw-board-widget-cell {
.board-widget__disabled-plugin,
.workboard-widget__state {
align-content: center;
- color: var(--muted, #8a919e);
+ color: var(--muted);
display: grid;
font-size: 11px;
gap: 10px;
@@ -548,7 +548,7 @@ openclaw-board-widget-cell {
}
.board-widget__disabled-plugin strong {
- color: var(--text, #d7dae0);
+ color: var(--text);
}
openclaw-workboard-card-widget,
@@ -576,7 +576,7 @@ openclaw-workboard-mini-widget {
.workboard-widget-card__heading > strong,
.workboard-widget-mini__card > strong {
- color: var(--text, #d7dae0);
+ color: var(--text);
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
@@ -586,7 +586,7 @@ openclaw-workboard-mini-widget {
.workboard-widget__status {
border: 1px solid var(--board-line);
border-radius: 999px;
- color: var(--muted, #8a919e);
+ color: var(--muted);
flex: 0 0 auto;
font-size: 9px;
padding: 2px 6px;
@@ -594,8 +594,8 @@ openclaw-workboard-mini-widget {
.workboard-widget__status--ready,
.workboard-widget__status--running {
- border-color: color-mix(in srgb, var(--accent, #ff5c5c) 45%, transparent);
- color: var(--accent, #ff5c5c);
+ border-color: color-mix(in srgb, var(--accent) 45%, transparent);
+ color: var(--accent);
}
.workboard-widget-card__meta {
@@ -607,7 +607,7 @@ openclaw-workboard-mini-widget {
.workboard-widget-card__meta div,
.workboard-widget-mini__counts span {
- background: color-mix(in srgb, var(--text, #d7dae0) 3%, transparent);
+ background: color-mix(in srgb, var(--text) 3%, transparent);
border: 1px solid var(--board-line);
border-radius: 8px;
min-width: 0;
@@ -616,13 +616,13 @@ openclaw-workboard-mini-widget {
.workboard-widget-card__meta dt,
.workboard-widget-card__move > span {
- color: var(--muted, #8a919e);
+ color: var(--muted);
font-size: 9px;
text-transform: uppercase;
}
.workboard-widget-card__meta dd {
- color: var(--text, #d7dae0);
+ color: var(--text);
font-size: 11px;
margin: 3px 0 0;
overflow: hidden;
@@ -636,16 +636,16 @@ openclaw-workboard-mini-widget {
}
.workboard-widget-card__move select {
- background: var(--panel, #171a20);
+ background: var(--panel);
border: 1px solid var(--board-line);
border-radius: 7px;
- color: var(--text, #d7dae0);
+ color: var(--text);
font: inherit;
padding: 6px 8px;
}
.workboard-widget-mini > header a {
- color: var(--accent, #ff5c5c);
+ color: var(--accent);
font-size: 10px;
}
@@ -656,7 +656,7 @@ openclaw-workboard-mini-widget {
}
.workboard-widget-mini__counts span {
- color: var(--muted, #8a919e);
+ color: var(--muted);
display: grid;
font-size: 8px;
gap: 2px;
@@ -664,7 +664,7 @@ openclaw-workboard-mini-widget {
}
.workboard-widget-mini__counts b {
- color: var(--text, #d7dae0);
+ color: var(--text);
font-size: 13px;
}
@@ -700,7 +700,7 @@ openclaw-workboard-mini-widget {
.board-widget__app-loading,
.board-widget__stale {
align-content: center;
- color: var(--muted, #8a919e);
+ color: var(--muted);
display: grid;
font-size: 11px;
gap: 8px;
@@ -711,7 +711,7 @@ openclaw-workboard-mini-widget {
}
.board-widget__stale strong {
- color: var(--text, #d7dae0);
+ color: var(--text);
font-size: 13px;
}
@@ -804,7 +804,7 @@ openclaw-workboard-mini-widget {
bar's corner; the revealed bar carries the full capabilities chip, so the
dot fades out together with the chrome fade-in. */
.board-widget__grant-dot {
- background: var(--ok, #4ec9a8);
+ background: var(--ok);
border-radius: 50%;
display: block;
height: 6px;
@@ -858,20 +858,20 @@ openclaw-workboard-mini-widget {
.board-widget__grant strong,
.board-widget__error strong {
- color: var(--text, #d7dae0);
+ color: var(--text);
font-size: 13px;
}
.board-widget__grant > span,
.board-widget__error > span {
- color: var(--muted, #8a919e);
+ color: var(--muted);
font-size: 11px;
line-height: 1.45;
max-width: 32ch;
}
.board-widget__grant-summary {
- color: var(--muted, #8a919e);
+ color: var(--muted);
display: grid;
font-size: 11px;
gap: 4px;
@@ -895,16 +895,16 @@ openclaw-workboard-mini-widget {
}
.board-widget__grant-groups section > strong {
- color: var(--text, #d7dae0);
+ color: var(--text);
font-size: 10px;
text-transform: uppercase;
}
.board-widget__capabilities {
- background: color-mix(in srgb, var(--success, #4fbf78) 13%, transparent);
- border: 1px solid color-mix(in srgb, var(--success, #4fbf78) 45%, transparent);
+ background: color-mix(in srgb, var(--ok) 13%, transparent);
+ border: 1px solid color-mix(in srgb, var(--ok) 45%, transparent);
border-radius: 999px;
- color: var(--success, #4fbf78);
+ color: var(--ok);
display: inline-flex;
font-size: 9px;
font-weight: 650;
@@ -915,10 +915,10 @@ openclaw-workboard-mini-widget {
.board-widget__grant-mark {
align-items: center;
- background: color-mix(in srgb, var(--warning, #e6ad55) 15%, transparent);
- border: 1px solid color-mix(in srgb, var(--warning, #e6ad55) 55%, transparent);
+ background: color-mix(in srgb, var(--warn) 15%, transparent);
+ border: 1px solid color-mix(in srgb, var(--warn) 55%, transparent);
border-radius: 50%;
- color: var(--warning, #e6ad55);
+ color: var(--warn);
display: flex;
font-size: 13px;
font-weight: 700;
@@ -943,7 +943,7 @@ openclaw-workboard-mini-widget {
}
.board-widget__error {
- background: color-mix(in srgb, var(--danger, #ff6b6b) 7%, transparent);
+ background: color-mix(in srgb, var(--danger) 7%, transparent);
}
.board-widget__error--inline {
@@ -954,7 +954,7 @@ openclaw-workboard-mini-widget {
}
.board-widget__error details {
- color: var(--muted, #8a919e);
+ color: var(--muted);
font-size: 10px;
max-width: 100%;
}
@@ -968,9 +968,9 @@ openclaw-workboard-mini-widget {
.board-empty {
align-items: center;
- border: 1px dashed color-mix(in srgb, var(--muted, #8a919e) 38%, transparent);
+ border: 1px dashed color-mix(in srgb, var(--muted) 38%, transparent);
border-radius: 14px;
- color: var(--muted, #8a919e);
+ color: var(--muted);
display: flex;
flex-direction: column;
gap: 7px;
@@ -981,7 +981,7 @@ openclaw-workboard-mini-widget {
}
.board-empty strong {
- color: var(--text, #d7dae0);
+ color: var(--text);
font-size: 14px;
}
@@ -990,7 +990,7 @@ openclaw-workboard-mini-widget {
}
.board-empty__mark {
- color: var(--accent, #ff5c5c);
+ color: var(--accent);
font-size: 24px;
}
diff --git a/ui/src/styles/chat/layout.css b/ui/src/styles/chat/layout.css
index b445352147de..b30fd8e5341c 100644
--- a/ui/src/styles/chat/layout.css
+++ b/ui/src/styles/chat/layout.css
@@ -924,21 +924,21 @@ openclaw-chat-page {
}
.agent-chat__goal--active {
- color: var(--success);
- background: color-mix(in srgb, var(--success) 9%, var(--card));
- border-color: color-mix(in srgb, var(--success) 28%, var(--border));
+ color: var(--ok);
+ background: color-mix(in srgb, var(--ok) 9%, var(--card));
+ border-color: color-mix(in srgb, var(--ok) 28%, var(--border));
}
.agent-chat__goal--blocked,
.agent-chat__goal--budget_limited,
.agent-chat__goal--usage_limited {
- color: var(--warning);
- background: color-mix(in srgb, var(--warning) 10%, var(--card));
- border-color: color-mix(in srgb, var(--warning) 30%, var(--border));
+ color: var(--warn);
+ background: color-mix(in srgb, var(--warn) 10%, var(--card));
+ border-color: color-mix(in srgb, var(--warn) 30%, var(--border));
}
.agent-chat__goal--complete {
- color: color-mix(in srgb, var(--success) 72%, var(--text));
+ color: color-mix(in srgb, var(--ok) 72%, var(--text));
}
/* Image attachments preview */
diff --git a/ui/src/styles/chat/sidebar.css b/ui/src/styles/chat/sidebar.css
index f6d8e785299b..2909e7d27dd5 100644
--- a/ui/src/styles/chat/sidebar.css
+++ b/ui/src/styles/chat/sidebar.css
@@ -79,7 +79,7 @@
padding: 0 3px;
border-radius: var(--radius-full);
background: var(--primary);
- color: var(--primary-foreground, #fff);
+ color: var(--primary-foreground);
font-size: 9px;
font-weight: 650;
line-height: 14px;
@@ -343,7 +343,7 @@
}
.chat-workspace-rail__state--error {
- color: var(--danger, #ef4444);
+ color: var(--danger);
}
.chat-workspace-rail__scroll {
@@ -469,7 +469,7 @@
}
.chat-workspace-rail__file-open:focus-visible {
- outline: 2px solid color-mix(in srgb, var(--accent, #7dd3fc) 65%, transparent);
+ outline: 2px solid color-mix(in srgb, var(--accent) 65%, transparent);
outline-offset: -2px;
}
@@ -506,8 +506,8 @@
.chat-workspace-rail__file-badge {
padding: 2px 6px;
border-radius: var(--radius-full);
- background: color-mix(in srgb, var(--danger, #ef4444) 12%, transparent);
- color: var(--danger, #ef4444);
+ background: color-mix(in srgb, var(--danger) 12%, transparent);
+ color: var(--danger);
font-size: 12px; /* was 10px */
line-height: 1.2;
}
@@ -703,7 +703,7 @@
}
.chat-tasks-rail__state--error {
- color: var(--danger, #ef4444);
+ color: var(--danger);
}
.chat-tasks-rail__scroll {
@@ -841,7 +841,7 @@
width: 7px;
height: 7px;
border-radius: var(--radius-full);
- background: var(--warn, #f59e0b);
+ background: var(--warn);
animation: chat-tasks-pulse 1.6s ease-in-out infinite;
}
@@ -877,7 +877,7 @@
.chat-tasks-rail__task-stop:focus-visible {
border-color: color-mix(in srgb, var(--border-strong) 72%, transparent);
background: color-mix(in srgb, var(--bg-elevated) 82%, transparent);
- color: var(--danger, #ef4444);
+ color: var(--danger);
}
.chat-tasks-rail__task-stop svg {
@@ -905,15 +905,15 @@
}
.chat-tasks-rail__task-status--ok {
- color: var(--ok, #22c55e);
+ color: var(--ok);
}
.chat-tasks-rail__task-status--warn {
- color: var(--warn, #f59e0b);
+ color: var(--warn);
}
.chat-tasks-rail__task-status--danger {
- color: var(--danger, #ef4444);
+ color: var(--danger);
}
.chat-tasks-rail__task-status--muted {
@@ -978,7 +978,7 @@
height: 28px;
padding: 0;
place-items: center;
- color: var(--danger, #ef4444);
+ color: var(--danger);
}
.chat-tasks-rail__detail-stop svg {
@@ -994,13 +994,13 @@
flex-direction: column;
gap: 3px;
padding: 10px;
- border: 1px solid color-mix(in srgb, var(--warn, #f59e0b) 24%, var(--border));
+ border: 1px solid color-mix(in srgb, var(--warn) 24%, var(--border));
border-radius: var(--radius-md);
- background: color-mix(in srgb, var(--warn, #f59e0b) 6%, transparent);
+ background: color-mix(in srgb, var(--warn) 6%, transparent);
}
.chat-tasks-rail__detail-activity span {
- color: var(--warn, #f59e0b);
+ color: var(--warn);
font-family: var(--mono);
font-size: var(--control-ui-text-xs);
font-weight: 650;
@@ -1060,8 +1060,8 @@
}
.chat-tasks-rail__task-inspector-state--error {
- border-color: color-mix(in srgb, var(--danger, #ef4444) 30%, var(--border));
- color: var(--danger, #ef4444);
+ border-color: color-mix(in srgb, var(--danger) 30%, var(--border));
+ color: var(--danger);
}
/* Quiet by default so a column of rows is not a column of accent links;
@@ -1403,6 +1403,9 @@ openclaw-session-discussion {
background: color-mix(in srgb, var(--accent) 22%, transparent);
}
+/* Code syntax palette (dark below, light overrides further down): deliberate
+ literal hexes tuned for code legibility, not theme tokens — the UI palette
+ has no per-token-kind roles and retinting per theme family is not wanted. */
.file-view .tok-comment {
color: var(--muted);
font-style: italic;
@@ -1503,8 +1506,8 @@ openclaw-session-discussion {
justify-content: space-between;
gap: 10px;
padding: 8px 10px;
- border-bottom: 1px solid color-mix(in srgb, var(--warning) 40%, var(--border));
- background: color-mix(in srgb, var(--warning) 10%, var(--panel));
+ border-bottom: 1px solid color-mix(in srgb, var(--warn) 40%, var(--border));
+ background: color-mix(in srgb, var(--warn) 10%, var(--panel));
color: var(--text);
font-size: 12px;
}
@@ -1828,19 +1831,19 @@ openclaw-session-discussion {
}
.session-diff__status--added {
- background: var(--ok, #22c55e);
+ background: var(--ok);
}
.session-diff__status--deleted {
- background: var(--destructive, #ef4444);
+ background: var(--destructive);
}
.session-diff__status--renamed {
- background: var(--accent, #a855f7);
+ background: var(--accent);
}
.session-diff__status--modified {
- background: var(--warning, #eab308);
+ background: var(--warn);
}
.session-diff__path {
diff --git a/ui/src/styles/components.css b/ui/src/styles/components.css
index 661740da44d8..7103c0d50e17 100644
--- a/ui/src/styles/components.css
+++ b/ui/src/styles/components.css
@@ -2272,7 +2272,7 @@ openclaw-chat-session-rail {
.code-block-copy.copied .code-block-copy__done {
display: inline;
- color: var(--success, #22c55e);
+ color: var(--ok);
}
.json-collapse {
@@ -3146,8 +3146,8 @@ td.data-table-key-col {
.exec-approval-card--inline {
padding: 14px 16px;
- border-color: color-mix(in srgb, var(--warning) 45%, var(--border));
- background: color-mix(in srgb, var(--warning) 5%, var(--card));
+ border-color: color-mix(in srgb, var(--warn) 45%, var(--border));
+ background: color-mix(in srgb, var(--warn) 5%, var(--card));
animation: none;
}
@@ -3230,7 +3230,7 @@ td.data-table-key-col {
.exec-approval-warning {
margin-top: 10px;
font-size: 13px;
- color: var(--warning, #b7791f);
+ color: var(--warn);
}
.exec-approval-actions {
@@ -3307,7 +3307,7 @@ td.data-table-key-col {
}
.exec-approval-list__expiry {
- color: var(--warning);
+ color: var(--warn);
font: 11px/1.2 var(--mono);
font-variant-numeric: tabular-nums;
}
@@ -5526,7 +5526,7 @@ td.data-table-key-col {
.session-approval-badge {
display: inline-flex;
align-items: center;
- color: var(--warning);
+ color: var(--warn);
}
.session-approval-badge svg {
diff --git a/ui/src/styles/layout.css b/ui/src/styles/layout.css
index ed560e541f9b..2dab71366d74 100644
--- a/ui/src/styles/layout.css
+++ b/ui/src/styles/layout.css
@@ -1000,12 +1000,12 @@ html.openclaw-native-web-chrome .shell-chrome-controls {
}
.sidebar-attention__item--warning {
- border-color: var(--warning-subtle, rgba(234, 179, 8, 0.25));
+ border-color: var(--warn-subtle);
background: rgba(234, 179, 8, 0.06);
}
.sidebar-attention__item--error {
- border-color: var(--danger-subtle, rgba(239, 68, 68, 0.25));
+ border-color: var(--danger-subtle);
background: rgba(239, 68, 68, 0.06);
}
@@ -1346,7 +1346,7 @@ html.openclaw-native-macos
display: inline-flex;
align-items: center;
justify-content: center;
- color: var(--warning);
+ color: var(--warn);
}
.sidebar-session-group-count--error svg {
@@ -1612,7 +1612,7 @@ html.openclaw-native-macos
display: inline-flex;
align-items: center;
justify-content: center;
- color: var(--warning);
+ color: var(--warn);
}
.sidebar-session-catalog-host__count--error svg {
@@ -2948,8 +2948,8 @@ wa-dropdown.sidebar-session-sort-menu::part(menu) {
justify-content: center;
padding: 0 5px;
border-radius: var(--radius-full);
- background: color-mix(in srgb, var(--warning) 18%, transparent);
- color: var(--warning);
+ background: color-mix(in srgb, var(--warn) 18%, transparent);
+ color: var(--warn);
font-size: 10px;
font-weight: 700;
font-variant-numeric: tabular-nums;