diff --git a/dashboard/src/__tests__/PipelinesPage.test.tsx b/dashboard/src/__tests__/PipelinesPage.test.tsx
index aad0e9e3..9c3374c7 100644
--- a/dashboard/src/__tests__/PipelinesPage.test.tsx
+++ b/dashboard/src/__tests__/PipelinesPage.test.tsx
@@ -118,7 +118,12 @@ describe('PipelinesPage', () => {
mockGetPipelines.mockResolvedValue(mockPipelines);
renderPage();
await waitFor(() => {
- expect(screen.getByText(/2 steps/)).toBeDefined();
+ // After Command Center redesign, the number is wrapped in font-mono span
+ // so text is split across elements: 2 steps
+ const stepCount = screen.getByText((_content, element) =>
+ element?.textContent === "2 steps"
+ );
+ expect(stepCount).toBeDefined();
});
});
diff --git a/dashboard/src/__tests__/a11y-css.test.ts b/dashboard/src/__tests__/a11y-css.test.ts
index 62b4d4f5..8064c783 100644
--- a/dashboard/src/__tests__/a11y-css.test.ts
+++ b/dashboard/src/__tests__/a11y-css.test.ts
@@ -23,10 +23,13 @@ describe('index.css — focus ring tokens', () => {
expect(css).toContain('--focus-ring-offset:');
});
- it('applies focus ring via :focus-visible', () => {
+ it('applies an amber focus ring via :focus-visible', () => {
+ // DESIGN §1: the focus ring is brand amber (--color-accent), applied as a
+ // 2px outline with a 1px offset (see index.css :focus-visible rule).
expect(css).toContain(':focus-visible');
// Command Center redesign uses outline-based focus ring (DESIGN.md §1)
expect(css).toContain('outline: 2px solid var(--color-accent)');
+ expect(css).toContain('outline-offset: 1px');
});
it('removes outline for :focus:not(:focus-visible)', () => {
diff --git a/dashboard/src/components/approvals/ApprovalBanner.tsx b/dashboard/src/components/approvals/ApprovalBanner.tsx
index 2d73f020..3f82d6f6 100644
--- a/dashboard/src/components/approvals/ApprovalBanner.tsx
+++ b/dashboard/src/components/approvals/ApprovalBanner.tsx
@@ -87,7 +87,7 @@ export function ApprovalBanner({ sessionId, sessionName }: ApprovalBannerProps)
type="button"
onClick={handleApprove}
disabled={isApproving || isRejecting}
- className="min-h-[44px] inline-flex items-center gap-1.5 rounded-lg bg-[var(--color-success)] px-4 py-2 text-sm font-medium text-white transition-colors hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-success)] disabled:cursor-not-allowed disabled:opacity-50"
+ className="min-h-[44px] inline-flex items-center gap-1.5 rounded border border-[var(--color-cta-bg)] bg-[var(--color-cta-bg)] px-4 py-2 text-[13px] font-semibold text-[var(--color-cta-text)] transition-colors hover:bg-[var(--color-cta-bg-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-cta-bg)] disabled:cursor-not-allowed disabled:opacity-50"
aria-label={`Approve session ${sessionName ?? sessionId}`}
>
{isApproving ? (
@@ -101,7 +101,7 @@ export function ApprovalBanner({ sessionId, sessionName }: ApprovalBannerProps)
type="button"
onClick={handleReject}
disabled={isApproving || isRejecting}
- className="min-h-[44px] inline-flex items-center gap-1.5 rounded-lg border border-[var(--color-danger)]/30 bg-[var(--color-error-bg)]/20 px-4 py-2 text-sm font-medium text-[var(--color-danger)] transition-colors hover:bg-[var(--color-error-bg)]/35 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-danger)] disabled:cursor-not-allowed disabled:opacity-50"
+ className="min-h-[44px] inline-flex items-center gap-1.5 rounded border border-[var(--color-danger)] bg-transparent px-4 py-2 text-[13px] font-semibold text-[var(--color-danger)] transition-colors hover:bg-[var(--color-danger)]/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-danger)] disabled:cursor-not-allowed disabled:opacity-50"
aria-label={`Reject session ${sessionName ?? sessionId}`}
>
{isRejecting ? (
diff --git a/dashboard/src/components/overview/SessionTable.tsx b/dashboard/src/components/overview/SessionTable.tsx
index 639beccd..f1affa47 100644
--- a/dashboard/src/components/overview/SessionTable.tsx
+++ b/dashboard/src/components/overview/SessionTable.tsx
@@ -481,7 +481,7 @@ export default React.memo(function SessionTable({ maxRows }: SessionTableProps =
if (isLoading && sessions.length === 0 && !loadError) {
return (
-
+
{t('sessionTable.wakingAgents')}
{t('sessionTable.wakingAgentsDescription')}
diff --git a/dashboard/src/components/session/AcpApprovalModal.tsx b/dashboard/src/components/session/AcpApprovalModal.tsx
index 15e75648..0f169222 100644
--- a/dashboard/src/components/session/AcpApprovalModal.tsx
+++ b/dashboard/src/components/session/AcpApprovalModal.tsx
@@ -108,7 +108,7 @@ export function AcpApprovalModal({
ref={trapRef}
aria-modal="true"
aria-label={t("aria.toolApprovalRequired")}
- className="flex flex-col gap-3 rounded-xl border border-[var(--color-warning)]/35 bg-[var(--color-surface)] p-4 shadow-2xl"
+ className="flex flex-col gap-3 rounded-xl border border-[var(--color-border)] border-l-[3px] border-l-[var(--color-warning)] bg-[var(--color-surface)] p-4 shadow-2xl"
>
{/* Header */}
@@ -181,7 +181,7 @@ export function AcpApprovalModal({
type="button"
onClick={handleApprove}
disabled={isLoading}
- className="flex flex-1 items-center justify-center gap-2 rounded-xl border border-[var(--color-success)]/30 bg-[var(--color-success-bg)] px-4 py-3 text-sm font-semibold text-[var(--color-success)] transition-colors hover:bg-[var(--color-success-bg-hover)] disabled:opacity-50 disabled:cursor-not-allowed"
+ className="flex flex-1 items-center justify-center gap-2 rounded-xl border border-[var(--color-cta-bg)] bg-[var(--color-cta-bg)] px-4 py-3 text-sm font-semibold text-[var(--color-cta-text)] transition-colors hover:bg-[var(--color-cta-bg-hover)] disabled:opacity-50 disabled:cursor-not-allowed"
aria-label={t("aria.approveTool")}
>
{isLoading ?
:
}
@@ -191,7 +191,7 @@ export function AcpApprovalModal({
type="button"
onClick={() => setShowRejectReason(true)}
disabled={isLoading}
- className="flex flex-1 items-center justify-center gap-2 rounded-xl border border-[var(--color-error)]/30 bg-[var(--color-error-bg)] px-4 py-3 text-sm font-semibold text-[var(--color-error)] transition-colors hover:bg-[var(--color-error-bg-hover)] disabled:opacity-50 disabled:cursor-not-allowed"
+ className="flex flex-1 items-center justify-center gap-2 rounded-xl border border-[var(--color-danger)] bg-transparent px-4 py-3 text-sm font-semibold text-[var(--color-danger)] transition-colors hover:bg-[var(--color-danger)]/10 disabled:opacity-50 disabled:cursor-not-allowed"
aria-label={t("aria.rejectTool")}
>
{isLoading ?
:
}
diff --git a/dashboard/src/components/session/PermissionPromptSheet.tsx b/dashboard/src/components/session/PermissionPromptSheet.tsx
index b2af3292..3aa3e4f3 100644
--- a/dashboard/src/components/session/PermissionPromptSheet.tsx
+++ b/dashboard/src/components/session/PermissionPromptSheet.tsx
@@ -65,7 +65,7 @@ export function PermissionPromptSheet({
ref={trapRef}
aria-modal="true"
aria-label={t("aria.permissionPrompt")}
- className="rounded-t-2xl border border-[var(--color-warning)]/35 bg-[var(--color-surface)] p-4 shadow-2xl"
+ className="rounded-t-2xl border border-[var(--color-border)] border-l-[3px] border-l-[var(--color-warning)] bg-[var(--color-surface)] p-4 shadow-2xl"
>
@@ -99,14 +99,14 @@ export function PermissionPromptSheet({
diff --git a/dashboard/src/components/session/TerminalDebugTab.tsx b/dashboard/src/components/session/TerminalDebugTab.tsx
index 98a7a8fe..b5c42cc0 100644
--- a/dashboard/src/components/session/TerminalDebugTab.tsx
+++ b/dashboard/src/components/session/TerminalDebugTab.tsx
@@ -235,7 +235,7 @@ export function TerminalDebugTab({
onChange={(e) => setInputValue(e.target.value)}
onKeyDown={handleKeyDown}
placeholder={t('sessionDetail.commandPlaceholder')}
- className="flex-1 bg-transparent font-mono text-xs text-[var(--color-text-primary)] placeholder-[var(--color-text-muted)] focus-visible:outline-none"
+ className="flex-1 rounded-sm bg-transparent font-mono text-xs text-[var(--color-text-primary)] placeholder-[var(--color-text-muted)]"
disabled={!isConnected}
autoFocus
aria-label={t("aria.terminalInput")}
diff --git a/dashboard/src/components/shared/CommandPalette.tsx b/dashboard/src/components/shared/CommandPalette.tsx
index b6bb02a0..e0da8f57 100644
--- a/dashboard/src/components/shared/CommandPalette.tsx
+++ b/dashboard/src/components/shared/CommandPalette.tsx
@@ -221,7 +221,7 @@ export default function CommandPalette({ open, onClose }: CommandPaletteProps) {
onChange={(e) => { setQuery(e.target.value); setActiveIndex(0); }}
onKeyDown={handleInputKeyDown}
placeholder={t('commandPalette.searchPlaceholder')}
- className="min-h-8 flex-1 bg-transparent text-sm text-white placeholder:text-[var(--color-text-muted)] outline-none"
+ className="min-h-8 flex-1 rounded-sm bg-transparent text-sm text-white placeholder:text-[var(--color-text-muted)]"
/>
ESC
diff --git a/dashboard/src/index.css b/dashboard/src/index.css
index 4f83de7c..d590c595 100644
--- a/dashboard/src/index.css
+++ b/dashboard/src/index.css
@@ -937,15 +937,11 @@ button:active:not(:disabled) {
box-shadow: 0 0 10px currentColor; /* Smooth bleed */
}
.status-dot--idle { color: var(--color-success); background-color: var(--color-success); }
-.status-dot--working { color: var(--color-warning); background-color: var(--color-warning); animation: pulse-intense 1.5s infinite; }
-.status-dot--permission_prompt { color: var(--color-danger); background-color: var(--color-danger); animation: pulse-intense 1s infinite; }
.status-dot--unknown { color: #475569; background-color: #475569; box-shadow: none; }
-
-@keyframes pulse-intense {
- 0% { transform: scale(1); opacity: 1; box-shadow: 0 0 0 0 rgba(var(--color-warning), 0.6); }
- 70% { transform: scale(1.2); opacity: 0.7; box-shadow: 0 0 0 6px rgba(var(--color-warning), 0); }
- 100% { transform: scale(1); opacity: 1; }
-}
+/* Live session/agent status dots — including the calm amber "working" pulse
+ * (opacity 1→0.4→1, DESIGN §5) — are owned by the canonical StatusDot
+ * component (components/overview/StatusDot.tsx). The old `.status-dot--working`
+ * / `--permission_prompt` modifiers used a bouncy scale pulse and were unused. */
/* ── Syntax Highlighting Tokens ────────────────────────────── */
.syn-keyword { color: var(--color-syn-keyword, #ff7b72); }
diff --git a/dashboard/src/pages/ActivityPage.tsx b/dashboard/src/pages/ActivityPage.tsx
index e589f43e..93185629 100644
--- a/dashboard/src/pages/ActivityPage.tsx
+++ b/dashboard/src/pages/ActivityPage.tsx
@@ -95,7 +95,7 @@ export default function ActivityPage() {
)}
-
+
{heatmapLoading ? (
diff --git a/dashboard/src/pages/AnalyticsPage.tsx b/dashboard/src/pages/AnalyticsPage.tsx
index 894ee67c..1c843769 100644
--- a/dashboard/src/pages/AnalyticsPage.tsx
+++ b/dashboard/src/pages/AnalyticsPage.tsx
@@ -407,7 +407,7 @@ export default function AnalyticsPage() {
{(data.topApiKeys ?? []).length > 0 ? (
{(data.topApiKeys ?? []).map((key) => (
-
+
{key.keyName}
{key.sessions} session{key.sessions !== 1 ? 's' : ''} · {key.messages} message{key.messages !== 1 ? 's' : ''}
@@ -482,7 +482,7 @@ function EmptyChart() {
function MetricBox({ label, value }: { label: string; value: string }) {
return (
-
+
diff --git a/dashboard/src/pages/AuditPage.tsx b/dashboard/src/pages/AuditPage.tsx
index e33e69a2..aaa7d063 100644
--- a/dashboard/src/pages/AuditPage.tsx
+++ b/dashboard/src/pages/AuditPage.tsx
@@ -190,7 +190,7 @@ function AuditRow({ record, index, onClick }: { record: AuditRecord; index: numb
}}
className="border-b border-[var(--color-void-lighter)] transition-colors hover:bg-[var(--color-void-light)]/40 cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-accent)]"
>
-
+ |
{formatTimestamp(record.ts)}
|
diff --git a/dashboard/src/pages/CostPage.tsx b/dashboard/src/pages/CostPage.tsx
index a89ed08d..af1b401f 100644
--- a/dashboard/src/pages/CostPage.tsx
+++ b/dashboard/src/pages/CostPage.tsx
@@ -44,7 +44,7 @@ import { getBudgetSettings, type BudgetSettings } from '../utils/budgetSettings'
const MODEL_COLORS: Record = {
'claude-sonnet-4.6': 'var(--color-accent-cyan)',
- 'claude-opus-4.7': 'var(--color-accent-purple)',
+ 'claude-opus-4.7': 'var(--color-accent)',
'claude-haiku-4.5': 'var(--color-success)',
'gpt-5.4': 'var(--color-warning)',
'gpt-4.1': 'var(--color-info)',
diff --git a/dashboard/src/pages/LoginPage.tsx b/dashboard/src/pages/LoginPage.tsx
index c5e048cf..9083b4c1 100644
--- a/dashboard/src/pages/LoginPage.tsx
+++ b/dashboard/src/pages/LoginPage.tsx
@@ -65,7 +65,7 @@ export default function LoginPage() {
return (
-
+
{/* Logo / Title */}
@@ -83,7 +83,7 @@ export default function LoginPage() {
|