StanDataCamp commited on
Commit
1e8a7e0
·
1 Parent(s): 84c92d2

Add automatic light/dark theme support

Browse files
Files changed (5) hide show
  1. .gitattributes +2 -0
  2. README.md +21 -0
  3. app.py +29 -4
  4. scripts/deploy_hf_space.sh +98 -0
  5. styles.css +192 -63
.gitattributes CHANGED
@@ -35,3 +35,5 @@ data/episodes_embedding_chunks.csv filter=lfs diff=lfs merge=lfs -text
35
  *.zip filter=lfs diff=lfs merge=lfs -text
36
  *.zst filter=lfs diff=lfs merge=lfs -text
37
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
35
  *.zip filter=lfs diff=lfs merge=lfs -text
36
  *.zst filter=lfs diff=lfs merge=lfs -text
37
  *tfevents* filter=lfs diff=lfs merge=lfs -text
38
+ *.faiss filter=lfs diff=lfs merge=lfs -text
39
+ data/episodes_embedding_chunks.csv filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -88,6 +88,27 @@ uv run app.py
88
 
89
  Open http://localhost:7860
90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  ### Why uv?
92
 
93
  We use [uv](https://docs.astral.sh/uv/) for dependency management — it's fast, handles Python versions, and creates reproducible environments via `uv.lock`. No Docker overhead needed.
 
88
 
89
  Open http://localhost:7860
90
 
91
+ ### Deploy to Hugging Face Spaces
92
+
93
+ Use the no-persistent-clone deploy script. It creates a temporary clone, shows the exact staged diff, pushes to your Space, then deletes the temp folder.
94
+
95
+ ```bash
96
+ # One-time prerequisite
97
+ brew install git-lfs
98
+
99
+ # Optional: use token-based auth for non-interactive push
100
+ export HF_TOKEN=hf_xxx
101
+
102
+ # Deploy (you will see pending changes before confirm)
103
+ ./scripts/deploy_hf_space.sh "Deploy latest Podcast Assistant updates"
104
+ ```
105
+
106
+ By default, it deploys to `StanKonkin/Podcast_Assistant`. Override with:
107
+
108
+ ```bash
109
+ SPACE_REPO=YourUser/YourSpace ./scripts/deploy_hf_space.sh "Deploy update"
110
+ ```
111
+
112
  ### Why uv?
113
 
114
  We use [uv](https://docs.astral.sh/uv/) for dependency management — it's fast, handles Python versions, and creates reproducible environments via `uv.lock`. No Docker overhead needed.
app.py CHANGED
@@ -95,6 +95,31 @@ feedback_logger = FeedbackLogger(FEEDBACK_FILE)
95
  def create_app():
96
  """Create and configure the Gradio application."""
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  with gr.Blocks(title="Podcast Assistant") as app:
99
  # State variables
100
  conversation_id = gr.State(lambda: str(uuid.uuid4()))
@@ -105,7 +130,7 @@ def create_app():
105
 
106
  # Header - centered
107
  gr.Markdown("""
108
- <div style="text-align: center;">
109
  <h1>🎧 Podcast Assistant</h1>
110
  <p>Ask questions about Lex Fridman podcast episodes. Get answers with quotes and links.</p>
111
  </div>
@@ -439,10 +464,10 @@ def create_app():
439
  ]
440
  )
441
 
442
- return app
443
 
444
 
445
  if __name__ == "__main__":
446
- app = create_app()
447
  # server_name="0.0.0.0" allows access from other devices on the same network
448
- app.launch(css=CUSTOM_CSS, footer_links=[], server_name="0.0.0.0")
 
95
  def create_app():
96
  """Create and configure the Gradio application."""
97
 
98
+ # Create a custom theme that supports both light and dark modes
99
+ custom_theme = gr.themes.Soft(
100
+ primary_hue=gr.themes.Color(
101
+ c50="#f0fdfa",
102
+ c100="#ccfbf1",
103
+ c200="#99f6e4",
104
+ c300="#5eead4",
105
+ c400="#2dd4bf",
106
+ c500="#0091ad", # Our primary teal
107
+ c600="#0091ad",
108
+ c700="#007a94",
109
+ c800="#006275",
110
+ c900="#004d5c",
111
+ c950="#003844",
112
+ ),
113
+ secondary_hue="slate",
114
+ neutral_hue="slate",
115
+ font=[
116
+ gr.themes.GoogleFont("Poppins"),
117
+ "ui-sans-serif",
118
+ "system-ui",
119
+ "sans-serif",
120
+ ],
121
+ )
122
+
123
  with gr.Blocks(title="Podcast Assistant") as app:
124
  # State variables
125
  conversation_id = gr.State(lambda: str(uuid.uuid4()))
 
130
 
131
  # Header - centered
132
  gr.Markdown("""
133
+ <div class="header-content">
134
  <h1>🎧 Podcast Assistant</h1>
135
  <p>Ask questions about Lex Fridman podcast episodes. Get answers with quotes and links.</p>
136
  </div>
 
464
  ]
465
  )
466
 
467
+ return app, custom_theme
468
 
469
 
470
  if __name__ == "__main__":
471
+ app, theme = create_app()
472
  # server_name="0.0.0.0" allows access from other devices on the same network
473
+ app.launch(theme=theme, css=CUSTOM_CSS, footer_links=[], server_name="0.0.0.0")
scripts/deploy_hf_space.sh ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Deploy Podcast Assistant to Hugging Face Spaces using a temporary clone.
5
+ # No persistent extra folders are left behind.
6
+ #
7
+ # Usage:
8
+ # ./scripts/deploy_hf_space.sh "Your commit message"
9
+ # Optional env:
10
+ # SPACE_REPO=StanKonkin/Podcast_Assistant
11
+ # HF_TOKEN=hf_xxx
12
+ # AUTO_CONFIRM=1
13
+
14
+ SPACE_REPO="${SPACE_REPO:-StanKonkin/Podcast_Assistant}"
15
+ PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
16
+ TMP_DIR="$(mktemp -d -t hf-space-deploy-XXXXXX)"
17
+ SPACE_CLONE="${TMP_DIR}/space"
18
+ SPACE_URL="https://huggingface.co/spaces/${SPACE_REPO}"
19
+ COMMIT_MSG="${*:-Deploy Podcast Assistant update}"
20
+
21
+ cleanup() {
22
+ rm -rf "${TMP_DIR}"
23
+ }
24
+ trap cleanup EXIT
25
+
26
+ if ! command -v git >/dev/null 2>&1; then
27
+ echo "git is required but not installed."
28
+ exit 1
29
+ fi
30
+
31
+ if ! command -v git-lfs >/dev/null 2>&1; then
32
+ echo "git-lfs is required. Install first: brew install git-lfs"
33
+ exit 1
34
+ fi
35
+
36
+ if [[ -n "${HF_TOKEN:-}" ]]; then
37
+ AUTH_URL="https://user:${HF_TOKEN}@huggingface.co/spaces/${SPACE_REPO}"
38
+ else
39
+ AUTH_URL="${SPACE_URL}"
40
+ fi
41
+
42
+ echo "Cloning ${SPACE_REPO} into temporary workspace..."
43
+ git clone "${AUTH_URL}" "${SPACE_CLONE}" >/dev/null
44
+
45
+ echo "Syncing local project into Space clone..."
46
+ rsync -a --delete \
47
+ --exclude '.git/' \
48
+ --exclude '.gitattributes' \
49
+ --exclude '.env' \
50
+ --exclude '.venv/' \
51
+ --exclude '.gradio/' \
52
+ --exclude '.cursor/' \
53
+ --exclude '.specstory/' \
54
+ --exclude '.cursorindexingignore' \
55
+ --exclude '__pycache__/' \
56
+ --exclude '.DS_Store' \
57
+ --exclude 'tasks.md' \
58
+ "${PROJECT_DIR}/" "${SPACE_CLONE}/"
59
+
60
+ ensure_lfs_rule() {
61
+ local rule="$1"
62
+ if ! rg -F -x -q "${rule}" "${SPACE_CLONE}/.gitattributes"; then
63
+ echo "${rule}" >> "${SPACE_CLONE}/.gitattributes"
64
+ fi
65
+ }
66
+
67
+ ensure_lfs_rule "*.faiss filter=lfs diff=lfs merge=lfs -text"
68
+ ensure_lfs_rule "data/episodes_embedding_chunks.csv filter=lfs diff=lfs merge=lfs -text"
69
+
70
+ cd "${SPACE_CLONE}"
71
+ git add .
72
+
73
+ echo
74
+ echo "===== Pending Space changes ====="
75
+ git status --short
76
+ echo
77
+ git diff --cached --stat
78
+ echo "================================="
79
+ echo
80
+
81
+ if git diff --cached --quiet; then
82
+ echo "No changes to deploy."
83
+ exit 0
84
+ fi
85
+
86
+ if [[ "${AUTO_CONFIRM:-0}" != "1" ]]; then
87
+ read -r -p "Commit and push to ${SPACE_REPO}? [y/N] " answer
88
+ if [[ ! "${answer}" =~ ^[Yy]$ ]]; then
89
+ echo "Cancelled. No push performed."
90
+ exit 0
91
+ fi
92
+ fi
93
+
94
+ git commit -m "${COMMIT_MSG}" >/dev/null
95
+ git push origin main
96
+
97
+ echo
98
+ echo "Deployment complete: ${SPACE_URL}/tree/main"
styles.css CHANGED
@@ -3,15 +3,7 @@
3
  *
4
  * Design: Modern, minimalistic interface with teal color palette
5
  * Typography: Poppins font family
6
- *
7
- * Color Palette:
8
- * Primary teal: #0091ad (buttons, links, accents)
9
- * Dark teal hover: #007a94
10
- * Light teal bg: #e0f7fa, #f0fdfa
11
- * Text dark: #0f172a
12
- * Text muted: #64748b, #94a3b8
13
- * Borders: #e2e8f0
14
- * Surface: #f8fafc
15
  */
16
 
17
  /* ============================================================
@@ -23,6 +15,113 @@
23
  font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif !important;
24
  }
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  /* ============================================================
27
  LAYOUT & CONTAINER
28
  ============================================================ */
@@ -63,26 +162,21 @@ footer.svelte-zxu34v {
63
  /* ============================================================
64
  COLOR THEME - Override Gradio orange with teal
65
  ============================================================ */
66
- :root {
67
- --color-accent: #0091ad !important;
68
- --color-accent-soft: #e0f7fa !important;
69
- }
70
-
71
  .orange, [class*="orange"], [style*="orange"] {
72
- background: #0091ad !important;
73
- border-color: #0091ad !important;
74
  }
75
 
76
  [style*="rgb(249"] {
77
- border-color: #0091ad !important;
78
  }
79
 
80
  .progress-bar, .progress-level {
81
- background: #0091ad !important;
82
  }
83
 
84
  *:focus {
85
- outline-color: #0091ad !important;
86
  }
87
 
88
  /* ============================================================
@@ -93,15 +187,21 @@ footer.svelte-zxu34v {
93
  text-align: center !important;
94
  }
95
 
96
- .header-section h1 {
 
 
 
 
 
97
  font-weight: 700 !important;
98
  font-size: 1.6rem !important;
99
  margin-bottom: 2px !important;
100
- color: #0f172a !important;
101
  }
102
 
103
- .header-section p {
104
- color: #64748b !important;
 
105
  font-size: 0.85rem !important;
106
  margin: 0 !important;
107
  }
@@ -111,7 +211,7 @@ footer.svelte-zxu34v {
111
  ============================================================ */
112
  #chatbot {
113
  border-radius: 12px !important;
114
- border: 1px solid #e2e8f0 !important;
115
  box-shadow: 0 2px 8px rgba(0,145,173,0.06) !important;
116
  min-height: 240px !important;
117
  }
@@ -137,27 +237,27 @@ footer.svelte-zxu34v {
137
  /* User message bubbles */
138
  #chatbot .user.message,
139
  .svelte-1nr59td.user {
140
- background: #e0f7fa !important;
141
- color: #0f172a !important;
142
- border: 1px solid #b2ebf2 !important;
143
  }
144
 
145
  /* Links in chat */
146
  #chatbot a {
147
- color: #0091ad !important;
148
  font-weight: 600 !important;
149
  text-decoration: underline !important;
150
  text-underline-offset: 2px !important;
151
  }
152
 
153
  #chatbot a:hover {
154
- color: #007a94 !important;
155
  }
156
 
157
  /* Blockquotes in chat */
158
  #chatbot blockquote {
159
- border-left: 3px solid #0091ad !important;
160
- background: #f0fdfa !important;
161
  padding: 10px 14px !important;
162
  margin: 8px 0 !important;
163
  border-radius: 0 8px 8px 0 !important;
@@ -187,19 +287,24 @@ footer.svelte-zxu34v {
187
  .input-row input,
188
  .input-row textarea {
189
  border-radius: 10px !important;
190
- border: 1px solid #e2e8f0 !important;
191
  padding: 12px 16px !important;
192
  font-size: 0.85rem !important;
193
  min-height: 44px !important;
194
- background: #f8fafc !important;
195
  max-width: 700px !important;
 
196
  }
197
 
198
  .input-row input:focus,
199
  .input-row textarea:focus {
200
- border-color: #0091ad !important;
201
  box-shadow: none !important;
202
- background: white !important;
 
 
 
 
203
  }
204
 
205
  /* ============================================================
@@ -237,22 +342,41 @@ button.primary:hover {
237
  background: linear-gradient(135deg, #007a94 0%, #0091ad 100%) !important;
238
  }
239
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  /* New button */
241
  .new-btn {
242
  gap: 0 !important;
243
  }
244
 
245
  .new-btn button {
246
- background: #f0fdfa !important;
247
- color: #0d9488 !important;
248
- border: 1px solid #99f6e4 !important;
249
  height: 30px !important;
250
  font-size: 0.7rem !important;
251
  }
252
 
253
  .new-btn button:hover {
254
- background: #ccfbf1 !important;
255
- border-color: #5eead4 !important;
256
  }
257
 
258
  /* ============================================================
@@ -267,7 +391,7 @@ button.primary:hover {
267
  .message-counter p {
268
  display: inline-block !important;
269
  background: transparent !important;
270
- color: #94a3b8 !important;
271
  font-size: 0.7rem !important;
272
  font-weight: 500 !important;
273
  padding: 2px 0 !important;
@@ -280,7 +404,7 @@ button.primary:hover {
280
  }
281
 
282
  .limit-msg p {
283
- color: #64748b !important;
284
  font-size: 0.75rem !important;
285
  font-weight: 500 !important;
286
  margin: 0 !important;
@@ -293,7 +417,7 @@ button.primary:hover {
293
  }
294
 
295
  .frozen-message p {
296
- color: #0091ad !important;
297
  font-size: 0.8rem !important;
298
  font-weight: 500 !important;
299
  margin: 0 !important;
@@ -326,7 +450,7 @@ button.primary:hover {
326
 
327
  .examples-section p {
328
  font-size: 0.7rem !important;
329
- color: #94a3b8 !important;
330
  font-weight: 500 !important;
331
  margin: 0 !important;
332
  white-space: nowrap !important;
@@ -336,11 +460,11 @@ button.primary:hover {
336
  .example-btn {
337
  font-size: 0.68rem !important;
338
  font-weight: 500 !important;
339
- background: #f8fafc !important;
340
- border: 1px solid #e2e8f0 !important;
341
  border-radius: 8px !important;
342
  padding: 8px 12px !important;
343
- color: #475569 !important;
344
  transition: all 0.15s ease !important;
345
  white-space: normal !important;
346
  text-align: center !important;
@@ -355,9 +479,9 @@ button.primary:hover {
355
  }
356
 
357
  .example-btn:hover {
358
- background: #f0fdfa !important;
359
- border-color: #0091ad !important;
360
- color: #0091ad !important;
361
  }
362
 
363
  /* ============================================================
@@ -366,9 +490,9 @@ button.primary:hover {
366
  .feedback-section {
367
  margin-top: 8px !important;
368
  padding: 8px 12px !important;
369
- background: #f8fafc !important;
370
  border-radius: 8px !important;
371
- border: 1px solid #e2e8f0 !important;
372
  display: flex !important;
373
  align-items: center !important;
374
  gap: 10px !important;
@@ -377,7 +501,7 @@ button.primary:hover {
377
  .feedback-section p {
378
  font-size: 0.75rem !important;
379
  font-weight: 500 !important;
380
- color: #64748b !important;
381
  margin: 0 !important;
382
  white-space: nowrap !important;
383
  }
@@ -387,13 +511,14 @@ button.primary:hover {
387
  font-weight: 500 !important;
388
  padding: 4px 12px !important;
389
  border-radius: 5px !important;
390
- background: white !important;
391
- border: 1px solid #e2e8f0 !important;
 
392
  }
393
 
394
  .feedback-section button:hover {
395
- background: #f0fdfa !important;
396
- border-color: #0091ad !important;
397
  }
398
 
399
  .feedback-input {
@@ -403,7 +528,9 @@ button.primary:hover {
403
  .feedback-input textarea {
404
  border-radius: 6px !important;
405
  font-size: 0.8rem !important;
406
- border: 1px solid #e2e8f0 !important;
 
 
407
  }
408
 
409
  /* ============================================================
@@ -429,14 +556,14 @@ button.primary:hover {
429
  .loading-msg {
430
  text-align: center !important;
431
  padding: 12px 20px !important;
432
- background: linear-gradient(90deg, #f0fdfa 0%, #e0f7fa 25%, #f0fdfa 50%, #e0f7fa 75%, #f0fdfa 100%) !important;
433
  background-size: 200% 100% !important;
434
  animation: shimmer 2s ease-in-out infinite, fadeInOut 2s ease-in-out infinite !important;
435
  border-radius: 10px !important;
436
  }
437
 
438
  .loading-msg p {
439
- color: #0091ad !important;
440
  font-size: 0.75rem !important;
441
  font-weight: 500 !important;
442
  margin: 0 !important;
@@ -456,7 +583,7 @@ button.primary:hover {
456
  }
457
 
458
  .footer p {
459
- color: #cbd5e1 !important;
460
  font-size: 0.65rem !important;
461
  font-weight: 400 !important;
462
  margin: 0 !important;
@@ -516,11 +643,13 @@ button.primary:hover {
516
  }
517
 
518
  /* Header smaller on mobile */
519
- .header-section h1 {
 
520
  font-size: 1.3rem !important;
521
  }
522
 
523
- .header-section p {
 
524
  font-size: 0.75rem !important;
525
  }
526
 
 
3
  *
4
  * Design: Modern, minimalistic interface with teal color palette
5
  * Typography: Poppins font family
6
+ * Supports both light and dark themes automatically
 
 
 
 
 
 
 
 
7
  */
8
 
9
  /* ============================================================
 
15
  font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif !important;
16
  }
17
 
18
+ /* ============================================================
19
+ CSS VARIABLES - Light & Dark Theme Support
20
+ ============================================================ */
21
+ :root {
22
+ /* Primary teal colors */
23
+ --teal-primary: #0091ad;
24
+ --teal-hover: #007a94;
25
+ --teal-light: #e0f7fa;
26
+ --teal-soft: #f0fdfa;
27
+
28
+ /* Light theme colors */
29
+ --text-primary: #0f172a;
30
+ --text-secondary: #64748b;
31
+ --text-muted: #94a3b8;
32
+ --bg-surface: #f8fafc;
33
+ --bg-input: #f8fafc;
34
+ --border-color: #e2e8f0;
35
+ --border-light: #f1f5f9;
36
+
37
+ /* User bubble */
38
+ --user-bubble-bg: #e0f7fa;
39
+ --user-bubble-border: #b2ebf2;
40
+
41
+ /* Blockquote */
42
+ --quote-bg: #f0fdfa;
43
+
44
+ /* Example buttons */
45
+ --example-bg: #f8fafc;
46
+ --example-text: #475569;
47
+
48
+ /* Feedback */
49
+ --feedback-bg: #f8fafc;
50
+
51
+ /* New button */
52
+ --new-btn-bg: #f0fdfa;
53
+ --new-btn-text: #0d9488;
54
+ --new-btn-border: #99f6e4;
55
+ --new-btn-hover-bg: #ccfbf1;
56
+ --new-btn-hover-border: #5eead4;
57
+ }
58
+
59
+ /* Dark theme overrides */
60
+ @media (prefers-color-scheme: dark) {
61
+ :root {
62
+ --teal-primary: #22d3ee;
63
+ --teal-hover: #67e8f9;
64
+ --teal-light: #164e63;
65
+ --teal-soft: #0f3d4c;
66
+
67
+ --text-primary: #f1f5f9;
68
+ --text-secondary: #94a3b8;
69
+ --text-muted: #64748b;
70
+ --bg-surface: #1e293b;
71
+ --bg-input: #1e293b;
72
+ --border-color: #334155;
73
+ --border-light: #1e293b;
74
+
75
+ --user-bubble-bg: #164e63;
76
+ --user-bubble-border: #0e7490;
77
+
78
+ --quote-bg: #0f3d4c;
79
+
80
+ --example-bg: #1e293b;
81
+ --example-text: #cbd5e1;
82
+
83
+ --feedback-bg: #1e293b;
84
+
85
+ --new-btn-bg: #0f3d4c;
86
+ --new-btn-text: #22d3ee;
87
+ --new-btn-border: #0e7490;
88
+ --new-btn-hover-bg: #164e63;
89
+ --new-btn-hover-border: #22d3ee;
90
+ }
91
+ }
92
+
93
+ /* Gradio dark mode class support */
94
+ .dark {
95
+ --teal-primary: #22d3ee;
96
+ --teal-hover: #67e8f9;
97
+ --teal-light: #164e63;
98
+ --teal-soft: #0f3d4c;
99
+
100
+ --text-primary: #f1f5f9;
101
+ --text-secondary: #94a3b8;
102
+ --text-muted: #64748b;
103
+ --bg-surface: #1e293b;
104
+ --bg-input: #1e293b;
105
+ --border-color: #334155;
106
+ --border-light: #1e293b;
107
+
108
+ --user-bubble-bg: #164e63;
109
+ --user-bubble-border: #0e7490;
110
+
111
+ --quote-bg: #0f3d4c;
112
+
113
+ --example-bg: #1e293b;
114
+ --example-text: #cbd5e1;
115
+
116
+ --feedback-bg: #1e293b;
117
+
118
+ --new-btn-bg: #0f3d4c;
119
+ --new-btn-text: #22d3ee;
120
+ --new-btn-border: #0e7490;
121
+ --new-btn-hover-bg: #164e63;
122
+ --new-btn-hover-border: #22d3ee;
123
+ }
124
+
125
  /* ============================================================
126
  LAYOUT & CONTAINER
127
  ============================================================ */
 
162
  /* ============================================================
163
  COLOR THEME - Override Gradio orange with teal
164
  ============================================================ */
 
 
 
 
 
165
  .orange, [class*="orange"], [style*="orange"] {
166
+ background: var(--teal-primary) !important;
167
+ border-color: var(--teal-primary) !important;
168
  }
169
 
170
  [style*="rgb(249"] {
171
+ border-color: var(--teal-primary) !important;
172
  }
173
 
174
  .progress-bar, .progress-level {
175
+ background: var(--teal-primary) !important;
176
  }
177
 
178
  *:focus {
179
+ outline-color: var(--teal-primary) !important;
180
  }
181
 
182
  /* ============================================================
 
187
  text-align: center !important;
188
  }
189
 
190
+ .header-content {
191
+ text-align: center;
192
+ }
193
+
194
+ .header-section h1,
195
+ .header-content h1 {
196
  font-weight: 700 !important;
197
  font-size: 1.6rem !important;
198
  margin-bottom: 2px !important;
199
+ color: var(--teal-primary) !important;
200
  }
201
 
202
+ .header-section p,
203
+ .header-content p {
204
+ color: var(--text-secondary) !important;
205
  font-size: 0.85rem !important;
206
  margin: 0 !important;
207
  }
 
211
  ============================================================ */
212
  #chatbot {
213
  border-radius: 12px !important;
214
+ border: 1px solid var(--border-color) !important;
215
  box-shadow: 0 2px 8px rgba(0,145,173,0.06) !important;
216
  min-height: 240px !important;
217
  }
 
237
  /* User message bubbles */
238
  #chatbot .user.message,
239
  .svelte-1nr59td.user {
240
+ background: var(--user-bubble-bg) !important;
241
+ color: var(--text-primary) !important;
242
+ border: 1px solid var(--user-bubble-border) !important;
243
  }
244
 
245
  /* Links in chat */
246
  #chatbot a {
247
+ color: var(--teal-primary) !important;
248
  font-weight: 600 !important;
249
  text-decoration: underline !important;
250
  text-underline-offset: 2px !important;
251
  }
252
 
253
  #chatbot a:hover {
254
+ color: var(--teal-hover) !important;
255
  }
256
 
257
  /* Blockquotes in chat */
258
  #chatbot blockquote {
259
+ border-left: 3px solid var(--teal-primary) !important;
260
+ background: var(--quote-bg) !important;
261
  padding: 10px 14px !important;
262
  margin: 8px 0 !important;
263
  border-radius: 0 8px 8px 0 !important;
 
287
  .input-row input,
288
  .input-row textarea {
289
  border-radius: 10px !important;
290
+ border: 1px solid var(--border-color) !important;
291
  padding: 12px 16px !important;
292
  font-size: 0.85rem !important;
293
  min-height: 44px !important;
294
+ background: var(--bg-input) !important;
295
  max-width: 700px !important;
296
+ color: var(--text-primary) !important;
297
  }
298
 
299
  .input-row input:focus,
300
  .input-row textarea:focus {
301
+ border-color: var(--teal-primary) !important;
302
  box-shadow: none !important;
303
+ }
304
+
305
+ .input-row input::placeholder,
306
+ .input-row textarea::placeholder {
307
+ color: var(--text-muted) !important;
308
  }
309
 
310
  /* ============================================================
 
342
  background: linear-gradient(135deg, #007a94 0%, #0091ad 100%) !important;
343
  }
344
 
345
+ /* Dark mode primary button - brighter */
346
+ @media (prefers-color-scheme: dark) {
347
+ button.primary {
348
+ background: linear-gradient(135deg, #0891b2 0%, #22d3ee 100%) !important;
349
+ }
350
+
351
+ button.primary:hover {
352
+ background: linear-gradient(135deg, #0e7490 0%, #06b6d4 100%) !important;
353
+ }
354
+ }
355
+
356
+ .dark button.primary {
357
+ background: linear-gradient(135deg, #0891b2 0%, #22d3ee 100%) !important;
358
+ }
359
+
360
+ .dark button.primary:hover {
361
+ background: linear-gradient(135deg, #0e7490 0%, #06b6d4 100%) !important;
362
+ }
363
+
364
  /* New button */
365
  .new-btn {
366
  gap: 0 !important;
367
  }
368
 
369
  .new-btn button {
370
+ background: var(--new-btn-bg) !important;
371
+ color: var(--new-btn-text) !important;
372
+ border: 1px solid var(--new-btn-border) !important;
373
  height: 30px !important;
374
  font-size: 0.7rem !important;
375
  }
376
 
377
  .new-btn button:hover {
378
+ background: var(--new-btn-hover-bg) !important;
379
+ border-color: var(--new-btn-hover-border) !important;
380
  }
381
 
382
  /* ============================================================
 
391
  .message-counter p {
392
  display: inline-block !important;
393
  background: transparent !important;
394
+ color: var(--text-muted) !important;
395
  font-size: 0.7rem !important;
396
  font-weight: 500 !important;
397
  padding: 2px 0 !important;
 
404
  }
405
 
406
  .limit-msg p {
407
+ color: var(--text-secondary) !important;
408
  font-size: 0.75rem !important;
409
  font-weight: 500 !important;
410
  margin: 0 !important;
 
417
  }
418
 
419
  .frozen-message p {
420
+ color: var(--teal-primary) !important;
421
  font-size: 0.8rem !important;
422
  font-weight: 500 !important;
423
  margin: 0 !important;
 
450
 
451
  .examples-section p {
452
  font-size: 0.7rem !important;
453
+ color: var(--text-muted) !important;
454
  font-weight: 500 !important;
455
  margin: 0 !important;
456
  white-space: nowrap !important;
 
460
  .example-btn {
461
  font-size: 0.68rem !important;
462
  font-weight: 500 !important;
463
+ background: var(--example-bg) !important;
464
+ border: 1px solid var(--border-color) !important;
465
  border-radius: 8px !important;
466
  padding: 8px 12px !important;
467
+ color: var(--example-text) !important;
468
  transition: all 0.15s ease !important;
469
  white-space: normal !important;
470
  text-align: center !important;
 
479
  }
480
 
481
  .example-btn:hover {
482
+ background: var(--teal-soft) !important;
483
+ border-color: var(--teal-primary) !important;
484
+ color: var(--teal-primary) !important;
485
  }
486
 
487
  /* ============================================================
 
490
  .feedback-section {
491
  margin-top: 8px !important;
492
  padding: 8px 12px !important;
493
+ background: var(--feedback-bg) !important;
494
  border-radius: 8px !important;
495
+ border: 1px solid var(--border-color) !important;
496
  display: flex !important;
497
  align-items: center !important;
498
  gap: 10px !important;
 
501
  .feedback-section p {
502
  font-size: 0.75rem !important;
503
  font-weight: 500 !important;
504
+ color: var(--text-secondary) !important;
505
  margin: 0 !important;
506
  white-space: nowrap !important;
507
  }
 
511
  font-weight: 500 !important;
512
  padding: 4px 12px !important;
513
  border-radius: 5px !important;
514
+ background: var(--bg-surface) !important;
515
+ border: 1px solid var(--border-color) !important;
516
+ color: var(--text-primary) !important;
517
  }
518
 
519
  .feedback-section button:hover {
520
+ background: var(--teal-soft) !important;
521
+ border-color: var(--teal-primary) !important;
522
  }
523
 
524
  .feedback-input {
 
528
  .feedback-input textarea {
529
  border-radius: 6px !important;
530
  font-size: 0.8rem !important;
531
+ border: 1px solid var(--border-color) !important;
532
+ background: var(--bg-input) !important;
533
+ color: var(--text-primary) !important;
534
  }
535
 
536
  /* ============================================================
 
556
  .loading-msg {
557
  text-align: center !important;
558
  padding: 12px 20px !important;
559
+ background: linear-gradient(90deg, var(--teal-soft) 0%, var(--teal-light) 25%, var(--teal-soft) 50%, var(--teal-light) 75%, var(--teal-soft) 100%) !important;
560
  background-size: 200% 100% !important;
561
  animation: shimmer 2s ease-in-out infinite, fadeInOut 2s ease-in-out infinite !important;
562
  border-radius: 10px !important;
563
  }
564
 
565
  .loading-msg p {
566
+ color: var(--teal-primary) !important;
567
  font-size: 0.75rem !important;
568
  font-weight: 500 !important;
569
  margin: 0 !important;
 
583
  }
584
 
585
  .footer p {
586
+ color: var(--text-muted) !important;
587
  font-size: 0.65rem !important;
588
  font-weight: 400 !important;
589
  margin: 0 !important;
 
643
  }
644
 
645
  /* Header smaller on mobile */
646
+ .header-section h1,
647
+ .header-content h1 {
648
  font-size: 1.3rem !important;
649
  }
650
 
651
+ .header-section p,
652
+ .header-content p {
653
  font-size: 0.75rem !important;
654
  }
655