Mridul Jain commited on
Commit
8c8e9ae
·
1 Parent(s): 17a146a

UI Excellence: Synchronizing Premium Dashboard refinements (v3.5/v3.8)

Browse files
Files changed (3) hide show
  1. server/static/app.js +54 -36
  2. server/static/index.html +204 -140
  3. server/static/style.css +895 -129
server/static/app.js CHANGED
@@ -6,6 +6,7 @@ const app = {
6
  typewriterTimeout: null,
7
  isAutoTraining: false,
8
  metrics: { count: 0, sumReward: 0 },
 
9
 
10
  init: function() {
11
  this.connectWS();
@@ -44,8 +45,30 @@ const app = {
44
  };
45
  },
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  startEpisode: function(taskId) {
48
  this.currentTask = taskId;
 
 
 
 
 
 
 
 
 
49
  const config = JSON.parse(sessionStorage.getItem('env_config') || '{}');
50
  this.ws.send(JSON.stringify({
51
  action: "reset",
@@ -54,7 +77,7 @@ const app = {
54
  }));
55
 
56
  document.getElementById('landing-page').style.display = 'none';
57
- document.getElementById('main-interface').style.display = 'block';
58
  document.getElementById('reward-overlay').style.display = 'none';
59
 
60
  // Reset Terminal
@@ -68,23 +91,20 @@ const app = {
68
  const b = obs.policy_briefing;
69
  const r = obs.global_risk;
70
 
71
- // Elite v3.0: Policy Briefing Update
72
  const banner = document.getElementById('policy-alert-banner');
73
  document.getElementById('alert-level').textContent = b.alert_level.toUpperCase();
74
  document.getElementById('alert-topic').textContent = b.current_focus;
75
  document.getElementById('alert-summary').textContent = b.guidance_summary;
76
-
77
- // Alert styling
78
  banner.className = 'alert-banner box-glow ' + b.alert_level.toLowerCase();
79
 
80
- // Elite v3.0: Risk Metrics
81
  document.getElementById('val-queue-depth').textContent = r.queue_depth;
82
  document.getElementById('val-avg-harm').textContent = r.avg_harm_potential;
83
 
84
  document.getElementById('current-task-badge').textContent = obs.task_name;
85
  document.getElementById('val-post-id').textContent = c.post_id;
86
  document.getElementById('val-platform').textContent = c.platform;
87
-
88
  document.getElementById('val-user-age').textContent = c.user_account.account_age_days;
89
  document.getElementById('val-prior-violations').textContent = c.user_account.prior_violations;
90
  document.getElementById('val-reports').textContent = c.engagement.reports_received;
@@ -114,7 +134,7 @@ const app = {
114
  html += `</div>`;
115
  }
116
 
117
- html += `<button class="btn btn-outline w-full" style="margin-top:0.5rem;" onclick="app.submitAction()">Manual Commit</button>`;
118
  panel.innerHTML = html;
119
  },
120
 
@@ -126,7 +146,7 @@ const app = {
126
  let val = input.value;
127
  if (input.type === 'number') val = parseInt(val, 10);
128
  if (key === 'policy_references' || key === 'diagnoses' || input.placeholder === 'Comma separated values') {
129
- val = val ? val.split(',').map(s=>s.trim()) : [];
130
  }
131
  payload[key] = val;
132
  });
@@ -135,6 +155,7 @@ const app = {
135
  this.ws.send(JSON.stringify({ action: "step", data: payload }));
136
  },
137
 
 
138
  toggleAutoLoop: function() {
139
  this.isAutoTraining = !this.isAutoTraining;
140
  const btn = document.getElementById('btn-auto-loop');
@@ -151,16 +172,14 @@ const app = {
151
  }
152
  },
153
 
154
- runAgent: function(isLooping = false) {
155
  this.terminalPrint(`> Autonomous agent invoked.`);
156
 
157
- // Setup streaming block
158
  const term = document.getElementById('terminal-output');
159
  this.terminalActiveLine = document.createElement('div');
160
  this.terminalActiveLine.className = 'log-line running';
161
  term.appendChild(this.terminalActiveLine);
162
 
163
- // Disable buttons to prevent spamming overlapping tasks
164
  document.getElementById('btn-run-agent').disabled = true;
165
  document.getElementById('btn-run-agent').style.opacity = '0.5';
166
  document.getElementById('btn-auto-loop').disabled = true;
@@ -178,7 +197,6 @@ const app = {
178
 
179
  this.terminalActiveLine.textContent += content;
180
 
181
- // Debounce scrolling to fix browser lag
182
  if (!this.scrollPending) {
183
  this.scrollPending = true;
184
  requestAnimationFrame(() => {
@@ -190,7 +208,6 @@ const app = {
190
  },
191
 
192
  handleStep: function(result) {
193
- // Stop streaming cursor
194
  if (this.terminalActiveLine) {
195
  this.terminalActiveLine.classList.remove('running');
196
  this.terminalActiveLine = null;
@@ -200,7 +217,7 @@ const app = {
200
  const rc = document.getElementById('reward-display');
201
  rc.textContent = rw.toFixed(2);
202
 
203
- let color = 'var(--danger)';
204
  let shadow = 'rgba(244, 63, 94, 0.5)';
205
  if (rw >= 0.8) { color = 'var(--success)'; shadow = 'rgba(16, 185, 129, 0.5)'; }
206
  else if (rw >= 0.4) { color = 'var(--warning)'; shadow = 'rgba(251, 191, 36, 0.5)'; }
@@ -212,7 +229,6 @@ const app = {
212
  document.getElementById('feedback-display').textContent = result.info.feedback;
213
  document.getElementById('reward-overlay').style.display = 'flex';
214
 
215
- // Re-enable button
216
  document.getElementById('btn-run-agent').disabled = false;
217
  document.getElementById('btn-run-agent').style.opacity = '1';
218
  document.getElementById('btn-auto-loop').disabled = false;
@@ -227,7 +243,7 @@ const app = {
227
  this.terminalPrint(`==============================`);
228
  this.terminalPrint('');
229
 
230
- // Update HUD Metrics
231
  this.metrics.count++;
232
  this.metrics.sumReward += rw;
233
  document.getElementById('hud-episodes').textContent = this.metrics.count;
@@ -237,23 +253,25 @@ const app = {
237
  this.terminalPrint(`> [LOOP] Waiting 2s before initiating next cycle...`);
238
  setTimeout(() => {
239
  if (this.isAutoTraining) {
240
- this.closeReward(true); // Resets environment and clears terminal safely
241
  setTimeout(() => {
242
  if (this.isAutoTraining) this.runAgent(true);
243
- }, 500); // Wait for reset to finish
244
  }
245
  }, 2000);
246
  }
247
  },
248
 
249
- closeReward: function(triggerNext = true) {
250
  document.getElementById('reward-overlay').style.display = 'none';
251
-
252
- // Clear terminal when explicitly moving to the next case
253
  document.getElementById('terminal-output').innerHTML = '';
254
-
255
  if (triggerNext && this.currentTask) this.startEpisode(this.currentTask);
256
  },
 
 
 
 
 
257
 
258
  terminalPrint: function(msg) {
259
  if (this.terminalActiveLine) {
@@ -266,7 +284,6 @@ const app = {
266
  line.textContent = msg;
267
  term.appendChild(line);
268
 
269
- // Truncate logic to prevent PC lag from infinitely expanding DOM
270
  while (term.children.length > 50) {
271
  term.removeChild(term.firstChild);
272
  }
@@ -294,15 +311,15 @@ const app = {
294
  type();
295
  },
296
 
 
297
  initVisuals: function() {
298
- // --- Fluid Particles Canvas System ---
299
  const canvas = document.getElementById('fluid-canvas');
300
  if (!canvas) return;
301
  const ctx = canvas.getContext('2d');
302
  let width = canvas.width = window.innerWidth;
303
  let height = canvas.height = window.innerHeight;
304
  const particles = [];
305
- const numParticles = 80;
306
 
307
  window.addEventListener('resize', () => {
308
  width = canvas.width = window.innerWidth;
@@ -313,10 +330,14 @@ const app = {
313
  particles.push({
314
  x: Math.random() * width,
315
  y: Math.random() * height,
316
- vx: (Math.random() - 0.5) * 0.5,
317
- vy: (Math.random() - 0.5) * 0.5,
318
- radius: Math.random() * 2 + 1,
319
- color: Math.random() > 0.5 ? 'rgba(99, 102, 241, 0.4)' : 'rgba(16, 185, 129, 0.3)'
 
 
 
 
320
  });
321
  }
322
 
@@ -326,7 +347,6 @@ const app = {
326
  particles.forEach(p => {
327
  p.x += p.vx;
328
  p.y += p.vy;
329
-
330
  if (p.x < 0 || p.x > width) p.vx *= -1;
331
  if (p.y < 0 || p.y > height) p.vy *= -1;
332
 
@@ -336,16 +356,15 @@ const app = {
336
  ctx.fill();
337
  });
338
 
339
- // Draw connecting lines
340
  for (let i = 0; i < particles.length; i++) {
341
  for (let j = i + 1; j < particles.length; j++) {
342
  const dx = particles[i].x - particles[j].x;
343
  const dy = particles[i].y - particles[j].y;
344
  const dist = Math.sqrt(dx * dx + dy * dy);
345
 
346
- if (dist < 150) {
347
  ctx.beginPath();
348
- ctx.strokeStyle = `rgba(255, 255, 255, ${0.1 - dist/1500})`;
349
  ctx.lineWidth = 0.5;
350
  ctx.moveTo(particles[i].x, particles[i].y);
351
  ctx.lineTo(particles[j].x, particles[j].y);
@@ -358,7 +377,7 @@ const app = {
358
  draw();
359
  },
360
 
361
- // --- Elite v3.3: Credential Management ---
362
  toggleSettings: function() {
363
  const modal = document.getElementById('settings-modal');
364
  modal.style.display = modal.style.display === 'none' ? 'flex' : 'none';
@@ -370,12 +389,11 @@ const app = {
370
  const baseUrl = document.getElementById('cfg-base-url').value;
371
  const model = document.getElementById('cfg-model').value;
372
 
373
- // Elite v3.5: Client-side Smart Validation
374
  if (apiKey.startsWith('hf_') && (!baseUrl || baseUrl.includes('openai.com'))) {
375
  if (confirm("Detected Hugging Face Token but OpenAI endpoint. Auto-switch to Hugging Face Inference API?")) {
376
  document.getElementById('cfg-base-url').value = "https://api-inference.huggingface.co/v1";
377
  if (!model) document.getElementById('cfg-model').value = "meta-llama/Llama-3-70b-instruct";
378
- return; // Let them save again with the new values
379
  }
380
  }
381
 
 
6
  typewriterTimeout: null,
7
  isAutoTraining: false,
8
  metrics: { count: 0, sumReward: 0 },
9
+ scrollPending: false,
10
 
11
  init: function() {
12
  this.connectWS();
 
45
  };
46
  },
47
 
48
+ // ===== SIDEBAR =====
49
+ toggleSidebar: function() {
50
+ const sidebar = document.getElementById('sidebar');
51
+ sidebar.classList.toggle('open');
52
+ },
53
+
54
+ setActiveNav: function(taskId) {
55
+ document.querySelectorAll('.nav-item[data-task]').forEach(btn => {
56
+ btn.classList.toggle('active', btn.dataset.task === taskId);
57
+ });
58
+ },
59
+
60
+ // ===== EPISODES =====
61
  startEpisode: function(taskId) {
62
  this.currentTask = taskId;
63
+ this.setActiveNav(taskId);
64
+
65
+ // Update breadcrumb
66
+ const labels = { easy: 'Easy (Detect)', medium: 'Medium (Action)', hard: 'Hard (Appeal)' };
67
+ document.getElementById('breadcrumb-task').textContent = labels[taskId] || taskId;
68
+
69
+ // Close sidebar on mobile
70
+ document.getElementById('sidebar').classList.remove('open');
71
+
72
  const config = JSON.parse(sessionStorage.getItem('env_config') || '{}');
73
  this.ws.send(JSON.stringify({
74
  action: "reset",
 
77
  }));
78
 
79
  document.getElementById('landing-page').style.display = 'none';
80
+ document.getElementById('main-interface').style.display = 'flex';
81
  document.getElementById('reward-overlay').style.display = 'none';
82
 
83
  // Reset Terminal
 
91
  const b = obs.policy_briefing;
92
  const r = obs.global_risk;
93
 
94
+ // Policy Briefing
95
  const banner = document.getElementById('policy-alert-banner');
96
  document.getElementById('alert-level').textContent = b.alert_level.toUpperCase();
97
  document.getElementById('alert-topic').textContent = b.current_focus;
98
  document.getElementById('alert-summary').textContent = b.guidance_summary;
 
 
99
  banner.className = 'alert-banner box-glow ' + b.alert_level.toLowerCase();
100
 
101
+ // Risk Metrics
102
  document.getElementById('val-queue-depth').textContent = r.queue_depth;
103
  document.getElementById('val-avg-harm').textContent = r.avg_harm_potential;
104
 
105
  document.getElementById('current-task-badge').textContent = obs.task_name;
106
  document.getElementById('val-post-id').textContent = c.post_id;
107
  document.getElementById('val-platform').textContent = c.platform;
 
108
  document.getElementById('val-user-age').textContent = c.user_account.account_age_days;
109
  document.getElementById('val-prior-violations').textContent = c.user_account.prior_violations;
110
  document.getElementById('val-reports').textContent = c.engagement.reports_received;
 
134
  html += `</div>`;
135
  }
136
 
137
+ html += `<button class="btn btn-outline w-full" style="margin-top: 0.5rem;" onclick="app.submitAction()"><i class="fa-solid fa-check"></i> Manual Commit</button>`;
138
  panel.innerHTML = html;
139
  },
140
 
 
146
  let val = input.value;
147
  if (input.type === 'number') val = parseInt(val, 10);
148
  if (key === 'policy_references' || key === 'diagnoses' || input.placeholder === 'Comma separated values') {
149
+ val = val ? val.split(',').map(s => s.trim()) : [];
150
  }
151
  payload[key] = val;
152
  });
 
155
  this.ws.send(JSON.stringify({ action: "step", data: payload }));
156
  },
157
 
158
+ // ===== AUTO TRAINING =====
159
  toggleAutoLoop: function() {
160
  this.isAutoTraining = !this.isAutoTraining;
161
  const btn = document.getElementById('btn-auto-loop');
 
172
  }
173
  },
174
 
175
+ runAgent: function(isLooping) {
176
  this.terminalPrint(`> Autonomous agent invoked.`);
177
 
 
178
  const term = document.getElementById('terminal-output');
179
  this.terminalActiveLine = document.createElement('div');
180
  this.terminalActiveLine.className = 'log-line running';
181
  term.appendChild(this.terminalActiveLine);
182
 
 
183
  document.getElementById('btn-run-agent').disabled = true;
184
  document.getElementById('btn-run-agent').style.opacity = '0.5';
185
  document.getElementById('btn-auto-loop').disabled = true;
 
197
 
198
  this.terminalActiveLine.textContent += content;
199
 
 
200
  if (!this.scrollPending) {
201
  this.scrollPending = true;
202
  requestAnimationFrame(() => {
 
208
  },
209
 
210
  handleStep: function(result) {
 
211
  if (this.terminalActiveLine) {
212
  this.terminalActiveLine.classList.remove('running');
213
  this.terminalActiveLine = null;
 
217
  const rc = document.getElementById('reward-display');
218
  rc.textContent = rw.toFixed(2);
219
 
220
+ let color = 'var(--danger)';
221
  let shadow = 'rgba(244, 63, 94, 0.5)';
222
  if (rw >= 0.8) { color = 'var(--success)'; shadow = 'rgba(16, 185, 129, 0.5)'; }
223
  else if (rw >= 0.4) { color = 'var(--warning)'; shadow = 'rgba(251, 191, 36, 0.5)'; }
 
229
  document.getElementById('feedback-display').textContent = result.info.feedback;
230
  document.getElementById('reward-overlay').style.display = 'flex';
231
 
 
232
  document.getElementById('btn-run-agent').disabled = false;
233
  document.getElementById('btn-run-agent').style.opacity = '1';
234
  document.getElementById('btn-auto-loop').disabled = false;
 
243
  this.terminalPrint(`==============================`);
244
  this.terminalPrint('');
245
 
246
+ // Update HUD
247
  this.metrics.count++;
248
  this.metrics.sumReward += rw;
249
  document.getElementById('hud-episodes').textContent = this.metrics.count;
 
253
  this.terminalPrint(`> [LOOP] Waiting 2s before initiating next cycle...`);
254
  setTimeout(() => {
255
  if (this.isAutoTraining) {
256
+ this.closeReward(true);
257
  setTimeout(() => {
258
  if (this.isAutoTraining) this.runAgent(true);
259
+ }, 500);
260
  }
261
  }, 2000);
262
  }
263
  },
264
 
265
+ closeReward: function(triggerNext) {
266
  document.getElementById('reward-overlay').style.display = 'none';
 
 
267
  document.getElementById('terminal-output').innerHTML = '';
 
268
  if (triggerNext && this.currentTask) this.startEpisode(this.currentTask);
269
  },
270
+
271
+ clearTerminal: function() {
272
+ document.getElementById('terminal-output').innerHTML = '';
273
+ this.terminalPrint('> Terminal cleared.');
274
+ },
275
 
276
  terminalPrint: function(msg) {
277
  if (this.terminalActiveLine) {
 
284
  line.textContent = msg;
285
  term.appendChild(line);
286
 
 
287
  while (term.children.length > 50) {
288
  term.removeChild(term.firstChild);
289
  }
 
311
  type();
312
  },
313
 
314
+ // ===== VISUALS =====
315
  initVisuals: function() {
 
316
  const canvas = document.getElementById('fluid-canvas');
317
  if (!canvas) return;
318
  const ctx = canvas.getContext('2d');
319
  let width = canvas.width = window.innerWidth;
320
  let height = canvas.height = window.innerHeight;
321
  const particles = [];
322
+ const numParticles = 60;
323
 
324
  window.addEventListener('resize', () => {
325
  width = canvas.width = window.innerWidth;
 
330
  particles.push({
331
  x: Math.random() * width,
332
  y: Math.random() * height,
333
+ vx: (Math.random() - 0.5) * 0.4,
334
+ vy: (Math.random() - 0.5) * 0.4,
335
+ radius: Math.random() * 1.8 + 0.8,
336
+ color: Math.random() > 0.6
337
+ ? 'rgba(99, 102, 241, 0.35)'
338
+ : Math.random() > 0.3
339
+ ? 'rgba(16, 185, 129, 0.25)'
340
+ : 'rgba(139, 92, 246, 0.2)'
341
  });
342
  }
343
 
 
347
  particles.forEach(p => {
348
  p.x += p.vx;
349
  p.y += p.vy;
 
350
  if (p.x < 0 || p.x > width) p.vx *= -1;
351
  if (p.y < 0 || p.y > height) p.vy *= -1;
352
 
 
356
  ctx.fill();
357
  });
358
 
 
359
  for (let i = 0; i < particles.length; i++) {
360
  for (let j = i + 1; j < particles.length; j++) {
361
  const dx = particles[i].x - particles[j].x;
362
  const dy = particles[i].y - particles[j].y;
363
  const dist = Math.sqrt(dx * dx + dy * dy);
364
 
365
+ if (dist < 140) {
366
  ctx.beginPath();
367
+ ctx.strokeStyle = `rgba(255, 255, 255, ${0.06 - dist / 2500})`;
368
  ctx.lineWidth = 0.5;
369
  ctx.moveTo(particles[i].x, particles[i].y);
370
  ctx.lineTo(particles[j].x, particles[j].y);
 
377
  draw();
378
  },
379
 
380
+ // ===== SETTINGS =====
381
  toggleSettings: function() {
382
  const modal = document.getElementById('settings-modal');
383
  modal.style.display = modal.style.display === 'none' ? 'flex' : 'none';
 
389
  const baseUrl = document.getElementById('cfg-base-url').value;
390
  const model = document.getElementById('cfg-model').value;
391
 
 
392
  if (apiKey.startsWith('hf_') && (!baseUrl || baseUrl.includes('openai.com'))) {
393
  if (confirm("Detected Hugging Face Token but OpenAI endpoint. Auto-switch to Hugging Face Inference API?")) {
394
  document.getElementById('cfg-base-url').value = "https://api-inference.huggingface.co/v1";
395
  if (!model) document.getElementById('cfg-model').value = "meta-llama/Llama-3-70b-instruct";
396
+ return;
397
  }
398
  }
399
 
server/static/index.html CHANGED
@@ -9,175 +9,239 @@
9
  <link rel="stylesheet" href="/static/style.css">
10
  </head>
11
  <body>
12
- <!-- Elite Fluid Particle Interaction Background -->
 
13
  <canvas id="fluid-canvas"></canvas>
14
 
15
- <!-- Top Navigation -->
16
- <header class="glass-panel main-header">
17
- <h1><i class="fa-solid fa-shield-halved"></i> <span>Content</span>GuardEnv</h1>
18
-
19
- <div class="task-selector" id="task-selector">
20
- <button class="btn btn-outline" onclick="app.startEpisode('easy')"><i class="fa-solid fa-magnifying-glass" style="color: #10b981;"></i> Easy (Detect)</button>
21
- <button class="btn btn-outline" onclick="app.startEpisode('medium')"><i class="fa-solid fa-gavel" style="color: #f59e0b;"></i> Medium (Action)</button>
22
- <button class="btn btn-outline" onclick="app.startEpisode('hard')"><i class="fa-solid fa-file-signature" style="color: #ef4444;"></i> Hard (Appeal)</button>
23
- </div>
24
 
25
- <div class="header-controls">
26
- <button class="btn btn-outline" onclick="app.toggleSettings()"><i class="fa-solid fa-gear"></i> Settings</button>
27
- <div class="status-badge glass-panel">
28
- <div id="status-indicator" class="status-indicator"></div>
29
- <span id="status-text">Connecting...</span>
 
 
 
 
 
30
  </div>
31
- </div>
32
- </header>
33
-
34
- <div class="container-fluid" id="landing-page">
35
- <div style="text-align: center; margin-top: 5rem;" id="intro-section">
36
- <h2 class="gradient-text" style="font-size: 3rem; margin-bottom: 0.5rem; text-transform:none;">Autonomous Moderation Workspace</h2>
37
- <p class="text-muted" style="font-size: 1.2rem;">Select a task difficulty above to spin up a simulated environment.</p>
38
- <div style="margin-top: 4rem; opacity: 0.7;">
39
- <i class="fa-brands fa-meta" style="font-size: 4rem;"></i>
40
- <i class="fa-solid fa-xmark" style="font-size: 1.5rem; margin: 0 2rem; vertical-align: super;"></i>
41
- <i class="fa-solid fa-face-smiling-hands" style="font-size: 4rem;"></i>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  </div>
43
- </div>
44
- </div>
45
 
46
- <div class="container-fluid" id="main-interface" style="display: none;">
47
- <div class="workspace-grid">
48
-
49
- <!-- Column 1: Case Data -->
50
- <div class="workspace-col fade-in" id="col-data">
51
- <div class="glass-panel panel-content h-full" style="display:flex; flex-direction:column; gap:1rem;">
52
-
53
- <!-- Elite v3.0: Policy Briefing Header -->
54
- <div class="alert-banner box-glow" id="policy-alert-banner">
55
- <div class="alert-badge" id="alert-level">GREEN</div>
56
- <div class="alert-content">
57
- <strong id="alert-topic">System Stable</strong>
58
- <p id="alert-summary">No active platform-wide risks detected.</p>
59
- </div>
60
- </div>
61
 
62
- <div class="panel-section scrollable" style="flex:1;">
63
- <div class="panel-header">
64
- <h3><i class="fa-solid fa-file-invoice"></i> Content Case <span id="current-task-badge" class="badge">Type</span></h3>
65
- <span class="post-id" id="val-post-id">#POST-XXX</span>
66
- </div>
67
-
68
- <div class="content-preview box-glow" id="val-content">
69
- <!-- Typewriter content goes here -->
 
 
 
 
 
 
 
 
 
 
70
  </div>
71
-
72
- <div class="meta-grid">
73
- <div class="stat-box">
74
- <span class="label">Platform <i class="fa-solid fa-globe"></i></span>
75
- <span class="value text-primary" id="val-platform">--</span>
76
- </div>
77
- <div class="stat-box">
78
- <span class="label">Acc. Age <i class="fa-solid fa-clock"></i></span>
79
- <span class="value" id="val-user-age">--</span>
80
- </div>
81
- <div class="stat-box">
82
- <span class="label">Violations <i class="fa-solid fa-triangle-exclamation"></i></span>
83
- <span class="value text-danger" id="val-prior-violations">--</span>
84
- </div>
85
- <div class="stat-box">
86
- <span class="label">Reports <i class="fa-solid fa-flag"></i></span>
87
- <span class="value text-warning" id="val-reports">--</span>
88
- </div>
89
  </div>
90
  </div>
 
 
91
 
92
- <!-- Elite v3.0: Platform Risk Telemetry -->
93
- <div class="panel-section" style="border-top:1px solid rgba(255,255,255,0.1); padding-top:1rem;">
94
- <h4 class="text-xs text-muted" style="margin-bottom:0.8rem; text-transform:uppercase; letter-spacing:1px;">Platform Risk Telemetry</h4>
95
- <div class="meta-grid">
96
- <div class="stat-box">
97
- <span class="label">Queue Depth</span>
98
- <span class="value" id="val-queue-depth">--</span>
99
- </div>
100
- <div class="stat-box">
101
- <span class="label">Avg Harm</span>
102
- <span class="value" id="val-avg-harm">--</span>
103
- </div>
104
- </div>
105
  </div>
106
-
107
  </div>
108
  </div>
109
 
110
- <!-- Column 2: Agent Configuration / Manual Ovveride -->
111
- <div class="workspace-col fade-in delay-1 tilt-card" id="col-config">
112
- <div class="glass-panel panel-content h-full">
113
- <div class="panel-header">
114
- <h3><i class="fa-solid fa-sliders"></i> Moderation Override</h3>
115
- </div>
116
-
117
- <div class="panel-body scrollable" style="display:flex; flex-direction:column; justify-content:space-between;">
118
- <div id="action-panel">
119
- <!-- Rendered form -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  </div>
121
-
122
- <div class="auto-agent-box">
123
- <h4><i class="fa-solid fa-robot"></i> Advanced Execution</h4>
124
- <p class="text-muted text-sm">Transfer control to the autonomous agent. Single step or enable Continuous RL Training mode.</p>
125
-
126
- <div style="display:flex; gap:0.5rem; justify-content:center;">
127
- <button class="btn btn-outline" style="border-color: #10b981; color: #10b981;" id="btn-run-agent" onclick="app.runAgent(false)">
128
- <i class="fa-solid fa-play"></i> Single Step
129
- </button>
130
-
131
- <button class="btn btn-ai" style="flex:1;" id="btn-auto-loop" onclick="app.toggleAutoLoop()">
132
- <i class="fa-solid fa-infinity"></i> Start Auto-Training Loop
133
  </button>
134
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
135
  </div>
136
  </div>
137
- </div>
138
- </div>
139
 
140
- <!-- Column 3: Terminal Feed / Results -->
141
- <div class="workspace-col fade-in delay-2 tilt-card" id="col-term">
142
- <div class="glass-panel panel-content h-full terminal-wrapper" style="display:flex; flex-direction:column;">
143
- <div class="global-hud">
144
- <div class="hud-item"><span class="hud-label">Episodes:</span><span class="hud-val" id="hud-episodes">0</span></div>
145
- <div class="hud-item"><span class="hud-label">Accuracy:</span><span class="hud-val" id="hud-accuracy">0.0%</span></div>
146
- </div>
147
- <div class="terminal-header">
148
- <span class="dot red"></span>
149
- <span class="dot yellow"></span>
150
- <span class="dot green"></span>
151
- <div class="terminal-title">agent-trace.sh</div>
152
- </div>
153
- <div class="terminal-body scrollable" id="terminal-output">
154
- <div class="log-line">> Initiating OpenEnv environment context...</div>
155
- <div class="log-line">> Waiting for execution command.</div>
156
- </div>
157
-
158
- <!-- Reward Overlay that pops up after completion -->
159
- <div class="reward-overlay" id="reward-overlay" style="display:none;">
160
- <div class="reward-ring" id="reward-display">0.0</div>
161
- <h4 style="margin-bottom:0.5rem;">Grade Received</h4>
162
- <div class="feedback-text text-sm" id="feedback-display">...</div>
163
- <button class="btn btn-outline" style="margin-top:1.5rem;" onclick="app.closeReward()">Dismiss</button>
164
- </div>
165
  </div>
166
  </div>
167
-
168
- </div>
169
- </div>
170
 
171
- <!-- Elite v3.3: Credentials Modal -->
 
 
 
172
  <div class="modal-overlay" id="settings-modal" style="display:none;">
173
  <div class="glass-panel modal-content box-glow">
174
  <div class="panel-header">
175
  <h3><i class="fa-solid fa-key"></i> Remote Inference Settings</h3>
176
- <button class="btn btn-outline btn-sm" onclick="app.toggleSettings()">×</button>
 
 
177
  </div>
178
  <div class="panel-body">
179
  <p class="text-xs text-muted" style="margin-bottom:1.5rem;">Judges can provide their own credentials for evaluation. These are stored locally and transmitted only for current session tasks.</p>
180
-
181
  <div class="form-group">
182
  <label>API Key / HF Token</label>
183
  <input type="password" id="cfg-api-key" placeholder="hf_... or sk-...">
@@ -190,8 +254,8 @@
190
  <label>Target Model</label>
191
  <input type="text" id="cfg-model" placeholder="meta-llama/Llama-3-70b-instruct">
192
  </div>
193
-
194
- <div style="margin-top:2rem; display:flex; gap:0.5rem;">
195
  <button class="btn btn-ai w-full" onclick="app.saveSettings()">Save & Activate</button>
196
  <button class="btn btn-outline" onclick="app.clearSettings()">Reset Default</button>
197
  </div>
 
9
  <link rel="stylesheet" href="/static/style.css">
10
  </head>
11
  <body>
12
+
13
+ <!-- Fluid Particle Background -->
14
  <canvas id="fluid-canvas"></canvas>
15
 
16
+ <!-- App Shell: Sidebar + Main -->
17
+ <div class="app-shell">
 
 
 
 
 
 
 
18
 
19
+ <!-- ===== SIDEBAR ===== -->
20
+ <aside class="sidebar glass-panel" id="sidebar">
21
+ <div class="sidebar-header">
22
+ <div class="sidebar-logo">
23
+ <i class="fa-solid fa-shield-halved"></i>
24
+ </div>
25
+ <div class="sidebar-brand">
26
+ <span class="brand-name"><span class="text-primary">Content</span>Guard</span>
27
+ <span class="brand-version">v1.0</span>
28
+ </div>
29
  </div>
30
+
31
+ <nav class="sidebar-nav">
32
+ <div class="nav-section">
33
+ <h4 class="nav-label">Tasks</h4>
34
+ <button class="nav-item" data-task="easy" onclick="app.startEpisode('easy')">
35
+ <i class="fa-solid fa-magnifying-glass nav-icon" style="color: var(--success);"></i>
36
+ <span>Easy (Detect)</span>
37
+ <span class="nav-badge">Lv.1</span>
38
+ </button>
39
+ <button class="nav-item" data-task="medium" onclick="app.startEpisode('medium')">
40
+ <i class="fa-solid fa-gavel nav-icon" style="color: var(--warning);"></i>
41
+ <span>Medium (Action)</span>
42
+ <span class="nav-badge">Lv.2</span>
43
+ </button>
44
+ <button class="nav-item" data-task="hard" onclick="app.startEpisode('hard')">
45
+ <i class="fa-solid fa-file-signature nav-icon" style="color: var(--danger);"></i>
46
+ <span>Hard (Appeal)</span>
47
+ <span class="nav-badge">Lv.3</span>
48
+ </button>
49
+ </div>
50
+
51
+ <div class="nav-section">
52
+ <h4 class="nav-label">Tools</h4>
53
+ <button class="nav-item" onclick="app.toggleSettings()">
54
+ <i class="fa-solid fa-gear nav-icon"></i>
55
+ <span>Settings</span>
56
+ </button>
57
+ </div>
58
+ </nav>
59
+
60
+ <div class="sidebar-footer">
61
+ <div class="status-badge" id="sidebar-status">
62
+ <div id="status-indicator" class="status-indicator"></div>
63
+ <span id="status-text">Connecting...</span>
64
+ </div>
65
  </div>
66
+ </aside>
 
67
 
68
+ <!-- ===== MAIN CONTENT ===== -->
69
+ <div class="main-content">
 
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
+ <!-- Top Bar -->
72
+ <header class="topbar glass-panel">
73
+ <div class="topbar-left">
74
+ <button class="btn btn-icon sidebar-toggle" onclick="app.toggleSidebar()" title="Toggle sidebar">
75
+ <i class="fa-solid fa-bars"></i>
76
+ </button>
77
+ <div class="breadcrumb">
78
+ <span class="breadcrumb-muted">Workspace</span>
79
+ <i class="fa-solid fa-chevron-right breadcrumb-sep"></i>
80
+ <span class="breadcrumb-current" id="breadcrumb-task">Home</span>
81
+ </div>
82
+ </div>
83
+ <div class="topbar-right">
84
+ <!-- HUD Metrics -->
85
+ <div class="hud-strip">
86
+ <div class="hud-item">
87
+ <span class="hud-label">Episodes</span>
88
+ <span class="hud-val" id="hud-episodes">0</span>
89
  </div>
90
+ <div class="hud-item">
91
+ <span class="hud-label">Accuracy</span>
92
+ <span class="hud-val" id="hud-accuracy">0.0%</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  </div>
94
  </div>
95
+ </div>
96
+ </header>
97
 
98
+ <!-- Landing Page -->
99
+ <div class="page-content" id="landing-page">
100
+ <div class="landing-hero">
101
+ <h2 class="gradient-text landing-title">Autonomous Moderation Workspace</h2>
102
+ <p class="text-muted landing-subtitle">Select a task difficulty from the sidebar to spin up a simulated environment.</p>
103
+ <div class="landing-icons">
104
+ <i class="fa-brands fa-meta"></i>
105
+ <i class="fa-solid fa-xmark landing-x"></i>
106
+ <i class="fa-solid fa-shield-halved"></i>
 
 
 
 
107
  </div>
 
108
  </div>
109
  </div>
110
 
111
+ <!-- Main Workspace (hidden initially) -->
112
+ <div class="page-content" id="main-interface" style="display: none;">
113
+ <div class="workspace-grid">
114
+
115
+ <!-- Column 1: Case Data + Actions (scrollable) -->
116
+ <div class="workspace-col fade-in">
117
+ <div class="glass-panel panel-content h-full" style="display:flex; flex-direction:column; gap:0;">
118
+
119
+ <!-- Policy Alert Banner -->
120
+ <div class="alert-banner box-glow" id="policy-alert-banner" style="margin: 1rem 1rem 0;">
121
+ <div class="alert-badge" id="alert-level">GREEN</div>
122
+ <div class="alert-content">
123
+ <strong id="alert-topic">System Stable</strong>
124
+ <p id="alert-summary">No active platform-wide risks detected.</p>
125
+ </div>
126
+ </div>
127
+
128
+ <div class="panel-section scrollable" style="flex:1; padding: 1.5rem;">
129
+ <div class="panel-header" style="padding: 0; background: transparent; border: none; margin-bottom: 1rem;">
130
+ <h3><i class="fa-solid fa-file-invoice"></i> Content Case <span id="current-task-badge" class="badge">Type</span></h3>
131
+ <span class="post-id" id="val-post-id">#POST-XXX</span>
132
+ </div>
133
+
134
+ <div class="content-preview box-glow" id="val-content">
135
+ <!-- Typewriter content -->
136
+ </div>
137
+
138
+ <div class="meta-grid">
139
+ <div class="stat-box">
140
+ <span class="label">Platform <i class="fa-solid fa-globe"></i></span>
141
+ <span class="value text-primary" id="val-platform">--</span>
142
+ </div>
143
+ <div class="stat-box">
144
+ <span class="label">Acc. Age <i class="fa-solid fa-clock"></i></span>
145
+ <span class="value" id="val-user-age">--</span>
146
+ </div>
147
+ <div class="stat-box">
148
+ <span class="label">Violations <i class="fa-solid fa-triangle-exclamation"></i></span>
149
+ <span class="value text-danger" id="val-prior-violations">--</span>
150
+ </div>
151
+ <div class="stat-box">
152
+ <span class="label">Reports <i class="fa-solid fa-flag"></i></span>
153
+ <span class="value text-warning" id="val-reports">--</span>
154
+ </div>
155
+ </div>
156
+
157
+ <!-- Telemetry -->
158
+ <div style="border-top:1px solid var(--glass-border); padding-top:1rem; margin-top:1rem;">
159
+ <h4 class="section-label">Platform Risk Telemetry</h4>
160
+ <div class="meta-grid">
161
+ <div class="stat-box">
162
+ <span class="label">Queue Depth</span>
163
+ <span class="value" id="val-queue-depth">--</span>
164
+ </div>
165
+ <div class="stat-box">
166
+ <span class="label">Avg Harm</span>
167
+ <span class="value" id="val-avg-harm">--</span>
168
+ </div>
169
+ </div>
170
+ </div>
171
+
172
+ <hr class="divider">
173
+
174
+ <!-- Moderation Override Form -->
175
+ <div class="panel-header" style="padding: 0; background: transparent; border: none; margin-bottom: 1rem;">
176
+ <h3><i class="fa-solid fa-sliders"></i> Moderation Override</h3>
177
+ </div>
178
+
179
+ <div id="action-panel">
180
+ <!-- Rendered form -->
181
+ </div>
182
+
183
+ <!-- Agent Execution Box -->
184
+ <div class="auto-agent-box">
185
+ <h4><i class="fa-solid fa-robot"></i> Advanced Execution</h4>
186
+ <p class="text-muted text-sm">Transfer control to the autonomous agent. Single step or enable Continuous RL Training mode.</p>
187
+ <div class="agent-btns">
188
+ <button class="btn btn-outline" id="btn-run-agent" onclick="app.runAgent(false)">
189
+ <i class="fa-solid fa-play"></i> Single Step
190
+ </button>
191
+ <button class="btn btn-ai" id="btn-auto-loop" onclick="app.toggleAutoLoop()">
192
+ <i class="fa-solid fa-infinity"></i> Start Auto-Training Loop
193
+ </button>
194
+ </div>
195
+ </div>
196
+ </div>
197
  </div>
198
+ </div>
199
+
200
+ <!-- Column 2: Terminal -->
201
+ <div class="workspace-col fade-in delay-1">
202
+ <div class="glass-panel panel-content h-full terminal-wrapper" style="display:flex; flex-direction:column;">
203
+ <div class="terminal-header">
204
+ <span class="dot red"></span>
205
+ <span class="dot yellow"></span>
206
+ <span class="dot green"></span>
207
+ <div class="terminal-title">agent-trace.sh</div>
208
+ <button class="btn btn-icon terminal-clear" onclick="app.clearTerminal()" title="Clear terminal">
209
+ <i class="fa-solid fa-trash-can"></i>
210
  </button>
211
  </div>
212
+ <div class="terminal-body scrollable" id="terminal-output">
213
+ <div class="log-line">> Initiating OpenEnv environment context...</div>
214
+ <div class="log-line">> Waiting for execution command.</div>
215
+ </div>
216
+
217
+ <!-- Reward Overlay -->
218
+ <div class="reward-overlay" id="reward-overlay" style="display:none;">
219
+ <div class="reward-ring" id="reward-display">0.0</div>
220
+ <h4 style="margin-bottom:0.5rem;">Grade Received</h4>
221
+ <div class="feedback-text text-sm" id="feedback-display">...</div>
222
+ <button class="btn btn-outline" style="margin-top:1.5rem;" onclick="app.closeReward()">Dismiss</button>
223
+ </div>
224
  </div>
225
  </div>
 
 
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  </div>
228
  </div>
 
 
 
229
 
230
+ </div><!-- /main-content -->
231
+ </div><!-- /app-shell -->
232
+
233
+ <!-- Settings Modal -->
234
  <div class="modal-overlay" id="settings-modal" style="display:none;">
235
  <div class="glass-panel modal-content box-glow">
236
  <div class="panel-header">
237
  <h3><i class="fa-solid fa-key"></i> Remote Inference Settings</h3>
238
+ <button class="btn btn-icon" onclick="app.toggleSettings()">
239
+ <i class="fa-solid fa-xmark"></i>
240
+ </button>
241
  </div>
242
  <div class="panel-body">
243
  <p class="text-xs text-muted" style="margin-bottom:1.5rem;">Judges can provide their own credentials for evaluation. These are stored locally and transmitted only for current session tasks.</p>
244
+
245
  <div class="form-group">
246
  <label>API Key / HF Token</label>
247
  <input type="password" id="cfg-api-key" placeholder="hf_... or sk-...">
 
254
  <label>Target Model</label>
255
  <input type="text" id="cfg-model" placeholder="meta-llama/Llama-3-70b-instruct">
256
  </div>
257
+
258
+ <div class="modal-actions">
259
  <button class="btn btn-ai w-full" onclick="app.saveSettings()">Save & Activate</button>
260
  <button class="btn btn-outline" onclick="app.clearSettings()">Reset Default</button>
261
  </div>
server/static/style.css CHANGED
@@ -1,197 +1,963 @@
1
- /* frontend/style.css */
2
  @import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;700&family=JetBrains+Mono:wght@400;600&display=swap');
3
 
 
4
  :root {
5
- --bg-base: #0a0f1c; /* Deeper dark base */
 
 
 
 
 
 
6
  --text-main: #f8fafc;
7
  --text-muted: #64748b;
 
 
 
8
  --glass-bg: rgba(15, 23, 42, 0.45);
9
- --glass-border: rgba(255, 255, 255, 0.05);
 
10
  --glass-shadow: 0 10px 40px rgba(0, 0, 0, 0.8);
11
-
12
- --primary: #6366f1; /* Indigo */
 
 
13
  --primary-glow: rgba(99, 102, 241, 0.5);
14
  --primary-light: #818cf8;
15
- --danger: #f43f5e; /* Rose/Red */
 
 
16
  --danger-glow: rgba(244, 63, 94, 0.5);
 
 
17
  --warning: #fbbf24;
 
 
18
  --success: #10b981;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  }
20
 
 
21
  * { box-sizing: border-box; }
22
 
23
  body {
24
  background-color: var(--bg-base);
25
  color: var(--text-main);
26
  font-family: 'Outfit', sans-serif;
27
- margin: 0; padding: 0;
28
- overflow-x: hidden; min-height: 100vh; overflow-y: auto;
29
- display: flex; flex-direction: column;
 
30
  }
31
 
32
- /* Elite Fluid Particles Canvas */
 
 
 
 
33
  #fluid-canvas {
34
  position: fixed;
35
- top: 0; left: 0; width: 100vw; height: 100vh;
 
36
  z-index: -1;
37
  pointer-events: none;
38
- background: radial-gradient(circle at center, #111827, #030712);
39
  }
40
 
41
- /* Layout & Spacing */
42
- .container-fluid { padding: 0 2rem; width: 100%; max-width: 1600px; margin: 0 auto; flex: 1; display: flex; flex-direction: column; }
43
- .h-full { height: 100%; display: flex; flex-direction: column; }
44
- .scrollable { overflow-y: auto; }
45
- .w-full { width: 100%; }
46
- .text-sm { font-size: 0.85rem; }
47
-
48
- /* Utilities */
49
  .text-primary { color: var(--primary-light); }
50
  .text-danger { color: var(--danger); font-weight: 600; }
51
  .text-warning { color: var(--warning); font-weight: 600; }
52
- .gradient-text { background: linear-gradient(135deg, var(--primary-light), #c084fc); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
 
 
 
 
 
53
 
54
- /* Header */
55
- .main-header { display: flex; justify-content: space-between; align-items: center; padding: 1rem 2rem; margin: 1rem 2rem; border-radius: 12px; }
56
- .main-header h1 { margin: 0; font-size: 1.4rem; font-weight: 700; display: flex; align-items: center; gap: 0.5rem; letter-spacing: 1px;}
57
- .main-header h1 span { color: var(--primary); }
 
 
58
 
59
- p { margin: 0; }
60
- h3 { margin: 0; font-weight: 500;}
 
 
 
 
 
 
61
 
62
- /* Status */
63
- .status-badge { display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 1rem; border-radius: 50px; font-size: 0.8rem; }
64
- .status-indicator { width: 8px; height: 8px; border-radius: 50%; background: var(--danger); box-shadow: 0 0 10px var(--danger); }
65
- .status-indicator.connected { background: var(--success); box-shadow: 0 0 10px var(--success); }
 
66
 
67
- /* Glass */
68
- .glass-panel { background: var(--glass-bg); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid var(--glass-border); box-shadow: var(--glass-shadow); }
 
 
 
 
 
 
69
 
70
- /* Grid */
71
- .workspace-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1.5rem; height: calc(100vh - 120px); padding-bottom: 2rem; }
72
- @media (max-width: 1200px) { .workspace-grid { grid-template-columns: 1fr; height: auto; } }
73
 
74
- .workspace-col { height: 100%; }
75
- .panel-content { border-radius: 16px; overflow: hidden; }
76
- .panel-header { padding: 1.5rem; border-bottom: 1px solid var(--glass-border); display: flex; justify-content: space-between; align-items: center; background: rgba(0,0,0,0.2); }
77
- .panel-body { padding: 1.5rem; flex: 1; }
 
 
78
 
79
- .badge { background: rgba(255,255,255,0.1); padding: 0.2rem 0.6rem; border-radius: 4px; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 1px; margin-left: 0.5rem; }
80
- .post-id { font-family: 'JetBrains Mono', monospace; color: var(--text-muted); font-size: 0.85rem;}
 
 
 
 
 
 
 
 
 
 
 
81
 
82
- /* Case Preview */
83
- .content-preview { font-size: 1.1rem; line-height: 1.6; padding: 1.5rem; background: rgba(0,0,0,0.3); border-radius: 8px; border-left: 4px solid var(--primary); margin-bottom: 2rem; min-height: 120px; font-weight: 300; max-height: 250px; overflow-y: auto; }
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
- .meta-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
86
- .stat-box { background: rgba(255,255,255,0.02); padding: 1rem; border-radius: 8px; border: 1px solid var(--glass-border); }
87
- .stat-box .label { display: flex; justify-content: space-between; font-size: 0.75rem; text-transform: uppercase; color: var(--text-muted); margin-bottom: 0.5rem; }
88
- .stat-box .value { font-size: 1.2rem; }
 
 
 
89
 
90
- /* Forms */
91
- .form-group { margin-bottom: 1.25rem; }
92
- label { display: block; margin-bottom: 0.4rem; font-size: 0.8rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px;}
93
- select, input, textarea { width: 100%; padding: 0.8rem 1rem; background: rgba(0, 0, 0, 0.4); border: 1px solid rgba(255,255,255,0.1); border-radius: 6px; color: var(--text-main); font-family: inherit; transition: all 0.2s ease; }
94
- select:focus, input:focus { border-color: var(--primary); outline: none; box-shadow: 0 0 15px rgba(99, 102, 241, 0.2); }
 
 
 
 
 
 
 
 
95
 
96
- /* Buttons */
97
- .btn { border: none; padding: 0.75rem 1.5rem; border-radius: 6px; font-family: inherit; font-weight: 500; cursor: pointer; transition: all 0.3s ease; display: inline-flex; justify-content: center; align-items: center; gap: 0.5rem; }
98
- .btn-primary { background: var(--primary); color: white; box-shadow: 0 4px 15px var(--primary-glow); }
99
- .btn-primary:hover { background: #4f46e5; transform: translateY(-2px); box-shadow: 0 6px 20px var(--primary-glow); }
 
100
 
101
- .btn-outline { background: transparent; color: var(--text-muted); border: 1px solid var(--glass-border); }
102
- .btn-outline:hover { color: var(--text-main); border-color: rgba(255,255,255,0.2); background: rgba(255,255,255,0.05); }
 
 
 
 
103
 
104
- .btn-ai { background: linear-gradient(135deg, #10b981, #059669); color: white; font-weight: 700; box-shadow: 0 4px 15px rgba(16, 185, 129, 0.4); transition: transform 0.2s, box-shadow 0.2s; border: 1px solid rgba(255,255,255,0.2); }
105
- .btn-ai:hover { transform: translateY(-2px); box-shadow: 0 8px 25px rgba(16, 185, 129, 0.6); }
 
 
 
 
106
 
107
- .auto-agent-box { margin-top: 2rem; padding: 1.5rem; background: rgba(16, 185, 129, 0.05); border: 1px solid rgba(16, 185, 129, 0.2); border-radius: 8px; }
108
- .auto-agent-box h4 { margin: 0 0 0.5rem 0; color: #10b981; }
109
- .auto-agent-box p { margin-bottom: 1.5rem; }
 
 
 
110
 
111
- /* Terminal */
112
- .terminal-wrapper { position: relative; }
113
- .terminal-header { background: #000; padding: 0.75rem 1rem; border-bottom: 1px solid #1f2937; display: flex; align-items: center; gap: 0.5rem; }
114
- .dot { width: 12px; height: 12px; border-radius: 50%; }
115
- .dot.red { background: #ff5f56; } .dot.yellow { background: #ffbd2e; } .dot.green { background: #27c93f; }
116
- .terminal-title { color: #6b7280; font-family: 'JetBrains Mono', monospace; font-size: 0.8rem; margin-left: 1rem; }
117
- .terminal-body { background: #050505; flex: 1; padding: 1.5rem; font-family: 'JetBrains Mono', monospace; font-size: 0.9rem; color: #a8b2d1; overflow-y: auto; max-height: 400px; }
118
 
119
- .log-line { margin-bottom: 0.5rem; line-height: 1.5; white-space: pre-wrap; word-break: break-all; }
120
- .log-line.running { position: relative; }
121
- .log-line.running::after { content: '█'; animation: blink 1s step-start infinite; color: var(--primary); margin-left: 5px; }
 
 
 
 
 
 
122
 
123
- /* Reward Overlay */
124
- .reward-overlay { position: absolute; inset: 0; background: rgba(5, 5, 5, 0.85); backdrop-filter: blur(5px); display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 50; animation: popIn 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
125
- .reward-ring { width: 140px; height: 140px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 3rem; font-weight: 700; border: 5px solid var(--glass-border); margin-bottom: 1.5rem; background: var(--bg-base); }
126
- .feedback-text { max-width: 80%; text-align: center; color: var(--text-muted); }
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
- /* Task selector top */
129
- #task-selector { display:flex; gap: 0.5rem; }
 
 
 
130
 
131
- /* Animations */
132
- @keyframes blink { 50% { opacity: 0; } }
133
- @keyframes popIn { 0% { opacity: 0; transform: scale(0.9); } 100% { opacity: 1; transform: scale(1); } }
134
- .fade-in { animation: fadeIn 0.8s ease backwards; }
135
- .delay-1 { animation-delay: 0.2s; } .delay-2 { animation-delay: 0.4s; }
136
- @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
137
-
138
- /* Scrollbars */
139
- ::-webkit-scrollbar { width: 6px; }
140
- ::-webkit-scrollbar-track { background: rgba(0,0,0,0.2); }
141
- ::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 10px; }
142
- ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.2); }
143
-
144
- /* Elite v3.0 Style Extensions */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  .alert-banner {
146
- display: flex; align-items: center; gap: 1rem; padding: 1rem; border-radius: 12px;
147
- background: rgba(15, 23, 42, 0.6); border: 1px solid rgba(255, 255, 255, 0.05);
148
- margin-bottom: 0.5rem; transition: all 0.3s ease;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  }
150
- .alert-banner.green { border-left: 5px solid var(--success); box-shadow: 0 0 20px rgba(16, 185, 129, 0.1); }
151
- .alert-banner.yellow { border-left: 5px solid var(--warning); box-shadow: 0 0 20px rgba(251, 191, 36, 0.1); }
152
- .alert-banner.elevated { border-left: 5px solid #f97316; box-shadow: 0 0 20px rgba(249, 115, 22, 0.1); }
153
- .alert-banner.critical { border-left: 5px solid var(--danger); box-shadow: 0 0 20px rgba(244, 63, 94, 0.2); animation: pulseAlert 2s infinite; }
154
 
155
- @keyframes pulseAlert { 0% { opacity: 1; } 50% { opacity: 0.7; } 100% { opacity: 1; } }
 
 
 
156
 
157
  .alert-badge {
158
- background: rgba(255, 255, 255, 0.1); padding: 0.3rem 0.6rem; border-radius: 4px;
159
- font-size: 0.7rem; font-weight: 700; letter-spacing: 1px; color: var(--text-main);
 
 
 
 
 
 
 
 
 
 
 
 
160
  }
161
- .alert-content strong { display: block; font-size: 0.9rem; margin-bottom: 0.2rem; }
162
- .alert-content p { font-size: 0.75rem; color: var(--text-muted); }
163
 
164
- .box-glow { box-shadow: inset 0 0 10px rgba(0,0,0,0.5); }
 
 
 
 
 
 
165
 
166
- /* Global Metrics HUD (Elite v3.0) */
167
- .global-hud {
168
- background: rgba(16, 185, 129, 0.05); border-bottom: 1px solid rgba(16, 185, 129, 0.2);
169
- display: flex; justify-content: space-around; padding: 0.75rem;
170
- font-family: 'JetBrains Mono', monospace; font-weight: 600;
 
 
171
  }
172
- .hud-item { display: flex; align-items: center; gap: 0.5rem; }
173
- .hud-label { color: var(--text-muted); text-transform: uppercase; font-size: 0.75rem;}
174
- .hud-val { color: var(--success); font-size: 1.1rem; text-shadow: 0 0 10px rgba(16, 185, 129, 0.5);}
175
 
176
- /* Elite Polish */
177
- .tilt-card:hover .panel-content {
178
- box-shadow: 0 10px 40px rgba(0,0,0,0.5), 0 0 15px var(--primary-glow);
179
- border-color: rgba(255,255,255,0.15);
 
 
 
 
 
 
180
  }
181
 
182
- .header-controls { display: flex; align-items: center; gap: 1rem; }
 
 
 
 
183
 
184
- /* Modal Overlay & Content (Elite v3.3) */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  .modal-overlay {
186
- position: fixed; inset: 0; background: rgba(5, 5, 5, 0.9);
187
- backdrop-filter: blur(10px); z-index: 1000;
188
- display: flex; align-items: center; justify-content: center;
 
 
 
 
 
189
  }
 
190
  .modal-content {
191
- width: 100%; max-width: 500px; border-radius: 20px;
192
- animation: modalPop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
 
 
 
 
 
 
 
 
193
  }
194
- @keyframes modalPop { 0% { opacity: 0; transform: scale(0.95); } 100% { opacity: 1; transform: scale(1); } }
195
 
196
- /* Form Elements (v3.3 specific) */
197
- .btn-sm { padding: 0.4rem 0.8rem; font-size: 0.8rem; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ContentGuardEnv — Sidebar Layout Theme */
2
  @import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;700&family=JetBrains+Mono:wght@400;600&display=swap');
3
 
4
+ /* ========== DESIGN TOKENS ========== */
5
  :root {
6
+ /* Core palette */
7
+ --bg-base: #0a0f1c;
8
+ --bg-surface: rgba(15, 23, 42, 0.45);
9
+ --bg-elevated: rgba(15, 23, 42, 0.7);
10
+ --bg-inset: rgba(0, 0, 0, 0.3);
11
+
12
+ /* Text */
13
  --text-main: #f8fafc;
14
  --text-muted: #64748b;
15
+ --text-dim: #475569;
16
+
17
+ /* Glass */
18
  --glass-bg: rgba(15, 23, 42, 0.45);
19
+ --glass-border: rgba(255, 255, 255, 0.06);
20
+ --glass-border-hover: rgba(255, 255, 255, 0.12);
21
  --glass-shadow: 0 10px 40px rgba(0, 0, 0, 0.8);
22
+ --glass-blur: 20px;
23
+
24
+ /* Brand colors */
25
+ --primary: #6366f1;
26
  --primary-glow: rgba(99, 102, 241, 0.5);
27
  --primary-light: #818cf8;
28
+ --primary-dim: rgba(99, 102, 241, 0.15);
29
+
30
+ --danger: #f43f5e;
31
  --danger-glow: rgba(244, 63, 94, 0.5);
32
+ --danger-dim: rgba(244, 63, 94, 0.1);
33
+
34
  --warning: #fbbf24;
35
+ --warning-dim: rgba(251, 191, 36, 0.1);
36
+
37
  --success: #10b981;
38
+ --success-glow: rgba(16, 185, 129, 0.4);
39
+ --success-dim: rgba(16, 185, 129, 0.1);
40
+
41
+ /* Spacing */
42
+ --space-xs: 0.25rem;
43
+ --space-sm: 0.5rem;
44
+ --space-md: 1rem;
45
+ --space-lg: 1.5rem;
46
+ --space-xl: 2rem;
47
+
48
+ /* Radii */
49
+ --radius-sm: 6px;
50
+ --radius-md: 10px;
51
+ --radius-lg: 16px;
52
+ --radius-xl: 20px;
53
+ --radius-full: 50px;
54
+
55
+ /* Sidebar */
56
+ --sidebar-width: 240px;
57
+ --sidebar-collapsed-width: 64px;
58
+
59
+ /* Transitions */
60
+ --transition-fast: 0.15s ease;
61
+ --transition-normal: 0.25s ease;
62
+ --transition-smooth: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
63
  }
64
 
65
+ /* ========== RESET & BASE ========== */
66
  * { box-sizing: border-box; }
67
 
68
  body {
69
  background-color: var(--bg-base);
70
  color: var(--text-main);
71
  font-family: 'Outfit', sans-serif;
72
+ margin: 0;
73
+ padding: 0;
74
+ overflow: hidden;
75
+ height: 100vh;
76
  }
77
 
78
+ p { margin: 0; }
79
+ h3 { margin: 0; font-weight: 500; }
80
+ h4 { margin: 0; }
81
+
82
+ /* ========== FLUID PARTICLES CANVAS ========== */
83
  #fluid-canvas {
84
  position: fixed;
85
+ top: 0; left: 0;
86
+ width: 100vw; height: 100vh;
87
  z-index: -1;
88
  pointer-events: none;
89
+ background: radial-gradient(ellipse at 20% 50%, #111827 0%, #030712 70%);
90
  }
91
 
92
+ /* ========== UTILITIES ========== */
 
 
 
 
 
 
 
93
  .text-primary { color: var(--primary-light); }
94
  .text-danger { color: var(--danger); font-weight: 600; }
95
  .text-warning { color: var(--warning); font-weight: 600; }
96
+ .text-muted { color: var(--text-muted); }
97
+ .text-sm { font-size: 0.85rem; }
98
+ .text-xs { font-size: 0.75rem; }
99
+ .w-full { width: 100%; }
100
+ .h-full { height: 100%; display: flex; flex-direction: column; }
101
+ .scrollable { overflow-y: auto; }
102
 
103
+ .gradient-text {
104
+ background: linear-gradient(135deg, var(--primary-light), #c084fc, #f472b6);
105
+ -webkit-background-clip: text;
106
+ -webkit-text-fill-color: transparent;
107
+ background-clip: text;
108
+ }
109
 
110
+ .section-label {
111
+ font-size: 0.7rem;
112
+ color: var(--text-muted);
113
+ text-transform: uppercase;
114
+ letter-spacing: 1.5px;
115
+ margin-bottom: 0.8rem;
116
+ font-weight: 500;
117
+ }
118
 
119
+ .divider {
120
+ border: none;
121
+ border-top: 1px solid var(--glass-border);
122
+ margin: 1.5rem 0;
123
+ }
124
 
125
+ /* ========== GLASS PANELS ========== */
126
+ .glass-panel {
127
+ background: var(--glass-bg);
128
+ backdrop-filter: blur(var(--glass-blur));
129
+ -webkit-backdrop-filter: blur(var(--glass-blur));
130
+ border: 1px solid var(--glass-border);
131
+ box-shadow: var(--glass-shadow);
132
+ }
133
 
134
+ .box-glow {
135
+ box-shadow: inset 0 0 12px rgba(0, 0, 0, 0.4);
136
+ }
137
 
138
+ /* ========== APP SHELL ========== */
139
+ .app-shell {
140
+ display: flex;
141
+ height: 100vh;
142
+ overflow: hidden;
143
+ }
144
 
145
+ /* ========== SIDEBAR ========== */
146
+ .sidebar {
147
+ width: var(--sidebar-width);
148
+ min-width: var(--sidebar-width);
149
+ height: 100vh;
150
+ display: flex;
151
+ flex-direction: column;
152
+ border-right: 1px solid var(--glass-border);
153
+ border-radius: 0;
154
+ transition: width var(--transition-smooth), min-width var(--transition-smooth), transform var(--transition-smooth);
155
+ z-index: 100;
156
+ position: relative;
157
+ }
158
 
159
+ .sidebar::after {
160
+ content: '';
161
+ position: absolute;
162
+ top: 0;
163
+ right: -1px;
164
+ width: 1px;
165
+ height: 100%;
166
+ background: linear-gradient(to bottom,
167
+ transparent,
168
+ var(--primary-dim) 30%,
169
+ var(--primary-dim) 70%,
170
+ transparent
171
+ );
172
+ pointer-events: none;
173
+ }
174
 
175
+ .sidebar-header {
176
+ padding: var(--space-lg);
177
+ border-bottom: 1px solid var(--glass-border);
178
+ display: flex;
179
+ align-items: center;
180
+ gap: var(--space-md);
181
+ }
182
 
183
+ .sidebar-logo {
184
+ width: 36px;
185
+ height: 36px;
186
+ background: linear-gradient(135deg, var(--primary), #8b5cf6);
187
+ border-radius: var(--radius-md);
188
+ display: flex;
189
+ align-items: center;
190
+ justify-content: center;
191
+ font-size: 1rem;
192
+ color: #fff;
193
+ box-shadow: 0 4px 12px var(--primary-glow);
194
+ flex-shrink: 0;
195
+ }
196
 
197
+ .sidebar-brand {
198
+ display: flex;
199
+ flex-direction: column;
200
+ overflow: hidden;
201
+ }
202
 
203
+ .brand-name {
204
+ font-size: 1rem;
205
+ font-weight: 700;
206
+ letter-spacing: 0.5px;
207
+ white-space: nowrap;
208
+ }
209
 
210
+ .brand-version {
211
+ font-size: 0.65rem;
212
+ color: var(--text-dim);
213
+ text-transform: uppercase;
214
+ letter-spacing: 1px;
215
+ }
216
 
217
+ /* Nav */
218
+ .sidebar-nav {
219
+ flex: 1;
220
+ padding: var(--space-md);
221
+ overflow-y: auto;
222
+ }
223
 
224
+ .nav-section {
225
+ margin-bottom: var(--space-lg);
226
+ }
 
 
 
 
227
 
228
+ .nav-label {
229
+ font-size: 0.65rem;
230
+ color: var(--text-dim);
231
+ text-transform: uppercase;
232
+ letter-spacing: 2px;
233
+ padding: 0 var(--space-sm);
234
+ margin-bottom: var(--space-sm);
235
+ font-weight: 500;
236
+ }
237
 
238
+ .nav-item {
239
+ width: 100%;
240
+ padding: 0.65rem 0.75rem;
241
+ border-radius: var(--radius-sm);
242
+ cursor: pointer;
243
+ display: flex;
244
+ align-items: center;
245
+ gap: var(--space-sm);
246
+ font-size: 0.85rem;
247
+ margin-bottom: 2px;
248
+ border: 1px solid transparent;
249
+ background: transparent;
250
+ color: var(--text-muted);
251
+ font-family: inherit;
252
+ transition: all var(--transition-fast);
253
+ text-align: left;
254
+ }
255
 
256
+ .nav-item:hover {
257
+ background: rgba(255, 255, 255, 0.04);
258
+ color: var(--text-main);
259
+ border-color: var(--glass-border);
260
+ }
261
 
262
+ .nav-item.active {
263
+ background: var(--primary-dim);
264
+ color: var(--primary-light);
265
+ border-color: rgba(99, 102, 241, 0.2);
266
+ font-weight: 500;
267
+ }
268
+
269
+ .nav-icon {
270
+ width: 18px;
271
+ text-align: center;
272
+ font-size: 0.85rem;
273
+ flex-shrink: 0;
274
+ }
275
+
276
+ .nav-badge {
277
+ margin-left: auto;
278
+ background: rgba(255, 255, 255, 0.06);
279
+ padding: 2px 8px;
280
+ border-radius: var(--radius-full);
281
+ font-size: 0.65rem;
282
+ color: var(--text-dim);
283
+ letter-spacing: 0.5px;
284
+ }
285
+
286
+ .nav-item.active .nav-badge {
287
+ background: rgba(99, 102, 241, 0.2);
288
+ color: var(--primary-light);
289
+ }
290
+
291
+ /* Footer */
292
+ .sidebar-footer {
293
+ padding: var(--space-md) var(--space-lg);
294
+ border-top: 1px solid var(--glass-border);
295
+ }
296
+
297
+ /* ========== STATUS BADGE ========== */
298
+ .status-badge {
299
+ display: flex;
300
+ align-items: center;
301
+ gap: var(--space-sm);
302
+ font-size: 0.75rem;
303
+ color: var(--text-muted);
304
+ }
305
+
306
+ .status-indicator {
307
+ width: 8px;
308
+ height: 8px;
309
+ border-radius: 50%;
310
+ background: var(--danger);
311
+ box-shadow: 0 0 10px var(--danger);
312
+ transition: all var(--transition-normal);
313
+ }
314
+
315
+ .status-indicator.connected {
316
+ background: var(--success);
317
+ box-shadow: 0 0 10px var(--success);
318
+ animation: pulseGlow 2s ease-in-out infinite;
319
+ }
320
+
321
+ @keyframes pulseGlow {
322
+ 0%, 100% { box-shadow: 0 0 8px var(--success); }
323
+ 50% { box-shadow: 0 0 16px var(--success-glow); }
324
+ }
325
+
326
+ /* ========== MAIN CONTENT ========== */
327
+ .main-content {
328
+ flex: 1;
329
+ display: flex;
330
+ flex-direction: column;
331
+ overflow: hidden;
332
+ min-width: 0;
333
+ }
334
+
335
+ /* ========== TOPBAR ========== */
336
+ .topbar {
337
+ display: flex;
338
+ justify-content: space-between;
339
+ align-items: center;
340
+ padding: 0.6rem var(--space-lg);
341
+ border-bottom: 1px solid var(--glass-border);
342
+ border-radius: 0;
343
+ flex-shrink: 0;
344
+ }
345
+
346
+ .topbar-left {
347
+ display: flex;
348
+ align-items: center;
349
+ gap: var(--space-md);
350
+ }
351
+
352
+ .topbar-right {
353
+ display: flex;
354
+ align-items: center;
355
+ gap: var(--space-lg);
356
+ }
357
+
358
+ .breadcrumb {
359
+ display: flex;
360
+ align-items: center;
361
+ gap: var(--space-sm);
362
+ font-size: 0.85rem;
363
+ }
364
+
365
+ .breadcrumb-muted { color: var(--text-dim); }
366
+ .breadcrumb-sep { font-size: 0.6rem; color: var(--text-dim); }
367
+ .breadcrumb-current { color: var(--text-main); font-weight: 500; }
368
+
369
+ .sidebar-toggle { display: none; }
370
+
371
+ /* ========== HUD STRIP ========== */
372
+ .hud-strip {
373
+ display: flex;
374
+ gap: var(--space-lg);
375
+ font-family: 'JetBrains Mono', monospace;
376
+ }
377
+
378
+ .hud-item {
379
+ display: flex;
380
+ align-items: center;
381
+ gap: var(--space-sm);
382
+ }
383
+
384
+ .hud-label {
385
+ color: var(--text-dim);
386
+ text-transform: uppercase;
387
+ font-size: 0.65rem;
388
+ letter-spacing: 1px;
389
+ }
390
+
391
+ .hud-val {
392
+ color: var(--success);
393
+ font-size: 0.9rem;
394
+ font-weight: 600;
395
+ text-shadow: 0 0 10px var(--success-glow);
396
+ }
397
+
398
+ /* ========== PAGE CONTENT ========== */
399
+ .page-content {
400
+ flex: 1;
401
+ overflow: hidden;
402
+ display: flex;
403
+ flex-direction: column;
404
+ }
405
+
406
+ /* ========== LANDING ========== */
407
+ .landing-hero {
408
+ flex: 1;
409
+ display: flex;
410
+ flex-direction: column;
411
+ align-items: center;
412
+ justify-content: center;
413
+ text-align: center;
414
+ padding: var(--space-xl);
415
+ animation: fadeIn 1s ease;
416
+ }
417
+
418
+ .landing-title {
419
+ font-size: 2.8rem;
420
+ margin-bottom: var(--space-sm);
421
+ text-transform: none;
422
+ line-height: 1.2;
423
+ }
424
+
425
+ .landing-subtitle {
426
+ font-size: 1.1rem;
427
+ max-width: 500px;
428
+ }
429
+
430
+ .landing-icons {
431
+ margin-top: 3rem;
432
+ opacity: 0.5;
433
+ display: flex;
434
+ align-items: center;
435
+ gap: 1.5rem;
436
+ font-size: 3rem;
437
+ animation: floatIcons 4s ease-in-out infinite;
438
+ }
439
+
440
+ .landing-x {
441
+ font-size: 1.2rem !important;
442
+ opacity: 0.6;
443
+ }
444
+
445
+ @keyframes floatIcons {
446
+ 0%, 100% { transform: translateY(0); }
447
+ 50% { transform: translateY(-8px); }
448
+ }
449
+
450
+ /* ========== WORKSPACE GRID ========== */
451
+ .workspace-grid {
452
+ display: grid;
453
+ grid-template-columns: 1fr 1fr;
454
+ gap: var(--space-lg);
455
+ padding: var(--space-lg);
456
+ height: 100%;
457
+ overflow: hidden;
458
+ }
459
+
460
+ .workspace-col { height: 100%; min-height: 0; }
461
+
462
+ .panel-content {
463
+ border-radius: var(--radius-lg);
464
+ overflow: hidden;
465
+ transition: box-shadow var(--transition-normal), border-color var(--transition-normal);
466
+ }
467
+
468
+ .panel-content:hover {
469
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5), 0 0 12px var(--primary-dim);
470
+ border-color: var(--glass-border-hover);
471
+ }
472
+
473
+ .panel-header {
474
+ padding: var(--space-lg);
475
+ border-bottom: 1px solid var(--glass-border);
476
+ display: flex;
477
+ justify-content: space-between;
478
+ align-items: center;
479
+ background: rgba(0, 0, 0, 0.2);
480
+ }
481
+
482
+ .panel-body { padding: var(--space-lg); flex: 1; }
483
+ .panel-section { padding: 0; }
484
+
485
+ /* ========== BADGE ========== */
486
+ .badge {
487
+ background: var(--primary-dim);
488
+ color: var(--primary-light);
489
+ padding: 0.15rem 0.6rem;
490
+ border-radius: var(--radius-sm);
491
+ font-size: 0.65rem;
492
+ text-transform: uppercase;
493
+ letter-spacing: 1px;
494
+ margin-left: var(--space-sm);
495
+ }
496
+
497
+ .post-id {
498
+ font-family: 'JetBrains Mono', monospace;
499
+ color: var(--text-muted);
500
+ font-size: 0.8rem;
501
+ }
502
+
503
+ /* ========== CONTENT PREVIEW ========== */
504
+ .content-preview {
505
+ font-size: 1rem;
506
+ line-height: 1.7;
507
+ padding: var(--space-lg);
508
+ background: var(--bg-inset);
509
+ border-radius: var(--radius-md);
510
+ border-left: 3px solid var(--primary);
511
+ margin-bottom: var(--space-lg);
512
+ min-height: 80px;
513
+ max-height: 200px;
514
+ overflow-y: auto;
515
+ font-weight: 300;
516
+ color: rgba(248, 250, 252, 0.85);
517
+ }
518
+
519
+ /* ========== STAT GRID ========== */
520
+ .meta-grid {
521
+ display: grid;
522
+ grid-template-columns: 1fr 1fr;
523
+ gap: var(--space-sm);
524
+ }
525
+
526
+ .stat-box {
527
+ background: rgba(255, 255, 255, 0.02);
528
+ padding: 0.75rem var(--space-md);
529
+ border-radius: var(--radius-sm);
530
+ border: 1px solid var(--glass-border);
531
+ transition: border-color var(--transition-fast), background var(--transition-fast);
532
+ }
533
+
534
+ .stat-box:hover {
535
+ border-color: var(--glass-border-hover);
536
+ background: rgba(255, 255, 255, 0.03);
537
+ }
538
+
539
+ .stat-box .label {
540
+ display: flex;
541
+ justify-content: space-between;
542
+ font-size: 0.7rem;
543
+ text-transform: uppercase;
544
+ color: var(--text-muted);
545
+ margin-bottom: 0.3rem;
546
+ letter-spacing: 0.5px;
547
+ }
548
+
549
+ .stat-box .value {
550
+ font-size: 1.1rem;
551
+ font-weight: 500;
552
+ }
553
+
554
+ /* ========== ALERT BANNER ========== */
555
  .alert-banner {
556
+ display: flex;
557
+ align-items: center;
558
+ gap: var(--space-md);
559
+ padding: 0.75rem var(--space-md);
560
+ border-radius: var(--radius-md);
561
+ background: var(--bg-elevated);
562
+ border: 1px solid var(--glass-border);
563
+ transition: all var(--transition-normal);
564
+ }
565
+
566
+ .alert-banner.green {
567
+ border-left: 4px solid var(--success);
568
+ box-shadow: inset 4px 0 12px -4px var(--success-dim);
569
+ }
570
+
571
+ .alert-banner.yellow {
572
+ border-left: 4px solid var(--warning);
573
+ box-shadow: inset 4px 0 12px -4px var(--warning-dim);
574
+ }
575
+
576
+ .alert-banner.elevated {
577
+ border-left: 4px solid #f97316;
578
+ box-shadow: inset 4px 0 12px -4px rgba(249, 115, 22, 0.15);
579
+ }
580
+
581
+ .alert-banner.critical {
582
+ border-left: 4px solid var(--danger);
583
+ box-shadow: inset 4px 0 12px -4px var(--danger-dim);
584
+ animation: pulseAlert 2.5s ease-in-out infinite;
585
  }
 
 
 
 
586
 
587
+ @keyframes pulseAlert {
588
+ 0%, 100% { opacity: 1; }
589
+ 50% { opacity: 0.75; }
590
+ }
591
 
592
  .alert-badge {
593
+ background: rgba(255, 255, 255, 0.08);
594
+ padding: 0.2rem 0.5rem;
595
+ border-radius: var(--radius-sm);
596
+ font-size: 0.65rem;
597
+ font-weight: 700;
598
+ letter-spacing: 1px;
599
+ color: var(--text-main);
600
+ flex-shrink: 0;
601
+ }
602
+
603
+ .alert-content strong {
604
+ display: block;
605
+ font-size: 0.85rem;
606
+ margin-bottom: 0.15rem;
607
  }
 
 
608
 
609
+ .alert-content p {
610
+ font-size: 0.7rem;
611
+ color: var(--text-muted);
612
+ }
613
+
614
+ /* ========== FORMS ========== */
615
+ .form-group { margin-bottom: 1.15rem; }
616
 
617
+ label {
618
+ display: block;
619
+ margin-bottom: 0.35rem;
620
+ font-size: 0.7rem;
621
+ color: var(--text-muted);
622
+ text-transform: uppercase;
623
+ letter-spacing: 1px;
624
  }
 
 
 
625
 
626
+ select, input, textarea {
627
+ width: 100%;
628
+ padding: 0.7rem 0.85rem;
629
+ background: rgba(0, 0, 0, 0.35);
630
+ border: 1px solid rgba(255, 255, 255, 0.08);
631
+ border-radius: var(--radius-sm);
632
+ color: var(--text-main);
633
+ font-family: inherit;
634
+ font-size: 0.9rem;
635
+ transition: all var(--transition-fast);
636
  }
637
 
638
+ select:focus, input:focus, textarea:focus {
639
+ border-color: var(--primary);
640
+ outline: none;
641
+ box-shadow: 0 0 0 3px var(--primary-dim);
642
+ }
643
 
644
+ select:hover, input:hover, textarea:hover {
645
+ border-color: rgba(255, 255, 255, 0.12);
646
+ }
647
+
648
+ /* ========== BUTTONS ========== */
649
+ .btn {
650
+ border: none;
651
+ padding: 0.65rem 1.25rem;
652
+ border-radius: var(--radius-sm);
653
+ font-family: inherit;
654
+ font-size: 0.85rem;
655
+ font-weight: 500;
656
+ cursor: pointer;
657
+ transition: all var(--transition-fast);
658
+ display: inline-flex;
659
+ justify-content: center;
660
+ align-items: center;
661
+ gap: var(--space-sm);
662
+ position: relative;
663
+ overflow: hidden;
664
+ }
665
+
666
+ .btn::after {
667
+ content: '';
668
+ position: absolute;
669
+ inset: 0;
670
+ background: linear-gradient(135deg, rgba(255,255,255,0.1), transparent);
671
+ opacity: 0;
672
+ transition: opacity var(--transition-fast);
673
+ }
674
+
675
+ .btn:hover::after { opacity: 1; }
676
+
677
+ .btn-primary {
678
+ background: var(--primary);
679
+ color: white;
680
+ box-shadow: 0 4px 15px var(--primary-glow);
681
+ }
682
+
683
+ .btn-primary:hover {
684
+ background: #4f46e5;
685
+ transform: translateY(-1px);
686
+ box-shadow: 0 6px 20px var(--primary-glow);
687
+ }
688
+
689
+ .btn-outline {
690
+ background: transparent;
691
+ color: var(--text-muted);
692
+ border: 1px solid var(--glass-border);
693
+ }
694
+
695
+ .btn-outline:hover {
696
+ color: var(--text-main);
697
+ border-color: var(--glass-border-hover);
698
+ background: rgba(255, 255, 255, 0.04);
699
+ }
700
+
701
+ .btn-ai {
702
+ background: linear-gradient(135deg, #10b981, #059669);
703
+ color: white;
704
+ font-weight: 600;
705
+ box-shadow: 0 4px 15px var(--success-glow);
706
+ border: 1px solid rgba(255, 255, 255, 0.15);
707
+ }
708
+
709
+ .btn-ai:hover {
710
+ transform: translateY(-1px);
711
+ box-shadow: 0 8px 25px var(--success-glow);
712
+ }
713
+
714
+ .btn-icon {
715
+ background: transparent;
716
+ color: var(--text-muted);
717
+ border: none;
718
+ padding: 0.4rem;
719
+ border-radius: var(--radius-sm);
720
+ font-size: 0.85rem;
721
+ cursor: pointer;
722
+ transition: all var(--transition-fast);
723
+ display: inline-flex;
724
+ align-items: center;
725
+ justify-content: center;
726
+ }
727
+
728
+ .btn-icon:hover {
729
+ color: var(--text-main);
730
+ background: rgba(255, 255, 255, 0.06);
731
+ }
732
+
733
+ /* ========== AGENT BOX ========== */
734
+ .auto-agent-box {
735
+ margin-top: var(--space-lg);
736
+ padding: var(--space-lg);
737
+ background: var(--success-dim);
738
+ border: 1px solid rgba(16, 185, 129, 0.15);
739
+ border-radius: var(--radius-md);
740
+ transition: border-color var(--transition-fast);
741
+ }
742
+
743
+ .auto-agent-box:hover {
744
+ border-color: rgba(16, 185, 129, 0.3);
745
+ }
746
+
747
+ .auto-agent-box h4 {
748
+ margin: 0 0 var(--space-sm) 0;
749
+ color: var(--success);
750
+ font-size: 0.9rem;
751
+ }
752
+
753
+ .auto-agent-box p {
754
+ margin-bottom: var(--space-md);
755
+ }
756
+
757
+ .agent-btns {
758
+ display: flex;
759
+ gap: var(--space-sm);
760
+ }
761
+
762
+ .agent-btns .btn-outline {
763
+ border-color: rgba(16, 185, 129, 0.3);
764
+ color: var(--success);
765
+ }
766
+
767
+ .agent-btns .btn-outline:hover {
768
+ background: rgba(16, 185, 129, 0.08);
769
+ border-color: rgba(16, 185, 129, 0.5);
770
+ }
771
+
772
+ .agent-btns .btn-ai { flex: 1; }
773
+
774
+ /* ========== TERMINAL ========== */
775
+ .terminal-wrapper { position: relative; }
776
+
777
+ .terminal-header {
778
+ background: rgba(0, 0, 0, 0.6);
779
+ padding: 0.65rem var(--space-md);
780
+ border-bottom: 1px solid rgba(255, 255, 255, 0.04);
781
+ display: flex;
782
+ align-items: center;
783
+ gap: var(--space-sm);
784
+ }
785
+
786
+ .dot {
787
+ width: 10px;
788
+ height: 10px;
789
+ border-radius: 50%;
790
+ transition: opacity var(--transition-fast);
791
+ }
792
+
793
+ .dot.red { background: #ff5f56; }
794
+ .dot.yellow { background: #ffbd2e; }
795
+ .dot.green { background: #27c93f; }
796
+
797
+ .terminal-title {
798
+ color: var(--text-dim);
799
+ font-family: 'JetBrains Mono', monospace;
800
+ font-size: 0.75rem;
801
+ margin-left: var(--space-sm);
802
+ }
803
+
804
+ .terminal-clear {
805
+ margin-left: auto;
806
+ font-size: 0.7rem;
807
+ }
808
+
809
+ .terminal-body {
810
+ background: rgba(5, 5, 5, 0.8);
811
+ flex: 1;
812
+ padding: var(--space-lg);
813
+ font-family: 'JetBrains Mono', monospace;
814
+ font-size: 0.8rem;
815
+ color: #a8b2d1;
816
+ overflow-y: auto;
817
+ line-height: 1.7;
818
+ }
819
+
820
+ .log-line {
821
+ margin-bottom: 0.35rem;
822
+ white-space: pre-wrap;
823
+ word-break: break-all;
824
+ }
825
+
826
+ .log-line.running { position: relative; }
827
+ .log-line.running::after {
828
+ content: '█';
829
+ animation: blink 1s step-start infinite;
830
+ color: var(--primary);
831
+ margin-left: 4px;
832
+ }
833
+
834
+ /* ========== REWARD OVERLAY ========== */
835
+ .reward-overlay {
836
+ position: absolute;
837
+ inset: 0;
838
+ background: rgba(5, 5, 5, 0.88);
839
+ backdrop-filter: blur(8px);
840
+ display: flex;
841
+ flex-direction: column;
842
+ align-items: center;
843
+ justify-content: center;
844
+ z-index: 50;
845
+ animation: rewardPopIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
846
+ }
847
+
848
+ .reward-ring {
849
+ width: 130px;
850
+ height: 130px;
851
+ border-radius: 50%;
852
+ display: flex;
853
+ align-items: center;
854
+ justify-content: center;
855
+ font-size: 2.8rem;
856
+ font-weight: 700;
857
+ border: 4px solid var(--glass-border);
858
+ margin-bottom: var(--space-lg);
859
+ background: var(--bg-base);
860
+ font-family: 'JetBrains Mono', monospace;
861
+ transition: all var(--transition-normal);
862
+ }
863
+
864
+ .feedback-text {
865
+ max-width: 80%;
866
+ text-align: center;
867
+ color: var(--text-muted);
868
+ line-height: 1.5;
869
+ }
870
+
871
+ /* ========== MODAL ========== */
872
  .modal-overlay {
873
+ position: fixed;
874
+ inset: 0;
875
+ background: rgba(5, 5, 5, 0.85);
876
+ backdrop-filter: blur(12px);
877
+ z-index: 1000;
878
+ display: flex;
879
+ align-items: center;
880
+ justify-content: center;
881
  }
882
+
883
  .modal-content {
884
+ width: 100%;
885
+ max-width: 460px;
886
+ border-radius: var(--radius-xl);
887
+ animation: modalSlideUp 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275);
888
+ }
889
+
890
+ .modal-actions {
891
+ margin-top: var(--space-xl);
892
+ display: flex;
893
+ gap: var(--space-sm);
894
  }
 
895
 
896
+ /* ========== ANIMATIONS ========== */
897
+ @keyframes blink { 50% { opacity: 0; } }
898
+
899
+ @keyframes rewardPopIn {
900
+ 0% { opacity: 0; transform: scale(0.92); }
901
+ 100% { opacity: 1; transform: scale(1); }
902
+ }
903
+
904
+ @keyframes modalSlideUp {
905
+ 0% { opacity: 0; transform: translateY(20px) scale(0.97); }
906
+ 100% { opacity: 1; transform: translateY(0) scale(1); }
907
+ }
908
+
909
+ @keyframes fadeIn {
910
+ from { opacity: 0; transform: translateY(10px); }
911
+ to { opacity: 1; transform: translateY(0); }
912
+ }
913
+
914
+ .fade-in { animation: fadeIn 0.6s ease backwards; }
915
+ .delay-1 { animation-delay: 0.15s; }
916
+
917
+ /* ========== SCROLLBARS ========== */
918
+ ::-webkit-scrollbar { width: 5px; }
919
+ ::-webkit-scrollbar-track { background: transparent; }
920
+ ::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.08); border-radius: 10px; }
921
+ ::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.15); }
922
+
923
+ /* ========== RESPONSIVE ========== */
924
+ @media (max-width: 1200px) {
925
+ .workspace-grid {
926
+ grid-template-columns: 1fr;
927
+ overflow-y: auto;
928
+ height: auto;
929
+ }
930
+
931
+ .workspace-col {
932
+ height: auto;
933
+ min-height: 500px;
934
+ }
935
+ }
936
+
937
+ @media (max-width: 900px) {
938
+ .sidebar {
939
+ position: fixed;
940
+ left: 0;
941
+ top: 0;
942
+ transform: translateX(-100%);
943
+ z-index: 200;
944
+ box-shadow: 4px 0 20px rgba(0, 0, 0, 0.5);
945
+ }
946
+
947
+ .sidebar.open {
948
+ transform: translateX(0);
949
+ }
950
+
951
+ .sidebar-toggle { display: inline-flex; }
952
+
953
+ .hud-strip { display: none; }
954
+
955
+ .landing-title { font-size: 2rem; }
956
+ .landing-icons { font-size: 2rem; }
957
+
958
+ .workspace-grid {
959
+ grid-template-columns: 1fr;
960
+ padding: var(--space-md);
961
+ gap: var(--space-md);
962
+ }
963
+ }