+
Intelligence Engine
New Analysis
Configure a multi-agent analysis run. Your AI team will research market data,
debate investment thesis, and deliver a structured decision.
diff --git a/ui/app/(dashboard)/runs/[id]/page.tsx b/ui/app/(dashboard)/runs/[id]/page.tsx
index 501b8ce2..4ea8b36e 100644
--- a/ui/app/(dashboard)/runs/[id]/page.tsx
+++ b/ui/app/(dashboard)/runs/[id]/page.tsx
@@ -7,11 +7,13 @@ import PhaseTabs from '@/features/run-detail/components/PhaseTabs'
import { getRun } from '@/lib/api-client'
import type { RunSummary } from '@/lib/types/run'
-const STATUS_CONFIG: Record = {
- connecting: { bg: 'var(--bg-elevated)', color: 'var(--text-mid)', dot: 'var(--text-low)', label: 'Connecting' },
- running: { bg: 'var(--hold-bg)', color: 'var(--hold)', dot: 'var(--hold)', label: 'Running' },
- complete: { bg: 'var(--buy-bg)', color: 'var(--buy)', dot: 'var(--buy)', label: 'Complete' },
- error: { bg: 'var(--error-bg)', color: 'var(--error)', dot: 'var(--error)', label: 'Error' },
+const STATUS_CONFIG: Record = {
+ connecting: { bg: 'var(--bg-elevated)', color: 'var(--text-mid)', dot: 'var(--text-low)', label: 'Connecting', pulse: false },
+ running: { bg: 'var(--hold-bg)', color: 'var(--hold)', dot: 'var(--hold)', label: 'Running', pulse: true },
+ complete: { bg: 'var(--buy-bg)', color: 'var(--buy)', dot: 'var(--buy)', label: 'Complete', pulse: false },
+ error: { bg: 'var(--error-bg)', color: 'var(--error)', dot: 'var(--error)', label: 'Error', pulse: false },
}
export default function RunDetailPage({ params }: { params: Promise<{ id: string }> }) {
@@ -29,51 +31,60 @@ export default function RunDetailPage({ params }: { params: Promise<{ id: string
{/* Header */}
-
+
-
+
Analysis Run
{run ? (
<>
- {run.ticker}
- ·
- {run.date}
+
+ {run.ticker}
+
+ ·
+
+ {run.date}
+
>
) : (
- Loading…
+ Loading…
)}
- {/* Status badge */}
+ {/* Status pill */}
- {sc.label}
+ {sc.label.toUpperCase()}
@@ -83,14 +94,14 @@ export default function RunDetailPage({ params }: { params: Promise<{ id: string
{/* Error */}
{error && (
- Error: {error}
+ Error: {error}
)}
@@ -101,7 +112,6 @@ export default function RunDetailPage({ params }: { params: Promise<{ id: string
{/* Phase tabs + reports */}
-
)
}
diff --git a/ui/app/globals.css b/ui/app/globals.css
index d371ca42..e33c72f6 100644
--- a/ui/app/globals.css
+++ b/ui/app/globals.css
@@ -1,57 +1,63 @@
@import "tailwindcss";
-/* ─── APEX Design Tokens ────────────────────────────────────────── */
+/* ─── OBSIDIAN Design Tokens ─────────────────────────────────────── */
:root {
/* Backgrounds */
- --bg-base: #040C1A;
- --bg-surface: #070F1C;
- --bg-card: #0C1628;
- --bg-elevated: #121E30;
- --bg-hover: #182338;
- --bg-active: #1E2E42;
- --bg-sidebar: #030810;
+ --bg-base: #050508;
+ --bg-surface: #08080F;
+ --bg-card: #0C0C18;
+ --bg-elevated: #111120;
+ --bg-hover: #17172A;
+ --bg-active: #1D1D38;
+ --bg-sidebar: #030306;
/* Borders */
- --border: rgba(82, 122, 196, 0.10);
- --border-raised: rgba(82, 122, 196, 0.18);
- --border-active: rgba(68, 128, 255, 0.40);
- --border-accent: rgba(68, 128, 255, 0.60);
+ --border: rgba(80, 80, 200, 0.07);
+ --border-raised: rgba(80, 80, 200, 0.14);
+ --border-active: rgba(0, 200, 240, 0.28);
+ --border-accent: rgba(0, 200, 240, 0.55);
/* Text */
- --text-high: #E0E8FF;
- --text-mid: #7A8FAD;
- --text-low: #354869;
- --text-faint: #1C2A40;
+ --text-high: #F0F2FF;
+ --text-mid: #525E80;
+ --text-low: #202840;
+ --text-faint: #0E1220;
- /* Accent Blue */
- --accent: #4480FF;
- --accent-light: #8AAFFF;
- --accent-dim: #1A3A88;
- --accent-glow: rgba(68, 128, 255, 0.14);
- --accent-glow2: rgba(68, 128, 255, 0.06);
+ /* Accent Cyan */
+ --accent: #00C4E8;
+ --accent-light: #65DAFF;
+ --accent-dim: #00243A;
+ --accent-glow: rgba(0, 196, 232, 0.14);
+ --accent-glow2: rgba(0, 196, 232, 0.05);
- /* Semantic */
- --buy: #00CE68;
- --buy-bg: rgba(0, 206, 104, 0.08);
- --buy-ring: rgba(0, 206, 104, 0.25);
- --sell: #FF3355;
- --sell-bg: rgba(255, 51, 85, 0.08);
- --sell-ring:rgba(255, 51, 85, 0.25);
- --hold: #F59E0B;
- --hold-bg: rgba(245, 158, 11, 0.08);
- --hold-ring:rgba(245, 158, 11, 0.25);
- --error: #FF4444;
- --error-bg: rgba(255, 68, 68, 0.08);
+ /* Gold (premium highlight) */
+ --gold: #FFB400;
+ --gold-bg: rgba(255, 180, 0, 0.07);
+ --gold-dim: #271D00;
+ --gold-ring: rgba(255, 180, 0, 0.25);
+
+ /* Semantic — BUY / SELL / HOLD */
+ --buy: #00E078;
+ --buy-bg: rgba(0, 224, 120, 0.07);
+ --buy-ring: rgba(0, 224, 120, 0.22);
+ --sell: #FF1F4C;
+ --sell-bg: rgba(255, 31, 76, 0.07);
+ --sell-ring: rgba(255, 31, 76, 0.22);
+ --hold: #FFB400;
+ --hold-bg: rgba(255, 180, 0, 0.07);
+ --hold-ring: rgba(255, 180, 0, 0.22);
+ --error: #FF2B3E;
+ --error-bg: rgba(255, 43, 62, 0.07);
/* Status */
- --status-running: #F59E0B;
- --status-done: #4480FF;
- --status-pending: #1C2A40;
+ --status-running: #FFB400;
+ --status-done: #00C4E8;
+ --status-pending: #141828;
}
-/* ─── Animations ─────────────────────────────────────────────────── */
+/* ─── Keyframes ──────────────────────────────────────────────────── */
@keyframes fadeUp {
- from { opacity: 0; transform: translateY(10px); }
+ from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
@@ -61,8 +67,8 @@
}
@keyframes shimmer {
- 0%, 100% { opacity: 0.35; }
- 50% { opacity: 0.9; }
+ 0%, 100% { opacity: 0.25; }
+ 50% { opacity: 1; }
}
@keyframes spin-slow {
@@ -70,8 +76,8 @@
}
@keyframes pulse-glow {
- 0%, 100% { box-shadow: 0 0 0 0 var(--accent-glow); }
- 50% { box-shadow: 0 0 0 6px var(--accent-glow); }
+ 0%, 100% { box-shadow: 0 0 0 0 var(--accent-glow); }
+ 50% { box-shadow: 0 0 0 8px var(--accent-glow); }
}
@keyframes scan-line {
@@ -79,6 +85,45 @@
to { transform: translateX(200%); }
}
+@keyframes float {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-6px); }
+}
+
+@keyframes glow-breathe {
+ 0%, 100% { opacity: 0.4; }
+ 50% { opacity: 1; }
+}
+
+@keyframes data-flicker {
+ 0%, 95%, 100% { opacity: 1; }
+ 96% { opacity: 0.6; }
+ 97% { opacity: 1; }
+ 98% { opacity: 0.75; }
+ 99% { opacity: 1; }
+}
+
+@keyframes verdict-reveal {
+ 0% { opacity: 0; transform: scale(0.88) translateY(10px); filter: blur(4px); }
+ 100% { opacity: 1; transform: scale(1) translateY(0); filter: blur(0); }
+}
+
+@keyframes orbit {
+ from { transform: rotate(0deg) translateX(24px) rotate(0deg); }
+ to { transform: rotate(360deg) translateX(24px) rotate(-360deg); }
+}
+
+@keyframes gradient-shift {
+ 0%, 100% { background-position: 0% 50%; }
+ 50% { background-position: 100% 50%; }
+}
+
+@keyframes step-complete {
+ 0% { transform: scale(0.5); opacity: 0; }
+ 60% { transform: scale(1.2); }
+ 100% { transform: scale(1); opacity: 1; }
+}
+
/* ─── Base ───────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
@@ -91,34 +136,68 @@ html, body {
font-feature-settings: "cv02", "cv03", "cv04", "cv11";
}
+/* ─── Background Textures ─────────────────────────────────────────── */
+.dot-grid {
+ background-image: radial-gradient(circle, rgba(100, 100, 255, 0.12) 1px, transparent 1px);
+ background-size: 24px 24px;
+}
+
+.mesh-bg {
+ background:
+ radial-gradient(ellipse 60% 40% at 20% 20%, rgba(0, 196, 232, 0.05) 0%, transparent 60%),
+ radial-gradient(ellipse 50% 60% at 80% 70%, rgba(80, 40, 200, 0.06) 0%, transparent 60%),
+ radial-gradient(ellipse 40% 50% at 50% 50%, rgba(255, 180, 0, 0.03) 0%, transparent 70%);
+}
+
/* ─── Typography ─────────────────────────────────────────────────── */
.apex-display {
- font-family: var(--font-manrope, 'Manrope'), sans-serif;
- font-weight: 700;
- letter-spacing: -0.03em;
+ font-family: var(--font-syne, 'Syne'), var(--font-manrope, 'Manrope'), sans-serif;
+ font-weight: 800;
+ letter-spacing: -0.04em;
color: var(--text-high);
}
.apex-label {
font-size: 10px;
- font-weight: 600;
- letter-spacing: 0.12em;
+ font-weight: 700;
+ letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--text-mid);
font-family: var(--font-manrope, 'Manrope'), sans-serif;
}
+.terminal-text {
+ font-family: var(--font-mono, 'JetBrains Mono'), 'Courier New', monospace;
+ font-feature-settings: "tnum";
+ font-variant-numeric: tabular-nums;
+}
+
+.gradient-text {
+ background: linear-gradient(135deg, var(--text-high) 0%, var(--accent-light) 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
/* ─── Cards ──────────────────────────────────────────────────────── */
.apex-card {
background: var(--bg-card);
border: 1px solid var(--border);
- border-radius: 10px;
+ border-radius: 12px;
}
.apex-card-elevated {
background: var(--bg-elevated);
border: 1px solid var(--border-raised);
- border-radius: 10px;
+ border-radius: 12px;
+}
+
+.glass-card {
+ background: rgba(12, 12, 28, 0.7);
+ backdrop-filter: blur(20px);
+ -webkit-backdrop-filter: blur(20px);
+ border: 1px solid var(--border-raised);
+ border-radius: 12px;
}
/* ─── Buttons ────────────────────────────────────────────────────── */
@@ -127,34 +206,36 @@ html, body {
overflow: hidden;
display: inline-flex;
align-items: center;
- gap: 6px;
+ gap: 7px;
background: var(--accent);
- color: #fff;
- font-weight: 600;
+ color: #020508;
+ font-weight: 700;
font-size: 13px;
- letter-spacing: 0.01em;
+ letter-spacing: 0.02em;
border-radius: 8px;
- padding: 9px 20px;
- transition: background 0.15s, opacity 0.15s, box-shadow 0.15s;
+ padding: 10px 22px;
+ transition: background 0.15s, opacity 0.15s, box-shadow 0.2s, transform 0.1s;
font-family: var(--font-manrope, 'Manrope'), sans-serif;
cursor: pointer;
}
-.btn-primary::after {
+.btn-primary::before {
content: '';
position: absolute;
inset: 0;
- background: linear-gradient(135deg, rgba(255,255,255,0.12) 0%, transparent 60%);
+ background: linear-gradient(135deg, rgba(255,255,255,0.18) 0%, transparent 55%);
pointer-events: none;
}
.btn-primary:hover {
- background: #5590FF;
- box-shadow: 0 4px 16px rgba(68,128,255,0.35);
+ background: #28DAFF;
+ box-shadow: 0 0 0 4px rgba(0, 196, 232, 0.18), 0 8px 24px rgba(0, 196, 232, 0.28);
+ transform: translateY(-1px);
}
-.btn-primary:active { opacity: 0.85; }
+.btn-primary:active { opacity: 0.85; transform: translateY(0); }
.btn-primary:disabled {
- opacity: 0.35;
+ opacity: 0.3;
cursor: not-allowed;
box-shadow: none;
+ transform: none;
}
.btn-secondary {
@@ -163,12 +244,12 @@ html, body {
gap: 6px;
background: var(--bg-elevated);
color: var(--text-mid);
- font-weight: 500;
+ font-weight: 600;
font-size: 13px;
border: 1px solid var(--border-raised);
border-radius: 8px;
- padding: 8px 16px;
- transition: background 0.15s, color 0.15s, border-color 0.15s;
+ padding: 9px 18px;
+ transition: background 0.15s, color 0.15s, border-color 0.15s, transform 0.1s;
font-family: var(--font-manrope, 'Manrope'), sans-serif;
cursor: pointer;
}
@@ -176,10 +257,29 @@ html, body {
background: var(--bg-hover);
color: var(--text-high);
border-color: var(--border-active);
+ transform: translateY(-1px);
+}
+.btn-ghost {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ background: var(--bg-elevated);
+ color: var(--text-mid);
+ font-weight: 600;
+ font-size: 13px;
+ border: 1px solid var(--border-raised);
+ border-radius: 8px;
+ padding: 9px 18px;
+ transition: background 0.15s, color 0.15s, border-color 0.15s, transform 0.1s;
+ font-family: var(--font-manrope, 'Manrope'), sans-serif;
+ cursor: pointer;
+}
+.btn-ghost:hover {
+ background: var(--bg-hover);
+ color: var(--text-high);
+ border-color: var(--border-active);
+ transform: translateY(-1px);
}
-
-/* backwards compat aliases */
-.btn-ghost { @apply btn-secondary; }
/* ─── Inputs ─────────────────────────────────────────────────────── */
.vault-input {
@@ -188,10 +288,10 @@ html, body {
color: var(--text-high);
font-size: 13px;
border: 1px solid var(--border-raised);
- border-radius: 6px;
- padding: 9px 12px;
+ border-radius: 8px;
+ padding: 10px 14px;
outline: none;
- transition: border-color 0.15s, background 0.15s, box-shadow 0.15s;
+ transition: border-color 0.15s, background 0.15s, box-shadow 0.2s;
font-family: var(--font-manrope, 'Manrope'), sans-serif;
}
.vault-input::placeholder { color: var(--text-low); }
@@ -202,15 +302,23 @@ html, body {
}
.vault-input option { background: var(--bg-elevated); }
+/* date input calendar icon color */
+.vault-input[type="date"]::-webkit-calendar-picker-indicator {
+ filter: invert(0.5) sepia(1) saturate(2) hue-rotate(180deg);
+ opacity: 0.5;
+ cursor: pointer;
+}
+
/* ─── Badges ─────────────────────────────────────────────────────── */
.badge-buy {
display: inline-flex; align-items: center;
background: var(--buy-bg);
color: var(--buy);
border: 1px solid var(--buy-ring);
- font-size: 11px; font-weight: 700;
- padding: 2px 9px; border-radius: 99px;
- letter-spacing: 0.04em;
+ font-size: 10px; font-weight: 800;
+ padding: 2px 10px; border-radius: 99px;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
font-family: var(--font-manrope, 'Manrope'), sans-serif;
}
.badge-sell {
@@ -218,9 +326,10 @@ html, body {
background: var(--sell-bg);
color: var(--sell);
border: 1px solid var(--sell-ring);
- font-size: 11px; font-weight: 700;
- padding: 2px 9px; border-radius: 99px;
- letter-spacing: 0.04em;
+ font-size: 10px; font-weight: 800;
+ padding: 2px 10px; border-radius: 99px;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
font-family: var(--font-manrope, 'Manrope'), sans-serif;
}
.badge-hold {
@@ -228,22 +337,40 @@ html, body {
background: var(--hold-bg);
color: var(--hold);
border: 1px solid var(--hold-ring);
- font-size: 11px; font-weight: 700;
- padding: 2px 9px; border-radius: 99px;
- letter-spacing: 0.04em;
+ font-size: 10px; font-weight: 800;
+ padding: 2px 10px; border-radius: 99px;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
font-family: var(--font-manrope, 'Manrope'), sans-serif;
}
+/* ─── Horizontal Rule ────────────────────────────────────────────── */
+.apex-rule {
+ height: 1px;
+ background: linear-gradient(90deg, transparent, var(--border-raised), transparent);
+ border: none;
+}
+
/* ─── Scrollbar ──────────────────────────────────────────────────── */
-::-webkit-scrollbar { width: 5px; height: 5px; }
+::-webkit-scrollbar { width: 4px; height: 4px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-raised); border-radius: 99px; }
::-webkit-scrollbar-thumb:hover { background: var(--border-active); }
/* ─── Selection ──────────────────────────────────────────────────── */
-::selection { background: var(--accent-glow); color: var(--text-high); }
+::selection { background: rgba(0, 196, 232, 0.20); color: var(--text-high); }
-/* ─── Fade animations for components ────────────────────────────── */
-.animate-fade-up { animation: fadeUp 0.3s ease-out both; }
-.animate-fade-in { animation: fadeIn 0.25s ease-out both; }
-.animate-shimmer { animation: shimmer 1.6s ease-in-out infinite; }
+/* ─── Animations ─────────────────────────────────────────────────── */
+.animate-fade-up { animation: fadeUp 0.35s cubic-bezier(0.16,1,0.3,1) both; }
+.animate-fade-in { animation: fadeIn 0.25s ease-out both; }
+.animate-shimmer { animation: shimmer 1.6s ease-in-out infinite; }
+.animate-float { animation: float 4s ease-in-out infinite; }
+.animate-glow { animation: glow-breathe 2.5s ease-in-out infinite; }
+.animate-flicker { animation: data-flicker 8s ease-in-out infinite; }
+
+/* Staggered fade-up delays */
+.delay-50 { animation-delay: 50ms; }
+.delay-100 { animation-delay: 100ms; }
+.delay-150 { animation-delay: 150ms; }
+.delay-200 { animation-delay: 200ms; }
+.delay-300 { animation-delay: 300ms; }
diff --git a/ui/app/layout.tsx b/ui/app/layout.tsx
index 176faeab..2b653e54 100644
--- a/ui/app/layout.tsx
+++ b/ui/app/layout.tsx
@@ -1,5 +1,5 @@
import type { Metadata } from 'next'
-import { Manrope, Inter } from 'next/font/google'
+import { Manrope, Syne, JetBrains_Mono } from 'next/font/google'
import './globals.css'
const manrope = Manrope({
@@ -8,15 +8,21 @@ const manrope = Manrope({
weight: ['400', '500', '600', '700', '800'],
})
-const inter = Inter({
- variable: '--font-inter',
+const syne = Syne({
+ variable: '--font-syne',
subsets: ['latin'],
- weight: ['400', '500', '600'],
+ weight: ['700', '800'],
+})
+
+const jetbrainsMono = JetBrains_Mono({
+ variable: '--font-mono',
+ subsets: ['latin'],
+ weight: ['400', '500', '600', '700'],
})
export const metadata: Metadata = {
- title: 'TradingAgents',
- description: 'Multi-agent trading analysis',
+ title: 'TradingAgents — Multi-Agent AI Analysis',
+ description: 'Institutional-grade multi-agent trading intelligence',
}
export default function RootLayout({
@@ -27,7 +33,7 @@ export default function RootLayout({
return (
{children}
diff --git a/ui/components/Sidebar.tsx b/ui/components/Sidebar.tsx
index d8d7a4a8..b796109f 100644
--- a/ui/components/Sidebar.tsx
+++ b/ui/components/Sidebar.tsx
@@ -6,31 +6,33 @@ const NAV = [
{
href: '/new-run',
label: 'New Analysis',
+ tag: 'RUN',
icon: (
-