FN-6686: canonicalize Command Center CSS tokens

Canonicalize Command Center CSS token references so chart accents and primary text no longer rely on undefined aliases.

- Replace Command Center uses of `--color-accent` with `--accent` and `--text-primary` with `--text` across shell, chart, area, and control styles.
- Add a scoped CSS token canonicalization regression test for Command Center styles.
- Document the Command Center token-only rule and add a patch changeset for the published package.

Files changed:
 .changeset/fn-6686-command-center-css-token-fix.md |  5 +++
 docs/dashboard-guide.md                            |  2 +-
 .../components/command-center/CommandCenter.css    | 28 +++++++--------
 .../components/command-center/DateRangePicker.css  |  2 +-
 .../command-center/MissionControlPanel.css         |  2 +-
 ...mmand-center-css-token-canonicalization.test.ts | 40 ++++++++++++++++++++++
 .../command-center/areas/SystemStatsArea.css       |  4 +--
 .../app/components/command-center/areas/areas.css  | 14 ++++----
 .../components/command-center/charts/charts.css    | 39 ++++++++++++---------
 9 files changed, 93 insertions(+), 43 deletions(-)

Fusion-Task-Id: FN-6686

Fusion-Task-Lineage: 10a79117-9716-4228-b2db-78791ec73d0d
This commit is contained in:
gsxdsm
2026-06-19 01:21:39 -07:00
parent 5e1a4ff3fd
commit 0f021aee4f
9 changed files with 93 additions and 43 deletions

View File

@@ -0,0 +1,5 @@
---
"@runfusion/fusion": patch
---
Fix Command Center charts and shell styling to use the canonical `--accent` and `--text` dashboard tokens instead of undefined `--color-accent` and `--text-primary` aliases, so chart accents and primary text render with the intended colors.

View File

@@ -1255,7 +1255,7 @@ The `index.html` shell is templated server-side: the server injects a per-user `
**Always reference tokens. Never hardcode pixels, hex, or `rgba()` in component CSS** — global/theme token CSS is also covered by `global-theme-css-no-raw-rgba.test.ts`, so raw `rgba()` belongs only in explicit `var(--token, rgba(...))` fallbacks. For translucent backgrounds use `color-mix(in srgb, var(--color) X%, transparent)`, not `rgba()`.
Command Center chart surfaces are a stricter token-only zone: `CommandCenter.css`, `areas/areas.css`, and `charts/charts.css` should avoid raw color fallbacks and hardcoded dimensions in component rules, keep secondary copy on `--text-muted`, use `--duration-*` for animation durations, and encode mobile chart invariants with shared classes rather than one-off area styles.
Command Center chart surfaces are a stricter token-only zone: `CommandCenter.css`, `areas/areas.css`, and `charts/charts.css` should avoid raw color fallbacks and hardcoded dimensions in component rules, keep secondary copy on `--text-muted`, use canonical `--accent` / `--text` for generic accent and primary text styling, use `--duration-*` for animation durations, and encode mobile chart invariants with shared classes rather than one-off area styles. The undefined `--color-accent` / `--text-primary` aliases are forbidden under `components/command-center/**` and guarded by `command-center-css-token-canonicalization.test.ts`.
### Theme system

View File

@@ -59,12 +59,12 @@ The Command Center must remain scrollable on mobile inside the overflow-hidden .
}
.cc-tab:hover {
color: var(--text-primary);
color: var(--text);
}
.cc-tab.active {
color: var(--text-primary);
border-bottom-color: var(--color-accent);
color: var(--text);
border-bottom-color: var(--accent);
}
.cc-tabpanel {
@@ -121,7 +121,7 @@ FN-6680 standardizes the Command Center card rhythm across overview, area, table
.cc-stat-value {
font-size: var(--font-size-xl);
font-variant-numeric: tabular-nums;
color: var(--text-primary);
color: var(--text);
}
.cc-stat-card--gauge {
@@ -182,9 +182,9 @@ FN-6680 keeps the FN-6664 live/chart shrink contract but replaces hardcoded trac
border: var(--border-width) solid var(--border-subtle);
border-radius: var(--radius-md);
background:
linear-gradient(135deg, color-mix(in srgb, var(--color-accent) 14%, transparent), transparent),
linear-gradient(135deg, color-mix(in srgb, var(--accent) 14%, transparent), transparent),
var(--surface-1);
box-shadow: 0 0 var(--space-4) color-mix(in srgb, var(--color-accent) 18%, transparent);
box-shadow: 0 0 var(--space-4) color-mix(in srgb, var(--accent) 18%, transparent);
overflow: hidden;
font-size: var(--font-size-sm);
}
@@ -193,7 +193,7 @@ FN-6680 keeps the FN-6664 live/chart shrink contract but replaces hardcoded trac
content: "";
position: absolute;
inset: 0;
background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--color-accent) 24%, transparent), transparent);
background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 24%, transparent), transparent);
opacity: 0.45;
transform: translateX(-100%);
animation: cc-live-signal-sweep calc(var(--duration-slow) * 8) linear infinite;
@@ -215,7 +215,7 @@ FN-6680 keeps the FN-6664 live/chart shrink contract but replaces hardcoded trac
}
.cc-live-strip-label {
color: var(--text-primary);
color: var(--text);
font-weight: 600;
}
@@ -238,7 +238,7 @@ FN-6680 keeps the FN-6664 live/chart shrink contract but replaces hardcoded trac
}
.cc-live-metric-value {
color: var(--text-primary);
color: var(--text);
font-size: var(--font-size-lg);
font-weight: 700;
font-variant-numeric: tabular-nums;
@@ -283,7 +283,7 @@ Overview token totals now live-poll and should visibly count up on change in bot
}
.cc-live-trend .cc-sparkline-bar {
box-shadow: 0 0 var(--space-2) color-mix(in srgb, var(--color-accent) 28%, transparent);
box-shadow: 0 0 var(--space-2) color-mix(in srgb, var(--accent) 28%, transparent);
animation: cc-live-signal-pulse calc(var(--duration-slow) * 5) ease-in-out infinite;
}
@@ -337,9 +337,9 @@ Overview charts must use dashboard tokens only and keep motion decorative; anima
border: var(--border-width) solid var(--border-subtle);
border-radius: var(--radius-md);
background:
linear-gradient(145deg, color-mix(in srgb, var(--color-accent) 10%, transparent), transparent),
linear-gradient(145deg, color-mix(in srgb, var(--accent) 10%, transparent), transparent),
var(--surface-1);
box-shadow: 0 0 var(--space-4) color-mix(in srgb, var(--color-accent) 12%, transparent);
box-shadow: 0 0 var(--space-4) color-mix(in srgb, var(--accent) 12%, transparent);
overflow: hidden;
animation: cc-overview-chart-rise var(--duration-normal) ease-out both;
}
@@ -352,7 +352,7 @@ Overview charts must use dashboard tokens only and keep motion decorative; anima
content: "";
position: absolute;
inset: 0;
background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--color-accent) 16%, transparent), transparent);
background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 16%, transparent), transparent);
opacity: 0;
pointer-events: none;
animation: cc-overview-chart-sheen calc(var(--duration-slow) * 7) ease-in-out infinite;
@@ -397,7 +397,7 @@ Overview recharts cards use token-derived height so ResponsiveContainer can rend
.cc-overview-chart-card .cc-bar-fill,
.cc-overview-chart-card .cc-sparkline-bar {
box-shadow: 0 0 var(--space-2) color-mix(in srgb, var(--color-accent) 30%, transparent);
box-shadow: 0 0 var(--space-2) color-mix(in srgb, var(--accent) 30%, transparent);
}
@keyframes cc-overview-chart-rise {

View File

@@ -57,6 +57,6 @@ Raw rgba fallbacks are replaced with byte-equivalent concrete-hex color-mix fall
background: var(--surface-2, color-mix(in srgb, #7f7f7f 12%, transparent));
border: 1px solid var(--border-subtle, color-mix(in srgb, #7f7f7f 25%, transparent));
border-radius: var(--radius-sm, 4px);
color: var(--text-primary, #ddd);
color: var(--text);
padding: var(--space-1, 0.25rem) var(--space-2, 0.5rem);
}

View File

@@ -85,7 +85,7 @@ Raw rgba fallbacks are replaced with byte-equivalent concrete-hex color-mix fall
padding: 2px 6px;
border-radius: var(--radius-sm, 6px);
background: var(--surface-2, color-mix(in srgb, #3b82f6 15%, transparent));
color: var(--text-primary, #ddd);
color: var(--text);
}
.cc-mc-badge.inactive {

View File

@@ -0,0 +1,40 @@
import { readFileSync, readdirSync, statSync } from "node:fs";
import path from "node:path";
import { describe, expect, it } from "vitest";
const COMMAND_CENTER_ROOT = path.resolve(__dirname, "..");
function collectCssFiles(dir: string): string[] {
const out: string[] = [];
for (const entry of readdirSync(dir)) {
const fullPath = path.join(dir, entry);
const stats = statSync(fullPath);
if (stats.isDirectory()) {
out.push(...collectCssFiles(fullPath));
continue;
}
if (entry.endsWith(".css")) {
out.push(path.relative(COMMAND_CENTER_ROOT, fullPath).split(path.sep).join("/"));
}
}
return out;
}
describe("Command Center CSS token canonicalization", () => {
it("keeps undefined accent and primary text aliases out of Command Center CSS", () => {
const offenders: string[] = [];
for (const relPath of collectCssFiles(COMMAND_CENTER_ROOT)) {
const content = readFileSync(path.join(COMMAND_CENTER_ROOT, relPath), "utf8");
if (/--(?:color-accent|text-primary)\b/.test(content)) offenders.push(relPath);
}
expect(offenders, `Unexpected undefined Command Center token aliases in: ${offenders.join(", ")}`).toEqual([]);
});
it("keeps chart primitives wired to canonical accent and text tokens", () => {
const chartsCss = readFileSync(path.join(COMMAND_CENTER_ROOT, "charts/charts.css"), "utf8");
expect(chartsCss).toContain("var(--accent)");
expect(chartsCss).toContain("var(--text)");
});
});

View File

@@ -72,12 +72,12 @@ System control cards sit beside chart/stat cards, so FN-6680 gives them the same
.cc-system-toggle-row,
.cc-system-threshold-row {
color: var(--text-primary);
color: var(--text);
font-size: var(--font-size-sm);
}
.cc-system-threshold-controls input[type="range"] {
accent-color: var(--color-accent);
accent-color: var(--accent);
}
.cc-system-threshold-controls .input {

View File

@@ -76,9 +76,9 @@ The Tokens area needs a real hour/day/week control and live token-number motion.
}
.cc-token-granularity .btn.active {
border-color: var(--color-accent);
color: var(--text-primary);
background: color-mix(in srgb, var(--color-accent) 14%, var(--surface-1));
border-color: var(--accent);
color: var(--text);
background: color-mix(in srgb, var(--accent) 14%, var(--surface-1));
}
.cc-token-count-live {
@@ -159,7 +159,7 @@ FN-6680 keeps table-heavy chart areas on the same --border-width/--border-subtle
}
.cc-table th.cc-sortable:hover {
color: var(--text-primary);
color: var(--text);
}
.cc-table tbody tr {
@@ -171,13 +171,13 @@ FN-6680 keeps table-heavy chart areas on the same --border-width/--border-subtle
}
.cc-table tbody tr.cc-row-selected td {
color: var(--text-primary);
color: var(--text);
}
.cc-sort-caret {
margin-inline-start: var(--space-1);
font-size: 0.7em;
color: var(--color-accent);
color: var(--accent);
}
/* Unavailable sentinel ("—") with a help cursor for its tooltip. */
@@ -264,7 +264,7 @@ The Team view must use dashboard design tokens only, preserve .cc-tabpanel as th
}
.cc-team-agent-name {
color: var(--text-primary);
color: var(--text);
font-weight: 600;
}

View File

@@ -1,3 +1,8 @@
/*
FNXC:CommandCenterStyling 2026-06-19-00:00:
FN-6686 requires Command Center CSS to use canonical --accent and --text tokens. Undefined legacy accent/text-primary aliases made chart primitives inherit fallback colors; the scoped token guard prevents reintroducing those aliases after the FN-6682 review finding.
*/
/*
FNXC:CommandCenterStyling 2026-06-17-18:46:
Chart labels and legends must use --text-muted so command-center CSS stays aligned with the FN-4286 canonical text-token guard and avoids raw color fallbacks.
@@ -65,7 +70,7 @@ FN-6680 re-checked FN-6664 in a real Blink layout engine because jsdom does not
.cc-bar-fill {
block-size: 100%;
background: var(--color-accent);
background: var(--accent);
border-radius: var(--radius-sm);
transition: width var(--transition-normal);
}
@@ -74,7 +79,7 @@ FN-6680 re-checked FN-6664 in a real Blink layout engine because jsdom does not
min-inline-size: 0;
font-size: var(--font-size-sm);
font-variant-numeric: tabular-nums;
color: var(--text-primary);
color: var(--text);
overflow-wrap: anywhere;
text-align: end;
}
@@ -96,7 +101,7 @@ FN-6680 re-checked FN-6664 in a real Blink layout engine because jsdom does not
.cc-stacked-segment {
block-size: 100%;
background: var(--color-accent);
background: var(--accent);
transition: width var(--transition-normal);
}
@@ -123,7 +128,7 @@ FN-6680 re-checked FN-6664 in a real Blink layout engine because jsdom does not
inline-size: var(--space-2);
block-size: var(--space-2);
border-radius: var(--radius-sm);
background: var(--color-accent);
background: var(--accent);
display: inline-block;
}
@@ -138,7 +143,7 @@ FN-6680 re-checked FN-6664 in a real Blink layout engine because jsdom does not
.cc-sparkline-bar {
flex: 1 1 0;
min-inline-size: var(--border-width);
background: var(--color-accent);
background: var(--accent);
border-radius: var(--border-width);
transition: height var(--transition-normal);
}
@@ -163,7 +168,7 @@ The token-over-time chart is live-updated and animated, but the motion is decora
padding: var(--space-3);
border: var(--border-width) solid var(--border-subtle);
border-radius: var(--radius-md);
background: linear-gradient(180deg, color-mix(in srgb, var(--color-accent) 10%, transparent), transparent), var(--surface-1);
background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 10%, transparent), transparent), var(--surface-1);
overflow: hidden;
}
@@ -171,8 +176,8 @@ The token-over-time chart is live-updated and animated, but the motion is decora
flex: 1 1 0;
min-inline-size: var(--space-1);
border-radius: var(--radius-sm) var(--radius-sm) 0 0;
background: linear-gradient(180deg, var(--color-accent), color-mix(in srgb, var(--color-accent) 45%, var(--surface-2)));
box-shadow: 0 0 var(--space-2) color-mix(in srgb, var(--color-accent) 24%, transparent);
background: linear-gradient(180deg, var(--accent), color-mix(in srgb, var(--accent) 45%, var(--surface-2)));
box-shadow: 0 0 var(--space-2) color-mix(in srgb, var(--accent) 24%, transparent);
transition: height var(--transition-normal);
animation: cc-token-series-rise var(--duration-normal) ease-out both;
}
@@ -240,12 +245,12 @@ Line-chart motion is decorative, token-timed, and disabled for reduced-motion us
inline-size: 100%;
block-size: clamp(var(--space-16), 22vw, calc(var(--space-20) * 2));
aspect-ratio: 5 / 2;
color: var(--color-accent);
color: var(--accent);
overflow: hidden;
}
.cc-line-chart-series {
color: var(--color-accent);
color: var(--accent);
}
.cc-line-chart-series:nth-child(2n) {
@@ -299,7 +304,7 @@ Line-chart motion is decorative, token-timed, and disabled for reduced-motion us
display: grid;
place-items: center;
gap: var(--space-2);
color: var(--text-primary);
color: var(--text);
}
.cc-radial-gauge-ring {
@@ -311,8 +316,8 @@ Line-chart motion is decorative, token-timed, and disabled for reduced-motion us
border-radius: 50%;
background:
radial-gradient(circle at center, var(--surface-1) 0 54%, transparent 55%),
conic-gradient(var(--color-accent) var(--cc-radial-value), var(--surface-2) 0);
box-shadow: 0 0 var(--space-4) color-mix(in srgb, var(--color-accent) 35%, transparent);
conic-gradient(var(--accent) var(--cc-radial-value), var(--surface-2) 0);
box-shadow: 0 0 var(--space-4) color-mix(in srgb, var(--accent) 35%, transparent);
isolation: isolate;
animation: cc-radial-gauge-pulse calc(var(--duration-slow) * 6) ease-in-out infinite;
}
@@ -322,8 +327,8 @@ Line-chart motion is decorative, token-timed, and disabled for reduced-motion us
position: absolute;
inset: var(--space-2);
border-radius: inherit;
border: var(--border-width) solid color-mix(in srgb, var(--color-accent) 45%, transparent);
box-shadow: inset 0 0 var(--space-3) color-mix(in srgb, var(--color-accent) 22%, transparent);
border: var(--border-width) solid color-mix(in srgb, var(--accent) 45%, transparent);
box-shadow: inset 0 0 var(--space-3) color-mix(in srgb, var(--accent) 22%, transparent);
animation: cc-radial-gauge-sweep calc(var(--duration-slow) * 8) linear infinite;
}
@@ -429,7 +434,7 @@ Line-chart motion is decorative, token-timed, and disabled for reduced-motion us
.cc-funnel-fill {
block-size: 100%;
background: var(--color-accent);
background: var(--accent);
border-radius: var(--radius-sm);
transition: width var(--transition-normal);
}
@@ -437,7 +442,7 @@ Line-chart motion is decorative, token-timed, and disabled for reduced-motion us
.cc-funnel-value {
font-size: var(--font-size-sm);
font-variant-numeric: tabular-nums;
color: var(--text-primary);
color: var(--text);
}
/* ---- Loading shimmer (used by chart skeletons) ---- */