crewlyze 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/.dockerignore +12 -0
  2. package/.gitattributes +2 -0
  3. package/CHANGELOG.md +86 -0
  4. package/Dockerfile +21 -0
  5. package/LICENSE +21 -0
  6. package/README.md +139 -0
  7. package/USAGE.md +106 -0
  8. package/agents/__init__.py +0 -0
  9. package/agents/cleaner.py +38 -0
  10. package/agents/insights.py +44 -0
  11. package/agents/relation.py +36 -0
  12. package/agents/visualizer.py +41 -0
  13. package/assets/badge_crewai.svg +4 -0
  14. package/assets/badge_matplotlib.svg +4 -0
  15. package/assets/badge_ollama.svg +4 -0
  16. package/assets/badge_pandas.svg +4 -0
  17. package/assets/badge_seaborn.svg +4 -0
  18. package/assets/branding_image.png +0 -0
  19. package/assets/complete_workflow.svg +216 -0
  20. package/assets/favicon.png +0 -0
  21. package/assets/logo.png +0 -0
  22. package/assets/stars.svg +12 -0
  23. package/bin/crewlyze.js +79 -0
  24. package/config/README.md +129 -0
  25. package/config/__init__.py +1 -0
  26. package/config/context.py +16 -0
  27. package/config/llm_config.py +300 -0
  28. package/config/metrics_tracker.py +70 -0
  29. package/crew.py +870 -0
  30. package/crewlyze-3.1.0.tgz +0 -0
  31. package/fix_syntax.py +54 -0
  32. package/main.py +1279 -0
  33. package/package.json +22 -0
  34. package/pyproject.toml +32 -0
  35. package/requirements.txt +33 -0
  36. package/tools/__init__.py +0 -0
  37. package/tools/dataset_tools.py +803 -0
  38. package/ui/__init__.py +3 -0
  39. package/ui/copilot.py +200 -0
  40. package/ui/export.py +800 -0
  41. package/update_appjs.py +54 -0
  42. package/update_llm.py +21 -0
  43. package/update_main.py +20 -0
  44. package/web/app.js +3142 -0
  45. package/web/index.html +1105 -0
  46. package/web/style.css +2561 -0
  47. package/workflows/__init__.py +0 -0
  48. package/workflows/pipeline.py +254 -0
package/web/index.html ADDED
@@ -0,0 +1,1105 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Crewlyze — AI-Powered Business Intelligence</title>
8
+ <meta name="description"
9
+ content="Autonomous Multi-Agent AI system for data cleaning, relationship analysis, business insights, and interactive visualizations." />
10
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
11
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
12
+ <link
13
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap"
14
+ rel="stylesheet" />
15
+ <script src="https://cdn.plot.ly/plotly-2.35.2.min.js"></script>
16
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
17
+ <!-- Lucide Icons -->
18
+ <script src="https://unpkg.com/lucide@latest"></script>
19
+ <link rel="stylesheet" href="/style.css" />
20
+ <link rel="icon" type="image/png" href="/assets/favicon.png" />
21
+ </head>
22
+
23
+ <body>
24
+
25
+ <!-- ═══════════════════════════════ SIDEBAR ══════════════════════════════════ -->
26
+ <aside id="sidebar" class="sidebar">
27
+ <div class="sidebar-header">
28
+ <div class="logo" id="sidebarLogo" style="cursor: pointer;" title="Go to Dashboard">
29
+ <img src="/assets/logo.png" alt="Crewlyze Logo" style="height: 32px; object-fit: contain;" />
30
+ <span class="logo-text" style="margin-left: 8px;">Crew<span class="logo-accent">lyze</span></span>
31
+ </div>
32
+ <button id="sidebarToggle" class="sidebar-toggle" title="Collapse sidebar">‹</button>
33
+ </div>
34
+
35
+ <!-- LLM Settings -->
36
+ <div class="sidebar-section">
37
+ <div class="sidebar-section-header"><span>LLM CONFIGURATION</span></div>
38
+
39
+ <label class="field-label">Provider</label>
40
+ <select id="llmProvider" class="field-select">
41
+ <option value="nvidia">NVIDIA NIM</option>
42
+ <option value="groq">Groq</option>
43
+ <option value="openai">OpenAI</option>
44
+ <option value="anthropic">Anthropic</option>
45
+ <option value="gemini">Google Gemini</option>
46
+ <option value="mistral">Mistral</option>
47
+ <option value="huggingface">HuggingFace</option>
48
+ <option value="ollama">Ollama (local)</option>
49
+ <option value="custom">Custom API (OpenAI Compatible)</option>
50
+ </select>
51
+
52
+ <label class="field-label">Model</label>
53
+ <select id="llmModel" class="field-select"></select>
54
+ <div id="sidebarApiKeyStatus"
55
+ style="font-size: 0.75rem; margin-top: 10px; text-align: center; display: flex; align-items: center; justify-content: center; gap: 6px;">
56
+ </div>
57
+
58
+ <!-- Hidden elements to ensure backward compatibility in app.js -->
59
+ <input type="hidden" id="apiKey" />
60
+ <input type="hidden" id="cooldown" value="5" />
61
+ <span id="cooldownVal" style="display: none;">5</span>
62
+ <span id="keyLabel" style="display: none;"></span>
63
+ <button id="testConnectionBtn" style="display: none;"></button>
64
+ <div id="connectionStatus" style="display: none;"></div>
65
+ </div>
66
+
67
+ <!-- Sidebar Project Actions -->
68
+ <div id="sidebarProjectActions" class="sidebar-section hidden"
69
+ style="margin-top: auto; border-top: 1px solid var(--border); padding-top: 15px;">
70
+ <div class="sidebar-section-header"><span>PROJECT ACTIONS</span></div>
71
+ <div style="display: flex; flex-direction: column; gap: 8px; margin-top: 8px;">
72
+ <button id="sidebarExportPdfBtn" class="sidebar-action-btn btn-primary"
73
+ style="width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 0.8rem; padding: 10px 12px; border-radius: var(--r-sm); font-weight: 600; cursor: pointer;"><i
74
+ data-lucide="file-text" style="width: 14px; height: 14px;"></i> Export PDF Report</button>
75
+ <button id="sidebarExportZipBtn" class="sidebar-action-btn btn-secondary"
76
+ style="width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 0.8rem; padding: 10px 12px; border-radius: var(--r-sm); font-weight: 600; cursor: pointer;"><i
77
+ data-lucide="archive" style="width: 14px; height: 14px;"></i> Export Project (.zip)</button>
78
+ <button id="sidebarDownloadCsvBtn" class="sidebar-action-btn btn-secondary"
79
+ style="width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 0.8rem; padding: 10px 12px; border-radius: var(--r-sm); cursor: pointer; color: var(--text-primary); border: 1px solid var(--border-mid); background: var(--bg-elevated);"><i
80
+ data-lucide="download" style="width: 14px; height: 14px;"></i> Download Cleaned CSV</button>
81
+ <button id="sidebarReRunBtn" class="sidebar-action-btn btn-ghost"
82
+ style="width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 0.8rem; padding: 10px 12px; border-radius: var(--r-sm); cursor: pointer; color: var(--text-secondary); background: transparent; border: 1px dashed var(--border-mid);"><i
83
+ data-lucide="refresh-cw" style="width: 14px; height: 14px;"></i> Re-run Analysis</button>
84
+ </div>
85
+ </div>
86
+
87
+ <div class="sidebar-footer">
88
+ <button id="sidebarMetricsBtn" class="btn-secondary"
89
+ style="width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; margin-bottom: 12px; padding: 8px 12px; border-radius: var(--r-sm); font-size: 0.8rem; background: var(--bg-elevated); border: 1px solid var(--border-mid); color: var(--text-primary); cursor: pointer; transition: all 0.2s;"><i
90
+ data-lucide="bar-chart-2" style="width: 14px; height: 14px;"></i> Performance Metrics</button>
91
+ <button id="sidebarSettingsBtn" class="btn-secondary"
92
+ style="width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; margin-bottom: 12px; padding: 8px 12px; border-radius: var(--r-sm); font-size: 0.8rem; background: var(--bg-elevated); border: 1px solid var(--border-mid); color: var(--text-primary); cursor: pointer; transition: all 0.2s;"><i
93
+ data-lucide="settings" style="width: 14px; height: 14px;"></i> Settings</button>
94
+ <span>Crewlyze v3.1</span>
95
+ </div>
96
+ </aside>
97
+
98
+ <!-- ═══════════════════════════════ MAIN AREA ═════════════════════════════════ -->
99
+ <main class="main-area">
100
+
101
+ <!-- TOP NAV -->
102
+ <header class="topbar">
103
+ <div class="topbar-left">
104
+ <button id="mobileSidebarBtn" class="btn-icon-lg">☰</button>
105
+ <div id="breadcrumb" class="breadcrumb">
106
+ <span class="breadcrumb-item active">Dashboard</span>
107
+ </div>
108
+ </div>
109
+ <div class="topbar-right">
110
+ <div id="statusPill" class="status-pill idle">● Idle</div>
111
+ </div>
112
+ </header>
113
+
114
+ <!-- ─── LANDING / UPLOAD SCREEN ─── -->
115
+ <section id="landingScreen" class="screen active">
116
+ <div class="landing-hero">
117
+ <div class="hero-badge">✦ Powered by CrewAI Multi-Agent Pipeline</div>
118
+ <h1 class="hero-title"><span class="gradient-text">Crewlyze</span></h1>
119
+ <p class="hero-subtitle">Upload a CSV and let autonomous AI agents clean your data, discover relationships,
120
+ surface strategic insights, and generate interactive visualizations — all in one pipeline.</p>
121
+
122
+ <!-- Wizard Container -->
123
+ <div class="wizard-container" id="newProjectWizard">
124
+ <!-- Step 0: Create Project Button Card -->
125
+ <div class="wizard-step active" id="wizardStep0"
126
+ style="width: 100%; display: flex; flex-direction: row !important; justify-content: center; gap: 20px; flex-wrap: wrap;">
127
+ <div class="create-project-card" id="startWizardCard">
128
+ <div class="create-project-plus">+</div>
129
+ <div class="create-project-text">Create New Project</div>
130
+ <div class="create-project-desc"
131
+ style="font-size: 0.75rem; color: var(--text-secondary); margin-top: 8px; text-align: center; max-width: 200px;">
132
+ Start a fresh analysis pipeline with a new CSV dataset</div>
133
+ </div>
134
+ <div class="create-project-card" id="importProjectCard"
135
+ style="background: rgba(16,185,129,0.02); border-color: rgba(16,185,129,0.2);">
136
+ <div class="create-project-plus" style="color: #10b981;">↓</div>
137
+ <div class="create-project-text" style="color: var(--text-primary);">Import Project (.zip)</div>
138
+ <div class="create-project-desc"
139
+ style="font-size: 0.75rem; color: var(--text-secondary); margin-top: 8px; text-align: center; max-width: 200px;">
140
+ Load and restore an existing project session from backup</div>
141
+ <input type="file" id="importZipFileInput" accept=".zip" style="display: none;" />
142
+ </div>
143
+ </div>
144
+
145
+ <!-- Step 1: Project Name -->
146
+ <div class="wizard-step" id="wizardStep1">
147
+ <button id="wizardBack1Btn" class="btn-back">← Back</button>
148
+ <div class="wizard-icon"><i data-lucide="sparkles"
149
+ style="width: 32px; height: 32px; color: var(--violet-light);"></i></div>
150
+ <h3 class="wizard-step-title">Create New Project</h3>
151
+ <p class="wizard-step-desc">Enter a name, and optionally a title and goal for your project.</p>
152
+ <div
153
+ style="width: 100%; max-width: 440px; margin: 16px auto 0; text-align: left; display: flex; flex-direction: column; gap: 12px;">
154
+ <div class="field-group">
155
+ <label class="field-label" style="font-weight: 600; margin-bottom: 4px;">Project Name</label>
156
+ <input type="text" id="wizardProjectName" class="field-input" placeholder="e.g. Sales Analysis Q3"
157
+ style="font-size: 0.95rem; padding: 10px 12px; width: 100%; box-sizing: border-box;" />
158
+ </div>
159
+ <div class="field-group">
160
+ <label class="field-label" style="font-weight: 600; margin-bottom: 4px;">Report Title (Optional)</label>
161
+ <input type="text" id="wizardReportTitle" class="field-input"
162
+ placeholder="e.g. Q3 Sales Executive Analysis"
163
+ style="font-size: 0.95rem; padding: 10px 12px; width: 100%; box-sizing: border-box;" />
164
+ </div>
165
+ <div class="field-group">
166
+ <label class="field-label" style="font-weight: 600; margin-bottom: 4px;">Project Goal / Objective
167
+ (Optional)</label>
168
+ <textarea id="wizardProjectGoal" class="field-input" rows="3"
169
+ placeholder="e.g. Identify top 10% highest-margin customer segments and explain why spend exceeded budget."
170
+ style="font-size: 0.95rem; padding: 10px 12px; font-family: inherit; resize: none; width: 100%; box-sizing: border-box;"></textarea>
171
+ </div>
172
+ </div>
173
+ <button id="wizardNextBtn" class="btn-primary btn-lg mt-20"
174
+ style="min-width: 200px; margin-top: 20px;">Continue to Upload →</button>
175
+ </div>
176
+
177
+ <!-- Step 2: Upload CSV -->
178
+ <div class="wizard-step" id="wizardStep2">
179
+ <button id="wizardBackBtn" class="btn-back">← Back</button>
180
+ <div class="wizard-icon"><i data-lucide="folder-open"
181
+ style="width: 32px; height: 32px; color: var(--violet-light);"></i></div>
182
+ <h3 class="wizard-step-title" id="wizardUploadTitle">Upload CSV Dataset</h3>
183
+ <p class="wizard-step-desc">Select or drop the CSV file you want the agents to analyze.</p>
184
+
185
+ <div class="upload-zone" id="uploadZone"
186
+ style="width: 100%; max-width: 520px; margin: 20px auto 0; background: rgba(124,58,237,0.02);">
187
+ <div class="upload-icon"><i data-lucide="file"
188
+ style="width: 32px; height: 32px; color: var(--violet-light);"></i></div>
189
+ <div class="upload-title">Drop your CSV here</div>
190
+ <div class="upload-hint">or <label for="fileInput" class="upload-link">browse files</label></div>
191
+ <input type="file" id="fileInput" accept=".csv" hidden />
192
+ <div id="uploadedFileMeta" class="upload-meta hidden"></div>
193
+ </div>
194
+
195
+ <div id="uploadedFileActions" class="upload-actions hidden" style="margin-top: 20px;">
196
+ <button id="startAnalysisBtn" class="btn-primary btn-lg"><i data-lucide="play"
197
+ style="width: 16px; height: 16px; fill: currentColor; vertical-align: middle; margin-right: 6px;"></i>
198
+ Configure &amp; Run Analysis</button>
199
+ </div>
200
+ </div>
201
+ </div>
202
+ </div>
203
+
204
+ <!-- Projects Section -->
205
+ <div class="dashboard-projects-section">
206
+ <div class="section-title-row">
207
+ <h2 class="section-title">Recent Projects</h2>
208
+ <span class="projects-count" id="dashboardProjectsCount">(0)</span>
209
+ </div>
210
+ <div class="projects-grid" id="dashboardProjectsGrid">
211
+ <!-- Rendered dynamically via app.js -->
212
+ </div>
213
+ </div>
214
+ </section>
215
+
216
+ <!-- ─── ANALYSIS CONFIG MODAL ─── -->
217
+ <div id="configModal" class="modal-overlay hidden">
218
+ <div class="modal-box">
219
+ <div class="modal-header">
220
+ <h2><i data-lucide="settings"
221
+ style="width: 20px; height: 20px; vertical-align: middle; margin-right: 6px;"></i> Analysis Configuration
222
+ </h2>
223
+ <button id="closeConfigModal" class="btn-icon">✕</button>
224
+ </div>
225
+
226
+ <div class="modal-body">
227
+ <p class="modal-hint">Select which stages to run. Dependencies are enforced automatically.</p>
228
+
229
+ <!-- Task cards -->
230
+ <div class="task-grid" id="taskGrid">
231
+ <label class="task-card" id="taskCardCleaning">
232
+ <input type="checkbox" id="taskCleaning" value="cleaning" checked />
233
+ <div class="task-card-icon"><i data-lucide="brush"
234
+ style="width: 20px; height: 20px; color: var(--violet-light);"></i></div>
235
+ <div class="task-card-body">
236
+ <div class="task-card-title">Data Cleaning</div>
237
+ <div class="task-card-desc">Fix quality issues: missing values, types, duplicates.</div>
238
+ </div>
239
+ <div class="task-card-check"><i data-lucide="check" style="width: 14px; height: 14px;"></i></div>
240
+ </label>
241
+
242
+ <label class="task-card" id="taskCardRelations">
243
+ <input type="checkbox" id="taskRelations" value="relations" checked />
244
+ <div class="task-card-icon"><i data-lucide="link"
245
+ style="width: 20px; height: 20px; color: var(--cyan);"></i></div>
246
+ <div class="task-card-body">
247
+ <div class="task-card-title">Relationship Analysis</div>
248
+ <div class="task-card-desc">Discover correlations &amp; patterns. <em>Requires Cleaning.</em></div>
249
+ </div>
250
+ <div class="task-card-check"><i data-lucide="check" style="width: 14px; height: 14px;"></i></div>
251
+ </label>
252
+
253
+ <label class="task-card" id="taskCardInsights">
254
+ <input type="checkbox" id="taskInsights" value="insights" checked />
255
+ <div class="task-card-icon"><i data-lucide="lightbulb"
256
+ style="width: 20px; height: 20px; color: var(--amber);"></i></div>
257
+ <div class="task-card-body">
258
+ <div class="task-card-title">Business Insights</div>
259
+ <div class="task-card-desc">Strategic recommendations. <em>Requires Cleaning.</em></div>
260
+ </div>
261
+ <div class="task-card-check"><i data-lucide="check" style="width: 14px; height: 14px;"></i></div>
262
+ </label>
263
+
264
+ <label class="task-card" id="taskCardViz">
265
+ <input type="checkbox" id="taskViz" value="visualization" checked />
266
+ <div class="task-card-icon"><i data-lucide="trending-up"
267
+ style="width: 20px; height: 20px; color: var(--rose);"></i></div>
268
+ <div class="task-card-body">
269
+ <div class="task-card-title">Visualization</div>
270
+ <div class="task-card-desc">Interactive charts &amp; PNGs. <em>Requires Relations.</em></div>
271
+ </div>
272
+ <div class="task-card-check"><i data-lucide="check" style="width: 14px; height: 14px;"></i></div>
273
+ </label>
274
+ </div>
275
+
276
+ <!-- Analysis depth -->
277
+ <div class="depth-selector">
278
+ <div class="depth-label"><i data-lucide="search"
279
+ style="width: 14px; height: 14px; vertical-align: middle; margin-right: 4px;"></i> Analysis Depth</div>
280
+ <div class="depth-options">
281
+ <label class="depth-option active" id="depthStandard">
282
+ <input type="radio" name="depth" value="false" checked />
283
+ <span class="depth-icon"><i data-lucide="zap"
284
+ style="width: 14px; height: 14px; color: var(--violet-light);"></i></span>
285
+ <span class="depth-name">Standard</span>
286
+ <span class="depth-desc">Faster, concise</span>
287
+ </label>
288
+ <label class="depth-option" id="depthDeep">
289
+ <input type="radio" name="depth" value="true" />
290
+ <span class="depth-icon"><i data-lucide="microscope"
291
+ style="width: 14px; height: 14px; color: var(--cyan);"></i></span>
292
+ <span class="depth-name">Deep</span>
293
+ <span class="depth-desc">Richer analysis &amp; detail</span>
294
+ </label>
295
+ </div>
296
+ </div>
297
+
298
+ <!-- Report title -->
299
+ <div class="field-group">
300
+ <label class="field-label">Report Title</label>
301
+ <input type="text" id="reportTitle" class="field-input"
302
+ placeholder="e.g. Q4 2024 Sales Performance Analysis" />
303
+ </div>
304
+ </div>
305
+
306
+ <div class="modal-footer">
307
+ <button id="cancelConfigBtn" class="btn-secondary">Cancel</button>
308
+ <button id="runAnalysisBtn" class="btn-primary"><i data-lucide="play"
309
+ style="width: 14px; height: 14px; fill: currentColor; vertical-align: middle; margin-right: 4px;"></i>
310
+ Start Analysis</button>
311
+ </div>
312
+ </div>
313
+ </div>
314
+
315
+ <!-- ─── ANALYSIS RUNNING SCREEN ─── -->
316
+ <section id="runningScreen" class="screen">
317
+ <div class="running-header" style="display: flex; align-items: center; width: 100%;">
318
+ <div class="running-spinner"></div>
319
+ <div style="flex: 1;">
320
+ <h2 id="runningTitle">Agents are Analysing Your Data…</h2>
321
+ <p class="running-sub">This may take 2–10 minutes depending on dataset size and LLM speed.</p>
322
+ </div>
323
+ <button id="btnRunInBackground" class="btn-secondary btn-sm"
324
+ style="margin-left: auto; display: flex; align-items: center; gap: 6px;"><i data-lucide="minimize-2"
325
+ style="width: 14px; height: 14px;"></i> Run in Background</button>
326
+ </div>
327
+
328
+ <!-- Stage progress -->
329
+ <div class="stages-track">
330
+ <div class="stage-item" data-stage="cleaning">
331
+ <div class="stage-dot"></div>
332
+ <div class="stage-label">Cleaning</div>
333
+ </div>
334
+ <div class="stage-item" data-stage="relations">
335
+ <div class="stage-dot"></div>
336
+ <div class="stage-label">Relations</div>
337
+ </div>
338
+ <div class="stage-item" data-stage="insights">
339
+ <div class="stage-dot"></div>
340
+ <div class="stage-label">Insights</div>
341
+ </div>
342
+ <div class="stage-item" data-stage="visualization">
343
+ <div class="stage-dot"></div>
344
+ <div class="stage-label">Visualization</div>
345
+ </div>
346
+ <div class="stage-item" data-stage="plotly">
347
+ <div class="stage-dot"></div>
348
+ <div class="stage-label">Charts</div>
349
+ </div>
350
+ </div>
351
+
352
+ <!-- Dynamic Stage POV Panel -->
353
+ <div id="stagePovPanel" class="stage-pov-panel">
354
+ <div class="pov-initial-state">
355
+ <div class="pov-pulse-ring"></div>
356
+ <p>Awaiting analysis stream...</p>
357
+ </div>
358
+ </div>
359
+
360
+ <!-- Live log -->
361
+ <div class="log-panel">
362
+ <div class="log-header">
363
+ <span><i data-lucide="clipboard-list"
364
+ style="width: 16px; height: 16px; vertical-align: middle; margin-right: 6px;"></i> Live Agent Log</span>
365
+ <button id="clearLogBtn" class="btn-xs">Clear</button>
366
+ </div>
367
+ <div id="logOutput" class="log-output"></div>
368
+ </div>
369
+ </section>
370
+
371
+ <!-- ─── RESULTS DASHBOARD SCREEN ─── -->
372
+ <section id="resultsScreen" class="screen">
373
+
374
+ <!-- Stat row -->
375
+ <div class="stats-row" id="statsRow" style="margin-bottom: 20px;"></div>
376
+
377
+ <!-- Main Sections Switch -->
378
+ <div class="sections-switch" style="display: none !important;">
379
+ <button class="section-switch-btn active" id="btnSectionChat"
380
+ style="flex: 1; padding: 10px 20px; border: none; background: var(--violet-dark); color: #fff; font-weight: 600; border-radius: 26px; cursor: pointer; transition: all 0.3s; display: flex; align-items: center; justify-content: center; gap: 8px;"><i
381
+ data-lucide="message-square" style="width: 16px; height: 16px;"></i> AI Data Chat</button>
382
+ <button class="section-switch-btn" id="btnSectionAgentic"
383
+ style="flex: 1; padding: 10px 20px; border: none; background: transparent; color: var(--text-secondary); font-weight: 600; border-radius: 26px; cursor: pointer; transition: all 0.3s; display: flex; align-items: center; justify-content: center; gap: 8px;"><i
384
+ data-lucide="bot" style="width: 16px; height: 16px;"></i> Agentic Analysis</button>
385
+ </div>
386
+
387
+ <!-- ───────────────── SECTION 0: WORKSPACE HUB (SELECT MODE) ───────────────── -->
388
+ <div id="areaHub" class="section-area active">
389
+ <div
390
+ style="display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 20px; text-align: center; max-width: 800px; margin: 0 auto; gap: 32px;">
391
+ <div>
392
+ <h2 style="font-size: 1.8rem; font-weight: 700; margin: 0 0 10px 0; color: #fff;">Choose Your Workspace Mode
393
+ </h2>
394
+ <p
395
+ style="color: var(--text-secondary); max-width: 540px; margin: 0 auto; font-size: 0.95rem; line-height: 1.5;">
396
+ Select how you would like to interact with the project dataset. Switch modes at any time.
397
+ </p>
398
+ </div>
399
+
400
+ <div class="hub-cards-grid"
401
+ style="display: flex; gap: 24px; width: 100%; justify-content: center; flex-wrap: wrap; margin-top: 10px;">
402
+ <!-- Card 1: AI Chat -->
403
+ <div class="hub-card" id="btnEnterChat"
404
+ style="flex: 1; min-width: 280px; max-width: 360px; background: var(--bg-elevated); border: 1px solid var(--border-mid); border-radius: var(--r-lg); padding: 32px 24px; text-align: center; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); display: flex; flex-direction: column; align-items: center; gap: 16px;">
405
+ <div class="hub-card-icon-wrap"
406
+ style="width: 64px; height: 64px; border-radius: 50%; background: rgba(167, 139, 250, 0.1); display: flex; align-items: center; justify-content: center;">
407
+ <i data-lucide="message-square" style="width: 32px; height: 32px; color: var(--violet-light);"></i>
408
+ </div>
409
+ <h3 style="margin: 0; font-size: 1.3rem; font-weight: 700; color: #fff;">AI Data Chat</h3>
410
+ <p style="color: var(--text-secondary); font-size: 0.85rem; line-height: 1.5; margin: 0; flex: 1;">
411
+ Ask questions, query statistical metrics, run quick data edits, and request tailored interactive
412
+ visualizations in a conversational interface.
413
+ </p>
414
+ <button class="btn-primary"
415
+ style="display: inline-flex; justify-content: center; align-items: center; text-align: center; pointer-events: none; width: 100%; padding: 10px 0; font-size: 0.85rem; font-weight: 700; background: var(--violet); color: #fff; border: none; transition: transform 0.2s;">Open
416
+ Chat Workspace</button>
417
+ </div>
418
+
419
+ <!-- Card 2: Crew Analysis -->
420
+ <div class="hub-card" id="btnEnterAgentic"
421
+ style="flex: 1; min-width: 280px; max-width: 360px; background: var(--bg-elevated); border: 1px solid var(--border-mid); border-radius: var(--r-lg); padding: 32px 24px; text-align: center; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); display: flex; flex-direction: column; align-items: center; gap: 16px;">
422
+ <div class="hub-card-icon-wrap"
423
+ style="width: 64px; height: 64px; border-radius: 50%; background: rgba(6, 182, 212, 0.1); display: flex; align-items: center; justify-content: center;">
424
+ <i data-lucide="bot" style="width: 32px; height: 32px; color: var(--cyan);"></i>
425
+ </div>
426
+ <h3 style="margin: 0; font-size: 1.3rem; font-weight: 700; color: #fff;">Crew Agentic Analysis</h3>
427
+ <p style="color: var(--text-secondary); font-size: 0.85rem; line-height: 1.5; margin: 0; flex: 1;">
428
+ Trigger structured multi-agent pipelines to clean datasets, map schema relationships, generate
429
+ McKinsey-style recommendations, and build dashboard suites.
430
+ </p>
431
+ <button class="btn-primary"
432
+ style="display: inline-flex; justify-content: center; align-items: center; text-align: center; pointer-events: none; width: 100%; padding: 10px 0; font-size: 0.85rem; font-weight: 700; background: var(--cyan); color: var(--bg-dark); border: none; transition: transform 0.2s;">Open
433
+ Agent Workspace</button>
434
+ </div>
435
+ </div>
436
+ </div>
437
+ </div>
438
+
439
+ <!-- ───────────────── SECTION 1: AI DATA CHAT ───────────────── -->
440
+ <div id="areaChat" class="section-area hidden">
441
+ <div style="display: flex; flex-direction: column; gap: 20px;">
442
+
443
+ <!-- Table Preview Area -->
444
+ <div id="datasetExplorerCard" class="card"
445
+ style="padding: 18px; background: var(--bg-elevated); border: 1px solid var(--border-mid);">
446
+ <div
447
+ style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; flex-wrap: wrap; gap: 8px;">
448
+ <h3 style="margin: 0; font-size: 1.1rem; display: flex; align-items: center; gap: 8px;"><i
449
+ data-lucide="search" style="width: 18px; height: 18px; color: var(--violet-light);"></i> Dataset
450
+ Explorer <span id="chatPreviewDims"
451
+ style="font-size: 0.75rem; font-weight: normal; color: var(--text-secondary);"></span></h3>
452
+ <div style="display: flex; gap: 8px;">
453
+ <button id="btnRenameColQuick" class="btn-secondary btn-sm"
454
+ style="font-size: 0.75rem; display: flex; align-items: center; gap: 4px;"><i data-lucide="edit"
455
+ style="width: 12px; height: 12px;"></i> Rename Column</button>
456
+ <button id="btnDeleteColQuick" class="btn-secondary btn-sm"
457
+ style="font-size: 0.75rem; border-color: rgba(239, 68, 68, 0.2); color: #ef4444; display: flex; align-items: center; gap: 4px;"><i
458
+ data-lucide="trash-2" style="width: 12px; height: 12px;"></i> Delete Column</button>
459
+ </div>
460
+ </div>
461
+ <div id="previewTableWrap" class="table-wrap" style="max-height: 250px; overflow-y: auto;">
462
+ <div id="previewTable" class="data-table-container"></div>
463
+ </div>
464
+ </div>
465
+
466
+ <!-- Chat Container -->
467
+ <div id="chatContainerCard" class="card"
468
+ style="padding: 20px; background: var(--bg-elevated); border: 1px solid var(--border-mid); display: flex; flex-direction: column; min-height: 480px;">
469
+ <div
470
+ style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; border-bottom: 1px solid var(--border-low); padding-bottom: 12px;">
471
+ <div style="display: flex; align-items: center; gap: 12px;">
472
+ <button id="chatBackBtn" class="btn-icon"
473
+ style="background:var(--bg-elevated); border:1px solid var(--border-mid); border-radius:var(--r-md); padding:10px; cursor:pointer; color:var(--text-primary);"
474
+ title="Back to Dashboard"><i data-lucide="arrow-left" style="width:20px; height:20px;"></i></button>
475
+ <h3 style="margin: 0; font-size: 1.1rem; display: flex; align-items: center; gap: 8px;"><i
476
+ data-lucide="message-square" style="width: 18px; height: 18px; color: var(--violet-light);"></i> AI
477
+ Copilot</h3>
478
+ </div>
479
+ <button id="clearChatBtn" class="btn-secondary btn-sm">Clear Conversation</button>
480
+ </div>
481
+
482
+ <div id="chatMessages" class="chat-messages"
483
+ style="flex: 1; min-height: 260px; overflow-y: auto; padding-right: 4px; display: flex; flex-direction: column; gap: 16px; margin-bottom: 16px;">
484
+ <!-- messages populate here -->
485
+ </div>
486
+
487
+ <div class="chat-input-area" style="position: relative;">
488
+ <div id="colPickerDropdown" class="col-picker-dropdown hidden"
489
+ style="position: absolute; bottom: 100%; left: 0; right: 0; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--r-md); z-index: 10; max-height: 160px; overflow-y: auto; padding: 4px;">
490
+ </div>
491
+ <div class="chat-input-row" style="display: flex; gap: 8px; align-items: flex-end;">
492
+ <textarea id="chatInput" class="chat-textarea" rows="2"
493
+ placeholder="Ask questions, request visual charts, or modify columns (type / to select a column)..."
494
+ style="flex: 1; background: var(--bg-card); color: var(--text-primary); border: 1px solid var(--border-mid); border-radius: var(--r-md); padding: 10px 14px; font-size: 0.9rem; font-family: inherit; resize: none;"></textarea>
495
+ <button id="sendChatBtn" class="btn-primary btn-send"
496
+ style="padding: 12px 20px; border-radius: var(--r-md); font-weight: 600;">Send ↑</button>
497
+ </div>
498
+ <div class="chat-hints"
499
+ style="display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; font-size: 0.75rem; color: var(--text-secondary);">
500
+ <span class="chat-hint-chip" data-query="Show summary statistics for all numeric columns"
501
+ style="background: var(--bg-card); border: 1px solid var(--border-low); padding: 4px 10px; border-radius: 12px; cursor: pointer; transition: all 0.2s;"><i
502
+ data-lucide="bar-chart-2"
503
+ style="width: 12px; height: 12px; vertical-align: middle; margin-right: 4px;"></i> Summary
504
+ Stats</span>
505
+ <span class="chat-hint-chip"
506
+ data-query="Plot a distribution histogram of the first column with custom color config"
507
+ style="background: var(--bg-card); border: 1px solid var(--border-low); padding: 4px 10px; border-radius: 12px; cursor: pointer; transition: all 0.2s;"><i
508
+ data-lucide="trending-down"
509
+ style="width: 12px; height: 12px; vertical-align: middle; margin-right: 4px;"></i> Custom
510
+ Histogram</span>
511
+ <span class="chat-hint-chip" data-query="Rename column..."
512
+ style="background: var(--bg-card); border: 1px solid var(--border-low); padding: 4px 10px; border-radius: 12px; cursor: pointer; transition: all 0.2s;"><i
513
+ data-lucide="edit"
514
+ style="width: 12px; height: 12px; vertical-align: middle; margin-right: 4px;"></i> Rename
515
+ Column</span>
516
+ <span class="chat-hint-chip" data-query="Delete column..."
517
+ style="background: var(--bg-card); border: 1px solid var(--border-low); padding: 4px 10px; border-radius: 12px; cursor: pointer; transition: all 0.2s;"><i
518
+ data-lucide="trash-2"
519
+ style="width: 12px; height: 12px; vertical-align: middle; margin-right: 4px;"></i> Delete
520
+ Column</span>
521
+ </div>
522
+ </div>
523
+ </div>
524
+
525
+ </div>
526
+ </div>
527
+
528
+ <!-- ───────────────── SECTION 2: AGENTIC ANALYSIS ───────────────── -->
529
+ <div id="areaAgentic" class="section-area hidden">
530
+ <!-- Run Analysis Placeholder -->
531
+ <div id="agenticPlaceholder" class="hidden"
532
+ style="text-align: center; padding: 60px 20px; background: rgba(24, 24, 27, 0.4); border: 1px dashed var(--border-mid); border-radius: var(--r-lg); max-width: 580px; margin: 40px auto; display: flex; flex-direction: column; align-items: center; gap: 16px; backdrop-filter: blur(12px);">
533
+ <div style="font-size: 3rem; animation: pulse 2s infinite;"><i data-lucide="bot"
534
+ style="width: 48px; height: 48px; color: var(--violet-light);"></i></div>
535
+ <h3 style="margin: 0; font-size: 1.2rem; font-weight: 700; color: #fff;">Automated Pipeline Analysis</h3>
536
+ <p style="color: var(--text-secondary); line-height: 1.5; margin: 0; font-size: 0.9rem;">
537
+ Trigger autonomous AI agents to perform data cleaning, schema relationship mapping, and surface
538
+ consulting-grade insights.
539
+ </p>
540
+ <button id="btnRunAgenticPipeline" class="btn-primary btn-lg" style="margin-top: 10px; font-weight: 600;"><i
541
+ data-lucide="play"
542
+ style="width: 16px; height: 16px; fill: currentColor; vertical-align: middle; margin-right: 6px;"></i>
543
+ Configure &amp; Run Analysis</button>
544
+ </div>
545
+
546
+ <!-- Tabs -->
547
+ <div class="tabs-bar" id="agenticTabsBar" style="margin-bottom: 16px;">
548
+ <button class="tab-btn active" data-tab="cleaning"><i data-lucide="brush"
549
+ style="width: 14px; height: 14px; vertical-align: middle; margin-right: 4px;"></i> Cleaning
550
+ Report</button>
551
+ <button class="tab-btn" data-tab="relations"><i data-lucide="link"
552
+ style="width: 14px; height: 14px; vertical-align: middle; margin-right: 4px;"></i> Relation
553
+ Mapper</button>
554
+ <button class="tab-btn" data-tab="insights"><i data-lucide="lightbulb"
555
+ style="width: 14px; height: 14px; vertical-align: middle; margin-right: 4px;"></i> Business
556
+ Insights</button>
557
+ <button class="tab-btn" data-tab="charts"><i data-lucide="trending-up"
558
+ style="width: 14px; height: 14px; vertical-align: middle; margin-right: 4px;"></i> Visualizations</button>
559
+ </div>
560
+
561
+ <!-- Tab panels -->
562
+ <div class="tab-panels" id="agenticTabPanels">
563
+ <!-- CLEANING REPORT -->
564
+ <div class="tab-panel active" id="panel-cleaning">
565
+ <h3 class="panel-title"><i data-lucide="brush"
566
+ style="width: 18px; height: 18px; vertical-align: middle; margin-right: 6px;"></i> Data Cleaning Audit
567
+ Trail</h3>
568
+ <div id="cleaningContent" class="cleaning-list"></div>
569
+ </div>
570
+
571
+ <!-- RELATIONS -->
572
+ <div class="tab-panel" id="panel-relations">
573
+ <h3 class="panel-title"><i data-lucide="link"
574
+ style="width: 18px; height: 18px; vertical-align: middle; margin-right: 6px;"></i> Relationship Mapping
575
+ </h3>
576
+ <div id="relationsContent" style="width: 100%;"></div>
577
+ </div>
578
+
579
+ <!-- INSIGHTS -->
580
+ <div class="tab-panel" id="panel-insights">
581
+ <h3 class="panel-title"><i data-lucide="lightbulb"
582
+ style="width: 18px; height: 18px; vertical-align: middle; margin-right: 6px;"></i> Strategic Business
583
+ Insights</h3>
584
+ <div id="insightsContent" class="insights-list"></div>
585
+ </div>
586
+
587
+ <!-- CHARTS -->
588
+ <div class="tab-panel" id="panel-charts">
589
+ <h3 class="panel-title"><i data-lucide="trending-up"
590
+ style="width: 18px; height: 18px; vertical-align: middle; margin-right: 6px;"></i> Visual Intelligence
591
+ </h3>
592
+ <div id="plotlyChartsWrap" class="charts-grid"></div>
593
+ <div id="pngChartsWrap" class="png-charts-wrap hidden">
594
+ <h4 class="sub-title"><i data-lucide="image"
595
+ style="width: 16px; height: 16px; vertical-align: middle; margin-right: 6px;"></i> Agent-Generated
596
+ Charts</h4>
597
+ <div id="pngCharts" class="png-grid"></div>
598
+ </div>
599
+ <details class="viz-code-details hidden" id="vizCodeDetails">
600
+ <summary><i data-lucide="code"
601
+ style="width: 16px; height: 16px; vertical-align: middle; margin-right: 6px;"></i> Visualization
602
+ Architecture Code</summary>
603
+ <pre id="vizCodeBlock" class="code-block"></pre>
604
+ </details>
605
+ </div>
606
+ </div>
607
+ </div>
608
+
609
+ <!-- Export/action bar -->
610
+ <div class="export-bar" style="margin-top: 24px;">
611
+ <button id="exportPdfBtn" class="btn-primary"><i data-lucide="file-text" style="width: 14px; height: 14px;"></i>
612
+ Export PDF Report</button>
613
+ <button id="exportZipBtn" class="btn-secondary"
614
+ style="background: rgba(124,58,237,0.06); border-color: var(--violet-light); color: var(--violet-light); font-weight: 600;"><i
615
+ data-lucide="archive" style="width: 14px; height: 14px;"></i> Export Project (.zip)</button>
616
+ <button id="downloadCsvBtn" class="btn-secondary"><i data-lucide="download"
617
+ style="width: 14px; height: 14px;"></i> Download Cleaned CSV</button>
618
+ <button id="reRunBtn" class="btn-ghost"><i data-lucide="refresh-cw" style="width: 14px; height: 14px;"></i>
619
+ Re-run Agentic Analysis</button>
620
+ </div>
621
+
622
+ </section><!-- /results screen -->
623
+
624
+ </main><!-- /main-area -->
625
+
626
+ <!-- Schema Relation Modal -->
627
+ <div id="relationModal" class="modal-overlay hidden">
628
+ <div class="modal-box"
629
+ style="max-width: 480px; padding: 24px; border: 1px solid rgba(34, 211, 238, 0.3); background: rgba(18, 18, 22, 0.98); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border-radius: var(--r-md);">
630
+ <div class="modal-header"
631
+ style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
632
+ <h2 id="relationModalTitle" style="margin: 0; font-size: 1.15rem; font-weight: 700; color: #fff;">Tweak
633
+ Relationship</h2>
634
+ <button id="closeRelationModalBtn"
635
+ style="background: transparent; border: none; font-size: 1.25rem; cursor: pointer; color: var(--text-secondary); width: auto; padding: 0;">✕</button>
636
+ </div>
637
+ <div class="modal-body" style="display: flex; flex-direction: column; gap: 14px; text-align: left;">
638
+ <div class="field-group" style="display: flex; flex-direction: column; gap: 4px;">
639
+ <label class="field-label" style="font-weight: 600; color: var(--text-secondary); font-size: 0.82rem;">X
640
+ Variable (Source Column)</label>
641
+ <select id="relationModalXSelect" class="field-input"
642
+ style="width:100%; box-sizing:border-box; background:var(--bg-card); color:var(--text-primary); border:1px solid var(--border-mid); border-radius:var(--r-sm); padding:8px;"></select>
643
+ </div>
644
+ <div class="field-group" style="display: flex; flex-direction: column; gap: 4px;">
645
+ <label class="field-label" style="font-weight: 600; color: var(--text-secondary); font-size: 0.82rem;">Y
646
+ Variable (Target Column)</label>
647
+ <select id="relationModalYSelect" class="field-input"
648
+ style="width:100%; box-sizing:border-box; background:var(--bg-card); color:var(--text-primary); border:1px solid var(--border-mid); border-radius:var(--r-sm); padding:8px;"></select>
649
+ </div>
650
+ <div class="field-group" style="display: flex; flex-direction: column; gap: 4px;">
651
+ <label class="field-label" style="font-weight: 600; color: var(--text-secondary); font-size: 0.82rem;">Visual
652
+ Plot Recommendation</label>
653
+ <select id="relationModalTypeSelect" class="field-input"
654
+ style="width:100%; box-sizing:border-box; background:var(--bg-card); color:var(--text-primary); border:1px solid var(--border-mid); border-radius:var(--r-sm); padding:8px;">
655
+ <option value="Scatter Plot">Scatter Plot</option>
656
+ <option value="Bar Chart">Bar Chart</option>
657
+ <option value="Line Chart">Line Chart</option>
658
+ <option value="Box Plot">Box Plot</option>
659
+ <option value="Histogram">Histogram</option>
660
+ <option value="Heatmap">Heatmap</option>
661
+ </select>
662
+ </div>
663
+ <div class="field-group" style="display: flex; flex-direction: column; gap: 4px;">
664
+ <label class="field-label"
665
+ style="font-weight: 600; color: var(--text-secondary); font-size: 0.82rem;">Correlation &amp; Statistical
666
+ Details</label>
667
+ <textarea id="relationModalDetails" class="field-input" rows="3"
668
+ placeholder="Explain the relationship correlation or domain relevance..."
669
+ style="width:100%; box-sizing:border-box; font-family:inherit; resize:none; padding:8px; background:var(--bg-card); color:var(--text-primary); border:1px solid var(--border-mid); border-radius:var(--r-sm);"></textarea>
670
+ </div>
671
+ </div>
672
+ <div class="modal-footer" style="display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px;">
673
+ <button id="relationModalCancelBtn" class="btn-secondary" style="padding: 8px 16px;">Cancel</button>
674
+ <button id="relationModalConfirmBtn" class="btn-primary" style="padding: 8px 16px;">Apply Changes</button>
675
+ </div>
676
+ </div>
677
+ </div>
678
+
679
+ <!-- API Warning Modal -->
680
+ <div id="apiWarningModal" class="modal-overlay hidden">
681
+ <div class="modal-box" style="max-width: 420px; text-align: center; padding: 30px;">
682
+ <div class="modal-icon" style="font-size: 3rem; margin-bottom: 15px;"><i data-lucide="key"
683
+ style="width: 48px; height: 48px; color: var(--violet-light);"></i></div>
684
+ <h2 style="margin-bottom: 10px;">API Key Required</h2>
685
+ <p style="font-size: 0.88rem; color: var(--text-secondary); line-height: 1.5; margin-bottom: 24px;">
686
+ An API key is required to run the analysis with <span id="warningProviderName"
687
+ style="color: var(--violet-light); font-weight: 600;"></span>. Let's configure it in your LLM Settings.
688
+ </p>
689
+ <div style="display: flex; flex-direction: column; gap: 10px;">
690
+ <button id="guideToApiBtn" class="btn-primary" style="width: 100%;">Configure API Key Now</button>
691
+ <button id="closeApiWarningBtn" class="btn-secondary" style="width: 100%;">Cancel</button>
692
+ </div>
693
+ </div>
694
+ </div>
695
+
696
+ <!-- ─── METRICS SCREEN ─── -->
697
+ <section id="metricsScreen" class="screen" style="padding: 24px; max-width: 1200px; margin: 0 auto; width: 100%; box-sizing: border-box;">
698
+ <div class="section-title-row" style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center; width: 100%;">
699
+ <h1 class="hero-title" style="margin: 0; font-size: 1.8rem; font-weight: 700; line-height: 1.2;"><span class="gradient-text">Performance Metrics</span></h1>
700
+ <button id="backToDashboardBtn" class="btn-secondary" style="padding: 8px 16px; border-radius: var(--r-sm); font-size: 0.85rem; cursor: pointer; display: flex; align-items: center; gap: 6px;"><i data-lucide="arrow-left" style="width: 14px; height: 14px;"></i> Back</button>
701
+ </div>
702
+ <p style="color: var(--text-secondary); margin-bottom: 24px; font-size: 0.9rem;">Track runtime performance, token consumption, and API costs across your data analysis runs.</p>
703
+
704
+ <!-- Metrics overview cards -->
705
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px; margin-bottom: 30px; width: 100%;">
706
+ <div class="stat-card" style="background: var(--bg-elevated); border: 1px solid var(--border); padding: 20px; border-radius: var(--r-md); box-sizing: border-box;">
707
+ <div style="font-size: 0.75rem; color: var(--text-secondary); font-weight: 600; margin-bottom: 8px; letter-spacing: 0.05em; text-transform: uppercase;">TOTAL RUNS</div>
708
+ <div id="metricsTotalRuns" style="font-size: 2rem; font-weight: 700; color: #fff;">0</div>
709
+ </div>
710
+ <div class="stat-card" style="background: var(--bg-elevated); border: 1px solid var(--border); padding: 20px; border-radius: var(--r-md); box-sizing: border-box;">
711
+ <div style="font-size: 0.75rem; color: var(--text-secondary); font-weight: 600; margin-bottom: 8px; letter-spacing: 0.05em; text-transform: uppercase;">AVG RUN TIME</div>
712
+ <div id="metricsAvgTime" style="font-size: 2rem; font-weight: 700; color: var(--violet-light);">0s</div>
713
+ </div>
714
+ <div class="stat-card" style="background: var(--bg-elevated); border: 1px solid var(--border); padding: 20px; border-radius: var(--r-md); box-sizing: border-box;">
715
+ <div style="font-size: 0.75rem; color: var(--text-secondary); font-weight: 600; margin-bottom: 8px; letter-spacing: 0.05em; text-transform: uppercase;">TOTAL TOKENS USED</div>
716
+ <div id="metricsTotalTokens" style="font-size: 2rem; font-weight: 700; color: var(--cyan);">0</div>
717
+ </div>
718
+ <div class="stat-card" style="background: var(--bg-elevated); border: 1px solid var(--border); padding: 20px; border-radius: var(--r-md); box-sizing: border-box;">
719
+ <div style="font-size: 0.75rem; color: var(--text-secondary); font-weight: 600; margin-bottom: 8px; letter-spacing: 0.05em; text-transform: uppercase;">ESTIMATED COST</div>
720
+ <div id="metricsTotalCost" style="font-size: 2rem; font-weight: 700; color: var(--amber);">$0.00</div>
721
+ </div>
722
+ </div>
723
+
724
+ <!-- Metrics table -->
725
+ <div style="background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; width: 100%; box-sizing: border-box;">
726
+ <div style="padding: 16px 20px; border-bottom: 1px solid var(--border); font-weight: 600; color: #fff; font-size: 0.95rem; background: rgba(255,255,255,0.01);">Run Execution History</div>
727
+ <div style="overflow-x: auto; max-height: 400px; width: 100%;">
728
+ <table style="width: 100%; border-collapse: collapse; text-align: left; font-size: 0.88rem; min-width: 700px;">
729
+ <thead>
730
+ <tr style="border-bottom: 1px solid var(--border); color: var(--text-secondary); font-weight: 600; background: rgba(0,0,0,0.15);">
731
+ <th style="padding: 12px 20px;">Dataset</th>
732
+ <th style="padding: 12px 20px;">Shape</th>
733
+ <th style="padding: 12px 20px;">Total Duration</th>
734
+ <th style="padding: 12px 20px;">Tokens Used</th>
735
+ <th style="padding: 12px 20px;">Estimated Cost</th>
736
+ <th style="padding: 12px 20px;">Timestamp</th>
737
+ <th style="padding: 12px 20px;">Status</th>
738
+ </tr>
739
+ </thead>
740
+ <tbody id="metricsTableBody">
741
+ <!-- Rendered dynamically -->
742
+ </tbody>
743
+ </table>
744
+ </div>
745
+ </div>
746
+ </section>
747
+
748
+ <!-- Settings Modal -->
749
+ <div id="settingsModal" class="modal-overlay hidden">
750
+ <div class="modal-box" style="max-width: 500px;">
751
+ <div class="modal-header">
752
+ <h2><i data-lucide="settings" style="width: 20px; height: 20px; vertical-align: middle; margin-right: 6px;"></i>
753
+ API Credentials &amp; Settings</h2>
754
+ <button id="closeSettingsModal" class="btn-icon">✕</button>
755
+ </div>
756
+
757
+ <div class="modal-body"
758
+ style="display: flex; flex-direction: column; gap: 14px; max-height: 520px; overflow-y: auto; padding-right: 4px;">
759
+ <p class="modal-hint">Configure API keys for each LLM provider. Keys are saved securely in your browser.
760
+ Check/uncheck "Show in sidebar" to filter the options on your dashboard.</p>
761
+
762
+ <!-- Provider Key inputs -->
763
+ <div style="display: flex; flex-direction: column; gap: 14px;">
764
+ <!-- NVIDIA -->
765
+ <div class="setting-row">
766
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
767
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">NVIDIA NIM API Key</label>
768
+ <label
769
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
770
+ <input type="checkbox" id="showNvidia" class="setting-show-checkbox" checked /> Show in sidebar
771
+ </label>
772
+ </div>
773
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
774
+ <input type="password" id="keyNvidia" class="field-input setting-key" placeholder="Enter key…"
775
+ style="flex: 1;" />
776
+ <button class="btn-eye toggle-setting-key" title="Show/hide key" style="padding: 0 10px;">👁</button>
777
+ <button class="btn-secondary test-individual-btn" data-provider="nvidia"
778
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
779
+ </div>
780
+ <div class="individual-status" id="statusNvidia"
781
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
782
+ </div>
783
+
784
+ <!-- Groq -->
785
+ <div class="setting-row">
786
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
787
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">Groq API Key</label>
788
+ <label
789
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
790
+ <input type="checkbox" id="showGroq" class="setting-show-checkbox" checked /> Show in sidebar
791
+ </label>
792
+ </div>
793
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
794
+ <input type="password" id="keyGroq" class="field-input setting-key" placeholder="Enter key…"
795
+ style="flex: 1;" />
796
+ <button class="btn-eye toggle-setting-key" title="Show/hide key" style="padding: 0 10px;">👁</button>
797
+ <button class="btn-secondary test-individual-btn" data-provider="groq"
798
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
799
+ </div>
800
+ <div class="individual-status" id="statusGroq"
801
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
802
+ </div>
803
+
804
+ <!-- OpenAI -->
805
+ <div class="setting-row">
806
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
807
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">OpenAI API Key</label>
808
+ <label
809
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
810
+ <input type="checkbox" id="showOpenai" class="setting-show-checkbox" checked /> Show in sidebar
811
+ </label>
812
+ </div>
813
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
814
+ <input type="password" id="keyOpenai" class="field-input setting-key" placeholder="Enter key…"
815
+ style="flex: 1;" />
816
+ <button class="btn-eye toggle-setting-key" title="Show/hide key" style="padding: 0 10px;">👁</button>
817
+ <button class="btn-secondary test-individual-btn" data-provider="openai"
818
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
819
+ </div>
820
+ <div class="individual-status" id="statusOpenai"
821
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
822
+ </div>
823
+
824
+ <!-- Anthropic -->
825
+ <div class="setting-row">
826
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
827
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">Anthropic API Key</label>
828
+ <label
829
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
830
+ <input type="checkbox" id="showAnthropic" class="setting-show-checkbox" checked /> Show in sidebar
831
+ </label>
832
+ </div>
833
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
834
+ <input type="password" id="keyAnthropic" class="field-input setting-key" placeholder="Enter key…"
835
+ style="flex: 1;" />
836
+ <button class="btn-eye toggle-setting-key" title="Show/hide key" style="padding: 0 10px;">👁</button>
837
+ <button class="btn-secondary test-individual-btn" data-provider="anthropic"
838
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
839
+ </div>
840
+ <div class="individual-status" id="statusAnthropic"
841
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
842
+ </div>
843
+
844
+ <!-- Google Gemini -->
845
+ <div class="setting-row">
846
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
847
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">Google Gemini API Key</label>
848
+ <label
849
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
850
+ <input type="checkbox" id="showGemini" class="setting-show-checkbox" checked /> Show in sidebar
851
+ </label>
852
+ </div>
853
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
854
+ <input type="password" id="keyGemini" class="field-input setting-key" placeholder="Enter key…"
855
+ style="flex: 1;" />
856
+ <button class="btn-eye toggle-setting-key" title="Show/hide key" style="padding: 0 10px;">👁</button>
857
+ <button class="btn-secondary test-individual-btn" data-provider="gemini"
858
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
859
+ </div>
860
+ <div class="individual-status" id="statusGemini"
861
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
862
+ </div>
863
+
864
+ <!-- Mistral -->
865
+ <div class="setting-row">
866
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
867
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">Mistral API Key</label>
868
+ <label
869
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
870
+ <input type="checkbox" id="showMistral" class="setting-show-checkbox" checked /> Show in sidebar
871
+ </label>
872
+ </div>
873
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
874
+ <input type="password" id="keyMistral" class="field-input setting-key" placeholder="Enter key…"
875
+ style="flex: 1;" />
876
+ <button class="btn-eye toggle-setting-key" title="Show/hide key" style="padding: 0 10px;">👁</button>
877
+ <button class="btn-secondary test-individual-btn" data-provider="mistral"
878
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
879
+ </div>
880
+ <div class="individual-status" id="statusMistral"
881
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
882
+ </div>
883
+
884
+ <!-- HuggingFace -->
885
+ <div class="setting-row">
886
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
887
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">HuggingFace API Key</label>
888
+ <label
889
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
890
+ <input type="checkbox" id="showHuggingface" class="setting-show-checkbox" checked /> Show in sidebar
891
+ </label>
892
+ </div>
893
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
894
+ <input type="password" id="keyHuggingface" class="field-input setting-key" placeholder="Enter key…"
895
+ style="flex: 1;" />
896
+ <button class="btn-eye toggle-setting-key" title="Show/hide key" style="padding: 0 10px;">👁</button>
897
+ <button class="btn-secondary test-individual-btn" data-provider="huggingface"
898
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
899
+ </div>
900
+ <div class="individual-status" id="statusHuggingface"
901
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
902
+ </div>
903
+
904
+ <!-- Cohere -->
905
+ <div class="setting-row">
906
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
907
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">Cohere API Key</label>
908
+ <label
909
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
910
+ <input type="checkbox" id="showCohere" class="setting-show-checkbox" checked /> Show in sidebar
911
+ </label>
912
+ </div>
913
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
914
+ <input type="password" id="keyCohere" class="field-input setting-key" placeholder="Enter key…"
915
+ style="flex: 1;" />
916
+ <button class="btn-eye toggle-setting-key" title="Show/hide key" style="padding: 0 10px;">👁</button>
917
+ <button class="btn-secondary test-individual-btn" data-provider="cohere"
918
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
919
+ </div>
920
+ <div class="individual-status" id="statusCohere"
921
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
922
+ </div>
923
+
924
+ <!-- TogetherAI -->
925
+ <div class="setting-row">
926
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
927
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">TogetherAI API Key</label>
928
+ <label
929
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
930
+ <input type="checkbox" id="showTogether" class="setting-show-checkbox" checked /> Show in sidebar
931
+ </label>
932
+ </div>
933
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
934
+ <input type="password" id="keyTogether" class="field-input setting-key" placeholder="Enter key…"
935
+ style="flex: 1;" />
936
+ <button class="btn-eye toggle-setting-key" title="Show/hide key" style="padding: 0 10px;">👁</button>
937
+ <button class="btn-secondary test-individual-btn" data-provider="together"
938
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
939
+ </div>
940
+ <div class="individual-status" id="statusTogether"
941
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
942
+ </div>
943
+
944
+ <!-- OpenRouter -->
945
+ <div class="setting-row">
946
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
947
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">OpenRouter API Key</label>
948
+ <label
949
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
950
+ <input type="checkbox" id="showOpenrouter" class="setting-show-checkbox" checked /> Show in sidebar
951
+ </label>
952
+ </div>
953
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
954
+ <input type="password" id="keyOpenrouter" class="field-input setting-key" placeholder="Enter key…"
955
+ style="flex: 1;" />
956
+ <button class="btn-eye toggle-setting-key" title="Show/hide key" style="padding: 0 10px;">👁</button>
957
+ <button class="btn-secondary test-individual-btn" data-provider="openrouter"
958
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
959
+ </div>
960
+ <div class="individual-status" id="statusOpenrouter"
961
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
962
+ </div>
963
+
964
+ <!-- DeepSeek -->
965
+ <div class="setting-row">
966
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
967
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">DeepSeek API Key</label>
968
+ <label
969
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
970
+ <input type="checkbox" id="showDeepseek" class="setting-show-checkbox" checked /> Show in sidebar
971
+ </label>
972
+ </div>
973
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
974
+ <input type="password" id="keyDeepseek" class="field-input setting-key" placeholder="Enter key…"
975
+ style="flex: 1;" />
976
+ <button class="btn-eye toggle-setting-key" title="Show/hide key" style="padding: 0 10px;">👁</button>
977
+ <button class="btn-secondary test-individual-btn" data-provider="deepseek"
978
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
979
+ </div>
980
+ <div class="individual-status" id="statusDeepseek"
981
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
982
+ </div>
983
+
984
+ <!-- Perplexity -->
985
+ <div class="setting-row">
986
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
987
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">Perplexity API Key</label>
988
+ <label
989
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
990
+ <input type="checkbox" id="showPerplexity" class="setting-show-checkbox" checked /> Show in sidebar
991
+ </label>
992
+ </div>
993
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
994
+ <input type="password" id="keyPerplexity" class="field-input setting-key" placeholder="Enter key…"
995
+ style="flex: 1;" />
996
+ <button class="btn-eye toggle-setting-key" title="Show/hide key" style="padding: 0 10px;">👁</button>
997
+ <button class="btn-secondary test-individual-btn" data-provider="perplexity"
998
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
999
+ </div>
1000
+ <div class="individual-status" id="statusPerplexity"
1001
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
1002
+ </div>
1003
+
1004
+ <!-- Ollama Base URL -->
1005
+ <div class="setting-row">
1006
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
1007
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">Ollama Base URL</label>
1008
+ <label
1009
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
1010
+ <input type="checkbox" id="showOllama" class="setting-show-checkbox" checked /> Show in sidebar
1011
+ </label>
1012
+ </div>
1013
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
1014
+ <input type="text" id="urlOllama" class="field-input setting-key" placeholder="http://localhost:11434"
1015
+ style="flex: 1;" />
1016
+ <button class="btn-secondary test-individual-btn" data-provider="ollama"
1017
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
1018
+ </div>
1019
+ <div class="individual-status" id="statusOllama"
1020
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
1021
+ </div>
1022
+
1023
+ <!-- Custom API URL & Key -->
1024
+ <div class="setting-row">
1025
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
1026
+ <label class="field-label" style="margin-bottom: 0; font-weight: 600;">Custom Base URL & Key</label>
1027
+ <label
1028
+ style="display: inline-flex; align-items: center; gap: 6px; font-size: 0.72rem; color: var(--text-secondary); cursor: pointer;">
1029
+ <input type="checkbox" id="showCustom" class="setting-show-checkbox" checked /> Show in sidebar
1030
+ </label>
1031
+ </div>
1032
+ <div class="key-input-wrap" style="display: flex; gap: 8px;">
1033
+ <input type="text" id="urlCustom" class="field-input setting-key" placeholder="https://api.your-provider.com/v1"
1034
+ style="flex: 1;" />
1035
+ <input type="password" id="keyCustom" class="field-input setting-key" placeholder="Enter key…"
1036
+ style="flex: 1;" />
1037
+ <button class="btn-secondary test-individual-btn" data-provider="custom"
1038
+ style="padding: 0 12px; font-size: 0.75rem; white-space: nowrap;">🔌 Test</button>
1039
+ </div>
1040
+ <div class="individual-status" id="statusCustom"
1041
+ style="font-size: 0.72rem; margin-top: 4px; min-height: 14px;"></div>
1042
+ </div>
1043
+ </div>
1044
+
1045
+ <hr style="border: none; border-top: 1px solid var(--border); margin: 8px 0;" />
1046
+
1047
+ <!-- Cooldown -->
1048
+ <div>
1049
+ <label class="field-label" style="display: block; margin-bottom: 6px;">API Cooldown: <span
1050
+ id="settingsCooldownVal">5</span>s</label>
1051
+ <input type="range" id="settingsCooldown" class="field-range" min="0" max="60" value="5" />
1052
+ </div>
1053
+ </div>
1054
+
1055
+ <div class="modal-footer">
1056
+ <button id="cancelSettingsBtn" class="btn-secondary">Close</button>
1057
+ <button id="saveSettingsBtn" class="btn-primary">Save Settings</button>
1058
+ </div>
1059
+ </div>
1060
+ </div>
1061
+
1062
+ <!-- Custom Dialog Modal (Alert/Confirm/Prompt) -->
1063
+ <div id="customDialogModal" class="modal-overlay hidden">
1064
+ <div class="modal-box" style="max-width: 460px;">
1065
+ <div class="modal-header">
1066
+ <h2 id="customDialogTitle">Confirm Action</h2>
1067
+ <button id="closeCustomDialogBtn" class="btn-icon">✕</button>
1068
+ </div>
1069
+ <div class="modal-body" style="gap: 16px; padding: 24px;">
1070
+ <p id="customDialogMessage"
1071
+ style="font-size: 0.92rem; line-height: 1.6; color: var(--text-secondary); margin: 0;"></p>
1072
+ <div id="customDialogPromptContainer" class="field-group hidden" style="margin-top: 8px;">
1073
+ <input type="text" id="customDialogInput" class="field-input"
1074
+ style="width: 100%; text-align: left; font-size: 0.95rem; padding: 10px 14px;" />
1075
+ </div>
1076
+ </div>
1077
+ <div class="modal-footer" style="padding: 16px 24px; background: rgba(0,0,0,0.15);">
1078
+ <button id="customDialogCancelBtn" class="btn-secondary">Cancel</button>
1079
+ <button id="customDialogConfirmBtn" class="btn-primary">Confirm</button>
1080
+ </div>
1081
+ </div>
1082
+ </div>
1083
+
1084
+ <!-- Floating Analysis Notification Widget (Top Right) -->
1085
+ <div id="analysisNotification" class="analysis-notification-toast hidden">
1086
+ <button id="dismissNotif" class="notif-close-btn">&times;</button>
1087
+ <div class="notification-body">
1088
+ <div class="notif-spinner"></div>
1089
+ <div class="notif-content">
1090
+ <div class="notif-title">Crewlyze Analysis Active</div>
1091
+ <div class="notif-details"><span id="notifActiveJob">Cleaning...</span> | <span id="notifTimer">00:00</span>
1092
+ </div>
1093
+ </div>
1094
+ <button id="btnMaximizeNotif" class="btn-primary btn-xs"
1095
+ style="padding: 6px 10px; font-size: 0.75rem; font-weight: 600; border-radius: var(--r-md);">View</button>
1096
+ </div>
1097
+ </div>
1098
+
1099
+ <!-- Toast notifications -->
1100
+ <div id="toastContainer" class="toast-container"></div>
1101
+
1102
+ <script src="/app.js"></script>
1103
+ </body>
1104
+
1105
+ </html>