diff --git a/web/src/tabs/OverviewTab.tsx b/web/src/tabs/OverviewTab.tsx
index 5a86fa2..25692e9 100644
--- a/web/src/tabs/OverviewTab.tsx
+++ b/web/src/tabs/OverviewTab.tsx
@@ -43,6 +43,30 @@ const WIN_RATE_WINDOW_OPTIONS: Array<{ key: WinRateWindow; label: string; ms?: n
{ key: 'all', label: 'All' }
];
const REFRESH_INTERVAL_MS = 30_000;
+const overviewWarningBorder = '1px solid color-mix(in oklab, var(--bl-warning) 28%, transparent)';
+const overviewWarningSurface = 'var(--bl-warning-muted)';
+const overviewWarningText = 'var(--bl-warning)';
+const overviewDangerBorder = '1px solid color-mix(in oklab, var(--bl-danger) 28%, transparent)';
+const overviewDangerSurface = 'var(--bl-danger-muted)';
+const overviewDangerText = 'var(--bl-danger)';
+const overviewMutedText = 'var(--bl-text-faint)';
+const overviewQuietText = 'var(--bl-text-quiet)';
+const overviewInfoText = 'var(--bl-info-strong)';
+const overviewAttentionText = 'var(--bl-warning)';
+const overviewSuccessText = 'var(--bl-success)';
+const overviewNeutralText = 'var(--foreground)';
+const overviewSoftBorder = '1px solid var(--bl-border-subtle)';
+const overviewActiveBorder = '1px solid color-mix(in oklab, var(--bl-success) 45%, transparent)';
+const overviewActiveSurface = 'color-mix(in oklab, var(--bl-success) 8%, transparent)';
+const overviewMutedSurface = 'color-mix(in oklab, var(--foreground) 3%, transparent)';
+const overviewSectionBorder = '1px solid color-mix(in oklab, var(--bl-border) 70%, transparent)';
+const overviewCardGradient = 'linear-gradient(145deg, color-mix(in oklab, var(--bl-surface-overlay) 92%, var(--card-elevated)), color-mix(in oklab, var(--bl-surface-overlay) 84%, var(--background)))';
+const overviewCardBorder = '1px solid color-mix(in oklab, var(--bl-border) 55%, transparent)';
+const overviewDivider = '1px solid color-mix(in oklab, var(--bl-border) 45%, transparent)';
+const overviewBotMuted = 'color-mix(in oklab, var(--muted-foreground) 62%, var(--background))';
+const overviewBotQuiet = 'color-mix(in oklab, var(--muted-foreground) 52%, var(--background))';
+const overviewTagBorder = '1px solid color-mix(in oklab, var(--bl-border) 82%, transparent)';
+
const formatUptime = (ms: number): string => {
if (ms < 60000) return `${Math.floor(ms / 1000)}s`;
@@ -569,9 +593,9 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
marginBottom: '12px',
padding: '8px 10px',
borderRadius: '8px',
- border: '1px solid rgba(251, 191, 36, 0.25)',
- background: 'rgba(251, 191, 36, 0.08)',
- color: '#fbbf24',
+ border: overviewWarningBorder,
+ background: overviewWarningSurface,
+ color: overviewWarningText,
fontSize: '0.75rem'
}}>
Canonical lifecycle is unavailable{canonicalLoading ? ' (loading)' : ''}. Showing fallback values from DB/runtime sources.
@@ -583,9 +607,9 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
marginBottom: '12px',
padding: '8px 10px',
borderRadius: '8px',
- border: '1px solid rgba(248, 113, 113, 0.28)',
- background: 'rgba(248, 113, 113, 0.08)',
- color: '#fca5a5',
+ border: overviewDangerBorder,
+ background: overviewDangerSurface,
+ color: overviewDangerText,
fontSize: '0.75rem'
}}>
Canonical lifecycle snapshot is truncated ({canonicalSnapshot.diagnostics.orderRows} rows). Narrow scope before using this for operational decisions.
@@ -593,7 +617,7 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
)}
-
+
Win Rate Window:
{WIN_RATE_WINDOW_OPTIONS.map((option) => {
@@ -603,9 +627,9 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
key={option.key}
onClick={() => setWinRateWindow(option.key)}
style={{
- border: active ? '1px solid rgba(0,255,136,0.45)' : '1px solid rgba(255,255,255,0.1)',
- color: active ? '#00ff88' : '#a1a1aa',
- background: active ? 'rgba(0,255,136,0.08)' : 'rgba(255,255,255,0.03)',
+ border: active ? overviewActiveBorder : overviewSoftBorder,
+ color: active ? overviewSuccessText : overviewQuietText,
+ background: active ? overviewActiveSurface : overviewMutedSurface,
borderRadius: '8px',
padding: '4px 8px',
fontSize: '0.7rem',
@@ -641,13 +665,13 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
Allocated:
{formatUsd(allocatedCapital)}
- {profileCount > 0 && ({profileCount} profiles)}
+ {profileCount > 0 && ({profileCount} profiles)}
Capital Used:
- {formatUsd(capitalUsed)}
+ {formatUsd(capitalUsed)}
{overAllocatedCapital > 1e-8 && (
-
+
capped (+{formatUsd(overAllocatedCapital)} raw)
)}
@@ -676,10 +700,10 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
Win Rate ({winRateWindowConfig.label}):
- = 50 ? '#4ade80' : '#fbbf24' }}>
+ = 50 ? overviewSuccessText : overviewWarningText }}>
{displayWindowAggregate.winRate.toFixed(1)}%
-
+
{displayWindowAggregate.tradeCount} trades
@@ -693,7 +717,7 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
>
{pnlWindow.durationLabel}
-
+
{pnlWindow.fromTs > 0
? `From ${new Date(pnlWindow.fromTs).toLocaleDateString()}`
: 'Awaiting trade history'}
@@ -702,7 +726,7 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
{/* --- NEW: Alpaca Account Health --- */}
-
+
Broker Balance (Alpaca):
@@ -711,7 +735,7 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
: 'Waiting for snapshot...'}
{botState.accountSnapshot && (
-
+
Cash: {formatUsd(botState.accountSnapshot.cash)} ({botState.accountSnapshot.currency})
)}
@@ -725,28 +749,28 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
)}
{/* Parity & Self-Healing Heartbeat */}
-
+
Parity Heartbeat:
{botState.health?.reconciliationParityMismatchTrades || 0} Mismatches
{Number(botState.health?.reconciliationParityAutoClosedTrades || 0) > 0 && (
-
+
({botState.health?.reconciliationParityAutoClosedTrades} Self-Healed)
)}
{Number(botState.health?.reconciliationParityQuarantinedTrades || 0) > 0 && (
-
+
({botState.health?.reconciliationParityQuarantinedTrades} Quarantined)
)}
{/* Recent Failures Summary */}
{(botState.orderFailures || []).length > 0 && (
-
-
Recent Rejections:
-
{(botState.orderFailures || []).length}
-
+
+ Recent Rejections:
+ {(botState.orderFailures || []).length}
+
Latest: {(botState.orderFailures || [])[0].symbol} ({(botState.orderFailures || [])[0].reason?.substring(0, 20)}...)
@@ -772,37 +796,37 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
profileCapitalRows.map((row) => {
const overAllocated = row.overAllocatedAmount > 1e-8;
const stateColor = row.runtimeTone === 'running'
- ? '#4ade80'
+ ? overviewSuccessText
: row.runtimeTone === 'cooldown'
- ? '#facc15'
+ ? overviewWarningText
: row.runtimeTone === 'armed'
- ? '#38bdf8'
+ ? overviewInfoText
: row.runtimeTone === 'blocked'
- ? '#f87171'
- : '#a1a1aa';
+ ? overviewDangerText
+ : overviewQuietText;
return (
| {row.name} |
{formatUsd(row.allocated)} |
- {formatUsd(row.used)} |
-
+ | {formatUsd(row.used)} |
+
{formatUsd(row.remaining)}
{overAllocated && (
-
+
raw +{formatUsd(row.overAllocatedAmount)}
)}
|
-
+ |
{row.utilizationPct.toFixed(1)}%
|
- = 50 ? '#4ade80' : '#fbbf24' }}>
+ | = 50 ? overviewSuccessText : overviewWarningText }}>
{row.winRate.toFixed(1)}%
-
+
({row.tradeCount})
|
- = 0 ? '#4ade80' : '#f87171' }}>
+ | = 0 ? overviewSuccessText : overviewDangerText }}>
{formatUsd(row.netPnl)}
|
@@ -810,7 +834,7 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
{row.runtimeState}
-
@@ -822,11 +846,11 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
|
| Account (Fallback) |
{formatUsd(allocatedCapital)} |
- {formatUsd(capitalUsed)} |
- 1e-8 ? '#f87171' : '#4ade80' }}>
+ | {formatUsd(capitalUsed)} |
+ 1e-8 ? overviewDangerText : overviewSuccessText }}>
{formatUsd(remainingCapital)}
{overAllocatedCapital > 1e-8 && (
-
+
raw +{formatUsd(overAllocatedCapital)}
)}
@@ -835,9 +859,9 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
{allocatedCapital > 0 ? ((capitalUsed / allocatedCapital) * 100).toFixed(1) : '0.0'}%
|
- |
- = 0 ? '#4ade80' : '#f87171' }}>{formatUsd(displayRealizedPnl)} |
+ = 0 ? overviewSuccessText : overviewDangerText }}>{formatUsd(displayRealizedPnl)} |
- No signal
+ No signal
|
)}
@@ -848,7 +872,7 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
{/* NEW: Recent Order Rejections List */}
{botState.orderFailures && botState.orderFailures.length > 0 && (
-
Recent Order Rejections
+
Recent Order Rejections
@@ -865,17 +889,17 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
{botState.orderFailures.slice(0, 10).map((fail, idx) => (
- | {new Date(fail.timestamp).toLocaleString()} |
+ {new Date(fail.timestamp).toLocaleString()} |
{fail.symbol} |
{fail.side} |
{fail.qty} |
-
+ |
{fail.reason}
|
-
+ |
{compactTag(fail.subTag)}
|
- {fail.profileId || 'Unknown'} |
+ {fail.profileId || 'Unknown'} |
))}
@@ -908,7 +932,7 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
{profileSignals.length > 0 && (
{profileSignals.map((ps, idx) => (
-
+
{(ps.profileName || `P${idx + 1}`)}: {ps.signal}
))}
@@ -943,18 +967,18 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
: 'NEUTRAL';
const directionLabel = bias4h === 'BULLISH' ? 'Uptrend' : bias4h === 'BEARISH' ? 'Downtrend' : 'Sideways';
- const directionColor = bias4h === 'BULLISH' ? '#00ff88' : bias4h === 'BEARISH' ? '#ff3366' : '#f59e0b';
+ const directionColor = bias4h === 'BULLISH' ? overviewSuccessText : bias4h === 'BEARISH' ? overviewDangerText : overviewAttentionText;
const rsi = data.indicators.rsi_1h || 50;
const momentumLabel = rsi > 60 ? 'Building strongly' : rsi > 50 ? 'Gaining' : rsi > 40 ? 'Neutral' : 'Fading';
- const momentumColor = rsi > 55 ? '#00ff88' : rsi > 45 ? '#f59e0b' : '#ff3366';
+ const momentumColor = rsi > 55 ? overviewSuccessText : rsi > 45 ? overviewAttentionText : overviewDangerText;
const sessionIsOff = data.session === 'OFF' || !data.session;
const sessionLabel = sessionIsOff ? 'Outside window' : 'Active now';
- const sessionColor = sessionIsOff ? '#555' : '#00ff88';
+ const sessionColor = sessionIsOff ? overviewBotMuted : overviewSuccessText;
const volLabel = data.volatility === 'HIGH' ? 'Very Active' : data.volatility === 'MEDIUM' ? 'Moderate' : data.volatility === 'LOW' ? 'Calm' : 'Normal';
- const volColor = data.volatility === 'HIGH' ? '#f59e0b' : data.volatility === 'MEDIUM' ? '#60a5fa' : '#a1a1aa';
+ const volColor = data.volatility === 'HIGH' ? overviewAttentionText : data.volatility === 'MEDIUM' ? overviewInfoText : overviewQuietText;
const botStatusEmoji = normalizedSignal === 'BUY' ? '📈' : normalizedSignal === 'SELL' ? '📉' : normalizedSignal === 'MIXED' ? '⚡' : '👀';
const botStatusLabel =
@@ -963,17 +987,17 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
normalizedSignal === 'MIXED' ? 'Conditions mixed — holding off' :
'Watching markets for the right setup';
const botStatusColor =
- normalizedSignal === 'BUY' ? '#00ff88' :
- normalizedSignal === 'SELL' ? '#ff3366' :
- normalizedSignal === 'MIXED' ? '#f59e0b' :
- '#555';
+ normalizedSignal === 'BUY' ? overviewSuccessText :
+ normalizedSignal === 'SELL' ? overviewDangerText :
+ normalizedSignal === 'MIXED' ? overviewAttentionText :
+ overviewBotMuted;
const change24h = data.change24h || 0;
return (
-
+
{symbol.split('/')[0]}
- /{symbol.split('/')[1] || 'USDT'}
+ /{symbol.split('/')[1] || 'USDT'}
-
= 0 ? '#00ff88' : '#ff3366', marginTop: '2px', fontFamily: 'monospace' }}>
+
= 0 ? overviewSuccessText : overviewDangerText, marginTop: '2px', fontFamily: 'monospace' }}>
{change24h >= 0 ? '+' : ''}{change24h.toFixed(2)}% today
@@ -1009,19 +1033,19 @@ export const OverviewTab = ({ botState, previewAsCustomer = false, connected = t
{ label: 'Market Activity', value: volLabel, color: volColor },
].map(({ label, value, color }) => (
))}
{/* Bot Status Footer */}
-
-
Bot Status
-
+
+
Bot Status
+
{botStatusLabel}