pkheria commited on
Commit
b30e78c
Β·
1 Parent(s): 7ecb96f

UI updated

Browse files
Files changed (5) hide show
  1. .DS_Store +0 -0
  2. app/.DS_Store +0 -0
  3. app/ui/gradio_app.py +40 -9
  4. app/ui/theme.py +431 -299
  5. requirements.txt +1 -0
.DS_Store ADDED
Binary file (8.2 kB). View file
 
app/.DS_Store ADDED
Binary file (6.15 kB). View file
 
app/ui/gradio_app.py CHANGED
@@ -169,12 +169,15 @@ def build_app() -> gr.Blocks:
169
  title=f"{settings.PROJECT_NAME} Ingestor",
170
  ) as demo:
171
  with gr.Column(elem_id="kh-shell"):
 
 
 
 
 
172
  gr.Markdown(
173
  f"""
174
- # {settings.PROJECT_NAME}
175
- Turn papers, PDFs, and articles into a searchable vector memory.
176
-
177
- Extract text, chunk it cleanly, embed locally, and use NVIDIA chat for grounded answers.
178
  """,
179
  elem_id="kh-title",
180
  )
@@ -195,7 +198,7 @@ Extract text, chunk it cleanly, embed locally, and use NVIDIA chat for grounded
195
  with gr.Row(equal_height=True):
196
  with gr.Column(scale=5, elem_classes=["kh-panel"]):
197
  gr.Markdown(
198
- "### Source Intake\n<div class='kh-subhead'>Upload a PDF or paste one link. The pipeline handles extraction, chunking, local embeddings, and Qdrant upload.</div>"
199
  )
200
  source_url = gr.Textbox(
201
  label="Medium or arXiv input",
@@ -212,7 +215,7 @@ Extract text, chunk it cleanly, embed locally, and use NVIDIA chat for grounded
212
  value=settings.QDRANT_COLLECTION_NAME,
213
  placeholder="Enter Qdrant collection name",
214
  )
215
- ingest_btn = gr.Button("Ingest into Qdrant", variant="primary")
216
 
217
  with gr.Column(scale=4, elem_classes=["kh-panel"]):
218
  gr.Markdown("### Pipeline Status")
@@ -274,7 +277,7 @@ Extract text, chunk it cleanly, embed locally, and use NVIDIA chat for grounded
274
  with gr.Row(equal_height=True):
275
  with gr.Column(scale=3, elem_classes=["kh-panel"]):
276
  gr.Markdown(
277
- "### Retrieval Probe\n<div class='kh-subhead'>Run a similarity search against the Qdrant collection. Returns top 3 matches.</div>"
278
  )
279
  query = gr.Textbox(
280
  label="Search query",
@@ -287,8 +290,21 @@ Extract text, chunk it cleanly, embed locally, and use NVIDIA chat for grounded
287
  placeholder="Enter Qdrant collection name",
288
  )
289
  with gr.Row():
290
- search_btn = gr.Button("Search Qdrant", variant="secondary")
291
- answer_btn = gr.Button("Answer with NVIDIA", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  with gr.Column(scale=5, elem_classes=["kh-panel"]):
293
  gr.Markdown("### Answer")
294
  answer_output = gr.Markdown(elem_id="kh-answer")
@@ -312,6 +328,21 @@ Extract text, chunk it cleanly, embed locally, and use NVIDIA chat for grounded
312
  outputs=[answer_output, reasoning_output, search_results],
313
  )
314
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  return demo
316
 
317
 
 
169
  title=f"{settings.PROJECT_NAME} Ingestor",
170
  ) as demo:
171
  with gr.Column(elem_id="kh-shell"):
172
+ # Room Tag badge inside the chalkboard frame
173
+ gr.HTML(
174
+ f'<div class="kh-room-tag">ROOM: {settings.QDRANT_COLLECTION_NAME}</div>',
175
+ elem_id="kh-room-container"
176
+ )
177
  gr.Markdown(
178
  f"""
179
+ # KnowledgeMesh
180
+ *push papers Β· ask questions Β· study together*
 
 
181
  """,
182
  elem_id="kh-title",
183
  )
 
198
  with gr.Row(equal_height=True):
199
  with gr.Column(scale=5, elem_classes=["kh-panel"]):
200
  gr.Markdown(
201
+ "### Push source\n<div class='kh-subhead'>Upload a PDF or paste one link. The pipeline handles extraction, chunking, local embeddings, and Qdrant upload.</div>"
202
  )
203
  source_url = gr.Textbox(
204
  label="Medium or arXiv input",
 
215
  value=settings.QDRANT_COLLECTION_NAME,
216
  placeholder="Enter Qdrant collection name",
217
  )
218
+ ingest_btn = gr.Button("Write to board β†’", variant="primary")
219
 
220
  with gr.Column(scale=4, elem_classes=["kh-panel"]):
221
  gr.Markdown("### Pipeline Status")
 
277
  with gr.Row(equal_height=True):
278
  with gr.Column(scale=3, elem_classes=["kh-panel"]):
279
  gr.Markdown(
280
+ "### Ask the room\n<div class='kh-subhead'>Run a similarity search against the Qdrant collection. Returns top 3 matches.</div>"
281
  )
282
  query = gr.Textbox(
283
  label="Search query",
 
290
  placeholder="Enter Qdrant collection name",
291
  )
292
  with gr.Row():
293
+ search_btn = gr.Button("Search", variant="secondary")
294
+ answer_btn = gr.Button("Answer", variant="primary")
295
+ gr.HTML(
296
+ """
297
+ <div class="kh-retrieve-status">
298
+ <div class="kh-online-status">
299
+ <span class="kh-dot green"></span>
300
+ <span class="kh-dot green"></span>
301
+ <span class="kh-dot green"></span>
302
+ <span class="kh-online-text">2/4 online</span>
303
+ </div>
304
+ <div class="kh-brackets">[ ]</div>
305
+ </div>
306
+ """
307
+ )
308
  with gr.Column(scale=5, elem_classes=["kh-panel"]):
309
  gr.Markdown("### Answer")
310
  answer_output = gr.Markdown(elem_id="kh-answer")
 
328
  outputs=[answer_output, reasoning_output, search_results],
329
  )
330
 
331
+ # Wooden chalk tray with white, yellow, and purple chalk pieces resting on it
332
+ gr.HTML(
333
+ """
334
+ <div class="kh-bottom-tray">
335
+ <div class="kh-chalks">
336
+ <span class="kh-chalk white"></span>
337
+ <span class="kh-chalk yellow"></span>
338
+ <span class="kh-chalk purple"></span>
339
+ </div>
340
+ <div class="kh-watermark">NVIDIA Β· Qdrant Β· k=3</div>
341
+ </div>
342
+ """,
343
+ elem_id="kh-bottom-container"
344
+ )
345
+
346
  return demo
347
 
348
 
app/ui/theme.py CHANGED
@@ -1,7 +1,7 @@
1
  HEAD = """
2
  <link rel="preconnect" href="https://fonts.googleapis.com">
3
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
4
- <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
5
  """
6
 
7
  JS = """
@@ -14,54 +14,21 @@ JS = """
14
 
15
  CSS = """
16
  /* ═══════════════════════════════════════════════
17
- KNOWLEDGEHUB β€” WARM LIGHT THEME
18
- Palette: parchment bg Β· sage green Β· warm amber
19
- Texture: fine cross-hatch + dot grid overlay
20
- ═══════════════════════════════════════════════ */
21
-
22
- :root {
23
- --kh-bg: #ede8db;
24
- --kh-bg2: #e8e2d4;
25
- --kh-surface: #faf7f0;
26
- --kh-surface2: #f5f1e6;
27
- --kh-ink: #1e1b15;
28
- --kh-muted: #6b6254;
29
- --kh-soft: #3d3828;
30
- --kh-line: rgba(80, 65, 35, 0.14);
31
- --kh-sage: #3d7a6a;
32
- --kh-sage-dim: rgba(61, 122, 106, 0.15);
33
- --kh-amber: #b87428;
34
- --kh-shadow: rgba(80, 60, 20, 0.10);
35
- --kh-shadow-md: rgba(80, 60, 20, 0.16);
36
- }
37
-
38
- /* ══ PAGE BACKGROUND β€” cross-hatch + dot texture ══ */
39
  .gradio-container {
40
  min-height: 100vh !important;
41
- background-color: var(--kh-bg) !important;
42
- /* Cross-hatch lines */
43
- background-image:
44
- linear-gradient(rgba(61,122,106,0.07) 1px, transparent 1px),
45
- linear-gradient(90deg, rgba(61,122,106,0.07) 1px, transparent 1px),
46
- linear-gradient(rgba(184,116,40,0.04) 1px, transparent 1px),
47
- linear-gradient(90deg, rgba(184,116,40,0.04) 1px, transparent 1px),
48
- radial-gradient(ellipse 65% 45% at 5% 0%, rgba(61,122,106,0.13) 0%, transparent 60%),
49
- radial-gradient(ellipse 55% 40% at 96% 4%, rgba(184,116,40,0.11) 0%, transparent 55%),
50
- radial-gradient(ellipse 80% 55% at 50% 105%, rgba(61,122,106,0.08) 0%, transparent 60%) !important;
51
- background-size:
52
- 32px 32px,
53
- 32px 32px,
54
- 8px 8px,
55
- 8px 8px,
56
- 100% 100%,
57
- 100% 100%,
58
- 100% 100% !important;
59
- color: var(--kh-ink) !important;
60
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, sans-serif !important;
 
61
  }
62
 
63
- /* ══ NUKE ALL DARK BACKGROUNDS from Gradio internals ══ */
64
- /* Every block, wrap, form, and container Gradio might use */
65
  .gradio-container *,
66
  .gradio-container .block,
67
  .gradio-container .form,
@@ -76,378 +43,543 @@ CSS = """
76
  .gradio-container .sm,
77
  .gradio-container .stretch {
78
  background-color: transparent !important;
79
- color: inherit !important;
80
- }
81
-
82
- /* Force all Gradio block panels to parchment */
83
- .gradio-container .block.padded,
84
- .gradio-container .block.padded.hide-container,
85
- .gradio-container div.block,
86
- .gradio-container fieldset,
87
- .gradio-container label.block {
88
- background-color: var(--kh-surface) !important;
89
- border-color: var(--kh-line) !important;
90
- color: var(--kh-ink) !important;
91
  }
92
 
93
- /* ══ SHELL ══ */
94
  #kh-shell {
95
- position: relative;
96
- z-index: 1;
97
- max-width: 1220px;
98
- margin: 0 auto;
99
- padding: 32px 20px 52px;
100
- }
101
-
102
- /* ══ TITLE ══ */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  #kh-title {
104
- padding: 36px 0 26px;
105
- border-bottom: 1px solid var(--kh-line);
106
  background: transparent !important;
 
107
  }
108
 
109
  #kh-title h1 {
110
- max-width: 960px;
111
- color: var(--kh-ink) !important;
112
- font-family: "Instrument Serif", Georgia, "Times New Roman", serif !important;
113
- font-size: clamp(2.8rem, 6.5vw, 6.2rem);
114
- font-weight: 400;
115
- font-style: italic;
116
- line-height: 0.92;
117
- margin: 0 0 16px;
118
- letter-spacing: -0.01em;
119
  }
120
 
121
  #kh-title p {
122
- max-width: 760px;
123
- color: var(--kh-muted) !important;
124
- font-size: 1.02rem;
125
- line-height: 1.7;
126
- margin: 6px 0 0;
127
  }
128
 
129
  /* ══ CODE CHIPS ══ */
130
- #kh-title code,
131
- .kh-chip code {
132
- color: var(--kh-sage) !important;
133
- background: rgba(61, 122, 106, 0.11) !important;
134
- border: 1px solid rgba(61, 122, 106, 0.22) !important;
135
- border-radius: 5px;
136
- padding: 2px 6px;
137
- font-family: "JetBrains Mono", ui-monospace, monospace;
138
- font-size: 0.87em;
139
- }
140
-
141
- /* ══ CHIP ROW ══ */
142
  .kh-chip-row {
143
  display: flex;
144
  flex-wrap: wrap;
145
- gap: 9px;
146
- margin-top: 18px;
147
  background: transparent !important;
148
  }
149
 
150
  .kh-chip {
151
- border: 1px solid var(--kh-line);
152
- border-radius: 999px;
153
- padding: 6px 14px;
154
- color: var(--kh-soft) !important;
155
- background: rgba(250, 247, 240, 0.85) !important;
156
- font-size: 0.87rem;
157
- font-weight: 500;
158
- box-shadow: 0 1px 3px var(--kh-shadow);
159
- }
160
-
161
- /* ══ PANELS β€” clean lifted paper, no inner texture ══ */
162
- .kh-panel,
163
- .kh-panel.block,
164
- .kh-panel > .block {
165
- border: 1px solid rgba(80, 65, 35, 0.13) !important;
166
- border-top: 2.5px solid rgba(61, 122, 106, 0.38) !important;
167
- border-radius: 14px !important;
168
- background: #fdfaf3 !important;
169
- box-shadow:
170
- 0 1px 0 rgba(255,255,255,0.95) inset,
171
- 0 4px 6px -2px rgba(80,60,20,0.06),
172
- 0 12px 32px rgba(80,60,20,0.09);
173
- padding: 22px !important;
174
- color: var(--kh-ink) !important;
175
- }
176
-
177
- /* Force all children of panels to be light too */
178
- .kh-panel *,
179
- .kh-panel .block,
180
- .kh-panel .wrap,
181
- .kh-panel .form,
182
- .kh-panel fieldset {
183
- background-color: transparent !important;
184
- color: var(--kh-ink) !important;
185
- border-color: var(--kh-line) !important;
186
- box-shadow: none !important;
187
  }
188
 
189
- /* Labels inside panels */
190
- .kh-panel label span,
191
- .kh-panel .label-wrap span,
192
- .kh-panel span.text-gray-500,
193
- .kh-panel span.text-sm {
194
- color: var(--kh-soft) !important;
195
- font-weight: 600 !important;
196
- font-size: 0.89rem !important;
197
- letter-spacing: 0.01em;
198
- }
199
-
200
- .kh-subhead {
201
- margin: 6px 0 16px;
202
- color: var(--kh-muted) !important;
203
- font-size: 0.93rem;
204
- line-height: 1.6;
205
- }
206
-
207
- /* ══ STAT BOXES ══ */
208
- .kh-stat,
209
- .kh-stat > .block,
210
- .kh-stat .wrap {
211
- min-height: 88px;
212
- border: 1px solid rgba(80,65,35,0.11) !important;
213
- border-radius: 10px !important;
214
- padding: 12px 16px;
215
- background: rgba(232, 226, 212, 0.6) !important;
216
- box-shadow: 0 1px 0 rgba(255,255,255,0.85) inset;
217
- }
218
-
219
- .kh-stat input,
220
- .kh-stat textarea {
221
- background: transparent !important;
222
- border: none !important;
223
- box-shadow: none !important;
224
- color: var(--kh-ink) !important;
225
  }
226
 
227
- /* ══ TABS ══ */
228
  .tabs {
229
- margin-top: 22px;
230
- background: transparent !important;
231
  }
232
 
233
  .tab-nav {
 
 
 
234
  background: transparent !important;
235
- border-bottom: 1px solid var(--kh-line) !important;
236
- gap: 4px;
237
  }
238
 
239
  .tab-nav button {
240
- color: var(--kh-muted) !important;
241
  background: transparent !important;
242
- border: 1px solid transparent !important;
243
- border-radius: 8px 8px 0 0 !important;
244
- font-weight: 600 !important;
245
- font-size: 0.95rem !important;
246
- padding: 9px 20px !important;
247
- transition: all 0.15s ease;
 
248
  }
249
 
250
  .tab-nav button:hover {
251
- color: var(--kh-sage) !important;
252
- background: rgba(61,122,106,0.07) !important;
253
  }
254
 
255
  .tab-nav button.selected {
256
- color: var(--kh-sage) !important;
257
- background: var(--kh-surface) !important;
258
- border: 1px solid var(--kh-line) !important;
259
- border-bottom-color: var(--kh-surface) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
  }
261
 
262
  /* ══ INPUTS & TEXTAREAS ══ */
263
  textarea,
264
  input[type="text"],
265
  input[type="number"],
266
- input[type="search"],
267
- input[type="email"] {
268
- color: var(--kh-ink) !important;
269
- background: rgba(255, 252, 244, 0.92) !important;
270
- border: 1px solid rgba(80,65,35,0.18) !important;
271
  border-radius: 8px !important;
 
272
  font-size: 0.94rem !important;
273
- font-family: Inter, ui-sans-serif, system-ui, sans-serif !important;
274
- box-shadow: 0 1px 2px rgba(80,60,20,0.05) inset !important;
275
- transition: border-color 0.15s, box-shadow 0.15s;
276
  }
277
 
278
  textarea:focus,
279
- input[type="text"]:focus {
280
- border-color: rgba(61,122,106,0.5) !important;
281
- box-shadow: 0 0 0 3px rgba(61,122,106,0.11), 0 1px 3px rgba(80,60,20,0.06) inset !important;
 
 
 
 
282
  outline: none !important;
283
  }
284
 
285
  textarea::placeholder,
286
  input::placeholder {
287
- color: rgba(107,98,84,0.52) !important;
 
 
 
 
 
 
 
 
 
 
 
 
288
  }
289
 
290
- /* ══ UPLOAD / FILE BLOCK ══ */
291
  .upload-container,
292
  .file-preview,
293
  [data-testid="file"],
294
  .file-upload {
295
- background:
296
- repeating-linear-gradient(
297
- 45deg,
298
- rgba(61,122,106,0.04) 0px,
299
- rgba(61,122,106,0.04) 1px,
300
- transparent 1px,
301
- transparent 10px
302
- ) !important;
303
- border: 1.5px dashed rgba(61,122,106,0.35) !important;
304
- border-radius: 10px !important;
305
- color: var(--kh-muted) !important;
306
- }
307
-
308
- .upload-container *,
309
- .file-preview * {
 
 
310
  background: transparent !important;
311
- color: var(--kh-muted) !important;
312
  }
313
 
314
  /* ══ BUTTONS ══ */
 
315
  button.primary,
316
  button[variant="primary"],
317
  .primary {
318
- min-height: 44px;
319
- background: linear-gradient(135deg, #3d7a6a 0%, #2e6055 100%) !important;
320
- color: #fff !important;
321
  border: none !important;
322
- border-radius: 9px !important;
323
- font-weight: 700 !important;
324
- font-size: 0.94rem !important;
325
- letter-spacing: 0.01em;
326
- box-shadow: 0 4px 14px rgba(61,122,106,0.30) !important;
327
- transition: transform 0.12s, box-shadow 0.12s;
 
 
328
  }
329
 
330
  button.primary:hover {
331
- transform: translateY(-1px);
332
- box-shadow: 0 7px 20px rgba(61,122,106,0.38) !important;
 
333
  }
334
 
 
 
 
 
 
335
  button.secondary,
336
  button[variant="secondary"],
337
  .secondary {
338
- background: rgba(232,226,212,0.8) !important;
339
- color: var(--kh-soft) !important;
340
- border: 1px solid rgba(80,65,35,0.18) !important;
341
- border-radius: 9px !important;
342
- font-weight: 600 !important;
 
 
 
 
 
 
343
  }
344
 
345
  button.secondary:hover {
346
- background: rgba(61,122,106,0.10) !important;
347
- border-color: rgba(61,122,106,0.32) !important;
348
- color: var(--kh-sage) !important;
349
- }
350
-
351
- /* ══ SLIDER ══ */
352
- input[type="range"] {
353
- accent-color: var(--kh-sage) !important;
354
  }
355
 
356
- /* ══ STATUS BOX ══ */
357
  #kh-status {
358
- min-height: 130px;
359
- color: var(--kh-ink) !important;
 
360
  }
361
 
362
  #kh-status h3 {
363
- color: var(--kh-sage) !important;
364
- font-family: "Instrument Serif", Georgia, serif !important;
365
- font-style: italic;
366
- font-weight: 400;
367
- font-size: 1.22rem;
368
  margin-top: 0;
369
  }
370
 
371
- /* ══ TEXT PREVIEW ══ */
372
- #kh-text-preview textarea {
373
- min-height: 430px !important;
374
- line-height: 1.65 !important;
375
- font-family: "JetBrains Mono", ui-monospace, monospace !important;
376
- font-size: 0.87rem !important;
377
- background: rgba(232,226,212,0.45) !important;
378
  }
379
 
380
- /* ══ SEARCH RESULTS / ANSWER / REASONING ══ */
381
- #kh-search-results {
382
- min-height: 410px;
383
- color: var(--kh-ink) !important;
384
  }
385
 
386
- #kh-search-results h3 {
387
- color: var(--kh-sage) !important;
388
- font-family: "Instrument Serif", Georgia, serif !important;
389
- font-style: italic;
390
- font-weight: 400;
 
 
 
 
 
 
 
 
 
 
391
  }
392
 
393
- #kh-answer {
394
- min-height: 240px;
395
- font-size: 1.02rem;
396
- line-height: 1.75;
397
- color: var(--kh-ink) !important;
 
 
 
 
 
 
 
 
 
398
  }
399
 
400
  #kh-reasoning {
401
- min-height: 240px;
402
- color: var(--kh-muted) !important;
403
- font-family: "JetBrains Mono", ui-monospace, monospace;
404
- font-size: 0.85rem;
405
- line-height: 1.65;
406
  }
407
 
408
- /* ══ MARKDOWN / PROSE ══ */
409
  .prose, .markdown,
410
  .prose *, .markdown * {
411
- color: var(--kh-soft) !important;
412
  background: transparent !important;
413
  }
414
 
415
- .prose strong, .markdown strong,
416
- .prose h1, .markdown h1,
417
- .prose h2, .markdown h2,
418
- .prose h3, .markdown h3 {
419
- color: var(--kh-ink) !important;
420
  }
421
 
422
  .prose h3, .markdown h3 {
423
- font-family: "Instrument Serif", Georgia, serif !important;
424
- font-style: italic;
425
- font-weight: 400;
426
- font-size: 1.13rem;
427
  }
428
 
429
  code {
430
- color: var(--kh-sage) !important;
431
- background: rgba(61,122,106,0.09) !important;
432
- border: 1px solid rgba(61,122,106,0.18) !important;
433
  border-radius: 4px;
434
- padding: 1px 5px;
435
- font-family: "JetBrains Mono", ui-monospace, monospace;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
  }
437
 
438
- /* ══ SCROLLBAR ══ */
439
- ::-webkit-scrollbar { width: 7px; height: 7px; }
440
- ::-webkit-scrollbar-track { background: rgba(232,226,212,0.4); }
441
- ::-webkit-scrollbar-thumb { background: rgba(61,122,106,0.32); border-radius: 99px; }
442
- ::-webkit-scrollbar-thumb:hover { background: rgba(61,122,106,0.52); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
 
444
- /* ══ DIVIDERS / MISC ══ */
445
- hr { border-color: var(--kh-line) !important; }
 
 
 
446
 
447
  /* ══ RESPONSIVE ══ */
448
- @media (max-width: 760px) {
449
- #kh-shell { padding: 18px 12px 36px; }
450
- #kh-title h1 { font-size: clamp(2.2rem, 13vw, 3.8rem); }
451
- .kh-panel { padding: 16px !important; }
 
 
 
 
 
 
 
452
  }
453
  """
 
1
  HEAD = """
2
  <link rel="preconnect" href="https://fonts.googleapis.com">
3
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
4
+ <link href="https://fonts.googleapis.com/css2?family=Gochi+Hand&family=Caveat:wght@400;700&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
5
  """
6
 
7
  JS = """
 
14
 
15
  CSS = """
16
  /* ═══════════════════════════════════════════════
17
+ KNOWLEDGEMESH β€” CHALKBOARD CLASSROOM THEME
18
+ Palette: Dark chalkboard green Β· Frosted glass Β· Warm chalk yellow Β· Neon chalk green
19
+ Texture: Wood border, vignette board, chalk doodles
20
+ ═══════════════════════════════════════════════ */
21
+
22
+ /* ══ PAGE BACKGROUND β€” Dark cozy classroom ══ */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  .gradio-container {
24
  min-height: 100vh !important;
25
+ background: radial-gradient(circle at center, #181715 0%, #0a0a09 100%) !important;
26
+ color: #f8fafc !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, sans-serif !important;
28
+ padding: 20px 10px !important;
29
  }
30
 
31
+ /* ══ NUKE GRADIO STYLING OVERRIDES ══ */
 
32
  .gradio-container *,
33
  .gradio-container .block,
34
  .gradio-container .form,
 
43
  .gradio-container .sm,
44
  .gradio-container .stretch {
45
  background-color: transparent !important;
46
+ color: inherit;
 
 
 
 
 
 
 
 
 
 
 
47
  }
48
 
49
+ /* ══ CHALKBOARD CONTAINER (FRAME & SURFACE) ══ */
50
  #kh-shell {
51
+ position: relative !important;
52
+ max-width: 1200px !important;
53
+ margin: 30px auto !important;
54
+ padding: 40px 40px 60px 40px !important;
55
+
56
+ /* Wood Frame border styling */
57
+ border: 14px solid #3d2314 !important;
58
+ border-radius: 12px !important;
59
+
60
+ /* Multi-layered shadows for frame bevel and board depth */
61
+ box-shadow:
62
+ 0 15px 35px rgba(0,0,0,0.85),
63
+ inset 0 0 20px rgba(0,0,0,0.9),
64
+ inset 0 0 0 1px #4f2f1c,
65
+ 0 0 0 1px #1d1009 !important;
66
+
67
+ /* Multiple backgrounds:
68
+ 1. Hanging lamp doodle (top right)
69
+ 2. Idea lightbulb (top center)
70
+ 3. Atom doodle (left)
71
+ 4. Neural Network sketch (left, lower)
72
+ 5. Mathematical graph (bottom left)
73
+ 6. Equations & math doodle (right)
74
+ 7. Tiny star/arrow doodle (top left)
75
+ 8. Chalkboard green vignette surface
76
+ */
77
+ background-image:
78
+ url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='80' height='180' viewBox='0 0 80 180'><path d='M 40,0 L 40,90' fill='none' stroke='rgba(255,255,255,0.18)' stroke-width='1.5'/><path d='M 25,90 L 55,90 L 60,105 L 20,105 Z' fill='rgba(255,255,255,0.04)' stroke='rgba(255,255,255,0.22)' stroke-width='1.5' stroke-linejoin='round'/><circle cx='40' cy='113' r='8' fill='rgba(255,255,220,0.12)' stroke='rgba(255,255,255,0.25)' stroke-width='1.5'/><path d='M 38,110 L 40,115 L 42,110' fill='none' stroke='rgba(255,255,220,0.5)' stroke-width='1'/><path d='M 20,125 L 10,135 M 30,128 L 25,140 M 50,128 L 55,140 M 60,125 L 70,135' fill='none' stroke='rgba(255,255,220,0.18)' stroke-width='1' stroke-linecap='round'/></svg>"),
79
+ url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='60' height='70' viewBox='0 0 60 70'><path d='M 30,10 C 20,10 15,20 15,30 C 15,40 25,45 25,50 L 35,50 C 35,45 45,40 45,30 C 45,20 40,10 30,10 Z M 25,50 L 35,50 M 27,54 L 33,54 M 29,58 L 31,58' fill='none' stroke='rgba(255,255,255,0.06)' stroke-width='1.2'/><path d='M 10,25 L 5,22 M 12,15 L 7,10 M 30,5 L 30,0 M 48,15 L 53,10 M 50,25 L 55,22' fill='none' stroke='rgba(255,255,255,0.06)' stroke-width='1' stroke-linecap='round'/></svg>"),
80
+ url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'><ellipse cx='50' cy='50' rx='42' ry='12' fill='none' stroke='rgba(255,255,255,0.06)' stroke-width='1.2' transform='rotate(30 50 50)'/><ellipse cx='50' cy='50' rx='42' ry='12' fill='none' stroke='rgba(255,255,255,0.06)' stroke-width='1.2' transform='rotate(-30 50 50)'/><ellipse cx='50' cy='50' rx='42' ry='12' fill='none' stroke='rgba(255,255,255,0.06)' stroke-width='1.2' transform='rotate(90 50 50)'/><circle cx='50' cy='50' r='5' fill='rgba(255,255,255,0.08)'/></svg>"),
81
+ url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='90' height='120' viewBox='0 0 90 120'><circle cx='20' cy='20' r='4' fill='none' stroke='rgba(255,255,255,0.05)' stroke-width='1.2'/><circle cx='20' cy='60' r='4' fill='none' stroke='rgba(255,255,255,0.05)' stroke-width='1.2'/><circle cx='20' cy='100' r='4' fill='none' stroke='rgba(255,255,255,0.05)' stroke-width='1.2'/><circle cx='70' cy='40' r='4' fill='none' stroke='rgba(255,255,255,0.05)' stroke-width='1.2'/><circle cx='70' cy='80' r='4' fill='none' stroke='rgba(255,255,255,0.05)' stroke-width='1.2'/><line x1='24' y1='20' x2='66' y2='40' stroke='rgba(255,255,255,0.03)' stroke-width='1'/><line x1='24' y1='20' x2='66' y2='80' stroke='rgba(255,255,255,0.03)' stroke-width='1'/><line x1='24' y1='60' x2='66' y2='40' stroke='rgba(255,255,255,0.03)' stroke-width='1'/><line x1='24' y1='60' x2='66' y2='80' stroke='rgba(255,255,255,0.03)' stroke-width='1'/><line x1='24' y1='100' x2='66' y2='40' stroke='rgba(255,255,255,0.03)' stroke-width='1'/><line x1='24' y1='100' x2='66' y2='80' stroke='rgba(255,255,255,0.03)' stroke-width='1'/></svg>"),
82
+ url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='90' height='80' viewBox='0 0 90 80'><path d='M 10,10 L 10,70 L 80,70' fill='none' stroke='rgba(255,255,255,0.05)' stroke-width='1.2'/><path d='M 10,60 Q 30,30 50,50 T 80,20' fill='none' stroke='rgba(255,255,255,0.05)' stroke-width='1.2' stroke-dasharray='3,3'/><path d='M 10,50 Q 25,20 45,30 T 75,10' fill='none' stroke='rgba(255,255,255,0.07)' stroke-width='1.2'/></svg>"),
83
+ url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 120 120'><path d='M 90,20 L 93,27 L 100,27 L 95,31 L 97,38 L 90,34 L 83,38 L 85,31 L 80,27 L 87,27 Z' fill='none' stroke='rgba(255,255,255,0.08)' stroke-width='1.2'/><text x='10' y='70' font-family='&apos;Gochi Hand&apos;, cursive' font-size='15' fill='rgba(255,255,255,0.07)' transform='rotate(-5 10 70)'>e^(i.pi) %2B 1 = 0</text><path d='M 20,90 L 50,90 M 50,90 L 45,86 M 50,90 L 45,94' fill='none' stroke='rgba(255,255,255,0.06)' stroke-width='1.2'/><path d='M 20,90 L 40,110 M 40,110 L 35,110 M 40,110 L 40,105' fill='none' stroke='rgba(255,255,255,0.06)' stroke-width='1.2'/><text x='55' y='93' font-family='&apos;Gochi Hand&apos;, cursive' font-size='12' fill='rgba(255,255,255,0.06)'>F</text></svg>"),
84
+ url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='80' height='80' viewBox='0 0 80 80'><path d='M 10,20 Q 25,5 40,20 Q 55,35 40,50 Q 25,65 15,50' fill='none' stroke='rgba(255,255,255,0.05)' stroke-width='1.5' stroke-linecap='round'/></svg>"),
85
+ radial-gradient(circle at 50% 30%, #1c3d28 0%, #0d1e13 100%) !important;
86
+
87
+ background-position:
88
+ right 35px top 0px,
89
+ center top 20px,
90
+ left 20px top 220px,
91
+ left 30px top 450px,
92
+ left 40px top 650px,
93
+ right 30px top 350px,
94
+ left 30px top 60px,
95
+ center center !important;
96
+ background-repeat: no-repeat !important;
97
+ background-size: auto, auto, auto, auto, auto, auto, auto, cover !important;
98
+ overflow: visible !important;
99
+ }
100
+ }
101
+
102
+ /* ══ ROOM TAG ══ */
103
+ .kh-room-tag {
104
+ position: absolute;
105
+ top: -12px;
106
+ left: 35px;
107
+ background: #142d1c !important;
108
+ border: 1.5px solid rgba(94, 189, 114, 0.45) !important;
109
+ color: #5ebd72 !important;
110
+ padding: 4px 14px;
111
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
112
+ font-size: 1.15rem !important;
113
+ border-radius: 6px !important;
114
+ transform: rotate(-1.5deg) !important;
115
+ box-shadow: 0 4px 12px rgba(0,0,0,0.4) !important;
116
+ z-index: 10;
117
+ pointer-events: none;
118
+ }
119
+
120
+ /* ══ HEADER & TYPOGRAPHY ══ */
121
  #kh-title {
122
+ padding: 10px 0 15px !important;
123
+ border-bottom: 2px dashed rgba(255, 255, 255, 0.12) !important;
124
  background: transparent !important;
125
+ text-align: left;
126
  }
127
 
128
  #kh-title h1 {
129
+ color: #ffffff !important;
130
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
131
+ font-size: clamp(2.8rem, 6vw, 4.8rem) !important;
132
+ font-weight: 400 !important;
133
+ line-height: 1.0;
134
+ margin: 0 0 6px !important;
135
+ text-shadow: 0 0 8px rgba(255, 255, 255, 0.4), 1px 1px 2px rgba(0,0,0,0.6) !important;
 
 
136
  }
137
 
138
  #kh-title p {
139
+ color: rgba(255, 255, 255, 0.75) !important;
140
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
141
+ font-size: 1.35rem !important;
142
+ margin: 0 !important;
143
+ letter-spacing: 0.03em !important;
144
  }
145
 
146
  /* ══ CODE CHIPS ══ */
 
 
 
 
 
 
 
 
 
 
 
 
147
  .kh-chip-row {
148
  display: flex;
149
  flex-wrap: wrap;
150
+ gap: 8px;
151
+ margin: 14px 0 24px !important;
152
  background: transparent !important;
153
  }
154
 
155
  .kh-chip {
156
+ border: 1px solid rgba(255, 255, 255, 0.15) !important;
157
+ border-radius: 999px !important;
158
+ padding: 4px 12px !important;
159
+ color: rgba(255, 255, 255, 0.7) !important;
160
+ background: rgba(255, 255, 255, 0.03) !important;
161
+ font-size: 0.82rem !important;
162
+ font-weight: 500 !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  }
164
 
165
+ .kh-chip code {
166
+ color: #5ebd72 !important;
167
+ background: rgba(94, 189, 114, 0.08) !important;
168
+ border: 1px solid rgba(94, 189, 114, 0.2) !important;
169
+ border-radius: 4px;
170
+ padding: 1px 4px;
171
+ font-family: "JetBrains Mono", monospace;
172
+ font-size: 0.85em;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  }
174
 
175
+ /* ══ CHALKBOARD TABS NAVIGATION ══ */
176
  .tabs {
177
+ margin-top: 10px !important;
178
+ border: none !important;
179
  }
180
 
181
  .tab-nav {
182
+ border-bottom: 2px dashed rgba(255, 255, 255, 0.15) !important;
183
+ margin-bottom: 22px !important;
184
+ gap: 12px !important;
185
  background: transparent !important;
 
 
186
  }
187
 
188
  .tab-nav button {
189
+ color: rgba(255, 255, 255, 0.55) !important;
190
  background: transparent !important;
191
+ border: none !important;
192
+ border-radius: 0 !important;
193
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
194
+ font-size: 1.45rem !important;
195
+ font-weight: normal !important;
196
+ padding: 6px 20px !important;
197
+ transition: all 0.2s ease !important;
198
  }
199
 
200
  .tab-nav button:hover {
201
+ color: #ffffff !important;
202
+ text-shadow: 0 0 6px rgba(255, 255, 255, 0.5) !important;
203
  }
204
 
205
  .tab-nav button.selected {
206
+ color: #ffffff !important;
207
+ text-shadow: 0 0 10px rgba(255, 255, 255, 0.8) !important;
208
+ border-bottom: 3px solid #5ebd72 !important;
209
+ }
210
+
211
+ /* ══ FROSTED GLASS CARDS ══ */
212
+ .kh-panel {
213
+ background: rgba(255, 255, 255, 0.038) !important;
214
+ backdrop-filter: blur(12px) !important;
215
+ -webkit-backdrop-filter: blur(12px) !important;
216
+ border: 1px solid rgba(255, 255, 255, 0.09) !important;
217
+ border-radius: 12px !important;
218
+ padding: 24px !important;
219
+ box-shadow:
220
+ 0 8px 32px 0 rgba(0, 0, 0, 0.28),
221
+ inset 0 1px 0 rgba(255, 255, 255, 0.04) !important;
222
+ color: #f8fafc !important;
223
+ margin-bottom: 15px !important;
224
+ }
225
+
226
+ .kh-panel h3 {
227
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
228
+ font-size: 1.6rem !important;
229
+ font-weight: normal !important;
230
+ color: #ffffff !important;
231
+ margin-top: 0 !important;
232
+ margin-bottom: 8px !important;
233
+ text-shadow: 1px 1px 2px rgba(0,0,0,0.4) !important;
234
+ }
235
+
236
+ .kh-subhead {
237
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
238
+ font-size: 1.15rem !important;
239
+ color: rgba(255, 255, 255, 0.55) !important;
240
+ line-height: 1.4 !important;
241
+ margin-bottom: 16px !important;
242
  }
243
 
244
  /* ══ INPUTS & TEXTAREAS ══ */
245
  textarea,
246
  input[type="text"],
247
  input[type="number"],
248
+ [data-testid="textbox"] input,
249
+ [data-testid="textbox"] textarea {
250
+ background: rgba(0, 0, 0, 0.28) !important;
251
+ color: #f8fafc !important;
252
+ border: 1px solid rgba(255, 255, 255, 0.14) !important;
253
  border-radius: 8px !important;
254
+ padding: 10px 14px !important;
255
  font-size: 0.94rem !important;
256
+ font-family: Inter, ui-sans-serif, sans-serif !important;
257
+ box-shadow: inset 0 2px 4px rgba(0,0,0,0.5) !important;
258
+ transition: all 0.2s ease !important;
259
  }
260
 
261
  textarea:focus,
262
+ input[type="text"]:focus,
263
+ [data-testid="textbox"] input:focus,
264
+ [data-testid="textbox"] textarea:focus {
265
+ border-color: rgba(94, 189, 114, 0.5) !important;
266
+ box-shadow:
267
+ 0 0 8px rgba(94, 189, 114, 0.25),
268
+ inset 0 2px 4px rgba(0,0,0,0.5) !important;
269
  outline: none !important;
270
  }
271
 
272
  textarea::placeholder,
273
  input::placeholder {
274
+ color: rgba(255, 255, 255, 0.38) !important;
275
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
276
+ font-size: 1.18rem !important;
277
+ }
278
+
279
+ /* Custom styles for Gradio form labels */
280
+ .kh-panel label span,
281
+ .kh-panel .label-wrap span {
282
+ color: rgba(255, 255, 255, 0.5) !important;
283
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
284
+ font-size: 1.15rem !important;
285
+ font-weight: normal !important;
286
+ margin-bottom: 4px !important;
287
  }
288
 
289
+ /* ══ UPLOAD DRAG/DROP FILE BLOCK ══ */
290
  .upload-container,
291
  .file-preview,
292
  [data-testid="file"],
293
  .file-upload {
294
+ background: rgba(0, 0, 0, 0.2) !important;
295
+ border: 2px dashed rgba(255, 255, 255, 0.14) !important;
296
+ border-radius: 8px !important;
297
+ color: rgba(255, 255, 255, 0.5) !important;
298
+ padding: 14px !important;
299
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
300
+ font-size: 1.18rem !important;
301
+ transition: all 0.2s ease !important;
302
+ text-align: center;
303
+ }
304
+
305
+ .upload-container:hover {
306
+ border-color: rgba(94, 189, 114, 0.45) !important;
307
+ background: rgba(94, 189, 114, 0.04) !important;
308
+ }
309
+
310
+ .upload-container *, .file-preview * {
311
  background: transparent !important;
312
+ color: rgba(255, 255, 255, 0.55) !important;
313
  }
314
 
315
  /* ══ BUTTONS ══ */
316
+ /* Primary Button β€” Warm Chalk Yellow, Slight Glow */
317
  button.primary,
318
  button[variant="primary"],
319
  .primary {
320
+ min-height: 42px;
321
+ background: #d9b84a !important;
322
+ color: #1c1605 !important;
323
  border: none !important;
324
+ border-radius: 8px !important;
325
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
326
+ font-size: 1.38rem !important;
327
+ font-weight: bold !important;
328
+ padding: 8px 24px !important;
329
+ box-shadow: 0 0 15px rgba(217, 184, 74, 0.32) !important;
330
+ cursor: pointer !important;
331
+ transition: all 0.2s ease !important;
332
  }
333
 
334
  button.primary:hover {
335
+ background: #e4c45a !important;
336
+ box-shadow: 0 0 22px rgba(217, 184, 74, 0.5) !important;
337
+ transform: translateY(-1.5px) !important;
338
  }
339
 
340
+ button.primary:active {
341
+ transform: translateY(0.5px) !important;
342
+ }
343
+
344
+ /* Secondary Button β€” Neon Chalk Green Outline */
345
  button.secondary,
346
  button[variant="secondary"],
347
  .secondary {
348
+ min-height: 42px;
349
+ background: transparent !important;
350
+ color: #5ebd72 !important;
351
+ border: 2px dashed #5ebd72 !important;
352
+ border-radius: 8px !important;
353
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
354
+ font-size: 1.38rem !important;
355
+ font-weight: bold !important;
356
+ padding: 6px 22px !important;
357
+ cursor: pointer !important;
358
+ transition: all 0.2s ease !important;
359
  }
360
 
361
  button.secondary:hover {
362
+ background: rgba(94, 189, 114, 0.08) !important;
363
+ box-shadow: 0 0 12px rgba(94, 189, 114, 0.35) !important;
364
+ border-style: solid !important;
 
 
 
 
 
365
  }
366
 
367
+ /* ══ PIPELINE STATUS WATERMARK ══ */
368
  #kh-status {
369
+ min-height: 100px;
370
+ color: #ffffff !important;
371
+ padding: 10px !important;
372
  }
373
 
374
  #kh-status h3 {
375
+ color: #d9b84a !important;
376
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
377
+ font-size: 1.38rem !important;
 
 
378
  margin-top: 0;
379
  }
380
 
381
+ #kh-status p {
382
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
383
+ font-size: 1.25rem !important;
384
+ color: rgba(255, 255, 255, 0.85) !important;
385
+ line-height: 1.4 !important;
 
 
386
  }
387
 
388
+ #kh-status code {
389
+ color: #5ebd72 !important;
390
+ background: rgba(94, 189, 114, 0.1) !important;
391
+ border: 1px dashed rgba(94, 189, 114, 0.25) !important;
392
  }
393
 
394
+ /* ══ STAT BOXES (INGEST STATS) ══ */
395
+ .kh-stat {
396
+ border: 1px solid rgba(255,255,255,0.08) !important;
397
+ border-radius: 8px !important;
398
+ padding: 8px 12px !important;
399
+ background: rgba(0,0,0,0.18) !important;
400
+ }
401
+
402
+ /* ══ PREVIEW & METADATA SECTIONS ══ */
403
+ #kh-text-preview textarea {
404
+ min-height: 400px !important;
405
+ font-family: "JetBrains Mono", monospace !important;
406
+ font-size: 0.86rem !important;
407
+ background: rgba(0,0,0,0.3) !important;
408
+ color: #e2e8f0 !important;
409
  }
410
 
411
+ #kh-search-results, #kh-answer, #kh-reasoning {
412
+ min-height: 180px;
413
+ background: rgba(0, 0, 0, 0.24) !important;
414
+ border: 1px solid rgba(255,255,255,0.08) !important;
415
+ border-radius: 8px !important;
416
+ padding: 16px !important;
417
+ color: #f1f5f9 !important;
418
+ }
419
+
420
+ #kh-search-results h3 {
421
+ color: #5ebd72 !important;
422
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
423
+ font-size: 1.35rem !important;
424
+ margin-top: 10px !important;
425
  }
426
 
427
  #kh-reasoning {
428
+ font-family: "JetBrains Mono", monospace !important;
429
+ font-size: 0.85rem !important;
430
+ color: #94a3b8 !important;
 
 
431
  }
432
 
433
+ /* ══ PROSE / MARKDOWN INTERNALS ══ */
434
  .prose, .markdown,
435
  .prose *, .markdown * {
436
+ color: rgba(255, 255, 255, 0.85) !important;
437
  background: transparent !important;
438
  }
439
 
440
+ .prose strong, .markdown strong {
441
+ color: #ffffff !important;
 
 
 
442
  }
443
 
444
  .prose h3, .markdown h3 {
445
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif !important;
446
+ font-size: 1.38rem !important;
447
+ color: #ffffff !important;
 
448
  }
449
 
450
  code {
451
+ color: #5ebd72 !important;
452
+ background: rgba(94,189,114,0.08) !important;
453
+ border: 1px solid rgba(94,189,114,0.2) !important;
454
  border-radius: 4px;
455
+ padding: 1px 4px;
456
+ font-family: "JetBrains Mono", monospace;
457
+ }
458
+
459
+ /* ══ RETRIEVE COLUMN WATERMARK & INDICATORS ══ */
460
+ .kh-retrieve-status {
461
+ display: flex;
462
+ justify-content: space-between;
463
+ align-items: center;
464
+ margin-top: 15px;
465
+ padding: 0 6px;
466
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif;
467
+ font-size: 1.25rem;
468
+ color: rgba(255,255,255,0.55);
469
+ }
470
+
471
+ .kh-online-status {
472
+ display: flex;
473
+ align-items: center;
474
+ gap: 5px;
475
+ }
476
+
477
+ .kh-dot {
478
+ width: 7px;
479
+ height: 7px;
480
+ border-radius: 50%;
481
+ background: rgba(255,255,255,0.2);
482
+ display: inline-block;
483
+ }
484
+
485
+ .kh-dot.green {
486
+ background: #5ebd72;
487
+ box-shadow: 0 0 6px #5ebd72;
488
+ }
489
+
490
+ .kh-brackets {
491
+ font-size: 1.6rem;
492
+ color: rgba(255, 255, 255, 0.35);
493
+ font-weight: bold;
494
+ letter-spacing: 2px;
495
  }
496
 
497
+ /* ══ BOTTOM TRAY & COLORED CHALK PIECES ══ */
498
+ #kh-bottom-container {
499
+ margin-top: 15px !important;
500
+ background: transparent !important;
501
+ }
502
+
503
+ .kh-bottom-tray {
504
+ display: flex;
505
+ justify-content: space-between;
506
+ align-items: flex-end;
507
+ padding: 10px 10px 0 10px;
508
+ position: relative;
509
+ }
510
+
511
+ /* Wooden Tray Ledge below the board frame */
512
+ .kh-bottom-tray::before {
513
+ content: "";
514
+ position: absolute;
515
+ bottom: -32px;
516
+ left: -40px;
517
+ right: -40px;
518
+ height: 13px;
519
+ background: linear-gradient(to bottom, #6d3f27, #442516);
520
+ border-radius: 2px;
521
+ box-shadow:
522
+ 0 10px 18px rgba(0, 0, 0, 0.65),
523
+ inset 0 1px 0 rgba(255, 255, 255, 0.12);
524
+ z-index: 5;
525
+ }
526
+
527
+ .kh-chalks {
528
+ display: flex;
529
+ gap: 10px;
530
+ position: absolute;
531
+ bottom: -31px;
532
+ left: 20px;
533
+ z-index: 6;
534
+ }
535
+
536
+ .kh-chalk {
537
+ width: 30px;
538
+ height: 7px;
539
+ border-radius: 2px;
540
+ box-shadow: 1px 1px 2px rgba(0,0,0,0.3);
541
+ }
542
+
543
+ .kh-chalk.white {
544
+ background: #f1f5f9;
545
+ transform: rotate(2deg);
546
+ }
547
+
548
+ .kh-chalk.yellow {
549
+ background: #e2c362;
550
+ transform: rotate(-3deg);
551
+ }
552
+
553
+ .kh-chalk.purple {
554
+ background: #d8b4fe;
555
+ transform: rotate(5deg);
556
+ }
557
+
558
+ .kh-watermark {
559
+ font-family: 'Gochi Hand', 'Caveat', cursive, sans-serif;
560
+ font-size: 1.15rem;
561
+ color: rgba(255, 255, 255, 0.35);
562
+ margin-bottom: -15px;
563
+ z-index: 6;
564
+ }
565
 
566
+ /* ══ SCROLLBARS ══ */
567
+ ::-webkit-scrollbar { width: 6px; height: 6px; }
568
+ ::-webkit-scrollbar-track { background: rgba(0,0,0,0.15); }
569
+ ::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.12); border-radius: 99px; }
570
+ ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.25); }
571
 
572
  /* ══ RESPONSIVE ══ */
573
+ @media (max-width: 768px) {
574
+ #kh-shell {
575
+ padding: 25px 20px 45px 20px !important;
576
+ border-width: 10px !important;
577
+ margin: 15px auto !important;
578
+ }
579
+ .kh-bottom-tray::before {
580
+ left: -20px;
581
+ right: -20px;
582
+ }
583
+ #kh-title h1 { font-size: 2.3rem !important; }
584
  }
585
  """
requirements.txt CHANGED
@@ -9,3 +9,4 @@ qdrant-client>=1.12.1
9
  requests>=2.32.3
10
  sentence-transformers>=3.0.1
11
  spaces
 
 
9
  requests>=2.32.3
10
  sentence-transformers>=3.0.1
11
  spaces
12
+ torchvision