Spaces:
Sleeping
Sleeping
| <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> | |
| <!-- ========================================================================================= | |
| [1] 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> | |
| <!-- ========================================================================================= | |
| [2] MASSIVE ENTERPRISE CSS ARCHITECTURE (विस्तृत और उन्नत स्टाइलिंग) | |
| ========================================================================================= --> | |
| <style> | |
| /* --------------------------------------------------------------------------------------- | |
| A. CSS VARIABLES, DESIGN TOKENS & TIRANGA BRANDING | |
| --------------------------------------------------------------------------------------- */ | |
| :root { | |
| /* Brand Identity: Saffron, White, Green (Tiranga) */ | |
| --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; | |
| /* 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.4); | |
| /* 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-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 */ | |
| --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; | |
| } | |
| /* --------------------------------------------------------------------------------------- | |
| B. GLOBAL RESET & ANTI-BLUE-HIGHLIGHT (सम्पूर्ण यूज़र इंटरफ़ेस फिक्स) | |
| --------------------------------------------------------------------------------------- */ | |
| *, *::before, *::after { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| /* CRITICAL: REMOVE BLUE TAP HIGHLIGHT ON MOBILE/BROWSERS */ | |
| -webkit-tap-highlight-color: transparent ; | |
| -webkit-touch-callout: none ; | |
| } | |
| 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; | |
| } | |
| /* Remove default outlines and use custom focus states */ | |
| *:focus { outline: none ; } | |
| button, input, textarea, select { | |
| font-family: inherit; | |
| color: inherit; | |
| border: none; | |
| background: transparent; | |
| } | |
| button { cursor: pointer; user-select: none; } | |
| a { color: inherit; text-decoration: none; } | |
| img { max-width: 100%; height: auto; display: block; } | |
| svg { flex-shrink: 0; } | |
| /* Highly Customized Scrollbars */ | |
| ::-webkit-scrollbar { width: 6px; height: 6px; } | |
| ::-webkit-scrollbar-track { background: transparent; } | |
| ::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.12); border-radius: 10px; transition: background var(--ease-smooth); } | |
| ::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.25); } | |
| /* --------------------------------------------------------------------------------------- | |
| C. AMBIENT BACKGROUND SYSTEM (प्रीमियम बैकग्राउंड इफ़ेक्ट्स) | |
| --------------------------------------------------------------------------------------- */ | |
| .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. 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: 400px; align-items: center; | |
| } | |
| .toast-notification { | |
| background: var(--text-primary); 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: 10px; width: fit-content; max-width: 100%; word-break: break-word; | |
| border: 1px solid rgba(255,255,255,0.1); | |
| } | |
| .toast-notification svg { width: 18px; height: 18px; flex-shrink: 0; color: var(--brand-saffron); } | |
| @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.3s 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 { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: scale(1); } } | |
| .startup-title { font-family: var(--font-sans); font-size: 2.5rem; font-weight: 900; color: var(--text-primary); letter-spacing: -1px; margin-bottom: 16px; animation: slideUp var(--ease-smooth) 0.4s both; } | |
| .startup-desc { font-size: 1.1rem; color: var(--text-secondary); line-height: 1.6; max-width: 550px; margin-bottom: 40px; animation: slideUp var(--ease-smooth) 0.5s both; font-weight: 500; } | |
| .btn-startup-launch { padding: 18px 48px; background: var(--text-primary); color: var(--text-inverse); border: none; border-radius: var(--radius-xl); font-size: 1.125rem; font-weight: 700; cursor: pointer; transition: var(--ease-spring); box-shadow: 0 10px 25px rgba(0,0,0,0.15); animation: slideUp var(--ease-smooth) 0.6s both; display: flex; align-items: center; gap: 12px; position: relative; overflow: hidden; } | |
| .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(20px); } 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: 50px; height: 50px; border-radius: var(--radius-md); object-fit: cover; box-shadow: var(--shadow-sm); border: 2px solid var(--bg-primary); transition: transform var(--ease-spring); } | |
| .brand-identity:hover img { transform: scale(1.08) rotate(-3deg); } | |
| .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), var(--brand-green)); -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: var(--shadow-glow-green); } | |
| .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: 18px 32px; border-bottom: 1px solid var(--border-light); background: rgba(255, 255, 255, 0.85); backdrop-filter: blur(15px); display: flex; align-items: center; justify-content: space-between; z-index: var(--z-header); } | |
| .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); } | |
| .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; } | |
| @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); } } | |
| .hero-greeting { font-size: 42px; font-weight: 900; letter-spacing: -1.5px; margin-bottom: 18px; color: var(--text-primary); } | |
| .hero-description { font-size: 17px; color: var(--text-secondary); line-height: 1.6; margin-bottom: 40px; font-weight: 500; } | |
| /* RESTORED: 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.5s var(--ease-spring) both; } | |
| @keyframes messagePopIn { from { opacity: 0; transform: translateY(25px) 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; } | |
| .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 Rendering 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 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; } | |
| .chat-bubble pre { background: #282c34; color: #abb2bf; padding: 20px; border-radius: var(--radius-md); overflow-x: auto; margin: 20px 0; font-family: var(--font-mono); font-size: 14px; line-height: 1.6; border: 1px solid #181a1f; box-shadow: var(--shadow-inner); } | |
| .chat-bubble pre code { background: transparent; color: inherit; padding: 0; font-weight: 400; border: none; } | |
| /* 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); } | |
| .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 (Non-Technical Vocabulary) */ | |
| .upload-preview-bar { display: none; padding: 20px 28px 0; align-items: center; gap: 16px; } | |
| .upload-preview-bar.visible { display: flex; animation: fadeIn 0.3s ease; } | |
| .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; } | |
| /* 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); } | |
| .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.active-listening { color: #ffffff; background: var(--text-error); animation: recordPulse 1.5s infinite; border-radius: var(--radius-full); } | |
| @keyframes recordPulse { 0% { box-shadow: 0 0 0 0 rgba(239,68,68,0.5); } 70% { box-shadow: 0 0 0 12px rgba(239,68,68,0); } 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); } } | |
| /* 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); } | |
| .btn-master-send svg { width: 20px; height: 20px; fill: white; transition: transform 0.2s; } | |
| .btn-master-send:hover { transform: translateY(-3px); box-shadow: 0 10px 25px rgba(255, 153, 51, 0.4); } | |
| .btn-master-send:hover svg { transform: translate(2px, -2px); } | |
| .btn-master-send:disabled { opacity: 0.4; 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; } | |
| .workspace-editor-surface pre { margin: 0; padding: 0; background: transparent; font-family: var(--font-mono); font-size: 15px; line-height: 1.6; overflow-x: auto; color: #abb2bf; border: none; box-shadow: none;} | |
| /* --------------------------------------------------------------------------------------- | |
| 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); } | |
| .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.1); box-shadow: 0 0 60px rgba(255,153,51,0.6); } } | |
| .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; } | |
| .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; } | |
| .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 20px 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); } | |
| .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; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- ========================================================================================= | |
| 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">Professional</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 Memory 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"> | |
| <div class="pulse-dot"></div> | |
| System Online | |
| </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="" 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"> | |
| <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 --> | |
| <textarea class="main-textarea" id="mainChatInput" placeholder="Message Arjun Intelligence..." rows="1"></textarea> | |
| <!-- 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"> | |
| <pre><code id="workspaceCodeBlock" class="hljs"></code></pre> | |
| </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> | |
| <!-- ========================================================================================= | |
| [3] 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 | |
| }; | |
| // Initialize PDF worker | |
| 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, | |
| // NEW: Add flags to track speech recognition state | |
| isProcessingSpeech: false, | |
| lastProcessedText: "", | |
| // NEW: Track live mode speech processing | |
| isLiveProcessing: false | |
| }; | |
| // Initialize Gradio Client Dynamically (Fixes the Module Bug) | |
| 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.error("Gradio Connection Error:", err); | |
| } | |
| }; | |
| window.initGradioEngine(); | |
| // ======================================================================================= | |
| // 2. UTILITY ENGINE (Robust Copy, Notifications, and Text Cleaners) | |
| // ======================================================================================= | |
| const Utils = { | |
| showToast: (message) => { | |
| const container = document.getElementById('toast-container'); | |
| const toast = document.createElement('div'); | |
| toast.className = 'toast-notification'; | |
| toast.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> ${message}`; | |
| container.appendChild(toast); | |
| setTimeout(() => toast.remove(), 3000); | |
| }, | |
| escapeHTML: (str) => { | |
| return str.replace(/&/g,'&').replace(//g,'>'); | |
| }, | |
| // ✨ CRITICAL FIX: Intelligent Text Cleaner for TTS (Ignores code, links, images) | |
| cleanTextForVoice: (rawText) => { | |
| if(!rawText) return ""; | |
| let cleaned = rawText; | |
| // 1. Remove Markdown Code Blocks (``` ... ```) | |
| cleaned = cleaned.replace(/```[\s\S]*?```/g, ''); | |
| // 2. Remove Inline Code (`...`) | |
| cleaned = cleaned.replace(/`.*?`/g, ''); | |
| // 3. Remove Markdown Images () | |
| cleaned = cleaned.replace(/!\[.*?\]\(.*?\)/g, ''); | |
| // 4. Remove Markdown Links ([text](url)) - Extract just the text | |
| cleaned = cleaned.replace(/\[(.*?)\]\(.*?\)/g, '$1'); | |
| // 5. Remove Think Tags (<think>...</think>) | |
| cleaned = cleaned.replace(/<think>[\s\S]*?<\/think>/gi, ''); | |
| // 6. Remove URLs/HTTP links explicitly | |
| cleaned = cleaned.replace(/https?:\/\/[^\s]+/g, ''); | |
| // 7. Remove stray Markdown formatting symbols | |
| cleaned = cleaned.replace(/[*_~#]/g, ''); | |
| 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"; | |
| 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 Successfully`; | |
| setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500); | |
| } else { | |
| Utils.showToast("Clipboard access denied by browser."); | |
| } | |
| } catch (err) { | |
| Utils.showToast("System error copying text."); | |
| } | |
| 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 Successfully`; | |
| setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500); | |
| }).catch((err) => { | |
| console.warn('Modern API failed, utilizing fallback...', err); | |
| Utils.executeFallbackCopy(textToCopy, btnElement); | |
| }); | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 3. AUTHENTICATION & SYNC MANAGER (Robust Fetch) | |
| // ======================================================================================= | |
| 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'); | |
| }, | |
| // ✨ FIXED GAS SYNC LOGIC | |
| process: async (actionType) => { | |
| 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."); | |
| 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."); | |
| 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."); | |
| 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 { | |
| // mode: 'cors' handles redirect issues from GAS effectively | |
| 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); | |
| 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); | |
| } | |
| } catch (error) { | |
| console.error("Auth Network Error: ", error); | |
| Utils.showToast("Encrypted gateway error. Check network."); | |
| } | |
| 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'); | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 5. SPEECH & TTS ENGINE (Bilingual STT + Gradio Edge-TTS + Smart Cleaner) | |
| // ======================================================================================= | |
| const VoiceEngine = { | |
| recognition: null, | |
| currentLanguage: 'en-IN', | |
| init: () => { | |
| const SR = window.SpeechRecognition || window.webkitSpeechRecognition; | |
| if (!SR) return; | |
| VoiceEngine.recognition = new SR(); | |
| // FIX: Setting continuous to false to prevent multiple recognitions | |
| VoiceEngine.recognition.continuous = false; | |
| VoiceEngine.recognition.interimResults = true; | |
| VoiceEngine.recognition.lang = VoiceEngine.currentLanguage; | |
| VoiceEngine.recognition.onstart = () => { | |
| AppState.isMicRecording = true; | |
| // NEW: Set processing flag to prevent duplicate processing | |
| AppState.isProcessingSpeech = true; | |
| document.getElementById('masterVoiceBtn').classList.add('active-listening'); | |
| 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) => { | |
| let finalTranscript = ''; | |
| let interimTranscript = ''; | |
| for (let i = event.resultIndex; i < event.results.length; ++i) { | |
| if (event.results[i].isFinal) { | |
| finalTranscript += event.results[i][0].transcript; | |
| } else { | |
| interimTranscript += event.results[i][0].transcript; | |
| } | |
| } | |
| if (finalTranscript.trim().length > 0) { | |
| let formattedText = finalTranscript.trim(); | |
| // NEW: Check if this text has already been processed to avoid duplication | |
| if (formattedText === AppState.lastProcessedText) { | |
| return; | |
| } | |
| AppState.lastProcessedText = formattedText; | |
| formattedText = formattedText.charAt(0).toUpperCase() + formattedText.slice(1); | |
| if (!/[.!?।]$/.test(formattedText)) formattedText += '.'; | |
| if (AppState.isLiveModeEngaged) { | |
| document.getElementById('liveTranscriptText').innerText = `"${formattedText}"`; | |
| document.getElementById('liveStatusText').innerText = "Synthesizing Response..."; | |
| document.getElementById('mainChatInput').value = formattedText; | |
| // NEW: Set live processing flag to prevent duplicate dispatches | |
| if (!AppState.isLiveProcessing) { | |
| AppState.isLiveProcessing = true; | |
| // Stop mic manually to trigger dispatch in Live Mode | |
| VoiceEngine.recognition.stop(); | |
| ChatEngine.initiateDispatch(); | |
| } | |
| } else { | |
| const inputField = document.getElementById('mainChatInput'); | |
| inputField.value = (inputField.value + ' ' + formattedText + ' ').trim(); | |
| UIManager.autoGrowTextArea(inputField); | |
| } | |
| } | |
| }; | |
| VoiceEngine.recognition.onend = () => { | |
| AppState.isMicRecording = false; | |
| // NEW: Reset processing flags when recognition ends | |
| AppState.isProcessingSpeech = false; | |
| if (AppState.isLiveModeEngaged) { | |
| AppState.isLiveProcessing = false; | |
| } | |
| document.getElementById('masterVoiceBtn').classList.remove('active-listening'); | |
| if (AppState.isLiveModeEngaged && !AppState.isProcessing) { | |
| document.getElementById('liveMicBtn').classList.remove('is-recording'); | |
| document.getElementById('liveStatusText').innerText = "Tap mic to interact"; | |
| document.getElementById('liveOrb').style.transform = "scale(1)"; | |
| } | |
| }; | |
| VoiceEngine.recognition.onerror = (event) => { | |
| AppState.isMicRecording = false; | |
| // NEW: Reset processing flags on error | |
| AppState.isProcessingSpeech = false; | |
| if (AppState.isLiveModeEngaged) { | |
| AppState.isLiveProcessing = false; | |
| } | |
| if(event.error !== 'no-speech') { | |
| Utils.showToast("Voice module error: " + event.error); | |
| } | |
| document.getElementById('masterVoiceBtn').classList.remove('active-listening'); | |
| 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 (देवनागरी)"); | |
| } else { | |
| VoiceEngine.currentLanguage = 'en-IN'; | |
| badge.innerText = 'EN'; | |
| btn.classList.remove('hindi-active'); | |
| Utils.showToast("Listening Protocol: English"); | |
| } | |
| if (VoiceEngine.recognition) { | |
| VoiceEngine.recognition.lang = VoiceEngine.currentLanguage; | |
| if(AppState.isMicRecording) { | |
| VoiceEngine.recognition.stop(); | |
| setTimeout(() => { VoiceEngine.recognition.start(); }, 400); | |
| } | |
| } | |
| }, | |
| toggleDictation: () => { | |
| if (!VoiceEngine.recognition) return Utils.showToast("Hardware dictation unsupported."); | |
| try { | |
| if(AppState.isMicRecording) { | |
| VoiceEngine.recognition.stop(); | |
| } else { | |
| VoiceEngine.recognition.start(); | |
| } | |
| } catch (e) { console.error("Mic Start Error", e); } | |
| }, | |
| // ✨ GRADIO TTS INTEGRATION WITH SMART CLEANER | |
| executeTTS: async (rawText) => { | |
| // Apply smart text cleaner so AI doesn't read code or image links | |
| const cleanSpeechText = Utils.cleanTextForVoice(rawText); | |
| if(!cleanSpeechText.trim()) { | |
| Utils.showToast("No readable text found."); | |
| return; | |
| } | |
| Utils.showToast("🔊 Linking with Neural Voice Matrix..."); | |
| if (AppState.isLiveModeEngaged) { | |
| document.getElementById('liveOrb').classList.add('speaking'); | |
| } | |
| try { | |
| if(!AppState.gradioClient) { | |
| // Fallback dynamically import if not connected | |
| 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[0]) { | |
| const audioUrl = typeof result.data[0] === 'string' ? result.data[0] : result.data[0].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."); | |
| 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){} | |
| }, 500); | |
| } | |
| }, | |
| 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 (Non-Technical Vocabulary) | |
| // ======================================================================================= | |
| const FileProcessor = { | |
| triggerFileSelector: (type) => { | |
| document.getElementById('attachDropdownMenu').classList.remove('visible'); | |
| document.getElementById('sys-inp-' + type).click(); | |
| }, | |
| processFile: async (inputElement, typeContext) => { | |
| const file = inputElement.files[0]; | |
| if (!file) return; | |
| const fName = file.name.toLowerCase(); | |
| const mime = file.type; | |
| if (typeContext === 'image' && !mime.startsWith('image/')) { Utils.showToast("Visual media required."); inputElement.value=''; return; } | |
| if (typeContext === 'video' && !mime.startsWith('video/')) { Utils.showToast("Video media required."); inputElement.value=''; return; } | |
| if (typeContext === 'audio' && !mime.startsWith('audio/')) { Utils.showToast("Audio media required."); inputElement.value=''; return; } | |
| Utils.showToast(`Uploading your file...`); | |
| 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(',')[1], 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(',')[1], 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("Your PDF is ready!"); | |
| } catch (e) { | |
| Utils.showToast("PDF parsing encountered an 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("Your Word document is ready!"); | |
| } catch(e) { | |
| Utils.showToast("Document parsing encountered an error."); | |
| FileProcessor.discardFile(); | |
| } | |
| }; | |
| fileReader.readAsArrayBuffer(file); | |
| } | |
| else { | |
| fileReader.onload = (e) => { | |
| AppState.pendingAttachment = { type: 'text', data: e.target.result, name: file.name }; | |
| Utils.showToast("Your file is ready!"); | |
| }; | |
| fileReader.readAsText(file); | |
| } | |
| } | |
| inputElement.value = ''; | |
| }, | |
| discardFile: () => { | |
| AppState.pendingAttachment = null; | |
| document.getElementById('filePreviewBar').classList.remove('visible'); | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 7. WORKSPACE ENGINE & 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 Code"; | |
| const blockDisplay = document.getElementById('workspaceCodeBlock'); | |
| blockDisplay.className = `hljs language-${codeData.lang || 'plaintext'}`; | |
| blockDisplay.textContent = codeData.code; | |
| hljs.highlightElement(blockDisplay); | |
| 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); | |
| } | |
| } | |
| }; | |
| 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[1] : (token.lang || ''); | |
| if (AppState.isStreamingActive) { | |
| return ` | |
| <div class="streaming-code-container"> | |
| <div class="streaming-code-header"> | |
| <div class="loading-ring"></div> | |
| Generating Architecture... | |
| </div> | |
| <pre><code class="language-${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>${langClass || 'Syntax Detected'} |