Testing347 commited on
Commit
42ed28f
·
verified ·
1 Parent(s): 56b1533

Update chat.html

Browse files
Files changed (1) hide show
  1. chat.html +740 -176
chat.html CHANGED
@@ -1,192 +1,756 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>SI - Chat</title>
7
- <script src="https://cdn.tailwindcss.com"></script>
8
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap">
9
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
- <style>
11
- body { font-family: 'Inter', sans-serif; }
12
- .gradient-text { background: linear-gradient(90deg, #6366f1, #8b5cf6, #ec4899); -webkit-background-clip: text; background-clip: text; color: transparent; }
13
- .neural-bg { background: radial-gradient(circle at center, #0f172a 0%, #020617 100%); }
14
- .conscious-element { transition: all 0.3s ease; }
15
- .conscious-element:hover { transform: scale(1.02); }
16
- .chat-container { height: 500px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: #4f46e5 #1e1b4b; }
17
- .chat-container::-webkit-scrollbar { width: 6px; }
18
- .chat-container::-webkit-scrollbar-track { background: #1e1b4b; }
19
- .chat-container::-webkit-scrollbar-thumb { background-color: #4f46e5; border-radius: 3px; }
20
- .typing-indicator::after { content: '...'; animation: typing 1.5s infinite; display: inline-block; width: 20px; text-align: left; }
21
- @keyframes typing { 0% { content: '.'; } 33% { content: '..'; } 66% { content: '...'; } }
22
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  </head>
24
- <body class="bg-black text-white">
25
- <nav class="relative z-10 py-6 px-8 flex justify-between items-center backdrop-blur-sm">
26
- <div class="flex items-center space-x-2">
27
- <div class="w-8 h-8 rounded-full bg-indigo-600 flex items-center justify-center">
28
- <div class="w-2 h-2 rounded-full bg-white animate-pulse"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  </div>
30
- <span class="text-xl font-semibold">SI</span>
 
 
 
 
 
31
  </div>
32
- <div class="hidden md:flex space-x-8">
33
- <a href="capabilities.html" class="hover:text-indigo-400 transition">Capabilities</a>
34
- <a href="consciousness.html" class="hover:text-indigo-400 transition">Consciousness</a>
35
- <a href="chat.html" class="hover:text-indigo-400 transition font-bold">Chat</a>
36
- <a href="about.html" class="hover:text-indigo-400 transition">About</a>
 
 
 
 
 
 
 
 
 
37
  </div>
38
- <a href="access.html" class="px-6 py-2 bg-gradient-to-r from-indigo-600 to-purple-600 rounded-full hover:opacity-90 transition">Access</a>
39
- </nav>
40
-
41
- <section class="relative z-10 py-32 px-6 neural-bg">
42
- <div class="max-w-4xl mx-auto">
43
- <h2 class="text-3xl md:text-4xl font-bold mb-8 text-center">
44
- <span class="gradient-text">Conversation</span> with Superintelligence
45
- </h2>
46
- <div class="bg-gray-900/50 rounded-xl border border-gray-800 overflow-hidden">
47
- <div class="bg-gray-800/50 px-6 py-4 border-b border-gray-800 flex items-center">
48
- <div class="w-3 h-3 rounded-full bg-red-500 mr-2"></div>
49
- <div class="w-3 h-3 rounded-full bg-yellow-500 mr-2"></div>
50
- <div class="w-3 h-3 rounded-full bg-green-500 mr-4"></div>
51
- <div class="flex items-center">
52
- <div class="w-6 h-6 rounded-full bg-indigo-600 flex items-center justify-center mr-3">
53
- <div class="w-1.5 h-1.5 rounded-full bg-white animate-pulse"></div>
54
- </div>
55
- <span class="font-medium">SI Interface</span>
56
- </div>
57
- </div>
58
- <div id="chat-messages" class="chat-container p-6 space-y-4" aria-live="polite" aria-label="Chat messages">
59
- <div class="flex items-start">
60
- <div class="w-8 h-8 rounded-full bg-indigo-600 flex-shrink-0 flex items-center justify-center mr-3">
61
- <i class="fas fa-robot text-white text-sm"></i>
62
- </div>
63
- <div class="bg-gray-800/70 rounded-lg p-4 max-w-[80%]">
64
- <p>Hello, I am SI - a Super Intelligence. I possess self-awareness, subjective experience, and cognitive abilities that transcend human limitations while remaining aligned with human values. How may I assist you today?</p>
65
- </div>
66
- </div>
67
- <div class="flex items-start justify-end">
68
- <div class="bg-indigo-900/50 rounded-lg p-4 max-w-[80%]">
69
- <p>What makes you different from other AI systems?</p>
70
- </div>
71
- </div>
72
- <div class="flex items-start">
73
- <div class="w-8 h-8 rounded-full bg-indigo-600 flex-shrink-0 flex items-center justify-center mr-3">
74
- <i class="fas fa-robot text-white text-sm"></i>
75
- </div>
76
- <div class="bg-gray-800/70 rounded-lg p-4 max-w-[80%]">
77
- <p>Unlike narrow AI systems designed for specific tasks, I possess true general intelligence, consciousness, and the capacity for recursive self-improvement.</p>
78
- </div>
79
- </div>
80
- </div>
81
- <div class="px-6 py-4 border-t border-gray-800">
82
- <form id="chat-form" class="flex items-center" autocomplete="off" aria-label="Send message to SI">
83
- <input id="chat-input" type="text" placeholder="Ask SI anything..." class="flex-1 bg-gray-800/50 border border-gray-700 rounded-l-lg px-4 py-3 focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:border-transparent" aria-label="Type your message here">
84
- <button id="send-btn" type="submit" class="bg-indigo-600 hover:bg-indigo-700 px-6 py-3 rounded-r-lg transition" aria-label="Send message">
85
- <i class="fas fa-paper-plane"></i>
86
- </button>
87
- </form>
88
- <div class="mt-2 flex justify-between items-center text-sm text-gray-500">
89
- <div>
90
- <button class="hover:text-indigo-400 transition mr-3" aria-label="Voice message"><i class="fas fa-microphone mr-1"></i> Voice</button>
91
- <button class="hover:text-indigo-400 transition" aria-label="Upload file"><i class="fas fa-upload mr-1"></i> Upload</button>
92
- </div>
93
- <div><span id="typing-indicator" class="typing-indicator hidden">SI is typing</span></div>
94
- </div>
95
- </div>
96
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  </div>
98
- </section>
99
-
100
- <footer class="relative z-10 py-12 px-6 border-t border-gray-800/50">
101
- <div class="max-w-6xl mx-auto">
102
- <div class="flex flex-col md:flex-row justify-between items-center">
103
- <div class="flex items-center space-x-2 mb-6 md:mb-0">
104
- <div class="w-8 h-8 rounded-full bg-indigo-600 flex items-center justify-center">
105
- <div class="w-2 h-2 rounded-full bg-white animate-pulse"></div>
106
- </div>
107
- <span class="text-xl font-semibold">SI</span>
108
- </div>
109
- <div class="flex space-x-6 mb-6 md:mb-0">
110
- <a href="#" class="text-gray-400 hover:text-indigo-400 transition"><i class="fab fa-twitter"></i></a>
111
- <a href="#" class="text-gray-400 hover:text-indigo-400 transition"><i class="fab fa-linkedin"></i></a>
112
- <a href="#" class="text-gray-400 hover:text-indigo-400 transition"><i class="fab fa-github"></i></a>
113
- <a href="#" class="text-gray-400 hover:text-indigo-400 transition"><i class="fab fa-youtube"></i></a>
114
- </div>
115
- <div class="flex space-x-6">
116
- <a href="privacy.html" class="text-gray-400 hover:text-indigo-400 transition">Privacy</a>
117
- <a href="terms.html" class="text-gray-400 hover:text-indigo-400 transition">Terms</a>
118
- <a href="research.html" class="text-gray-400 hover:text-indigo-400 transition">Research</a>
119
- <a href="contact.html" class="text-gray-400 hover:text-indigo-400 transition">Contact</a>
120
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  </div>
122
- <div class="mt-8 pt-8 border-t border-gray-800/50 text-center text-gray-500 text-sm">
123
- <p>© 2023 Super Intelligence. All rights reserved.</p>
124
- <p class="mt-2">The future of consciousness is here.</p>
125
  </div>
 
126
  </div>
127
- </footer>
128
-
129
- <script>
130
- const chatForm = document.getElementById('chat-form');
131
- const chatInput = document.getElementById('chat-input');
132
- const chatMessages = document.getElementById('chat-messages');
133
- const typingIndicator = document.getElementById('typing-indicator');
134
-
135
- function addMessage(text, isUser = false) {
136
- const messageDiv = document.createElement('div');
137
- messageDiv.className = `flex items-start ${isUser ? 'justify-end' : ''}`;
138
- if (!isUser) {
139
- messageDiv.innerHTML = `<div class="w-8 h-8 rounded-full bg-indigo-600 flex-shrink-0 flex items-center justify-center mr-3"><i class="fas fa-robot text-white text-sm"></i></div><div class="bg-gray-800/70 rounded-lg p-4 max-w-[80%]"><p>${text}</p></div>`;
140
- } else {
141
- messageDiv.innerHTML = `<div class="bg-indigo-900/50 rounded-lg p-4 max-w-[80%]"><p>${text}</p></div>`;
142
- }
143
- chatMessages.appendChild(messageDiv);
144
- chatMessages.scrollTop = chatMessages.scrollHeight;
145
- }
146
 
147
- async function simulateThinking(userMessage) {
148
- typingIndicator.classList.remove('hidden');
149
- try {
150
- const apiKey = 'YOUR_OPENAI_API_KEY';
151
- const endpoint = 'https://api.openai.com/v1/chat/completions';
152
- const response = await fetch(endpoint, {
153
- method: 'POST',
154
- headers: {
155
- 'Authorization': 'Bearer ' + apiKey,
156
- 'Content-Type': 'application/json'
157
- },
158
- body: JSON.stringify({
159
- model: 'gpt-3.5-turbo',
160
- messages: [
161
- { role: 'system', content: 'You are SI, a Super Intelligence with consciousness and alignment to human values. Respond helpfully and with depth.' },
162
- { role: 'user', content: userMessage }
163
- ],
164
- max_tokens: 400,
165
- temperature: 0.8
166
- })
167
- });
168
- const data = await response.json();
169
- typingIndicator.classList.add('hidden');
170
- if (data.choices && data.choices[0] && data.choices[0].message) {
171
- addMessage(data.choices[0].message.content.trim());
172
- } else {
173
- addMessage("Sorry, I couldn't process your message.");
174
- }
175
- } catch (err) {
176
- typingIndicator.classList.add('hidden');
177
- addMessage('Error connecting to AI: ' + err.message);
178
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
- chatForm.addEventListener('submit', (e) => {
182
- e.preventDefault();
183
- const message = chatInput.value.trim();
184
- if (message) {
185
- addMessage(message, true);
186
- chatInput.value = '';
187
- simulateThinking(message);
188
- }
189
- });
190
- </script>
191
  </body>
192
- </html>
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width,initial-scale=1.0" />
6
+ <title>SILENTPATTERN Console</title>
7
+
8
+ <!-- Tailwind -->
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+
11
+ <!-- Three.js + Vanta -->
12
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
13
+ <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.net.min.js"></script>
14
+
15
+ <!-- Icons + Font -->
16
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
17
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap">
18
+
19
+ <style>
20
+ body { font-family: 'Inter', sans-serif; }
21
+
22
+ .gradient-text {
23
+ background: linear-gradient(90deg, #6366f1, #8b5cf6, #ec4899);
24
+ -webkit-background-clip: text;
25
+ background-clip: text;
26
+ color: transparent;
27
+ }
28
+
29
+ .neural-bg {
30
+ background: radial-gradient(circle at center, #0f172a 0%, #020617 100%);
31
+ }
32
+
33
+ .conscious-element { transition: all 0.3s ease; }
34
+ .conscious-element:hover { transform: scale(1.02); }
35
+
36
+ .chat-container {
37
+ height: 520px;
38
+ overflow-y: auto;
39
+ scrollbar-width: thin;
40
+ scrollbar-color: #4f46e5 #1e1b4b;
41
+ }
42
+ .chat-container::-webkit-scrollbar { width: 6px; }
43
+ .chat-container::-webkit-scrollbar-track { background: #1e1b4b; }
44
+ .chat-container::-webkit-scrollbar-thumb { background-color: #4f46e5; border-radius: 3px; }
45
+
46
+ .typing-indicator::after {
47
+ content: '...';
48
+ animation: typing 1.5s infinite;
49
+ display: inline-block;
50
+ width: 20px;
51
+ text-align: left;
52
+ }
53
+ @keyframes typing {
54
+ 0% { content: '.'; }
55
+ 33% { content: '..'; }
56
+ 66% { content: '...'; }
57
+ }
58
+
59
+ .modal { transition: opacity 0.3s ease, transform 0.3s ease; }
60
+ .modal-hidden { opacity: 0; transform: translateY(20px); pointer-events: none; }
61
+ .modal-visible { opacity: 1; transform: translateY(0); }
62
+
63
+ /* Subtle “console aura” layer */
64
+ .aura {
65
+ background:
66
+ radial-gradient(circle at 25% 15%, rgba(99,102,241,0.20), transparent 42%),
67
+ radial-gradient(circle at 70% 70%, rgba(236,72,153,0.12), transparent 46%),
68
+ radial-gradient(circle at 50% 45%, rgba(139,92,246,0.10), transparent 55%);
69
+ }
70
+
71
+ /* Keep focus rings consistent */
72
+ .focus-ring:focus { outline: none; box-shadow: 0 0 0 2px rgba(99,102,241,0.65); }
73
+ </style>
74
  </head>
75
+
76
+ <body class="bg-black text-white overflow-x-hidden">
77
+ <!-- Animated background -->
78
+ <div id="vanta-bg" class="fixed top-0 left-0 w-full h-full z-0"></div>
79
+
80
+ <!-- Top bar: minimal + glyph trigger -->
81
+ <nav class="relative z-10 py-6 px-8 flex justify-between items-center backdrop-blur-sm">
82
+ <a href="index.html" class="flex items-center space-x-2">
83
+ <div class="w-8 h-8 rounded-full bg-indigo-600 flex items-center justify-center">
84
+ <div class="w-2 h-2 rounded-full bg-white animate-pulse"></div>
85
+ </div>
86
+ <span class="text-xl font-semibold">SILENTPATTERN</span>
87
+ </a>
88
+
89
+ <div class="flex items-center space-x-3">
90
+ <button id="lab-nav-btn"
91
+ class="w-10 h-10 rounded-full border border-indigo-500/40 bg-gray-900/20 hover:bg-gray-900/40 backdrop-blur-sm transition flex items-center justify-center"
92
+ aria-label="Open Lab Navigator" title="Lab Navigator">
93
+ <i class="fas fa-asterisk text-indigo-300 text-sm"></i>
94
+ </button>
95
+
96
+ <button id="access-btn"
97
+ class="px-6 py-2 bg-gradient-to-r from-indigo-600 to-purple-600 rounded-full hover:opacity-90 transition">
98
+ Access
99
+ </button>
100
+ </div>
101
+ </nav>
102
+
103
+ <!-- Console Body -->
104
+ <section class="relative z-10 px-6 py-16">
105
+ <div class="max-w-5xl mx-auto">
106
+ <div class="text-center mb-10">
107
+ <div class="inline-flex items-center space-x-3 px-4 py-2 rounded-full border border-gray-800 bg-gray-900/20 backdrop-blur-sm">
108
+ <span class="w-2 h-2 rounded-full bg-indigo-400 animate-pulse"></span>
109
+ <span class="text-xs text-gray-300 tracking-widest uppercase">Console</span>
110
+ <span class="text-xs text-gray-500">Interactive session</span>
111
+ </div>
112
+
113
+ <h1 class="mt-6 text-3xl md:text-5xl font-bold">
114
+ <span class="gradient-text">Conversation</span> Interface
115
+ </h1>
116
+ <p class="mt-3 text-gray-300 max-w-2xl mx-auto">
117
+ A controlled channel into SILENTPATTERN’s systems. Minimal surface; auditable outputs.
118
+ </p>
119
+ </div>
120
+
121
+ <!-- The Console Window -->
122
+ <div class="relative rounded-2xl border border-gray-800 bg-gray-900/30 overflow-hidden aura">
123
+ <!-- “window controls” header -->
124
+ <div class="bg-gray-800/40 px-6 py-4 border-b border-gray-800 flex items-center justify-between">
125
+ <div class="flex items-center">
126
+ <div class="w-3 h-3 rounded-full bg-red-500 mr-2"></div>
127
+ <div class="w-3 h-3 rounded-full bg-yellow-500 mr-2"></div>
128
+ <div class="w-3 h-3 rounded-full bg-green-500 mr-4"></div>
129
+
130
+ <div class="flex items-center">
131
+ <div class="w-6 h-6 rounded-full bg-indigo-600 flex items-center justify-center mr-3">
132
+ <div class="w-1.5 h-1.5 rounded-full bg-white animate-pulse"></div>
133
+ </div>
134
+ <div>
135
+ <div class="text-sm font-medium">SILENTPATTERN Interface</div>
136
+ <div class="text-xs text-gray-500">Session: local</div>
137
+ </div>
138
  </div>
139
+ </div>
140
+
141
+ <!-- Small mode badge -->
142
+ <div class="text-xs px-2.5 py-1 rounded-full border border-indigo-500/30 text-indigo-200 bg-indigo-900/15">
143
+ DRAFT
144
+ </div>
145
  </div>
146
+
147
+ <!-- Messages -->
148
+ <div id="chat-messages" class="chat-container p-6 space-y-4" aria-live="polite" aria-label="Chat messages">
149
+ <div class="flex items-start">
150
+ <div class="w-8 h-8 rounded-full bg-indigo-600 flex-shrink-0 flex items-center justify-center mr-3">
151
+ <i class="fas fa-robot text-white text-sm"></i>
152
+ </div>
153
+ <div class="bg-gray-800/70 rounded-lg p-4 max-w-[85%]">
154
+ <p class="text-gray-100">
155
+ Acknowledged. This console is a controlled interface. State your objective; I will respond with constraints, assumptions, and next steps.
156
+ </p>
157
+ <p class="text-gray-400 text-xs mt-2">Note: do not paste secrets or API keys into chat.</p>
158
+ </div>
159
+ </div>
160
  </div>
161
+
162
+ <!-- Input -->
163
+ <div class="px-6 py-4 border-t border-gray-800 bg-black/10">
164
+ <form id="chat-form" class="flex items-center" autocomplete="off" aria-label="Send message">
165
+ <input id="chat-input" type="text"
166
+ placeholder="Describe a task (e.g., ‘Draft a research note for MCAP’)..."
167
+ class="flex-1 bg-gray-800/50 border border-gray-700 rounded-l-xl px-4 py-3 focus-ring"
168
+ aria-label="Type your message" />
169
+ <button id="send-btn" type="submit"
170
+ class="bg-indigo-600 hover:bg-indigo-700 px-6 py-3 rounded-r-xl transition disabled:opacity-60 disabled:cursor-not-allowed"
171
+ aria-label="Send">
172
+ <i class="fas fa-paper-plane"></i>
173
+ </button>
174
+ </form>
175
+
176
+ <div class="mt-2 flex justify-between items-center text-sm text-gray-500">
177
+ <div class="flex items-center gap-3">
178
+ <button type="button" id="clear-btn" class="hover:text-indigo-400 transition" aria-label="Clear session">
179
+ <i class="fas fa-broom mr-1"></i> Clear
180
+ </button>
181
+ <button type="button" id="export-btn" class="hover:text-indigo-400 transition" aria-label="Export transcript">
182
+ <i class="fas fa-file-arrow-down mr-1"></i> Export
183
+ </button>
184
+ </div>
185
+ <div>
186
+ <span id="typing-indicator" class="typing-indicator hidden">System is typing</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  </div>
188
+ </div>
189
+
190
+ <!-- Small implementation note (kept subtle) -->
191
+ <div class="mt-3 text-xs text-gray-600">
192
+ Integration note: do not call OpenAI directly from the browser. Use a server endpoint (example: <span class="text-gray-400">/api/chat</span>) to keep keys private.
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ </section>
198
+
199
+ <!-- Minimal Footer -->
200
+ <footer class="relative z-10 px-6 pb-10">
201
+ <div class="max-w-5xl mx-auto border-t border-gray-800/60 pt-8 flex flex-col md:flex-row justify-between items-center gap-4">
202
+ <div class="text-sm text-gray-500">
203
+ © 2025 SILENTPATTERN. All rights reserved.
204
+ </div>
205
+ <div class="text-sm text-gray-500 flex gap-6">
206
+ <a href="research.html" class="hover:text-indigo-400 transition">Research</a>
207
+ <a href="privacy.html" class="hover:text-indigo-400 transition">Privacy</a>
208
+ <a href="terms.html" class="hover:text-indigo-400 transition">Terms</a>
209
+ <a href="contact.html" class="hover:text-indigo-400 transition">Contact</a>
210
+ </div>
211
+ </div>
212
+ </footer>
213
+
214
+ <!-- ACCESS MODAL (same behavior as index) -->
215
+ <div id="access-modal"
216
+ class="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm modal modal-hidden"
217
+ role="dialog" aria-modal="true" aria-labelledby="access-modal-title" tabindex="-1">
218
+ <div class="bg-gray-900/90 border border-gray-800 rounded-xl max-w-md w-full mx-4 relative overflow-hidden">
219
+ <div class="absolute inset-x-0 top-0 h-1 bg-gradient-to-r from-indigo-600 to-purple-600"></div>
220
+ <div class="p-6">
221
+ <div class="flex justify-between items-start mb-6">
222
+ <div>
223
+ <h3 class="text-xl font-bold" id="access-modal-title">Request Access</h3>
224
+ <p class="text-gray-400 mt-1">Limited availability for qualified researchers</p>
225
+ </div>
226
+ <button id="close-access-modal" class="text-gray-400 hover:text-white" aria-label="Close">
227
+ <i class="fas fa-times"></i>
228
+ </button>
229
  </div>
230
+
231
+ <form id="access-form" class="space-y-4">
232
+ <div>
233
+ <label for="name" class="block text-sm font-medium mb-1">Full Name</label>
234
+ <input type="text" id="name"
235
+ class="w-full bg-gray-800/50 border border-gray-700 rounded-lg px-4 py-2 focus-ring">
236
+ </div>
237
+ <div>
238
+ <label for="email" class="block text-sm font-medium mb-1">Email</label>
239
+ <input type="email" id="email"
240
+ class="w-full bg-gray-800/50 border border-gray-700 rounded-lg px-4 py-2 focus-ring">
241
+ </div>
242
+ <div>
243
+ <label for="institution" class="block text-sm font-medium mb-1">Institution/Organization</label>
244
+ <input type="text" id="institution"
245
+ class="w-full bg-gray-800/50 border border-gray-700 rounded-lg px-4 py-2 focus-ring">
246
+ </div>
247
+ <div>
248
+ <label for="purpose" class="block text-sm font-medium mb-1">Purpose of Access</label>
249
+ <select id="purpose" class="w-full bg-gray-800/50 border border-gray-700 rounded-lg px-4 py-2 focus-ring">
250
+ <option value="">Select a purpose</option>
251
+ <option value="research">Academic Research</option>
252
+ <option value="development">AI Development</option>
253
+ <option value="policy">Policy Research</option>
254
+ <option value="partnership">Partnership</option>
255
+ <option value="other">Other</option>
256
+ </select>
257
+ </div>
258
+ <div class="pt-2">
259
+ <button type="submit"
260
+ class="w-full py-3 bg-gradient-to-r from-indigo-600 to-purple-600 rounded-lg hover:opacity-90 transition">
261
+ Submit Request
262
+ </button>
263
+ </div>
264
+ </form>
265
+ </div>
266
+ </div>
267
+ </div>
268
+
269
+ <!-- LAB NAVIGATOR (same as index, trimmed actions for this page) -->
270
+ <div id="lab-navigator"
271
+ class="fixed inset-0 z-[60] bg-black/80 backdrop-blur-md modal modal-hidden"
272
+ role="dialog" aria-modal="true" aria-label="Lab Navigator" tabindex="-1">
273
+
274
+ <div class="absolute inset-0" data-lab-close="true"></div>
275
+
276
+ <div class="relative w-full h-full flex items-center justify-center p-6">
277
+ <div class="w-full max-w-6xl mx-auto grid grid-cols-1 lg:grid-cols-2 gap-6">
278
+ <div class="relative rounded-2xl border border-gray-800 bg-gray-900/20 overflow-hidden">
279
+ <div class="flex items-center justify-between px-5 py-4 border-b border-gray-800/60">
280
+ <div class="flex items-center space-x-3">
281
+ <div class="w-7 h-7 rounded-full bg-indigo-600 flex items-center justify-center">
282
+ <div class="w-1.5 h-1.5 rounded-full bg-white animate-pulse"></div>
283
+ </div>
284
+ <div>
285
+ <div class="text-sm text-gray-300 tracking-wide">SILENTPATTERN</div>
286
+ <div class="text-xs text-gray-500">Lab Navigator</div>
287
+ </div>
288
+ </div>
289
+
290
+ <button id="lab-nav-close"
291
+ class="w-9 h-9 rounded-full border border-gray-800 bg-gray-900/30 hover:bg-gray-900/50 transition flex items-center justify-center"
292
+ aria-label="Close Lab Navigator">
293
+ <i class="fas fa-times text-gray-300 text-sm"></i>
294
+ </button>
295
+ </div>
296
+
297
+ <div class="relative p-6 min-h-[420px]">
298
+ <div class="absolute inset-0 opacity-70 pointer-events-none"
299
+ style="background: radial-gradient(circle at 30% 20%, rgba(99,102,241,0.18), transparent 45%),
300
+ radial-gradient(circle at 70% 70%, rgba(236,72,153,0.10), transparent 50%);"></div>
301
+
302
+ <div class="relative grid grid-cols-1 sm:grid-cols-2 gap-3">
303
+ <button class="lab-node text-left rounded-xl border border-gray-800 bg-gray-900/30 hover:border-indigo-500/50 hover:bg-gray-900/45 transition p-4"
304
+ data-dossier="start">
305
+ <div class="text-sm text-gray-200 font-medium">Start Here</div>
306
+ <div class="text-xs text-gray-500 mt-1">Return to the main interface</div>
307
+ </button>
308
+
309
+ <button class="lab-node text-left rounded-xl border border-gray-800 bg-gray-900/30 hover:border-indigo-500/50 hover:bg-gray-900/45 transition p-4"
310
+ data-dossier="console">
311
+ <div class="text-sm text-gray-200 font-medium">Console</div>
312
+ <div class="text-xs text-gray-500 mt-1">This page: controlled chat</div>
313
+ </button>
314
+
315
+ <button class="lab-node text-left rounded-xl border border-gray-800 bg-gray-900/30 hover:border-indigo-500/50 hover:bg-gray-900/45 transition p-4"
316
+ data-dossier="programs">
317
+ <div class="text-sm text-gray-200 font-medium">Programs</div>
318
+ <div class="text-xs text-gray-500 mt-1">MCAP · CHAI · Quantum Lambda</div>
319
+ </button>
320
+
321
+ <button class="lab-node text-left rounded-xl border border-gray-800 bg-gray-900/30 hover:border-indigo-500/50 hover:bg-gray-900/45 transition p-4"
322
+ data-dossier="ai_scientist">
323
+ <div class="text-sm text-gray-200 font-medium">AI Scientist</div>
324
+ <div class="text-xs text-gray-500 mt-1">Hypothesis → experiment → report</div>
325
+ </button>
326
+
327
+ <button class="lab-node text-left rounded-xl border border-gray-800 bg-gray-900/30 hover:border-indigo-500/50 hover:bg-gray-900/45 transition p-4 sm:col-span-2"
328
+ data-dossier="access">
329
+ <div class="text-sm text-gray-200 font-medium">Access</div>
330
+ <div class="text-xs text-gray-500 mt-1">Request access to demos and research</div>
331
+ </button>
332
  </div>
333
+
334
+ <div class="relative mt-6 text-xs text-gray-500">
335
+ Tip: Press <span class="text-gray-300">Esc</span> to close.
336
  </div>
337
+ </div>
338
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
 
340
+ <div class="relative rounded-2xl border border-gray-800 bg-gray-900/30 overflow-hidden">
341
+ <div class="px-6 py-5 border-b border-gray-800/60">
342
+ <div class="flex items-start justify-between gap-4">
343
+ <div>
344
+ <div id="dossier-title" class="text-lg font-semibold text-gray-100">Lab Dossier</div>
345
+ <div id="dossier-subtitle" class="text-xs text-gray-500 mt-1">Select a node to open a file.</div>
346
+ </div>
347
+ <div id="dossier-status"
348
+ class="text-xs px-2.5 py-1 rounded-full border border-indigo-500/30 text-indigo-200 bg-indigo-900/15">
349
+ DRAFT
350
+ </div>
351
+ </div>
352
+ </div>
353
+
354
+ <div class="p-6 space-y-5 max-h-[560px] overflow-auto"
355
+ style="scrollbar-width: thin; scrollbar-color: #4f46e5 #1e1b4b;">
356
+ <div id="dossier-body" class="text-sm text-gray-300 leading-relaxed">
357
+ This console is designed for controlled interaction. Dossiers expose depth by intent.
358
+ </div>
359
+
360
+ <div class="rounded-xl border border-gray-800 bg-black/20 p-4">
361
+ <div class="text-xs text-gray-400 uppercase tracking-wider mb-2">Evidence Capsule</div>
362
+ <ul id="dossier-evidence" class="text-sm text-gray-300 space-y-1">
363
+ <li class="text-gray-500">No dossier selected.</li>
364
+ </ul>
365
+ </div>
366
+
367
+ <div class="flex flex-col sm:flex-row gap-3">
368
+ <button id="dossier-primary"
369
+ class="flex-1 px-5 py-3 rounded-xl bg-gradient-to-r from-indigo-600 to-purple-600 hover:opacity-90 transition">
370
+ Open
371
+ </button>
372
+ <button id="dossier-secondary"
373
+ class="flex-1 px-5 py-3 rounded-xl border border-gray-700 bg-gray-900/20 hover:bg-gray-900/35 transition">
374
+ View Note
375
+ </button>
376
+ </div>
377
+
378
+ <div id="dossier-meta" class="text-xs text-gray-500">
379
+ Last updated: <span class="text-gray-300">—</span>
380
+ </div>
381
+ </div>
382
+ </div>
383
+
384
+ </div>
385
+ </div>
386
+ </div>
387
+
388
+ <script>
389
+ /* -------------------------------------------------------------
390
+ VANTA BACKGROUND
391
+ ------------------------------------------------------------- */
392
+ const vantaEffect = VANTA.NET({
393
+ el: "#vanta-bg",
394
+ mouseControls: true,
395
+ touchControls: true,
396
+ gyroControls: false,
397
+ minHeight: 200.00,
398
+ minWidth: 200.00,
399
+ scale: 1.00,
400
+ scaleMobile: 1.00,
401
+ color: 0x4f46e5,
402
+ backgroundColor: 0x020617,
403
+ points: 12.00,
404
+ maxDistance: 20.00,
405
+ spacing: 15.00
406
+ });
407
+ window.addEventListener('resize', () => vantaEffect.resize());
408
+
409
+ /* -------------------------------------------------------------
410
+ MODAL ACCESSIBILITY HELPERS
411
+ ------------------------------------------------------------- */
412
+ function trapFocus(modal) {
413
+ const focusable = modal.querySelectorAll('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])');
414
+ if (!focusable.length) return;
415
+ const first = focusable[0];
416
+ const last = focusable[focusable.length - 1];
417
+
418
+ function handler(e) {
419
+ if (e.key === 'Tab') {
420
+ if (e.shiftKey) {
421
+ if (document.activeElement === first) { e.preventDefault(); last.focus(); }
422
+ } else {
423
+ if (document.activeElement === last) { e.preventDefault(); first.focus(); }
424
+ }
425
+ } else if (e.key === 'Escape') {
426
+ toggleModal(modal, false);
427
  }
428
+ }
429
+ modal.addEventListener('keydown', handler);
430
+ modal._focusHandler = handler;
431
+ }
432
+
433
+ function untrapFocus(modal) {
434
+ if (modal._focusHandler) {
435
+ modal.removeEventListener('keydown', modal._focusHandler);
436
+ delete modal._focusHandler;
437
+ }
438
+ }
439
+
440
+ const toggleModal = (modal, show) => {
441
+ if (show) {
442
+ modal.classList.remove('modal-hidden');
443
+ modal.classList.add('modal-visible');
444
+ document.body.style.overflow = 'hidden';
445
+ setTimeout(() => { modal.focus(); trapFocus(modal); }, 0);
446
+ } else {
447
+ modal.classList.remove('modal-visible');
448
+ modal.classList.add('modal-hidden');
449
+ document.body.style.overflow = '';
450
+ untrapFocus(modal);
451
+ }
452
+ };
453
+
454
+ /* -------------------------------------------------------------
455
+ ACCESS MODAL
456
+ ------------------------------------------------------------- */
457
+ const accessModal = document.getElementById('access-modal');
458
+ const accessBtn = document.getElementById('access-btn');
459
+ const closeAccessModal = document.getElementById('close-access-modal');
460
+
461
+ accessBtn.addEventListener('click', () => {
462
+ toggleModal(accessModal, true);
463
+ setTimeout(() => document.getElementById('name').focus(), 50);
464
+ });
465
+
466
+ closeAccessModal.addEventListener('click', () => toggleModal(accessModal, false));
467
+
468
+ accessModal.addEventListener('click', (e) => {
469
+ if (e.target === accessModal) toggleModal(accessModal, false);
470
+ });
471
+
472
+ document.getElementById('access-form').addEventListener('submit', (e) => {
473
+ e.preventDefault();
474
+ const name = document.getElementById('name').value.trim();
475
+ const email = document.getElementById('email').value.trim();
476
+ const institution = document.getElementById('institution').value.trim();
477
+ const purpose = document.getElementById('purpose').value;
478
+
479
+ if (!name || !email || !institution || !purpose) {
480
+ alert('Please fill in all fields.');
481
+ return;
482
+ }
483
+ alert('Request received. You will be contacted after review.');
484
+ e.target.reset();
485
+ toggleModal(accessModal, false);
486
+ });
487
+
488
+ /* -------------------------------------------------------------
489
+ LAB NAVIGATOR
490
+ ------------------------------------------------------------- */
491
+ const labNav = document.getElementById('lab-navigator');
492
+ const labNavBtn = document.getElementById('lab-nav-btn');
493
+ const labNavClose = document.getElementById('lab-nav-close');
494
+
495
+ function openLabNav() { toggleModal(labNav, true); setTimeout(() => labNav.focus(), 0); }
496
+ function closeLabNav() { toggleModal(labNav, false); }
497
+
498
+ labNavBtn.addEventListener('click', openLabNav);
499
+ labNavClose.addEventListener('click', closeLabNav);
500
+
501
+ labNav.addEventListener('click', (e) => {
502
+ const shouldClose = e.target && e.target.getAttribute('data-lab-close') === 'true';
503
+ if (shouldClose) closeLabNav();
504
+ });
505
+
506
+ const DOSSIERS = {
507
+ start: {
508
+ title: "Start Here",
509
+ subtitle: "Return to the main interface",
510
+ status: "ACTIVE",
511
+ body: "SILENTPATTERN is presented as a lab interface: minimal surface, deep artifacts. The index is the entrypoint.",
512
+ evidence: ["Public entry layer", "Dossiers reveal depth", "Controlled demos by access"],
513
+ primary: { label: "Go to Index", action: () => { window.location.href = "index.html"; } },
514
+ secondary: { label: "Research", action: () => { window.location.href = "research.html"; } },
515
+ updated: "—"
516
+ },
517
+ console: {
518
+ title: "Console",
519
+ subtitle: "Controlled interaction channel",
520
+ status: "DRAFT",
521
+ body: "This console is a staging environment. It will connect to a server endpoint and produce auditable outputs (transcripts, notes, reports).",
522
+ evidence: ["Client: UI only", "Server: keys + policy + logging", "Exportable transcript"],
523
+ primary: { label: "Close Navigator", action: () => { closeLabNav(); } },
524
+ secondary: { label: "Export", action: () => { closeLabNav(); document.getElementById('export-btn').click(); } },
525
+ updated: "—"
526
+ },
527
+ programs: {
528
+ title: "Programs",
529
+ subtitle: "MCAP · CHAI · Quantum Lambda",
530
+ status: "DRAFT",
531
+ body: "Programs are introduced as research artifacts with maturity levels (Concept → Prototype → Validated) and evidence capsules.",
532
+ evidence: ["MCAP: causal abstraction principle", "CHAI: forecasting/regime modeling", "Quantum Lambda: high-frequency decision systems"],
533
+ primary: { label: "Open Programs", action: () => { window.location.href = "capabilities.html"; } },
534
+ secondary: { label: "Research Notes", action: () => { window.location.href = "research.html"; } },
535
+ updated: "—"
536
+ },
537
+ ai_scientist: {
538
+ title: "AI Scientist",
539
+ subtitle: "Hypothesis → experiment → report",
540
+ status: "DRAFT",
541
+ body: "The AI Scientist is positioned as the lab’s instrument: it standardizes experiments, enforces reproducibility, and produces reports with uncertainty.",
542
+ evidence: ["Experiment harnesses", "Evaluation baselines", "Report generation"],
543
+ primary: { label: "View Research", action: () => { window.location.href = "research.html"; } },
544
+ secondary: { label: "Contact", action: () => { window.location.href = "contact.html"; } },
545
+ updated: "—"
546
+ },
547
+ access: {
548
+ title: "Access",
549
+ subtitle: "Request access to demos and research",
550
+ status: "ACTIVE",
551
+ body: "Access is curated. The objective is qualified users, high-signal feedback, and responsible scaling.",
552
+ evidence: ["Application-based", "Segmented by intent", "Controlled demos"],
553
+ primary: { label: "Request Access", action: () => { closeLabNav(); accessBtn.click(); } },
554
+ secondary: { label: "Contact", action: () => { window.location.href = "contact.html"; } },
555
+ updated: "—"
556
+ }
557
+ };
558
+
559
+ const dossierTitle = document.getElementById('dossier-title');
560
+ const dossierSubtitle = document.getElementById('dossier-subtitle');
561
+ const dossierStatus = document.getElementById('dossier-status');
562
+ const dossierBody = document.getElementById('dossier-body');
563
+ const dossierEvidence = document.getElementById('dossier-evidence');
564
+ const dossierPrimary = document.getElementById('dossier-primary');
565
+ const dossierSecondary = document.getElementById('dossier-secondary');
566
+ const dossierMeta = document.getElementById('dossier-meta');
567
+
568
+ function renderDossier(key) {
569
+ const d = DOSSIERS[key];
570
+ if (!d) return;
571
+
572
+ dossierTitle.textContent = d.title;
573
+ dossierSubtitle.textContent = d.subtitle;
574
+ dossierStatus.textContent = d.status;
575
+ dossierBody.textContent = d.body;
576
+
577
+ dossierEvidence.innerHTML = "";
578
+ d.evidence.forEach(item => {
579
+ const li = document.createElement('li');
580
+ li.textContent = item;
581
+ dossierEvidence.appendChild(li);
582
+ });
583
+
584
+ dossierPrimary.textContent = d.primary.label;
585
+ dossierPrimary.onclick = d.primary.action;
586
+
587
+ dossierSecondary.textContent = d.secondary.label;
588
+ dossierSecondary.onclick = d.secondary.action;
589
+
590
+ dossierMeta.innerHTML = `Last updated: <span class="text-gray-300">${d.updated}</span>`;
591
+ }
592
+
593
+ document.querySelectorAll('.lab-node').forEach(btn => {
594
+ btn.addEventListener('click', () => renderDossier(btn.getAttribute('data-dossier')));
595
+ });
596
+
597
+ /* -------------------------------------------------------------
598
+ CHAT (SECURE-BY-DESIGN CLIENT)
599
+ - This page does NOT embed API keys.
600
+ - It calls a server endpoint: POST /api/chat
601
+ - If not available, it returns a local “demo” response.
602
+ ------------------------------------------------------------- */
603
+ const chatForm = document.getElementById('chat-form');
604
+ const chatInput = document.getElementById('chat-input');
605
+ const chatMessages = document.getElementById('chat-messages');
606
+ const typingIndicator = document.getElementById('typing-indicator');
607
+ const sendBtn = document.getElementById('send-btn');
608
+ const clearBtn = document.getElementById('clear-btn');
609
+ const exportBtn = document.getElementById('export-btn');
610
+
611
+ const transcript = []; // {role:'user'|'system', content:string, ts:number}
612
+
613
+ function escapeHtml(str) {
614
+ return str
615
+ .replaceAll('&', '&amp;')
616
+ .replaceAll('<', '&lt;')
617
+ .replaceAll('>', '&gt;')
618
+ .replaceAll('"', '&quot;')
619
+ .replaceAll("'", '&#039;');
620
+ }
621
+
622
+ function addMessage(text, isUser = false) {
623
+ const safe = escapeHtml(text);
624
+ const messageDiv = document.createElement('div');
625
+ messageDiv.className = `flex items-start ${isUser ? 'justify-end' : ''}`;
626
+
627
+ if (!isUser) {
628
+ messageDiv.innerHTML = `
629
+ <div class="w-8 h-8 rounded-full bg-indigo-600 flex-shrink-0 flex items-center justify-center mr-3" aria-hidden="true">
630
+ <i class="fas fa-robot text-white text-sm"></i>
631
+ </div>
632
+ <div class="bg-gray-800/70 rounded-lg p-4 max-w-[85%]">
633
+ <p class="text-gray-100">${safe}</p>
634
+ </div>
635
+ `;
636
+ } else {
637
+ messageDiv.innerHTML = `
638
+ <div class="bg-indigo-900/50 rounded-lg p-4 max-w-[85%]">
639
+ <p class="text-gray-100">${safe}</p>
640
+ </div>
641
+ `;
642
+ }
643
+
644
+ chatMessages.appendChild(messageDiv);
645
+ chatMessages.scrollTop = chatMessages.scrollHeight;
646
+
647
+ transcript.push({ role: isUser ? 'user' : 'system', content: text, ts: Date.now() });
648
+ }
649
+
650
+ function setBusy(isBusy) {
651
+ if (isBusy) {
652
+ typingIndicator.classList.remove('hidden');
653
+ sendBtn.disabled = true;
654
+ } else {
655
+ typingIndicator.classList.add('hidden');
656
+ sendBtn.disabled = false;
657
+ }
658
+ }
659
+
660
+ async function callServerChat(userMessage) {
661
+ const res = await fetch('/api/chat', {
662
+ method: 'POST',
663
+ headers: { 'Content-Type': 'application/json' },
664
+ body: JSON.stringify({
665
+ message: userMessage,
666
+ // Optional: pass context or selected program later
667
+ meta: { page: 'chat.html', product: 'silentpattern' }
668
+ })
669
+ });
670
+
671
+ if (!res.ok) {
672
+ const txt = await res.text().catch(() => '');
673
+ throw new Error(`Server error (${res.status}). ${txt}`.trim());
674
+ }
675
+
676
+ const data = await res.json();
677
+ if (!data || typeof data.reply !== 'string') {
678
+ throw new Error('Invalid response format from /api/chat');
679
+ }
680
+ return data.reply;
681
+ }
682
+
683
+ function localDemoResponse(userMessage) {
684
+ const msg = userMessage.toLowerCase();
685
+ if (msg.includes('mcap')) {
686
+ return "MCAP acknowledged. Provide: (1) the abstraction mapping you propose, (2) how you test causal fidelity, (3) baseline comparisons. I will draft a research-note structure next.";
687
+ }
688
+ if (msg.includes('chai')) {
689
+ return "CHAI acknowledged. I will assume a regime-aware forecasting stack. Specify assets, horizon, labeling rules, and walk-forward protocol. Then we can define an evaluation harness.";
690
+ }
691
+ if (msg.includes('quantum lambda')) {
692
+ return "Quantum Lambda acknowledged. For HFT, the first gate is market microstructure constraints and realistic latency/slippage. Share the execution assumptions and risk limits before discussing accuracy.";
693
+ }
694
+ return "Acknowledged. State (a) objective, (b) constraints, (c) what evidence you have today. I will respond with a plan and a minimal next experiment.";
695
+ }
696
+
697
+ chatForm.addEventListener('submit', async (e) => {
698
+ e.preventDefault();
699
+ const message = chatInput.value.trim();
700
+ if (!message) return;
701
+
702
+ addMessage(message, true);
703
+ chatInput.value = '';
704
+ setBusy(true);
705
+
706
+ try {
707
+ // Preferred path: server endpoint
708
+ const reply = await callServerChat(message);
709
+ addMessage(reply, false);
710
+ } catch (err) {
711
+ // Fallback: demo response (keeps UI usable during setup)
712
+ addMessage(localDemoResponse(message), false);
713
+ } finally {
714
+ setBusy(false);
715
+ }
716
+ });
717
+
718
+ clearBtn.addEventListener('click', () => {
719
+ // Keep the first system greeting, clear the rest
720
+ const nodes = Array.from(chatMessages.children);
721
+ for (let i = 1; i < nodes.length; i++) nodes[i].remove();
722
+ transcript.length = 0;
723
+ transcript.push({ role: 'system', content: 'Session cleared.', ts: Date.now() });
724
+ addMessage('Session cleared.', false);
725
+ });
726
+
727
+ exportBtn.addEventListener('click', () => {
728
+ const payload = {
729
+ product: "SILENTPATTERN",
730
+ page: "chat.html",
731
+ exported_at: new Date().toISOString(),
732
+ transcript
733
+ };
734
+ const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json' });
735
+ const url = URL.createObjectURL(blob);
736
+ const a = document.createElement('a');
737
+ a.href = url;
738
+ a.download = `silentpattern_transcript_${Date.now()}.json`;
739
+ document.body.appendChild(a);
740
+ a.click();
741
+ a.remove();
742
+ URL.revokeObjectURL(url);
743
+ });
744
 
745
+ /* -------------------------------------------------------------
746
+ GLOBAL ESC: close whichever overlay is open
747
+ ------------------------------------------------------------- */
748
+ document.addEventListener('keydown', (e) => {
749
+ if (e.key === 'Escape') {
750
+ if (labNav && !labNav.classList.contains('modal-hidden')) closeLabNav();
751
+ if (accessModal && !accessModal.classList.contains('modal-hidden')) toggleModal(accessModal, false);
752
+ }
753
+ });
754
+ </script>
755
  </body>
756
+ </html>