Vedika commited on
Commit
0968610
·
verified ·
1 Parent(s): 2eb1d86

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +355 -186
index.html CHANGED
@@ -1,3 +1,4 @@
 
1
  <!DOCTYPE html>
2
  <html lang="en" dir="ltr">
3
  <head>
@@ -11,7 +12,7 @@
11
  <title>Arjun 2.O - Professional Advanced AI</title>
12
 
13
  <!-- =========================================================================================
14
- [1] EXTERNAL RESOURCES, FONTS & LIBRARIES (बाहरी स्रोत)
15
  ========================================================================================= -->
16
  <link rel="preconnect" href="https://fonts.googleapis.com">
17
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -29,14 +30,14 @@
29
  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.1/marked.min.js"></script>
30
 
31
  <!-- =========================================================================================
32
- [2] MASSIVE ENTERPRISE CSS ARCHITECTURE (विस्तृत और उन्नत स्टाइलिंग)
33
  ========================================================================================= -->
34
  <style>
35
  /* ---------------------------------------------------------------------------------------
36
- A. CSS VARIABLES, DESIGN TOKENS & TIRANGA BRANDING
37
  --------------------------------------------------------------------------------------- */
38
  :root {
39
- /* Brand Identity: Saffron, White, Green (Tiranga) */
40
  --brand-saffron: #FF9933;
41
  --brand-saffron-light: rgba(255, 153, 51, 0.12);
42
  --brand-saffron-dark: #e68a2e;
@@ -64,11 +65,12 @@
64
  --text-tertiary: #9ca3af;
65
  --text-inverse: #ffffff;
66
  --text-error: #ef4444;
 
67
 
68
  /* Borders & Dividers */
69
  --border-light: rgba(0, 0, 0, 0.08);
70
  --border-medium: rgba(0, 0, 0, 0.15);
71
- --border-focus: rgba(255, 153, 51, 0.4);
72
 
73
  /* Shadows & Elevation */
74
  --shadow-xs: 0 1px 2px rgba(0,0,0,0.04);
@@ -76,6 +78,7 @@
76
  --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.05), 0 2px 4px -1px rgba(0,0,0,0.03);
77
  --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025);
78
  --shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.05), 0 10px 10px -5px rgba(0,0,0,0.02);
 
79
  --shadow-inner: inset 0 2px 4px rgba(0,0,0,0.06);
80
 
81
  /* Font Families */
@@ -96,7 +99,7 @@
96
  --ease-smooth: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
97
  --ease-spring: 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
98
 
99
- /* Z-Indices */
100
  --z-ambient: -1;
101
  --z-base: 1;
102
  --z-header: 10;
@@ -107,6 +110,7 @@
107
  --z-modal: 5000;
108
  --z-toast: 9000;
109
  --z-live: 9999;
 
110
  }
111
 
112
  /* ---------------------------------------------------------------------------------------
@@ -116,7 +120,6 @@
116
  box-sizing: border-box;
117
  margin: 0;
118
  padding: 0;
119
- /* CRITICAL: REMOVE BLUE TAP HIGHLIGHT ON MOBILE/BROWSERS */
120
  -webkit-tap-highlight-color: transparent !important;
121
  -webkit-touch-callout: none !important;
122
  }
@@ -135,8 +138,9 @@
135
  -moz-osx-font-smoothing: grayscale;
136
  }
137
 
138
- /* Remove default outlines and use custom focus states */
139
- *:focus { outline: none !important; }
 
140
 
141
  button, input, textarea, select {
142
  font-family: inherit;
@@ -146,19 +150,27 @@
146
  }
147
 
148
  button { cursor: pointer; user-select: none; }
 
149
  a { color: inherit; text-decoration: none; }
150
  img { max-width: 100%; height: auto; display: block; }
151
  svg { flex-shrink: 0; }
152
 
153
- /* Highly Customized Scrollbars */
154
- ::-webkit-scrollbar { width: 6px; height: 6px; }
155
  ::-webkit-scrollbar-track { background: transparent; }
156
- ::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.12); border-radius: 10px; transition: background var(--ease-smooth); }
157
- ::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.25); }
158
 
159
  /* ---------------------------------------------------------------------------------------
160
- C. AMBIENT BACKGROUND SYSTEM (प्रीमियम बैकग्राउंड इफ़ेक्ट्स)
161
  --------------------------------------------------------------------------------------- */
 
 
 
 
 
 
 
162
  .ambient-environment {
163
  position: fixed; inset: 0; z-index: var(--z-ambient); overflow: hidden; pointer-events: none;
164
  background: linear-gradient(135deg, var(--brand-saffron-light) 0%, var(--bg-primary) 50%, var(--brand-green-light) 100%);
@@ -185,21 +197,25 @@
185
  }
186
 
187
  /* ---------------------------------------------------------------------------------------
188
- D. TOAST NOTIFICATION ENGINE (सुंदर और स्पष्ट सूचनाएं)
189
  --------------------------------------------------------------------------------------- */
190
  .toast-wrapper {
191
  position: absolute; top: 24px; left: 50%; transform: translateX(-50%);
192
  z-index: var(--z-toast); display: flex; flex-direction: column; gap: 12px;
193
- pointer-events: none; width: 90%; max-width: 400px; align-items: center;
194
  }
195
  .toast-notification {
196
- background: var(--text-primary); color: var(--text-inverse); padding: 14px 24px;
197
  border-radius: var(--radius-full); font-size: 14px; font-weight: 600; box-shadow: var(--shadow-xl);
198
  animation: toastSlideIn var(--ease-spring) forwards, toastFadeOut 0.4s 3.5s forwards;
199
- display: flex; align-items: center; gap: 10px; width: fit-content; max-width: 100%; word-break: break-word;
200
- border: 1px solid rgba(255,255,255,0.1);
201
  }
202
- .toast-notification svg { width: 18px; height: 18px; flex-shrink: 0; color: var(--brand-saffron); }
 
 
 
 
203
  @keyframes toastSlideIn { from { opacity: 0; transform: translateY(-30px) scale(0.9); } to { opacity: 1; transform: translateY(0) scale(1); } }
204
  @keyframes toastFadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } }
205
 
@@ -214,22 +230,22 @@
214
  }
215
  .startup-overlay.hidden { opacity: 0; visibility: hidden; pointer-events: none; }
216
 
217
- .startup-logo-container { position: relative; margin-bottom: 32px; animation: popIn var(--ease-spring) 0.3s both; }
218
  .startup-logo-container img { width: 140px; height: 140px; border-radius: var(--radius-xl); object-fit: cover; box-shadow: var(--shadow-xl); border: 4px solid var(--bg-primary); position: relative; z-index: 2; }
219
  .startup-logo-glow { position: absolute; inset: -20px; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); filter: blur(30px); opacity: 0.4; border-radius: var(--radius-full); z-index: 1; animation: pulseGlow 3s infinite alternate; }
220
 
221
  @keyframes pulseGlow { from { opacity: 0.3; transform: scale(0.95); } to { opacity: 0.6; transform: scale(1.05); } }
222
- @keyframes popIn { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: scale(1); } }
223
 
224
- .startup-title { font-family: var(--font-sans); font-size: 2.5rem; font-weight: 900; color: var(--text-primary); letter-spacing: -1px; margin-bottom: 16px; animation: slideUp var(--ease-smooth) 0.4s both; }
225
- .startup-desc { font-size: 1.1rem; color: var(--text-secondary); line-height: 1.6; max-width: 550px; margin-bottom: 40px; animation: slideUp var(--ease-smooth) 0.5s both; font-weight: 500; }
226
 
227
- .btn-startup-launch { padding: 18px 48px; background: var(--text-primary); color: var(--text-inverse); border: none; border-radius: var(--radius-xl); font-size: 1.125rem; font-weight: 700; cursor: pointer; transition: var(--ease-spring); box-shadow: 0 10px 25px rgba(0,0,0,0.15); animation: slideUp var(--ease-smooth) 0.6s both; display: flex; align-items: center; gap: 12px; position: relative; overflow: hidden; }
228
  .btn-startup-launch::before { content: ''; position: absolute; top: 0; left: -100%; width: 50%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); transform: skewX(-20deg); transition: 0.5s; }
229
  .btn-startup-launch:hover { background: #000000; transform: translateY(-4px) scale(1.02); box-shadow: 0 15px 35px rgba(0,0,0,0.25); }
230
  .btn-startup-launch:hover::before { left: 150%; }
231
 
232
- @keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
233
 
234
  /* ---------------------------------------------------------------------------------------
235
  F. CORE APPLICATION LAYOUT & SIDEBAR
@@ -241,11 +257,11 @@
241
  .sidebar-header { padding: 28px 24px; border-bottom: 1px solid var(--border-light); display: flex; justify-content: space-between; align-items: center; }
242
 
243
  .brand-identity { display: flex; align-items: center; gap: 14px; text-decoration: none; }
244
- .brand-identity img { width: 50px; height: 50px; border-radius: var(--radius-md); object-fit: cover; box-shadow: var(--shadow-sm); border: 2px solid var(--bg-primary); transition: transform var(--ease-spring); }
245
- .brand-identity:hover img { transform: scale(1.08) rotate(-3deg); }
246
  .brand-typography { display: flex; flex-direction: column; }
247
  .brand-name { font-family: var(--font-sans); font-weight: 900; font-size: 20px; color: var(--text-primary); letter-spacing: -0.5px; line-height: 1.1; }
248
- .brand-edition { font-size: 11px; font-weight: 800; letter-spacing: 1.5px; text-transform: uppercase; background: linear-gradient(90deg, var(--brand-saffron), var(--brand-green)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-top: 4px; }
249
 
250
  .btn-mobile-close { display: none; background: rgba(0,0,0,0.05); border: none; width: 36px; height: 36px; border-radius: 50%; color: var(--text-primary); cursor: pointer; align-items: center; justify-content: center; transition: var(--ease-fast); }
251
  .btn-mobile-close:hover { background: rgba(239, 68, 68, 0.15); color: var(--text-error); transform: rotate(90deg); }
@@ -264,7 +280,7 @@
264
  .user-details { flex: 1; overflow: hidden; }
265
  .user-email-id { font-size: 14px; font-weight: 700; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
266
  .user-clearance-level { font-size: 11px; color: var(--brand-green); font-weight: 600; margin-top: 2px; display: flex; align-items: center; gap: 4px; }
267
- .user-clearance-level::before { content: ''; display: block; width: 6px; height: 6px; border-radius: 50%; background: var(--brand-green); box-shadow: var(--shadow-glow-green); }
268
  .btn-system-logout { background: rgba(239, 68, 68, 0.08); color: var(--text-error); border: none; width: 38px; height: 38px; border-radius: var(--radius-md); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--ease-fast); }
269
  .btn-system-logout:hover { background: var(--text-error); color: #ffffff; transform: scale(1.05); }
270
 
@@ -285,13 +301,14 @@
285
  --------------------------------------------------------------------------------------- */
286
  .main-chat-wrapper { flex: 1; display: flex; flex-direction: column; position: relative; min-width: 320px; transition: width var(--ease-smooth); background: transparent; }
287
 
288
- .chat-top-bar { padding: 18px 32px; border-bottom: 1px solid var(--border-light); background: rgba(255, 255, 255, 0.85); backdrop-filter: blur(15px); display: flex; align-items: center; justify-content: space-between; z-index: var(--z-header); }
289
  .top-bar-left { display: flex; align-items: center; gap: 16px; }
290
  .btn-hamburger { display: none; background: var(--bg-primary); border: 1px solid var(--border-light); cursor: pointer; color: var(--text-primary); width: 42px; height: 42px; border-radius: var(--radius-sm); align-items: center; justify-content: center; box-shadow: var(--shadow-sm); transition: var(--ease-fast); }
291
  .btn-hamburger:hover { background: var(--bg-secondary); }
292
 
293
- .system-status-pill { display: flex; align-items: center; gap: 10px; font-size: 14px; font-weight: 700; color: var(--text-primary); padding: 8px 18px; background: var(--bg-secondary); border-radius: var(--radius-full); border: 1px solid var(--border-light); }
294
- .pulse-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--brand-green); box-shadow: 0 0 0 3px rgba(19, 136, 8, 0.2); animation: statusPulse 2s infinite; }
 
295
  @keyframes statusPulse { 0% { box-shadow: 0 0 0 0 rgba(19,136,8,0.4); } 70% { box-shadow: 0 0 0 6px rgba(19,136,8,0); } 100% { box-shadow: 0 0 0 0 rgba(19,136,8,0); } }
296
 
297
  /* DYNAMIC LIVE MODE ACTIVATOR */
@@ -309,11 +326,12 @@
309
  .hero-avatar-wrapper img { width: 100px; height: 100px; border-radius: var(--radius-xl); object-fit: cover; box-shadow: var(--shadow-xl); border: 3px solid var(--bg-primary); position: relative; z-index: 2; }
310
  .hero-avatar-glow { position: absolute; inset: -12px; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); filter: blur(25px); opacity: 0.35; border-radius: 40px; z-index: 1; animation: rotateGlow 10s linear infinite;}
311
  @keyframes rotateGlow { 100% { transform: rotate(360deg); } }
 
312
 
313
- .hero-greeting { font-size: 42px; font-weight: 900; letter-spacing: -1.5px; margin-bottom: 18px; color: var(--text-primary); }
314
  .hero-description { font-size: 17px; color: var(--text-secondary); line-height: 1.6; margin-bottom: 40px; font-weight: 500; }
315
 
316
- /* RESTORED: GUEST BADGE LIMIT DISPLAY */
317
  .guest-warning-badge { font-size: 13px; font-weight: 700; color: var(--text-error); background: #fee2e2; padding: 10px 20px; border-radius: var(--radius-full); margin-bottom: 32px; display: none; align-items: center; gap: 8px; border: 1px solid #fca5a5; box-shadow: var(--shadow-sm); }
318
  .guest-warning-badge svg { width: 18px; height: 18px; }
319
 
@@ -329,8 +347,8 @@
329
  /* ---------------------------------------------------------------------------------------
330
  H. CHAT MESSAGE BUBBLES & PREVIEWS
331
  --------------------------------------------------------------------------------------- */
332
- .chat-message-row { display: flex; gap: 20px; max-width: 88%; animation: messagePopIn 0.5s var(--ease-spring) both; }
333
- @keyframes messagePopIn { from { opacity: 0; transform: translateY(25px) scale(0.97); } to { opacity: 1; transform: none; } }
334
  .chat-message-row.user-msg { flex-direction: row-reverse; align-self: flex-end; }
335
  .chat-message-row.bot-msg { align-self: flex-start; }
336
 
@@ -346,7 +364,8 @@
346
  .file-badge svg { width: 12px; height: 12px; }
347
 
348
  /* In-Bubble File Previews */
349
- .chat-in-bubble-img { max-width: 320px; max-height: 320px; border-radius: var(--radius-md); object-fit: cover; border: 2px solid rgba(255,255,255,0.2); box-shadow: var(--shadow-md); margin-bottom: 12px; }
 
350
  .chat-file-card { display: flex; align-items: center; gap: 14px; background: rgba(255,255,255,0.15); border: 1px solid rgba(255,255,255,0.3); padding: 12px 18px; border-radius: var(--radius-md); margin-bottom: 12px; max-width: 350px; backdrop-filter: blur(10px); }
351
  .chat-file-card .icon { font-size: 24px; background: rgba(0,0,0,0.1); width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-sm); }
352
  .chat-file-card .name { font-size: 14px; font-weight: 600; color: var(--brand-white); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@@ -366,15 +385,29 @@
366
  .btn-bot-action.action-tts { color: var(--brand-green-dark); border-color: rgba(19, 136, 8, 0.25); background: var(--brand-green-light); }
367
  .btn-bot-action.action-tts:hover { background: rgba(19, 136, 8, 0.2); }
368
 
369
- /* Markdown Rendering inside Bubbles */
370
  .chat-bubble p { margin-bottom: 16px; }
371
  .chat-bubble p:last-child { margin-bottom: 0; }
372
  .chat-bubble strong { font-weight: 800; color: inherit; }
 
 
 
 
 
 
 
 
 
 
 
373
  .chat-bubble code { font-family: var(--font-mono); background: rgba(0,0,0,0.06); padding: 4px 8px; border-radius: 6px; font-size: 0.85em; color: #d946ef; font-weight: 600; border: 1px solid rgba(0,0,0,0.05); }
374
  .user-msg .chat-bubble code { background: rgba(255,255,255,0.2); color: var(--brand-white); border-color: rgba(255,255,255,0.1); }
 
375
  .chat-bubble img { max-width: 100%; border-radius: var(--radius-md); margin: 16px 0; box-shadow: var(--shadow-lg); border: 1px solid var(--border-light); display: block; }
376
- .chat-bubble pre { background: #282c34; color: #abb2bf; padding: 20px; border-radius: var(--radius-md); overflow-x: auto; margin: 20px 0; font-family: var(--font-mono); font-size: 14px; line-height: 1.6; border: 1px solid #181a1f; box-shadow: var(--shadow-inner); }
377
- .chat-bubble pre code { background: transparent; color: inherit; padding: 0; font-weight: 400; border: none; }
 
 
378
 
379
  /* Streaming Loading UI Component */
380
  .streaming-code-container { background: #1e1e2e; border-radius: var(--radius-md); border: 1px solid #313244; overflow: hidden; margin: 20px 0; box-shadow: var(--shadow-lg); }
@@ -398,12 +431,12 @@
398
  I. BOTTOM INPUT DOCK & TOOLS
399
  --------------------------------------------------------------------------------------- */
400
  .input-dock { flex-shrink: 0; padding: 0 40px 32px; background: transparent; position: relative; z-index: var(--z-dock); }
401
- .input-master-container { display: flex; flex-direction: column; background: var(--bg-glass); backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px); border: 1px solid var(--border-light); border-radius: var(--radius-xl); box-shadow: var(--shadow-xl); transition: var(--ease-smooth); }
402
  .input-master-container:focus-within { border-color: var(--brand-saffron); box-shadow: 0 20px 40px -5px rgba(255,153,51,0.15), 0 0 0 4px var(--brand-saffron-light); }
403
 
404
- /* Upload Preview Header (Non-Technical Vocabulary) */
405
- .upload-preview-bar { display: none; padding: 20px 28px 0; align-items: center; gap: 16px; }
406
- .upload-preview-bar.visible { display: flex; animation: fadeIn 0.3s ease; }
407
  .upload-thumb { width: 52px; height: 52px; object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--border-light); display: flex; justify-content: center; align-items: center; background: var(--bg-tertiary); font-size: 24px; box-shadow: var(--shadow-sm); }
408
  .upload-meta { flex: 1; }
409
  .upload-filename { font-size: 14px; font-weight: 700; color: var(--text-primary); max-width: 250px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@@ -418,9 +451,13 @@
418
  .main-textarea { flex: 1; border: none; outline: none; background: transparent; font-family: var(--font-sans); font-size: 16px; color: var(--text-primary); line-height: 1.5; resize: none; max-height: 200px; min-height: 24px; padding: 12px 0; margin: 0 8px; font-weight: 500; }
419
  .main-textarea::placeholder { color: var(--text-tertiary); font-weight: 400; }
420
 
 
 
 
 
421
  /* Attachment Menu Dropdown */
422
  .attachment-module { position: relative; }
423
- .btn-tool-icon { width: 44px; height: 44px; border-radius: var(--radius-md); background: transparent; border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-secondary); transition: var(--ease-fast); }
424
  .btn-tool-icon:hover { background: var(--bg-tertiary); color: var(--text-primary); }
425
  .btn-tool-icon svg { width: 24px; height: 24px; stroke-width: 2; }
426
 
@@ -438,15 +475,19 @@
438
  .language-toggle-chip.hindi-active { background: var(--brand-green-light); color: var(--brand-green-dark); border-color: var(--brand-green); }
439
  .language-toggle-chip svg { width: 16px; height: 16px; }
440
 
441
- .btn-mic-tool.active-listening { color: #ffffff; background: var(--text-error); animation: recordPulse 1.5s infinite; border-radius: var(--radius-full); }
442
- @keyframes recordPulse { 0% { box-shadow: 0 0 0 0 rgba(239,68,68,0.5); } 70% { box-shadow: 0 0 0 12px rgba(239,68,68,0); } 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); } }
 
 
443
 
444
  /* Master Send Button */
445
- .btn-master-send { width: 48px; height: 48px; border-radius: 16px; border: none; background: linear-gradient(135deg, var(--brand-saffron) 0%, var(--brand-green) 100%); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--ease-spring); box-shadow: 0 6px 20px rgba(19, 136, 8, 0.25); }
446
- .btn-master-send svg { width: 20px; height: 20px; fill: white; transition: transform 0.2s; }
 
447
  .btn-master-send:hover { transform: translateY(-3px); box-shadow: 0 10px 25px rgba(255, 153, 51, 0.4); }
 
448
  .btn-master-send:hover svg { transform: translate(2px, -2px); }
449
- .btn-master-send:disabled { opacity: 0.4; cursor: not-allowed; filter: grayscale(100%); transform: none; box-shadow: none; }
450
 
451
  .bottom-branding-text { text-align: center; font-size: 12px; color: var(--text-tertiary); margin-top: 16px; font-weight: 600; letter-spacing: 0.5px; }
452
 
@@ -467,12 +508,16 @@
467
  .btn-workspace-tool.close:hover { color: #e06c75; background: rgba(224, 108, 117, 0.1); }
468
 
469
  .workspace-editor-surface { flex: 1; overflow-y: auto; background: #282c34; padding: 24px; position: relative; }
470
- .workspace-editor-surface pre { margin: 0; padding: 0; background: transparent; font-family: var(--font-mono); font-size: 15px; line-height: 1.6; overflow-x: auto; color: #abb2bf; border: none; box-shadow: none;}
 
 
 
 
471
 
472
  /* ---------------------------------------------------------------------------------------
473
  K. LIVE MODE FULLSCREEN OVERLAY
474
  --------------------------------------------------------------------------------------- */
475
- .live-mode-viewport { position: fixed; inset: 0; background: rgba(255, 255, 255, 0.98); z-index: var(--z-live); display: flex; flex-direction: column; align-items: center; justify-content: center; opacity: 0; pointer-events: none; transition: opacity var(--ease-smooth); }
476
  .live-mode-viewport.active { opacity: 1; pointer-events: auto; }
477
  .btn-close-live { position: absolute; top: 40px; right: 40px; background: rgba(0,0,0,0.04); border: none; width: 56px; height: 56px; border-radius: 50%; font-size: 24px; cursor: pointer; transition: var(--ease-spring); display: flex; align-items: center; justify-content: center; color: var(--text-secondary); }
478
  .btn-close-live:hover { background: rgba(239, 68, 68, 0.15); color: var(--text-error); transform: rotate(90deg); }
@@ -480,22 +525,22 @@
480
  .pulsing-orb-wrapper { position: relative; width: 250px; height: 250px; display: flex; align-items: center; justify-content: center; margin-bottom: 50px; }
481
  .energy-core { width: 120px; height: 120px; border-radius: 50%; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); box-shadow: 0 0 50px rgba(19, 136, 8, 0.5); position: relative; z-index: 2; transition: transform 0.15s ease-out; }
482
  .energy-core.speaking { animation: coreSpeak 0.5s infinite alternate; }
483
- @keyframes coreSpeak { 0% { transform: scale(1); box-shadow: 0 0 30px rgba(19,136,8,0.4); } 100% { transform: scale(1.1); box-shadow: 0 0 60px rgba(255,153,51,0.6); } }
484
 
485
  .energy-ring { position: absolute; inset: 0; border: 3px solid var(--brand-saffron); border-radius: 50%; opacity: 0; animation: energyRipple 2.5s cubic-bezier(0.4, 0, 0.2, 1) infinite; }
486
  .energy-ring:nth-child(2) { animation-delay: 0.8s; border-color: var(--brand-green); }
487
  .energy-ring:nth-child(3) { animation-delay: 1.6s; border-color: var(--text-primary); }
488
  @keyframes energyRipple { 0% { transform: scale(0.4); opacity: 1; border-width: 6px; } 100% { transform: scale(1.6); opacity: 0; border-width: 1px; } }
489
 
490
- .live-feedback-status { font-size: 28px; font-weight: 900; color: var(--text-primary); margin-bottom: 16px; font-family: var(--font-sans); letter-spacing: -0.5px; }
491
- .live-feedback-text { font-size: 18px; color: var(--text-secondary); max-width: 700px; text-align: center; line-height: 1.6; min-height: 60px; font-weight: 500; padding: 0 20px; }
492
 
493
  .live-control-deck { display: flex; gap: 24px; margin-top: 50px; }
494
  .btn-live-deck { width: 80px; height: 80px; border-radius: 50%; border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: var(--shadow-lg); transition: var(--ease-spring); }
495
  .btn-live-deck.mic-control { background: var(--bg-primary); border: 3px solid var(--border-light); color: var(--text-primary); }
496
  .btn-live-deck.mic-control:hover { transform: translateY(-6px); border-color: var(--brand-saffron); color: var(--brand-saffron); box-shadow: var(--shadow-xl); }
497
  .btn-live-deck.mic-control.is-recording { background: var(--text-error); color: white; border-color: var(--text-error); animation: pulseMicLive 1.2s infinite; }
498
- @keyframes pulseMicLive { 0% { box-shadow: 0 0 0 0 rgba(239,68,68,0.6); } 70% { box-shadow: 0 0 0 20px rgba(239,68,68,0); } 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); } }
499
 
500
  /* Scroll Trigger Button */
501
  .btn-scroll-trigger { position: absolute; bottom: 150px; left: 50%; width: 48px; height: 48px; border-radius: 50%; background: var(--bg-glass); backdrop-filter: blur(15px); border: 1px solid var(--border-light); box-shadow: var(--shadow-lg); display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-secondary); opacity: 0; pointer-events: none; transform: translateX(-50%) translateY(20px); transition: var(--ease-smooth); z-index: 20; }
@@ -508,7 +553,7 @@
508
  .secure-modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.5); backdrop-filter: blur(10px); z-index: var(--z-modal); display: none; justify-content: center; align-items: center; animation: fadeIn 0.3s ease; }
509
  .secure-modal-surface { background: var(--bg-primary); padding: 44px; border-radius: var(--radius-xl); width: 90%; max-width: 460px; box-shadow: var(--shadow-xl); position: relative; border: 1px solid rgba(255,255,255,0.4); }
510
  .btn-modal-dismiss { position: absolute; top: 24px; right: 24px; background: var(--bg-secondary); border: none; width: 36px; height: 36px; border-radius: 50%; font-size: 18px; color: var(--text-secondary); cursor: pointer; transition: 0.2s; display: flex; align-items: center; justify-content: center; }
511
- .btn-modal-dismiss:hover { background: #fee2e2; color: var(--text-error); }
512
  .modal-brand-header { text-align: center; margin-bottom: 36px; font-family: var(--font-sans); font-size: 28px; font-weight: 900; color: var(--text-primary); letter-spacing: -0.5px; }
513
 
514
  .auth-tab-switch { display: flex; background: var(--bg-secondary); padding: 6px; border-radius: var(--radius-md); margin-bottom: 28px; }
@@ -562,11 +607,20 @@
562
 
563
  .input-tools-row { flex-wrap: wrap; }
564
  .main-textarea { min-width: 100%; order: -1; margin-bottom: 10px; }
 
565
  }
566
  </style>
567
  </head>
568
  <body>
569
 
 
 
 
 
 
 
 
 
570
  <!-- =========================================================================================
571
  DOM STRUCTURE: NOTIFICATIONS
572
  ========================================================================================= -->
@@ -633,7 +687,7 @@
633
  <img src="https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png" alt="Arjun Logo">
634
  <div class="brand-typography">
635
  <span class="brand-name">ARJUN 2.O</span>
636
- <span class="brand-edition">Professional</span>
637
  </div>
638
  </a>
639
  <button class="btn-mobile-close" id="btnSidebarClose">
@@ -671,7 +725,7 @@
671
  <!-- Wipe Memory Button -->
672
  <button class="btn-erase-memory" id="btnClearMemory">
673
  <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>
674
- Wipe Memory Context
675
  </button>
676
  </div>
677
  </aside>
@@ -685,9 +739,9 @@
685
  <button class="btn-hamburger" id="btnSidebarOpen">
686
  <svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2.5" fill="none"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
687
  </button>
688
- <div class="system-status-pill">
689
  <div class="pulse-dot"></div>
690
- System Online
691
  </div>
692
  </div>
693
 
@@ -742,7 +796,7 @@
742
 
743
  <!-- File Preview Component -->
744
  <div class="upload-preview-bar" id="filePreviewBar">
745
- <img class="upload-thumb" id="previewImgThumb" src="" style="display:none;">
746
  <div class="upload-thumb" id="previewDocIcon" style="display:none;">📄</div>
747
  <div class="upload-meta">
748
  <div class="upload-filename" id="previewFileName">document.pdf</div>
@@ -751,7 +805,7 @@
751
  File ready to be transmitted
752
  </div>
753
  </div>
754
- <button class="btn-discard-upload" id="btnDiscardFile">
755
  <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
756
  </button>
757
  </div>
@@ -803,7 +857,11 @@
803
  </button>
804
 
805
  <!-- Expanding Text Area -->
806
- <textarea class="main-textarea" id="mainChatInput" placeholder="Message Arjun Intelligence..." rows="1"></textarea>
 
 
 
 
807
 
808
  <!-- Master Send Button -->
809
  <button class="btn-master-send" id="masterSendBtn">
@@ -833,7 +891,10 @@
833
  </div>
834
  </div>
835
  <div class="workspace-editor-surface">
836
- <pre><code id="workspaceCodeBlock" class="hljs"></code></pre>
 
 
 
837
  </div>
838
  </aside>
839
  </div>
@@ -883,11 +944,8 @@
883
  </div>
884
 
885
  <!-- =========================================================================================
886
- [3] MASSIVE ENTERPRISE JAVASCRIPT ARCHITECTURE
887
  ========================================================================================= -->
888
- <!-- CRITICAL FIX: Removed type="module" from the script block to ensure all elements
889
- and functions remain within the window/global scope and are easily bound.
890
- Gradio Client will be dynamically imported. -->
891
  <script>
892
  // =======================================================================================
893
  // 1. CONFIGURATION & STATE MANAGEMENT
@@ -897,6 +955,7 @@
897
  LOGO_URL: "https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png",
898
  PDF_WORKER: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js',
899
  API_ENDPOINT: '/api/chat', // Uses relative path to connect to Flask App.py
 
900
  };
901
 
902
  // Initialize PDF worker
@@ -914,17 +973,19 @@
914
  isStreamingActive: false,
915
  isLiveModeEngaged: false,
916
  gradioClient: null,
917
- isMicRecording: false
 
918
  };
919
 
920
- // Initialize Gradio Client Dynamically (Fixes the Module Bug)
921
  window.initGradioEngine = async function() {
922
  try {
923
  const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
924
  AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS");
925
  console.log("Neural TTS Engine connected successfully to Gradio.");
926
  } catch(err) {
927
- console.error("Gradio Connection Error:", err);
 
928
  }
929
  };
930
  window.initGradioEngine();
@@ -933,38 +994,37 @@
933
  // 2. UTILITY ENGINE (Robust Copy, Notifications, and Text Cleaners)
934
  // =======================================================================================
935
  const Utils = {
936
- showToast: (message) => {
937
  const container = document.getElementById('toast-container');
938
  const toast = document.createElement('div');
939
- toast.className = 'toast-notification';
940
- toast.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> ${message}`;
 
 
 
 
941
  container.appendChild(toast);
942
- setTimeout(() => toast.remove(), 3000);
943
  },
944
 
945
  escapeHTML: (str) => {
 
946
  return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
947
  },
948
 
949
- // ✨ CRITICAL FIX: Intelligent Text Cleaner for TTS (Ignores code, links, images)
950
  cleanTextForVoice: (rawText) => {
951
  if(!rawText) return "";
952
  let cleaned = rawText;
953
 
954
- // 1. Remove Markdown Code Blocks (``` ... ```)
955
- cleaned = cleaned.replace(/```[\s\S]*?```/g, '');
956
- // 2. Remove Inline Code (`...`)
957
- cleaned = cleaned.replace(/`.*?`/g, '');
958
- // 3. Remove Markdown Images (![alt](url))
959
- cleaned = cleaned.replace(/!\[.*?\]\(.*?\)/g, '');
960
- // 4. Remove Markdown Links ([text](url)) - Extract just the text
961
- cleaned = cleaned.replace(/\[(.*?)\]\(.*?\)/g, '$1');
962
- // 5. Remove Think Tags (<think>...</think>)
963
- cleaned = cleaned.replace(/<think>[\s\S]*?<\/think>/gi, '');
964
- // 6. Remove URLs/HTTP links explicitly
965
- cleaned = cleaned.replace(/https?:\/\/[^\s]+/g, '');
966
- // 7. Remove stray Markdown formatting symbols
967
- cleaned = cleaned.replace(/[*_~#]/g, '');
968
 
969
  return cleaned.trim();
970
  },
@@ -974,6 +1034,7 @@
974
  const textArea = document.createElement("textarea");
975
  textArea.value = text;
976
  textArea.style.top = "0"; textArea.style.left = "0"; textArea.style.position = "fixed";
 
977
  document.body.appendChild(textArea);
978
  textArea.focus(); textArea.select();
979
 
@@ -981,13 +1042,13 @@
981
  const successful = document.execCommand('copy');
982
  if (successful) {
983
  const originalHTML = btnElement.innerHTML;
984
- btnElement.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> Copied Successfully`;
985
  setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
986
  } else {
987
- Utils.showToast("Clipboard access denied by browser.");
988
  }
989
  } catch (err) {
990
- Utils.showToast("System error copying text.");
991
  }
992
  document.body.removeChild(textArea);
993
  },
@@ -999,7 +1060,7 @@
999
  }
1000
  navigator.clipboard.writeText(textToCopy).then(() => {
1001
  const originalHTML = btnElement.innerHTML;
1002
- btnElement.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> Copied Successfully`;
1003
  setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
1004
  }).catch((err) => {
1005
  console.warn('Modern API failed, utilizing fallback...', err);
@@ -1009,7 +1070,7 @@
1009
  };
1010
 
1011
  // =======================================================================================
1012
- // 3. AUTHENTICATION & SYNC MANAGER (Robust Fetch)
1013
  // =======================================================================================
1014
  const AuthManager = {
1015
  initUI: () => {
@@ -1048,8 +1109,9 @@
1048
  document.getElementById(nextId).classList.add('active');
1049
  },
1050
 
1051
- // ✨ FIXED GAS SYNC LOGIC
1052
  process: async (actionType) => {
 
 
1053
  const payload = { action: actionType };
1054
  let buttonId = '';
1055
 
@@ -1057,18 +1119,18 @@
1057
  payload.name = document.getElementById('authRegName').value.trim();
1058
  payload.email = document.getElementById('authRegEmail').value.trim();
1059
  payload.phone = "0000000000"; payload.organization = "Arjun Base";
1060
- if (!payload.email || !payload.name) return Utils.showToast("Identification details required.");
1061
  buttonId = 'btn-fire-reg-otp';
1062
  }
1063
  else if (actionType === 'login_send_otp') {
1064
  payload.email = document.getElementById('authLogEmail').value.trim();
1065
- if (!payload.email) return Utils.showToast("Email required for validation.");
1066
  buttonId = 'btn-fire-log-otp';
1067
  }
1068
  else if (actionType === 'register_verify' || actionType === 'login_verify') {
1069
  payload.email = document.getElementById(actionType === 'register_verify' ? 'authRegEmail' : 'authLogEmail').value.trim();
1070
  payload.otp = document.getElementById(actionType === 'register_verify' ? 'authRegOTP' : 'authLogOTP').value.trim();
1071
- if (!payload.otp) return Utils.showToast("Security token required.");
1072
  buttonId = actionType === 'register_verify' ? 'btn-fire-reg-verify' : 'btn-fire-log-verify';
1073
  }
1074
 
@@ -1078,7 +1140,6 @@
1078
  triggerBtn.innerText = 'Establishing Connection...';
1079
 
1080
  try {
1081
- // mode: 'cors' handles redirect issues from GAS effectively
1082
  const response = await fetch(Config.GAS_URL, {
1083
  method: 'POST',
1084
  mode: 'cors',
@@ -1089,7 +1150,7 @@
1089
  const result = await response.json();
1090
 
1091
  if (result.status === 'success') {
1092
- Utils.showToast(result.message);
1093
  if (actionType === 'register_send_otp') AuthManager.switchPhase('auth-reg-phase-1', 'auth-reg-phase-2');
1094
  else if (actionType === 'login_send_otp') AuthManager.switchPhase('auth-log-phase-1', 'auth-log-phase-2');
1095
  else if (actionType === 'register_verify' || actionType === 'login_verify') {
@@ -1100,11 +1161,11 @@
1100
  ChatEngine.syncHistoryFromCloud();
1101
  }
1102
  } else {
1103
- Utils.showToast(result.message);
1104
  }
1105
  } catch (error) {
1106
  console.error("Auth Network Error: ", error);
1107
- Utils.showToast("Encrypted gateway error. Check network.");
1108
  }
1109
 
1110
  triggerBtn.disabled = false;
@@ -1153,22 +1214,48 @@
1153
 
1154
  toggleAttachMenu: () => {
1155
  document.getElementById('attachDropdownMenu').classList.toggle('visible');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1156
  }
1157
  };
1158
 
1159
  // =======================================================================================
1160
- // 5. SPEECH & TTS ENGINE (Bilingual STT + Gradio Edge-TTS + Smart Cleaner)
1161
  // =======================================================================================
1162
  const VoiceEngine = {
1163
  recognition: null,
1164
  currentLanguage: 'en-IN',
1165
-
 
 
1166
  init: () => {
1167
  const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
1168
- if (!SR) return;
 
 
 
 
1169
 
1170
  VoiceEngine.recognition = new SR();
1171
- // FIX: Setting continuous to true prevents mic from stopping abruptly
1172
  VoiceEngine.recognition.continuous = true;
1173
  VoiceEngine.recognition.interimResults = true;
1174
  VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
@@ -1176,7 +1263,12 @@
1176
  VoiceEngine.recognition.onstart = () => {
1177
  AppState.isMicRecording = true;
1178
  document.getElementById('masterVoiceBtn').classList.add('active-listening');
 
 
 
 
1179
  if (AppState.isLiveModeEngaged) {
 
1180
  document.getElementById('liveMicBtn').classList.add('is-recording');
1181
  document.getElementById('liveStatusText').innerText = "Listening...";
1182
  document.getElementById('liveOrb').classList.remove('speaking');
@@ -1185,34 +1277,56 @@
1185
  };
1186
 
1187
  VoiceEngine.recognition.onresult = (event) => {
1188
- let finalTranscript = '';
1189
- let interimTranscript = '';
 
 
 
1190
 
1191
- for (let i = event.resultIndex; i < event.results.length; ++i) {
 
 
1192
  if (event.results[i].isFinal) {
1193
- finalTranscript += event.results[i][0].transcript;
1194
  } else {
1195
- interimTranscript += event.results[i][0].transcript;
1196
  }
1197
  }
1198
 
1199
- if (finalTranscript.trim().length > 0) {
1200
- let formattedText = finalTranscript.trim();
1201
- formattedText = formattedText.charAt(0).toUpperCase() + formattedText.slice(1);
1202
- if (!/[.!?।]$/.test(formattedText)) formattedText += '.';
 
 
 
 
 
 
1203
 
1204
- if (AppState.isLiveModeEngaged) {
1205
- document.getElementById('liveTranscriptText').innerText = `"${formattedText}"`;
1206
- document.getElementById('liveStatusText').innerText = "Synthesizing Response...";
1207
- document.getElementById('mainChatInput').value = formattedText;
1208
-
1209
- // Stop mic manually to trigger dispatch in Live Mode
1210
- VoiceEngine.recognition.stop();
1211
- ChatEngine.initiateDispatch();
 
 
 
 
 
 
 
 
 
 
 
 
 
1212
  } else {
1213
- const inputField = document.getElementById('mainChatInput');
1214
- inputField.value = (inputField.value + ' ' + formattedText + ' ').trim();
1215
- UIManager.autoGrowTextArea(inputField);
1216
  }
1217
  }
1218
  };
@@ -1220,20 +1334,31 @@
1220
  VoiceEngine.recognition.onend = () => {
1221
  AppState.isMicRecording = false;
1222
  document.getElementById('masterVoiceBtn').classList.remove('active-listening');
 
1223
 
1224
- if (AppState.isLiveModeEngaged && !AppState.isProcessing) {
1225
  document.getElementById('liveMicBtn').classList.remove('is-recording');
1226
- document.getElementById('liveStatusText').innerText = "Tap mic to interact";
1227
  document.getElementById('liveOrb').style.transform = "scale(1)";
 
 
 
 
 
 
 
 
 
1228
  }
1229
  };
1230
 
1231
  VoiceEngine.recognition.onerror = (event) => {
1232
  AppState.isMicRecording = false;
1233
- if(event.error !== 'no-speech') {
1234
- Utils.showToast("Voice module error: " + event.error);
1235
  }
1236
  document.getElementById('masterVoiceBtn').classList.remove('active-listening');
 
 
1237
  if (AppState.isLiveModeEngaged) {
1238
  document.getElementById('liveMicBtn').classList.remove('is-recording');
1239
  document.getElementById('liveStatusText').innerText = "Audio Failure. Retry.";
@@ -1249,25 +1374,26 @@
1249
  VoiceEngine.currentLanguage = 'hi-IN';
1250
  badge.innerText = 'हि';
1251
  btn.classList.add('hindi-active');
1252
- Utils.showToast("Listening Protocol: Hindi (देवनागरी)");
1253
  } else {
1254
  VoiceEngine.currentLanguage = 'en-IN';
1255
  badge.innerText = 'EN';
1256
  btn.classList.remove('hindi-active');
1257
- Utils.showToast("Listening Protocol: English");
1258
  }
1259
 
1260
  if (VoiceEngine.recognition) {
1261
  VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
1262
  if(AppState.isMicRecording) {
1263
  VoiceEngine.recognition.stop();
1264
- setTimeout(() => { VoiceEngine.recognition.start(); }, 400);
 
1265
  }
1266
  }
1267
  },
1268
 
1269
  toggleDictation: () => {
1270
- if (!VoiceEngine.recognition) return Utils.showToast("Hardware dictation unsupported.");
1271
  try {
1272
  if(AppState.isMicRecording) {
1273
  VoiceEngine.recognition.stop();
@@ -1277,13 +1403,12 @@
1277
  } catch (e) { console.error("Mic Start Error", e); }
1278
  },
1279
 
1280
- // ✨ GRADIO TTS INTEGRATION WITH SMART CLEANER
1281
  executeTTS: async (rawText) => {
1282
  // Apply smart text cleaner so AI doesn't read code or image links
1283
  const cleanSpeechText = Utils.cleanTextForVoice(rawText);
1284
 
1285
  if(!cleanSpeechText.trim()) {
1286
- Utils.showToast("No readable text found.");
1287
  return;
1288
  }
1289
 
@@ -1294,7 +1419,6 @@
1294
 
1295
  try {
1296
  if(!AppState.gradioClient) {
1297
- // Fallback dynamically import if not connected
1298
  const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
1299
  AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS");
1300
  }
@@ -1304,8 +1428,8 @@
1304
  voice_type: "प्रभात (भारी और प्राकृतिक आवाज़ - हिंग्लिश के लिए)"
1305
  });
1306
 
1307
- if (result.data && result.data[0]) {
1308
- const audioUrl = typeof result.data[0] === 'string' ? result.data[0] : result.data[0].url;
1309
  const audio = new Audio(audioUrl);
1310
 
1311
  audio.onended = () => {
@@ -1320,7 +1444,7 @@
1320
  throw new Error("No audio payload returned.");
1321
  }
1322
  } catch (error) {
1323
- Utils.showToast("Voice Neural Matrix is currently overloaded.");
1324
  console.error("Gradio TTS Error:", error);
1325
  if (AppState.isLiveModeEngaged) {
1326
  document.getElementById('liveOrb').classList.remove('speaking');
@@ -1339,7 +1463,7 @@
1339
  if (VoiceEngine.recognition && !AppState.isMicRecording) {
1340
  setTimeout(() => {
1341
  try { VoiceEngine.recognition.start(); } catch(e){}
1342
- }, 500);
1343
  }
1344
  },
1345
  terminate: () => {
@@ -1352,7 +1476,7 @@
1352
  };
1353
 
1354
  // =======================================================================================
1355
- // 6. FILE & DOCUMENT PROCESSOR (Non-Technical Vocabulary)
1356
  // =======================================================================================
1357
  const FileProcessor = {
1358
  triggerFileSelector: (type) => {
@@ -1361,17 +1485,25 @@
1361
  },
1362
 
1363
  processFile: async (inputElement, typeContext) => {
1364
- const file = inputElement.files[0];
1365
  if (!file) return;
1366
 
 
 
 
 
 
 
 
 
1367
  const fName = file.name.toLowerCase();
1368
  const mime = file.type;
1369
 
1370
- if (typeContext === 'image' && !mime.startsWith('image/')) { Utils.showToast("Visual media required."); inputElement.value=''; return; }
1371
- if (typeContext === 'video' && !mime.startsWith('video/')) { Utils.showToast("Video media required."); inputElement.value=''; return; }
1372
- if (typeContext === 'audio' && !mime.startsWith('audio/')) { Utils.showToast("Audio media required."); inputElement.value=''; return; }
1373
 
1374
- Utils.showToast(`Uploading your file...`);
1375
 
1376
  const thumbImg = document.getElementById('previewImgThumb');
1377
  const docIcon = document.getElementById('previewDocIcon');
@@ -1385,7 +1517,7 @@
1385
 
1386
  if (typeContext === 'image') {
1387
  fileReader.onload = (e) => {
1388
- AppState.pendingAttachment = { type: 'image', data: e.target.result.split(',')[1], name: file.name };
1389
  thumbImg.src = e.target.result;
1390
  thumbImg.style.display = 'flex';
1391
  };
@@ -1393,7 +1525,7 @@
1393
  }
1394
  else if (typeContext === 'video' || typeContext === 'audio') {
1395
  fileReader.onload = (e) => {
1396
- AppState.pendingAttachment = { type: typeContext, data: e.target.result.split(',')[1], name: file.name };
1397
  docIcon.innerText = typeContext === 'video' ? '🎥' : '🎵';
1398
  docIcon.style.display = 'flex';
1399
  };
@@ -1415,9 +1547,9 @@
1415
  extractedText += content.items.map(s => s.str).join(' ') + "\n";
1416
  }
1417
  AppState.pendingAttachment = { type: 'text', data: extractedText.trim() || "No readable text found.", name: file.name };
1418
- Utils.showToast("Your PDF is ready!");
1419
  } catch (e) {
1420
- Utils.showToast("PDF parsing encountered an error.");
1421
  FileProcessor.discardFile();
1422
  }
1423
  };
@@ -1429,9 +1561,9 @@
1429
  const buffer = this.result;
1430
  const resultData = await mammoth.extractRawText({ arrayBuffer: buffer });
1431
  AppState.pendingAttachment = { type: 'text', data: resultData.value.trim() || "No readable text found.", name: file.name };
1432
- Utils.showToast("Your Word document is ready!");
1433
  } catch(e) {
1434
- Utils.showToast("Document parsing encountered an error.");
1435
  FileProcessor.discardFile();
1436
  }
1437
  };
@@ -1440,7 +1572,7 @@
1440
  else {
1441
  fileReader.onload = (e) => {
1442
  AppState.pendingAttachment = { type: 'text', data: e.target.result, name: file.name };
1443
- Utils.showToast("Your file is ready!");
1444
  };
1445
  fileReader.readAsText(file);
1446
  }
@@ -1451,23 +1583,31 @@
1451
  discardFile: () => {
1452
  AppState.pendingAttachment = null;
1453
  document.getElementById('filePreviewBar').classList.remove('visible');
 
1454
  }
1455
  };
1456
 
1457
  // =======================================================================================
1458
- // 7. WORKSPACE ENGINE & MARKDOWN RENDERING
1459
  // =======================================================================================
1460
  const WorkspaceEngine = {
1461
  launch: (codeBlockId) => {
1462
  AppState.currentWorkspaceId = codeBlockId;
1463
  const codeData = AppState.generatedCodeBlocks[codeBlockId];
1464
 
1465
- document.getElementById('wsTitleText').innerText = codeData.lang ? `Generated ${codeData.lang.toUpperCase()}` : "Compiled Code";
1466
  const blockDisplay = document.getElementById('workspaceCodeBlock');
1467
  blockDisplay.className = `hljs language-${codeData.lang || 'plaintext'}`;
1468
  blockDisplay.textContent = codeData.code;
1469
 
1470
  hljs.highlightElement(blockDisplay);
 
 
 
 
 
 
 
1471
  document.getElementById('workspacePanel').classList.add('expanded');
1472
 
1473
  if (window.innerWidth <= 1024) {
@@ -1485,17 +1625,18 @@
1485
  }
1486
  };
1487
 
 
1488
  const MD_Renderer = new marked.Renderer();
1489
  MD_Renderer.code = function(token) {
1490
  const rawCode = typeof token === 'string' ? token : (token.text || '');
1491
- const langClass = typeof token === 'string' ? arguments[1] : (token.lang || '');
1492
 
1493
  if (AppState.isStreamingActive) {
1494
  return `
1495
  <div class="streaming-code-container">
1496
  <div class="streaming-code-header">
1497
  <div class="loading-ring"></div>
1498
- Generating Architecture...
1499
  </div>
1500
  <pre><code class="language-${langClass}">${Utils.escapeHTML(rawCode)}</code></pre>
1501
  </div>`;
@@ -1512,15 +1653,36 @@
1512
  </div>
1513
  <div class="ws-card-details">
1514
  <h4>Code Module Compiled</h4>
1515
- <p>${langClass || 'Syntax Detected'}</p>
1516
  </div>
1517
  </div>
1518
  <button class="btn-launch-workspace btn-launch-ws" data-id="${internalId}">Open Workspace</button>
1519
  </div>`;
1520
  };
1521
- marked.use({ renderer: MD_Renderer });
1522
 
1523
- // Event delegation for workspace buttons
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1524
  document.getElementById('msgs').addEventListener('click', function(e) {
1525
  if (e.target && e.target.classList.contains('btn-launch-ws')) {
1526
  const blockId = e.target.getAttribute('data-id');
@@ -1545,8 +1707,10 @@
1545
  },
1546
 
1547
  clearMemory: async () => {
 
 
1548
  if (AppState.currentUser) {
1549
- Utils.showToast("Purging neural link memory...");
1550
  try {
1551
  await fetch(Config.GAS_URL, {
1552
  method: 'POST',
@@ -1560,6 +1724,8 @@
1560
  },
1561
 
1562
  syncHistoryFromCloud: async () => {
 
 
1563
  const messageZone = document.getElementById('msgs');
1564
  document.getElementById('welcomeState').style.display = 'none';
1565
  messageZone.innerHTML = '<div style="text-align:center; padding:80px; font-weight:800; color:var(--brand-saffron); font-size:18px;">Decrypting Historic Archives...</div>';
@@ -1595,7 +1761,7 @@
1595
  },
1596
 
1597
  saveHistoryToCloud: () => {
1598
- if (AppState.currentUser) {
1599
  fetch(Config.GAS_URL, {
1600
  method: 'POST',
1601
  mode: 'cors',
@@ -1608,13 +1774,13 @@
1608
  buildPreviewHTML: (attachmentObj) => {
1609
  if (!attachmentObj) return '';
1610
  if (attachmentObj.type === 'image') {
1611
- return `<img src="data:image/jpeg;base64,${attachmentObj.data}" class="chat-in-bubble-img" alt="Attached Image">`;
1612
  } else if (attachmentObj.type === 'video') {
1613
- return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><polygon points="23 7 16 12 23 17 23 7"></polygon><rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect></svg></div><span class="name">${attachmentObj.name}</span></div>`;
1614
  } else if (attachmentObj.type === 'audio') {
1615
- return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18V5l12-2v13"></path><circle cx="6" cy="18" r="3"></circle><circle cx="18" cy="16" r="3"></circle></svg></div><span class="name">${attachmentObj.name}</span></div>`;
1616
  } else {
1617
- return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg></div><span class="name">${attachmentObj.name}</span></div>`;
1618
  }
1619
  },
1620
 
@@ -1624,7 +1790,7 @@
1624
  let visibleText = textContent;
1625
  if(textContent.includes('---DATA BEGIN---')) {
1626
  const parts = textContent.split('User Prompt:');
1627
- if(parts.length > 1) visibleText = parts[1].trim();
1628
  }
1629
 
1630
  const bubbleBox = document.createElement('div');
@@ -1669,7 +1835,7 @@
1669
  let actionTray = bubbleDOM.querySelector('.bot-actions-row');
1670
  if (!isCurrentlyStreaming && !actionTray && strippedMarkup.trim().length > 0) {
1671
  const safeRawCopy = strippedMarkup.replace(/"/g, '&quot;').replace(/'/g, "\\'").replace(/\n/g, '\\n').replace(/\r/g, '');
1672
- // safeRawTTS is passed as is, because the executeTTS function now handles the Smart Cleaning internally
1673
  const safeRawTTS = strippedMarkup.replace(/"/g, '&quot;').replace(/'/g, "\\'").replace(/\n/g, ' ');
1674
 
1675
  const actionsHTML = `
@@ -1691,6 +1857,7 @@
1691
  },
1692
 
1693
  initiateDispatch: async () => {
 
1694
  if (AppState.isProcessing) return;
1695
 
1696
  const inputField = document.getElementById('mainChatInput');
@@ -1702,14 +1869,14 @@
1702
  if (!AppState.currentUser) {
1703
  if (AppState.guestCount >= 3) {
1704
  AuthManager.openModal();
1705
- return Utils.showToast("Query limit reached. Secure Login required.");
1706
  }
1707
  AppState.guestCount++;
1708
  localStorage.setItem('arjun_guest', AppState.guestCount.toString());
1709
  document.getElementById('guestCountDisplay').innerText = AppState.guestCount;
1710
  }
1711
 
1712
- // Prepare UI
1713
  inputField.value = '';
1714
  inputField.style.height = 'auto';
1715
  document.getElementById('masterSendBtn').disabled = true;
@@ -1752,21 +1919,21 @@
1752
  const activeBotBubble = ChatEngine.renderBotMessage('', false);
1753
  UIManager.forceScrollDown();
1754
 
1755
- // 🎲 Dynamic Pollinations Generator
1756
  const cryptographicSeed = Math.floor(Math.random() * 999999999);
1757
 
1758
- // 🧠 Advanced Cognitive System Instructions
1759
- let cognitivePrompt = `You are Arjun 2.O, a sophisticated enterprise AI system architected by Abhay Kumar.
1760
- LANGUAGE REGULATION: Your default cognitive language is ENGLISH. If the user writes in English, reply in purely professional English. If the user writes in Hindi or Hinglish, reply gracefully in Hindi. Never force Hindi translation if the prompt is English.
1761
 
1762
  IMAGE SYNTHESIS OVERRIDE:
1763
  When commanded to render, generate, or create an image/photograph, you MUST reply with a precise markdown image node targeting Pollinations AI.
1764
  Formula: ![Generating Vision...](https://image.pollinations.ai/prompt/{URL_ENCODED_PROMPT_DETAIL}?width=1024&height=1024&nologo=true&model={MODEL}&seed=${cryptographicSeed})
1765
  Available Models: flux, flux-realism, flux-anime, flux-3d.
1766
- CRITICAL: The seed parameter is mandatory to bypass cache mechanics. Always render this markdown node.`;
1767
 
1768
  if (AppState.isLiveModeEngaged) {
1769
- cognitivePrompt += `\n\n[LIVE ACOUSTIC OVERRIDE]: You are currently engaged in a LIVE, REAL-TIME VOCAL INTERFACE.
1770
  MANDATORY direct answers. Maximum brevity. Eliminate complex markdown, massive code blocks, or extended lists. Replicate human telephonic brevity perfectly.`;
1771
  }
1772
 
@@ -1777,7 +1944,7 @@
1777
  attachments: payloadAttachments,
1778
  system_prompt: cognitivePrompt,
1779
  history: secureHistory,
1780
- max_tokens: AppState.isLiveModeEngaged ? 120 : 4096,
1781
  temperature: 0.75
1782
  };
1783
 
@@ -1811,8 +1978,8 @@
1811
 
1812
  try {
1813
  const jsonSegment = JSON.parse(parseableStr);
1814
- if (jsonSegment.choices && jsonSegment.choices[0].delta.content) {
1815
- responseBuffer += jsonSegment.choices[0].delta.content;
1816
  ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, true);
1817
  UIManager.autoScroll();
1818
  }
@@ -1849,14 +2016,12 @@
1849
  // 9. EVENT DELEGATION & BOOTSTRAP INVOCATION
1850
  // =======================================================================================
1851
 
1852
- // Define global function for welcome screen overlay
1853
  window.startArjunApp = function() {
1854
  document.getElementById('welcomeOverlay').classList.add('hidden');
1855
  localStorage.setItem('arjun_welcome_seen', 'true');
1856
  setTimeout(() => { document.getElementById('welcomeOverlay').style.display = 'none'; }, 400);
1857
  };
1858
 
1859
- // Bind all interactive elements safely using Event Listeners to avoid scope issues
1860
  document.addEventListener('DOMContentLoaded', () => {
1861
  // Sidebar Controls
1862
  document.getElementById('btnSidebarOpen').addEventListener('click', UIManager.toggleSidebar);
@@ -1918,6 +2083,10 @@
1918
  document.getElementById('msgs').addEventListener('scroll', UIManager.checkScrollState);
1919
  document.getElementById('scrollTriggerBtn').addEventListener('click', UIManager.forceScrollDown);
1920
 
 
 
 
 
1921
  // Prevent unwanted default mobile behaviours on double-tap
1922
  document.addEventListener('dblclick', function(event) {
1923
  event.preventDefault();
@@ -1931,6 +2100,7 @@
1931
  }
1932
 
1933
  // Fire Boot Processes
 
1934
  VoiceEngine.init();
1935
  AuthManager.initUI();
1936
  if(AppState.currentUser) { ChatEngine.syncHistoryFromCloud(); }
@@ -1939,4 +2109,3 @@
1939
  </script>
1940
  </body>
1941
  </html>
1942
-
 
1
+
2
  <!DOCTYPE html>
3
  <html lang="en" dir="ltr">
4
  <head>
 
12
  <title>Arjun 2.O - Professional Advanced AI</title>
13
 
14
  <!-- =========================================================================================
15
+ EXTERNAL RESOURCES, FONTS & LIBRARIES (बाहरी स्रोत)
16
  ========================================================================================= -->
17
  <link rel="preconnect" href="https://fonts.googleapis.com">
18
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
 
30
  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.1/marked.min.js"></script>
31
 
32
  <!-- =========================================================================================
33
+ MASSIVE ENTERPRISE CSS ARCHITECTURE (विस्तृत और उन्नत स्टाइलिंग)
34
  ========================================================================================= -->
35
  <style>
36
  /* ---------------------------------------------------------------------------------------
37
+ A. CSS VARIABLES, DESIGN TOKENS & BRANDING
38
  --------------------------------------------------------------------------------------- */
39
  :root {
40
+ /* Brand Identity: Saffron, White, Green (Tiranga Theme) */
41
  --brand-saffron: #FF9933;
42
  --brand-saffron-light: rgba(255, 153, 51, 0.12);
43
  --brand-saffron-dark: #e68a2e;
 
65
  --text-tertiary: #9ca3af;
66
  --text-inverse: #ffffff;
67
  --text-error: #ef4444;
68
+ --text-success: #10b981;
69
 
70
  /* Borders & Dividers */
71
  --border-light: rgba(0, 0, 0, 0.08);
72
  --border-medium: rgba(0, 0, 0, 0.15);
73
+ --border-focus: rgba(255, 153, 51, 0.5);
74
 
75
  /* Shadows & Elevation */
76
  --shadow-xs: 0 1px 2px rgba(0,0,0,0.04);
 
78
  --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.05), 0 2px 4px -1px rgba(0,0,0,0.03);
79
  --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025);
80
  --shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.05), 0 10px 10px -5px rgba(0,0,0,0.02);
81
+ --shadow-float: 0 25px 50px -12px rgba(0,0,0,0.15);
82
  --shadow-inner: inset 0 2px 4px rgba(0,0,0,0.06);
83
 
84
  /* Font Families */
 
99
  --ease-smooth: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
100
  --ease-spring: 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
101
 
102
+ /* Z-Indices - Properly Layered Enterprise System */
103
  --z-ambient: -1;
104
  --z-base: 1;
105
  --z-header: 10;
 
110
  --z-modal: 5000;
111
  --z-toast: 9000;
112
  --z-live: 9999;
113
+ --z-offline: 10000;
114
  }
115
 
116
  /* ---------------------------------------------------------------------------------------
 
120
  box-sizing: border-box;
121
  margin: 0;
122
  padding: 0;
 
123
  -webkit-tap-highlight-color: transparent !important;
124
  -webkit-touch-callout: none !important;
125
  }
 
138
  -moz-osx-font-smoothing: grayscale;
139
  }
140
 
141
+ /* Accessibilty focus states */
142
+ *:focus-visible { outline: 2px solid var(--brand-saffron); outline-offset: 2px; }
143
+ *:focus { outline: none; }
144
 
145
  button, input, textarea, select {
146
  font-family: inherit;
 
150
  }
151
 
152
  button { cursor: pointer; user-select: none; }
153
+ button:disabled { cursor: not-allowed; opacity: 0.6; }
154
  a { color: inherit; text-decoration: none; }
155
  img { max-width: 100%; height: auto; display: block; }
156
  svg { flex-shrink: 0; }
157
 
158
+ /* Custom Enterprise Scrollbars */
159
+ ::-webkit-scrollbar { width: 8px; height: 8px; }
160
  ::-webkit-scrollbar-track { background: transparent; }
161
+ ::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 10px; border: 2px solid transparent; background-clip: padding-box; transition: background var(--ease-smooth); }
162
+ ::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.3); border: 2px solid transparent; background-clip: padding-box; }
163
 
164
  /* ---------------------------------------------------------------------------------------
165
+ C. NETWORK OFFLINE & AMBIENT BACKGROUND SYSTEM
166
  --------------------------------------------------------------------------------------- */
167
+ .network-offline-banner {
168
+ position: fixed; top: 0; left: 0; right: 0; background: var(--text-error); color: white;
169
+ text-align: center; padding: 8px; font-size: 14px; font-weight: 700; z-index: var(--z-offline);
170
+ transform: translateY(-100%); transition: transform var(--ease-spring); display: flex; align-items: center; justify-content: center; gap: 8px; box-shadow: var(--shadow-md);
171
+ }
172
+ .network-offline-banner.active { transform: translateY(0); }
173
+
174
  .ambient-environment {
175
  position: fixed; inset: 0; z-index: var(--z-ambient); overflow: hidden; pointer-events: none;
176
  background: linear-gradient(135deg, var(--brand-saffron-light) 0%, var(--bg-primary) 50%, var(--brand-green-light) 100%);
 
197
  }
198
 
199
  /* ---------------------------------------------------------------------------------------
200
+ D. ENTERPRISE TOAST NOTIFICATION ENGINE
201
  --------------------------------------------------------------------------------------- */
202
  .toast-wrapper {
203
  position: absolute; top: 24px; left: 50%; transform: translateX(-50%);
204
  z-index: var(--z-toast); display: flex; flex-direction: column; gap: 12px;
205
+ pointer-events: none; width: 90%; max-width: 450px; align-items: center;
206
  }
207
  .toast-notification {
208
+ background: rgba(17, 24, 39, 0.95); color: var(--text-inverse); padding: 14px 24px;
209
  border-radius: var(--radius-full); font-size: 14px; font-weight: 600; box-shadow: var(--shadow-xl);
210
  animation: toastSlideIn var(--ease-spring) forwards, toastFadeOut 0.4s 3.5s forwards;
211
+ display: flex; align-items: center; gap: 12px; width: fit-content; max-width: 100%; word-break: break-word;
212
+ backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,0.1);
213
  }
214
+ .toast-notification.error { background: rgba(239, 68, 68, 0.95); border-color: rgba(255,255,255,0.2); }
215
+ .toast-notification.success { background: rgba(16, 185, 129, 0.95); border-color: rgba(255,255,255,0.2); }
216
+ .toast-notification svg { width: 20px; height: 20px; flex-shrink: 0; color: var(--brand-saffron); }
217
+ .toast-notification.error svg, .toast-notification.success svg { color: white; }
218
+
219
  @keyframes toastSlideIn { from { opacity: 0; transform: translateY(-30px) scale(0.9); } to { opacity: 1; transform: translateY(0) scale(1); } }
220
  @keyframes toastFadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } }
221
 
 
230
  }
231
  .startup-overlay.hidden { opacity: 0; visibility: hidden; pointer-events: none; }
232
 
233
+ .startup-logo-container { position: relative; margin-bottom: 32px; animation: popIn var(--ease-spring) 0.5s both; }
234
  .startup-logo-container img { width: 140px; height: 140px; border-radius: var(--radius-xl); object-fit: cover; box-shadow: var(--shadow-xl); border: 4px solid var(--bg-primary); position: relative; z-index: 2; }
235
  .startup-logo-glow { position: absolute; inset: -20px; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); filter: blur(30px); opacity: 0.4; border-radius: var(--radius-full); z-index: 1; animation: pulseGlow 3s infinite alternate; }
236
 
237
  @keyframes pulseGlow { from { opacity: 0.3; transform: scale(0.95); } to { opacity: 0.6; transform: scale(1.05); } }
238
+ @keyframes popIn { 0% { opacity: 0; transform: scale(0.8) translateY(20px); } 100% { opacity: 1; transform: scale(1) translateY(0); } }
239
 
240
+ .startup-title { font-family: var(--font-sans); font-size: 2.8rem; font-weight: 900; color: var(--text-primary); letter-spacing: -1px; margin-bottom: 16px; animation: slideUp var(--ease-smooth) 0.6s both; }
241
+ .startup-desc { font-size: 1.15rem; color: var(--text-secondary); line-height: 1.6; max-width: 600px; margin-bottom: 40px; animation: slideUp var(--ease-smooth) 0.7s both; font-weight: 500; }
242
 
243
+ .btn-startup-launch { padding: 18px 48px; background: var(--text-primary); color: var(--text-inverse); border: none; border-radius: var(--radius-xl); font-size: 1.125rem; font-weight: 700; cursor: pointer; transition: var(--ease-spring); box-shadow: 0 10px 25px rgba(0,0,0,0.15); animation: slideUp var(--ease-smooth) 0.8s both; display: flex; align-items: center; gap: 12px; position: relative; overflow: hidden; }
244
  .btn-startup-launch::before { content: ''; position: absolute; top: 0; left: -100%; width: 50%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); transform: skewX(-20deg); transition: 0.5s; }
245
  .btn-startup-launch:hover { background: #000000; transform: translateY(-4px) scale(1.02); box-shadow: 0 15px 35px rgba(0,0,0,0.25); }
246
  .btn-startup-launch:hover::before { left: 150%; }
247
 
248
+ @keyframes slideUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
249
 
250
  /* ---------------------------------------------------------------------------------------
251
  F. CORE APPLICATION LAYOUT & SIDEBAR
 
257
  .sidebar-header { padding: 28px 24px; border-bottom: 1px solid var(--border-light); display: flex; justify-content: space-between; align-items: center; }
258
 
259
  .brand-identity { display: flex; align-items: center; gap: 14px; text-decoration: none; }
260
+ .brand-identity img { width: 48px; height: 48px; border-radius: var(--radius-md); object-fit: cover; box-shadow: var(--shadow-sm); border: 2px solid var(--bg-primary); transition: transform var(--ease-spring); }
261
+ .brand-identity:hover img { transform: scale(1.08) rotate(-5deg); box-shadow: var(--shadow-md); }
262
  .brand-typography { display: flex; flex-direction: column; }
263
  .brand-name { font-family: var(--font-sans); font-weight: 900; font-size: 20px; color: var(--text-primary); letter-spacing: -0.5px; line-height: 1.1; }
264
+ .brand-edition { font-size: 11px; font-weight: 800; letter-spacing: 1.5px; text-transform: uppercase; background: linear-gradient(90deg, var(--brand-saffron-dark), var(--brand-green-dark)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-top: 4px; }
265
 
266
  .btn-mobile-close { display: none; background: rgba(0,0,0,0.05); border: none; width: 36px; height: 36px; border-radius: 50%; color: var(--text-primary); cursor: pointer; align-items: center; justify-content: center; transition: var(--ease-fast); }
267
  .btn-mobile-close:hover { background: rgba(239, 68, 68, 0.15); color: var(--text-error); transform: rotate(90deg); }
 
280
  .user-details { flex: 1; overflow: hidden; }
281
  .user-email-id { font-size: 14px; font-weight: 700; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
282
  .user-clearance-level { font-size: 11px; color: var(--brand-green); font-weight: 600; margin-top: 2px; display: flex; align-items: center; gap: 4px; }
283
+ .user-clearance-level::before { content: ''; display: block; width: 6px; height: 6px; border-radius: 50%; background: var(--brand-green); box-shadow: 0 0 5px var(--brand-green-glow); }
284
  .btn-system-logout { background: rgba(239, 68, 68, 0.08); color: var(--text-error); border: none; width: 38px; height: 38px; border-radius: var(--radius-md); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--ease-fast); }
285
  .btn-system-logout:hover { background: var(--text-error); color: #ffffff; transform: scale(1.05); }
286
 
 
301
  --------------------------------------------------------------------------------------- */
302
  .main-chat-wrapper { flex: 1; display: flex; flex-direction: column; position: relative; min-width: 320px; transition: width var(--ease-smooth); background: transparent; }
303
 
304
+ .chat-top-bar { padding: 16px 32px; border-bottom: 1px solid var(--border-light); background: rgba(255, 255, 255, 0.85); backdrop-filter: blur(15px); display: flex; align-items: center; justify-content: space-between; z-index: var(--z-header); }
305
  .top-bar-left { display: flex; align-items: center; gap: 16px; }
306
  .btn-hamburger { display: none; background: var(--bg-primary); border: 1px solid var(--border-light); cursor: pointer; color: var(--text-primary); width: 42px; height: 42px; border-radius: var(--radius-sm); align-items: center; justify-content: center; box-shadow: var(--shadow-sm); transition: var(--ease-fast); }
307
  .btn-hamburger:hover { background: var(--bg-secondary); }
308
 
309
+ .system-status-pill { display: flex; align-items: center; gap: 10px; font-size: 14px; font-weight: 700; color: var(--text-primary); padding: 8px 18px; background: var(--bg-secondary); border-radius: var(--radius-full); border: 1px solid var(--border-light); transition: var(--ease-smooth); }
310
+ .pulse-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--brand-green); box-shadow: 0 0 0 3px rgba(19, 136, 8, 0.2); animation: statusPulse 2s infinite; transition: background var(--ease-smooth); }
311
+ .system-status-pill.offline .pulse-dot { background: var(--text-error); box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2); animation: none; }
312
  @keyframes statusPulse { 0% { box-shadow: 0 0 0 0 rgba(19,136,8,0.4); } 70% { box-shadow: 0 0 0 6px rgba(19,136,8,0); } 100% { box-shadow: 0 0 0 0 rgba(19,136,8,0); } }
313
 
314
  /* DYNAMIC LIVE MODE ACTIVATOR */
 
326
  .hero-avatar-wrapper img { width: 100px; height: 100px; border-radius: var(--radius-xl); object-fit: cover; box-shadow: var(--shadow-xl); border: 3px solid var(--bg-primary); position: relative; z-index: 2; }
327
  .hero-avatar-glow { position: absolute; inset: -12px; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); filter: blur(25px); opacity: 0.35; border-radius: 40px; z-index: 1; animation: rotateGlow 10s linear infinite;}
328
  @keyframes rotateGlow { 100% { transform: rotate(360deg); } }
329
+ @keyframes slideUpFade { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
330
 
331
+ .hero-greeting { font-size: 42px; font-weight: 900; letter-spacing: -1.5px; margin-bottom: 18px; color: var(--text-primary); line-height: 1.2; }
332
  .hero-description { font-size: 17px; color: var(--text-secondary); line-height: 1.6; margin-bottom: 40px; font-weight: 500; }
333
 
334
+ /* GUEST BADGE LIMIT DISPLAY */
335
  .guest-warning-badge { font-size: 13px; font-weight: 700; color: var(--text-error); background: #fee2e2; padding: 10px 20px; border-radius: var(--radius-full); margin-bottom: 32px; display: none; align-items: center; gap: 8px; border: 1px solid #fca5a5; box-shadow: var(--shadow-sm); }
336
  .guest-warning-badge svg { width: 18px; height: 18px; }
337
 
 
347
  /* ---------------------------------------------------------------------------------------
348
  H. CHAT MESSAGE BUBBLES & PREVIEWS
349
  --------------------------------------------------------------------------------------- */
350
+ .chat-message-row { display: flex; gap: 20px; max-width: 88%; animation: messagePopIn 0.4s var(--ease-spring) both; }
351
+ @keyframes messagePopIn { from { opacity: 0; transform: translateY(20px) scale(0.97); } to { opacity: 1; transform: none; } }
352
  .chat-message-row.user-msg { flex-direction: row-reverse; align-self: flex-end; }
353
  .chat-message-row.bot-msg { align-self: flex-start; }
354
 
 
364
  .file-badge svg { width: 12px; height: 12px; }
365
 
366
  /* In-Bubble File Previews */
367
+ .chat-in-bubble-img { max-width: 320px; max-height: 320px; border-radius: var(--radius-md); object-fit: cover; border: 2px solid rgba(255,255,255,0.2); box-shadow: var(--shadow-md); margin-bottom: 12px; transition: transform var(--ease-smooth); cursor: zoom-in; }
368
+ .chat-in-bubble-img:hover { transform: scale(1.02); }
369
  .chat-file-card { display: flex; align-items: center; gap: 14px; background: rgba(255,255,255,0.15); border: 1px solid rgba(255,255,255,0.3); padding: 12px 18px; border-radius: var(--radius-md); margin-bottom: 12px; max-width: 350px; backdrop-filter: blur(10px); }
370
  .chat-file-card .icon { font-size: 24px; background: rgba(0,0,0,0.1); width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-sm); }
371
  .chat-file-card .name { font-size: 14px; font-weight: 600; color: var(--brand-white); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
 
385
  .btn-bot-action.action-tts { color: var(--brand-green-dark); border-color: rgba(19, 136, 8, 0.25); background: var(--brand-green-light); }
386
  .btn-bot-action.action-tts:hover { background: rgba(19, 136, 8, 0.2); }
387
 
388
+ /* Markdown Formatting inside Bubbles */
389
  .chat-bubble p { margin-bottom: 16px; }
390
  .chat-bubble p:last-child { margin-bottom: 0; }
391
  .chat-bubble strong { font-weight: 800; color: inherit; }
392
+ .chat-bubble em { font-style: italic; }
393
+ .chat-bubble ul, .chat-bubble ol { margin-bottom: 16px; padding-left: 24px; }
394
+ .chat-bubble li { margin-bottom: 6px; }
395
+ .chat-bubble blockquote { border-left: 4px solid var(--brand-saffron); padding-left: 16px; margin: 16px 0; color: var(--text-secondary); background: var(--bg-secondary); padding: 12px 16px; border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
396
+
397
+ /* Advanced Tables */
398
+ .chat-bubble table { width: 100%; border-collapse: collapse; margin: 20px 0; border-radius: var(--radius-sm); overflow: hidden; box-shadow: var(--shadow-sm); }
399
+ .chat-bubble th, .chat-bubble td { border: 1px solid var(--border-light); padding: 12px 16px; text-align: left; }
400
+ .chat-bubble th { background: var(--bg-secondary); font-weight: 700; color: var(--text-primary); }
401
+ .chat-bubble tr:nth-child(even) { background: var(--bg-tertiary); }
402
+
403
  .chat-bubble code { font-family: var(--font-mono); background: rgba(0,0,0,0.06); padding: 4px 8px; border-radius: 6px; font-size: 0.85em; color: #d946ef; font-weight: 600; border: 1px solid rgba(0,0,0,0.05); }
404
  .user-msg .chat-bubble code { background: rgba(255,255,255,0.2); color: var(--brand-white); border-color: rgba(255,255,255,0.1); }
405
+
406
  .chat-bubble img { max-width: 100%; border-radius: var(--radius-md); margin: 16px 0; box-shadow: var(--shadow-lg); border: 1px solid var(--border-light); display: block; }
407
+
408
+ /* Custom Pre-Code Blocks */
409
+ .chat-bubble pre { background: #1e1e2e; color: #a6adc8; padding: 0; border-radius: var(--radius-md); overflow: hidden; margin: 20px 0; font-family: var(--font-mono); font-size: 14px; line-height: 1.6; border: 1px solid #313244; box-shadow: var(--shadow-md); }
410
+ .chat-bubble pre code { background: transparent; color: inherit; padding: 20px; font-weight: 400; border: none; display: block; overflow-x: auto; }
411
 
412
  /* Streaming Loading UI Component */
413
  .streaming-code-container { background: #1e1e2e; border-radius: var(--radius-md); border: 1px solid #313244; overflow: hidden; margin: 20px 0; box-shadow: var(--shadow-lg); }
 
431
  I. BOTTOM INPUT DOCK & TOOLS
432
  --------------------------------------------------------------------------------------- */
433
  .input-dock { flex-shrink: 0; padding: 0 40px 32px; background: transparent; position: relative; z-index: var(--z-dock); }
434
+ .input-master-container { display: flex; flex-direction: column; background: var(--bg-glass); backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px); border: 1px solid var(--border-light); border-radius: var(--radius-xl); box-shadow: var(--shadow-xl); transition: var(--ease-smooth); position: relative; }
435
  .input-master-container:focus-within { border-color: var(--brand-saffron); box-shadow: 0 20px 40px -5px rgba(255,153,51,0.15), 0 0 0 4px var(--brand-saffron-light); }
436
 
437
+ /* Upload Preview Header */
438
+ .upload-preview-bar { display: none; padding: 20px 28px 0; align-items: center; gap: 16px; border-bottom: 1px solid transparent; }
439
+ .upload-preview-bar.visible { display: flex; animation: fadeIn 0.3s ease; border-bottom-color: var(--border-light); padding-bottom: 15px; }
440
  .upload-thumb { width: 52px; height: 52px; object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--border-light); display: flex; justify-content: center; align-items: center; background: var(--bg-tertiary); font-size: 24px; box-shadow: var(--shadow-sm); }
441
  .upload-meta { flex: 1; }
442
  .upload-filename { font-size: 14px; font-weight: 700; color: var(--text-primary); max-width: 250px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
 
451
  .main-textarea { flex: 1; border: none; outline: none; background: transparent; font-family: var(--font-sans); font-size: 16px; color: var(--text-primary); line-height: 1.5; resize: none; max-height: 200px; min-height: 24px; padding: 12px 0; margin: 0 8px; font-weight: 500; }
452
  .main-textarea::placeholder { color: var(--text-tertiary); font-weight: 400; }
453
 
454
+ /* Real-time Interim Text Feedback */
455
+ .interim-text-overlay { position: absolute; pointer-events: none; color: var(--text-tertiary); font-style: italic; z-index: 2; padding: 12px 0; margin: 0 8px; left: 140px; top: 14px; right: 80px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; display: none; }
456
+ .interim-text-overlay.active { display: block; }
457
+
458
  /* Attachment Menu Dropdown */
459
  .attachment-module { position: relative; }
460
+ .btn-tool-icon { width: 44px; height: 44px; border-radius: var(--radius-md); background: transparent; border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-secondary); transition: var(--ease-fast); position: relative; }
461
  .btn-tool-icon:hover { background: var(--bg-tertiary); color: var(--text-primary); }
462
  .btn-tool-icon svg { width: 24px; height: 24px; stroke-width: 2; }
463
 
 
475
  .language-toggle-chip.hindi-active { background: var(--brand-green-light); color: var(--brand-green-dark); border-color: var(--brand-green); }
476
  .language-toggle-chip svg { width: 16px; height: 16px; }
477
 
478
+ .btn-mic-tool { position: relative; }
479
+ .btn-mic-tool.active-listening { color: #ffffff; background: var(--text-error); border-radius: var(--radius-full); }
480
+ .btn-mic-tool.active-listening::before { content: ''; position: absolute; inset: -4px; border-radius: 50%; border: 2px solid var(--text-error); animation: rippleMic 1.5s infinite ease-out; }
481
+ @keyframes rippleMic { 0% { transform: scale(0.8); opacity: 1; } 100% { transform: scale(1.5); opacity: 0; } }
482
 
483
  /* Master Send Button */
484
+ .btn-master-send { width: 48px; height: 48px; border-radius: 16px; border: none; background: linear-gradient(135deg, var(--brand-saffron) 0%, var(--brand-green) 100%); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--ease-spring); box-shadow: 0 6px 20px rgba(19, 136, 8, 0.25); position: relative; overflow: hidden; }
485
+ .btn-master-send::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent); transition: 0.5s; }
486
+ .btn-master-send svg { width: 20px; height: 20px; fill: white; transition: transform 0.2s; position: relative; z-index: 2; }
487
  .btn-master-send:hover { transform: translateY(-3px); box-shadow: 0 10px 25px rgba(255, 153, 51, 0.4); }
488
+ .btn-master-send:hover::before { left: 100%; }
489
  .btn-master-send:hover svg { transform: translate(2px, -2px); }
490
+ .btn-master-send:disabled { opacity: 0.5; cursor: not-allowed; filter: grayscale(100%); transform: none; box-shadow: none; }
491
 
492
  .bottom-branding-text { text-align: center; font-size: 12px; color: var(--text-tertiary); margin-top: 16px; font-weight: 600; letter-spacing: 0.5px; }
493
 
 
508
  .btn-workspace-tool.close:hover { color: #e06c75; background: rgba(224, 108, 117, 0.1); }
509
 
510
  .workspace-editor-surface { flex: 1; overflow-y: auto; background: #282c34; padding: 24px; position: relative; }
511
+
512
+ /* Line Numbers Implementation for Workspace */
513
+ .workspace-editor-content { display: flex; font-family: var(--font-mono); font-size: 14px; line-height: 1.6; }
514
+ .workspace-line-numbers { padding-right: 15px; border-right: 1px solid #3e4451; color: #5c6370; text-align: right; user-select: none; }
515
+ .workspace-editor-surface pre { margin: 0; padding: 0 0 0 15px; background: transparent; overflow-x: auto; color: #abb2bf; border: none; box-shadow: none; flex: 1; }
516
 
517
  /* ---------------------------------------------------------------------------------------
518
  K. LIVE MODE FULLSCREEN OVERLAY
519
  --------------------------------------------------------------------------------------- */
520
+ .live-mode-viewport { position: fixed; inset: 0; background: rgba(255, 255, 255, 0.98); z-index: var(--z-live); display: flex; flex-direction: column; align-items: center; justify-content: center; opacity: 0; pointer-events: none; transition: opacity var(--ease-smooth); backdrop-filter: blur(20px); }
521
  .live-mode-viewport.active { opacity: 1; pointer-events: auto; }
522
  .btn-close-live { position: absolute; top: 40px; right: 40px; background: rgba(0,0,0,0.04); border: none; width: 56px; height: 56px; border-radius: 50%; font-size: 24px; cursor: pointer; transition: var(--ease-spring); display: flex; align-items: center; justify-content: center; color: var(--text-secondary); }
523
  .btn-close-live:hover { background: rgba(239, 68, 68, 0.15); color: var(--text-error); transform: rotate(90deg); }
 
525
  .pulsing-orb-wrapper { position: relative; width: 250px; height: 250px; display: flex; align-items: center; justify-content: center; margin-bottom: 50px; }
526
  .energy-core { width: 120px; height: 120px; border-radius: 50%; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); box-shadow: 0 0 50px rgba(19, 136, 8, 0.5); position: relative; z-index: 2; transition: transform 0.15s ease-out; }
527
  .energy-core.speaking { animation: coreSpeak 0.5s infinite alternate; }
528
+ @keyframes coreSpeak { 0% { transform: scale(1); box-shadow: 0 0 30px rgba(19,136,8,0.4); } 100% { transform: scale(1.2); box-shadow: 0 0 80px rgba(255,153,51,0.7); } }
529
 
530
  .energy-ring { position: absolute; inset: 0; border: 3px solid var(--brand-saffron); border-radius: 50%; opacity: 0; animation: energyRipple 2.5s cubic-bezier(0.4, 0, 0.2, 1) infinite; }
531
  .energy-ring:nth-child(2) { animation-delay: 0.8s; border-color: var(--brand-green); }
532
  .energy-ring:nth-child(3) { animation-delay: 1.6s; border-color: var(--text-primary); }
533
  @keyframes energyRipple { 0% { transform: scale(0.4); opacity: 1; border-width: 6px; } 100% { transform: scale(1.6); opacity: 0; border-width: 1px; } }
534
 
535
+ .live-feedback-status { font-size: 28px; font-weight: 900; color: var(--text-primary); margin-bottom: 16px; font-family: var(--font-sans); letter-spacing: -0.5px; transition: color var(--ease-fast); }
536
+ .live-feedback-text { font-size: 18px; color: var(--text-secondary); max-width: 700px; text-align: center; line-height: 1.6; min-height: 60px; font-weight: 500; padding: 0 20px; transition: opacity var(--ease-smooth); }
537
 
538
  .live-control-deck { display: flex; gap: 24px; margin-top: 50px; }
539
  .btn-live-deck { width: 80px; height: 80px; border-radius: 50%; border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: var(--shadow-lg); transition: var(--ease-spring); }
540
  .btn-live-deck.mic-control { background: var(--bg-primary); border: 3px solid var(--border-light); color: var(--text-primary); }
541
  .btn-live-deck.mic-control:hover { transform: translateY(-6px); border-color: var(--brand-saffron); color: var(--brand-saffron); box-shadow: var(--shadow-xl); }
542
  .btn-live-deck.mic-control.is-recording { background: var(--text-error); color: white; border-color: var(--text-error); animation: pulseMicLive 1.2s infinite; }
543
+ @keyframes pulseMicLive { 0% { box-shadow: 0 0 0 0 rgba(239,68,68,0.6); } 70% { box-shadow: 0 0 0 25px rgba(239,68,68,0); } 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); } }
544
 
545
  /* Scroll Trigger Button */
546
  .btn-scroll-trigger { position: absolute; bottom: 150px; left: 50%; width: 48px; height: 48px; border-radius: 50%; background: var(--bg-glass); backdrop-filter: blur(15px); border: 1px solid var(--border-light); box-shadow: var(--shadow-lg); display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-secondary); opacity: 0; pointer-events: none; transform: translateX(-50%) translateY(20px); transition: var(--ease-smooth); z-index: 20; }
 
553
  .secure-modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.5); backdrop-filter: blur(10px); z-index: var(--z-modal); display: none; justify-content: center; align-items: center; animation: fadeIn 0.3s ease; }
554
  .secure-modal-surface { background: var(--bg-primary); padding: 44px; border-radius: var(--radius-xl); width: 90%; max-width: 460px; box-shadow: var(--shadow-xl); position: relative; border: 1px solid rgba(255,255,255,0.4); }
555
  .btn-modal-dismiss { position: absolute; top: 24px; right: 24px; background: var(--bg-secondary); border: none; width: 36px; height: 36px; border-radius: 50%; font-size: 18px; color: var(--text-secondary); cursor: pointer; transition: 0.2s; display: flex; align-items: center; justify-content: center; }
556
+ .btn-modal-dismiss:hover { background: #fee2e2; color: var(--text-error); transform: rotate(90deg); }
557
  .modal-brand-header { text-align: center; margin-bottom: 36px; font-family: var(--font-sans); font-size: 28px; font-weight: 900; color: var(--text-primary); letter-spacing: -0.5px; }
558
 
559
  .auth-tab-switch { display: flex; background: var(--bg-secondary); padding: 6px; border-radius: var(--radius-md); margin-bottom: 28px; }
 
607
 
608
  .input-tools-row { flex-wrap: wrap; }
609
  .main-textarea { min-width: 100%; order: -1; margin-bottom: 10px; }
610
+ .interim-text-overlay { left: 15px; top: 12px; }
611
  }
612
  </style>
613
  </head>
614
  <body>
615
 
616
+ <!-- =========================================================================================
617
+ DOM STRUCTURE: OFFLINE BANNER
618
+ ========================================================================================= -->
619
+ <div id="networkStatusBanner" class="network-offline-banner">
620
+ <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
621
+ System Offline. Please check your internet connection.
622
+ </div>
623
+
624
  <!-- =========================================================================================
625
  DOM STRUCTURE: NOTIFICATIONS
626
  ========================================================================================= -->
 
687
  <img src="https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png" alt="Arjun Logo">
688
  <div class="brand-typography">
689
  <span class="brand-name">ARJUN 2.O</span>
690
+ <span class="brand-edition">Enterprise</span>
691
  </div>
692
  </a>
693
  <button class="btn-mobile-close" id="btnSidebarClose">
 
725
  <!-- Wipe Memory Button -->
726
  <button class="btn-erase-memory" id="btnClearMemory">
727
  <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>
728
+ Wipe Neural Context
729
  </button>
730
  </div>
731
  </aside>
 
739
  <button class="btn-hamburger" id="btnSidebarOpen">
740
  <svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2.5" fill="none"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
741
  </button>
742
+ <div class="system-status-pill" id="mainStatusPill">
743
  <div class="pulse-dot"></div>
744
+ <span id="mainStatusText">System Online</span>
745
  </div>
746
  </div>
747
 
 
796
 
797
  <!-- File Preview Component -->
798
  <div class="upload-preview-bar" id="filePreviewBar">
799
+ <img class="upload-thumb" id="previewImgThumb" src="" alt="Thumbnail" style="display:none;">
800
  <div class="upload-thumb" id="previewDocIcon" style="display:none;">📄</div>
801
  <div class="upload-meta">
802
  <div class="upload-filename" id="previewFileName">document.pdf</div>
 
805
  File ready to be transmitted
806
  </div>
807
  </div>
808
+ <button class="btn-discard-upload" id="btnDiscardFile" title="Remove Attachment">
809
  <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
810
  </button>
811
  </div>
 
857
  </button>
858
 
859
  <!-- Expanding Text Area -->
860
+ <div style="flex:1; position: relative;">
861
+ <!-- STT Interim Feedback Overlay -->
862
+ <div id="interimTextOverlay" class="interim-text-overlay"></div>
863
+ <textarea class="main-textarea" id="mainChatInput" placeholder="Message Arjun Intelligence..." rows="1" style="width: 100%;"></textarea>
864
+ </div>
865
 
866
  <!-- Master Send Button -->
867
  <button class="btn-master-send" id="masterSendBtn">
 
891
  </div>
892
  </div>
893
  <div class="workspace-editor-surface">
894
+ <div class="workspace-editor-content">
895
+ <div class="workspace-line-numbers" id="wsLineNumbers">1</div>
896
+ <pre><code id="workspaceCodeBlock" class="hljs"></code></pre>
897
+ </div>
898
  </div>
899
  </aside>
900
  </div>
 
944
  </div>
945
 
946
  <!-- =========================================================================================
947
+ MASSIVE ENTERPRISE JAVASCRIPT ARCHITECTURE
948
  ========================================================================================= -->
 
 
 
949
  <script>
950
  // =======================================================================================
951
  // 1. CONFIGURATION & STATE MANAGEMENT
 
955
  LOGO_URL: "https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png",
956
  PDF_WORKER: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js',
957
  API_ENDPOINT: '/api/chat', // Uses relative path to connect to Flask App.py
958
+ MAX_FILE_SIZE_MB: 10, // Prevent UI freeze on giant files
959
  };
960
 
961
  // Initialize PDF worker
 
973
  isStreamingActive: false,
974
  isLiveModeEngaged: false,
975
  gradioClient: null,
976
+ isMicRecording: false,
977
+ isOnline: navigator.onLine
978
  };
979
 
980
+ // Initialize Gradio Client Dynamically for TTS
981
  window.initGradioEngine = async function() {
982
  try {
983
  const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
984
  AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS");
985
  console.log("Neural TTS Engine connected successfully to Gradio.");
986
  } catch(err) {
987
+ console.warn("Gradio Connection Warning:", err.message);
988
+ // Non-blocking failure, app still works
989
  }
990
  };
991
  window.initGradioEngine();
 
994
  // 2. UTILITY ENGINE (Robust Copy, Notifications, and Text Cleaners)
995
  // =======================================================================================
996
  const Utils = {
997
+ showToast: (message, type = 'info') => {
998
  const container = document.getElementById('toast-container');
999
  const toast = document.createElement('div');
1000
+ toast.className = `toast-notification ${type}`;
1001
+
1002
+ let icon = '<polyline points="20 6 9 17 4 12"></polyline>'; // Checkmark
1003
+ if (type === 'error') icon = '<line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line>';
1004
+
1005
+ toast.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">${icon}</svg> ${message}`;
1006
  container.appendChild(toast);
1007
+ setTimeout(() => { if (toast.parentNode) toast.remove(); }, 3500);
1008
  },
1009
 
1010
  escapeHTML: (str) => {
1011
+ if (!str) return '';
1012
  return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
1013
  },
1014
 
1015
+ // ✨ Intelligent Text Cleaner for TTS (Ignores code, links, images)
1016
  cleanTextForVoice: (rawText) => {
1017
  if(!rawText) return "";
1018
  let cleaned = rawText;
1019
 
1020
+ // Remove Markdown Elements sequentially to prevent regex conflicts
1021
+ cleaned = cleaned.replace(/```[\s\S]*?```/g, ''); // Code blocks
1022
+ cleaned = cleaned.replace(/`.*?`/g, ''); // Inline code
1023
+ cleaned = cleaned.replace(/!\[.*?\]\(.*?\)/g, ''); // Images
1024
+ cleaned = cleaned.replace(/\[(.*?)\]\(.*?\)/g, '$1'); // Links
1025
+ cleaned = cleaned.replace(/<think>[\s\S]*?<\/think>/gi, ''); // Think Tags
1026
+ cleaned = cleaned.replace(/https?:\/\/[^\s]+/g, ''); // Bare URLs
1027
+ cleaned = cleaned.replace(/[*_~#|-]/g, ''); // Formatting symbols
 
 
 
 
 
 
1028
 
1029
  return cleaned.trim();
1030
  },
 
1034
  const textArea = document.createElement("textarea");
1035
  textArea.value = text;
1036
  textArea.style.top = "0"; textArea.style.left = "0"; textArea.style.position = "fixed";
1037
+ textArea.style.opacity = "0";
1038
  document.body.appendChild(textArea);
1039
  textArea.focus(); textArea.select();
1040
 
 
1042
  const successful = document.execCommand('copy');
1043
  if (successful) {
1044
  const originalHTML = btnElement.innerHTML;
1045
+ btnElement.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> Copied Data`;
1046
  setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
1047
  } else {
1048
+ Utils.showToast("Clipboard access denied by browser.", "error");
1049
  }
1050
  } catch (err) {
1051
+ Utils.showToast("System error copying text.", "error");
1052
  }
1053
  document.body.removeChild(textArea);
1054
  },
 
1060
  }
1061
  navigator.clipboard.writeText(textToCopy).then(() => {
1062
  const originalHTML = btnElement.innerHTML;
1063
+ btnElement.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> Copied Data`;
1064
  setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
1065
  }).catch((err) => {
1066
  console.warn('Modern API failed, utilizing fallback...', err);
 
1070
  };
1071
 
1072
  // =======================================================================================
1073
+ // 3. AUTHENTICATION & SYNC MANAGER
1074
  // =======================================================================================
1075
  const AuthManager = {
1076
  initUI: () => {
 
1109
  document.getElementById(nextId).classList.add('active');
1110
  },
1111
 
 
1112
  process: async (actionType) => {
1113
+ if (!AppState.isOnline) return Utils.showToast("System is offline. Cannot authenticate.", "error");
1114
+
1115
  const payload = { action: actionType };
1116
  let buttonId = '';
1117
 
 
1119
  payload.name = document.getElementById('authRegName').value.trim();
1120
  payload.email = document.getElementById('authRegEmail').value.trim();
1121
  payload.phone = "0000000000"; payload.organization = "Arjun Base";
1122
+ if (!payload.email || !payload.name) return Utils.showToast("Identification details required.", "error");
1123
  buttonId = 'btn-fire-reg-otp';
1124
  }
1125
  else if (actionType === 'login_send_otp') {
1126
  payload.email = document.getElementById('authLogEmail').value.trim();
1127
+ if (!payload.email) return Utils.showToast("Email required for validation.", "error");
1128
  buttonId = 'btn-fire-log-otp';
1129
  }
1130
  else if (actionType === 'register_verify' || actionType === 'login_verify') {
1131
  payload.email = document.getElementById(actionType === 'register_verify' ? 'authRegEmail' : 'authLogEmail').value.trim();
1132
  payload.otp = document.getElementById(actionType === 'register_verify' ? 'authRegOTP' : 'authLogOTP').value.trim();
1133
+ if (!payload.otp) return Utils.showToast("Security token required.", "error");
1134
  buttonId = actionType === 'register_verify' ? 'btn-fire-reg-verify' : 'btn-fire-log-verify';
1135
  }
1136
 
 
1140
  triggerBtn.innerText = 'Establishing Connection...';
1141
 
1142
  try {
 
1143
  const response = await fetch(Config.GAS_URL, {
1144
  method: 'POST',
1145
  mode: 'cors',
 
1150
  const result = await response.json();
1151
 
1152
  if (result.status === 'success') {
1153
+ Utils.showToast(result.message, "success");
1154
  if (actionType === 'register_send_otp') AuthManager.switchPhase('auth-reg-phase-1', 'auth-reg-phase-2');
1155
  else if (actionType === 'login_send_otp') AuthManager.switchPhase('auth-log-phase-1', 'auth-log-phase-2');
1156
  else if (actionType === 'register_verify' || actionType === 'login_verify') {
 
1161
  ChatEngine.syncHistoryFromCloud();
1162
  }
1163
  } else {
1164
+ Utils.showToast(result.message, "error");
1165
  }
1166
  } catch (error) {
1167
  console.error("Auth Network Error: ", error);
1168
+ Utils.showToast("Encrypted gateway error. Check network.", "error");
1169
  }
1170
 
1171
  triggerBtn.disabled = false;
 
1214
 
1215
  toggleAttachMenu: () => {
1216
  document.getElementById('attachDropdownMenu').classList.toggle('visible');
1217
+ },
1218
+
1219
+ updateNetworkStatus: () => {
1220
+ AppState.isOnline = navigator.onLine;
1221
+ const banner = document.getElementById('networkStatusBanner');
1222
+ const pill = document.getElementById('mainStatusPill');
1223
+ const pillText = document.getElementById('mainStatusText');
1224
+
1225
+ if (AppState.isOnline) {
1226
+ banner.classList.remove('active');
1227
+ pill.classList.remove('offline');
1228
+ pillText.innerText = 'System Online';
1229
+ if(!AppState.isProcessing && AppState.history.length > 0) {
1230
+ Utils.showToast("Network connection restored.", "success");
1231
+ }
1232
+ } else {
1233
+ banner.classList.add('active');
1234
+ pill.classList.add('offline');
1235
+ pillText.innerText = 'System Offline';
1236
+ }
1237
  }
1238
  };
1239
 
1240
  // =======================================================================================
1241
+ // 5. SPEECH & TTS ENGINE (FIXED STT DUPLICATION & PREMATURE DISPATCH)
1242
  // =======================================================================================
1243
  const VoiceEngine = {
1244
  recognition: null,
1245
  currentLanguage: 'en-IN',
1246
+ baseInputText: '', // ✨ KEY FIX: Stores text existing BEFORE mic turns on
1247
+ silenceTimer: null, // ✨ KEY FIX: Detects silence for Live Mode dispatch
1248
+
1249
  init: () => {
1250
  const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
1251
+ if (!SR) {
1252
+ console.warn("Speech Recognition API not supported in this browser.");
1253
+ document.getElementById('masterVoiceBtn').style.display = 'none';
1254
+ return;
1255
+ }
1256
 
1257
  VoiceEngine.recognition = new SR();
1258
+ // 'continuous = true' prevents random stops while user is speaking
1259
  VoiceEngine.recognition.continuous = true;
1260
  VoiceEngine.recognition.interimResults = true;
1261
  VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
 
1263
  VoiceEngine.recognition.onstart = () => {
1264
  AppState.isMicRecording = true;
1265
  document.getElementById('masterVoiceBtn').classList.add('active-listening');
1266
+
1267
+ // SAVE BASE TEXT: So we don't blindly append duplicates
1268
+ VoiceEngine.baseInputText = document.getElementById('mainChatInput').value;
1269
+
1270
  if (AppState.isLiveModeEngaged) {
1271
+ VoiceEngine.baseInputText = ''; // Clear for live mode
1272
  document.getElementById('liveMicBtn').classList.add('is-recording');
1273
  document.getElementById('liveStatusText').innerText = "Listening...";
1274
  document.getElementById('liveOrb').classList.remove('speaking');
 
1277
  };
1278
 
1279
  VoiceEngine.recognition.onresult = (event) => {
1280
+ // Clear the silence timer because the user is currently generating sound
1281
+ if (VoiceEngine.silenceTimer) clearTimeout(VoiceEngine.silenceTimer);
1282
+
1283
+ let finalSpeech = '';
1284
+ let interimSpeech = '';
1285
 
1286
+ // REBUILD the entire speech buffer from index 0. This PREVENTS duplicates
1287
+ // entirely because we construct the absolute truth string every tick.
1288
+ for (let i = 0; i < event.results.length; ++i) {
1289
  if (event.results[i].isFinal) {
1290
+ finalSpeech += event.results[i].transcript;
1291
  } else {
1292
+ interimSpeech += event.results[i].transcript;
1293
  }
1294
  }
1295
 
1296
+ // Clean formatting
1297
+ let totalNewSpeech = (finalSpeech + interimSpeech).replace(/\s+/g, ' ');
1298
+ if (totalNewSpeech.length > 0) {
1299
+ totalNewSpeech = totalNewSpeech.charAt(0).toUpperCase() + totalNewSpeech.slice(1);
1300
+ }
1301
+
1302
+ if (AppState.isLiveModeEngaged) {
1303
+ // Update UI for Live Mode
1304
+ document.getElementById('liveTranscriptText').innerText = totalNewSpeech ? `"${totalNewSpeech}"` : "Listening...";
1305
+ document.getElementById('mainChatInput').value = totalNewSpeech;
1306
 
1307
+ // ✨ VAD / SILENCE DETECTOR: Wait 1.8 seconds of complete silence before dispatching
1308
+ VoiceEngine.silenceTimer = setTimeout(() => {
1309
+ if (totalNewSpeech.trim().length > 0) {
1310
+ VoiceEngine.recognition.stop();
1311
+ // stop() will naturally trigger onend, which handles dispatch
1312
+ }
1313
+ }, 1800);
1314
+
1315
+ } else {
1316
+ // Regular chat mode: append intelligently to base text
1317
+ const separator = (VoiceEngine.baseInputText && totalNewSpeech && !VoiceEngine.baseInputText.endsWith(' ')) ? ' ' : '';
1318
+ const combinedText = VoiceEngine.baseInputText + separator + totalNewSpeech;
1319
+
1320
+ document.getElementById('mainChatInput').value = combinedText;
1321
+ UIManager.autoGrowTextArea(document.getElementById('mainChatInput'));
1322
+
1323
+ // Show visual feedback for interim vs final
1324
+ const interimOverlay = document.getElementById('interimTextOverlay');
1325
+ if (interimSpeech.length > 0) {
1326
+ interimOverlay.innerText = interimSpeech;
1327
+ interimOverlay.classList.add('active');
1328
  } else {
1329
+ interimOverlay.classList.remove('active');
 
 
1330
  }
1331
  }
1332
  };
 
1334
  VoiceEngine.recognition.onend = () => {
1335
  AppState.isMicRecording = false;
1336
  document.getElementById('masterVoiceBtn').classList.remove('active-listening');
1337
+ document.getElementById('interimTextOverlay').classList.remove('active');
1338
 
1339
+ if (AppState.isLiveModeEngaged) {
1340
  document.getElementById('liveMicBtn').classList.remove('is-recording');
 
1341
  document.getElementById('liveOrb').style.transform = "scale(1)";
1342
+
1343
+ const currentInput = document.getElementById('mainChatInput').value.trim();
1344
+ if (currentInput !== '' && !AppState.isProcessing) {
1345
+ // The silence timer finished, user stopped talking, auto-dispatch!
1346
+ document.getElementById('liveStatusText').innerText = "Processing...";
1347
+ ChatEngine.initiateDispatch();
1348
+ } else if (!AppState.isProcessing) {
1349
+ document.getElementById('liveStatusText').innerText = "Tap mic to interact";
1350
+ }
1351
  }
1352
  };
1353
 
1354
  VoiceEngine.recognition.onerror = (event) => {
1355
  AppState.isMicRecording = false;
1356
+ if(event.error !== 'no-speech' && event.error !== 'aborted') {
1357
+ Utils.showToast("Voice module error: " + event.error, "error");
1358
  }
1359
  document.getElementById('masterVoiceBtn').classList.remove('active-listening');
1360
+ document.getElementById('interimTextOverlay').classList.remove('active');
1361
+
1362
  if (AppState.isLiveModeEngaged) {
1363
  document.getElementById('liveMicBtn').classList.remove('is-recording');
1364
  document.getElementById('liveStatusText').innerText = "Audio Failure. Retry.";
 
1374
  VoiceEngine.currentLanguage = 'hi-IN';
1375
  badge.innerText = 'हि';
1376
  btn.classList.add('hindi-active');
1377
+ Utils.showToast("Listening Protocol: Hindi (देवनागरी)", "success");
1378
  } else {
1379
  VoiceEngine.currentLanguage = 'en-IN';
1380
  badge.innerText = 'EN';
1381
  btn.classList.remove('hindi-active');
1382
+ Utils.showToast("Listening Protocol: English", "success");
1383
  }
1384
 
1385
  if (VoiceEngine.recognition) {
1386
  VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
1387
  if(AppState.isMicRecording) {
1388
  VoiceEngine.recognition.stop();
1389
+ // Slight delay to allow system to halt before restarting
1390
+ setTimeout(() => { try{VoiceEngine.recognition.start();}catch(e){} }, 400);
1391
  }
1392
  }
1393
  },
1394
 
1395
  toggleDictation: () => {
1396
+ if (!VoiceEngine.recognition) return Utils.showToast("Hardware dictation unsupported in this browser.", "error");
1397
  try {
1398
  if(AppState.isMicRecording) {
1399
  VoiceEngine.recognition.stop();
 
1403
  } catch (e) { console.error("Mic Start Error", e); }
1404
  },
1405
 
 
1406
  executeTTS: async (rawText) => {
1407
  // Apply smart text cleaner so AI doesn't read code or image links
1408
  const cleanSpeechText = Utils.cleanTextForVoice(rawText);
1409
 
1410
  if(!cleanSpeechText.trim()) {
1411
+ Utils.showToast("No readable conversational text found in this block.", "error");
1412
  return;
1413
  }
1414
 
 
1419
 
1420
  try {
1421
  if(!AppState.gradioClient) {
 
1422
  const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
1423
  AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS");
1424
  }
 
1428
  voice_type: "प्रभात (भारी और प्राकृतिक आवाज़ - हिंग्लिश के लिए)"
1429
  });
1430
 
1431
+ if (result.data && result.data) {
1432
+ const audioUrl = typeof result.data === 'string' ? result.data : result.data.url;
1433
  const audio = new Audio(audioUrl);
1434
 
1435
  audio.onended = () => {
 
1444
  throw new Error("No audio payload returned.");
1445
  }
1446
  } catch (error) {
1447
+ Utils.showToast("Voice Neural Matrix is currently overloaded.", "error");
1448
  console.error("Gradio TTS Error:", error);
1449
  if (AppState.isLiveModeEngaged) {
1450
  document.getElementById('liveOrb').classList.remove('speaking');
 
1463
  if (VoiceEngine.recognition && !AppState.isMicRecording) {
1464
  setTimeout(() => {
1465
  try { VoiceEngine.recognition.start(); } catch(e){}
1466
+ }, 600);
1467
  }
1468
  },
1469
  terminate: () => {
 
1476
  };
1477
 
1478
  // =======================================================================================
1479
+ // 6. FILE & DOCUMENT PROCESSOR (Robust & Size Validated)
1480
  // =======================================================================================
1481
  const FileProcessor = {
1482
  triggerFileSelector: (type) => {
 
1485
  },
1486
 
1487
  processFile: async (inputElement, typeContext) => {
1488
+ const file = inputElement.files;
1489
  if (!file) return;
1490
 
1491
+ // Size Validation to prevent UI thread lock
1492
+ const fileSizeMB = file.size / (1024 * 1024);
1493
+ if (fileSizeMB > Config.MAX_FILE_SIZE_MB) {
1494
+ Utils.showToast(`File exceeds ${Config.MAX_FILE_SIZE_MB}MB enterprise limit.`, "error");
1495
+ inputElement.value = '';
1496
+ return;
1497
+ }
1498
+
1499
  const fName = file.name.toLowerCase();
1500
  const mime = file.type;
1501
 
1502
+ if (typeContext === 'image' && !mime.startsWith('image/')) { Utils.showToast("Visual media required.", "error"); inputElement.value=''; return; }
1503
+ if (typeContext === 'video' && !mime.startsWith('video/')) { Utils.showToast("Video media required.", "error"); inputElement.value=''; return; }
1504
+ if (typeContext === 'audio' && !mime.startsWith('audio/')) { Utils.showToast("Audio media required.", "error"); inputElement.value=''; return; }
1505
 
1506
+ Utils.showToast(`Analyzing ${file.name}...`, "info");
1507
 
1508
  const thumbImg = document.getElementById('previewImgThumb');
1509
  const docIcon = document.getElementById('previewDocIcon');
 
1517
 
1518
  if (typeContext === 'image') {
1519
  fileReader.onload = (e) => {
1520
+ AppState.pendingAttachment = { type: 'image', data: e.target.result.split(','), name: file.name };
1521
  thumbImg.src = e.target.result;
1522
  thumbImg.style.display = 'flex';
1523
  };
 
1525
  }
1526
  else if (typeContext === 'video' || typeContext === 'audio') {
1527
  fileReader.onload = (e) => {
1528
+ AppState.pendingAttachment = { type: typeContext, data: e.target.result.split(','), name: file.name };
1529
  docIcon.innerText = typeContext === 'video' ? '🎥' : '🎵';
1530
  docIcon.style.display = 'flex';
1531
  };
 
1547
  extractedText += content.items.map(s => s.str).join(' ') + "\n";
1548
  }
1549
  AppState.pendingAttachment = { type: 'text', data: extractedText.trim() || "No readable text found.", name: file.name };
1550
+ Utils.showToast("Document payload secured.", "success");
1551
  } catch (e) {
1552
+ Utils.showToast("PDF architecture parsing failed.", "error");
1553
  FileProcessor.discardFile();
1554
  }
1555
  };
 
1561
  const buffer = this.result;
1562
  const resultData = await mammoth.extractRawText({ arrayBuffer: buffer });
1563
  AppState.pendingAttachment = { type: 'text', data: resultData.value.trim() || "No readable text found.", name: file.name };
1564
+ Utils.showToast("Document payload secured.", "success");
1565
  } catch(e) {
1566
+ Utils.showToast("Document architecture parsing failed.", "error");
1567
  FileProcessor.discardFile();
1568
  }
1569
  };
 
1572
  else {
1573
  fileReader.onload = (e) => {
1574
  AppState.pendingAttachment = { type: 'text', data: e.target.result, name: file.name };
1575
+ Utils.showToast("File payload secured.", "success");
1576
  };
1577
  fileReader.readAsText(file);
1578
  }
 
1583
  discardFile: () => {
1584
  AppState.pendingAttachment = null;
1585
  document.getElementById('filePreviewBar').classList.remove('visible');
1586
+ document.getElementById('previewImgThumb').src = '';
1587
  }
1588
  };
1589
 
1590
  // =======================================================================================
1591
+ // 7. WORKSPACE ENGINE & ADVANCED MARKDOWN RENDERING
1592
  // =======================================================================================
1593
  const WorkspaceEngine = {
1594
  launch: (codeBlockId) => {
1595
  AppState.currentWorkspaceId = codeBlockId;
1596
  const codeData = AppState.generatedCodeBlocks[codeBlockId];
1597
 
1598
+ document.getElementById('wsTitleText').innerText = codeData.lang ? `Generated ${codeData.lang.toUpperCase()}` : "Compiled Logic";
1599
  const blockDisplay = document.getElementById('workspaceCodeBlock');
1600
  blockDisplay.className = `hljs language-${codeData.lang || 'plaintext'}`;
1601
  blockDisplay.textContent = codeData.code;
1602
 
1603
  hljs.highlightElement(blockDisplay);
1604
+
1605
+ // Add Line Numbers dynamically
1606
+ const lineCount = codeData.code.split('\n').length;
1607
+ let numbersHTML = '';
1608
+ for(let i=1; i<=lineCount; i++) { numbersHTML += `${i}<br>`; }
1609
+ document.getElementById('wsLineNumbers').innerHTML = numbersHTML;
1610
+
1611
  document.getElementById('workspacePanel').classList.add('expanded');
1612
 
1613
  if (window.innerWidth <= 1024) {
 
1625
  }
1626
  };
1627
 
1628
+ // Custom Marked Renderer for UI perfection
1629
  const MD_Renderer = new marked.Renderer();
1630
  MD_Renderer.code = function(token) {
1631
  const rawCode = typeof token === 'string' ? token : (token.text || '');
1632
+ const langClass = typeof token === 'string' ? arguments : (token.lang || '');
1633
 
1634
  if (AppState.isStreamingActive) {
1635
  return `
1636
  <div class="streaming-code-container">
1637
  <div class="streaming-code-header">
1638
  <div class="loading-ring"></div>
1639
+ Generating Secure Architecture...
1640
  </div>
1641
  <pre><code class="language-${langClass}">${Utils.escapeHTML(rawCode)}</code></pre>
1642
  </div>`;
 
1653
  </div>
1654
  <div class="ws-card-details">
1655
  <h4>Code Module Compiled</h4>
1656
+ <p>${langClass || 'Syntax Module'}</p>
1657
  </div>
1658
  </div>
1659
  <button class="btn-launch-workspace btn-launch-ws" data-id="${internalId}">Open Workspace</button>
1660
  </div>`;
1661
  };
 
1662
 
1663
+ MD_Renderer.table = function(token) {
1664
+ let html = '<table>';
1665
+ if (token.header) {
1666
+ html += '<thead><tr>';
1667
+ token.header.forEach(th => { html += `<th>${marked.parseInline(th.text)}</th>`; });
1668
+ html += '</tr></thead>';
1669
+ }
1670
+ if (token.rows) {
1671
+ html += '<tbody>';
1672
+ token.rows.forEach(tr => {
1673
+ html += '<tr>';
1674
+ tr.forEach(td => { html += `<td>${marked.parseInline(td.text)}</td>`; });
1675
+ html += '</tr>';
1676
+ });
1677
+ html += '</tbody>';
1678
+ }
1679
+ html += '</table>';
1680
+ return html;
1681
+ };
1682
+
1683
+ marked.use({ renderer: MD_Renderer, breaks: true, gfm: true });
1684
+
1685
+ // Event delegation for dynamically generated workspace buttons
1686
  document.getElementById('msgs').addEventListener('click', function(e) {
1687
  if (e.target && e.target.classList.contains('btn-launch-ws')) {
1688
  const blockId = e.target.getAttribute('data-id');
 
1707
  },
1708
 
1709
  clearMemory: async () => {
1710
+ if(!confirm("Are you sure you want to wipe the neural context? This action cannot be undone.")) return;
1711
+
1712
  if (AppState.currentUser) {
1713
+ Utils.showToast("Purging neural link memory...", "info");
1714
  try {
1715
  await fetch(Config.GAS_URL, {
1716
  method: 'POST',
 
1724
  },
1725
 
1726
  syncHistoryFromCloud: async () => {
1727
+ if (!AppState.isOnline) return;
1728
+
1729
  const messageZone = document.getElementById('msgs');
1730
  document.getElementById('welcomeState').style.display = 'none';
1731
  messageZone.innerHTML = '<div style="text-align:center; padding:80px; font-weight:800; color:var(--brand-saffron); font-size:18px;">Decrypting Historic Archives...</div>';
 
1761
  },
1762
 
1763
  saveHistoryToCloud: () => {
1764
+ if (AppState.currentUser && AppState.isOnline) {
1765
  fetch(Config.GAS_URL, {
1766
  method: 'POST',
1767
  mode: 'cors',
 
1774
  buildPreviewHTML: (attachmentObj) => {
1775
  if (!attachmentObj) return '';
1776
  if (attachmentObj.type === 'image') {
1777
+ return `<img src="data:image/jpeg;base64,${attachmentObj.data}" class="chat-in-bubble-img" alt="Attached Media">`;
1778
  } else if (attachmentObj.type === 'video') {
1779
+ return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><polygon points="23 7 16 12 23 17 23 7"></polygon><rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect></svg></div><span class="name">${Utils.escapeHTML(attachmentObj.name)}</span></div>`;
1780
  } else if (attachmentObj.type === 'audio') {
1781
+ return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18V5l12-2v13"></path><circle cx="6" cy="18" r="3"></circle><circle cx="18" cy="16" r="3"></circle></svg></div><span class="name">${Utils.escapeHTML(attachmentObj.name)}</span></div>`;
1782
  } else {
1783
+ return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg></div><span class="name">${Utils.escapeHTML(attachmentObj.name)}</span></div>`;
1784
  }
1785
  },
1786
 
 
1790
  let visibleText = textContent;
1791
  if(textContent.includes('---DATA BEGIN---')) {
1792
  const parts = textContent.split('User Prompt:');
1793
+ if(parts.length > 1) visibleText = parts.trim();
1794
  }
1795
 
1796
  const bubbleBox = document.createElement('div');
 
1835
  let actionTray = bubbleDOM.querySelector('.bot-actions-row');
1836
  if (!isCurrentlyStreaming && !actionTray && strippedMarkup.trim().length > 0) {
1837
  const safeRawCopy = strippedMarkup.replace(/"/g, '&quot;').replace(/'/g, "\\'").replace(/\n/g, '\\n').replace(/\r/g, '');
1838
+ // Safe injection for TTS payload
1839
  const safeRawTTS = strippedMarkup.replace(/"/g, '&quot;').replace(/'/g, "\\'").replace(/\n/g, ' ');
1840
 
1841
  const actionsHTML = `
 
1857
  },
1858
 
1859
  initiateDispatch: async () => {
1860
+ if (!AppState.isOnline) return Utils.showToast("Cannot process request. System is Offline.", "error");
1861
  if (AppState.isProcessing) return;
1862
 
1863
  const inputField = document.getElementById('mainChatInput');
 
1869
  if (!AppState.currentUser) {
1870
  if (AppState.guestCount >= 3) {
1871
  AuthManager.openModal();
1872
+ return Utils.showToast("Query limit reached. Secure Login required.", "error");
1873
  }
1874
  AppState.guestCount++;
1875
  localStorage.setItem('arjun_guest', AppState.guestCount.toString());
1876
  document.getElementById('guestCountDisplay').innerText = AppState.guestCount;
1877
  }
1878
 
1879
+ // Prepare UI for Dispatch
1880
  inputField.value = '';
1881
  inputField.style.height = 'auto';
1882
  document.getElementById('masterSendBtn').disabled = true;
 
1919
  const activeBotBubble = ChatEngine.renderBotMessage('', false);
1920
  UIManager.forceScrollDown();
1921
 
1922
+ // Dynamic Pollinations Seed Generator
1923
  const cryptographicSeed = Math.floor(Math.random() * 999999999);
1924
 
1925
+ // Advanced Cognitive System Instructions
1926
+ let cognitivePrompt = `You are Arjun 2.O, a highly advanced enterprise AI system architected and engineered by Abhay Kumar.
1927
+ LANGUAGE PROTOCOL: Your primary logic is English. If the user interacts in Hindi/Hinglish, you must dynamically switch to a professional Hindi response. Never force translation on pure English prompts.
1928
 
1929
  IMAGE SYNTHESIS OVERRIDE:
1930
  When commanded to render, generate, or create an image/photograph, you MUST reply with a precise markdown image node targeting Pollinations AI.
1931
  Formula: ![Generating Vision...](https://image.pollinations.ai/prompt/{URL_ENCODED_PROMPT_DETAIL}?width=1024&height=1024&nologo=true&model={MODEL}&seed=${cryptographicSeed})
1932
  Available Models: flux, flux-realism, flux-anime, flux-3d.
1933
+ CRITICAL: The seed parameter is mandatory to bypass cache mechanics. Always render this markdown node inline.`;
1934
 
1935
  if (AppState.isLiveModeEngaged) {
1936
+ cognitivePrompt += `\n\n[LIVE ACOUSTIC OVERRIDE ACTIVE]: You are currently engaged in a LIVE, REAL-TIME VOCAL INTERFACE.
1937
  MANDATORY direct answers. Maximum brevity. Eliminate complex markdown, massive code blocks, or extended lists. Replicate human telephonic brevity perfectly.`;
1938
  }
1939
 
 
1944
  attachments: payloadAttachments,
1945
  system_prompt: cognitivePrompt,
1946
  history: secureHistory,
1947
+ max_tokens: AppState.isLiveModeEngaged ? 150 : 4096,
1948
  temperature: 0.75
1949
  };
1950
 
 
1978
 
1979
  try {
1980
  const jsonSegment = JSON.parse(parseableStr);
1981
+ if (jsonSegment.choices && jsonSegment.choices.delta.content) {
1982
+ responseBuffer += jsonSegment.choices.delta.content;
1983
  ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, true);
1984
  UIManager.autoScroll();
1985
  }
 
2016
  // 9. EVENT DELEGATION & BOOTSTRAP INVOCATION
2017
  // =======================================================================================
2018
 
 
2019
  window.startArjunApp = function() {
2020
  document.getElementById('welcomeOverlay').classList.add('hidden');
2021
  localStorage.setItem('arjun_welcome_seen', 'true');
2022
  setTimeout(() => { document.getElementById('welcomeOverlay').style.display = 'none'; }, 400);
2023
  };
2024
 
 
2025
  document.addEventListener('DOMContentLoaded', () => {
2026
  // Sidebar Controls
2027
  document.getElementById('btnSidebarOpen').addEventListener('click', UIManager.toggleSidebar);
 
2083
  document.getElementById('msgs').addEventListener('scroll', UIManager.checkScrollState);
2084
  document.getElementById('scrollTriggerBtn').addEventListener('click', UIManager.forceScrollDown);
2085
 
2086
+ // Network Monitoring
2087
+ window.addEventListener('online', UIManager.updateNetworkStatus);
2088
+ window.addEventListener('offline', UIManager.updateNetworkStatus);
2089
+
2090
  // Prevent unwanted default mobile behaviours on double-tap
2091
  document.addEventListener('dblclick', function(event) {
2092
  event.preventDefault();
 
2100
  }
2101
 
2102
  // Fire Boot Processes
2103
+ UIManager.updateNetworkStatus();
2104
  VoiceEngine.init();
2105
  AuthManager.initUI();
2106
  if(AppState.currentUser) { ChatEngine.syncHistoryFromCloud(); }
 
2109
  </script>
2110
  </body>
2111
  </html>