d9ed625579
Replace all 13 occurrences of github.com/tonnylegacy/MT5_Optimizer with github.com/tonnylegacy/Apex_AI_MT5_EA_Optimizer across: - README.md (clone instructions) - SUBMISSION.md (GitHub URL field + checklist) - TODO_NEXT.md (next-session prompt) - PROJECT_HANDOFF.md (header + status table + footer) - docs/GETTING_STARTED.md (clone instructions, issue tracker link) - ui/templates/dashboard.html (Source on GitHub nav link) Also clean up the SUBMISSION.md Video/GIF block to list both the YouTube video and the in-README demo GIF. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2401 lines
87 KiB
HTML
2401 lines
87 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>APEX — AI-Powered EA Optimizer</title>
|
||
<link rel="icon" type="image/png" href="/static/img/favicon.png">
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||
<style>
|
||
/* ── CSS Variables ──────────────────────────────────────────── */
|
||
:root {
|
||
--bg: #080d1a;
|
||
--sidebar-bg: #0a0f1e;
|
||
--card-bg: #0f1629;
|
||
--card-hover: #131d35;
|
||
--border: rgba(255,255,255,0.07);
|
||
--border-hover: rgba(255,255,255,0.14);
|
||
--brand-cyan: #00d4ff;
|
||
--brand-blue: #4f6cff;
|
||
--brand-purple: #9333ea;
|
||
--accent: #4f6cff;
|
||
--accent2: #8b5cf6;
|
||
--teal: #00d4aa;
|
||
--text: #e2e8f0;
|
||
--muted: #64748b;
|
||
--green: #10b981;
|
||
--red: #ef4444;
|
||
--yellow: #f59e0b;
|
||
--nav-active-bg: rgba(79,108,255,0.18);
|
||
--nav-active-border: #4f6cff;
|
||
}
|
||
|
||
/* ── Reset ──────────────────────────────────────────────────── */
|
||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||
|
||
body {
|
||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||
background: var(--bg);
|
||
color: var(--text);
|
||
height: 100vh;
|
||
overflow: hidden;
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
/* ── App shell ──────────────────────────────────────────────── */
|
||
.app-shell {
|
||
display: flex;
|
||
height: 100vh;
|
||
}
|
||
|
||
/* ══════════════════════════════════════════════════════════════
|
||
SIDEBAR
|
||
══════════════════════════════════════════════════════════════ */
|
||
.sidebar {
|
||
width: 220px;
|
||
flex-shrink: 0;
|
||
background: var(--sidebar-bg);
|
||
border-right: 1px solid var(--border);
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding: 1.25rem 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* Logo */
|
||
.logo-wrap {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.65rem;
|
||
padding: 0 1.25rem 1.25rem;
|
||
border-bottom: 1px solid var(--border);
|
||
margin-bottom: 0.75rem;
|
||
}
|
||
.logo-mark,
|
||
.cmd-mark {
|
||
display: block;
|
||
flex-shrink: 0;
|
||
filter: drop-shadow(0 0 10px rgba(79,108,255,0.3));
|
||
}
|
||
.logo-text {
|
||
font-size: 1.25rem;
|
||
font-weight: 800;
|
||
letter-spacing: 0.12em;
|
||
background: linear-gradient(180deg, #ffffff 0%, #d4dae6 100%);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
.logo-tagline {
|
||
font-size: 0.58rem;
|
||
color: var(--muted);
|
||
font-weight: 600;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
display: block;
|
||
line-height: 1;
|
||
margin-top: 2px;
|
||
-webkit-text-fill-color: var(--muted);
|
||
}
|
||
|
||
/* Nav */
|
||
.sidebar-nav {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1px;
|
||
padding: 0.25rem 0;
|
||
}
|
||
.nav-section-label {
|
||
font-size: 0.6rem;
|
||
font-weight: 700;
|
||
letter-spacing: 0.1em;
|
||
text-transform: uppercase;
|
||
color: var(--muted);
|
||
padding: 0.75rem 1.25rem 0.35rem;
|
||
}
|
||
.nav-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.7rem;
|
||
padding: 0.6rem 1.25rem;
|
||
color: var(--muted);
|
||
text-decoration: none;
|
||
font-size: 0.83rem;
|
||
font-weight: 500;
|
||
transition: all 0.15s ease;
|
||
border-left: 2px solid transparent;
|
||
position: relative;
|
||
}
|
||
.nav-item svg { flex-shrink: 0; }
|
||
.nav-item:hover {
|
||
color: var(--text);
|
||
background: rgba(255,255,255,0.04);
|
||
}
|
||
.nav-item.active {
|
||
color: var(--text);
|
||
background: var(--nav-active-bg);
|
||
border-left-color: var(--accent);
|
||
}
|
||
.nav-item.active svg { color: var(--accent2); }
|
||
.nav-badge {
|
||
margin-left: auto;
|
||
background: var(--accent);
|
||
color: white;
|
||
font-size: 0.6rem;
|
||
font-weight: 700;
|
||
padding: 0.1rem 0.4rem;
|
||
border-radius: 999px;
|
||
min-width: 18px;
|
||
text-align: center;
|
||
}
|
||
|
||
/* Sidebar footer */
|
||
.sidebar-footer {
|
||
padding: 1rem 1.25rem 0;
|
||
border-top: 1px solid var(--border);
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.75rem;
|
||
}
|
||
.mt5-status {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.6rem;
|
||
}
|
||
.mt5-dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
background: var(--green);
|
||
box-shadow: 0 0 8px var(--green);
|
||
animation: pulse-dot 2s ease-in-out infinite;
|
||
flex-shrink: 0;
|
||
}
|
||
.mt5-dot.disconnected {
|
||
background: var(--red);
|
||
box-shadow: 0 0 8px var(--red);
|
||
animation: none;
|
||
}
|
||
@keyframes pulse-dot {
|
||
0%, 100% { opacity: 1; box-shadow: 0 0 8px var(--green); }
|
||
50% { opacity: 0.6; box-shadow: 0 0 4px var(--green); }
|
||
}
|
||
.mt5-label { font-size: 0.68rem; color: var(--muted); font-weight: 500; }
|
||
.mt5-state { font-size: 0.75rem; color: var(--text); font-weight: 600; }
|
||
.mt5-brand {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
font-size: 0.7rem;
|
||
color: var(--muted);
|
||
}
|
||
|
||
/* ══════════════════════════════════════════════════════════════
|
||
MAIN CONTENT
|
||
══════════════════════════════════════════════════════════════ */
|
||
.main-content {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
padding: 1.25rem 1.5rem 1.5rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.85rem;
|
||
scrollbar-width: thin;
|
||
scrollbar-color: rgba(255,255,255,0.1) transparent;
|
||
}
|
||
.main-content::-webkit-scrollbar { width: 5px; }
|
||
.main-content::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 999px; }
|
||
|
||
/* ── Command Header ──────────────────────────────────────── */
|
||
.cmd-header {
|
||
display: flex;
|
||
align-items: center;
|
||
background: var(--card-bg);
|
||
border: 1px solid rgba(79,70,229,0.28);
|
||
border-radius: 14px;
|
||
padding: 0.7rem 1.25rem;
|
||
flex-shrink: 0;
|
||
position: relative;
|
||
overflow: hidden;
|
||
gap: 0;
|
||
}
|
||
.cmd-header::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0; left: 0; right: 0; height: 1px;
|
||
background: linear-gradient(90deg, rgba(0,212,255,0.55), rgba(79,108,255,0.65), rgba(147,51,234,0.55));
|
||
}
|
||
.cmd-logo {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.6rem;
|
||
flex-shrink: 0;
|
||
}
|
||
.cmd-logo-text {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.05rem;
|
||
}
|
||
.cmd-apex {
|
||
font-size: 1.05rem;
|
||
font-weight: 800;
|
||
letter-spacing: 0.14em;
|
||
background: linear-gradient(180deg, #ffffff 0%, #d4dae6 100%);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
.cmd-tagline {
|
||
font-size: 0.5rem;
|
||
font-weight: 700;
|
||
letter-spacing: 0.18em;
|
||
text-transform: uppercase;
|
||
display: inline-flex;
|
||
gap: 0.35em;
|
||
}
|
||
.cmd-tagline .tag-cyan { color: #00d4ff; }
|
||
.cmd-tagline .tag-purple { color: #b06bff; }
|
||
.cmd-tagline .tag-white { color: #cfd5e0; }
|
||
.cmd-sep {
|
||
width: 1px;
|
||
height: 30px;
|
||
background: var(--border);
|
||
margin: 0 1.1rem;
|
||
flex-shrink: 0;
|
||
}
|
||
.cmd-section {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.12rem;
|
||
}
|
||
.cmd-gen-section { min-width: 145px; }
|
||
.cmd-status-row { display: flex; align-items: center; gap: 0.4rem; }
|
||
.cmd-status-dot {
|
||
width: 8px; height: 8px;
|
||
border-radius: 50%;
|
||
background: var(--muted);
|
||
flex-shrink: 0;
|
||
transition: background 0.3s, box-shadow 0.3s;
|
||
}
|
||
.cmd-status-dot.running {
|
||
background: var(--green);
|
||
box-shadow: 0 0 8px rgba(16,185,129,0.6);
|
||
animation: pulse-dot 1.5s ease-in-out infinite;
|
||
}
|
||
.cmd-status-label {
|
||
font-size: 0.82rem;
|
||
font-weight: 600;
|
||
color: var(--text);
|
||
white-space: nowrap;
|
||
}
|
||
.cmd-section-sub { font-size: 0.66rem; color: var(--muted); white-space: nowrap; }
|
||
.cmd-gen-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 0.5rem;
|
||
}
|
||
.cmd-gen-label {
|
||
font-size: 0.61rem;
|
||
font-weight: 700;
|
||
color: var(--muted);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.07em;
|
||
}
|
||
.cmd-gen-val {
|
||
font-size: 0.8rem;
|
||
font-weight: 700;
|
||
color: var(--text);
|
||
font-family: 'JetBrains Mono', monospace;
|
||
}
|
||
.cmd-gen-sep { color: var(--muted); margin: 0 0.1rem; font-weight: 400; }
|
||
.cmd-prog-track {
|
||
width: 100%;
|
||
height: 3px;
|
||
background: rgba(255,255,255,0.07);
|
||
border-radius: 999px;
|
||
overflow: hidden;
|
||
margin: 0.12rem 0;
|
||
}
|
||
.cmd-prog-fill {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, #00d4ff, #4f6cff, #9333ea);
|
||
border-radius: 999px;
|
||
transition: width 0.5s ease;
|
||
}
|
||
.cmd-pct-label { font-size: 0.61rem; color: var(--muted); }
|
||
.cmd-score-label {
|
||
font-size: 0.61rem;
|
||
font-weight: 700;
|
||
color: var(--muted);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.07em;
|
||
}
|
||
.cmd-score-val {
|
||
font-size: 0.98rem;
|
||
font-weight: 700;
|
||
color: var(--teal);
|
||
font-family: 'JetBrains Mono', monospace;
|
||
}
|
||
.cmd-score-delta { font-size: 0.62rem; color: var(--muted); }
|
||
.cmd-spacer { flex: 1; }
|
||
.cmd-actions { display: flex; align-items: center; gap: 0.45rem; flex-shrink: 0; }
|
||
.cmd-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.35rem;
|
||
padding: 0.45rem 0.85rem;
|
||
border-radius: 8px;
|
||
font-size: 0.76rem;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
border: 1px solid transparent;
|
||
font-family: inherit;
|
||
transition: all 0.15s;
|
||
text-decoration: none;
|
||
white-space: nowrap;
|
||
}
|
||
.cmd-btn-start {
|
||
background: linear-gradient(135deg, #4f6cff 0%, #9333ea 100%);
|
||
color: white;
|
||
box-shadow: 0 0 0 1px rgba(147,51,234,0.4), 0 4px 14px rgba(79,108,255,0.25);
|
||
}
|
||
.cmd-btn-start:hover { opacity: 0.88; }
|
||
.cmd-btn-pause {
|
||
background: rgba(245,158,11,0.1);
|
||
border-color: rgba(245,158,11,0.25);
|
||
color: var(--yellow);
|
||
opacity: 0.4;
|
||
pointer-events: none;
|
||
}
|
||
.cmd-btn-pause.active { opacity: 1; pointer-events: auto; }
|
||
.cmd-btn-pause.active:hover { background: rgba(245,158,11,0.18); }
|
||
.cmd-btn-stop {
|
||
background: rgba(100,116,139,0.08);
|
||
border-color: rgba(100,116,139,0.2);
|
||
color: var(--muted);
|
||
opacity: 0.4;
|
||
pointer-events: none;
|
||
}
|
||
.cmd-btn-stop.active {
|
||
background: rgba(239,68,68,0.12);
|
||
border-color: rgba(239,68,68,0.35);
|
||
color: var(--red);
|
||
opacity: 1;
|
||
pointer-events: auto;
|
||
}
|
||
.cmd-btn-stop.active:hover { background: rgba(239,68,68,0.22); }
|
||
/* keep run-indicator wiring for JS compat, always hidden */
|
||
#run-indicator { display: none !important; }
|
||
|
||
/* ── Metric cards row ────────────────────────────────────── */
|
||
.metrics-row {
|
||
display: grid;
|
||
grid-template-columns: repeat(6, minmax(0, 1fr));
|
||
gap: 0.7rem;
|
||
flex-shrink: 0;
|
||
}
|
||
.metric-card {
|
||
background: var(--card-bg);
|
||
border: 1px solid var(--border);
|
||
border-radius: 12px;
|
||
padding: 0.9rem 1rem;
|
||
transition: border-color 0.2s, transform 0.15s;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.metric-card::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0; left: 0; right: 0;
|
||
height: 2px;
|
||
background: linear-gradient(90deg, #00d4ff, #4f6cff, #9333ea);
|
||
opacity: 0;
|
||
transition: opacity 0.2s;
|
||
}
|
||
.metric-card:hover { border-color: var(--border-hover); }
|
||
.metric-card:hover::before { opacity: 1; }
|
||
.metric-label { font-size: 0.68rem; color: var(--muted); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; margin-bottom: 0.3rem; }
|
||
.metric-value { font-size: 1.35rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1.1; }
|
||
.metric-value.green { color: var(--green); }
|
||
.metric-value.red { color: var(--red); }
|
||
.metric-value.gold { color: var(--yellow); }
|
||
.metric-value.teal { color: var(--teal); }
|
||
.metric-value.white { color: var(--text); }
|
||
.metric-delta {
|
||
font-size: 0.7rem;
|
||
color: var(--muted);
|
||
margin-top: 0.2rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.2rem;
|
||
}
|
||
.delta-up { color: var(--green); }
|
||
.delta-down { color: var(--red); }
|
||
.sparkline-wrap {
|
||
margin-top: 0.55rem;
|
||
}
|
||
|
||
/* AI Confidence card */
|
||
.ai-conf-card { display: flex; flex-direction: column; }
|
||
.ai-conf-value {
|
||
font-size: 0.95rem;
|
||
font-weight: 700;
|
||
color: var(--text);
|
||
margin-top: 0.15rem;
|
||
}
|
||
.ai-gauge-wrap {
|
||
margin-top: 0.45rem;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
/* ── Charts + AI panel row ───────────────────────────────── */
|
||
.charts-ai-row {
|
||
display: grid;
|
||
grid-template-columns: 2fr 1fr;
|
||
gap: 0.7rem;
|
||
flex-shrink: 0;
|
||
}
|
||
.charts-col {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.7rem;
|
||
}
|
||
|
||
/* Card base */
|
||
.card {
|
||
background: var(--card-bg);
|
||
border: 1px solid var(--border);
|
||
border-radius: 12px;
|
||
padding: 1rem 1.25rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 0.6rem;
|
||
flex-shrink: 0;
|
||
}
|
||
.card-title {
|
||
font-size: 0.82rem;
|
||
font-weight: 600;
|
||
color: var(--text);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
.card-title .dot {
|
||
width: 7px; height: 7px; border-radius: 50%;
|
||
background: var(--teal);
|
||
}
|
||
.card-badge {
|
||
font-size: 0.65rem;
|
||
font-weight: 600;
|
||
padding: 0.15rem 0.5rem;
|
||
border-radius: 999px;
|
||
background: rgba(0,212,170,0.12);
|
||
color: var(--teal);
|
||
}
|
||
.chart-wrap {
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.chart-wrap canvas {
|
||
position: absolute !important;
|
||
inset: 0;
|
||
width: 100% !important;
|
||
height: 100% !important;
|
||
}
|
||
.equity-chart-wrap { height: 165px; }
|
||
.drawdown-chart-wrap { height: 100px; }
|
||
|
||
/* ── AI Summary panel ────────────────────────────────────── */
|
||
.ai-panel-col {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.ai-panel-card {
|
||
background: var(--card-bg);
|
||
border: 1px solid rgba(79,70,229,0.3);
|
||
border-radius: 12px;
|
||
padding: 1rem 1.25rem;
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.75rem;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.ai-panel-card::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0; left: 0; right: 0; height: 1px;
|
||
background: linear-gradient(90deg, transparent, rgba(124,109,250,0.6), transparent);
|
||
}
|
||
.ai-panel-card::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: -80px; right: -80px;
|
||
width: 200px; height: 200px;
|
||
background: radial-gradient(circle, rgba(79,70,229,0.06) 0%, transparent 70%);
|
||
pointer-events: none;
|
||
}
|
||
.ai-panel-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
}
|
||
.ai-panel-title {
|
||
font-size: 0.82rem;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
}
|
||
.ai-icon {
|
||
color: var(--accent2);
|
||
font-size: 0.9rem;
|
||
}
|
||
.view-details-link {
|
||
font-size: 0.72rem;
|
||
color: var(--accent2);
|
||
text-decoration: none;
|
||
transition: opacity 0.15s;
|
||
}
|
||
.view-details-link:hover { opacity: 0.7; }
|
||
.ai-waiting {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex: 1;
|
||
gap: 0.75rem;
|
||
color: var(--muted);
|
||
font-size: 0.78rem;
|
||
}
|
||
.ai-pulse-dot {
|
||
width: 32px; height: 32px;
|
||
border-radius: 50%;
|
||
border: 2px solid rgba(124,109,250,0.4);
|
||
position: relative;
|
||
animation: ai-spin 2s linear infinite;
|
||
}
|
||
.ai-pulse-dot::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 4px; left: 4px; right: 4px; bottom: 4px;
|
||
border-radius: 50%;
|
||
background: rgba(124,109,250,0.3);
|
||
animation: ai-pulse 2s ease-in-out infinite;
|
||
}
|
||
@keyframes ai-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
||
@keyframes ai-pulse { 0%,100% { opacity: 0.4; } 50% { opacity: 1; } }
|
||
|
||
.ai-content { display: flex; flex-direction: column; gap: 0.65rem; overflow-y: auto; flex: 1; }
|
||
.ai-content::-webkit-scrollbar { width: 3px; }
|
||
.ai-content::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 999px; }
|
||
.ai-headline {
|
||
font-size: 0.82rem;
|
||
font-weight: 600;
|
||
color: var(--text);
|
||
line-height: 1.4;
|
||
padding-bottom: 0.5rem;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.ai-diagnosis { font-size: 0.78rem; line-height: 1.7; color: #94a3b8; }
|
||
.ai-sub-title {
|
||
font-size: 0.65rem;
|
||
font-weight: 700;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.09em;
|
||
color: var(--muted);
|
||
margin-bottom: 0.35rem;
|
||
}
|
||
.ai-sub-title.warn { color: #f59e0b; }
|
||
.ai-check-list { list-style: none; display: flex; flex-direction: column; gap: 0.3rem; }
|
||
.ai-check-list li {
|
||
font-size: 0.76rem;
|
||
color: var(--text);
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 0.45rem;
|
||
line-height: 1.4;
|
||
}
|
||
.ai-check-list li::before { content: "✓"; color: var(--green); font-weight: 700; flex-shrink: 0; margin-top: 0.05em; }
|
||
.ai-warn-list { list-style: none; display: flex; flex-direction: column; gap: 0.3rem; }
|
||
.ai-warn-list li {
|
||
font-size: 0.76rem;
|
||
color: #fbbf24;
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 0.45rem;
|
||
line-height: 1.4;
|
||
}
|
||
.ai-warn-list li::before { content: "⚠"; flex-shrink: 0; margin-top: 0.05em; font-size: 0.7rem; }
|
||
.ai-suggestion-box {
|
||
background: rgba(79,70,229,0.1);
|
||
border: 1px solid rgba(79,70,229,0.22);
|
||
border-radius: 8px;
|
||
padding: 0.7rem 0.75rem;
|
||
position: relative;
|
||
}
|
||
.ai-suggestion-text { font-size: 0.76rem; color: var(--text); line-height: 1.55; padding-right: 1.5rem; }
|
||
.ai-badge {
|
||
position: absolute;
|
||
top: 0.45rem;
|
||
right: 0.45rem;
|
||
background: var(--accent);
|
||
color: white;
|
||
font-size: 0.58rem;
|
||
font-weight: 700;
|
||
padding: 0.1rem 0.35rem;
|
||
border-radius: 4px;
|
||
letter-spacing: 0.04em;
|
||
}
|
||
.ai-confidence-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.6rem;
|
||
margin-top: auto;
|
||
padding-top: 0.5rem;
|
||
border-top: 1px solid var(--border);
|
||
flex-shrink: 0;
|
||
}
|
||
.ai-conf-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.3rem;
|
||
padding: 0.2rem 0.6rem;
|
||
border-radius: 6px;
|
||
font-size: 0.7rem;
|
||
font-weight: 600;
|
||
text-transform: capitalize;
|
||
}
|
||
.ai-conf-badge::before { content: '●'; font-size: 0.5rem; }
|
||
.ai-conf-badge.high { background: rgba(16,185,129,0.15); color: #10b981; }
|
||
.ai-conf-badge.medium { background: rgba(245,158,11,0.15); color: #f59e0b; }
|
||
.ai-conf-badge.low { background: rgba(239,68,68,0.15); color: #ef4444; }
|
||
.ai-run-ref { font-size: 0.68rem; color: var(--muted); margin-left: auto; font-family: 'JetBrains Mono', monospace; }
|
||
|
||
/* ── Bottom row ──────────────────────────────────────────── */
|
||
.bottom-row {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 0.7rem;
|
||
flex-shrink: 0;
|
||
}
|
||
.bottom-card {
|
||
background: var(--card-bg);
|
||
border: 1px solid var(--border);
|
||
border-radius: 12px;
|
||
padding: 0.9rem 1rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.bottom-card-title {
|
||
font-size: 0.8rem;
|
||
font-weight: 600;
|
||
margin-bottom: 0.6rem;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
}
|
||
.view-all-link {
|
||
font-size: 0.7rem;
|
||
color: var(--accent2);
|
||
text-decoration: none;
|
||
font-weight: 500;
|
||
}
|
||
.view-all-link:hover { opacity: 0.75; }
|
||
|
||
/* Tables */
|
||
.params-table, .runs-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: 0.76rem;
|
||
}
|
||
.params-table th, .runs-table th {
|
||
color: var(--muted);
|
||
font-size: 0.64rem;
|
||
font-weight: 700;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.07em;
|
||
padding: 0.3rem 0.5rem;
|
||
border-bottom: 1px solid var(--border);
|
||
text-align: left;
|
||
}
|
||
.params-table td, .runs-table td {
|
||
padding: 0.38rem 0.5rem;
|
||
border-bottom: 1px solid rgba(255,255,255,0.03);
|
||
vertical-align: middle;
|
||
}
|
||
.params-table tr:last-child td, .runs-table tr:last-child td { border-bottom: none; }
|
||
.params-table tr:hover td, .runs-table tr:hover td { background: rgba(255,255,255,0.02); }
|
||
.param-name { font-family: 'JetBrains Mono', monospace; font-size: 0.7rem; color: var(--text); }
|
||
.param-val { font-family: 'JetBrains Mono', monospace; font-size: 0.72rem; color: var(--teal); font-weight: 600; }
|
||
.impact-high { display: inline-block; background: rgba(16,185,129,0.15); color: var(--green); padding: 0.08rem 0.4rem; border-radius: 4px; font-size: 0.64rem; font-weight: 700; }
|
||
.impact-medium { display: inline-block; background: rgba(245,158,11,0.15); color: var(--yellow); padding: 0.08rem 0.4rem; border-radius: 4px; font-size: 0.64rem; font-weight: 700; }
|
||
.impact-low { display: inline-block; background: rgba(100,116,139,0.15); color: var(--muted); padding: 0.08rem 0.4rem; border-radius: 4px; font-size: 0.64rem; font-weight: 700; }
|
||
.verdict-recommended { display: inline-block; background: rgba(16,185,129,0.15); color: var(--green); padding: 0.08rem 0.45rem; border-radius: 4px; font-size: 0.64rem; font-weight: 700; }
|
||
.verdict-risky { display: inline-block; background: rgba(245,158,11,0.15); color: var(--yellow); padding: 0.08rem 0.45rem; border-radius: 4px; font-size: 0.64rem; font-weight: 700; }
|
||
.verdict-not-reliable { display: inline-block; background: rgba(239,68,68,0.15); color: var(--red); padding: 0.08rem 0.45rem; border-radius: 4px; font-size: 0.64rem; font-weight: 700; }
|
||
.empty-state { color: var(--muted); font-size: 0.76rem; padding: 0.65rem 0.5rem; }
|
||
.run-num { font-family: 'JetBrains Mono', monospace; font-size: 0.7rem; color: var(--muted); }
|
||
.profit-pos { color: var(--green); font-weight: 600; }
|
||
.profit-neg { color: var(--red); font-weight: 600; }
|
||
|
||
/* Optimization progress */
|
||
.opt-gen-label {
|
||
font-size: 0.75rem;
|
||
color: var(--muted);
|
||
font-family: 'JetBrains Mono', monospace;
|
||
margin-bottom: 0.45rem;
|
||
}
|
||
.opt-progress-bar-track {
|
||
height: 5px;
|
||
background: rgba(255,255,255,0.06);
|
||
border-radius: 999px;
|
||
overflow: hidden;
|
||
margin-bottom: 0.65rem;
|
||
}
|
||
.opt-progress-bar-fill {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, var(--accent), var(--teal));
|
||
border-radius: 999px;
|
||
transition: width 0.6s ease;
|
||
width: 0%;
|
||
}
|
||
.opt-stats-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr 1fr;
|
||
gap: 0.5rem;
|
||
}
|
||
.opt-stat { }
|
||
.opt-stat-label { font-size: 0.63rem; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; }
|
||
.opt-stat-val { font-size: 0.8rem; color: var(--text); font-weight: 600; margin-top: 0.15rem; }
|
||
|
||
/* Phase steps */
|
||
.phase-steps {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-top: 0.6rem;
|
||
gap: 0;
|
||
}
|
||
.phase-step {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 0.3rem;
|
||
flex: 1;
|
||
position: relative;
|
||
}
|
||
.phase-dot {
|
||
width: 24px; height: 24px;
|
||
border-radius: 50%;
|
||
border: 2px solid rgba(255,255,255,0.1);
|
||
background: var(--bg);
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 0.65rem;
|
||
font-weight: 700;
|
||
color: var(--muted);
|
||
transition: all 0.35s;
|
||
z-index: 1;
|
||
}
|
||
.phase-name { font-size: 0.6rem; color: var(--muted); font-weight: 500; text-align: center; }
|
||
.phase-connector {
|
||
flex: 1;
|
||
height: 2px;
|
||
background: rgba(255,255,255,0.07);
|
||
margin-top: -14px;
|
||
}
|
||
.phase-step.active .phase-dot { border-color: var(--teal); color: var(--teal); background: rgba(0,212,170,0.1); box-shadow: 0 0 10px rgba(0,212,170,0.25); }
|
||
.phase-step.active .phase-name { color: var(--teal); }
|
||
.phase-step.done .phase-dot { border-color: var(--teal); background: var(--teal); color: #051a14; }
|
||
.phase-step.done .phase-name { color: var(--text); }
|
||
|
||
/* ── Live log ────────────────────────────────────────────── */
|
||
.log-panel {
|
||
flex-shrink: 0;
|
||
}
|
||
.log-toggle-btn {
|
||
width: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0.5rem 1rem;
|
||
background: var(--card-bg);
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
font-size: 0.75rem;
|
||
color: var(--muted);
|
||
font-weight: 500;
|
||
transition: all 0.15s;
|
||
}
|
||
.log-toggle-btn:hover { color: var(--text); border-color: var(--border-hover); }
|
||
.log-toggle-icon { transition: transform 0.2s; }
|
||
.log-toggle-icon.open { transform: rotate(180deg); }
|
||
.log-body {
|
||
display: none;
|
||
margin-top: 0.35rem;
|
||
background: var(--card-bg);
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
}
|
||
.log-body.open { display: block; }
|
||
.log-feed {
|
||
height: 120px;
|
||
overflow-y: auto;
|
||
padding: 0.6rem 0.75rem;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: 0.7rem;
|
||
line-height: 1.7;
|
||
color: #64748b;
|
||
scrollbar-width: thin;
|
||
scrollbar-color: rgba(255,255,255,0.06) transparent;
|
||
}
|
||
.log-feed::-webkit-scrollbar { width: 3px; }
|
||
.log-line { display: flex; gap: 0.6rem; }
|
||
.log-time { color: rgba(100,116,139,0.6); flex-shrink: 0; }
|
||
.log-line.info .log-msg { color: #94a3b8; }
|
||
.log-line.success .log-msg { color: var(--green); }
|
||
.log-line.warn .log-msg { color: var(--yellow); }
|
||
.log-line.error .log-msg { color: var(--red); }
|
||
|
||
/* ── Verdict overlay ─────────────────────────────────────── */
|
||
.verdict-overlay {
|
||
position: fixed; inset: 0;
|
||
background: rgba(0,0,0,0.75);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 200;
|
||
backdrop-filter: blur(5px);
|
||
}
|
||
.verdict-card {
|
||
background: var(--card-bg);
|
||
border: 1px solid var(--border);
|
||
border-radius: 20px;
|
||
padding: 2.25rem 2.5rem;
|
||
max-width: 580px;
|
||
width: 92%;
|
||
animation: popIn 0.4s cubic-bezier(0.34,1.56,0.64,1) both;
|
||
}
|
||
@keyframes popIn {
|
||
from { opacity: 0; transform: scale(0.88) translateY(20px); }
|
||
to { opacity: 1; transform: scale(1) translateY(0); }
|
||
}
|
||
.verdict-header-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1.25rem;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
.verdict-icon-big { font-size: 2.5rem; line-height: 1; }
|
||
.verdict-title {
|
||
font-size: 1.5rem;
|
||
font-weight: 800;
|
||
letter-spacing: -0.02em;
|
||
}
|
||
.verdict-subtitle { font-size: 0.85rem; color: var(--muted); margin-top: 0.25rem; line-height: 1.5; }
|
||
.verdict-metrics-row {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 1rem;
|
||
padding: 1.25rem 0;
|
||
border-top: 1px solid var(--border);
|
||
border-bottom: 1px solid var(--border);
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
.vm { text-align: center; }
|
||
.vm-val { font-size: 1.1rem; font-weight: 700; }
|
||
.vm-lbl { font-size: 0.68rem; color: var(--muted); margin-top: 0.2rem; font-weight: 500; }
|
||
.verdict-actions-row {
|
||
display: flex;
|
||
gap: 0.65rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
.verdict-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
padding: 0.6rem 1.1rem;
|
||
border-radius: 8px;
|
||
font-size: 0.82rem;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
text-decoration: none;
|
||
font-family: inherit;
|
||
border: 1px solid transparent;
|
||
transition: all 0.15s;
|
||
}
|
||
.verdict-btn.primary { background: linear-gradient(135deg, var(--accent), var(--accent2)); color: white; }
|
||
.verdict-btn.primary:hover { opacity: 0.88; }
|
||
.verdict-btn.secondary { background: rgba(255,255,255,0.06); border-color: var(--border); color: var(--text); }
|
||
.verdict-btn.secondary:hover { background: rgba(255,255,255,0.1); }
|
||
.verdict-btn.ghost { background: transparent; border-color: rgba(255,255,255,0.1); color: var(--muted); }
|
||
.verdict-btn.ghost:hover { color: var(--text); }
|
||
|
||
/* ── Settings Modal ─────────────────────────────────────── */
|
||
.settings-overlay {
|
||
position: fixed; inset: 0;
|
||
background: rgba(0,0,0,0.78);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 300;
|
||
backdrop-filter: blur(6px);
|
||
animation: fadeIn 0.2s ease both;
|
||
}
|
||
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
||
.settings-card {
|
||
background: var(--card-bg);
|
||
border: 1px solid var(--border);
|
||
border-radius: 18px;
|
||
width: 680px;
|
||
max-width: 95vw;
|
||
max-height: 90vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
animation: popIn 0.3s cubic-bezier(0.34,1.56,0.64,1) both;
|
||
}
|
||
.settings-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 1.25rem 1.5rem;
|
||
border-bottom: 1px solid var(--border);
|
||
flex-shrink: 0;
|
||
}
|
||
.settings-title {
|
||
font-size: 1rem;
|
||
font-weight: 700;
|
||
letter-spacing: -0.01em;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.6rem;
|
||
}
|
||
.settings-title svg { color: var(--accent2); }
|
||
.settings-close-btn {
|
||
width: 28px; height: 28px;
|
||
border-radius: 50%;
|
||
background: rgba(255,255,255,0.06);
|
||
border: 1px solid var(--border);
|
||
color: var(--muted);
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.15s;
|
||
font-size: 14px;
|
||
line-height: 1;
|
||
}
|
||
.settings-close-btn:hover { background: rgba(255,255,255,0.12); color: var(--text); }
|
||
.settings-tabs {
|
||
display: flex;
|
||
gap: 0;
|
||
padding: 0 1.5rem;
|
||
border-bottom: 1px solid var(--border);
|
||
flex-shrink: 0;
|
||
overflow-x: auto;
|
||
}
|
||
.settings-tab {
|
||
padding: 0.65rem 1rem;
|
||
font-size: 0.78rem;
|
||
font-weight: 600;
|
||
color: var(--muted);
|
||
cursor: pointer;
|
||
border-bottom: 2px solid transparent;
|
||
transition: all 0.15s;
|
||
white-space: nowrap;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
}
|
||
.settings-tab:hover { color: var(--text); }
|
||
.settings-tab.active { color: var(--text); border-bottom-color: var(--accent); }
|
||
.settings-body {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 1.5rem;
|
||
scrollbar-width: thin;
|
||
scrollbar-color: rgba(255,255,255,0.1) transparent;
|
||
}
|
||
.settings-panel { display: none; }
|
||
.settings-panel.active { display: block; }
|
||
.settings-section-label {
|
||
font-size: 0.62rem;
|
||
font-weight: 700;
|
||
letter-spacing: 0.1em;
|
||
text-transform: uppercase;
|
||
color: var(--muted);
|
||
margin-bottom: 0.75rem;
|
||
margin-top: 1.25rem;
|
||
}
|
||
.settings-section-label:first-child { margin-top: 0; }
|
||
.settings-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 0.75rem;
|
||
}
|
||
.settings-grid.full { grid-template-columns: 1fr; }
|
||
.settings-field {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.35rem;
|
||
}
|
||
.settings-field label {
|
||
font-size: 0.72rem;
|
||
font-weight: 600;
|
||
color: var(--muted);
|
||
letter-spacing: 0.02em;
|
||
}
|
||
.settings-input {
|
||
background: rgba(255,255,255,0.04);
|
||
border: 1px solid var(--border);
|
||
border-radius: 7px;
|
||
padding: 0.5rem 0.75rem;
|
||
color: var(--text);
|
||
font-size: 0.82rem;
|
||
font-family: inherit;
|
||
transition: border-color 0.15s;
|
||
width: 100%;
|
||
}
|
||
.settings-input:focus {
|
||
outline: none;
|
||
border-color: var(--accent);
|
||
background: rgba(79,70,229,0.06);
|
||
}
|
||
.settings-input.mono { font-family: 'JetBrains Mono', monospace; font-size: 0.78rem; }
|
||
.settings-select {
|
||
background: rgba(255,255,255,0.04);
|
||
border: 1px solid var(--border);
|
||
border-radius: 7px;
|
||
padding: 0.5rem 0.75rem;
|
||
color: var(--text);
|
||
font-size: 0.82rem;
|
||
font-family: inherit;
|
||
transition: border-color 0.15s;
|
||
width: 100%;
|
||
cursor: pointer;
|
||
}
|
||
.settings-select:focus { outline: none; border-color: var(--accent); }
|
||
.settings-select option { background: #0f1629; }
|
||
.settings-toggle-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
background: rgba(255,255,255,0.03);
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
padding: 0.6rem 0.85rem;
|
||
}
|
||
.settings-toggle-label { font-size: 0.82rem; font-weight: 500; }
|
||
.settings-toggle-sub { font-size: 0.7rem; color: var(--muted); margin-top: 0.15rem; }
|
||
.settings-toggle {
|
||
width: 40px; height: 22px;
|
||
background: rgba(255,255,255,0.12);
|
||
border-radius: 999px;
|
||
border: none;
|
||
cursor: pointer;
|
||
position: relative;
|
||
transition: background 0.2s;
|
||
flex-shrink: 0;
|
||
}
|
||
.settings-toggle::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 3px; left: 3px;
|
||
width: 16px; height: 16px;
|
||
border-radius: 50%;
|
||
background: white;
|
||
transition: transform 0.2s;
|
||
}
|
||
.settings-toggle.on { background: var(--accent); }
|
||
.settings-toggle.on::after { transform: translateX(18px); }
|
||
.settings-hint {
|
||
font-size: 0.68rem;
|
||
color: var(--muted);
|
||
margin-top: 0.2rem;
|
||
line-height: 1.4;
|
||
}
|
||
.settings-footer {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
gap: 0.65rem;
|
||
padding: 1rem 1.5rem;
|
||
border-top: 1px solid var(--border);
|
||
flex-shrink: 0;
|
||
}
|
||
.settings-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
padding: 0.55rem 1.1rem;
|
||
border-radius: 8px;
|
||
font-size: 0.82rem;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
border: 1px solid transparent;
|
||
transition: all 0.15s;
|
||
}
|
||
.settings-btn.cancel {
|
||
background: rgba(255,255,255,0.05);
|
||
border-color: var(--border);
|
||
color: var(--muted);
|
||
}
|
||
.settings-btn.cancel:hover { background: rgba(255,255,255,0.1); color: var(--text); }
|
||
.settings-btn.save {
|
||
background: linear-gradient(135deg, var(--accent), var(--accent2));
|
||
color: white;
|
||
}
|
||
.settings-btn.save:hover { opacity: 0.88; }
|
||
.settings-btn.save:disabled { opacity: 0.5; cursor: not-allowed; }
|
||
.settings-save-msg {
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
margin-right: auto;
|
||
transition: opacity 0.3s;
|
||
}
|
||
.settings-save-msg.ok { color: var(--green); }
|
||
.settings-save-msg.err { color: var(--red); }
|
||
|
||
/* ── No profit state banner ──────────────────────────────── */
|
||
.no-profit-banner {
|
||
display: none;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
padding: 0.75rem 1rem;
|
||
background: rgba(239,68,68,0.1);
|
||
border: 1px solid rgba(239,68,68,0.25);
|
||
border-radius: 10px;
|
||
font-size: 0.8rem;
|
||
color: var(--red);
|
||
}
|
||
.no-profit-banner.active { display: flex; }
|
||
.no-profit-banner-icon { font-size: 1.1rem; flex-shrink: 0; }
|
||
|
||
/* ── Scrollbar for whole page ────────────────────────────── */
|
||
::-webkit-scrollbar { width: 5px; height: 5px; }
|
||
::-webkit-scrollbar-track { background: transparent; }
|
||
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 999px; }
|
||
|
||
/* ── AI panel expand / collapse ─────────────────────────── */
|
||
.ai-preview { display: flex; flex-direction: column; gap: 0.5rem; }
|
||
.ai-details { display: none; flex-direction: column; gap: 0.65rem; }
|
||
.ai-details.open { display: flex; animation: slideDown 0.2s ease; }
|
||
@keyframes slideDown { from { opacity:0; transform:translateY(-6px); } to { opacity:1; transform:translateY(0); } }
|
||
.ai-expand-btn {
|
||
align-self: flex-start;
|
||
background: rgba(79,70,229,0.12);
|
||
border: 1px solid rgba(79,70,229,0.28);
|
||
border-radius: 6px;
|
||
color: var(--accent2);
|
||
font-size: 0.72rem;
|
||
font-weight: 600;
|
||
padding: 0.25rem 0.65rem;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
transition: all 0.15s;
|
||
margin-top: 0.15rem;
|
||
}
|
||
.ai-expand-btn:hover { background: rgba(79,70,229,0.22); }
|
||
|
||
/* ── Details button in runs table ───────────────────────── */
|
||
.detail-btn {
|
||
background: rgba(79,70,229,0.1);
|
||
border: 1px solid rgba(79,70,229,0.22);
|
||
border-radius: 5px;
|
||
color: var(--accent2);
|
||
font-size: 0.65rem;
|
||
font-weight: 600;
|
||
padding: 0.15rem 0.5rem;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
transition: all 0.15s;
|
||
white-space: nowrap;
|
||
}
|
||
.detail-btn:hover { background: rgba(79,70,229,0.22); }
|
||
|
||
/* ── Run Detail Modal ────────────────────────────────────── */
|
||
.run-detail-overlay {
|
||
position: fixed; inset: 0;
|
||
background: rgba(0,0,0,0.78);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 250;
|
||
backdrop-filter: blur(5px);
|
||
}
|
||
.run-detail-card {
|
||
background: var(--card-bg);
|
||
border: 1px solid var(--border);
|
||
border-radius: 18px;
|
||
width: 720px;
|
||
max-width: 95vw;
|
||
max-height: 88vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
animation: popIn 0.3s cubic-bezier(0.34,1.56,0.64,1) both;
|
||
}
|
||
.run-detail-header {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
padding: 1.1rem 1.5rem;
|
||
border-bottom: 1px solid var(--border);
|
||
flex-shrink: 0;
|
||
}
|
||
.run-detail-title {
|
||
font-size: 0.95rem;
|
||
font-weight: 700;
|
||
color: var(--text);
|
||
font-family: 'JetBrains Mono', monospace;
|
||
letter-spacing: 0.02em;
|
||
}
|
||
.run-detail-sub { font-size: 0.72rem; color: var(--muted); margin-top: 0.2rem; }
|
||
.run-detail-body {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 1.1rem 1.5rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
scrollbar-width: thin;
|
||
scrollbar-color: rgba(255,255,255,0.1) transparent;
|
||
}
|
||
.rd-metrics-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 0.6rem;
|
||
}
|
||
.rd-metric {
|
||
background: rgba(255,255,255,0.03);
|
||
border: 1px solid var(--border);
|
||
border-radius: 9px;
|
||
padding: 0.65rem 0.8rem;
|
||
}
|
||
.rd-metric-label { font-size: 0.6rem; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; }
|
||
.rd-metric-val { font-size: 1rem; font-weight: 700; margin-top: 0.15rem; }
|
||
.rd-section-title {
|
||
font-size: 0.63rem;
|
||
font-weight: 700;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.1em;
|
||
color: var(--muted);
|
||
padding-bottom: 0.4rem;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.rd-params-wrap { max-height: 200px; overflow-y: auto; }
|
||
.rd-ai-box {
|
||
background: rgba(79,70,229,0.07);
|
||
border: 1px solid rgba(79,70,229,0.2);
|
||
border-radius: 10px;
|
||
padding: 0.9rem 1rem;
|
||
font-size: 0.78rem;
|
||
color: var(--text);
|
||
line-height: 1.7;
|
||
}
|
||
.rd-ai-analysis { color: #94a3b8; margin-bottom: 0.65rem; }
|
||
.rd-ai-changes { display: flex; flex-direction: column; gap: 0.35rem; }
|
||
.rd-ai-change {
|
||
display: flex; align-items: center; gap: 0.5rem;
|
||
font-family: 'JetBrains Mono', monospace; font-size: 0.72rem;
|
||
}
|
||
.rd-ai-change-param { color: var(--teal); }
|
||
.rd-ai-change-arrow { color: var(--muted); }
|
||
.rd-ai-change-val { color: var(--text); font-weight: 600; }
|
||
.run-detail-footer {
|
||
padding: 0.85rem 1.5rem;
|
||
border-top: 1px solid var(--border);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
gap: 0.65rem;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* ── Live Intelligence (thinking / changes / validation) ──── */
|
||
.live-intel-row {
|
||
display: grid;
|
||
grid-template-columns: 1.1fr 1fr 1fr;
|
||
gap: 0.7rem;
|
||
flex-shrink: 0;
|
||
}
|
||
.live-intel-card {
|
||
background: var(--card-bg);
|
||
border: 1px solid var(--border);
|
||
border-radius: 12px;
|
||
padding: 0.9rem 1rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: 240px;
|
||
max-height: 280px;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.live-intel-card.accent {
|
||
border-color: rgba(79,70,229,0.32);
|
||
}
|
||
.live-intel-card.accent::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0; left: 0; right: 0; height: 1px;
|
||
background: linear-gradient(90deg, transparent, rgba(124,109,250,0.7), transparent);
|
||
}
|
||
.live-intel-title {
|
||
font-size: 0.78rem;
|
||
font-weight: 600;
|
||
color: var(--text);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
margin-bottom: 0.65rem;
|
||
flex-shrink: 0;
|
||
}
|
||
.live-intel-title .icon { color: var(--accent2); }
|
||
.live-intel-title .badge {
|
||
margin-left: auto;
|
||
font-size: 0.6rem;
|
||
font-weight: 700;
|
||
padding: 0.12rem 0.5rem;
|
||
border-radius: 999px;
|
||
background: rgba(100,116,139,0.15);
|
||
color: var(--muted);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.06em;
|
||
}
|
||
.live-intel-title .badge.live {
|
||
background: rgba(0,212,170,0.15);
|
||
color: var(--teal);
|
||
}
|
||
.live-intel-title .badge.live::before {
|
||
content: '●';
|
||
margin-right: 0.25rem;
|
||
animation: pulse-dot 1.8s ease-in-out infinite;
|
||
}
|
||
.live-intel-body {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
scrollbar-width: thin;
|
||
scrollbar-color: rgba(255,255,255,0.1) transparent;
|
||
}
|
||
.live-intel-body::-webkit-scrollbar { width: 3px; }
|
||
.live-intel-body::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 999px; }
|
||
.live-intel-empty {
|
||
color: var(--muted);
|
||
font-size: 0.76rem;
|
||
padding: 1rem 0.5rem;
|
||
text-align: center;
|
||
}
|
||
|
||
/* ── Thinking feed entries ──────────────────────────────── */
|
||
.tf-entry {
|
||
display: flex;
|
||
gap: 0.55rem;
|
||
padding: 0.5rem 0.1rem;
|
||
border-bottom: 1px solid rgba(255,255,255,0.03);
|
||
font-size: 0.76rem;
|
||
line-height: 1.45;
|
||
animation: tf-slidein 0.25s ease both;
|
||
}
|
||
@keyframes tf-slidein {
|
||
from { opacity: 0; transform: translateY(-4px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
.tf-entry:last-child { border-bottom: none; }
|
||
.tf-marker {
|
||
flex-shrink: 0;
|
||
width: 18px;
|
||
text-align: center;
|
||
font-weight: 700;
|
||
font-size: 0.78rem;
|
||
margin-top: 0.05em;
|
||
}
|
||
.tf-entry.info .tf-marker { color: var(--muted); }
|
||
.tf-entry.reasoning .tf-marker { color: var(--accent2); }
|
||
.tf-entry.decision .tf-marker { color: var(--teal); }
|
||
.tf-entry.success .tf-marker { color: var(--green); }
|
||
.tf-entry.warning .tf-marker { color: var(--yellow); }
|
||
.tf-entry.hypothesis .tf-marker { color: #a78bfa; }
|
||
.tf-body { flex: 1; min-width: 0; }
|
||
.tf-msg { color: var(--text); word-wrap: break-word; }
|
||
.tf-entry.info .tf-msg { color: #94a3b8; }
|
||
.tf-entry.warning .tf-msg { color: #fbbf24; }
|
||
.tf-meta {
|
||
font-size: 0.62rem;
|
||
color: var(--muted);
|
||
margin-top: 0.15rem;
|
||
display: flex;
|
||
gap: 0.5rem;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
}
|
||
.tf-cursor {
|
||
display: inline-block;
|
||
margin-left: 1px;
|
||
color: var(--accent2);
|
||
font-weight: 700;
|
||
animation: tf-blink 1s steps(2) infinite;
|
||
}
|
||
@keyframes tf-blink { 50% { opacity: 0; } }
|
||
.tf-chip {
|
||
display: inline-block;
|
||
padding: 0.05rem 0.35rem;
|
||
border-radius: 4px;
|
||
background: rgba(255,255,255,0.05);
|
||
color: var(--muted);
|
||
font-size: 0.6rem;
|
||
letter-spacing: 0.04em;
|
||
}
|
||
|
||
/* ── Parameter Changes list ─────────────────────────────── */
|
||
.pc-iteration {
|
||
border-bottom: 1px solid rgba(255,255,255,0.04);
|
||
padding: 0.55rem 0.1rem;
|
||
animation: tf-slidein 0.25s ease both;
|
||
}
|
||
.pc-iteration:last-child { border-bottom: none; }
|
||
.pc-iter-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
font-size: 0.72rem;
|
||
color: var(--text);
|
||
font-weight: 600;
|
||
margin-bottom: 0.3rem;
|
||
}
|
||
.pc-iter-label {
|
||
background: rgba(79,70,229,0.15);
|
||
color: var(--accent2);
|
||
font-family: 'JetBrains Mono', monospace;
|
||
padding: 0.08rem 0.4rem;
|
||
border-radius: 4px;
|
||
font-size: 0.65rem;
|
||
}
|
||
.pc-iter-conf {
|
||
margin-left: auto;
|
||
font-size: 0.62rem;
|
||
color: var(--muted);
|
||
}
|
||
.pc-change {
|
||
font-size: 0.7rem;
|
||
line-height: 1.55;
|
||
padding: 0.12rem 0;
|
||
}
|
||
.pc-param { color: var(--teal); font-family: 'JetBrains Mono', monospace; }
|
||
.pc-arrow { color: var(--muted); margin: 0 0.3rem; }
|
||
.pc-oldval { color: var(--muted); font-family: 'JetBrains Mono', monospace; text-decoration: line-through; }
|
||
.pc-newval { color: var(--text); font-family: 'JetBrains Mono', monospace; font-weight: 600; }
|
||
.pc-reason { color: #94a3b8; font-size: 0.66rem; margin-left: 1.3rem; font-style: italic; }
|
||
|
||
/* ── Validation Live Panel ──────────────────────────────── */
|
||
.val-header {
|
||
font-size: 0.7rem;
|
||
color: var(--muted);
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
.val-progress-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.45rem;
|
||
font-size: 0.68rem;
|
||
color: var(--muted);
|
||
margin-bottom: 0.6rem;
|
||
}
|
||
.val-progress-bar {
|
||
flex: 1;
|
||
height: 4px;
|
||
background: rgba(255,255,255,0.07);
|
||
border-radius: 999px;
|
||
overflow: hidden;
|
||
}
|
||
.val-progress-fill {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, var(--accent), var(--teal));
|
||
width: 0%;
|
||
transition: width 0.4s ease;
|
||
}
|
||
.val-run {
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
padding: 0.55rem 0.7rem;
|
||
margin-bottom: 0.4rem;
|
||
background: rgba(255,255,255,0.02);
|
||
animation: tf-slidein 0.25s ease both;
|
||
}
|
||
.val-run.active { border-color: rgba(0,212,170,0.4); background: rgba(0,212,170,0.04); }
|
||
.val-run.pass { border-color: rgba(16,185,129,0.35); }
|
||
.val-run.fail { border-color: rgba(239,68,68,0.35); }
|
||
.val-run-title {
|
||
font-size: 0.72rem;
|
||
font-weight: 600;
|
||
color: var(--text);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
}
|
||
.val-run-kind {
|
||
font-size: 0.58rem;
|
||
font-weight: 700;
|
||
padding: 0.08rem 0.4rem;
|
||
border-radius: 4px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.06em;
|
||
background: rgba(100,116,139,0.15);
|
||
color: var(--muted);
|
||
}
|
||
.val-run-kind.oos { background: rgba(79,70,229,0.18); color: var(--accent2); }
|
||
.val-run-kind.sensitivity { background: rgba(245,158,11,0.15); color: var(--yellow); }
|
||
.val-run-desc { font-size: 0.64rem; color: #94a3b8; margin-top: 0.2rem; line-height: 1.4; }
|
||
.val-run-metrics {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 0.3rem;
|
||
margin-top: 0.4rem;
|
||
}
|
||
.val-metric { background: rgba(255,255,255,0.03); border-radius: 5px; padding: 0.25rem 0.4rem; }
|
||
.val-metric-lbl { font-size: 0.55rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
|
||
.val-metric-val { font-size: 0.72rem; font-weight: 700; margin-top: 0.05rem; }
|
||
.val-spinner {
|
||
display: inline-block;
|
||
width: 10px; height: 10px;
|
||
border: 2px solid rgba(124,109,250,0.3);
|
||
border-top-color: var(--accent2);
|
||
border-radius: 50%;
|
||
animation: ai-spin 0.8s linear infinite;
|
||
}
|
||
|
||
/* ── Early Termination Banner ───────────────────────────── */
|
||
.early-term-banner {
|
||
display: none;
|
||
flex-direction: column;
|
||
gap: 0.35rem;
|
||
padding: 0.85rem 1.1rem;
|
||
background: rgba(245,158,11,0.08);
|
||
border: 1px solid rgba(245,158,11,0.28);
|
||
border-radius: 12px;
|
||
font-size: 0.82rem;
|
||
color: var(--yellow);
|
||
animation: tf-slidein 0.3s ease both;
|
||
}
|
||
.early-term-banner.active { display: flex; }
|
||
.early-term-banner.success { background: rgba(16,185,129,0.08); border-color: rgba(16,185,129,0.3); color: var(--green); }
|
||
.early-term-banner.warning { background: rgba(245,158,11,0.08); border-color: rgba(245,158,11,0.28); color: var(--yellow); }
|
||
.early-term-banner.critical { background: rgba(239,68,68,0.1); border-color: rgba(239,68,68,0.3); color: var(--red); }
|
||
.early-term-title { display: flex; align-items: center; gap: 0.55rem; font-weight: 700; }
|
||
.early-term-msg { font-size: 0.75rem; color: var(--text); line-height: 1.5; font-weight: 500; }
|
||
.early-term-details {
|
||
font-size: 0.7rem;
|
||
color: var(--muted);
|
||
margin-top: 0.2rem;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.5rem 1rem;
|
||
}
|
||
.early-term-dismiss {
|
||
background: transparent;
|
||
border: none;
|
||
color: var(--muted);
|
||
cursor: pointer;
|
||
margin-left: auto;
|
||
font-size: 1rem;
|
||
line-height: 1;
|
||
padding: 0;
|
||
}
|
||
.early-term-dismiss:hover { color: var(--text); }
|
||
|
||
/* ── Phase tracker (enhanced) ───────────────────────────── */
|
||
.phase-step .phase-sub {
|
||
font-size: 0.55rem;
|
||
color: var(--muted);
|
||
margin-top: 0.1rem;
|
||
text-align: center;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
line-height: 1;
|
||
}
|
||
.phase-step.active .phase-sub { color: var(--teal); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="app-shell">
|
||
|
||
<!-- ══════════════════════════════════════
|
||
SIDEBAR
|
||
══════════════════════════════════════ -->
|
||
<aside class="sidebar">
|
||
|
||
<!-- Logo -->
|
||
<div class="logo-wrap">
|
||
<img src="/static/img/apex-mark.png" alt="APEX" class="logo-mark" width="38" height="42">
|
||
<div>
|
||
<span class="logo-text">APEX</span>
|
||
<span class="logo-tagline">AI Powered Optimizer</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Navigation -->
|
||
<nav class="sidebar-nav">
|
||
|
||
<a href="/dashboard" class="nav-item active" data-page="dashboard">
|
||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/>
|
||
</svg>
|
||
Dashboard
|
||
</a>
|
||
|
||
<a href="/setup" class="nav-item" data-page="setup">
|
||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<line x1="4" y1="21" x2="4" y2="14"/><line x1="4" y1="10" x2="4" y2="3"/>
|
||
<line x1="12" y1="21" x2="12" y2="12"/><line x1="12" y1="8" x2="12" y2="3"/>
|
||
<line x1="20" y1="21" x2="20" y2="16"/><line x1="20" y1="12" x2="20" y2="3"/>
|
||
<line x1="1" y1="14" x2="7" y2="14"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="17" y1="16" x2="23" y2="16"/>
|
||
</svg>
|
||
New Run
|
||
</a>
|
||
|
||
<a href="/reports" class="nav-item" data-page="reports">
|
||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/>
|
||
<line x1="6" y1="20" x2="6" y2="14"/><line x1="2" y1="20" x2="22" y2="20"/>
|
||
</svg>
|
||
Reports
|
||
</a>
|
||
|
||
<a href="https://github.com/tonnylegacy/Apex_AI_MT5_EA_Optimizer" target="_blank" rel="noopener" class="nav-item" data-page="github">
|
||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/>
|
||
</svg>
|
||
Source on GitHub
|
||
</a>
|
||
|
||
<a href="#" class="nav-item" data-page="set" onclick="openSettings(); return false;">
|
||
<!-- Gear icon -->
|
||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="3"/>
|
||
<path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z"/>
|
||
</svg>
|
||
Settings
|
||
</a>
|
||
|
||
</nav>
|
||
|
||
<!-- Footer: MT5 status -->
|
||
<div class="sidebar-footer">
|
||
<div class="mt5-status">
|
||
<div class="mt5-dot" id="mt5-dot"></div>
|
||
<div>
|
||
<div class="mt5-label">MT5 Connection</div>
|
||
<div class="mt5-state" id="mt5-state">Ready</div>
|
||
</div>
|
||
</div>
|
||
<div class="mt5-brand">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/>
|
||
</svg>
|
||
MetaTrader 5
|
||
</div>
|
||
</div>
|
||
|
||
</aside>
|
||
|
||
<!-- ══════════════════════════════════════
|
||
MAIN CONTENT
|
||
══════════════════════════════════════ -->
|
||
<div class="main-content" id="main-content">
|
||
|
||
<!-- ── Command Header ────────────────────────────────────── -->
|
||
<div class="cmd-header">
|
||
|
||
<!-- Logo -->
|
||
<div class="cmd-logo">
|
||
<img src="/static/img/apex-mark.png" alt="APEX" class="cmd-mark" width="34" height="38">
|
||
<div class="cmd-logo-text">
|
||
<span class="cmd-apex">APEX</span>
|
||
<span class="cmd-tagline">
|
||
<span class="tag-cyan">AI</span>
|
||
<span class="tag-white">POWERED</span>
|
||
<span class="tag-purple">EA</span>
|
||
<span class="tag-white">OPTIMIZER</span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="cmd-sep"></div>
|
||
|
||
<!-- Status -->
|
||
<div class="cmd-section">
|
||
<div class="cmd-status-row">
|
||
<div class="cmd-status-dot" id="hdr-dot"></div>
|
||
<span class="cmd-status-label" id="hdr-status">System Idle</span>
|
||
</div>
|
||
<div class="cmd-section-sub" id="hdr-status-sub">Ready to optimize</div>
|
||
</div>
|
||
|
||
<div class="cmd-sep"></div>
|
||
|
||
<!-- Generation / Progress -->
|
||
<div class="cmd-section cmd-gen-section">
|
||
<div class="cmd-gen-row">
|
||
<span class="cmd-gen-label">Generation</span>
|
||
<span class="cmd-gen-val"><span id="hdr-gen-cur">0</span><span class="cmd-gen-sep">/</span><span id="hdr-gen-total">—</span></span>
|
||
</div>
|
||
<div class="cmd-prog-track">
|
||
<div class="cmd-prog-fill" id="hdr-prog-fill" style="width:0%"></div>
|
||
</div>
|
||
<div class="cmd-pct-label" id="hdr-pct">0% Complete</div>
|
||
</div>
|
||
|
||
<div class="cmd-sep"></div>
|
||
|
||
<!-- Best Score -->
|
||
<div class="cmd-section">
|
||
<div class="cmd-score-label">Best Score</div>
|
||
<div class="cmd-score-val" id="hdr-score">—</div>
|
||
<div class="cmd-score-delta" id="hdr-score-delta">Waiting for results...</div>
|
||
</div>
|
||
|
||
<div class="cmd-spacer"></div>
|
||
|
||
<!-- Action buttons -->
|
||
<div class="cmd-actions">
|
||
<a href="/setup" class="cmd-btn cmd-btn-start">
|
||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||
Start New
|
||
</a>
|
||
<!-- Pause is intentionally not shown — pipeline doesn't currently support it
|
||
(see: optimizer/pipeline.py — only _stop_flag exists, no _pause_event). -->
|
||
<button class="cmd-btn cmd-btn-stop" id="btn-stop">
|
||
<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><rect x="4" y="4" width="16" height="16" rx="2"/></svg>
|
||
Stop
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Hidden run-indicator kept for JS compatibility -->
|
||
<div id="run-indicator" style="display:none!important;"><span id="run-indicator-label"></span></div>
|
||
|
||
</div>
|
||
|
||
<!-- No-profit error banner -->
|
||
<div class="no-profit-banner" id="no-profit-banner">
|
||
<span class="no-profit-banner-icon">⚠</span>
|
||
<div>
|
||
<strong>No profitable configuration found.</strong>
|
||
<span id="no-profit-msg"> Try different parameters or date ranges.</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Early Termination banner (dismissible) -->
|
||
<div class="early-term-banner" id="early-term-banner">
|
||
<div class="early-term-title">
|
||
<span id="early-term-icon">⚠</span>
|
||
<span id="early-term-heading">Optimization stopped early</span>
|
||
<button class="early-term-dismiss" onclick="dismissEarlyTerm()">✕</button>
|
||
</div>
|
||
<div class="early-term-msg" id="early-term-msg"></div>
|
||
<div class="early-term-details" id="early-term-details"></div>
|
||
</div>
|
||
|
||
<!-- ── Metric cards ────────────────────────────────────────── -->
|
||
<div class="metrics-row">
|
||
|
||
<!-- Net Profit (clickable → Best Result detail) -->
|
||
<div class="metric-card" id="best-card" onclick="openBestResult()" style="cursor:pointer" title="Click to see how the AI arrived at this best result">
|
||
<div class="metric-label">Best Net Profit <span style="font-size:0.55rem;color:var(--accent2);font-weight:700">▸ details</span></div>
|
||
<div class="metric-value green" id="m-net-profit">$0.00</div>
|
||
<div class="metric-delta" id="m-net-profit-delta">
|
||
<span class="delta-up">↑</span>
|
||
<span id="m-net-profit-delta-val">0%</span>
|
||
<span style="margin-left:2px">vs baseline</span>
|
||
</div>
|
||
<div class="sparkline-wrap">
|
||
<canvas id="spark-profit" width="80" height="28"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Max Drawdown -->
|
||
<div class="metric-card">
|
||
<div class="metric-label">Max Drawdown</div>
|
||
<div class="metric-value red" id="m-max-dd">0.00%</div>
|
||
<div class="metric-delta" id="m-max-dd-delta">
|
||
<span class="delta-down">↓</span>
|
||
<span id="m-max-dd-delta-val">0%</span>
|
||
<span style="margin-left:2px">vs baseline</span>
|
||
</div>
|
||
<div class="sparkline-wrap">
|
||
<canvas id="spark-dd" width="80" height="28"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Profit Factor -->
|
||
<div class="metric-card">
|
||
<div class="metric-label">Profit Factor</div>
|
||
<div class="metric-value gold" id="m-pf">0.00</div>
|
||
<div class="metric-delta">
|
||
<span id="m-pf-quality" style="color:var(--muted)">—</span>
|
||
</div>
|
||
<div class="sparkline-wrap">
|
||
<canvas id="spark-pf" width="80" height="28"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Total Trades -->
|
||
<div class="metric-card">
|
||
<div class="metric-label">Total Trades</div>
|
||
<div class="metric-value teal" id="m-trades">0</div>
|
||
<div class="metric-delta">
|
||
<span style="color:var(--muted)">This run</span>
|
||
</div>
|
||
<div class="sparkline-wrap">
|
||
<canvas id="spark-trades" width="80" height="28"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Optimization Runs -->
|
||
<div class="metric-card">
|
||
<div class="metric-label">Optimization Runs</div>
|
||
<div class="metric-value white" id="m-runs">0</div>
|
||
<div class="metric-delta">
|
||
<span style="color:var(--muted)">This session</span>
|
||
</div>
|
||
<div class="sparkline-wrap">
|
||
<canvas id="spark-runs" width="80" height="28"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- AI Confidence (special) -->
|
||
<div class="metric-card ai-conf-card">
|
||
<div class="metric-label">AI Confidence</div>
|
||
<div class="ai-conf-value" id="ai-conf-label">—</div>
|
||
<div class="ai-gauge-wrap">
|
||
<svg id="ai-gauge" width="60" height="60" viewBox="0 0 64 64">
|
||
<circle cx="32" cy="32" r="26" fill="none" stroke="rgba(255,255,255,0.07)" stroke-width="6"/>
|
||
<circle id="ai-gauge-arc" cx="32" cy="32" r="26" fill="none"
|
||
stroke="#00d4aa" stroke-width="6" stroke-linecap="round"
|
||
stroke-dasharray="163.4" stroke-dashoffset="163.4"
|
||
transform="rotate(-90 32 32)"
|
||
style="transition: stroke-dashoffset 1s ease, stroke 0.5s ease"/>
|
||
<text id="ai-gauge-pct" x="32" y="37" text-anchor="middle"
|
||
fill="#e2e8f0" font-size="12" font-weight="700" font-family="Inter, sans-serif">0%</text>
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ── Charts + AI panel ────────────────────────────────────── -->
|
||
<div class="charts-ai-row">
|
||
|
||
<!-- Left: charts column -->
|
||
<div class="charts-col">
|
||
|
||
<!-- Equity Curve -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title">
|
||
<div class="dot"></div>
|
||
Equity Curve
|
||
</div>
|
||
<div style="display:flex;gap:0.6rem;align-items:center;">
|
||
<span style="font-size:0.68rem;color:var(--muted);display:flex;align-items:center;gap:0.3rem;">
|
||
<span style="display:inline-block;width:20px;height:2px;background:#4f46e5;border-radius:2px;"></span> Equity
|
||
</span>
|
||
<span style="font-size:0.68rem;color:var(--muted);display:flex;align-items:center;gap:0.3rem;">
|
||
<span style="display:inline-block;width:20px;height:2px;background:#00d4aa;border-radius:2px;border-bottom:2px dashed #00d4aa;height:0;"></span> Balance
|
||
</span>
|
||
<div class="card-badge" id="equity-badge">Live</div>
|
||
</div>
|
||
</div>
|
||
<div class="chart-wrap equity-chart-wrap">
|
||
<canvas id="equityChart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Drawdown Chart -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<div class="card-title">
|
||
<div class="dot" style="background:var(--red);"></div>
|
||
Drawdown Analysis
|
||
</div>
|
||
<span class="card-badge" id="max-dd-badge" style="background:rgba(239,68,68,0.12);color:var(--red);">Max DD: 0%</span>
|
||
</div>
|
||
<div class="chart-wrap drawdown-chart-wrap">
|
||
<canvas id="drawdownChart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- Right: AI panel -->
|
||
<div class="ai-panel-col">
|
||
<div class="ai-panel-card" id="ai-panel">
|
||
<div class="ai-panel-header">
|
||
<div class="ai-panel-title">
|
||
<span class="ai-icon">✦</span>
|
||
AI Summary
|
||
</div>
|
||
<a href="#" class="view-details-link" id="ai-view-details" onclick="toggleAIDetails(); return false;">View Details →</a>
|
||
</div>
|
||
|
||
<!-- Waiting / no-key state -->
|
||
<div class="ai-waiting" id="ai-waiting">
|
||
<div class="ai-pulse-dot"></div>
|
||
<span id="ai-waiting-text">Waiting for optimization to start...</span>
|
||
<a href="#" id="ai-waiting-action" onclick="openSettings(); return false;"
|
||
style="display:none;font-size:0.72rem;color:var(--accent2);text-decoration:underline;cursor:pointer;">
|
||
Configure API key in Settings →
|
||
</a>
|
||
</div>
|
||
|
||
<!-- Active state -->
|
||
<div class="ai-content" id="ai-content" style="display:none;">
|
||
|
||
<!-- Collapsed preview (always shown when data loaded) -->
|
||
<div class="ai-preview" id="ai-preview">
|
||
<div class="ai-headline" id="ai-headline" style="display:none;"></div>
|
||
<p class="ai-diagnosis" id="ai-diagnosis-text">—</p>
|
||
<button class="ai-expand-btn" id="ai-expand-btn" onclick="toggleAIDetails()">View Details →</button>
|
||
</div>
|
||
|
||
<!-- Expanded details (hidden by default) -->
|
||
<div class="ai-details" id="ai-details">
|
||
<div id="ai-strengths-section" style="display:none;">
|
||
<div class="ai-sub-title">Top Patterns</div>
|
||
<ul class="ai-check-list" id="ai-strengths-list"></ul>
|
||
</div>
|
||
|
||
<div class="ai-suggestion-box" id="ai-suggestion-box" style="display:none;">
|
||
<div class="ai-sub-title" style="margin-bottom:0.3rem;">Key Suggestion</div>
|
||
<p class="ai-suggestion-text" id="ai-suggestion-text"></p>
|
||
<div class="ai-badge">AI</div>
|
||
</div>
|
||
|
||
<div id="ai-risks-section" style="display:none;">
|
||
<div class="ai-sub-title warn">Risk Flags</div>
|
||
<ul class="ai-warn-list" id="ai-risks-list"></ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="ai-confidence-row">
|
||
<span class="ai-conf-badge" id="ai-panel-conf-badge">analyzing</span>
|
||
<span class="ai-run-ref" id="ai-run-ref"></span>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ── Live Intelligence (thinking feed / param changes / validation) ── -->
|
||
<div class="live-intel-row">
|
||
|
||
<!-- AI Thinking Feed -->
|
||
<div class="live-intel-card accent">
|
||
<div class="live-intel-title">
|
||
<span class="icon">✦</span>
|
||
AI Thinking
|
||
<span class="badge" id="tf-badge">Idle</span>
|
||
</div>
|
||
<div class="live-intel-body" id="thinking-feed">
|
||
<div class="live-intel-empty">Waiting for the optimizer to start…<br><span style="font-size:0.68rem">The AI's reasoning will stream here in real time.</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Parameter Changes -->
|
||
<div class="live-intel-card">
|
||
<div class="live-intel-title">
|
||
<svg class="icon" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
|
||
Parameter Changes
|
||
<span class="badge" id="pc-badge">—</span>
|
||
</div>
|
||
<div class="live-intel-body" id="param-changes-list">
|
||
<div class="live-intel-empty">No iterations yet.<br><span style="font-size:0.68rem">AI-driven parameter edits appear per iteration.</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Validation Activity -->
|
||
<div class="live-intel-card">
|
||
<div class="live-intel-title">
|
||
<svg class="icon" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
|
||
Validation
|
||
<span class="badge" id="val-badge">Pending</span>
|
||
</div>
|
||
<div class="live-intel-body" id="validation-panel">
|
||
<div class="live-intel-empty">Validation runs after optimization.<br><span style="font-size:0.68rem">Out-of-sample + sensitivity tests.</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ── Bottom row ───────────────────────────────────────────── -->
|
||
<div class="bottom-row">
|
||
|
||
<!-- Top Parameters -->
|
||
<div class="bottom-card">
|
||
<div class="bottom-card-title">
|
||
Top Parameters
|
||
<span style="font-size:0.65rem;color:var(--muted);font-weight:400;">(Best Run)</span>
|
||
</div>
|
||
<div style="overflow-x:auto;flex:1;">
|
||
<table class="params-table" id="params-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Parameter</th>
|
||
<th>Value</th>
|
||
<th>Impact</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="params-tbody">
|
||
<tr><td colspan="3" class="empty-state">Run optimizer to see parameters</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Optimization Progress -->
|
||
<div class="bottom-card">
|
||
<div class="bottom-card-title">Optimization Progress</div>
|
||
<div style="display:flex;flex-direction:column;gap:0.5rem;flex:1;">
|
||
<div class="opt-gen-label" id="opt-gen">Generation — / —</div>
|
||
<div class="opt-progress-bar-track">
|
||
<div class="opt-progress-bar-fill" id="opt-progress-fill" style="width:0%"></div>
|
||
</div>
|
||
<div class="opt-stats-grid">
|
||
<div class="opt-stat">
|
||
<div class="opt-stat-label">Current Phase</div>
|
||
<div class="opt-stat-val" id="opt-phase">Waiting</div>
|
||
</div>
|
||
<div class="opt-stat">
|
||
<div class="opt-stat-label">Elapsed</div>
|
||
<div class="opt-stat-val" id="opt-elapsed">—</div>
|
||
</div>
|
||
<div class="opt-stat">
|
||
<div class="opt-stat-label">Est. Remaining</div>
|
||
<div class="opt-stat-val" id="opt-remaining">—</div>
|
||
</div>
|
||
</div>
|
||
<!-- Phase steps -->
|
||
<div class="phase-steps" id="phase-steps">
|
||
<div class="phase-step" id="phase-step-1">
|
||
<div class="phase-dot">1</div>
|
||
<div class="phase-name">Exploration</div>
|
||
<div class="phase-sub" id="phase-sub-1">—</div>
|
||
</div>
|
||
<div class="phase-connector"></div>
|
||
<div class="phase-step" id="phase-step-2">
|
||
<div class="phase-dot">2</div>
|
||
<div class="phase-name">Iteration</div>
|
||
<div class="phase-sub" id="phase-sub-2">—</div>
|
||
</div>
|
||
<div class="phase-connector"></div>
|
||
<div class="phase-step" id="phase-step-3">
|
||
<div class="phase-dot">3</div>
|
||
<div class="phase-name">Validation</div>
|
||
<div class="phase-sub" id="phase-sub-3">—</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Recent Runs -->
|
||
<div class="bottom-card">
|
||
<div class="bottom-card-title">
|
||
Recent Runs
|
||
<a href="/reports" class="view-all-link">View All →</a>
|
||
</div>
|
||
<div style="overflow-x:auto;flex:1;">
|
||
<table class="runs-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Run</th>
|
||
<th>Net Profit</th>
|
||
<th>PF</th>
|
||
<th>Max DD</th>
|
||
<th>Verdict</th>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="recent-runs-tbody">
|
||
<tr><td colspan="6" class="empty-state">No runs yet</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ── Live log (collapsible) ───────────────────────────────── -->
|
||
<div class="log-panel">
|
||
<button class="log-toggle-btn" id="log-toggle-btn" onclick="toggleLog()">
|
||
<span style="display:flex;align-items:center;gap:0.5rem;">
|
||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>
|
||
Live Log
|
||
<span id="log-count" style="background:rgba(100,116,139,0.2);color:var(--muted);font-size:0.65rem;padding:0.05rem 0.4rem;border-radius:999px;font-weight:600;">0</span>
|
||
</span>
|
||
<svg class="log-toggle-icon" id="log-toggle-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
|
||
</button>
|
||
<div class="log-body" id="log-body">
|
||
<div class="log-feed" id="log-feed"></div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /.main-content -->
|
||
|
||
</div><!-- /.app-shell -->
|
||
|
||
<!-- ══════════════════════════════════════
|
||
SETTINGS MODAL
|
||
══════════════════════════════════════ -->
|
||
<div class="settings-overlay" id="settings-overlay" style="display:none;" onclick="if(event.target===this)closeSettings()">
|
||
<div class="settings-card">
|
||
|
||
<div class="settings-header">
|
||
<div class="settings-title">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="3"/>
|
||
<path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z"/>
|
||
</svg>
|
||
Settings
|
||
</div>
|
||
<button class="settings-close-btn" onclick="closeSettings()">✕</button>
|
||
</div>
|
||
|
||
<div class="settings-tabs">
|
||
<div class="settings-tab active" data-tab="ai" onclick="switchSettingsTab('ai')">
|
||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
|
||
AI Engine
|
||
</div>
|
||
<div class="settings-tab" data-tab="mt5" onclick="switchSettingsTab('mt5')">
|
||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
|
||
MetaTrader 5
|
||
</div>
|
||
<div class="settings-tab" data-tab="broker" onclick="switchSettingsTab('broker')">
|
||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6"/></svg>
|
||
Broker
|
||
</div>
|
||
<div class="settings-tab" data-tab="thresholds" onclick="switchSettingsTab('thresholds')">
|
||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="4" y1="21" x2="4" y2="14"/><line x1="4" y1="10" x2="4" y2="3"/><line x1="12" y1="21" x2="12" y2="12"/><line x1="12" y1="8" x2="12" y2="3"/><line x1="20" y1="21" x2="20" y2="16"/><line x1="20" y1="12" x2="20" y2="3"/><line x1="1" y1="14" x2="7" y2="14"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="17" y1="16" x2="23" y2="16"/></svg>
|
||
Thresholds
|
||
</div>
|
||
</div>
|
||
|
||
<div class="settings-body">
|
||
|
||
<!-- AI Engine tab -->
|
||
<div class="settings-panel active" id="stab-ai">
|
||
<div class="settings-section-label">AI Analysis Engine</div>
|
||
<div class="settings-toggle-row" style="margin-bottom:0.75rem;">
|
||
<div>
|
||
<div class="settings-toggle-label">Enable AI Insights</div>
|
||
<div class="settings-toggle-sub">Claude analyzes each run and provides actionable suggestions</div>
|
||
</div>
|
||
<button class="settings-toggle" id="s-ai-enabled" onclick="toggleSettingsBool(this)"></button>
|
||
</div>
|
||
<div class="settings-grid full">
|
||
<div class="settings-field">
|
||
<label>Anthropic API Key</label>
|
||
<input type="password" class="settings-input mono" id="s-ai-key" placeholder="sk-ant-api03-..." autocomplete="off">
|
||
<div class="settings-hint">Your Claude API key from console.anthropic.com. Kept locally in config.yaml.</div>
|
||
</div>
|
||
</div>
|
||
<div class="settings-grid" style="margin-top:0.75rem;">
|
||
<div class="settings-field">
|
||
<label>Model</label>
|
||
<select class="settings-select" id="s-ai-model">
|
||
<option value="claude-opus-4-7">claude-opus-4-7 (Most capable)</option>
|
||
<option value="claude-sonnet-4-6">claude-sonnet-4-6 (Balanced)</option>
|
||
<option value="claude-haiku-4-5-20251001">claude-haiku-4-5 (Fast)</option>
|
||
</select>
|
||
</div>
|
||
<div class="settings-field">
|
||
<label>Timeout (seconds)</label>
|
||
<input type="number" class="settings-input" id="s-ai-timeout" min="10" max="120" step="5">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MetaTrader 5 tab -->
|
||
<div class="settings-panel" id="stab-mt5">
|
||
<div class="settings-section-label">Terminal Paths</div>
|
||
<div class="settings-grid full">
|
||
<div class="settings-field">
|
||
<label>Terminal Executable</label>
|
||
<input type="text" class="settings-input mono" id="s-mt5-exe" placeholder="C:/Program Files/MetaTrader 5/terminal64.exe">
|
||
<div class="settings-hint">Full path to terminal64.exe</div>
|
||
</div>
|
||
<div class="settings-field" style="margin-top:0.5rem;">
|
||
<label>AppData Path</label>
|
||
<input type="text" class="settings-input mono" id="s-mt5-appdata" placeholder="C:/Users/.../AppData/Roaming/MetaQuotes/Terminal/...">
|
||
</div>
|
||
<div class="settings-field" style="margin-top:0.5rem;">
|
||
<label>MQL5 Files Path</label>
|
||
<input type="text" class="settings-input mono" id="s-mt5-mql5" placeholder="C:/Users/.../MQL5/Files">
|
||
</div>
|
||
</div>
|
||
<div class="settings-section-label">Tester Settings</div>
|
||
<div class="settings-grid">
|
||
<div class="settings-field">
|
||
<label>Tester Timeout (seconds)</label>
|
||
<input type="number" class="settings-input" id="s-mt5-timeout" min="30" max="600" step="10">
|
||
</div>
|
||
<div class="settings-field">
|
||
<label>Tester Model</label>
|
||
<select class="settings-select" id="s-mt5-model">
|
||
<option value="1">1 — Every tick</option>
|
||
<option value="2">2 — Every tick based on real ticks</option>
|
||
<option value="3">3 — OHLC (M1)</option>
|
||
<option value="4">4 — Open prices only</option>
|
||
<option value="5">5 — Math calculations</option>
|
||
</select>
|
||
<div class="settings-hint">Strategy Tester modeling method</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Broker tab -->
|
||
<div class="settings-panel" id="stab-broker">
|
||
<div class="settings-section-label">Broker Configuration</div>
|
||
<div class="settings-grid">
|
||
<div class="settings-field">
|
||
<label>Timezone Offset (hours)</label>
|
||
<input type="number" class="settings-input" id="s-broker-tz" min="-12" max="14" step="0.5">
|
||
<div class="settings-hint">GMT offset, e.g. 3 for EET (Eastern European Time)</div>
|
||
</div>
|
||
<div class="settings-field">
|
||
<label>Account Deposit ($)</label>
|
||
<input type="number" class="settings-input" id="s-broker-deposit" min="100" step="100">
|
||
</div>
|
||
<div class="settings-field">
|
||
<label>Leverage (1:X)</label>
|
||
<input type="number" class="settings-input" id="s-broker-leverage" min="1" max="2000" step="1">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Thresholds tab -->
|
||
<div class="settings-panel" id="stab-thresholds">
|
||
<div class="settings-section-label">Quality Filters</div>
|
||
<div class="settings-grid">
|
||
<div class="settings-field">
|
||
<label>Min Trades</label>
|
||
<input type="number" class="settings-input" id="s-thr-trades" min="1" step="1">
|
||
<div class="settings-hint">Minimum trades per backtest to pass</div>
|
||
</div>
|
||
<div class="settings-field">
|
||
<label>Min Profit Factor</label>
|
||
<input type="number" class="settings-input" id="s-thr-pf" min="0" max="10" step="0.05">
|
||
</div>
|
||
<div class="settings-field">
|
||
<label>Min Calmar Ratio</label>
|
||
<input type="number" class="settings-input" id="s-thr-calmar" min="0" max="10" step="0.05">
|
||
</div>
|
||
<div class="settings-field">
|
||
<label>Max OOS Degradation</label>
|
||
<input type="number" class="settings-input" id="s-thr-oos" min="0" max="1" step="0.01">
|
||
<div class="settings-hint">Max allowed out-of-sample score drop (0–1)</div>
|
||
</div>
|
||
<div class="settings-field">
|
||
<label>Sensitivity Tolerance</label>
|
||
<input type="number" class="settings-input" id="s-thr-sens" min="0" max="1" step="0.01">
|
||
<div class="settings-hint">Allowed parameter sensitivity variance (0–1)</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /.settings-body -->
|
||
|
||
<div class="settings-footer">
|
||
<span class="settings-save-msg" id="settings-save-msg" style="opacity:0;"></span>
|
||
<button class="settings-btn cancel" onclick="closeSettings()">Cancel</button>
|
||
<button class="settings-btn save" id="settings-save-btn" onclick="saveSettings()">Save Settings</button>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ══════════════════════════════════════
|
||
RUN DETAIL MODAL
|
||
══════════════════════════════════════ -->
|
||
<div class="run-detail-overlay" id="run-detail-overlay" style="display:none;" onclick="if(event.target===this)closeRunDetail()">
|
||
<div class="run-detail-card">
|
||
|
||
<div class="run-detail-header">
|
||
<div>
|
||
<div class="run-detail-title" id="rd-run-id">Run Details</div>
|
||
<div class="run-detail-sub" id="rd-meta"></div>
|
||
</div>
|
||
<button class="settings-close-btn" onclick="closeRunDetail()">✕</button>
|
||
</div>
|
||
|
||
<div class="run-detail-body">
|
||
<div class="rd-metrics-grid" id="rd-metrics"></div>
|
||
|
||
<div class="rd-section-title">Parameters</div>
|
||
<div class="rd-params-wrap">
|
||
<table class="params-table" style="width:100%">
|
||
<thead><tr><th>Parameter</th><th>Value</th></tr></thead>
|
||
<tbody id="rd-params-tbody">
|
||
<tr><td colspan="2" class="empty-state">Loading...</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div id="rd-ai-section" style="display:none;">
|
||
<div class="rd-section-title">AI Reasoning</div>
|
||
<div id="rd-ai-content"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="run-detail-footer" id="rd-footer">
|
||
<button class="verdict-btn ghost" onclick="closeRunDetail()">Close</button>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ══════════════════════════════════════
|
||
VERDICT OVERLAY
|
||
══════════════════════════════════════ -->
|
||
<div class="verdict-overlay" id="verdict-overlay" style="display:none;">
|
||
<div class="verdict-card" id="verdict-card">
|
||
<div class="verdict-header-row">
|
||
<div class="verdict-icon-big" id="verdict-icon">✅</div>
|
||
<div>
|
||
<div class="verdict-title" id="verdict-title">RECOMMENDED</div>
|
||
<div class="verdict-subtitle" id="verdict-subtitle">Optimization complete.</div>
|
||
</div>
|
||
</div>
|
||
<div class="verdict-metrics-row" id="verdict-metrics"></div>
|
||
<div class="verdict-actions-row" id="verdict-actions"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ══════════════════════════════════════
|
||
SCRIPTS
|
||
══════════════════════════════════════ -->
|
||
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.4/dist/chart.umd.min.js"></script>
|
||
<script src="/static/js/dashboard.js"></script>
|
||
|
||
</body>
|
||
</html>
|