CodeVed / index.html
Vedika
Update index.html
ff7fffe verified
Raw
History Blame
143 kB
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- Viewport Settings: Disables zoom, removes blue tap highlights on mobile devices -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<meta name="description" content="Arjun 2.O Ultimate Enterprise Artificial Intelligence System engineered by Abhay Kumar.">
<meta name="theme-color" content="#FF9933">
<title>Arjun 2.O - Professional Advanced AI</title>
<!-- =========================================================================================
EXTERNAL RESOURCES, FONTS & LIBRARIES (बाहरी स्रोत)
========================================================================================= -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Professional Typography: Inter for UI, Geist Mono for Code, Instrument Serif for Headers -->
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Inter:wght@300;400;500;600;700;800;900&family=Geist+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- Syntax Highlighting (Atom One Dark for Workspace Environment) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
<!-- Data Extraction & Rendering Utilities -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.1/marked.min.js"></script>
<!-- =========================================================================================
MASSIVE ENTERPRISE CSS ARCHITECTURE (विस्तृत और उन्नत स्टाइलिंग)
========================================================================================= -->
<style>
/* ---------------------------------------------------------------------------------------
A. CSS VARIABLES, DESIGN TOKENS & BRANDING
--------------------------------------------------------------------------------------- */
:root {
/* Brand Identity: Saffron, White, Green (Tiranga Theme) */
--brand-saffron: #FF9933;
--brand-saffron-light: rgba(255, 153, 51, 0.12);
--brand-saffron-dark: #e68a2e;
--brand-saffron-glow: rgba(255, 153, 51, 0.4);
--brand-white: #FFFFFF;
--brand-white-glass: rgba(255, 255, 255, 0.88);
--brand-green: #138808;
--brand-green-light: rgba(19, 136, 8, 0.12);
--brand-green-dark: #0f6e06;
--brand-green-glow: rgba(19, 136, 8, 0.4);
/* Structural Colors & Backgrounds */
--bg-primary: #ffffff;
--bg-secondary: #f8f9fa;
--bg-tertiary: #f1f3f5;
--bg-glass: rgba(255, 255, 255, 0.75);
--bg-glass-heavy: rgba(255, 255, 255, 0.95);
--bg-overlay: rgba(0, 0, 0, 0.5);
/* Text & Typography Colors */
--text-primary: #111827;
--text-secondary: #4b5563;
--text-tertiary: #9ca3af;
--text-inverse: #ffffff;
--text-error: #ef4444;
--text-success: #10b981;
/* Borders & Dividers */
--border-light: rgba(0, 0, 0, 0.08);
--border-medium: rgba(0, 0, 0, 0.15);
--border-focus: rgba(255, 153, 51, 0.5);
/* Shadows & Elevation */
--shadow-xs: 0 1px 2px rgba(0,0,0,0.04);
--shadow-sm: 0 1px 3px rgba(0,0,0,0.05), 0 1px 2px rgba(0,0,0,0.03);
--shadow-md: 0 4px 6px -1px rgba(0,0,0,0.05), 0 2px 4px -1px rgba(0,0,0,0.03);
--shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025);
--shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.05), 0 10px 10px -5px rgba(0,0,0,0.02);
--shadow-float: 0 25px 50px -12px rgba(0,0,0,0.15);
--shadow-inner: inset 0 2px 4px rgba(0,0,0,0.06);
/* Font Families */
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--font-mono: 'Geist Mono', Consolas, Monaco, monospace;
--font-serif: 'Instrument Serif', Georgia, serif;
/* Radii */
--radius-xs: 4px;
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--radius-xl: 24px;
--radius-full: 9999px;
/* Animation Easing */
--ease-fast: 0.15s cubic-bezier(0.4, 0, 0.2, 1);
--ease-smooth: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
--ease-spring: 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
/* Z-Indices - Properly Layered Enterprise System */
--z-ambient: -1;
--z-base: 1;
--z-header: 10;
--z-dock: 20;
--z-workspace: 25;
--z-dropdown: 50;
--z-sidebar: 100;
--z-modal: 5000;
--z-toast: 9000;
--z-live: 9999;
--z-offline: 10000;
}
/* ---------------------------------------------------------------------------------------
B. GLOBAL RESET & ANTI-BLUE-HIGHLIGHT
--------------------------------------------------------------------------------------- */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
-webkit-tap-highlight-color: transparent !important;
-webkit-touch-callout: none !important;
}
html { font-size: 16px; -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
height: 100dvh;
width: 100vw;
overflow: hidden;
background-color: var(--bg-primary);
color: var(--text-primary);
font-family: var(--font-sans);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Accessibilty focus states */
*:focus-visible { outline: 2px solid var(--brand-saffron); outline-offset: 2px; }
*:focus { outline: none; }
button, input, textarea, select {
font-family: inherit;
color: inherit;
border: none;
background: transparent;
}
button { cursor: pointer; user-select: none; }
button:disabled { cursor: not-allowed; opacity: 0.6; }
a { color: inherit; text-decoration: none; }
img { max-width: 100%; height: auto; display: block; }
svg { flex-shrink: 0; }
/* Custom Enterprise Scrollbars */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-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); }
::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.3); border: 2px solid transparent; background-clip: padding-box; }
/* ---------------------------------------------------------------------------------------
C. NETWORK OFFLINE & AMBIENT BACKGROUND SYSTEM
--------------------------------------------------------------------------------------- */
.network-offline-banner {
position: fixed; top: 0; left: 0; right: 0; background: var(--text-error); color: white;
text-align: center; padding: 8px; font-size: 14px; font-weight: 700; z-index: var(--z-offline);
transform: translateY(-100%); transition: transform var(--ease-spring); display: flex; align-items: center; justify-content: center; gap: 8px; box-shadow: var(--shadow-md);
}
.network-offline-banner.active { transform: translateY(0); }
.ambient-environment {
position: fixed; inset: 0; z-index: var(--z-ambient); overflow: hidden; pointer-events: none;
background: linear-gradient(135deg, var(--brand-saffron-light) 0%, var(--bg-primary) 50%, var(--brand-green-light) 100%);
}
.ambient-orb {
position: absolute; border-radius: 50%; filter: blur(120px); opacity: 0.35;
animation: orbFloat 40s ease-in-out infinite alternate; will-change: transform;
}
.orb-top-left {
width: 650px; height: 650px;
background: radial-gradient(circle, rgba(255,153,51,0.2) 0%, transparent 70%);
top: -200px; left: -150px;
}
.orb-bottom-right {
width: 550px; height: 550px;
background: radial-gradient(circle, rgba(19,136,8,0.15) 0%, transparent 70%);
bottom: -150px; right: -100px; animation-delay: -20s;
}
@keyframes orbFloat {
0% { transform: translate(0, 0) scale(1); }
33% { transform: translate(50px, 70px) scale(1.05); }
66% { transform: translate(-30px, 40px) scale(0.95); }
100% { transform: translate(60px, -20px) scale(1.1); }
}
/* ---------------------------------------------------------------------------------------
D. ENTERPRISE TOAST NOTIFICATION ENGINE
--------------------------------------------------------------------------------------- */
.toast-wrapper {
position: absolute; top: 24px; left: 50%; transform: translateX(-50%);
z-index: var(--z-toast); display: flex; flex-direction: column; gap: 12px;
pointer-events: none; width: 90%; max-width: 450px; align-items: center;
}
.toast-notification {
background: rgba(17, 24, 39, 0.95); color: var(--text-inverse); padding: 14px 24px;
border-radius: var(--radius-full); font-size: 14px; font-weight: 600; box-shadow: var(--shadow-xl);
animation: toastSlideIn var(--ease-spring) forwards, toastFadeOut 0.4s 3.5s forwards;
display: flex; align-items: center; gap: 12px; width: fit-content; max-width: 100%; word-break: break-word;
backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,0.1);
}
.toast-notification.error { background: rgba(239, 68, 68, 0.95); border-color: rgba(255,255,255,0.2); }
.toast-notification.success { background: rgba(16, 185, 129, 0.95); border-color: rgba(255,255,255,0.2); }
.toast-notification svg { width: 20px; height: 20px; flex-shrink: 0; color: var(--brand-saffron); }
.toast-notification.error svg, .toast-notification.success svg { color: white; }
@keyframes toastSlideIn { from { opacity: 0; transform: translateY(-30px) scale(0.9); } to { opacity: 1; transform: translateY(0) scale(1); } }
@keyframes toastFadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } }
/* ---------------------------------------------------------------------------------------
E. INITIAL WELCOME OVERLAY
--------------------------------------------------------------------------------------- */
.startup-overlay {
position: fixed; inset: 0; background: var(--brand-white-glass);
backdrop-filter: blur(25px); -webkit-backdrop-filter: blur(25px); z-index: calc(var(--z-toast) + 100);
display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 24px;
transition: opacity var(--ease-smooth), visibility var(--ease-smooth);
}
.startup-overlay.hidden { opacity: 0; visibility: hidden; pointer-events: none; }
.startup-logo-container { position: relative; margin-bottom: 32px; animation: popIn var(--ease-spring) 0.5s both; }
.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; }
.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; }
@keyframes pulseGlow { from { opacity: 0.3; transform: scale(0.95); } to { opacity: 0.6; transform: scale(1.05); } }
@keyframes popIn { 0% { opacity: 0; transform: scale(0.8) translateY(20px); } 100% { opacity: 1; transform: scale(1) translateY(0); } }
.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; }
.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; }
.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; }
.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; }
.btn-startup-launch:hover { background: #000000; transform: translateY(-4px) scale(1.02); box-shadow: 0 15px 35px rgba(0,0,0,0.25); }
.btn-startup-launch:hover::before { left: 150%; }
@keyframes slideUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
/* ---------------------------------------------------------------------------------------
F. CORE APPLICATION LAYOUT & SIDEBAR
--------------------------------------------------------------------------------------- */
.app-root { position: relative; z-index: var(--z-base); display: flex; height: 100dvh; width: 100vw; overflow: hidden; background: var(--bg-glass); backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px); }
/* Sidebar Navigation System */
.sidebar-container { width: 320px; display: flex; flex-direction: column; background: rgba(248, 249, 250, 0.85); border-right: 1px solid var(--border-light); flex-shrink: 0; z-index: var(--z-sidebar); transition: transform var(--ease-smooth), box-shadow var(--ease-smooth); backdrop-filter: blur(15px); }
.sidebar-header { padding: 28px 24px; border-bottom: 1px solid var(--border-light); display: flex; justify-content: space-between; align-items: center; }
.brand-identity { display: flex; align-items: center; gap: 14px; text-decoration: none; }
.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); }
.brand-identity:hover img { transform: scale(1.08) rotate(-5deg); box-shadow: var(--shadow-md); }
.brand-typography { display: flex; flex-direction: column; }
.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; }
.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; }
.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); }
.btn-mobile-close:hover { background: rgba(239, 68, 68, 0.15); color: var(--text-error); transform: rotate(90deg); }
.sidebar-body { flex: 1; overflow-y: auto; padding: 24px; display: flex; flex-direction: column; gap: 28px; }
/* Advanced Auth Widget in Sidebar */
.auth-widget { background: var(--bg-primary); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 20px; box-shadow: var(--shadow-sm); transition: var(--ease-smooth); }
.auth-widget:hover { box-shadow: var(--shadow-md); border-color: var(--border-medium); }
.btn-secure-connect { width: 100%; padding: 14px; background: var(--text-primary); color: var(--text-inverse); border: none; border-radius: var(--radius-md); font-size: 14px; font-weight: 700; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 10px; transition: var(--ease-fast); }
.btn-secure-connect:hover { background: #000000; transform: translateY(-2px); box-shadow: var(--shadow-md); }
.user-profile-display { display: none; align-items: center; gap: 14px; }
.avatar-badge { width: 46px; height: 46px; border-radius: var(--radius-full); background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); color: var(--brand-white); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 18px; box-shadow: var(--shadow-sm); border: 2px solid var(--bg-primary); text-shadow: 0 1px 2px rgba(0,0,0,0.3); }
.user-details { flex: 1; overflow: hidden; }
.user-email-id { font-size: 14px; font-weight: 700; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.user-clearance-level { font-size: 11px; color: var(--brand-green); font-weight: 600; margin-top: 2px; display: flex; align-items: center; gap: 4px; }
.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); }
.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); }
.btn-system-logout:hover { background: var(--text-error); color: #ffffff; transform: scale(1.05); }
/* Developer Box with Tiranga Accent */
.developer-credit-box { background: var(--bg-primary); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 28px 20px; text-align: center; box-shadow: var(--shadow-sm); margin-top: auto; position: relative; overflow: hidden; }
.developer-credit-box::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; background: linear-gradient(90deg, var(--brand-saffron), var(--brand-white), var(--brand-green)); }
.developer-credit-box img { width: 72px; height: 72px; border-radius: var(--radius-lg); object-fit: cover; margin-bottom: 16px; box-shadow: var(--shadow-md); border: 1px solid var(--border-light); margin-left: auto; margin-right: auto; transition: var(--ease-spring); }
.developer-credit-box:hover img { transform: scale(1.05); }
.dev-box-title { font-size: 18px; font-weight: 800; color: var(--text-primary); margin-bottom: 6px; }
.dev-box-subtitle { font-size: 11px; font-weight: 800; color: var(--text-tertiary); letter-spacing: 1px; text-transform: uppercase; }
/* Dangerous Action Button */
.btn-erase-memory { width: 100%; padding: 16px; border-radius: var(--radius-md); background: var(--bg-primary); border: 1px solid var(--border-light); color: var(--text-secondary); font-size: 14px; font-weight: 700; cursor: pointer; transition: var(--ease-fast); display: flex; align-items: center; justify-content: center; gap: 10px; }
.btn-erase-memory:hover { background: #fee2e2; color: var(--text-error); border-color: #fca5a5; }
/* ---------------------------------------------------------------------------------------
G. MAIN CHAT AREA & HEADER
--------------------------------------------------------------------------------------- */
.main-chat-wrapper { flex: 1; display: flex; flex-direction: column; position: relative; min-width: 320px; transition: width var(--ease-smooth); background: transparent; }
.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); }
.top-bar-left { display: flex; align-items: center; gap: 16px; }
.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); }
.btn-hamburger:hover { background: var(--bg-secondary); }
.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); }
.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); }
.system-status-pill.offline .pulse-dot { background: var(--text-error); box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2); animation: none; }
@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); } }
/* DYNAMIC LIVE MODE ACTIVATOR */
.btn-activate-live { background: linear-gradient(135deg, #ef4444 0%, #b91c1c 100%); color: white; border: none; padding: 10px 22px; border-radius: var(--radius-full); font-size: 14px; font-weight: 800; display: flex; align-items: center; gap: 8px; cursor: pointer; box-shadow: 0 4px 15px rgba(239, 68, 68, 0.35); transition: var(--ease-spring); letter-spacing: 0.5px; }
.btn-activate-live:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 8px 25px rgba(239, 68, 68, 0.45); }
.btn-activate-live svg { width: 18px; height: 18px; animation: liveBlink 1.5s infinite; }
@keyframes liveBlink { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
/* Chat Scrollable Area */
.chat-scroll-area { flex: 1; overflow-y: auto; padding: 40px 10%; display: flex; flex-direction: column; gap: 36px; scroll-behavior: smooth; position: relative; }
/* Internal Welcome Hero Box */
.chat-hero-section { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 60px 20px; margin: auto; animation: slideUpFade 0.7s var(--ease-spring) both; max-width: 750px; }
.hero-avatar-wrapper { position: relative; margin-bottom: 36px; }
.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; }
.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;}
@keyframes rotateGlow { 100% { transform: rotate(360deg); } }
@keyframes slideUpFade { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
.hero-greeting { font-size: 42px; font-weight: 900; letter-spacing: -1.5px; margin-bottom: 18px; color: var(--text-primary); line-height: 1.2; }
.hero-description { font-size: 17px; color: var(--text-secondary); line-height: 1.6; margin-bottom: 40px; font-weight: 500; }
/* GUEST BADGE LIMIT DISPLAY */
.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); }
.guest-warning-badge svg { width: 18px; height: 18px; }
.prompt-suggestions-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; width: 100%; }
.prompt-card { background: rgba(255, 255, 255, 0.7); backdrop-filter: blur(15px); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 24px; cursor: pointer; text-align: left; transition: var(--ease-smooth); box-shadow: var(--shadow-sm); position: relative; overflow: hidden; }
.prompt-card::after { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: var(--brand-saffron); opacity: 0; transition: var(--ease-fast); }
.prompt-card:hover { transform: translateY(-5px); box-shadow: var(--shadow-lg); border-color: var(--brand-saffron); background: rgba(255, 255, 255, 0.95); }
.prompt-card:hover::after { opacity: 1; }
.prompt-icon { font-size: 28px; margin-bottom: 14px; display: inline-block; background: var(--bg-tertiary); padding: 10px; border-radius: var(--radius-md); }
.prompt-title { font-size: 15px; font-weight: 800; color: var(--text-primary); margin-bottom: 8px; }
.prompt-desc { font-size: 13px; color: var(--text-secondary); line-height: 1.5; }
/* ---------------------------------------------------------------------------------------
H. CHAT MESSAGE BUBBLES & PREVIEWS
--------------------------------------------------------------------------------------- */
.chat-message-row { display: flex; gap: 20px; max-width: 88%; animation: messagePopIn 0.4s var(--ease-spring) both; }
@keyframes messagePopIn { from { opacity: 0; transform: translateY(20px) scale(0.97); } to { opacity: 1; transform: none; } }
.chat-message-row.user-msg { flex-direction: row-reverse; align-self: flex-end; }
.chat-message-row.bot-msg { align-self: flex-start; }
.msg-avatar { width: 42px; height: 42px; border-radius: var(--radius-md); flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800; box-shadow: var(--shadow-sm); }
.user-msg .msg-avatar { background: var(--text-primary); color: var(--brand-white); }
.bot-msg .msg-avatar { background: var(--bg-primary); border: 1px solid var(--border-light); padding: 3px; }
.bot-msg .msg-avatar img { width: 100%; height: 100%; border-radius: 8px; object-fit: cover; }
.msg-content-column { display: flex; flex-direction: column; gap: 8px; max-width: 100%; min-width: 0; }
.user-msg .msg-content-column { align-items: flex-end; }
.file-badge { font-size: 11px; font-weight: 700; color: var(--brand-saffron-dark); background: var(--brand-saffron-light); padding: 4px 12px; border-radius: var(--radius-full); margin-bottom: 4px; display: inline-flex; align-items: center; gap: 6px; border: 1px solid rgba(255,153,51,0.2); }
.file-badge svg { width: 12px; height: 12px; }
/* In-Bubble File Previews */
.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; }
.chat-in-bubble-img:hover { transform: scale(1.02); }
.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); }
.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); }
.chat-file-card .name { font-size: 14px; font-weight: 600; color: var(--brand-white); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-bubble { padding: 18px 24px; font-size: 16px; line-height: 1.6; position: relative; word-wrap: break-word; overflow-wrap: anywhere; }
.user-msg .chat-bubble { background: var(--text-primary); color: var(--text-inverse); border-radius: 24px 24px 6px 24px; box-shadow: var(--shadow-md); }
.bot-msg .chat-bubble { background: var(--bg-primary); color: var(--text-primary); border: 1px solid var(--border-light); border-radius: 6px 24px 24px 24px; box-shadow: var(--shadow-sm); width: 100%; }
/* Bot Action Buttons (Copy & TTS) */
.bot-actions-row { display: flex; gap: 10px; margin-top: 8px; padding-left: 14px; opacity: 0; transition: opacity var(--ease-smooth); flex-wrap: wrap; }
.bot-msg:hover .bot-actions-row { opacity: 1; }
.btn-bot-action { background: var(--bg-secondary); border: 1px solid var(--border-light); color: var(--text-secondary); font-size: 13px; font-weight: 700; cursor: pointer; display: flex; align-items: center; gap: 6px; padding: 8px 16px; border-radius: var(--radius-full); transition: var(--ease-fast); }
.btn-bot-action:hover { background: var(--bg-primary); color: var(--text-primary); transform: translateY(-2px); box-shadow: var(--shadow-sm); border-color: var(--border-medium); }
.btn-bot-action svg { width: 16px; height: 16px; }
.btn-bot-action.action-tts { color: var(--brand-green-dark); border-color: rgba(19, 136, 8, 0.25); background: var(--brand-green-light); }
.btn-bot-action.action-tts:hover { background: rgba(19, 136, 8, 0.2); }
/* Markdown Formatting inside Bubbles */
.chat-bubble p { margin-bottom: 16px; }
.chat-bubble p:last-child { margin-bottom: 0; }
.chat-bubble strong { font-weight: 800; color: inherit; }
.chat-bubble em { font-style: italic; }
.chat-bubble ul, .chat-bubble ol { margin-bottom: 16px; padding-left: 24px; }
.chat-bubble li { margin-bottom: 6px; }
.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; }
/* Advanced Tables */
.chat-bubble table { width: 100%; border-collapse: collapse; margin: 20px 0; border-radius: var(--radius-sm); overflow: hidden; box-shadow: var(--shadow-sm); }
.chat-bubble th, .chat-bubble td { border: 1px solid var(--border-light); padding: 12px 16px; text-align: left; }
.chat-bubble th { background: var(--bg-secondary); font-weight: 700; color: var(--text-primary); }
.chat-bubble tr:nth-child(even) { background: var(--bg-tertiary); }
.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); }
.user-msg .chat-bubble code { background: rgba(255,255,255,0.2); color: var(--brand-white); border-color: rgba(255,255,255,0.1); }
.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; }
/* Custom Pre-Code Blocks */
.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); }
.chat-bubble pre code { background: transparent; color: inherit; padding: 20px; font-weight: 400; border: none; display: block; overflow-x: auto; }
/* Streaming Loading UI Component */
.streaming-code-container { background: #1e1e2e; border-radius: var(--radius-md); border: 1px solid #313244; overflow: hidden; margin: 20px 0; box-shadow: var(--shadow-lg); }
.streaming-code-header { background: #11111b; padding: 14px 20px; font-size: 12px; font-weight: 700; color: #a6adc8; display: flex; align-items: center; gap: 12px; border-bottom: 1px solid #313244; font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 1.5px; }
.loading-ring { width: 16px; height: 16px; border: 2px solid rgba(255,255,255,0.1); border-top-color: var(--brand-saffron); border-radius: 50%; animation: ringSpin 1s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite; }
@keyframes ringSpin { to { transform: rotate(360deg); } }
.streaming-code-container pre { margin: 0; background: transparent; border: none; border-radius: 0; box-shadow: none; }
/* Workspace Execute Card */
.workspace-execute-card { background: var(--bg-secondary); border: 1px solid var(--border-light); border-radius: var(--radius-md); padding: 20px; margin: 20px 0; display: flex; align-items: center; justify-content: space-between; box-shadow: var(--shadow-sm); transition: var(--ease-smooth); }
.workspace-execute-card:hover { border-color: var(--brand-saffron-light); box-shadow: var(--shadow-md); background: var(--bg-primary); }
.ws-card-left { display: flex; align-items: center; gap: 16px; }
.ws-card-icon-box { width: 54px; height: 54px; border-radius: var(--radius-sm); background: var(--bg-primary); display: flex; align-items: center; justify-content: center; font-size: 26px; box-shadow: var(--shadow-sm); border: 1px solid var(--border-light); color: var(--text-primary); }
.ws-card-icon-box svg { color: var(--brand-saffron); }
.ws-card-details h4 { font-size: 16px; font-weight: 800; margin-bottom: 4px; color: var(--text-primary); }
.ws-card-details p { font-size: 12px; color: var(--text-secondary); font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; }
.btn-launch-workspace { padding: 12px 24px; background: var(--text-primary); color: var(--brand-white); border: none; border-radius: var(--radius-sm); font-size: 14px; font-weight: 700; cursor: pointer; transition: var(--ease-spring); box-shadow: var(--shadow-sm); }
.btn-launch-workspace:hover { transform: scale(1.05); background: var(--brand-saffron); box-shadow: 0 6px 15px rgba(255,153,51,0.35); }
/* ---------------------------------------------------------------------------------------
I. BOTTOM INPUT DOCK & TOOLS
--------------------------------------------------------------------------------------- */
.input-dock { flex-shrink: 0; padding: 0 40px 32px; background: transparent; position: relative; z-index: var(--z-dock); }
.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; }
.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); }
/* Upload Preview Header */
.upload-preview-bar { display: none; padding: 20px 28px 0; align-items: center; gap: 16px; border-bottom: 1px solid transparent; }
.upload-preview-bar.visible { display: flex; animation: fadeIn 0.3s ease; border-bottom-color: var(--border-light); padding-bottom: 15px; }
.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); }
.upload-meta { flex: 1; }
.upload-filename { font-size: 14px; font-weight: 700; color: var(--text-primary); max-width: 250px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.upload-status-text { font-size: 12px; color: var(--brand-green); font-weight: 600; margin-top: 2px; display: flex; align-items: center; gap: 6px; }
.upload-status-text svg { width: 14px; height: 14px; }
.btn-discard-upload { background: rgba(239, 68, 68, 0.1); border: none; width: 32px; height: 32px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; color: var(--text-error); transition: var(--ease-fast); }
.btn-discard-upload:hover { background: var(--text-error); color: #fff; }
.input-tools-row { display: flex; align-items: flex-end; gap: 12px; padding: 14px 20px 14px 24px; }
.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; }
.main-textarea::placeholder { color: var(--text-tertiary); font-weight: 400; }
/* Real-time Interim Text Feedback */
.interim-text-overlay { position: absolute; pointer-events: none; color: var(--brand-saffron-dark); 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; font-weight: 600; }
.interim-text-overlay.active { display: block; }
/* Attachment Menu Dropdown */
.attachment-module { position: relative; }
.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; }
.btn-tool-icon:hover { background: var(--bg-tertiary); color: var(--text-primary); }
.btn-tool-icon svg { width: 24px; height: 24px; stroke-width: 2; }
.attachment-dropdown { position: absolute; bottom: 60px; left: 0; background: rgba(255,255,255,0.95); backdrop-filter: blur(25px); -webkit-backdrop-filter: blur(25px); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 10px; box-shadow: var(--shadow-xl); display: none; flex-direction: column; gap: 6px; z-index: var(--z-dropdown); min-width: 240px; transform: translateY(15px) scale(0.95); opacity: 0; transition: all var(--ease-fast); transform-origin: bottom left; }
.attachment-dropdown.visible { display: flex; transform: translateY(0) scale(1); opacity: 1; }
.dropdown-item { display: flex; align-items: center; gap: 14px; padding: 14px 18px; border-radius: var(--radius-sm); cursor: pointer; font-size: 15px; font-weight: 600; color: var(--text-primary); transition: var(--ease-fast); }
.dropdown-item:hover { background: var(--bg-tertiary); color: var(--brand-saffron-dark); }
.dropdown-item svg { width: 20px; height: 20px; color: var(--text-secondary); }
.dropdown-item:hover svg { color: var(--brand-saffron); }
.stealth-input { display: none; }
/* Smart Language Toggle & Mic */
.language-toggle-chip { font-size: 13px; font-weight: 800; color: var(--text-secondary); border: 2px solid var(--border-light); background: var(--bg-primary); border-radius: 10px; padding: 6px 12px; cursor: pointer; transition: var(--ease-smooth); display: flex; align-items: center; gap: 6px; user-select: none; }
.language-toggle-chip:hover { background: var(--brand-saffron-light); color: var(--brand-saffron-dark); border-color: var(--brand-saffron); }
.language-toggle-chip.hindi-active { background: var(--brand-green-light); color: var(--brand-green-dark); border-color: var(--brand-green); }
.language-toggle-chip svg { width: 16px; height: 16px; }
.btn-mic-tool { position: relative; }
.btn-mic-tool.active-listening { color: #ffffff; background: var(--text-error); border-radius: var(--radius-full); }
.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; }
@keyframes rippleMic { 0% { transform: scale(0.8); opacity: 1; } 100% { transform: scale(1.5); opacity: 0; } }
/* Master Send Button */
.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; }
.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; }
.btn-master-send svg { width: 20px; height: 20px; fill: white; transition: transform 0.2s; position: relative; z-index: 2; }
.btn-master-send:hover { transform: translateY(-3px); box-shadow: 0 10px 25px rgba(255, 153, 51, 0.4); }
.btn-master-send:hover::before { left: 100%; }
.btn-master-send:hover svg { transform: translate(2px, -2px); }
.btn-master-send:disabled { opacity: 0.5; cursor: not-allowed; filter: grayscale(100%); transform: none; box-shadow: none; }
.bottom-branding-text { text-align: center; font-size: 12px; color: var(--text-tertiary); margin-top: 16px; font-weight: 600; letter-spacing: 0.5px; }
/* ---------------------------------------------------------------------------------------
J. WORKSPACE PRO (VS-CODE LIKE EDITOR PANEL)
--------------------------------------------------------------------------------------- */
.code-workspace-panel { width: 0; background: #1e1e1e; border-left: 1px solid var(--border-light); display: flex; flex-direction: column; transition: width var(--ease-smooth); overflow: hidden; box-shadow: -15px 0 40px rgba(0,0,0,0.15); z-index: var(--z-workspace); }
.code-workspace-panel.expanded { width: 55%; }
.workspace-header-bar { padding: 16px 24px; border-bottom: 1px solid #333; background: #252526; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; }
.workspace-title-group { font-size: 14px; font-weight: 700; display: flex; align-items: center; gap: 10px; color: #abb2bf; font-family: var(--font-mono); letter-spacing: 0.5px;}
.workspace-tools { display: flex; gap: 10px; }
.btn-workspace-tool { padding: 8px 16px; border-radius: var(--radius-sm); background: #3e4451; border: 1px solid #181a1f; cursor: pointer; display: flex; align-items: center; gap: 8px; color: #fff; transition: var(--ease-fast); font-size: 13px; font-weight: 600; }
.btn-workspace-tool:hover { background: #4b5263; }
.btn-workspace-tool.close { padding: 8px; background: transparent; border-color: transparent; color: #abb2bf; }
.btn-workspace-tool.close:hover { color: #e06c75; background: rgba(224, 108, 117, 0.1); }
.workspace-editor-surface { flex: 1; overflow-y: auto; background: #282c34; padding: 24px; position: relative; }
/* Line Numbers Implementation for Workspace */
.workspace-editor-content { display: flex; font-family: var(--font-mono); font-size: 14px; line-height: 1.6; }
.workspace-line-numbers { padding-right: 15px; border-right: 1px solid #3e4451; color: #5c6370; text-align: right; user-select: none; }
.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; }
/* ---------------------------------------------------------------------------------------
K. LIVE MODE FULLSCREEN OVERLAY
--------------------------------------------------------------------------------------- */
.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); }
.live-mode-viewport.active { opacity: 1; pointer-events: auto; }
.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); }
.btn-close-live:hover { background: rgba(239, 68, 68, 0.15); color: var(--text-error); transform: rotate(90deg); }
.pulsing-orb-wrapper { position: relative; width: 250px; height: 250px; display: flex; align-items: center; justify-content: center; margin-bottom: 50px; }
.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; }
.energy-core.speaking { animation: coreSpeak 0.5s infinite alternate; }
@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); } }
.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; }
.energy-ring:nth-child(2) { animation-delay: 0.8s; border-color: var(--brand-green); }
.energy-ring:nth-child(3) { animation-delay: 1.6s; border-color: var(--text-primary); }
@keyframes energyRipple { 0% { transform: scale(0.4); opacity: 1; border-width: 6px; } 100% { transform: scale(1.6); opacity: 0; border-width: 1px; } }
.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); }
.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); }
.live-control-deck { display: flex; gap: 24px; margin-top: 50px; }
.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); }
.btn-live-deck.mic-control { background: var(--bg-primary); border: 3px solid var(--border-light); color: var(--text-primary); }
.btn-live-deck.mic-control:hover { transform: translateY(-6px); border-color: var(--brand-saffron); color: var(--brand-saffron); box-shadow: var(--shadow-xl); }
.btn-live-deck.mic-control.is-recording { background: var(--text-error); color: white; border-color: var(--text-error); animation: pulseMicLive 1.2s infinite; }
@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); } }
/* Scroll Trigger Button */
.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; }
.btn-scroll-trigger.visible { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
.btn-scroll-trigger:hover { background: var(--text-primary); color: var(--text-inverse); transform: translateX(-50%) translateY(-5px); box-shadow: var(--shadow-xl); }
/* ---------------------------------------------------------------------------------------
L. AUTHENTICATION SECURE GATEWAY (MODAL)
--------------------------------------------------------------------------------------- */
.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; }
.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); }
.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; }
.btn-modal-dismiss:hover { background: #fee2e2; color: var(--text-error); transform: rotate(90deg); }
.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; }
.auth-tab-switch { display: flex; background: var(--bg-secondary); padding: 6px; border-radius: var(--radius-md); margin-bottom: 28px; }
.auth-tab-item { flex: 1; padding: 14px; text-align: center; border-radius: var(--radius-sm); font-size: 15px; font-weight: 800; color: var(--text-secondary); cursor: pointer; transition: var(--ease-fast); }
.auth-tab-item.active { background: var(--bg-primary); color: var(--text-primary); box-shadow: var(--shadow-sm); }
.auth-form-view { display: none; flex-direction: column; animation: slideIn 0.3s ease; }
.auth-form-view.active { display: flex; }
.auth-input-element { width: 100%; padding: 18px; border: 2px solid var(--border-light); border-radius: var(--radius-md); font-size: 16px; outline: none; background: var(--bg-secondary); transition: var(--ease-fast); font-family: var(--font-sans); margin-bottom: 20px; font-weight: 500; }
.auth-input-element:focus { border-color: var(--brand-saffron); background: var(--bg-primary); box-shadow: 0 0 0 4px var(--brand-saffron-light); }
.btn-auth-execute { width: 100%; padding: 18px; background: var(--text-primary); color: var(--brand-white); border: none; border-radius: var(--radius-md); font-size: 16px; font-weight: 800; cursor: pointer; transition: var(--ease-fast); margin-top: 10px; }
.btn-auth-execute:hover { background: #000000; transform: translateY(-2px); box-shadow: var(--shadow-md); }
.btn-auth-return { width: 100%; padding: 14px; background: transparent; color: var(--text-tertiary); border: none; font-size: 15px; font-weight: 700; cursor: pointer; margin-top: 10px; transition: 0.2s; }
.btn-auth-return:hover { color: var(--text-primary); }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideIn { from { opacity: 0; transform: translateX(25px); } to { opacity: 1; transform: none; } }
/* Cursor & Loading UI */
.typing-cursor { display: inline-block; width: 10px; height: 18px; background: var(--brand-saffron); margin-left: 4px; animation: cursorBlink 1s step-end infinite; vertical-align: middle; }
@keyframes cursorBlink { 50% { opacity: 0; } }
.loading-dots-container { display: flex; align-items: center; gap: 6px; padding: 6px; }
.loading-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-tertiary); opacity: 0.4; animation: dotBounce 1.4s infinite ease-in-out both; }
.loading-dot:nth-child(1) { animation-delay: -0.32s; } .loading-dot:nth-child(2) { animation-delay: -0.16s; }
@keyframes dotBounce { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } }
/* ---------------------------------------------------------------------------------------
M. RESPONSIVE DESIGN (MOBILE & TABLET ADAPTATIONS)
--------------------------------------------------------------------------------------- */
@media (max-width: 1024px) {
.code-workspace-panel.expanded { width: 100%; position: absolute; top: 0; left: 0; height: 100%; z-index: 2000; }
}
@media (max-width: 900px) {
.sidebar-container { position: absolute; left: -320px; z-index: 1000; height: 100%; box-shadow: var(--shadow-float); }
.sidebar-container.active { left: 0; }
.btn-hamburger { display: flex; }
.btn-mobile-close { display: flex; }
.chat-scroll-area { padding: 24px 15px; }
.input-dock { padding: 10px 15px 20px; }
.chat-message-row { max-width: 98%; }
.btn-scroll-trigger { bottom: 130px; }
.hero-greeting { font-size: 32px; }
.prompt-suggestions-grid { grid-template-columns: 1fr; }
.input-tools-row { flex-wrap: wrap; }
.main-textarea { min-width: 100%; order: -1; margin-bottom: 10px; }
.interim-text-overlay { left: 15px; top: 12px; }
}
</style>
</head>
<body>
<!-- =========================================================================================
DOM STRUCTURE: OFFLINE BANNER
========================================================================================= -->
<div id="networkStatusBanner" class="network-offline-banner">
<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>
System Offline. Please check your internet connection.
</div>
<!-- =========================================================================================
DOM STRUCTURE: NOTIFICATIONS
========================================================================================= -->
<div id="toast-container" class="toast-wrapper"></div>
<!-- =========================================================================================
DOM STRUCTURE: STARTUP OVERLAY
========================================================================================= -->
<div class="startup-overlay" id="welcomeOverlay">
<div class="startup-logo-container">
<div class="startup-logo-glow"></div>
<img src="https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png" alt="Arjun Core Identity">
</div>
<h1 class="startup-title">Welcome to Arjun 2.O</h1>
<p class="startup-desc">Professional Enterprise Edition. Experience secure workspace logic generation, high-fidelity visual rendering, and zero-latency live conversational mode.</p>
<button class="btn-startup-launch" id="btnLaunchSystem">
Initialize System
<svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>
</button>
</div>
<!-- =========================================================================================
DOM STRUCTURE: LIVE MODE FULLSCREEN OVERLAY
========================================================================================= -->
<div class="live-mode-viewport" id="liveOverlay">
<button class="btn-close-live" id="btnExitLiveMode" title="Exit Live Mode">
<svg viewBox="0 0 24 24" 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>
</button>
<div class="pulsing-orb-wrapper">
<div class="energy-ring"></div>
<div class="energy-ring"></div>
<div class="energy-ring"></div>
<div class="energy-core" id="liveOrb"></div>
</div>
<div class="live-feedback-status" id="liveStatusText">Initializing Audio Stream...</div>
<div class="live-feedback-text" id="liveTranscriptText">Speak directly to Arjun. Natural language processing active.</div>
<div class="live-control-deck">
<button class="btn-live-deck mic-control" id="liveMicBtn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path><path d="M19 10v2a7 7 0 0 1-14 0v-2"></path><line x1="12" x2="12" y1="19" y2="22"></line></svg>
</button>
</div>
</div>
<!-- =========================================================================================
DOM STRUCTURE: AMBIENT BACKGROUND
========================================================================================= -->
<div class="ambient-environment">
<div class="ambient-orb orb-top-left"></div>
<div class="ambient-orb orb-bottom-right"></div>
</div>
<!-- =========================================================================================
DOM STRUCTURE: MASTER APPLICATION CONTAINER
========================================================================================= -->
<div class="app-root">
<!-- A. NAVIGATION SIDEBAR -->
<aside class="sidebar-container" id="sidebar">
<div class="sidebar-header">
<a href="#" class="brand-identity">
<img src="https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png" alt="Arjun Logo">
<div class="brand-typography">
<span class="brand-name">ARJUN 2.O</span>
<span class="brand-edition">Enterprise</span>
</div>
</a>
<button class="btn-mobile-close" id="btnSidebarClose">
<svg viewBox="0 0 24 24" width="20" height="20" stroke="currentColor" stroke-width="2.5" fill="none"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
</button>
</div>
<div class="sidebar-body">
<!-- Authentication Widget -->
<div class="auth-widget">
<button id="loginPromptBtn" class="btn-secure-connect">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
Secure Login
</button>
<div id="userProfile" class="user-profile-display">
<div class="avatar-badge" id="uAvatar">U</div>
<div class="user-details">
<div class="user-email-id" id="uEmail">user@network.com</div>
<div class="user-clearance-level">Verified Clearance</div>
</div>
<button class="btn-system-logout" id="btnLogout" title="Terminate Session">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line></svg>
</button>
</div>
</div>
<!-- Branding Box -->
<div class="developer-credit-box">
<img src="https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png" alt="Arjun Core Image">
<h3 class="dev-box-title">Arjun Intelligence</h3>
<p class="dev-box-subtitle">ENGINEERED BY ABHAY KUMAR</p>
</div>
<!-- Wipe Memory Button -->
<button class="btn-erase-memory" id="btnClearMemory">
<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>
Wipe Neural Context
</button>
</div>
</aside>
<!-- B. MAIN CHAT ENGINE INTERFACE -->
<main class="main-chat-wrapper">
<!-- Top Status Bar -->
<header class="chat-top-bar">
<div class="top-bar-left">
<button class="btn-hamburger" id="btnSidebarOpen">
<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>
</button>
<div class="system-status-pill" id="mainStatusPill">
<div class="pulse-dot"></div>
<span id="mainStatusText">System Online</span>
</div>
</div>
<!-- LIVE MODE ACTIVATOR -->
<button class="btn-activate-live" id="btnStartLiveMode">
<svg viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5" fill="none"><circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="4" fill="currentColor"></circle></svg>
LIVE MODE
</button>
</header>
<!-- Scrollable Conversation Area -->
<div class="chat-scroll-area" id="msgs">
<!-- Internal Welcome / Guest Warning State -->
<div class="chat-hero-section" id="welcomeState">
<div class="hero-avatar-wrapper">
<div class="hero-avatar-glow"></div>
<img src="https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png" alt="Arjun Logo Large">
</div>
<h2 class="hero-greeting">How can I assist you today?</h2>
<p class="hero-description">Experience next-generation reasoning, seamless multi-file analysis, and secure workspace code generation engineered by Abhay Kumar.</p>
<!-- GUEST BADGE LIMIT DISPLAY -->
<div id="guestBadge" class="guest-warning-badge">
<svg viewBox="0 0 24 24" 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>
Guest Mode Active: <span id="guestCountDisplay">0</span>/3 Queries Used. Please login.
</div>
<div class="prompt-suggestions-grid">
<div class="prompt-card" id="suggCodeBtn">
<span class="prompt-icon">💻</span>
<div class="prompt-title">Generate Production Code</div>
<div class="prompt-desc">Create secure, workspace-ready architecture instantly.</div>
</div>
<div class="prompt-card" id="suggImgBtn">
<span class="prompt-icon">🎨</span>
<div class="prompt-title">Render Stunning Visions</div>
<div class="prompt-desc">Utilize advanced AI to paint your imagination.</div>
</div>
</div>
</div>
</div>
<!-- Floating Scroll Down Button -->
<button class="btn-scroll-trigger" id="scrollTriggerBtn">
<svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="6 9 12 15 18 9"></polyline></svg>
</button>
<!-- Bottom Input Dock -->
<div class="input-dock">
<div class="input-master-container">
<!-- File Preview Component -->
<div class="upload-preview-bar" id="filePreviewBar">
<img class="upload-thumb" id="previewImgThumb" src="" alt="Thumbnail" style="display:none;">
<div class="upload-thumb" id="previewDocIcon" style="display:none;">📄</div>
<div class="upload-meta">
<div class="upload-filename" id="previewFileName">document.pdf</div>
<div class="upload-status-text">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"></polyline></svg>
File ready to be transmitted
</div>
</div>
<button class="btn-discard-upload" id="btnDiscardFile" title="Remove Attachment">
<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>
</button>
</div>
<!-- Main Tool & Input Row -->
<div class="input-tools-row">
<!-- Attachment Dropdown Module -->
<div class="attachment-module">
<button class="btn-tool-icon" id="btnAttachMenuToggle" title="Attach File">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path></svg>
</button>
<div class="attachment-dropdown" id="attachDropdownMenu">
<div class="dropdown-item" id="opt-image">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline></svg>
High-Res Image
</div>
<div class="dropdown-item" id="opt-video">
<svg viewBox="0 0 24 24" 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>
Video Media
</div>
<div class="dropdown-item" id="opt-audio">
<svg viewBox="0 0 24 24" 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>
Audio Track
</div>
<div class="dropdown-item" id="opt-document">
<svg viewBox="0 0 24 24" 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>
Document / Code
</div>
</div>
<!-- Hidden File Inputs -->
<input type="file" id="sys-inp-image" class="stealth-input" accept="image/*">
<input type="file" id="sys-inp-video" class="stealth-input" accept="video/*">
<input type="file" id="sys-inp-audio" class="stealth-input" accept="audio/*">
<input type="file" id="sys-inp-document" class="stealth-input" accept=".pdf,.doc,.docx,.txt,.md,.csv,.json,.py,.js,.html,.css,.cpp,.c,.java">
</div>
<!-- Smart Language Toggle Button (Bilingual STT logic) -->
<button class="language-toggle-chip" id="smartLangToggle" title="Toggle Voice Engine Language">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>
<span id="langDisplayBadge">EN</span>
</button>
<!-- Voice Dictation Button -->
<button class="btn-tool-icon btn-mic-tool" id="masterVoiceBtn" title="Voice Dictation">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path><path d="M19 10v2a7 7 0 0 1-14 0v-2"></path><line x1="12" x2="12" y1="19" y2="22"></line></svg>
</button>
<!-- Expanding Text Area -->
<div style="flex:1; position: relative;">
<!-- STT Interim Feedback Overlay -->
<div id="interimTextOverlay" class="interim-text-overlay"></div>
<textarea class="main-textarea" id="mainChatInput" placeholder="Message Arjun Intelligence..." rows="1" style="width: 100%;"></textarea>
</div>
<!-- Master Send Button -->
<button class="btn-master-send" id="masterSendBtn">
<svg viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
</button>
</div>
</div>
<div class="bottom-branding-text">Secured by Arjun Core Architecture • Developed by Abhay Kumar</div>
</div>
</main>
<!-- C. WORKSPACE CODE EDITOR PANEL -->
<aside class="code-workspace-panel" id="workspacePanel">
<div class="workspace-header-bar">
<div class="workspace-title-group">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg>
<span id="wsTitleText">Workspace Logic</span>
</div>
<div class="workspace-tools">
<button class="btn-workspace-tool" id="btnWsCopy">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
Copy Source
</button>
<button class="btn-workspace-tool close" id="btnWsClose" title="Close Editor">
<svg viewBox="0 0 24 24" width="18" height="18" 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>
</button>
</div>
</div>
<div class="workspace-editor-surface">
<div class="workspace-editor-content">
<div class="workspace-line-numbers" id="wsLineNumbers">1</div>
<pre><code id="workspaceCodeBlock" class="hljs"></code></pre>
</div>
</div>
</aside>
</div>
<!-- =========================================================================================
DOM STRUCTURE: SECURE AUTHENTICATION MODAL
========================================================================================= -->
<div class="secure-modal-backdrop" id="secureAuthModal">
<div class="secure-modal-surface">
<button class="btn-modal-dismiss" id="btnAuthClose">
<svg viewBox="0 0 24 24" 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>
</button>
<div class="modal-brand-header">Arjun Network</div>
<div class="auth-tab-switch">
<div class="auth-tab-item active" id="btn-tab-login">Connect</div>
<div class="auth-tab-item" id="btn-tab-register">Enroll</div>
</div>
<!-- Login Flow -->
<div id="auth-flow-login">
<div class="auth-form-view active" id="auth-log-phase-1">
<input type="email" class="auth-input-element" id="authLogEmail" placeholder="Authorized Email Address">
<button class="btn-auth-execute" id="btn-fire-log-otp">Generate Secure Token (OTP)</button>
</div>
<div class="auth-form-view" id="auth-log-phase-2">
<input type="number" class="auth-input-element" id="authLogOTP" placeholder="Validation Code (OTP)">
<button class="btn-auth-execute" id="btn-fire-log-verify">Authenticate Session</button>
<button class="btn-auth-return" id="btnLogBack">← Return</button>
</div>
</div>
<!-- Register Flow -->
<div id="auth-flow-register" style="display:none;">
<div class="auth-form-view active" id="auth-reg-phase-1">
<input type="text" class="auth-input-element" id="authRegName" placeholder="Full Legal Name">
<input type="email" class="auth-input-element" id="authRegEmail" placeholder="Communication Email">
<button class="btn-auth-execute" id="btn-fire-reg-otp">Verify Identity</button>
</div>
<div class="auth-form-view" id="auth-reg-phase-2">
<input type="number" class="auth-input-element" id="authRegOTP" placeholder="Identity Token (OTP)">
<button class="btn-auth-execute" id="btn-fire-reg-verify">Initialize Account</button>
<button class="btn-auth-return" id="btnRegBack">← Return</button>
</div>
</div>
</div>
</div>
<!-- =========================================================================================
MASSIVE ENTERPRISE JAVASCRIPT ARCHITECTURE
========================================================================================= -->
<script>
// =======================================================================================
// 1. CONFIGURATION & STATE MANAGEMENT
// =======================================================================================
const Config = {
GAS_URL: "https://script.google.com/macros/s/AKfycbzTsXGoVh97JjtFAAG825GF4WUZqf7FDB3Zbxyf0nrLXt_1HjJSSqA829UcdoamRPvg0A/exec",
LOGO_URL: "https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png",
PDF_WORKER: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js',
API_ENDPOINT: '/api/chat', // Uses relative path to connect to Flask App.py
MAX_FILE_SIZE_MB: 10, // Prevent UI freeze on giant files
};
// Initialize PDF worker
if (typeof pdfjsLib !== 'undefined') {
pdfjsLib.GlobalWorkerOptions.workerSrc = Config.PDF_WORKER;
}
const AppState = {
currentUser: localStorage.getItem('arjun_user') || null,
guestCount: parseInt(localStorage.getItem('arjun_guest') || '0', 10),
history: [],
pendingAttachment: null,
isProcessing: false,
isUserScrolling: false,
generatedCodeBlocks: [],
currentWorkspaceId: null,
isStreamingActive: false,
isLiveModeEngaged: false,
gradioClient: null,
isMicRecording: false,
isOnline: navigator.onLine
};
// Initialize Gradio Client Dynamically for TTS
window.initGradioEngine = async function() {
try {
const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS");
console.log("Neural TTS Engine connected successfully to Gradio.");
} catch(err) {
console.warn("Gradio Connection Warning:", err.message);
// Non-blocking failure, app still works
}
};
window.initGradioEngine();
// =======================================================================================
// 2. UTILITY ENGINE (Robust Copy, Notifications, and Text Cleaners)
// =======================================================================================
const Utils = {
showToast: (message, type = 'info') => {
const container = document.getElementById('toast-container');
const toast = document.createElement('div');
toast.className = `toast-notification ${type}`;
let icon = '<polyline points="20 6 9 17 4 12"></polyline>'; // Checkmark
if (type === 'error') icon = '<line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line>';
toast.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">${icon}</svg> ${Utils.escapeHTML(message)}`;
container.appendChild(toast);
setTimeout(() => { if (toast.parentNode) toast.remove(); }, 3500);
},
escapeHTML: (str) => {
if (str === null || str === undefined) return '';
return String(str).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
},
// ✨ Intelligent Text Cleaner for TTS (Ignores code, links, images)
cleanTextForVoice: (rawText) => {
if(!rawText) return "";
let cleaned = String(rawText);
// Remove Markdown Elements sequentially to prevent regex conflicts
cleaned = cleaned.replace(/```[\s\S]*?```/g, ''); // Code blocks
cleaned = cleaned.replace(/`.*?`/g, ''); // Inline code
cleaned = cleaned.replace(/!\[.*?\]\(.*?\)/g, ''); // Images
cleaned = cleaned.replace(/\[(.*?)\]\(.*?\)/g, '$1'); // Links
cleaned = cleaned.replace(/<think>[\s\S]*?<\/think>/gi, ''); // Think Tags
cleaned = cleaned.replace(/https?:\/\/[^\s]+/g, ''); // Bare URLs
cleaned = cleaned.replace(/[*_~#|-]/g, ''); // Formatting symbols
return cleaned.trim();
},
// Robust Fallback Copy Mechanism
executeFallbackCopy: (text, btnElement) => {
const textArea = document.createElement("textarea");
textArea.value = text;
textArea.style.top = "0"; textArea.style.left = "0"; textArea.style.position = "fixed";
textArea.style.opacity = "0";
document.body.appendChild(textArea);
textArea.focus(); textArea.select();
try {
const successful = document.execCommand('copy');
if (successful) {
const originalHTML = btnElement.innerHTML;
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`;
setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
} else {
Utils.showToast("Clipboard access denied by browser.", "error");
}
} catch (err) {
Utils.showToast("System error copying text.", "error");
}
document.body.removeChild(textArea);
},
copyToClipboard: (btnElement, textToCopy) => {
if (!navigator.clipboard) {
Utils.executeFallbackCopy(textToCopy, btnElement);
return;
}
navigator.clipboard.writeText(textToCopy).then(() => {
const originalHTML = btnElement.innerHTML;
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`;
setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
}).catch((err) => {
console.warn('Modern API failed, utilizing fallback...', err);
Utils.executeFallbackCopy(textToCopy, btnElement);
});
}
};
// =======================================================================================
// 3. AUTHENTICATION & SYNC MANAGER
// =======================================================================================
const AuthManager = {
initUI: () => {
const promptBtn = document.getElementById('loginPromptBtn');
const profileCard = document.getElementById('userProfile');
const guestBadge = document.getElementById('guestBadge');
if (AppState.currentUser) {
promptBtn.style.display = 'none';
profileCard.style.display = 'flex';
document.getElementById('uEmail').innerText = AppState.currentUser;
document.getElementById('uAvatar').innerText = AppState.currentUser.charAt(0).toUpperCase();
if(guestBadge) guestBadge.style.display = 'none';
} else {
promptBtn.style.display = 'flex';
profileCard.style.display = 'none';
if(guestBadge) {
guestBadge.style.display = 'inline-flex';
document.getElementById('guestCountDisplay').innerText = AppState.guestCount;
}
}
},
openModal: () => { document.getElementById('secureAuthModal').style.display = 'flex'; },
closeModal: () => { document.getElementById('secureAuthModal').style.display = 'none'; },
switchTab: (tabName) => {
document.querySelectorAll('.auth-tab-item').forEach(el => el.classList.remove('active'));
document.getElementById(tabName === 'login' ? 'btn-tab-login' : 'btn-tab-register').classList.add('active');
document.getElementById('auth-flow-login').style.display = tabName === 'login' ? 'block' : 'none';
document.getElementById('auth-flow-register').style.display = tabName === 'register' ? 'block' : 'none';
},
switchPhase: (currentId, nextId) => {
document.getElementById(currentId).classList.remove('active');
document.getElementById(nextId).classList.add('active');
},
process: async (actionType) => {
if (!AppState.isOnline) return Utils.showToast("System is offline. Cannot authenticate.", "error");
const payload = { action: actionType };
let buttonId = '';
if (actionType === 'register_send_otp') {
payload.name = document.getElementById('authRegName').value.trim();
payload.email = document.getElementById('authRegEmail').value.trim();
payload.phone = "0000000000"; payload.organization = "Arjun Base";
if (!payload.email || !payload.name) return Utils.showToast("Identification details required.", "error");
buttonId = 'btn-fire-reg-otp';
}
else if (actionType === 'login_send_otp') {
payload.email = document.getElementById('authLogEmail').value.trim();
if (!payload.email) return Utils.showToast("Email required for validation.", "error");
buttonId = 'btn-fire-log-otp';
}
else if (actionType === 'register_verify' || actionType === 'login_verify') {
payload.email = document.getElementById(actionType === 'register_verify' ? 'authRegEmail' : 'authLogEmail').value.trim();
payload.otp = document.getElementById(actionType === 'register_verify' ? 'authRegOTP' : 'authLogOTP').value.trim();
if (!payload.otp) return Utils.showToast("Security token required.", "error");
buttonId = actionType === 'register_verify' ? 'btn-fire-reg-verify' : 'btn-fire-log-verify';
}
const triggerBtn = document.getElementById(buttonId);
const originalText = triggerBtn.innerHTML;
triggerBtn.disabled = true;
triggerBtn.innerText = 'Establishing Connection...';
try {
const response = await fetch(Config.GAS_URL, {
method: 'POST',
mode: 'cors',
headers: { 'Content-Type': 'text/plain;charset=utf-8' },
body: JSON.stringify(payload)
});
const result = await response.json();
if (result.status === 'success') {
Utils.showToast(result.message, "success");
if (actionType === 'register_send_otp') AuthManager.switchPhase('auth-reg-phase-1', 'auth-reg-phase-2');
else if (actionType === 'login_send_otp') AuthManager.switchPhase('auth-log-phase-1', 'auth-log-phase-2');
else if (actionType === 'register_verify' || actionType === 'login_verify') {
AppState.currentUser = payload.email;
localStorage.setItem('arjun_user', AppState.currentUser);
AuthManager.closeModal();
AuthManager.initUI();
ChatEngine.syncHistoryFromCloud();
}
} else {
Utils.showToast(result.message, "error");
}
} catch (error) {
console.error("Auth Network Error: ", error);
Utils.showToast("Encrypted gateway error. Check network.", "error");
}
triggerBtn.disabled = false;
triggerBtn.innerHTML = originalText;
},
logout: () => {
localStorage.removeItem('arjun_user');
location.reload();
}
};
// =======================================================================================
// 4. UI & DOM MANAGER
// =======================================================================================
const UIManager = {
toggleSidebar: () => { document.getElementById('sidebar').classList.toggle('active'); },
checkScrollState: () => {
const msgArea = document.getElementById('msgs');
const isAtBottom = Math.abs((msgArea.scrollHeight - msgArea.scrollTop) - msgArea.clientHeight) < 80;
AppState.isUserScrolling = !isAtBottom;
const scrollBtn = document.getElementById('scrollTriggerBtn');
if (AppState.isUserScrolling) scrollBtn.classList.add('visible');
else scrollBtn.classList.remove('visible');
},
forceScrollDown: () => {
const msgArea = document.getElementById('msgs');
msgArea.scrollTo({ top: msgArea.scrollHeight, behavior: 'smooth' });
AppState.isUserScrolling = false;
document.getElementById('scrollTriggerBtn').classList.remove('visible');
},
autoScroll: () => {
if (!AppState.isUserScrolling) {
const msgArea = document.getElementById('msgs');
msgArea.scrollTop = msgArea.scrollHeight;
}
},
autoGrowTextArea: (element) => {
element.style.height = 'auto';
element.style.height = Math.min(element.scrollHeight, 200) + 'px';
},
toggleAttachMenu: () => {
document.getElementById('attachDropdownMenu').classList.toggle('visible');
},
updateNetworkStatus: () => {
AppState.isOnline = navigator.onLine;
const banner = document.getElementById('networkStatusBanner');
const pill = document.getElementById('mainStatusPill');
const pillText = document.getElementById('mainStatusText');
if (AppState.isOnline) {
banner.classList.remove('active');
pill.classList.remove('offline');
pillText.innerText = 'System Online';
if(!AppState.isProcessing && AppState.history.length > 0) {
Utils.showToast("Network connection restored.", "success");
}
} else {
banner.classList.add('active');
pill.classList.add('offline');
pillText.innerText = 'System Offline';
}
}
};
// =======================================================================================
// 5. THE BUG-FREE SPEECH & TTS ENGINE (STT DUPLICATION FIX IMPLEMENTED)
// =======================================================================================
const VoiceEngine = {
recognition: null,
currentLanguage: 'en-IN',
silenceTimer: null,
liveSessionText: "",
init: () => {
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
if (!SR) {
console.warn("Speech Recognition API not supported in this browser.");
document.getElementById('masterVoiceBtn').style.display = 'none';
return;
}
VoiceEngine.recognition = new SR();
VoiceEngine.recognition.continuous = true;
VoiceEngine.recognition.interimResults = true;
VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
VoiceEngine.recognition.onstart = () => {
AppState.isMicRecording = true;
document.getElementById('masterVoiceBtn').classList.add('active-listening');
VoiceEngine.liveSessionText = "";
if (AppState.isLiveModeEngaged) {
document.getElementById('liveMicBtn').classList.add('is-recording');
document.getElementById('liveStatusText').innerText = "Listening...";
document.getElementById('liveOrb').classList.remove('speaking');
document.getElementById('liveOrb').style.transform = "scale(1.25)";
}
};
VoiceEngine.recognition.onresult = (event) => {
if (VoiceEngine.silenceTimer) clearTimeout(VoiceEngine.silenceTimer);
let finalTranscript = '';
let interimTranscript = '';
// ✨ The Standard Loop - Prevents all Duplication and Undefined errors
for (let i = event.resultIndex; i < event.results.length; ++i) {
let transcriptSegment = event.results[i].transcript;
if (transcriptSegment === undefined || transcriptSegment === null) continue;
if (event.results[i].isFinal) {
finalTranscript += transcriptSegment;
} else {
interimTranscript += transcriptSegment;
}
}
if (AppState.isLiveModeEngaged) {
if (finalTranscript) {
VoiceEngine.liveSessionText += (VoiceEngine.liveSessionText ? ' ' : '') + finalTranscript.trim();
}
let displayString = (VoiceEngine.liveSessionText + ' ' + interimTranscript).trim();
if (displayString) {
document.getElementById('liveTranscriptText').innerText = `"${displayString}"`;
document.getElementById('mainChatInput').value = displayString;
}
// Silence Detector
VoiceEngine.silenceTimer = setTimeout(() => {
if (document.getElementById('mainChatInput').value.trim().length > 0) {
VoiceEngine.recognition.stop();
}
}, 1800);
} else {
// Regular Chat Text Box Appending
if (finalTranscript) {
const inputField = document.getElementById('mainChatInput');
let currentVal = inputField.value;
const separator = (currentVal && !currentVal.endsWith(' ')) ? ' ' : '';
inputField.value = currentVal + separator + finalTranscript.trim();
UIManager.autoGrowTextArea(inputField);
}
// Show visual feedback for interim vs final
const interimOverlay = document.getElementById('interimTextOverlay');
if (interimTranscript) {
interimOverlay.innerText = interimTranscript.trim();
interimOverlay.classList.add('active');
} else {
interimOverlay.classList.remove('active');
}
}
};
VoiceEngine.recognition.onend = () => {
AppState.isMicRecording = false;
document.getElementById('masterVoiceBtn').classList.remove('active-listening');
document.getElementById('interimTextOverlay').classList.remove('active');
if (AppState.isLiveModeEngaged) {
document.getElementById('liveMicBtn').classList.remove('is-recording');
document.getElementById('liveOrb').style.transform = "scale(1)";
const currentInput = document.getElementById('mainChatInput').value.trim();
if (currentInput !== '' && !AppState.isProcessing) {
document.getElementById('liveStatusText').innerText = "Processing...";
ChatEngine.initiateDispatch();
} else if (!AppState.isProcessing) {
document.getElementById('liveStatusText').innerText = "Tap mic to interact";
}
}
};
VoiceEngine.recognition.onerror = (event) => {
AppState.isMicRecording = false;
if(event.error !== 'no-speech' && event.error !== 'aborted') {
Utils.showToast("Voice module error: " + event.error, "error");
}
document.getElementById('masterVoiceBtn').classList.remove('active-listening');
document.getElementById('interimTextOverlay').classList.remove('active');
if (AppState.isLiveModeEngaged) {
document.getElementById('liveMicBtn').classList.remove('is-recording');
document.getElementById('liveStatusText').innerText = "Audio Failure. Retry.";
}
};
},
switchLanguage: () => {
const btn = document.getElementById('smartLangToggle');
const badge = document.getElementById('langDisplayBadge');
if (VoiceEngine.currentLanguage === 'en-IN') {
VoiceEngine.currentLanguage = 'hi-IN';
badge.innerText = 'हि';
btn.classList.add('hindi-active');
Utils.showToast("Listening Protocol: Hindi (देवनागरी)", "success");
} else {
VoiceEngine.currentLanguage = 'en-IN';
badge.innerText = 'EN';
btn.classList.remove('hindi-active');
Utils.showToast("Listening Protocol: English", "success");
}
if (VoiceEngine.recognition) {
VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
if(AppState.isMicRecording) {
VoiceEngine.recognition.stop();
// Slight delay to allow system to halt before restarting
setTimeout(() => { try{VoiceEngine.recognition.start();}catch(e){} }, 400);
}
}
},
toggleDictation: () => {
if (!VoiceEngine.recognition) return Utils.showToast("Hardware dictation unsupported in this browser.", "error");
try {
if(AppState.isMicRecording) {
VoiceEngine.recognition.stop();
} else {
VoiceEngine.recognition.start();
}
} catch (e) { console.error("Mic Start Error", e); }
},
executeTTS: async (rawText) => {
const cleanSpeechText = Utils.cleanTextForVoice(rawText);
if(!cleanSpeechText.trim()) {
Utils.showToast("No readable conversational text found in this block.", "error");
return;
}
Utils.showToast("🔊 Linking with Neural Voice Matrix...");
if (AppState.isLiveModeEngaged) {
document.getElementById('liveOrb').classList.add('speaking');
}
try {
if(!AppState.gradioClient) {
const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS");
}
const result = await AppState.gradioClient.predict("/smart_hybrid_tts", {
text: cleanSpeechText,
voice_type: "प्रभात (भारी और प्राकृतिक आवाज़ - हिंग्लिश के लिए)"
});
if (result.data && result.data) {
const audioUrl = typeof result.data === 'string' ? result.data : result.data.url;
const audio = new Audio(audioUrl);
audio.onended = () => {
if (AppState.isLiveModeEngaged) {
document.getElementById('liveOrb').classList.remove('speaking');
document.getElementById('liveStatusText').innerText = "Tap mic to respond";
}
};
audio.play();
} else {
throw new Error("No audio payload returned.");
}
} catch (error) {
Utils.showToast("Voice Neural Matrix is currently overloaded.", "error");
console.error("Gradio TTS Error:", error);
if (AppState.isLiveModeEngaged) {
document.getElementById('liveOrb').classList.remove('speaking');
}
}
}
};
/**
* Live Mode Controller
*/
const LiveModeController = {
initialize: () => {
AppState.isLiveModeEngaged = true;
document.getElementById('liveOverlay').classList.add('active');
if (VoiceEngine.recognition && !AppState.isMicRecording) {
setTimeout(() => {
try { VoiceEngine.recognition.start(); } catch(e){}
}, 600);
}
},
terminate: () => {
AppState.isLiveModeEngaged = false;
document.getElementById('liveOverlay').classList.remove('active');
if (VoiceEngine.recognition && AppState.isMicRecording) {
try { VoiceEngine.recognition.stop(); } catch(e){}
}
}
};
// =======================================================================================
// 6. FILE & DOCUMENT PROCESSOR (Robust & Size Validated)
// =======================================================================================
const FileProcessor = {
triggerFileSelector: (type) => {
document.getElementById('attachDropdownMenu').classList.remove('visible');
document.getElementById('sys-inp-' + type).click();
},
processFile: async (inputElement, typeContext) => {
const file = inputElement.files;
if (!file) return;
// Size Validation to prevent UI thread lock
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > Config.MAX_FILE_SIZE_MB) {
Utils.showToast(`File exceeds ${Config.MAX_FILE_SIZE_MB}MB enterprise limit.`, "error");
inputElement.value = '';
return;
}
const fName = file.name.toLowerCase();
const mime = file.type;
if (typeContext === 'image' && !mime.startsWith('image/')) { Utils.showToast("Visual media required.", "error"); inputElement.value=''; return; }
if (typeContext === 'video' && !mime.startsWith('video/')) { Utils.showToast("Video media required.", "error"); inputElement.value=''; return; }
if (typeContext === 'audio' && !mime.startsWith('audio/')) { Utils.showToast("Audio media required.", "error"); inputElement.value=''; return; }
Utils.showToast(`Analyzing ${file.name}...`, "info");
const thumbImg = document.getElementById('previewImgThumb');
const docIcon = document.getElementById('previewDocIcon');
thumbImg.style.display = 'none';
docIcon.style.display = 'none';
document.getElementById('previewFileName').innerText = file.name;
document.getElementById('filePreviewBar').classList.add('visible');
const fileReader = new FileReader();
if (typeContext === 'image') {
fileReader.onload = (e) => {
AppState.pendingAttachment = { type: 'image', data: e.target.result.split(','), name: file.name };
thumbImg.src = e.target.result;
thumbImg.style.display = 'flex';
};
fileReader.readAsDataURL(file);
}
else if (typeContext === 'video' || typeContext === 'audio') {
fileReader.onload = (e) => {
AppState.pendingAttachment = { type: typeContext, data: e.target.result.split(','), name: file.name };
docIcon.innerText = typeContext === 'video' ? '🎥' : '🎵';
docIcon.style.display = 'flex';
};
fileReader.readAsDataURL(file);
}
else if (typeContext === 'document') {
docIcon.innerText = '📄';
docIcon.style.display = 'flex';
if (fName.endsWith('.pdf')) {
fileReader.onload = async function() {
try {
const typedArray = new Uint8Array(this.result);
const pdfDoc = await pdfjsLib.getDocument(typedArray).promise;
let extractedText = "";
for (let i = 1; i <= pdfDoc.numPages; i++) {
const page = await pdfDoc.getPage(i);
const content = await page.getTextContent();
extractedText += content.items.map(s => s.str).join(' ') + "\n";
}
AppState.pendingAttachment = { type: 'text', data: extractedText.trim() || "No readable text found.", name: file.name };
Utils.showToast("Document payload secured.", "success");
} catch (e) {
Utils.showToast("PDF architecture parsing failed.", "error");
FileProcessor.discardFile();
}
};
fileReader.readAsArrayBuffer(file);
}
else if (fName.endsWith('.docx') || fName.endsWith('.doc')) {
fileReader.onload = async function() {
try {
const buffer = this.result;
const resultData = await mammoth.extractRawText({ arrayBuffer: buffer });
AppState.pendingAttachment = { type: 'text', data: resultData.value.trim() || "No readable text found.", name: file.name };
Utils.showToast("Document payload secured.", "success");
} catch(e) {
Utils.showToast("Document architecture parsing failed.", "error");
FileProcessor.discardFile();
}
};
fileReader.readAsArrayBuffer(file);
}
else {
fileReader.onload = (e) => {
AppState.pendingAttachment = { type: 'text', data: e.target.result, name: file.name };
Utils.showToast("File payload secured.", "success");
};
fileReader.readAsText(file);
}
}
inputElement.value = '';
},
discardFile: () => {
AppState.pendingAttachment = null;
document.getElementById('filePreviewBar').classList.remove('visible');
document.getElementById('previewImgThumb').src = '';
}
};
// =======================================================================================
// 7. WORKSPACE ENGINE & ADVANCED MARKDOWN RENDERING
// =======================================================================================
const WorkspaceEngine = {
launch: (codeBlockId) => {
AppState.currentWorkspaceId = codeBlockId;
const codeData = AppState.generatedCodeBlocks[codeBlockId];
document.getElementById('wsTitleText').innerText = codeData.lang ? `Generated ${codeData.lang.toUpperCase()}` : "Compiled Logic";
const blockDisplay = document.getElementById('workspaceCodeBlock');
blockDisplay.className = `hljs language-${codeData.lang || 'plaintext'}`;
blockDisplay.textContent = codeData.code;
hljs.highlightElement(blockDisplay);
// Add Line Numbers dynamically
const lineCount = codeData.code.split('\n').length;
let numbersHTML = '';
for(let i=1; i<=lineCount; i++) { numbersHTML += `${i}<br>`; }
document.getElementById('wsLineNumbers').innerHTML = numbersHTML;
document.getElementById('workspacePanel').classList.add('expanded');
if (window.innerWidth <= 1024) {
document.getElementById('sidebar').classList.remove('active');
}
},
closePanel: () => { document.getElementById('workspacePanel').classList.remove('expanded'); },
executeCopy: (btnElement) => {
if (AppState.currentWorkspaceId !== null) {
const srcCode = AppState.generatedCodeBlocks[AppState.currentWorkspaceId].code;
Utils.copyToClipboard(btnElement, srcCode);
}
}
};
// Custom Marked Renderer for UI perfection
const MD_Renderer = new marked.Renderer();
MD_Renderer.code = function(token) {
const rawCode = typeof token === 'string' ? token : (token.text || '');
const langClass = typeof token === 'string' ? arguments : (token.lang || '');
if (AppState.isStreamingActive) {
return `
<div class="streaming-code-container">
<div class="streaming-code-header">
<div class="loading-ring"></div>
Generating Secure Architecture...
</div>
<pre><code class="language-${Utils.escapeHTML(langClass)}">${Utils.escapeHTML(rawCode)}</code></pre>
</div>`;
}
const internalId = AppState.generatedCodeBlocks.length;
AppState.generatedCodeBlocks.push({ code: rawCode, lang: langClass });
return `
<div class="workspace-execute-card">
<div class="ws-card-left">
<div class="ws-card-icon-box">
<svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg>
</div>
<div class="ws-card-details">
<h4>Code Module Compiled</h4>
<p>${Utils.escapeHTML(langClass) || 'Syntax Module'}</p>
</div>
</div>
<button class="btn-launch-workspace btn-launch-ws" data-id="${internalId}">Open Workspace</button>
</div>`;
};
MD_Renderer.table = function(token) {
let html = '<table>';
if (token.header) {
html += '<thead><tr>';
token.header.forEach(th => { html += `<th>${marked.parseInline(th.text)}</th>`; });
html += '</tr></thead>';
}
if (token.rows) {
html += '<tbody>';
token.rows.forEach(tr => {
html += '<tr>';
tr.forEach(td => { html += `<td>${marked.parseInline(td.text)}</td>`; });
html += '</tr>';
});
html += '</tbody>';
}
html += '</table>';
return html;
};
marked.use({ renderer: MD_Renderer, breaks: true, gfm: true });
// Event delegation for dynamically generated workspace buttons
document.getElementById('msgs').addEventListener('click', function(e) {
if (e.target && e.target.classList.contains('btn-launch-ws')) {
const blockId = e.target.getAttribute('data-id');
WorkspaceEngine.launch(blockId);
}
});
// =======================================================================================
// 8. CORE CHAT ENGINE & LLM LOGIC
// =======================================================================================
const ChatEngine = {
handleKeyboard: (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
ChatEngine.initiateDispatch();
}
},
sendExample: (queryText) => {
document.getElementById('mainChatInput').value = queryText;
ChatEngine.initiateDispatch();
},
clearMemory: async () => {
if(!confirm("Are you sure you want to wipe the neural context? This action cannot be undone.")) return;
if (AppState.currentUser) {
Utils.showToast("Purging neural link memory...", "info");
try {
await fetch(Config.GAS_URL, {
method: 'POST',
mode: 'cors',
headers: { 'Content-Type': 'text/plain;charset=utf-8' },
body: JSON.stringify({ action: "delete_history", email: AppState.currentUser })
});
} catch(e) {}
}
location.reload();
},
syncHistoryFromCloud: async () => {
if (!AppState.isOnline) return;
const messageZone = document.getElementById('msgs');
document.getElementById('welcomeState').style.display = 'none';
messageZone.innerHTML = '<div style="text-align:center; padding:80px; font-weight:800; color:var(--brand-saffron); font-size:18px;">Decrypting Historic Archives...</div>';
try {
const response = await fetch(Config.GAS_URL, {
method: 'POST',
mode: 'cors',
headers: { 'Content-Type': 'text/plain;charset=utf-8' },
body: JSON.stringify({ action: "get_history", email: AppState.currentUser })
});
const resData = await response.json();
messageZone.innerHTML = '';
if (resData.status === 'success' && resData.historyJSON !== "[]") {
AppState.history = JSON.parse(resData.historyJSON);
AppState.history.forEach(msgObj => {
if (msgObj.role === 'user') {
ChatEngine.renderUserMessage(msgObj.content, msgObj.badge, msgObj.previewHTML);
} else {
AppState.isStreamingActive = false;
ChatEngine.renderBotMessage(msgObj.content, true);
}
});
setTimeout(UIManager.forceScrollDown, 150);
} else {
document.getElementById('welcomeState').style.display = 'flex';
}
} catch (err) {
messageZone.innerHTML = '';
document.getElementById('welcomeState').style.display = 'flex';
}
},
saveHistoryToCloud: () => {
if (AppState.currentUser && AppState.isOnline) {
fetch(Config.GAS_URL, {
method: 'POST',
mode: 'cors',
headers: { 'Content-Type': 'text/plain;charset=utf-8' },
body: JSON.stringify({ action: "save_history", email: AppState.currentUser, historyJSON: JSON.stringify(AppState.history) })
});
}
},
buildPreviewHTML: (attachmentObj) => {
if (!attachmentObj) return '';
if (attachmentObj.type === 'image') {
return `<img src="data:image/jpeg;base64,${Utils.escapeHTML(attachmentObj.data)}" class="chat-in-bubble-img" alt="Attached Media">`;
} else if (attachmentObj.type === 'video') {
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>`;
} else if (attachmentObj.type === 'audio') {
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>`;
} else {
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>`;
}
},
renderUserMessage: (textContent, badgeText, previewHTMLString = '') => {
let badgeNode = badgeText ? `<div class="file-badge"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path></svg> ${Utils.escapeHTML(badgeText)}</div>` : '';
let visibleText = textContent || '';
if(visibleText.includes('---DATA BEGIN---')) {
const parts = visibleText.split('User Prompt:');
if(parts.length > 1) visibleText = parts.trim();
}
const bubbleBox = document.createElement('div');
bubbleBox.className = 'chat-message-row user-msg';
bubbleBox.innerHTML = `
<div class="msg-avatar">U</div>
<div class="msg-content-column">
${badgeNode}
<div class="chat-bubble">
${previewHTMLString}
${Utils.escapeHTML(visibleText)}
</div>
</div>`;
document.getElementById('msgs').appendChild(bubbleBox);
},
renderBotMessage: (textContent, bypassStreamFormatting = false) => {
const bubbleBox = document.createElement('div');
bubbleBox.className = 'chat-message-row bot-msg';
bubbleBox.innerHTML = `
<div class="msg-avatar"><img src="${Config.LOGO_URL}" alt="AI"></div>
<div class="msg-content-column">
<div class="chat-bubble"></div>
</div>`;
document.getElementById('msgs').appendChild(bubbleBox);
ChatEngine.updateBotBubble(bubbleBox, textContent || '', !bypassStreamFormatting);
return bubbleBox;
},
updateBotBubble: (bubbleDOM, rawMarkup, isCurrentlyStreaming) => {
if(!rawMarkup) rawMarkup = '';
const contentTarget = bubbleDOM.querySelector('.chat-bubble');
const strippedMarkup = rawMarkup.replace(/<think>([\s\S]*?)(<\/think>|$)/gi, '');
let renderHTML = marked.parse(strippedMarkup.trim());
if (isCurrentlyStreaming) {
renderHTML += `<div class="loading-dots-container"><div class="loading-dot"></div><div class="loading-dot"></div><div class="loading-dot"></div></div>`;
}
contentTarget.innerHTML = renderHTML;
let actionTray = bubbleDOM.querySelector('.bot-actions-row');
if (!isCurrentlyStreaming && !actionTray && strippedMarkup.trim().length > 0) {
const safeRawCopy = strippedMarkup.replace(/"/g, '&quot;').replace(/'/g, "\\'").replace(/\n/g, '\\n').replace(/\r/g, '');
const safeRawTTS = strippedMarkup.replace(/"/g, '&quot;').replace(/'/g, "\\'").replace(/\n/g, ' ');
const actionsHTML = `
<div class="bot-actions-row">
<button class="btn-bot-action btn-cpy-action" data-cpy="${safeRawCopy}">
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
Copy Data
</button>
<button class="btn-bot-action action-tts btn-tts-action" data-tts="${safeRawTTS}">
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path></svg>
Read Aloud
</button>
</div>`;
bubbleDOM.querySelector('.msg-content-column').insertAdjacentHTML('beforeend', actionsHTML);
bubbleDOM.querySelector('.btn-cpy-action').addEventListener('click', function() { Utils.copyToClipboard(this, this.getAttribute('data-cpy')); });
bubbleDOM.querySelector('.btn-tts-action').addEventListener('click', function() { VoiceEngine.executeTTS(this.getAttribute('data-tts')); });
}
},
initiateDispatch: async () => {
if (!AppState.isOnline) return Utils.showToast("Cannot process request. System is Offline.", "error");
if (AppState.isProcessing) return;
const inputField = document.getElementById('mainChatInput');
const rawUserText = inputField.value.trim();
if (!rawUserText && !AppState.pendingAttachment) return;
// VALIDATE GUEST LIMIT
if (!AppState.currentUser) {
if (AppState.guestCount >= 3) {
AuthManager.openModal();
return Utils.showToast("Query limit reached. Secure Login required.", "error");
}
AppState.guestCount++;
localStorage.setItem('arjun_guest', AppState.guestCount.toString());
document.getElementById('guestCountDisplay').innerText = AppState.guestCount;
}
// Prepare UI for Dispatch
inputField.value = '';
inputField.style.height = 'auto';
document.getElementById('masterSendBtn').disabled = true;
AppState.isProcessing = true;
const wState = document.getElementById('welcomeState');
if (wState) wState.style.display = 'none';
let payloadStr = rawUserText;
let payloadAttachments = [];
let visualBadge = null;
let previewHTMLForChat = '';
// Attachment Processing Logic
if (AppState.pendingAttachment) {
previewHTMLForChat = ChatEngine.buildPreviewHTML(AppState.pendingAttachment);
if (AppState.pendingAttachment.type === 'text') {
payloadStr = `[Document Analyzed: ${AppState.pendingAttachment.name}]\n\n---DATA BEGIN---\n${AppState.pendingAttachment.data}\n---DATA END---\n\nUser Prompt: ${rawUserText}`;
visualBadge = 'File Appended';
} else {
payloadAttachments.push({
type: AppState.pendingAttachment.type,
data: AppState.pendingAttachment.data,
name: AppState.pendingAttachment.name
});
visualBadge = "Media Appended";
}
ChatEngine.renderUserMessage(rawUserText || '[Transmitting Media Context]', visualBadge, previewHTMLForChat);
AppState.history.push({ role: 'user', content: payloadStr, badge: visualBadge, previewHTML: previewHTMLForChat });
} else {
ChatEngine.renderUserMessage(rawUserText, null, '');
AppState.history.push({ role: 'user', content: rawUserText });
}
FileProcessor.discardFile();
ChatEngine.saveHistoryToCloud();
const activeBotBubble = ChatEngine.renderBotMessage('', false);
UIManager.forceScrollDown();
// Dynamic Pollinations Seed Generator
const cryptographicSeed = Math.floor(Math.random() * 999999999);
// Advanced Cognitive System Instructions
let cognitivePrompt = `You are Arjun 2.O, a highly advanced enterprise AI system architected and engineered by Abhay Kumar.
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.
IMAGE SYNTHESIS OVERRIDE:
When commanded to render, generate, or create an image/photograph, you MUST reply with a precise markdown image node targeting Pollinations AI.
Formula: ![Generating Vision...](https://image.pollinations.ai/prompt/{URL_ENCODED_PROMPT_DETAIL}?width=1024&height=1024&nologo=true&model={MODEL}&seed=${cryptographicSeed})
Available Models: flux, flux-realism, flux-anime, flux-3d.
CRITICAL: The seed parameter is mandatory to bypass cache mechanics. Always render this markdown node inline.`;
if (AppState.isLiveModeEngaged) {
cognitivePrompt += `\n\n[LIVE ACOUSTIC OVERRIDE ACTIVE]: You are currently engaged in a LIVE, REAL-TIME VOCAL INTERFACE.
MANDATORY direct answers. Maximum brevity. Eliminate complex markdown, massive code blocks, or extended lists. Replicate human telephonic brevity perfectly.`;
}
const secureHistory = AppState.history.slice(0, -1).map(h => ({ role: h.role, content: h.content }));
const transmissionPayload = {
message: payloadStr,
attachments: payloadAttachments,
system_prompt: cognitivePrompt,
history: secureHistory,
max_tokens: AppState.isLiveModeEngaged ? 150 : 4096,
temperature: 0.75
};
// Network Transmission Logic
try {
const fetchOp = await fetch(Config.API_ENDPOINT, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(transmissionPayload)
});
if (!fetchOp.ok) throw new Error("API Matrix Disconnected.");
const networkReader = fetchOp.body.getReader();
const textDecoder = new TextDecoder();
let responseBuffer = "";
AppState.isStreamingActive = true;
while (true) {
const { done, value } = await networkReader.read();
if (done) break;
const decodedChunk = textDecoder.decode(value, { stream: true });
const fragmentedLines = decodedChunk.split('\n');
for (let line of fragmentedLines) {
if (line.startsWith('data: ')) {
const parseableStr = line.substring(6);
if (parseableStr.trim() === '[DONE]') continue;
try {
const jsonSegment = JSON.parse(parseableStr);
if (jsonSegment.choices && jsonSegment.choices.delta.content) {
responseBuffer += jsonSegment.choices.delta.content;
ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, true);
UIManager.autoScroll();
}
} catch (e) { }
}
}
}
AppState.isStreamingActive = false;
ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, false);
AppState.history.push({ role: 'bot', content: responseBuffer });
ChatEngine.saveHistoryToCloud();
if (AppState.isLiveModeEngaged) {
document.getElementById('liveStatusText').innerText = "Arjun Transmitting...";
await VoiceEngine.executeTTS(responseBuffer);
}
} catch(error) {
AppState.isStreamingActive = false;
ChatEngine.updateBotBubble(activeBotBubble, `**System Error:** Communication array offline. Verification needed.`, false);
if (AppState.isLiveModeEngaged) {
document.getElementById('liveStatusText').innerText = "Neural Link Severed.";
}
}
AppState.isProcessing = false;
document.getElementById('masterSendBtn').disabled = false;
UIManager.autoScroll();
}
};
// =======================================================================================
// 9. EVENT DELEGATION & BOOTSTRAP INVOCATION
// =======================================================================================
window.startArjunApp = function() {
document.getElementById('welcomeOverlay').classList.add('hidden');
localStorage.setItem('arjun_welcome_seen', 'true');
setTimeout(() => { document.getElementById('welcomeOverlay').style.display = 'none'; }, 400);
};
document.addEventListener('DOMContentLoaded', () => {
// Sidebar Controls
document.getElementById('btnSidebarOpen').addEventListener('click', UIManager.toggleSidebar);
document.getElementById('btnSidebarClose').addEventListener('click', UIManager.toggleSidebar);
document.getElementById('btnLaunchSystem').addEventListener('click', window.startArjunApp);
// Auth Flow Controls
document.getElementById('loginPromptBtn').addEventListener('click', AuthManager.openModal);
document.getElementById('btnAuthClose').addEventListener('click', AuthManager.closeModal);
document.getElementById('btn-tab-login').addEventListener('click', () => AuthManager.switchTab('login'));
document.getElementById('btn-tab-register').addEventListener('click', () => AuthManager.switchTab('register'));
document.getElementById('btn-fire-log-otp').addEventListener('click', () => AuthManager.process('login_send_otp'));
document.getElementById('btn-fire-log-verify').addEventListener('click', () => AuthManager.process('login_verify'));
document.getElementById('btn-fire-reg-otp').addEventListener('click', () => AuthManager.process('register_send_otp'));
document.getElementById('btn-fire-reg-verify').addEventListener('click', () => AuthManager.process('register_verify'));
document.getElementById('btnLogBack').addEventListener('click', () => AuthManager.switchPhase('auth-log-phase-2', 'auth-log-phase-1'));
document.getElementById('btnRegBack').addEventListener('click', () => AuthManager.switchPhase('auth-reg-phase-2', 'auth-reg-phase-1'));
document.getElementById('btnLogout').addEventListener('click', AuthManager.logout);
document.getElementById('btnClearMemory').addEventListener('click', ChatEngine.clearMemory);
// File Attachment Routing
document.getElementById('btnAttachMenuToggle').addEventListener('click', UIManager.toggleAttachMenu);
document.getElementById('opt-image').addEventListener('click', () => FileProcessor.triggerFileSelector('image'));
document.getElementById('opt-video').addEventListener('click', () => FileProcessor.triggerFileSelector('video'));
document.getElementById('opt-audio').addEventListener('click', () => FileProcessor.triggerFileSelector('audio'));
document.getElementById('opt-document').addEventListener('click', () => FileProcessor.triggerFileSelector('document'));
document.getElementById('sys-inp-image').addEventListener('change', function() { FileProcessor.processFile(this, 'image'); });
document.getElementById('sys-inp-video').addEventListener('change', function() { FileProcessor.processFile(this, 'video'); });
document.getElementById('sys-inp-audio').addEventListener('change', function() { FileProcessor.processFile(this, 'audio'); });
document.getElementById('sys-inp-document').addEventListener('change', function() { FileProcessor.processFile(this, 'document'); });
document.getElementById('btnDiscardFile').addEventListener('click', FileProcessor.discardFile);
// Primary Message Controls
document.getElementById('masterSendBtn').addEventListener('click', ChatEngine.initiateDispatch);
document.getElementById('mainChatInput').addEventListener('keydown', ChatEngine.handleKeyboard);
document.getElementById('mainChatInput').addEventListener('input', function() { UIManager.autoGrowTextArea(this); });
// Example Prompt Controls
document.getElementById('suggCodeBtn').addEventListener('click', () => ChatEngine.sendExample('Write a secure python script for a modern Flask backend server.'));
document.getElementById('suggImgBtn').addEventListener('click', () => ChatEngine.sendExample('Create a hyper-realistic 8k image of a futuristic Indian smart city.'));
// Voice & STT Options
document.getElementById('smartLangToggle').addEventListener('click', VoiceEngine.switchLanguage);
document.getElementById('masterVoiceBtn').addEventListener('click', VoiceEngine.toggleDictation);
// Live Mode Options
document.getElementById('btnStartLiveMode').addEventListener('click', LiveModeController.initialize);
document.getElementById('btnExitLiveMode').addEventListener('click', LiveModeController.terminate);
document.getElementById('liveMicBtn').addEventListener('click', VoiceEngine.toggleDictation);
// Workspace Logic Hooks
document.getElementById('btnWsClose').addEventListener('click', WorkspaceEngine.closePanel);
document.getElementById('btnWsCopy').addEventListener('click', function() { WorkspaceEngine.executeCopy(this); });
// Interaction Scroll Listeners
document.getElementById('msgs').addEventListener('scroll', UIManager.checkScrollState);
document.getElementById('scrollTriggerBtn').addEventListener('click', UIManager.forceScrollDown);
// Network Monitoring
window.addEventListener('online', UIManager.updateNetworkStatus);
window.addEventListener('offline', UIManager.updateNetworkStatus);
// Prevent unwanted default mobile behaviours on double-tap
document.addEventListener('dblclick', function(event) {
event.preventDefault();
}, { passive: false });
// Ensure startup screen displays if memory cleared
if(!localStorage.getItem('arjun_welcome_seen')) {
document.getElementById('welcomeOverlay').style.display = 'flex';
} else {
document.getElementById('welcomeOverlay').style.display = 'none';
}
// Fire Boot Processes
UIManager.updateNetworkStatus();
VoiceEngine.init();
AuthManager.initUI();
if(AppState.currentUser) { ChatEngine.syncHistoryFromCloud(); }
});
</script>
</body>
</html>