CodeVed / index.html
Vedika
Update index.html
5df859e verified
Raw
History Blame
133 kB
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<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 Advanced Artificial Intelligence System engineered by Abhay Kumar.">
<meta name="theme-color" content="#FF9933">
<title>Arjun 2.O - Professional Advanced AI</title>
<!-- =========================================================================================
1. EXTERNAL RESOURCES & LIBRARIES (बाहरी स्रोत और लाइब्रेरीज़)
========================================================================================= -->
<!-- Preconnect for Performance -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Professional Typography: Inter (Sans), Geist Mono (Code), Instrument Serif (Display) -->
<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 Theme (Atom One Dark for Professional Coding Workspace) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
<!-- Core External Scripts for Data Extraction and Rendering -->
<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 CSS ARCHITECTURE (विस्तृत स्टाइलिंग और एनीमेशन)
========================================================================================= -->
<style>
/* ---------------------------------------------------------------------------------------
A. CSS VARIABLES & DESIGN TOKENS
--------------------------------------------------------------------------------------- */
:root {
/* Branding: Professional Tiranga Theme */
--brand-saffron: #FF9933;
--brand-saffron-light: rgba(255, 153, 51, 0.12);
--brand-saffron-hover: #e68a2e;
--brand-saffron-active: #cc7a29;
--brand-white: #FFFFFF;
--brand-white-glass: rgba(255, 255, 255, 0.85);
--brand-green: #138808;
--brand-green-light: rgba(19, 136, 8, 0.12);
--brand-green-hover: #0f6e06;
--brand-green-active: #0c5905;
/* Core UI Colors */
--bg-primary: #ffffff;
--bg-secondary: #f8f9fa;
--bg-tertiary: #f1f3f5;
--bg-glass: rgba(255, 255, 255, 0.75);
--bg-overlay: rgba(0, 0, 0, 0.4);
/* Text Hierarchy */
--text-primary: #111827;
--text-secondary: #4b5563;
--text-tertiary: #9ca3af;
--text-inverse: #ffffff;
/* Border & Dividers */
--border-light: rgba(0, 0, 0, 0.08);
--border-medium: rgba(0, 0, 0, 0.15);
--border-focus: rgba(255, 153, 51, 0.35);
/* Depth & Elevation (Shadows) */
--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-glow-saffron: 0 0 15px rgba(255, 153, 51, 0.4);
--shadow-glow-green: 0 0 15px rgba(19, 136, 8, 0.4);
/* Typography Scale */
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
--font-mono: 'Geist Mono', Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
--font-serif: 'Instrument Serif', Georgia, Cambria, "Times New Roman", Times, serif;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 1.875rem;
--text-4xl: 2.25rem;
/* Border Radii */
--radius-xs: 4px;
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--radius-xl: 24px;
--radius-2xl: 32px;
--radius-full: 9999px;
/* Transitions & 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);
--ease-bounce: 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
/* Z-Index Hierarchy */
--z-bg: -1;
--z-base: 1;
--z-overlay: 10;
--z-dropdown: 50;
--z-sidebar: 100;
--z-modal: 5000;
--z-toast: 9000;
--z-live-mode: 9999;
}
/* ---------------------------------------------------------------------------------------
B. RESET & GLOBAL BASE
--------------------------------------------------------------------------------------- */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 16px;
-webkit-text-size-adjust: 100%;
}
body {
height: 100dvh;
width: 100vw;
overflow: hidden;
background-color: var(--bg-primary);
color: var(--text-primary);
font-family: var(--font-sans);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
button, input, textarea, select {
font-family: inherit;
color: inherit;
}
a {
color: inherit;
text-decoration: none;
}
img {
max-width: 100%;
height: auto;
display: block;
}
/* ---------------------------------------------------------------------------------------
C. AMBIENT BACKGROUND EFFECTS
--------------------------------------------------------------------------------------- */
.ambient-environment {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
z-index: var(--z-bg);
overflow: hidden;
pointer-events: none;
background: linear-gradient(135deg, var(--brand-saffron-light) 0%, #ffffff 50%, var(--brand-green-light) 100%);
}
.ambient-orb {
position: absolute;
border-radius: 50%;
filter: blur(120px);
opacity: 0.45;
animation: orbFloat 35s ease-in-out infinite alternate;
will-change: transform;
}
.orb-top-left {
width: 650px;
height: 650px;
background: radial-gradient(circle, rgba(255,153,51,0.25) 0%, transparent 70%);
top: -200px;
left: -150px;
}
.orb-bottom-right {
width: 550px;
height: 550px;
background: radial-gradient(circle, rgba(19,136,8,0.2) 0%, transparent 70%);
bottom: -150px;
right: -100px;
animation-delay: -15s;
animation-duration: 40s;
}
@keyframes orbFloat {
0% { transform: translate(0, 0) scale(1); }
33% { transform: translate(60px, 80px) scale(1.1); }
66% { transform: translate(-40px, 50px) scale(0.95); }
100% { transform: translate(70px, -30px) scale(1.05); }
}
/* ---------------------------------------------------------------------------------------
D. TOAST NOTIFICATION SYSTEM
--------------------------------------------------------------------------------------- */
.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;
}
.toast-notification {
background: var(--text-primary);
color: var(--text-inverse);
padding: 14px 28px;
border-radius: var(--radius-full);
font-size: var(--text-sm);
font-weight: 600;
box-shadow: var(--shadow-lg);
animation: toastSlideIn var(--ease-spring) forwards, toastFadeOut 0.4s 2.6s forwards;
display: flex;
align-items: center;
gap: 10px;
}
.toast-notification svg {
width: 18px;
height: 18px;
stroke-width: 2.5;
}
@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.2s both;
}
.startup-logo-container img {
width: 140px;
height: 140px;
border-radius: var(--radius-xl);
object-fit: cover;
box-shadow: var(--shadow-xl);
border: 3px solid var(--bg-primary);
position: relative;
z-index: 2;
}
.startup-logo-glow {
position: absolute;
inset: -15px;
background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green));
filter: blur(25px);
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: var(--text-4xl);
font-weight: 900;
color: var(--text-primary);
letter-spacing: -1.5px;
margin-bottom: 16px;
animation: slideUp var(--ease-smooth) 0.3s both;
}
.startup-desc {
font-size: var(--text-lg);
color: var(--text-secondary);
line-height: 1.6;
max-width: 500px;
margin-bottom: 40px;
animation: slideUp var(--ease-smooth) 0.4s both;
}
.btn-startup-launch {
padding: 18px 48px;
background: var(--text-primary);
color: var(--text-inverse);
border: none;
border-radius: var(--radius-xl);
font-size: var(--text-lg);
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.5s both;
display: flex;
align-items: center;
gap: 12px;
}
.btn-startup-launch:hover {
background: #000000;
transform: translateY(-4px) scale(1.02);
box-shadow: 0 15px 35px rgba(0,0,0,0.25);
}
@keyframes slideUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
/* ---------------------------------------------------------------------------------------
F. CORE APPLICATION LAYOUT
--------------------------------------------------------------------------------------- */
.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);
}
/* ---------------------------------------------------------------------------------------
G. SIDEBAR NAVIGATION
--------------------------------------------------------------------------------------- */
.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);
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: 52px;
height: 52px;
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: #ef4444;
}
/* Sidebar Content & Scrollbar */
.sidebar-body {
flex: 1;
overflow-y: auto;
padding: 24px;
display: flex;
flex-direction: column;
gap: 28px;
}
.sidebar-body::-webkit-scrollbar { width: 5px; }
.sidebar-body::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.1); border-radius: 10px; }
.sidebar-body::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.2); }
/* Authentication UI Widget */
.auth-widget {
background: var(--bg-primary);
border: 1px solid var(--border-light);
border-radius: var(--radius-lg);
padding: 20px;
box-shadow: var(--shadow-sm);
position: relative;
overflow: hidden;
}
.btn-secure-connect {
width: 100%;
padding: 14px;
background: var(--text-primary);
color: var(--text-inverse);
border: none;
border-radius: var(--radius-md);
font-size: var(--text-sm);
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: 44px;
height: 44px;
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);
}
.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);
}
.btn-system-logout {
background: rgba(239, 68, 68, 0.1);
color: #ef4444;
border: none;
width: 36px;
height: 36px;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: var(--ease-fast);
}
.btn-system-logout:hover {
background: #ef4444;
color: #ffffff;
}
/* Branding Box at Bottom */
.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);
}
.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;
}
/* Clear Memory 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: var(--text-sm);
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: #ef4444;
border-color: #fca5a5;
}
/* ---------------------------------------------------------------------------------------
H. MAIN CHAT INTERFACE
--------------------------------------------------------------------------------------- */
.main-chat-wrapper {
flex: 1;
display: flex;
flex-direction: column;
position: relative;
min-width: 320px;
transition: width var(--ease-smooth);
background: transparent;
}
/* Chat Header */
.chat-top-bar {
padding: 18px 32px;
border-bottom: 1px solid var(--border-light);
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
display: flex;
align-items: center;
justify-content: space-between;
z-index: var(--z-overlay);
}
.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: 40px;
height: 40px;
border-radius: var(--radius-sm);
align-items: center;
justify-content: center;
box-shadow: var(--shadow-sm);
}
.system-status-pill {
display: flex;
align-items: center;
gap: 10px;
font-size: var(--text-sm);
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);
box-shadow: inset 0 1px 2px rgba(255,255,255,0.5);
}
.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); }
}
/* LIVE MODE TOGGLE BUTTON */
.btn-activate-live {
background: linear-gradient(135deg, #ef4444 0%, #b91c1c 100%);
color: white;
border: none;
padding: 10px 20px;
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.02);
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; }
}
/* ---------------------------------------------------------------------------------------
I. CONVERSATION SCROLL AREA & WELCOME
--------------------------------------------------------------------------------------- */
.chat-scroll-area {
flex: 1;
overflow-y: auto;
padding: 40px 10%;
display: flex;
flex-direction: column;
gap: 36px;
scroll-behavior: smooth;
position: relative;
}
.chat-scroll-area::-webkit-scrollbar { width: 6px; }
.chat-scroll-area::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 10px; }
/* Internal Welcome Hero */
.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;
}
.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: 400;
}
.guest-warning-badge {
font-size: 13px;
font-weight: 700;
color: #ef4444;
background: #fee2e2;
padding: 8px 16px;
border-radius: var(--radius-full);
margin-bottom: 32px;
display: none;
align-items: center;
gap: 8px;
border: 1px solid #fca5a5;
}
/* Action Suggestions Grid */
.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);
}
.prompt-card:hover {
transform: translateY(-5px);
box-shadow: var(--shadow-lg);
border-color: var(--brand-saffron);
background: rgba(255, 255, 255, 0.95);
}
.prompt-icon {
font-size: 28px;
margin-bottom: 14px;
display: inline-block;
}
.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;
}
/* ---------------------------------------------------------------------------------------
J. CHAT MESSAGE BUBBLES & ATTACHMENT 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-sm);
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: 6px;
object-fit: cover;
}
.msg-content-column {
display: flex;
flex-direction: column;
gap: 8px;
max-width: 100%;
min-width: 0; /* Prevents flex blowout */
}
.user-msg .msg-content-column {
align-items: flex-end;
}
/* NEW: In-Message File Preview Cards */
.chat-in-bubble-img {
max-width: 300px;
max-height: 300px;
border-radius: var(--radius-md);
object-fit: cover;
border: 2px solid rgba(255,255,255,0.2);
box-shadow: var(--shadow-md);
margin-bottom: 8px;
}
.chat-file-card {
display: flex;
align-items: center;
gap: 12px;
background: rgba(255,255,255,0.15);
border: 1px solid rgba(255,255,255,0.3);
padding: 12px 16px;
border-radius: var(--radius-md);
margin-bottom: 8px;
backdrop-filter: blur(5px);
max-width: 350px;
}
.chat-file-card .icon {
font-size: 24px;
background: rgba(0,0,0,0.1);
width: 40px; height: 40px;
display: flex; align-items: center; justify-content: center;
border-radius: var(--radius-sm);
}
.chat-file-card .name {
font-size: 13px;
font-weight: 600;
color: var(--brand-white);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.chat-bubble {
padding: 18px 24px;
font-size: 15px;
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 (TTS & Copy) */
.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: 12px;
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);
}
.btn-bot-action.action-tts {
color: var(--brand-green-hover);
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);
}
/* ---------------------------------------------------------------------------------------
K. MARKDOWN & CODE RENDERING STYLES
--------------------------------------------------------------------------------------- */
.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;
}
.user-msg .chat-bubble code {
background: rgba(255,255,255,0.2);
color: var(--brand-white);
}
.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;
}
.chat-bubble pre code {
background: transparent;
color: inherit;
padding: 0;
font-weight: 400;
}
/* Streaming "Generating Code..." 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: 12px 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;
}
/* Final 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(--border-medium);
box-shadow: var(--shadow-md);
}
.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-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);
}
.btn-launch-workspace:hover {
transform: scale(1.05);
background: var(--brand-saffron);
box-shadow: 0 6px 15px rgba(255,153,51,0.35);
}
/* ---------------------------------------------------------------------------------------
L. INPUT AREA & CONTROLS (BOTTOM BAR)
--------------------------------------------------------------------------------------- */
.input-dock {
flex-shrink: 0;
padding: 0 40px 32px;
background: transparent;
position: relative;
z-index: 20;
}
.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-2xl);
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);
}
/* Uploaded File Preview Strip */
.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;
}
.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: #ef4444;
transition: var(--ease-fast);
}
.btn-discard-upload:hover {
background: #ef4444;
color: #fff;
}
/* Input Tools Row */
.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 Dropdown Menu (Gemini Style) */
.attachment-module {
position: relative;
}
.btn-tool-icon {
width: 44px;
height: 44px;
border-radius: var(--radius-md);
background: transparent;
border: none;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: var(--text-secondary);
transition: var(--ease-fast);
position: relative;
}
.btn-tool-icon:hover {
background: var(--bg-tertiary);
color: var(--text-primary);
}
.btn-tool-icon svg {
width: 24px;
height: 24px;
stroke-width: 2;
}
.attachment-dropdown {
position: absolute;
bottom: 60px;
left: 0;
background: rgba(255,255,255,0.95);
backdrop-filter: blur(25px);
-webkit-backdrop-filter: blur(25px);
border: 1px solid var(--border-light);
border-radius: var(--radius-lg);
padding: 10px;
box-shadow: var(--shadow-xl);
display: none;
flex-direction: column;
gap: 6px;
z-index: var(--z-dropdown);
min-width: 220px;
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-hover);
}
.dropdown-item span.emoji-icon {
font-size: 20px;
}
.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 10px;
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);
}
.btn-mic-tool.active-listening {
color: #ffffff;
background: #ef4444;
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); }
}
/* Primary 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;
}
/* ---------------------------------------------------------------------------------------
M. LIVE MODE FULLSCREEN OVERLAY
--------------------------------------------------------------------------------------- */
.live-mode-viewport {
position: fixed;
inset: 0;
background: rgba(255, 255, 255, 0.98);
z-index: var(--z-live-mode);
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: #ef4444;
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-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;
}
.live-control-deck {
display: flex;
gap: 24px;
margin-top: 50px;
}
.btn-live-deck {
width: 76px;
height: 76px;
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: #ef4444;
color: white;
border-color: #ef4444;
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); }
}
.btn-live-deck svg {
width: 32px;
height: 32px;
}
/* Scroll 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(--bg-primary);
color: var(--text-primary);
transform: translateX(-50%) translateY(-5px);
box-shadow: var(--shadow-xl);
}
/* ---------------------------------------------------------------------------------------
N. WORKSPACE (CODE EXECUTION PANEL)
--------------------------------------------------------------------------------------- */
.code-workspace-panel {
width: 0;
background: var(--bg-primary);
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.04);
z-index: 25;
}
.code-workspace-panel.expanded {
width: 55%;
}
.workspace-header-bar {
padding: 20px 28px;
border-bottom: 1px solid var(--border-light);
background: var(--bg-primary);
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
}
.workspace-title-group {
font-size: 16px;
font-weight: 800;
display: flex;
align-items: center;
gap: 12px;
color: var(--text-primary);
}
.workspace-tools {
display: flex;
gap: 12px;
}
.btn-workspace-tool {
padding: 10px 18px;
border-radius: var(--radius-sm);
background: var(--bg-secondary);
border: 1px solid var(--border-light);
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
color: var(--text-primary);
transition: var(--ease-fast);
font-size: 14px;
font-weight: 700;
}
.btn-workspace-tool:hover {
background: var(--bg-tertiary);
border-color: var(--border-medium);
}
.btn-workspace-tool.close {
padding: 10px;
}
.btn-workspace-tool.close:hover {
color: #ef4444;
background: #fee2e2;
border-color: #fca5a5;
}
.workspace-editor-surface {
flex: 1;
overflow-y: auto;
background: var(--bg-secondary);
padding: 30px;
}
.workspace-editor-surface pre {
margin: 0;
padding: 28px;
background: #282c34; /* Atom One Dark BG */
border: 1px solid var(--border-light);
border-radius: var(--radius-lg);
font-family: var(--font-mono);
font-size: 15px;
line-height: 1.6;
overflow-x: auto;
box-shadow: var(--shadow-lg);
color: #abb2bf;
}
/* ---------------------------------------------------------------------------------------
O. AUTHENTICATION MODAL (SECURE GATEWAY)
--------------------------------------------------------------------------------------- */
.secure-modal-backdrop {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.5);
backdrop-filter: blur(10px);
-webkit-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: #ef4444;
}
.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);
}
/* Core Animations */
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideIn { from { opacity: 0; transform: translateX(25px); } to { opacity: 1; transform: none; } }
/* Blinking Cursor for Typing */
.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 */
.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); } }
/* ---------------------------------------------------------------------------------------
P. RESPONSIVE MEDIA QUERIES
--------------------------------------------------------------------------------------- */
@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: 95%; }
.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 ELEMENT 1: GLOBAL NOTIFICATIONS
========================================================================================= -->
<div id="toast-container" class="toast-wrapper"></div>
<!-- =========================================================================================
DOM ELEMENT 2: INITIAL 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" onclick="ApplicationCore.launchSystem()">
Initialize System
<svg viewBox="0 0 24 24" width="20" height="20" 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 ELEMENT 3: LIVE MODE FULLSCREEN OVERLAY
========================================================================================= -->
<div class="live-mode-viewport" id="liveOverlay">
<button class="btn-close-live" onclick="LiveModeController.terminate()" 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" onclick="VoiceEngine.toggleLive()">
<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 ELEMENT 4: AMBIENT BACKGROUND
========================================================================================= -->
<div class="ambient-environment">
<div class="ambient-orb orb-top-left"></div>
<div class="ambient-orb orb-bottom-right"></div>
</div>
<!-- =========================================================================================
DOM ELEMENT 5: 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" onclick="UIManager.toggleSidebar()">
<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" onclick="AuthManager.openModal()">
<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" onclick="AuthManager.logout()" 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 & Developer Info -->
<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>
<!-- Clear Memory Context -->
<button class="btn-erase-memory" onclick="ChatEngine.clearMemory()">
<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" onclick="UIManager.toggleSidebar()">
<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" onclick="LiveModeController.initialize()">
<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" onscroll="UIManager.checkScrollState()">
<!-- Internal Welcome / Empty 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>
<div id="guestBadge" class="guest-warning-badge">
⚠️ Guest Mode Active: <span id="guestCountDisplay">0</span>/3 Queries Used. Please login.
</div>
<div class="prompt-suggestions-grid">
<div class="prompt-card" onclick="ChatEngine.sendExample('Write a secure python script for a modern Flask backend server.')">
<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" onclick="ChatEngine.sendExample('Create a hyper-realistic 8k image of a futuristic Indian smart city.')">
<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>
<!-- Dynamic Chat Bubbles will be appended here -->
</div>
<!-- Floating Scroll Down Button -->
<button class="btn-scroll-trigger" id="scrollTriggerBtn" onclick="UIManager.forceScrollDown()">
<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">File ready to analyze</div>
</div>
<button class="btn-discard-upload" onclick="FileProcessor.discardFile()">
<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" onclick="UIManager.toggleAttachMenu()" 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" onclick="FileProcessor.triggerFileSelector('image')">
<span class="emoji-icon">🖼️</span> High-Res Image
</div>
<div class="dropdown-item" onclick="FileProcessor.triggerFileSelector('video')">
<span class="emoji-icon">🎥</span> Video Media
</div>
<div class="dropdown-item" onclick="FileProcessor.triggerFileSelector('audio')">
<span class="emoji-icon">🎵</span> Audio Track
</div>
<div class="dropdown-item" onclick="FileProcessor.triggerFileSelector('document')">
<span class="emoji-icon">📄</span> Document / Code
</div>
</div>
<!-- Hidden File Inputs -->
<input type="file" id="sys-inp-image" class="stealth-input" accept="image/*" onchange="FileProcessor.processFile(this, 'image')">
<input type="file" id="sys-inp-video" class="stealth-input" accept="video/*" onchange="FileProcessor.processFile(this, 'video')">
<input type="file" id="sys-inp-audio" class="stealth-input" accept="audio/*" onchange="FileProcessor.processFile(this, '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" onchange="FileProcessor.processFile(this, 'document')">
</div>
<!-- Smart Language Toggle Button -->
<button class="language-toggle-chip" id="smartLangToggle" onclick="VoiceEngine.switchLanguage()" title="Switch Voice Engine Language">
🌐 <span id="langDisplayBadge">EN</span>
</button>
<!-- Voice Dictation Button -->
<button class="btn-tool-icon btn-mic-tool" id="masterVoiceBtn" onclick="VoiceEngine.toggleDictation()" 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" onkeydown="ChatEngine.handleKeyboard(event)" oninput="UIManager.autoGrowTextArea(this)"></textarea>
<!-- Master Send Button -->
<button class="btn-master-send" id="masterSendBtn" onclick="ChatEngine.initiateDispatch()">
<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="workspaceTitleBadge">Workspace</span>
</div>
<div class="workspace-tools">
<button class="btn-workspace-tool" onclick="WorkspaceEngine.executeCopy(this)">
<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" onclick="WorkspaceEngine.closePanel()" 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 ELEMENT 6: SECURE AUTHENTICATION MODAL
========================================================================================= -->
<div class="secure-modal-backdrop" id="secureAuthModal">
<div class="secure-modal-surface">
<button class="btn-modal-dismiss" onclick="AuthManager.closeModal()">
<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" onclick="AuthManager.switchTab('login')">Connect</div>
<div class="auth-tab-item" id="btn-tab-register" onclick="AuthManager.switchTab('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" onclick="AuthManager.process('login_send_otp')">Generate 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" onclick="AuthManager.process('login_verify')">Authenticate</button>
<button class="btn-auth-return" onclick="AuthManager.switchPhase('auth-log-phase-2', 'auth-log-phase-1')">← Go Back</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="Email Address">
<button class="btn-auth-execute" id="btn-fire-reg-otp" onclick="AuthManager.process('register_send_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" onclick="AuthManager.process('register_verify')">Initialize Account</button>
<button class="btn-auth-return" onclick="AuthManager.switchPhase('auth-reg-phase-2', 'auth-reg-phase-1')">← Go Back</button>
</div>
</div>
</div>
</div>
<!-- =========================================================================================
7. ENTERPRISE JAVASCRIPT LOGIC (पूर्ण आर्किटेक्चर)
========================================================================================= -->
<script>
/**
* System 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'
};
// Initialize PDF worker
pdfjsLib.GlobalWorkerOptions.workerSrc = Config.PDF_WORKER;
// Global Application State
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
};
/**
* Utility Classes & Functions
*/
const Utils = {
showToast: (message) => {
const container = document.getElementById('toast-container');
const toast = document.createElement('div');
toast.className = 'toast-notification';
// Success SVG Icon inline
toast.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><polyline points="20 6 9 17 4 12"></polyline></svg> ${message}`;
container.appendChild(toast);
setTimeout(() => toast.remove(), 3000);
},
escapeHTML: (str) => {
return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
},
// Robust Fallback Copy Mechanism (100% Reliability)
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> Success`;
setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
} else {
Utils.showToast("Clipboard access denied.");
}
} 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> Success`;
setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
}).catch((err) => {
console.warn('Modern API failed, utilizing fallback...', err);
Utils.executeFallbackCopy(textToCopy, btnElement);
});
}
};
/**
* Authentication Manager (Google Apps Script Integration)
*/
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(`btn-tab-${tabName}`).classList.add('active');
document.getElementById('auth-flow-login').style.display = tabName === 'login' ? 'block' : 'none';
document.getElementById('auth-flow-register').style.display = tabName === 'register' ? 'block' : 'none';
},
switchPhase: (currentId, nextId) => {
document.getElementById(currentId).classList.remove('active');
document.getElementById(nextId).classList.add('active');
},
process: async (actionType) => {
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 {
const response = await fetch(Config.GAS_URL, { method: 'POST', 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) {
Utils.showToast("Encrypted gateway error. Check network.");
}
triggerBtn.disabled = false;
triggerBtn.innerHTML = originalText;
},
logout: () => {
localStorage.removeItem('arjun_user');
location.reload();
}
};
/**
* UI & DOM Management
*/
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');
}
};
// Close dropdown when clicking outside
document.addEventListener('click', (event) => {
const wrapper = document.querySelector('.attachment-module');
if (!wrapper.contains(event.target)) {
document.getElementById('attachDropdownMenu').classList.remove('visible');
}
});
/**
* Voice & Speech Engine (Smart Bilingual Toggle)
*/
const VoiceEngine = {
recognition: null,
currentLanguage: 'en-IN',
init: () => {
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
if (!SR) return;
VoiceEngine.recognition = new SR();
VoiceEngine.recognition.continuous = false;
VoiceEngine.recognition.interimResults = false;
VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
VoiceEngine.recognition.onstart = () => {
document.getElementById('masterVoiceBtn').classList.add('active-listening');
if (AppState.isLiveModeEngaged) {
document.getElementById('liveMicBtn').classList.add('is-recording');
document.getElementById('liveStatusText').innerText = "Analyzing Input...";
document.getElementById('liveOrb').style.transform = "scale(1.25)";
}
};
VoiceEngine.recognition.onresult = (event) => {
let transcript = '';
for (let i = event.resultIndex; i < event.results.length; ++i) {
transcript += event.results[i][0].transcript;
}
transcript = transcript.trim();
if (transcript.length > 0) {
transcript = transcript.charAt(0).toUpperCase() + transcript.slice(1);
if (!/[.!?।]$/.test(transcript)) transcript += '.';
transcript += ' ';
}
if (AppState.isLiveModeEngaged) {
document.getElementById('liveTranscriptText').innerText = `"${transcript}"`;
document.getElementById('liveStatusText').innerText = "Synthesizing Response...";
document.getElementById('mainChatInput').value = transcript;
ChatEngine.initiateDispatch();
} else {
const inputField = document.getElementById('mainChatInput');
inputField.value = (inputField.value + ' ' + transcript).trim();
UIManager.autoGrowTextArea(inputField);
}
};
VoiceEngine.recognition.onend = () => {
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) => {
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("Acoustic Protocol: Pure Hindi (देवनागरी)");
} else {
VoiceEngine.currentLanguage = 'en-IN';
badge.innerText = 'EN';
btn.classList.remove('hindi-active');
Utils.showToast("Acoustic Protocol: English / Hybrid");
}
if (VoiceEngine.recognition) {
VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
}
},
toggleDictation: () => {
if (!VoiceEngine.recognition) return Utils.showToast("Hardware dictation unsupported.");
try { VoiceEngine.recognition.start(); } catch (e) { VoiceEngine.recognition.stop(); }
},
toggleLive: () => {
if (!VoiceEngine.recognition) return Utils.showToast("Hardware dictation unsupported.");
try { VoiceEngine.recognition.start(); } catch (e) { VoiceEngine.recognition.stop(); }
},
// Calling Backend TTS
executeTTS: async (text) => {
const cleanText = text.replace(/[*_~`#]/g, '').replace(/<[^>]*>?/gm, '');
Utils.showToast("🔊 Linking with Neural Voice Matrix...");
try {
const response = await fetch('/api/tts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: cleanText })
});
if (!response.ok) throw new Error("Backend Synthesis Fault");
const blob = await response.blob();
const audioUrl = URL.createObjectURL(blob);
const audio = new Audio(audioUrl);
audio.play();
} catch (error) {
Utils.showToast("Neural link failed. Verify backend integrity.");
}
}
};
VoiceEngine.init();
/**
* Live Mode Controller
*/
const LiveModeController = {
initialize: () => {
AppState.isLiveModeEngaged = true;
document.getElementById('liveOverlay').classList.add('active');
if (VoiceEngine.recognition) {
setTimeout(() => {
try { VoiceEngine.recognition.start(); } catch(e){}
}, 600);
}
},
terminate: () => {
AppState.isLiveModeEngaged = false;
document.getElementById('liveOverlay').classList.remove('active');
if (VoiceEngine.recognition) {
try { VoiceEngine.recognition.stop(); } catch(e){}
}
}
};
/**
* File & Attachment Processor
*/
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;
// Strict validation
if (typeContext === 'image' && !mime.startsWith('image/')) { Utils.showToast("Format Rejected: Visual media required."); inputElement.value=''; return; }
if (typeContext === 'video' && !mime.startsWith('video/')) { Utils.showToast("Format Rejected: Video media required."); inputElement.value=''; return; }
if (typeContext === 'audio' && !mime.startsWith('audio/')) { Utils.showToast("Format Rejected: Audio media required."); inputElement.value=''; return; }
// Non-technical Toast Update
Utils.showToast("Uploading your file, please wait...");
// Prepare UI preview
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 {
// Standard Text/Code parsing
fileReader.onload = (e) => {
AppState.pendingAttachment = { type: 'text', data: e.target.result, name: file.name };
Utils.showToast("Your file is ready!");
};
fileReader.readAsText(file);
}
}
// Reset input for sequential identical uploads
inputElement.value = '';
},
discardFile: () => {
AppState.pendingAttachment = null;
document.getElementById('filePreviewBar').classList.remove('visible');
}
};
/**
* Workspace Code Engine
*/
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);
}
}
};
// Customize Marked.js Renderer for Streaming UI & Workspace Cards
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 || '');
// Render beautiful loading box during stream
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>`;
}
// Once stream ends, render functional Workspace button
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'}</p>
</div>
</div>
<button class="btn-launch-workspace" onclick="WorkspaceEngine.launch(${internalId})">Open Workspace</button>
</div>`;
};
marked.use({ renderer: MD_Renderer });
/**
* Core Chat Processing Engine
*/
const ChatEngine = {
handleKeyboard: (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
ChatEngine.initiateDispatch();
}
},
sendExample: (queryText) => {
document.getElementById('mainChatInput').value = queryText;
ChatEngine.initiateDispatch();
},
clearMemory: async () => {
if (AppState.currentUser) {
Utils.showToast("Purging neural link memory...");
await fetch(Config.GAS_URL, {
method: 'POST',
body: JSON.stringify({ action: "delete_history", email: AppState.currentUser })
});
}
location.reload();
},
syncHistoryFromCloud: async () => {
const messageZone = document.getElementById('msgs');
document.getElementById('welcomeState').style.display = 'none';
messageZone.innerHTML = '<div style="text-align:center; padding:80px; font-weight:800; color:var(--brand-saffron); font-size:18px;">Decrypting Historic Archives...</div>';
try {
const response = await fetch(Config.GAS_URL, {
method: 'POST',
body: JSON.stringify({ action: "get_history", email: AppState.currentUser })
});
const resData = await response.json();
messageZone.innerHTML = '';
if (resData.status === 'success' && resData.historyJSON !== "[]") {
AppState.history = JSON.parse(resData.historyJSON);
AppState.history.forEach(msgObj => {
if (msgObj.role === 'user') {
ChatEngine.renderUserMessage(msgObj.content, msgObj.badge, msgObj.previewHTML);
} else {
AppState.isStreamingActive = false;
ChatEngine.renderBotMessage(msgObj.content, true);
}
});
setTimeout(UIManager.forceScrollDown, 150);
} else {
document.getElementById('welcomeState').style.display = 'flex';
}
} catch (err) {
messageZone.innerHTML = '';
document.getElementById('welcomeState').style.display = 'flex';
}
},
saveHistoryToCloud: () => {
if (AppState.currentUser) {
fetch(Config.GAS_URL, {
method: 'POST',
body: JSON.stringify({ action: "save_history", email: AppState.currentUser, historyJSON: JSON.stringify(AppState.history) })
});
}
},
// Creates visually appealing preview HTML for within the chat bubble
buildPreviewHTML: (attachmentObj) => {
if (!attachmentObj) return '';
if (attachmentObj.type === 'image') {
return `<img src="data:image/jpeg;base64,${attachmentObj.data}" class="chat-in-bubble-img" alt="Attached Image">`;
} else if (attachmentObj.type === 'video') {
return `<div class="chat-file-card"><span class="icon">🎥</span><span class="name">${attachmentObj.name}</span></div>`;
} else if (attachmentObj.type === 'audio') {
return `<div class="chat-file-card"><span class="icon">🎵</span><span class="name">${attachmentObj.name}</span></div>`;
} else {
return `<div class="chat-file-card"><span class="icon">📄</span><span class="name">${attachmentObj.name}</span></div>`;
}
},
renderUserMessage: (textContent, badgeText, previewHTMLString = '') => {
let badgeNode = badgeText ? `<div class="file-badge">${Utils.escapeHTML(badgeText)}</div>` : '';
const bubbleBox = document.createElement('div');
bubbleBox.className = 'chat-message-row user-msg';
bubbleBox.innerHTML = `
<div class="msg-avatar">U</div>
<div class="msg-content-column">
${badgeNode}
<div class="chat-bubble">
${previewHTMLString}
${Utils.escapeHTML(textContent)}
</div>
</div>`;
document.getElementById('msgs').appendChild(bubbleBox);
},
renderBotMessage: (textContent, bypassStreamFormatting = false) => {
const bubbleBox = document.createElement('div');
bubbleBox.className = 'chat-message-row bot-msg';
bubbleBox.innerHTML = `
<div class="msg-avatar"><img src="${Config.LOGO_URL}" alt="AI"></div>
<div class="msg-content-column">
<div class="chat-bubble"></div>
</div>`;
document.getElementById('msgs').appendChild(bubbleBox);
ChatEngine.updateBotBubble(bubbleBox, textContent, !bypassStreamFormatting);
return bubbleBox;
},
updateBotBubble: (bubbleDOM, rawMarkup, isCurrentlyStreaming) => {
const contentTarget = bubbleDOM.querySelector('.chat-bubble');
// Strip out internal `<think>` reasoning logic so it is hidden
const strippedMarkup = rawMarkup.replace(/<think>([\s\S]*?)(<\/think>|$)/gi, '');
let renderHTML = marked.parse(strippedMarkup.trim());
if (isCurrentlyStreaming) {
renderHTML += `<div class="loading-dots-container"><div class="loading-dot"></div><div class="loading-dot"></div><div class="loading-dot"></div></div>`;
}
contentTarget.innerHTML = renderHTML;
// Mount actionable buttons when complete
let actionTray = bubbleDOM.querySelector('.bot-actions-row');
if (!isCurrentlyStreaming && !actionTray && strippedMarkup.trim().length > 0) {
const safeRawCopy = strippedMarkup.replace(/"/g, '&quot;').replace(/'/g, "\\'").replace(/\n/g, '\\n').replace(/\r/g, '');
const safeRawTTS = strippedMarkup.replace(/"/g, '&quot;').replace(/'/g, "\\'").replace(/\n/g, ' ');
const actionsHTML = `
<div class="bot-actions-row">
<button class="btn-bot-action" onclick="Utils.copyToClipboard(this, \`${safeRawCopy}\`)">
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
Copy Logic
</button>
<button class="btn-bot-action action-tts" onclick="VoiceEngine.executeTTS(\`${safeRawTTS}\`)">
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path></svg>
Neural Voice
</button>
</div>`;
bubbleDOM.querySelector('.msg-content-column').insertAdjacentHTML('beforeend', actionsHTML);
}
},
initiateDispatch: async () => {
if (AppState.isProcessing) return;
const inputField = document.getElementById('mainChatInput');
const rawUserText = inputField.value.trim();
if (!rawUserText && !AppState.pendingAttachment) return;
// Validate Guest Session Constraint
if (!AppState.currentUser) {
if (AppState.guestCount >= 3) {
AuthManager.openModal();
return Utils.showToast("Unregistered query limit reached. Secure Login required.");
}
AppState.guestCount++;
localStorage.setItem('arjun_guest', AppState.guestCount.toString());
document.getElementById('guestCountDisplay').innerText = AppState.guestCount;
}
// UI Cleanup prior to dispatch
inputField.value = '';
inputField.style.height = 'auto';
document.getElementById('masterSendBtn').disabled = true;
AppState.isProcessing = true;
const wState = document.getElementById('welcomeState');
if (wState) wState.style.display = 'none';
let payloadStr = rawUserText;
let payloadAttachments = [];
let visualBadge = null;
let previewHTMLForChat = '';
// Handle Pending Document/Media Logic
if (AppState.pendingAttachment) {
previewHTMLForChat = ChatEngine.buildPreviewHTML(AppState.pendingAttachment);
if (AppState.pendingAttachment.type === 'text') {
payloadStr = `[Document Analyzed: ${AppState.pendingAttachment.name}]\n\n---DATA BEGIN---\n${AppState.pendingAttachment.data}\n---DATA END---\n\nUser Prompt: ${rawUserText}`;
visualBadge = '📄 File Appended';
} else {
payloadAttachments.push({
type: AppState.pendingAttachment.type,
data: AppState.pendingAttachment.data,
name: AppState.pendingAttachment.name
});
const icoMap = { 'video': '🎥 ', 'audio': '🎵 ', 'image': '🖼️ ' };
visualBadge = (icoMap[AppState.pendingAttachment.type] || '📎 ') + "Media Appended";
}
// Render locally
ChatEngine.renderUserMessage(rawUserText || '[Transmitting Media Context]', visualBadge, previewHTMLForChat);
// Save to logical history
AppState.history.push({
role: 'user',
content: payloadStr,
badge: visualBadge,
previewHTML: previewHTMLForChat
});
} else {
ChatEngine.renderUserMessage(rawUserText, null, '');
AppState.history.push({ role: 'user', content: rawUserText });
}
FileProcessor.discardFile();
ChatEngine.saveHistoryToCloud();
// Create Empty Bot Bubble for streaming
const activeBotBubble = ChatEngine.renderBotMessage('', false);
UIManager.forceScrollDown();
// 🎲 Dynamic Pollinations Generator
const cryptographicSeed = Math.floor(Math.random() * 999999999);
// 🧠 Advanced Cognitive System Instructions
let cognitivePrompt = `You are Arjun 2.O, a sophisticated enterprise AI system architected by Abhay Kumar.
LANGUAGE REGULATION: You possess strict bilingual fluency. You MUST analyze the user's language and respond seamlessly in BOTH English and Hindi.
- If the prompt is purely English, output pure English.
- If the prompt contains Hindi (Devanagari or Hinglish), respond in natural Hindi.
- Adapt tone to be highly professional, intelligent, and authoritative.
IMAGE SYNTHESIS OVERRIDE:
When commanded to render, generate, or create an image/photograph, you MUST reply with a precise markdown image node targeting Pollinations AI.
Formula: ![Generating Vision...](https://image.pollinations.ai/prompt/{URL_ENCODED_PROMPT_DETAIL}?width=1024&height=1024&nologo=true&model={MODEL}&seed=${cryptographicSeed})
Available Models: flux, flux-realism, flux-anime, flux-3d.
CRITICAL: The seed parameter is mandatory to bypass cache mechanics. Always render this markdown node.`;
if (AppState.isLiveModeEngaged) {
cognitivePrompt += `\n\n[LIVE ACOUSTIC OVERRIDE]: You are currently engaged in a LIVE, REAL-TIME VOCAL INTERFACE.
MANDATORY direct answers. Maximum brevity. Eliminate complex markdown, massive code blocks, or extended lists. Replicate human telephonic brevity perfectly.`;
}
// Sanitize payload for backend
const secureHistory = AppState.history.slice(0, -1).map(h => ({ role: h.role, content: h.content }));
const transmissionPayload = {
message: payloadStr,
attachments: payloadAttachments,
system_prompt: cognitivePrompt,
history: secureHistory,
max_tokens: AppState.isLiveModeEngaged ? 120 : 4096,
temperature: 0.75
};
// Network Transmission Logic
try {
const fetchOp = await fetch('/api/chat', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(transmissionPayload)
});
if (!fetchOp.ok) throw new Error("API Matrix Disconnected.");
const networkReader = fetchOp.body.getReader();
const textDecoder = new TextDecoder();
let responseBuffer = "";
AppState.isStreamingActive = true;
while (true) {
const { done, value } = await networkReader.read();
if (done) break;
const decodedChunk = textDecoder.decode(value, { stream: true });
const fragmentedLines = decodedChunk.split('\n');
for (let line of fragmentedLines) {
if (line.startsWith('data: ')) {
const parseableStr = line.substring(6);
if (parseableStr.trim() === '[DONE]') continue;
try {
const jsonSegment = JSON.parse(parseableStr);
if (jsonSegment.choices && jsonSegment.choices[0].delta.content) {
responseBuffer += jsonSegment.choices[0].delta.content;
ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, true);
UIManager.autoScroll();
}
} catch (e) { /* Segment fragmentation caught silently */ }
}
}
}
AppState.isStreamingActive = false;
ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, false);
AppState.history.push({ role: 'bot', content: responseBuffer });
ChatEngine.saveHistoryToCloud();
if (AppState.isLiveModeEngaged) {
document.getElementById('liveStatusText').innerText = "Arjun Transmitting...";
await VoiceEngine.executeTTS(responseBuffer);
document.getElementById('liveStatusText').innerText = "Tap mic to respond";
}
} catch(error) {
AppState.isStreamingActive = false;
ChatEngine.updateBotBubble(activeBotBubble, `**System Error:** Communication array offline. Verification needed.`, false);
if (AppState.isLiveModeEngaged) {
document.getElementById('liveStatusText').innerText = "Neural Link Severed.";
}
}
AppState.isProcessing = false;
document.getElementById('masterSendBtn').disabled = false;
UIManager.autoScroll();
}
};
// Bootstrap Core
window.ApplicationCore = {
launchSystem: startArjunApp
};
</script>
</body>
</html>