Komalpreet Kaur commited on
Commit
7a8d4bd
Β·
unverified Β·
1 Parent(s): 22fff46

UI: Split layout for chat and neural mesh side-by-side

Browse files
frontend/src/App.css CHANGED
@@ -1,102 +1,120 @@
1
- /* ═══════════════════════════════════════════════════════════════
2
- SOMA β€” Immersive Brain HUD Layout
3
- The 3D Neural Mesh is ALWAYS the full-screen background.
4
- Everything else is a transparent floating HUD layer.
5
- ═══════════════════════════════════════════════════════════════ */
6
 
7
  .app-container {
8
- position: relative;
9
- width: 100vw;
10
  height: 100vh;
11
- overflow: hidden;
12
- background-color: transparent;
13
- }
14
-
15
- /* ═══ LAYER 0: Persistent 3D Neural Mesh Background ═══ */
16
- .neural-mesh-bg {
17
- position: fixed;
18
- top: 0;
19
- left: 0;
20
  width: 100vw;
21
- height: 100vh;
22
- z-index: 0;
23
  }
24
 
25
- /* ═══ LAYER 1: Header β€” Floating Top Bar ═══ */
26
  .app-header {
27
- position: fixed;
28
- top: 0;
29
- left: 0;
30
- right: 0;
31
- height: 52px;
32
  display: flex;
33
  justify-content: space-between;
34
  align-items: center;
35
  padding: 0 24px;
36
- background: linear-gradient(180deg, rgba(5, 2, 11, 0.85) 0%, rgba(5, 2, 11, 0.4) 70%, transparent 100%);
 
 
37
  backdrop-filter: blur(12px);
38
- z-index: 100;
39
- border-bottom: 1px solid rgba(255, 255, 255, 0.04);
40
  }
41
 
42
  .logo-section {
43
  display: flex;
44
  align-items: center;
45
- gap: 12px;
46
  }
47
 
48
  .brain-pulse-icon {
49
- width: 14px;
50
- height: 14px;
51
  border-radius: 50%;
52
- background: linear-gradient(135deg, var(--accent-cyan), var(--accent-pink));
53
- box-shadow: 0 0 12px rgba(0, 240, 255, 0.4), 0 0 30px rgba(255, 0, 229, 0.2);
54
  animation: brain-pulse 3s ease-in-out infinite;
55
  }
56
 
57
  @keyframes brain-pulse {
58
- 0%, 100% { box-shadow: 0 0 12px rgba(0, 240, 255, 0.4), 0 0 30px rgba(255, 0, 229, 0.2); transform: scale(1); }
59
- 50% { box-shadow: 0 0 20px rgba(255, 0, 229, 0.6), 0 0 40px rgba(0, 240, 255, 0.3); transform: scale(1.15); }
60
  }
61
 
62
  .app-header h1 {
63
  margin: 0;
64
- font-size: 1.1rem;
65
  font-weight: 700;
66
- background: linear-gradient(90deg, var(--accent-cyan), var(--accent-pink));
67
  -webkit-background-clip: text;
68
  -webkit-text-fill-color: transparent;
69
  background-clip: text;
70
  letter-spacing: 0.4em;
71
  }
72
 
73
- .header-subtitle {
74
- font-size: 0.55rem !important;
75
- color: var(--text-dim) !important;
76
- opacity: 0.6;
 
 
 
 
77
  }
78
 
79
- /* ── Status / Persona (Header Right) ── */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  .status-indicator {
81
  display: flex;
82
  align-items: center;
83
- gap: 14px;
84
  font-size: 0.7rem;
85
  font-family: var(--font-mono);
86
  color: var(--text-dim);
87
  text-transform: uppercase;
88
- letter-spacing: 0.15em;
89
  }
90
 
91
  .persona-select {
92
  background: rgba(10, 5, 20, 0.8) !important;
93
  color: var(--accent-primary) !important;
94
- border: 1px solid rgba(0, 240, 255, 0.2) !important;
95
  padding: 4px 8px !important;
96
  border-radius: 4px;
97
  outline: none;
98
  cursor: pointer;
99
- font-size: 0.65rem !important;
100
  }
101
 
102
  .persona-select option {
@@ -119,168 +137,126 @@
119
  .dot.thinking {
120
  background: var(--accent-secondary);
121
  box-shadow: 0 0 10px var(--accent-glow-pink);
122
- animation: pulse-pink 1s ease-in-out infinite alternate;
123
  }
124
 
125
- @keyframes pulse-pink {
126
  0% { opacity: 1; transform: scale(1); }
127
  100% { opacity: 0.4; transform: scale(0.6); }
128
  }
129
 
130
- /* ═══ LAYER 2: Floating Toolbar (Left Edge) ═══ */
131
- .floating-toolbar {
132
- position: fixed;
133
- left: 16px;
134
- top: 50%;
135
- transform: translateY(-50%);
136
- z-index: 100;
137
  display: flex;
138
- flex-direction: column;
139
- gap: 6px;
140
- padding: 12px 8px;
141
- background: rgba(5, 2, 11, 0.6);
142
- backdrop-filter: blur(16px);
143
- border: 1px solid rgba(255, 255, 255, 0.05);
144
- border-radius: 14px;
145
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
146
  }
147
 
148
- .toolbar-btn {
 
 
 
149
  display: flex;
150
  flex-direction: column;
151
- align-items: center;
152
- gap: 4px;
153
- padding: 10px 12px;
154
- border-radius: 10px;
155
- border: 1px solid transparent;
156
- background: transparent;
157
- cursor: pointer;
158
- transition: all 0.3s ease;
159
- color: var(--text-dim);
160
- box-shadow: none;
161
- text-shadow: none;
162
- }
163
-
164
- .toolbar-btn:hover {
165
- background: rgba(0, 240, 255, 0.06);
166
- color: var(--text-secondary);
167
- border-color: rgba(255, 255, 255, 0.05);
168
- transform: none;
169
- box-shadow: none;
170
  }
171
 
172
- .toolbar-btn.active {
173
- background: rgba(0, 240, 255, 0.1);
174
- color: var(--accent-primary);
175
- border-color: rgba(0, 240, 255, 0.25);
176
- box-shadow: 0 0 15px rgba(0, 240, 255, 0.1);
177
- }
178
-
179
- .toolbar-icon {
180
- font-size: 1.1rem;
181
- line-height: 1;
182
- }
183
-
184
- .toolbar-label {
185
- font-family: var(--font-mono);
186
- font-size: 0.5rem;
187
- text-transform: uppercase;
188
- letter-spacing: 0.15em;
189
  }
190
 
191
- /* Mini vitals in toolbar */
192
- .toolbar-vitals {
193
  display: flex;
194
- flex-direction: column;
195
- gap: 4px;
196
- margin-top: 10px;
197
- padding-top: 10px;
198
- border-top: 1px solid rgba(255, 255, 255, 0.05);
 
199
  }
200
 
201
- .mini-vital {
202
  display: flex;
203
- justify-content: space-between;
204
  align-items: center;
205
- gap: 8px;
206
- padding: 2px 6px;
207
  }
208
 
209
- .mini-label {
210
  font-family: var(--font-mono);
211
- font-size: 0.45rem;
212
  color: var(--text-dim);
213
  text-transform: uppercase;
214
  letter-spacing: 0.1em;
215
  }
216
 
217
- .mini-value {
218
  font-family: var(--font-mono);
219
- font-size: 0.65rem;
220
  font-weight: 700;
221
  color: var(--accent-primary);
222
  text-shadow: 0 0 6px var(--accent-glow);
223
  }
224
 
225
- .mini-value.purple {
226
- color: var(--accent-secondary);
227
  text-shadow: 0 0 6px var(--accent-glow-pink);
228
  }
229
 
230
- /* ═══ LAYER 3: Center Overlay (Chat / Dreams) ═══ */
231
- .center-overlay {
232
- position: fixed;
233
- top: 52px;
234
- left: 100px;
235
- right: 0;
236
- bottom: 0;
237
- z-index: 50;
238
- pointer-events: none;
239
- opacity: 0;
240
- transition: opacity 0.4s ease;
241
- }
242
-
243
- .center-overlay.visible {
244
- opacity: 1;
245
- pointer-events: all;
246
  }
247
 
248
- /* ═══ LAYER 4: Right Diagnostic HUD ═══ */
249
- .diagnostic-hud {
250
- position: fixed;
251
- top: 52px;
252
- right: 0;
253
- bottom: 0;
254
- width: 300px;
255
- z-index: 60;
256
- background: linear-gradient(180deg, rgba(5, 2, 11, 0.75) 0%, rgba(5, 2, 11, 0.5) 100%);
257
- backdrop-filter: blur(16px);
258
- border-left: 1px solid rgba(255, 255, 255, 0.04);
259
- padding: 20px;
260
- overflow-y: auto;
261
- transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
262
  }
263
 
264
- .diagnostic-hud.collapsed {
265
- transform: translateX(100%);
 
266
  }
267
 
268
- /* ═══ Responsive ═══ */
269
  @media (max-width: 768px) {
270
- .floating-toolbar { display: none; }
271
- .diagnostic-hud { display: none; }
272
- .center-overlay {
273
- left: 0;
274
  }
 
 
 
 
 
 
 
 
 
 
 
275
  }
276
 
277
  .ephemeral-pill {
278
- background: rgba(255, 51, 102, 0.1);
279
  color: var(--accent-error);
280
- border: 1px solid rgba(255, 51, 102, 0.3);
281
  padding: 3px 8px;
282
  border-radius: 4px;
283
  font-size: 0.55rem;
284
- text-transform: uppercase;
285
- letter-spacing: 0.1em;
286
  }
 
1
+ /* ═══════════════════════════════════════════════
2
+ SOMA β€” Clean Side-by-Side Layout
3
+ Chat LEFT | Neural Mesh RIGHT
4
+ ═══════════════════════════════════════════════ */
 
5
 
6
  .app-container {
7
+ display: flex;
8
+ flex-direction: column;
9
  height: 100vh;
 
 
 
 
 
 
 
 
 
10
  width: 100vw;
11
+ overflow: hidden;
 
12
  }
13
 
14
+ /* ── Header ── */
15
  .app-header {
 
 
 
 
 
16
  display: flex;
17
  justify-content: space-between;
18
  align-items: center;
19
  padding: 0 24px;
20
+ height: 50px;
21
+ min-height: 50px;
22
+ background: rgba(7, 3, 15, 0.85);
23
  backdrop-filter: blur(12px);
24
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
25
+ z-index: 10;
26
  }
27
 
28
  .logo-section {
29
  display: flex;
30
  align-items: center;
31
+ gap: 10px;
32
  }
33
 
34
  .brain-pulse-icon {
35
+ width: 12px;
36
+ height: 12px;
37
  border-radius: 50%;
38
+ background: linear-gradient(135deg, var(--accent-synapse), var(--accent-impulse));
39
+ box-shadow: 0 0 10px rgba(192, 132, 252, 0.5);
40
  animation: brain-pulse 3s ease-in-out infinite;
41
  }
42
 
43
  @keyframes brain-pulse {
44
+ 0%, 100% { transform: scale(1); box-shadow: 0 0 10px rgba(192, 132, 252, 0.5); }
45
+ 50% { transform: scale(1.2); box-shadow: 0 0 18px rgba(240, 171, 252, 0.6); }
46
  }
47
 
48
  .app-header h1 {
49
  margin: 0;
50
+ font-size: 1rem;
51
  font-weight: 700;
52
+ background: linear-gradient(90deg, var(--accent-synapse), var(--accent-impulse));
53
  -webkit-background-clip: text;
54
  -webkit-text-fill-color: transparent;
55
  background-clip: text;
56
  letter-spacing: 0.4em;
57
  }
58
 
59
+ /* ── Header Center Tabs ── */
60
+ .header-center {
61
+ display: flex;
62
+ gap: 4px;
63
+ background: rgba(10, 5, 20, 0.6);
64
+ border-radius: 8px;
65
+ padding: 3px;
66
+ border: 1px solid rgba(255, 255, 255, 0.05);
67
  }
68
 
69
+ .tab-btn {
70
+ font-family: var(--font-mono);
71
+ font-size: 0.6rem;
72
+ text-transform: uppercase;
73
+ letter-spacing: 0.12em;
74
+ padding: 6px 16px;
75
+ border-radius: 6px;
76
+ border: 1px solid transparent;
77
+ background: transparent;
78
+ color: var(--text-dim);
79
+ cursor: pointer;
80
+ transition: all 0.25s ease;
81
+ box-shadow: none;
82
+ }
83
+
84
+ .tab-btn:hover {
85
+ color: var(--text-secondary);
86
+ background: rgba(192, 132, 252, 0.06);
87
+ transform: none;
88
+ box-shadow: none;
89
+ }
90
+
91
+ .tab-btn.active {
92
+ background: rgba(192, 132, 252, 0.15);
93
+ color: var(--accent-primary);
94
+ border-color: rgba(192, 132, 252, 0.25);
95
+ }
96
+
97
+ /* ── Status / Persona ── */
98
  .status-indicator {
99
  display: flex;
100
  align-items: center;
101
+ gap: 12px;
102
  font-size: 0.7rem;
103
  font-family: var(--font-mono);
104
  color: var(--text-dim);
105
  text-transform: uppercase;
106
+ letter-spacing: 0.12em;
107
  }
108
 
109
  .persona-select {
110
  background: rgba(10, 5, 20, 0.8) !important;
111
  color: var(--accent-primary) !important;
112
+ border: 1px solid rgba(192, 132, 252, 0.2) !important;
113
  padding: 4px 8px !important;
114
  border-radius: 4px;
115
  outline: none;
116
  cursor: pointer;
117
+ font-size: 0.6rem !important;
118
  }
119
 
120
  .persona-select option {
 
137
  .dot.thinking {
138
  background: var(--accent-secondary);
139
  box-shadow: 0 0 10px var(--accent-glow-pink);
140
+ animation: pulse-dot 1s ease-in-out infinite alternate;
141
  }
142
 
143
+ @keyframes pulse-dot {
144
  0% { opacity: 1; transform: scale(1); }
145
  100% { opacity: 0.4; transform: scale(0.6); }
146
  }
147
 
148
+ /* ═══ Split Layout ═══ */
149
+ .split-layout {
150
+ flex: 1;
 
 
 
 
151
  display: flex;
152
+ overflow: hidden;
 
 
 
 
 
 
 
153
  }
154
 
155
+ /* ── Left Pane: Chat ── */
156
+ .left-pane {
157
+ width: 45%;
158
+ min-width: 380px;
159
  display: flex;
160
  flex-direction: column;
161
+ border-right: 1px solid rgba(255, 255, 255, 0.04);
162
+ background: rgba(7, 3, 15, 0.3);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  }
164
 
165
+ /* ── Right Pane: Graph / Dreams ── */
166
+ .right-pane {
167
+ flex: 1;
168
+ position: relative;
169
+ overflow: hidden;
170
+ background: transparent;
 
 
 
 
 
 
 
 
 
 
 
171
  }
172
 
173
+ /* ── Compact Vitals Bar ── */
174
+ .vitals-bar {
175
  display: flex;
176
+ align-items: center;
177
+ gap: 16px;
178
+ padding: 8px 20px;
179
+ background: rgba(7, 3, 15, 0.6);
180
+ border-top: 1px solid rgba(255, 255, 255, 0.04);
181
+ flex-shrink: 0;
182
  }
183
 
184
+ .vb-item {
185
  display: flex;
 
186
  align-items: center;
187
+ gap: 6px;
 
188
  }
189
 
190
+ .vb-label {
191
  font-family: var(--font-mono);
192
+ font-size: 0.5rem;
193
  color: var(--text-dim);
194
  text-transform: uppercase;
195
  letter-spacing: 0.1em;
196
  }
197
 
198
+ .vb-value {
199
  font-family: var(--font-mono);
200
+ font-size: 0.75rem;
201
  font-weight: 700;
202
  color: var(--accent-primary);
203
  text-shadow: 0 0 6px var(--accent-glow);
204
  }
205
 
206
+ .vb-value.purple {
207
+ color: var(--accent-impulse);
208
  text-shadow: 0 0 6px var(--accent-glow-pink);
209
  }
210
 
211
+ .sleep-btn-compact {
212
+ margin-left: auto;
213
+ font-family: var(--font-mono);
214
+ font-size: 0.55rem;
215
+ padding: 5px 12px;
216
+ border-radius: 6px;
217
+ background: rgba(124, 58, 237, 0.15);
218
+ border: 1px solid rgba(192, 132, 252, 0.2);
219
+ color: var(--text-secondary);
220
+ cursor: pointer;
221
+ transition: all 0.25s ease;
 
 
 
 
 
222
  }
223
 
224
+ .sleep-btn-compact:hover {
225
+ background: rgba(192, 132, 252, 0.2);
226
+ border-color: var(--accent-primary);
227
+ color: var(--accent-primary);
228
+ transform: none;
229
+ box-shadow: 0 0 10px var(--accent-glow);
 
 
 
 
 
 
 
 
230
  }
231
 
232
+ .sleep-btn-compact:disabled {
233
+ opacity: 0.4;
234
+ cursor: not-allowed;
235
  }
236
 
237
+ /* ── Responsive ── */
238
  @media (max-width: 768px) {
239
+ .split-layout {
240
+ flex-direction: column;
 
 
241
  }
242
+ .left-pane {
243
+ width: 100%;
244
+ min-width: unset;
245
+ height: 50%;
246
+ border-right: none;
247
+ border-bottom: 1px solid rgba(255, 255, 255, 0.04);
248
+ }
249
+ .right-pane {
250
+ height: 50%;
251
+ }
252
+ .header-center { display: none; }
253
  }
254
 
255
  .ephemeral-pill {
256
+ background: rgba(251, 113, 133, 0.1);
257
  color: var(--accent-error);
258
+ border: 1px solid rgba(251, 113, 133, 0.3);
259
  padding: 3px 8px;
260
  border-radius: 4px;
261
  font-size: 0.55rem;
 
 
262
  }
frontend/src/App.jsx CHANGED
@@ -19,9 +19,8 @@ function App() {
19
  cognitiveState: "IDLE",
20
  traces: []
21
  })
22
- const [currentOverlay, setCurrentOverlay] = useState('chat') // 'chat', 'dreams', or 'none'
23
  const [currentPersona, setCurrentPersona] = useState('User_Alpha')
24
- const [hudCollapsed, setHudCollapsed] = useState(false)
25
 
26
  // Fetch Brain Vitals
27
  useEffect(() => {
@@ -79,29 +78,28 @@ function App() {
79
 
80
  return (
81
  <div className={`app-container state-${brainState.cognitiveState.toLowerCase()}`}>
82
-
83
- {/* ═══ LAYER 0: The 3D Neural Mesh β€” Always Present ═══ */}
84
- <div className="neural-mesh-bg">
85
- <KnowledgeGraph
86
- highlightedNodes={brainState.highlightedNodes}
87
- currentPersona={currentPersona}
88
- isBackground={true}
89
- />
90
- </div>
91
-
92
- {/* ═══ LAYER 1: Floating HUD Shell ═══ */}
93
  <header className="app-header">
94
  <div className="logo-section">
95
  <div className="brain-pulse-icon" />
96
  <h1>SOMA</h1>
97
- <span className="label-mono header-subtitle">Cognitive Neural Interface</span>
98
  </div>
99
 
 
 
 
 
 
 
 
 
 
 
 
100
  <div className="status-indicator">
101
  <span className={`dot ${brainState.isLoading ? 'thinking' : 'idle'}`}></span>
102
  <span className="label-mono">{brainState.cognitiveState}</span>
103
-
104
- {/* Persona Switcher β€” compact in header */}
105
  <select
106
  className="persona-select label-mono"
107
  value={currentPersona}
@@ -114,53 +112,11 @@ function App() {
114
  </div>
115
  </header>
116
 
117
- {/* ═══ LAYER 2: Left Floating Toolbar ═══ */}
118
- <div className="floating-toolbar">
119
- <button
120
- className={`toolbar-btn ${currentOverlay === 'chat' ? 'active' : ''}`}
121
- onClick={() => setCurrentOverlay(currentOverlay === 'chat' ? 'none' : 'chat')}
122
- title="Neural Interface"
123
- >
124
- <span className="toolbar-icon">⚑</span>
125
- <span className="toolbar-label">Interface</span>
126
- </button>
127
- <button
128
- className={`toolbar-btn ${currentOverlay === 'dreams' ? 'active' : ''}`}
129
- onClick={() => setCurrentOverlay(currentOverlay === 'dreams' ? 'none' : 'dreams')}
130
- title="Dream Sequence"
131
- >
132
- <span className="toolbar-icon">β—Ž</span>
133
- <span className="toolbar-label">Dreams</span>
134
- </button>
135
- <button
136
- className={`toolbar-btn ${hudCollapsed ? '' : 'active'}`}
137
- onClick={() => setHudCollapsed(!hudCollapsed)}
138
- title="Toggle Diagnostics"
139
- >
140
- <span className="toolbar-icon">β—ˆ</span>
141
- <span className="toolbar-label">Vitals</span>
142
- </button>
143
 
144
- {/* Brain vitals mini readout */}
145
- <div className="toolbar-vitals">
146
- <div className="mini-vital">
147
- <span className="mini-label">SEN</span>
148
- <span className="mini-value">{brainState.sensoryDocuments}</span>
149
- </div>
150
- <div className="mini-vital">
151
- <span className="mini-label">SYN</span>
152
- <span className="mini-value purple">{brainState.graphRelations}</span>
153
- </div>
154
- <div className="mini-vital">
155
- <span className="mini-label">WRK</span>
156
- <span className="mini-value">{brainState.workingMemory}</span>
157
- </div>
158
- </div>
159
- </div>
160
-
161
- {/* ═══ LAYER 3: Central Overlay (Chat or Dreams) ═══ */}
162
- <div className={`center-overlay ${currentOverlay !== 'none' ? 'visible' : ''}`}>
163
- {currentOverlay === 'chat' && (
164
  <ChatPanel
165
  messages={messages}
166
  setMessages={setMessages}
@@ -169,20 +125,53 @@ function App() {
169
  isLoading={brainState.isLoading}
170
  currentPersona={currentPersona}
171
  />
172
- )}
173
- {currentOverlay === 'dreams' && (
174
- <DreamSequence sparks={brainState.sparks} />
175
- )}
176
- </div>
177
 
178
- {/* ═══ LAYER 4: Right Diagnostic HUD (collapsible) ═══ */}
179
- <aside className={`diagnostic-hud ${hudCollapsed ? 'collapsed' : ''}`}>
180
- <CognitiveDashboard
181
- brainState={brainState}
182
- setBrainState={setBrainState}
183
- />
184
- </aside>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
 
 
186
  </div>
187
  )
188
  }
 
19
  cognitiveState: "IDLE",
20
  traces: []
21
  })
22
+ const [rightPanel, setRightPanel] = useState('graph') // 'graph' or 'dreams'
23
  const [currentPersona, setCurrentPersona] = useState('User_Alpha')
 
24
 
25
  // Fetch Brain Vitals
26
  useEffect(() => {
 
78
 
79
  return (
80
  <div className={`app-container state-${brainState.cognitiveState.toLowerCase()}`}>
81
+
82
+ {/* ── Header ── */}
 
 
 
 
 
 
 
 
 
83
  <header className="app-header">
84
  <div className="logo-section">
85
  <div className="brain-pulse-icon" />
86
  <h1>SOMA</h1>
 
87
  </div>
88
 
89
+ <div className="header-center">
90
+ <button
91
+ className={`tab-btn ${rightPanel === 'graph' ? 'active' : ''}`}
92
+ onClick={() => setRightPanel('graph')}
93
+ >Neural Mesh</button>
94
+ <button
95
+ className={`tab-btn ${rightPanel === 'dreams' ? 'active' : ''}`}
96
+ onClick={() => setRightPanel('dreams')}
97
+ >Dreams</button>
98
+ </div>
99
+
100
  <div className="status-indicator">
101
  <span className={`dot ${brainState.isLoading ? 'thinking' : 'idle'}`}></span>
102
  <span className="label-mono">{brainState.cognitiveState}</span>
 
 
103
  <select
104
  className="persona-select label-mono"
105
  value={currentPersona}
 
112
  </div>
113
  </header>
114
 
115
+ {/* ── Main Split Layout ── */}
116
+ <div className="split-layout">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
+ {/* LEFT: Chat + Mini Vitals */}
119
+ <div className="left-pane">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  <ChatPanel
121
  messages={messages}
122
  setMessages={setMessages}
 
125
  isLoading={brainState.isLoading}
126
  currentPersona={currentPersona}
127
  />
 
 
 
 
 
128
 
129
+ {/* Compact vitals bar under chat */}
130
+ <div className="vitals-bar">
131
+ <div className="vb-item">
132
+ <span className="vb-label">Sensory</span>
133
+ <span className="vb-value">{brainState.sensoryDocuments}</span>
134
+ </div>
135
+ <div className="vb-item">
136
+ <span className="vb-label">Synaptic</span>
137
+ <span className="vb-value purple">{brainState.graphRelations}</span>
138
+ </div>
139
+ <div className="vb-item">
140
+ <span className="vb-label">Working</span>
141
+ <span className="vb-value">{brainState.workingMemory}</span>
142
+ </div>
143
+ <button
144
+ className="sleep-btn-compact"
145
+ onClick={async () => {
146
+ setBrainState(prev => ({ ...prev, isLoading: true, statusMessage: 'Sleeping...' }));
147
+ try {
148
+ const res = await fetch('/api/v1/sleep', { method: 'POST' });
149
+ const data = await res.json();
150
+ setBrainState(prev => ({ ...prev, isLoading: false, statusMessage: `Sleep done. ${data.graph_relations_extracted} relations.` }));
151
+ } catch (e) {
152
+ setBrainState(prev => ({ ...prev, isLoading: false, statusMessage: 'Sleep failed.' }));
153
+ }
154
+ }}
155
+ disabled={brainState.isLoading}
156
+ >
157
+ πŸ’€ Sleep
158
+ </button>
159
+ </div>
160
+ </div>
161
+
162
+ {/* RIGHT: Neural Mesh or Dreams */}
163
+ <div className="right-pane">
164
+ {rightPanel === 'graph' ? (
165
+ <KnowledgeGraph
166
+ highlightedNodes={brainState.highlightedNodes}
167
+ currentPersona={currentPersona}
168
+ />
169
+ ) : (
170
+ <DreamSequence sparks={brainState.sparks} />
171
+ )}
172
+ </div>
173
 
174
+ </div>
175
  </div>
176
  )
177
  }
frontend/src/components/ChatPanel.css CHANGED
@@ -1,12 +1,11 @@
1
- /* ═══ Chat Panel β€” Holographic Overlay Mode ═══ */
2
  .chat-panel {
3
  display: flex;
4
  flex-direction: column;
5
- height: 100%;
 
6
  background: transparent;
7
- padding: 24px 40px;
8
- max-width: 750px;
9
- margin: 0 auto;
10
  }
11
 
12
  /* ── Chat Header ── */
 
1
+ /* ═══ Chat Panel β€” Left Pane Mode ═══ */
2
  .chat-panel {
3
  display: flex;
4
  flex-direction: column;
5
+ flex: 1;
6
+ overflow: hidden;
7
  background: transparent;
8
+ padding: 20px 24px;
 
 
9
  }
10
 
11
  /* ── Chat Header ── */