MrNK2107 commited on
Commit
700f674
Β·
1 Parent(s): 9ac0c92

feat: complete UI redesign with pastel purple/orange theme

Browse files

- Font: DM Sans (body), Space Grotesk (headings), JetBrains Mono (code)
- Pastel purple (#C4B5FD-#8B5CF6) + marigold orange (#FDE68A-#F59E0B) palette
- Depth through color shades (50-700) with consistent dark/light hierarchy
- Hover borders: cards get purple left accent + lift + shadow on hover
- Loading: animated ring spinner + floating particle dots + shimmer gradient bar
- Button click chain: loading overlay β†’ search β†’ analytics update
- All Gradio controls (inputs, tabs, buttons, sliders) themed to match
- Removed old gr.themes.Soft() β€” theme fully CSS-driven now
- Error panels, empty states, skill chips, badges all use theme variables
- Responsive layout for mobile
- Scrollbar styled to match theme

Files changed (3) hide show
  1. src/ui/app.py +10 -7
  2. src/ui/components.py +23 -17
  3. src/ui/styles.css +539 -345
src/ui/app.py CHANGED
@@ -22,6 +22,7 @@ from src.ui.components import ( # noqa: E402
22
  create_analytics_dashboard,
23
  create_candidate_card,
24
  create_empty_state,
 
25
  create_progress_html,
26
  create_rationale_panel,
27
  )
@@ -326,10 +327,19 @@ def create_app() -> gr.Blocks:
326
  *slider_inputs,
327
  ]
328
  search_btn.click(
 
 
 
 
329
  fn=search_handler,
330
  inputs=search_inputs,
331
  outputs=[results_area, rationale_area, results_state],
332
  show_progress="full",
 
 
 
 
 
333
  )
334
 
335
  re_rank_inputs = [results_state, *slider_inputs]
@@ -356,12 +366,6 @@ def create_app() -> gr.Blocks:
356
  outputs=[analytics_html],
357
  show_progress="hidden",
358
  )
359
- search_btn.click(
360
- fn=create_analytics_dashboard,
361
- inputs=[results_state],
362
- outputs=[analytics_html],
363
- show_progress="hidden",
364
- )
365
 
366
  with gr.Tab("ℹ️ About"):
367
  gr.HTML("""
@@ -420,6 +424,5 @@ if __name__ == "__main__":
420
  app.launch(
421
  server_name="127.0.0.1",
422
  server_port=7860,
423
- theme=gr.themes.Soft(),
424
  css="src/ui/styles.css",
425
  )
 
22
  create_analytics_dashboard,
23
  create_candidate_card,
24
  create_empty_state,
25
+ create_loading_overlay,
26
  create_progress_html,
27
  create_rationale_panel,
28
  )
 
327
  *slider_inputs,
328
  ]
329
  search_btn.click(
330
+ fn=lambda: create_loading_overlay("Initializing search..."),
331
+ outputs=[results_area],
332
+ show_progress="hidden",
333
+ ).then(
334
  fn=search_handler,
335
  inputs=search_inputs,
336
  outputs=[results_area, rationale_area, results_state],
337
  show_progress="full",
338
+ ).then(
339
+ fn=create_analytics_dashboard,
340
+ inputs=[results_state],
341
+ outputs=[analytics_html],
342
+ show_progress="hidden",
343
  )
344
 
345
  re_rank_inputs = [results_state, *slider_inputs]
 
366
  outputs=[analytics_html],
367
  show_progress="hidden",
368
  )
 
 
 
 
 
 
369
 
370
  with gr.Tab("ℹ️ About"):
371
  gr.HTML("""
 
424
  app.launch(
425
  server_name="127.0.0.1",
426
  server_port=7860,
 
427
  css="src/ui/styles.css",
428
  )
src/ui/components.py CHANGED
@@ -453,11 +453,6 @@ def _step_extra(i: int, current_step: int, desc: str) -> str:
453
 
454
 
455
  def create_progress_html(current_step: int = 0) -> str:
456
- """Generate animated progress bar with step labels.
457
-
458
- Args:
459
- current_step: 0 to 4, -1 means all completed (final state)
460
- """
461
  if current_step < 0:
462
  steps_html = "".join(
463
  f'<div class="progress-step completed">'
@@ -498,12 +493,23 @@ def create_progress_html(current_step: int = 0) -> str:
498
  """
499
 
500
 
501
- def create_premium_spinner(message: str = "Searching candidates...") -> str:
502
  return f"""\
503
- <div class="premium-spinner">
504
- <div class="premium-spinner-ring"></div>
505
- <div class="premium-spinner-text">{message}</div>
506
- <div class="premium-spinner-sub">This may take 10-30 seconds for deep search</div>
 
 
 
 
 
 
 
 
 
 
 
507
  </div>
508
  """
509
 
@@ -511,8 +517,8 @@ def create_premium_spinner(message: str = "Searching candidates...") -> str:
511
  def create_empty_state() -> str:
512
  return """\
513
  <div class="empty-state">
514
- <div class="empty-state-icon">πŸ”</div>
515
- <div class="empty-state-title">No search yet</div>
516
  <div class="empty-state-desc">
517
  Describe the ideal candidate on the left and click <strong>Search Candidates</strong>
518
  to find matching profiles.
@@ -527,20 +533,20 @@ def create_empty_state() -> str:
527
  def create_error_panel(message: str) -> str:
528
  """Return a prominent error message panel for display in the UI."""
529
  return f"""\
530
- <div style="border:1px solid var(--pastel-coral, #fecaca);background:rgba(254,202,202,0.15);backdrop-filter:blur(8px);border-radius:var(--radius-md);padding:20px;margin:12px 0;">
531
  <div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;">
532
  <span style="font-size:22px;">⚠️</span>
533
- <strong style="color:#e11d48;font-size:15px;">Error</strong>
534
  </div>
535
- <p style="color:#be123c;margin:0;font-size:13px;line-height:1.6;">{message}</p>
536
  </div>"""
537
 
538
 
539
  def create_empty_analytics() -> str:
540
  return """\
541
  <div class="empty-state">
542
- <div class="empty-state-icon">πŸ“Š</div>
543
- <div class="empty-state-title">No results to analyze</div>
544
  <div class="empty-state-desc">Run a search first to see analytics and fairness metrics.</div>
545
  </div>
546
  """
 
453
 
454
 
455
  def create_progress_html(current_step: int = 0) -> str:
 
 
 
 
 
456
  if current_step < 0:
457
  steps_html = "".join(
458
  f'<div class="progress-step completed">'
 
493
  """
494
 
495
 
496
+ def create_loading_overlay(message: str = "Searching candidates...") -> str:
497
  return f"""\
498
+ <div class="loading-overlay">
499
+ <div class="loading-ring-container">
500
+ <div class="loading-ring"></div>
501
+ <div class="loading-ring"></div>
502
+ <div class="loading-ring"></div>
503
+ </div>
504
+ <div class="loading-text">{message}</div>
505
+ <div class="loading-sub">This may take 10-30 seconds for deep search</div>
506
+ <div class="loading-particles">
507
+ <div class="loading-particle"></div>
508
+ <div class="loading-particle"></div>
509
+ <div class="loading-particle"></div>
510
+ <div class="loading-particle"></div>
511
+ <div class="loading-particle"></div>
512
+ </div>
513
  </div>
514
  """
515
 
 
517
  def create_empty_state() -> str:
518
  return """\
519
  <div class="empty-state">
520
+ <div class="empty-state-icon" style="animation:float 3s ease-in-out infinite;">πŸ”</div>
521
+ <div class="empty-state-title">Ready to find talent</div>
522
  <div class="empty-state-desc">
523
  Describe the ideal candidate on the left and click <strong>Search Candidates</strong>
524
  to find matching profiles.
 
533
  def create_error_panel(message: str) -> str:
534
  """Return a prominent error message panel for display in the UI."""
535
  return f"""\
536
+ <div style="border:1.5px solid var(--red-100);background:rgba(254,226,226,0.15);backdrop-filter:blur(8px);border-radius:var(--radius-md);padding:20px;margin:12px 0;">
537
  <div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;">
538
  <span style="font-size:22px;">⚠️</span>
539
+ <strong style="color:var(--red-700);font-size:15px;">Error</strong>
540
  </div>
541
+ <p style="color:var(--red-700);margin:0;font-size:13px;line-height:1.6;">{message}</p>
542
  </div>"""
543
 
544
 
545
  def create_empty_analytics() -> str:
546
  return """\
547
  <div class="empty-state">
548
+ <div class="empty-state-icon" style="animation:float 3s ease-in-out infinite;">πŸ“Š</div>
549
+ <div class="empty-state-title">No results yet</div>
550
  <div class="empty-state-desc">Run a search first to see analytics and fairness metrics.</div>
551
  </div>
552
  """
src/ui/styles.css CHANGED
@@ -1,87 +1,102 @@
1
- /* ═══════════════════════════════════════════════════════════════════════
2
- INDIA RUNS β€” Peaceful Design
3
- Warm neutrals, muted accents, borders for elevation, zero gradients.
4
- ═══════════════════════════════════════════════════════════════════════ */
5
 
6
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap');
7
-
8
- /* ── Palette ─────────────────────────────────────────────────────────── */
9
  :root {
10
- --warm-50: #faf8f4;
11
- --warm-100: #f5f0e8;
12
- --warm-200: #e8e0d4;
13
- --warm-300: #d4c9b8;
14
- --warm-400: #bfb09c;
15
- --warm-500: #a89880;
16
-
17
- --primary-100: #ede7f3;
18
- --primary-200: #d4c9e3;
19
- --primary-300: #b8a9c9;
20
- --primary-400: #9a8ab0;
21
- --primary-500: #7c6b94;
22
-
23
- --mint-100: #e8f5ef;
24
- --mint-200: #c5e0d3;
25
- --mint-300: #a8ccb8;
26
- --mint-400: #8ab89e;
27
- --mint-500: #6da384;
28
-
29
- --rose-100: #f5eaed;
30
- --rose-200: #e0cdd2;
31
- --rose-300: #ccafb6;
32
- --rose-400: #b8929a;
33
- --rose-500: #a3757e;
34
-
35
- --gold-100: #f5f0e5;
36
- --gold-200: #e0d8c2;
37
- --gold-300: #ccc09f;
38
- --gold-400: #b8a87c;
39
- --gold-500: #a39059;
40
-
41
- --accent: var(--primary-300);
42
- --accent-deep: var(--primary-400);
43
-
44
- --bg-base: var(--warm-50);
 
 
 
 
 
 
45
  --bg-card: #ffffff;
46
- --bg-hover: var(--primary-100);
 
47
 
48
- --text-primary: #3d3833;
49
- --text-secondary: #8a8480;
50
- --text-muted: #b0aaa4;
51
 
52
  --border: var(--warm-200);
53
- --border-hover: var(--warm-300);
54
- --border-accent: var(--primary-200);
 
 
 
 
 
 
55
 
56
  --radius-sm: 8px;
57
  --radius-md: 12px;
58
  --radius-lg: 16px;
59
- --radius-xl: 20px;
60
  }
61
 
62
- /* ── Global ─────────────────────────────────────────────────────────── */
63
- *, *::before, *::after {
64
- box-sizing: border-box;
65
- }
66
 
67
  body, .gradio-container, grad-container {
68
- font-family: 'Inter', system-ui, -apple-system, sans-serif !important;
69
- background: var(--bg-base) !important;
70
  color: var(--text-primary) !important;
 
71
  }
72
 
73
  .gradio-container {
74
  max-width: 1400px !important;
75
  margin: 0 auto !important;
76
- padding: 24px 32px !important;
77
  background: transparent !important;
78
  }
79
 
 
 
 
 
 
 
 
 
 
80
  /* ── App Header ─────────────────────────────────────────────────────── */
81
  .app-header {
82
  text-align: center;
83
- padding: 28px 20px 20px;
84
  position: relative;
 
85
  }
86
 
87
  .app-header::after {
@@ -90,52 +105,158 @@ body, .gradio-container, grad-container {
90
  bottom: 0;
91
  left: 50%;
92
  transform: translateX(-50%);
93
- width: 64px;
94
- height: 3px;
95
- background: var(--primary-300);
96
  border-radius: 2px;
 
 
 
 
 
 
 
97
  }
98
 
99
  .app-title {
100
- font-size: 38px;
101
  font-weight: 700;
102
- letter-spacing: -1px;
103
  color: var(--text-primary);
104
  line-height: 1.1;
105
  margin: 0;
 
 
 
 
106
  }
107
 
108
  .app-subtitle {
109
  font-size: 15px;
110
  color: var(--text-secondary);
111
  font-weight: 400;
112
- margin-top: 6px;
113
- letter-spacing: -0.1px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  }
115
 
116
  /* ── Progress / Loading ─────────────────────────────────────────────── */
117
  .progress-container {
118
  background: var(--bg-card);
119
- border: 1px solid var(--border);
120
  border-radius: var(--radius-lg);
121
  padding: 24px 28px;
122
  margin-bottom: 20px;
 
123
  }
124
 
125
  .progress-header {
126
  display: flex;
127
  justify-content: space-between;
128
  align-items: center;
129
- margin-bottom: 14px;
130
  }
131
 
132
  .progress-title {
133
- font-size: 14px;
134
  font-weight: 600;
135
  color: var(--text-primary);
136
  display: flex;
137
  align-items: center;
138
  gap: 8px;
 
139
  }
140
 
141
  .progress-step-label {
@@ -146,121 +267,253 @@ body, .gradio-container, grad-container {
146
 
147
  .progress-track {
148
  width: 100%;
149
- height: 6px;
150
- background: var(--warm-100);
151
- border-radius: 3px;
152
  overflow: hidden;
 
153
  }
154
 
155
  .progress-fill {
156
  height: 100%;
157
- background: var(--primary-300);
158
- border-radius: 3px;
159
- transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  }
161
 
162
  .progress-steps {
163
  display: flex;
164
  justify-content: space-between;
165
- margin-top: 14px;
166
  gap: 4px;
167
  }
168
 
169
  .progress-step {
170
  flex: 1;
171
  text-align: center;
172
- padding: 8px 4px;
173
  border-radius: var(--radius-sm);
174
  font-size: 11px;
175
  font-weight: 500;
176
  color: var(--text-muted);
177
- transition: all 0.3s;
 
178
  }
179
 
180
  .progress-step.active {
181
- color: var(--accent);
182
- background: var(--primary-100);
 
183
  }
184
 
185
  .progress-step.completed {
186
- color: var(--mint-400);
187
  }
188
 
189
  .progress-step .step-icon {
190
  display: block;
191
- font-size: 18px;
192
  margin-bottom: 4px;
 
193
  }
194
 
195
- /* ── Loading Spinner ─────────────────────────────────────────────────── */
196
- .premium-spinner {
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  display: flex;
198
  flex-direction: column;
199
  align-items: center;
200
  justify-content: center;
201
- padding: 60px 20px;
202
- gap: 20px;
 
 
203
  }
204
 
205
- .premium-spinner-ring {
206
- width: 40px;
207
- height: 40px;
 
 
 
 
 
 
 
 
 
 
 
208
  border-radius: 50%;
209
- border: 3px solid var(--warm-200);
210
- border-top-color: var(--primary-300);
211
- animation: spin 1s linear infinite;
 
 
 
 
212
  }
213
 
214
- @keyframes spin {
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  to { transform: rotate(360deg); }
216
  }
217
 
218
- .premium-spinner-text {
219
- font-size: 14px;
220
- color: var(--text-secondary);
221
- font-weight: 500;
 
 
222
  }
223
 
224
- .premium-spinner-sub {
225
- font-size: 12px;
 
 
 
 
 
226
  color: var(--text-muted);
227
  font-weight: 400;
228
  }
229
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  /* ── Candidate Card ──────────────────────────────────────────────────── */
231
  .candidate-card {
232
  background: var(--bg-card);
233
- border: 1px solid var(--border);
234
  border-radius: var(--radius-lg);
235
  padding: 24px;
236
  margin-bottom: 14px;
237
- transition: all 0.25s;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  }
239
 
240
  .candidate-card:hover {
241
  border-color: var(--border-hover);
242
- background: #fcfaf8;
 
 
 
 
 
 
243
  }
244
 
245
  .candidate-rank {
246
  display: inline-flex;
247
  align-items: center;
248
  justify-content: center;
249
- width: 26px;
250
- height: 26px;
251
  border-radius: 6px;
252
  font-size: 12px;
253
- font-weight: 600;
254
- color: var(--text-muted);
255
- background: var(--warm-100);
256
- margin-right: 8px;
 
 
 
 
 
 
 
257
  }
258
 
259
  .candidate-name {
260
  font-size: 18px;
261
  font-weight: 600;
262
  color: var(--text-primary);
263
- letter-spacing: -0.2px;
 
 
 
 
 
264
  }
265
 
266
  .candidate-role {
@@ -291,12 +544,16 @@ body, .gradio-container, grad-container {
291
  border-radius: var(--radius-md);
292
  font-weight: 700;
293
  text-align: center;
 
 
 
 
 
294
  }
295
 
296
  .score-badge-value {
297
  font-size: 22px;
298
  font-weight: 700;
299
- letter-spacing: -0.5px;
300
  line-height: 1;
301
  }
302
 
@@ -310,50 +567,51 @@ body, .gradio-container, grad-container {
310
  }
311
 
312
  .score-strong {
313
- background: var(--mint-100) !important;
314
- color: var(--mint-500) !important;
315
- border: 1px solid var(--mint-200) !important;
316
  }
317
 
318
  .score-good {
319
- background: var(--primary-100) !important;
320
- color: var(--primary-400) !important;
321
- border: 1px solid var(--primary-200) !important;
322
  }
323
 
324
  .score-potential {
325
- background: var(--gold-100) !important;
326
- color: var(--gold-500) !important;
327
- border: 1px solid var(--gold-200) !important;
328
  }
329
 
330
  .score-weak {
331
- background: var(--rose-100) !important;
332
- color: var(--rose-500) !important;
333
- border: 1px solid var(--rose-200) !important;
334
  }
335
 
336
  /* ── Score Bars ──────────────────────────────────────────────────────── */
337
  .score-bar-row {
338
  display: flex;
339
  align-items: center;
340
- margin: 5px 0;
341
  gap: 8px;
342
  }
343
 
344
  .score-bar-label {
345
  font-size: 11px;
346
- font-weight: 500;
347
  color: var(--text-secondary);
348
  width: 90px;
349
  text-align: right;
350
  flex-shrink: 0;
 
351
  }
352
 
353
  .score-bar-track {
354
  flex: 1;
355
  height: 6px;
356
- background: var(--warm-100);
357
  border-radius: 3px;
358
  overflow: hidden;
359
  }
@@ -362,11 +620,27 @@ body, .gradio-container, grad-container {
362
  height: 100%;
363
  border-radius: 3px;
364
  transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  }
366
 
367
  .score-bar-pct {
368
  font-size: 11px;
369
- font-weight: 500;
370
  color: var(--text-secondary);
371
  width: 36px;
372
  text-align: right;
@@ -377,29 +651,37 @@ body, .gradio-container, grad-container {
377
  /* ── Skill Chips ─────────────────────────────────────────────────────── */
378
  .skill-chip {
379
  display: inline-block;
380
- padding: 3px 10px;
381
  margin: 2px;
382
- border-radius: 6px;
383
  font-size: 11px;
384
  font-weight: 500;
385
  letter-spacing: 0.2px;
386
- transition: all 0.15s;
 
387
  }
388
 
389
  .skill-chip.matched {
390
- background: var(--mint-100);
391
- color: var(--mint-500);
392
- border: 1px solid var(--mint-200);
 
 
 
 
 
 
393
  }
394
 
395
  .skill-chip.missing {
396
- background: var(--rose-100);
397
- color: var(--rose-500);
398
- border: 1px solid var(--rose-200);
399
  }
400
 
401
- .skill-chip:hover {
402
- background: var(--warm-100);
 
403
  }
404
 
405
  /* ── Status Badges ───────────────────────────────────────────────────── */
@@ -407,320 +689,232 @@ body, .gradio-container, grad-container {
407
  display: inline-flex;
408
  align-items: center;
409
  gap: 4px;
410
- padding: 4px 12px;
411
  border-radius: 999px;
412
  font-size: 11px;
413
  font-weight: 600;
414
- letter-spacing: 0.2px;
415
- transition: all 0.15s;
 
 
 
 
 
416
  }
417
 
418
  .badge-listwise {
419
- background: var(--primary-100);
420
- color: var(--primary-400);
421
- border: 1px solid var(--primary-200);
422
  }
423
 
424
  .badge-pii {
425
- background: var(--mint-100);
426
- color: var(--mint-500);
427
- border: 1px solid var(--mint-200);
428
  }
429
 
430
  .badge-method {
431
- background: var(--primary-100);
432
- color: var(--primary-400);
433
- border: 1px solid var(--primary-200);
434
  }
435
 
436
  .badge-turbo {
437
- background: var(--gold-100);
438
- color: var(--gold-500);
439
- border: 1px solid var(--gold-200);
440
  }
441
 
442
  /* ── Metric Cards ────────────────────────────────────────────────────── */
443
  .metric-card {
444
  background: var(--bg-card);
445
- border: 1px solid var(--border);
446
  border-radius: var(--radius-md);
447
  padding: 20px;
448
  text-align: center;
449
- transition: all 0.2s;
 
450
  }
451
 
452
  .metric-card:hover {
453
- border-color: var(--border-hover);
454
- background: #fcfaf8;
 
455
  }
456
 
457
  .metric-label {
458
- font-size: 12px;
459
  font-weight: 600;
460
  text-transform: uppercase;
461
- letter-spacing: 0.5px;
462
  color: var(--text-muted);
463
- margin-bottom: 6px;
464
  }
465
 
466
  .metric-value {
467
  font-size: 30px;
468
  font-weight: 700;
469
- color: var(--primary-400);
470
  }
471
 
472
- /* ── Results Container ───────────────────────────────────────────────── */
473
- .results-container {
474
- max-height: 850px;
475
- overflow-y: auto;
476
- padding-right: 8px;
477
- scroll-behavior: smooth;
478
- }
479
-
480
- .results-container::-webkit-scrollbar { width: 5px; }
481
- .results-container::-webkit-scrollbar-track { background: transparent; }
482
- .results-container::-webkit-scrollbar-thumb { background: var(--warm-200); border-radius: 3px; }
483
- .results-container::-webkit-scrollbar-thumb:hover { background: var(--warm-300); }
484
-
485
  /* ── Empty State ─────────────────────────────────────────────────────── */
486
  .empty-state {
487
- display: flex;
488
- flex-direction: column;
489
- align-items: center;
490
- justify-content: center;
491
- padding: 60px 20px;
492
  text-align: center;
 
493
  }
494
 
495
  .empty-state-icon {
496
- font-size: 44px;
497
- margin-bottom: 14px;
498
- opacity: 0.5;
 
 
 
 
 
499
  }
500
 
501
  .empty-state-title {
502
- font-size: 18px;
 
503
  font-weight: 600;
504
  color: var(--text-primary);
505
- margin-bottom: 6px;
506
  }
507
 
508
  .empty-state-desc {
509
  font-size: 14px;
510
  color: var(--text-secondary);
511
- max-width: 400px;
512
  line-height: 1.6;
 
 
513
  }
514
 
515
  .empty-state-hint {
516
  font-size: 12px;
517
  color: var(--text-muted);
518
- margin-top: 14px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
519
  }
520
 
521
- /* ── About Tab ───────────────────────────────────────────────────────── */
522
  .about-section {
523
- background: var(--bg-card);
524
- border: 1px solid var(--border);
525
- border-radius: var(--radius-lg);
526
- padding: 32px;
527
- margin-bottom: 16px;
528
  }
529
 
530
  .about-section h2 {
531
- font-size: 22px;
 
532
  font-weight: 700;
533
- letter-spacing: -0.3px;
534
- margin: 0 0 14px;
535
  color: var(--text-primary);
 
536
  }
537
 
538
  .about-section h3 {
539
- font-size: 16px;
 
540
  font-weight: 600;
541
  color: var(--text-primary);
542
- margin: 20px 0 8px;
543
- }
544
-
545
- .about-section p {
546
- font-size: 14px;
547
- color: var(--text-secondary);
548
- line-height: 1.7;
549
- margin: 4px 0;
550
- }
551
-
552
- .about-section ul {
553
- font-size: 14px;
554
- color: var(--text-secondary);
555
- line-height: 1.8;
556
- padding-left: 20px;
557
  }
558
 
559
  .about-feature-grid {
560
  display: grid;
561
- grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
562
- gap: 12px;
563
  margin: 16px 0;
564
  }
565
 
566
  .about-feature-card {
567
- background: var(--warm-50);
568
- border: 1px solid var(--border);
569
  border-radius: var(--radius-md);
570
- padding: 16px;
571
- transition: all 0.15s;
 
 
 
 
572
  }
573
 
574
  .about-feature-card:hover {
575
- border-color: var(--border-accent);
576
- background: var(--primary-100);
 
577
  }
578
 
579
  .about-feature-card strong {
580
- display: block;
581
  font-size: 14px;
582
- color: var(--text-primary);
583
- margin-bottom: 4px;
584
  }
585
 
586
  .about-feature-card span {
587
- font-size: 12px;
588
  color: var(--text-secondary);
589
  line-height: 1.5;
590
  }
591
 
592
- /* ── Gradio Overrides ─────────────────────────────────────────────────── */
593
- button, .gr-button {
594
- border-radius: var(--radius-md) !important;
595
- font-weight: 500 !important;
596
- font-size: 14px !important;
597
- transition: all 0.15s !important;
598
- border: 1px solid var(--border) !important;
599
- }
600
-
601
- button.primary, .gr-button.primary {
602
- background: var(--primary-300) !important;
603
- color: #fff !important;
604
- border: 1px solid var(--primary-300) !important;
605
- }
606
-
607
- button.primary:hover {
608
- background: var(--primary-400) !important;
609
- border-color: var(--primary-400) !important;
610
- }
611
-
612
- button.secondary, .gr-button.secondary {
613
- background: var(--bg-card) !important;
614
- color: var(--text-primary) !important;
615
- }
616
-
617
- button.secondary:hover {
618
- background: var(--warm-100) !important;
619
- border-color: var(--border-hover) !important;
620
- }
621
-
622
- /* Tabs */
623
- .tabs, .tab-nav {
624
- border-bottom: 1px solid var(--border) !important;
625
- }
626
-
627
- .tab-nav button {
628
- background: transparent !important;
629
- border: none !important;
630
- border-bottom: 2px solid transparent !important;
631
- color: var(--text-muted) !important;
632
- font-weight: 500 !important;
633
- font-size: 14px !important;
634
- padding: 10px 16px !important;
635
- margin-bottom: -1px !important;
636
- border-radius: 0 !important;
637
- transition: all 0.15s !important;
638
- }
639
-
640
- .tab-nav button:hover {
641
- color: var(--text-primary) !important;
642
- background: var(--primary-100) !important;
643
- }
644
-
645
- .tab-nav button.selected {
646
- color: var(--primary-400) !important;
647
- border-bottom-color: var(--primary-400) !important;
648
- font-weight: 600 !important;
649
- }
650
-
651
- /* Inputs */
652
- input, textarea, .gr-input, .gr-text-input {
653
- border-radius: var(--radius-sm) !important;
654
- border: 1px solid var(--border) !important;
655
- background: var(--bg-card) !important;
656
- color: var(--text-primary) !important;
657
- font-size: 14px !important;
658
- padding: 10px 14px !important;
659
- transition: all 0.15s !important;
660
- }
661
-
662
- input:focus, textarea:focus, .gr-input:focus {
663
- border-color: var(--primary-300) !important;
664
- outline: none !important;
665
- }
666
-
667
- /* Slider */
668
- .slider, input[type="range"] {
669
- accent-color: var(--primary-300) !important;
670
- }
671
-
672
- /* Checkbox */
673
- .checkbox {
674
- accent-color: var(--primary-300) !important;
675
- }
676
-
677
- /* Accordion */
678
- .accordion {
679
- border: 1px solid var(--border) !important;
680
- border-radius: var(--radius-md) !important;
681
- overflow: hidden !important;
682
- }
683
-
684
- /* Labels */
685
- label, .gr-label {
686
- font-size: 13px !important;
687
- font-weight: 500 !important;
688
- color: var(--text-secondary) !important;
689
- margin-bottom: 4px !important;
690
- }
691
-
692
- /* Examples */
693
- .gr-examples {
694
- font-size: 12px !important;
695
- color: var(--text-muted) !important;
696
  }
697
 
698
- /* Panels */
699
- .gr-panel, .panel, .gr-box {
700
- background: transparent !important;
701
- border: none !important;
702
  }
703
 
704
- /* Rationale panel */
705
- .rationale-panel {
706
- border-left: 3px solid var(--primary-300) !important;
707
- padding: 16px !important;
708
- margin: 12px 0 !important;
709
- background: var(--warm-50) !important;
710
- border-radius: 0 var(--radius-sm) var(--radius-sm) 0 !important;
711
  }
712
 
713
- /* Hide default Gradio progress */
714
- .progress-bar, .progress-text, .meta-text, .eta-bar {
715
- display: none !important;
716
  }
717
 
718
- /* ── Responsive ──────────────────────────────────────────────────────── */
719
  @media (max-width: 768px) {
720
- .gradio-container { padding: 16px !important; }
721
- .app-title { font-size: 26px; }
722
- .app-subtitle { font-size: 13px; }
723
- .candidate-card { padding: 16px; }
724
- .progress-steps { flex-wrap: wrap; }
725
- .progress-step { flex: 1 1 30%; font-size: 10px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
726
  }
 
1
+ @import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@300;400;500;600;700;800&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
 
 
 
2
 
 
 
 
3
  :root {
4
+ --purple-50: #f5f3ff;
5
+ --purple-100: #ede9fe;
6
+ --purple-200: #ddd6fe;
7
+ --purple-300: #c4b5fd;
8
+ --purple-400: #a78bfa;
9
+ --purple-500: #8b5cf6;
10
+ --purple-600: #7c3aed;
11
+ --purple-700: #6d28d9;
12
+
13
+ --marigold-50: #fffbeb;
14
+ --marigold-100: #fef3c7;
15
+ --marigold-200: #fde68a;
16
+ --marigold-300: #fcd34d;
17
+ --marigold-400: #fbbf24;
18
+ --marigold-500: #f59e0b;
19
+
20
+ --warm-50: #fefcf7;
21
+ --warm-100: #fdf8ee;
22
+ --warm-200: #faf0dd;
23
+ --warm-300: #f5e5c4;
24
+
25
+ --slate-50: #f8fafc;
26
+ --slate-100: #f1f5f9;
27
+ --slate-200: #e2e8f0;
28
+ --slate-300: #cbd5e1;
29
+ --slate-400: #94a3b8;
30
+ --slate-500: #64748b;
31
+ --slate-600: #475569;
32
+ --slate-700: #334155;
33
+ --slate-800: #1e293b;
34
+
35
+ --green-100: #d1fae5;
36
+ --green-500: #10b981;
37
+ --green-700: #047857;
38
+ --red-100: #fee2e2;
39
+ --red-500: #ef4444;
40
+ --red-700: #b91c1c;
41
+ --blue-100: #dbeafe;
42
+ --blue-500: #3b82f6;
43
+
44
+ --bg: var(--warm-50);
45
  --bg-card: #ffffff;
46
+ --bg-hover: var(--purple-50);
47
+ --bg-input: var(--warm-100);
48
 
49
+ --text-primary: var(--slate-800);
50
+ --text-secondary: var(--slate-500);
51
+ --text-muted: var(--slate-400);
52
 
53
  --border: var(--warm-200);
54
+ --border-hover: var(--purple-200);
55
+ --border-accent: var(--purple-300);
56
+ --border-focus: var(--purple-400);
57
+
58
+ --shadow-sm: 0 1px 2px rgba(0,0,0,0.03);
59
+ --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.04), 0 2px 4px -2px rgba(0,0,0,0.03);
60
+ --shadow-lg: 0 10px 15px -3px rgba(139,92,246,0.06), 0 4px 6px -4px rgba(139,92,246,0.04);
61
+ --shadow-hover: 0 8px 30px rgba(139,92,246,0.1);
62
 
63
  --radius-sm: 8px;
64
  --radius-md: 12px;
65
  --radius-lg: 16px;
66
+ --radius-xl: 24px;
67
  }
68
 
69
+ *, *::before, *::after { box-sizing: border-box; }
 
 
 
70
 
71
  body, .gradio-container, grad-container {
72
+ font-family: 'DM Sans', system-ui, -apple-system, sans-serif !important;
73
+ background: var(--bg) !important;
74
  color: var(--text-primary) !important;
75
+ -webkit-font-smoothing: antialiased;
76
  }
77
 
78
  .gradio-container {
79
  max-width: 1400px !important;
80
  margin: 0 auto !important;
81
+ padding: 20px 32px 40px !important;
82
  background: transparent !important;
83
  }
84
 
85
+ h1, h2, h3, h4, h5, h6, .app-title, .candidate-name, .metric-value, .score-badge-value {
86
+ font-family: 'Space Grotesk', sans-serif !important;
87
+ letter-spacing: -0.02em;
88
+ }
89
+
90
+ code, pre, .mono {
91
+ font-family: 'JetBrains Mono', monospace !important;
92
+ }
93
+
94
  /* ── App Header ─────────────────────────────────────────────────────── */
95
  .app-header {
96
  text-align: center;
97
+ padding: 36px 20px 28px;
98
  position: relative;
99
+ margin-bottom: 8px;
100
  }
101
 
102
  .app-header::after {
 
105
  bottom: 0;
106
  left: 50%;
107
  transform: translateX(-50%);
108
+ width: 80px;
109
+ height: 4px;
110
+ background: linear-gradient(90deg, var(--purple-300), var(--marigold-300), var(--purple-300));
111
  border-radius: 2px;
112
+ background-size: 200% 100%;
113
+ animation: shimmer 3s ease-in-out infinite;
114
+ }
115
+
116
+ @keyframes shimmer {
117
+ 0%, 100% { background-position: 0% 50%; }
118
+ 50% { background-position: 100% 50%; }
119
  }
120
 
121
  .app-title {
122
+ font-size: 40px;
123
  font-weight: 700;
 
124
  color: var(--text-primary);
125
  line-height: 1.1;
126
  margin: 0;
127
+ background: linear-gradient(135deg, var(--purple-500), var(--purple-300), var(--marigold-400));
128
+ -webkit-background-clip: text;
129
+ -webkit-text-fill-color: transparent;
130
+ background-clip: text;
131
  }
132
 
133
  .app-subtitle {
134
  font-size: 15px;
135
  color: var(--text-secondary);
136
  font-weight: 400;
137
+ margin-top: 8px;
138
+ }
139
+
140
+ /* ── Gradio Overrides ────────────────────────────────────────────────── */
141
+ .gr-box, .gr-form, .panel, .tab-nav, .tabs, .tabitem {
142
+ border-color: var(--border) !important;
143
+ border-radius: var(--radius-md) !important;
144
+ background: transparent !important;
145
+ }
146
+
147
+ input, textarea, select, .gr-input, .gr-text-input, .gr-box input, .gr-box textarea {
148
+ background: var(--bg-input) !important;
149
+ border: 1.5px solid var(--border) !important;
150
+ border-radius: var(--radius-sm) !important;
151
+ font-family: 'DM Sans', sans-serif !important;
152
+ font-size: 14px !important;
153
+ color: var(--text-primary) !important;
154
+ transition: all 0.2s ease;
155
+ }
156
+
157
+ input:focus, textarea:focus, .gr-input:focus-within, .gr-text-input:focus-within {
158
+ border-color: var(--border-focus) !important;
159
+ box-shadow: 0 0 0 3px var(--purple-100) !important;
160
+ outline: none !important;
161
+ }
162
+
163
+ .gr-box, label, .gr-label, .block-label {
164
+ font-family: 'DM Sans', sans-serif !important;
165
+ font-size: 13px !important;
166
+ font-weight: 600 !important;
167
+ color: var(--text-secondary) !important;
168
+ letter-spacing: 0.02em;
169
+ }
170
+
171
+ .gr-button, button, .gr-btn {
172
+ font-family: 'DM Sans', sans-serif !important;
173
+ font-weight: 600 !important;
174
+ border-radius: var(--radius-sm) !important;
175
+ transition: all 0.2s ease !important;
176
+ border: 1.5px solid transparent !important;
177
+ }
178
+
179
+ .gr-button-primary, button.gr-button-lg {
180
+ background: linear-gradient(135deg, var(--purple-400), var(--purple-500)) !important;
181
+ color: white !important;
182
+ border: none !important;
183
+ box-shadow: var(--shadow-md) !important;
184
+ }
185
+
186
+ .gr-button-primary:hover {
187
+ transform: translateY(-1px) !important;
188
+ box-shadow: var(--shadow-hover) !important;
189
+ background: linear-gradient(135deg, var(--purple-500), var(--purple-600)) !important;
190
+ }
191
+
192
+ .gr-button-secondary {
193
+ background: var(--bg-card) !important;
194
+ color: var(--purple-500) !important;
195
+ border: 1.5px solid var(--purple-200) !important;
196
+ }
197
+
198
+ .gr-button-secondary:hover {
199
+ background: var(--purple-50) !important;
200
+ border-color: var(--purple-300) !important;
201
+ }
202
+
203
+ .gr-accordion {
204
+ border: 1.5px solid var(--border) !important;
205
+ border-radius: var(--radius-md) !important;
206
+ background: var(--bg-card) !important;
207
+ }
208
+
209
+ .gr-checkbox {
210
+ accent-color: var(--purple-400) !important;
211
+ }
212
+
213
+ .gr-slider input[type="range"] {
214
+ accent-color: var(--purple-400) !important;
215
+ }
216
+
217
+ .tabs, .tab-nav {
218
+ border-bottom: 1.5px solid var(--border) !important;
219
+ }
220
+
221
+ button.tab-nav {
222
+ font-family: 'DM Sans', sans-serif !important;
223
+ font-size: 14px !important;
224
+ font-weight: 500 !important;
225
+ color: var(--text-secondary) !important;
226
+ border-bottom: 2px solid transparent !important;
227
+ transition: all 0.2s;
228
+ }
229
+
230
+ button.tab-nav.selected {
231
+ color: var(--purple-500) !important;
232
+ border-bottom-color: var(--purple-400) !important;
233
  }
234
 
235
  /* ── Progress / Loading ─────────────────────────────────────────────── */
236
  .progress-container {
237
  background: var(--bg-card);
238
+ border: 1.5px solid var(--border);
239
  border-radius: var(--radius-lg);
240
  padding: 24px 28px;
241
  margin-bottom: 20px;
242
+ box-shadow: var(--shadow-sm);
243
  }
244
 
245
  .progress-header {
246
  display: flex;
247
  justify-content: space-between;
248
  align-items: center;
249
+ margin-bottom: 16px;
250
  }
251
 
252
  .progress-title {
253
+ font-size: 15px;
254
  font-weight: 600;
255
  color: var(--text-primary);
256
  display: flex;
257
  align-items: center;
258
  gap: 8px;
259
+ font-family: 'Space Grotesk', sans-serif;
260
  }
261
 
262
  .progress-step-label {
 
267
 
268
  .progress-track {
269
  width: 100%;
270
+ height: 8px;
271
+ background: var(--warm-200);
272
+ border-radius: 4px;
273
  overflow: hidden;
274
+ position: relative;
275
  }
276
 
277
  .progress-fill {
278
  height: 100%;
279
+ border-radius: 4px;
280
+ background: linear-gradient(90deg, var(--purple-300), var(--purple-400), var(--marigold-300), var(--purple-400));
281
+ background-size: 300% 100%;
282
+ animation: progressGlow 2s ease-in-out infinite;
283
+ transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
284
+ position: relative;
285
+ }
286
+
287
+ .progress-fill::after {
288
+ content: '';
289
+ position: absolute;
290
+ right: 0;
291
+ top: 0;
292
+ height: 100%;
293
+ width: 20px;
294
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4));
295
+ border-radius: 4px;
296
+ }
297
+
298
+ @keyframes progressGlow {
299
+ 0%, 100% { background-position: 0% 50%; }
300
+ 50% { background-position: 100% 50%; }
301
  }
302
 
303
  .progress-steps {
304
  display: flex;
305
  justify-content: space-between;
306
+ margin-top: 16px;
307
  gap: 4px;
308
  }
309
 
310
  .progress-step {
311
  flex: 1;
312
  text-align: center;
313
+ padding: 10px 4px;
314
  border-radius: var(--radius-sm);
315
  font-size: 11px;
316
  font-weight: 500;
317
  color: var(--text-muted);
318
+ transition: all 0.4s ease;
319
+ position: relative;
320
  }
321
 
322
  .progress-step.active {
323
+ color: var(--purple-500);
324
+ background: var(--purple-50);
325
+ transform: scale(1.02);
326
  }
327
 
328
  .progress-step.completed {
329
+ color: var(--green-500);
330
  }
331
 
332
  .progress-step .step-icon {
333
  display: block;
334
+ font-size: 20px;
335
  margin-bottom: 4px;
336
+ transition: transform 0.3s ease;
337
  }
338
 
339
+ .progress-step.active .step-icon {
340
+ animation: stepBounce 1s ease-in-out infinite;
341
+ }
342
+
343
+ @keyframes stepBounce {
344
+ 0%, 100% { transform: translateY(0); }
345
+ 50% { transform: translateY(-4px); }
346
+ }
347
+
348
+ /* ── Loading Overlay ──────────────────────────────────────────────────── */
349
+ .loading-overlay {
350
+ position: absolute;
351
+ inset: 0;
352
+ background: rgba(254,252,247,0.85);
353
+ backdrop-filter: blur(8px);
354
  display: flex;
355
  flex-direction: column;
356
  align-items: center;
357
  justify-content: center;
358
+ z-index: 100;
359
+ border-radius: var(--radius-lg);
360
+ gap: 24px;
361
+ animation: fadeIn 0.3s ease;
362
  }
363
 
364
+ @keyframes fadeIn {
365
+ from { opacity: 0; }
366
+ to { opacity: 1; }
367
+ }
368
+
369
+ .loading-ring-container {
370
+ position: relative;
371
+ width: 80px;
372
+ height: 80px;
373
+ }
374
+
375
+ .loading-ring {
376
+ position: absolute;
377
+ inset: 0;
378
  border-radius: 50%;
379
+ border: 3px solid transparent;
380
+ animation: ringSpin 1.5s cubic-bezier(0.4, 0, 0.2, 1) infinite;
381
+ }
382
+
383
+ .loading-ring:nth-child(1) {
384
+ border-top-color: var(--purple-400);
385
+ animation-delay: 0s;
386
  }
387
 
388
+ .loading-ring:nth-child(2) {
389
+ inset: 8px;
390
+ border-right-color: var(--marigold-400);
391
+ animation-delay: 0.2s;
392
+ animation-direction: reverse;
393
+ }
394
+
395
+ .loading-ring:nth-child(3) {
396
+ inset: 16px;
397
+ border-bottom-color: var(--purple-300);
398
+ animation-delay: 0.4s;
399
+ }
400
+
401
+ @keyframes ringSpin {
402
  to { transform: rotate(360deg); }
403
  }
404
 
405
+ .loading-text {
406
+ font-family: 'Space Grotesk', sans-serif;
407
+ font-size: 18px;
408
+ font-weight: 600;
409
+ color: var(--text-primary);
410
+ animation: textPulse 2s ease-in-out infinite;
411
  }
412
 
413
+ @keyframes textPulse {
414
+ 0%, 100% { opacity: 0.7; }
415
+ 50% { opacity: 1; }
416
+ }
417
+
418
+ .loading-sub {
419
+ font-size: 13px;
420
  color: var(--text-muted);
421
  font-weight: 400;
422
  }
423
 
424
+ /* ── Particle dots ────────────────────────────────────────────────────── */
425
+ .loading-particles {
426
+ display: flex;
427
+ gap: 8px;
428
+ align-items: center;
429
+ }
430
+
431
+ .loading-particle {
432
+ width: 8px;
433
+ height: 8px;
434
+ border-radius: 50%;
435
+ animation: particleFloat 1.2s ease-in-out infinite;
436
+ }
437
+
438
+ .loading-particle:nth-child(1) { background: var(--purple-400); animation-delay: 0s; }
439
+ .loading-particle:nth-child(2) { background: var(--marigold-400); animation-delay: 0.2s; }
440
+ .loading-particle:nth-child(3) { background: var(--purple-300); animation-delay: 0.4s; }
441
+ .loading-particle:nth-child(4) { background: var(--marigold-300); animation-delay: 0.6s; }
442
+ .loading-particle:nth-child(5) { background: var(--purple-400); animation-delay: 0.8s; }
443
+
444
+ @keyframes particleFloat {
445
+ 0%, 100% { transform: translateY(0) scale(1); opacity: 0.4; }
446
+ 50% { transform: translateY(-12px) scale(1.3); opacity: 1; }
447
+ }
448
+
449
  /* ── Candidate Card ──────────────────────────────────────────────────── */
450
  .candidate-card {
451
  background: var(--bg-card);
452
+ border: 1.5px solid var(--border);
453
  border-radius: var(--radius-lg);
454
  padding: 24px;
455
  margin-bottom: 14px;
456
+ box-shadow: var(--shadow-sm);
457
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
458
+ position: relative;
459
+ overflow: hidden;
460
+ }
461
+
462
+ .candidate-card::before {
463
+ content: '';
464
+ position: absolute;
465
+ top: 0;
466
+ left: 0;
467
+ width: 4px;
468
+ height: 100%;
469
+ background: var(--purple-300);
470
+ opacity: 0;
471
+ transition: opacity 0.3s ease;
472
+ border-radius: 0 4px 4px 0;
473
  }
474
 
475
  .candidate-card:hover {
476
  border-color: var(--border-hover);
477
+ box-shadow: var(--shadow-hover);
478
+ transform: translateY(-2px);
479
+ background: var(--bg-hover);
480
+ }
481
+
482
+ .candidate-card:hover::before {
483
+ opacity: 1;
484
  }
485
 
486
  .candidate-rank {
487
  display: inline-flex;
488
  align-items: center;
489
  justify-content: center;
490
+ width: 28px;
491
+ height: 28px;
492
  border-radius: 6px;
493
  font-size: 12px;
494
+ font-weight: 700;
495
+ color: var(--purple-500);
496
+ background: var(--purple-100);
497
+ margin-right: 10px;
498
+ font-family: 'Space Grotesk', sans-serif;
499
+ transition: all 0.2s;
500
+ }
501
+
502
+ .candidate-card:hover .candidate-rank {
503
+ background: var(--purple-200);
504
+ color: var(--purple-600);
505
  }
506
 
507
  .candidate-name {
508
  font-size: 18px;
509
  font-weight: 600;
510
  color: var(--text-primary);
511
+ letter-spacing: -0.3px;
512
+ transition: color 0.2s;
513
+ }
514
+
515
+ .candidate-card:hover .candidate-name {
516
+ color: var(--purple-600);
517
  }
518
 
519
  .candidate-role {
 
544
  border-radius: var(--radius-md);
545
  font-weight: 700;
546
  text-align: center;
547
+ transition: all 0.3s ease;
548
+ }
549
+
550
+ .candidate-card:hover .score-badge {
551
+ transform: scale(1.05);
552
  }
553
 
554
  .score-badge-value {
555
  font-size: 22px;
556
  font-weight: 700;
 
557
  line-height: 1;
558
  }
559
 
 
567
  }
568
 
569
  .score-strong {
570
+ background: var(--green-100) !important;
571
+ color: var(--green-700) !important;
572
+ border: 1px solid #a7f3d0 !important;
573
  }
574
 
575
  .score-good {
576
+ background: var(--purple-100) !important;
577
+ color: var(--purple-600) !important;
578
+ border: 1px solid var(--purple-200) !important;
579
  }
580
 
581
  .score-potential {
582
+ background: var(--marigold-100) !important;
583
+ color: #d97706 !important;
584
+ border: 1px solid var(--marigold-200) !important;
585
  }
586
 
587
  .score-weak {
588
+ background: var(--red-100) !important;
589
+ color: var(--red-700) !important;
590
+ border: 1px solid #fecaca !important;
591
  }
592
 
593
  /* ── Score Bars ──────────────────────────────────────────────────────── */
594
  .score-bar-row {
595
  display: flex;
596
  align-items: center;
597
+ margin: 6px 0;
598
  gap: 8px;
599
  }
600
 
601
  .score-bar-label {
602
  font-size: 11px;
603
+ font-weight: 600;
604
  color: var(--text-secondary);
605
  width: 90px;
606
  text-align: right;
607
  flex-shrink: 0;
608
+ letter-spacing: 0.02em;
609
  }
610
 
611
  .score-bar-track {
612
  flex: 1;
613
  height: 6px;
614
+ background: var(--warm-200);
615
  border-radius: 3px;
616
  overflow: hidden;
617
  }
 
620
  height: 100%;
621
  border-radius: 3px;
622
  transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
623
+ position: relative;
624
+ }
625
+
626
+ .score-bar-fill::after {
627
+ content: '';
628
+ position: absolute;
629
+ right: 0;
630
+ top: 0;
631
+ height: 100%;
632
+ width: 12px;
633
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3));
634
+ border-radius: 3px;
635
+ }
636
+
637
+ .candidate-card:hover .score-bar-fill {
638
+ filter: brightness(1.1);
639
  }
640
 
641
  .score-bar-pct {
642
  font-size: 11px;
643
+ font-weight: 600;
644
  color: var(--text-secondary);
645
  width: 36px;
646
  text-align: right;
 
651
  /* ── Skill Chips ─────────────────────────────────────────────────────── */
652
  .skill-chip {
653
  display: inline-block;
654
+ padding: 4px 12px;
655
  margin: 2px;
656
+ border-radius: 8px;
657
  font-size: 11px;
658
  font-weight: 500;
659
  letter-spacing: 0.2px;
660
+ transition: all 0.2s ease;
661
+ cursor: default;
662
  }
663
 
664
  .skill-chip.matched {
665
+ background: var(--purple-100);
666
+ color: var(--purple-600);
667
+ border: 1px solid var(--purple-200);
668
+ }
669
+
670
+ .skill-chip.matched:hover {
671
+ background: var(--purple-200);
672
+ transform: translateY(-1px);
673
+ box-shadow: 0 2px 8px rgba(139,92,246,0.15);
674
  }
675
 
676
  .skill-chip.missing {
677
+ background: var(--red-100);
678
+ color: var(--red-700);
679
+ border: 1px solid #fecaca;
680
  }
681
 
682
+ .skill-chip.missing:hover {
683
+ background: #fecaca;
684
+ transform: translateY(-1px);
685
  }
686
 
687
  /* ── Status Badges ───────────────────────────────────────────────────── */
 
689
  display: inline-flex;
690
  align-items: center;
691
  gap: 4px;
692
+ padding: 4px 14px;
693
  border-radius: 999px;
694
  font-size: 11px;
695
  font-weight: 600;
696
+ letter-spacing: 0.3px;
697
+ transition: all 0.2s ease;
698
+ cursor: default;
699
+ }
700
+
701
+ .badge:hover {
702
+ transform: translateY(-1px);
703
  }
704
 
705
  .badge-listwise {
706
+ background: var(--purple-100);
707
+ color: var(--purple-600);
708
+ border: 1px solid var(--purple-200);
709
  }
710
 
711
  .badge-pii {
712
+ background: var(--green-100);
713
+ color: var(--green-700);
714
+ border: 1px solid #a7f3d0;
715
  }
716
 
717
  .badge-method {
718
+ background: var(--marigold-100);
719
+ color: #d97706;
720
+ border: 1px solid var(--marigold-200);
721
  }
722
 
723
  .badge-turbo {
724
+ background: var(--warm-200);
725
+ color: var(--slate-600);
726
+ border: 1px solid var(--warm-300);
727
  }
728
 
729
  /* ── Metric Cards ────────────────────────────────────────────────────── */
730
  .metric-card {
731
  background: var(--bg-card);
732
+ border: 1.5px solid var(--border);
733
  border-radius: var(--radius-md);
734
  padding: 20px;
735
  text-align: center;
736
+ transition: all 0.3s ease;
737
+ box-shadow: var(--shadow-sm);
738
  }
739
 
740
  .metric-card:hover {
741
+ border-color: var(--purple-200);
742
+ box-shadow: var(--shadow-hover);
743
+ transform: translateY(-2px);
744
  }
745
 
746
  .metric-label {
747
+ font-size: 11px;
748
  font-weight: 600;
749
  text-transform: uppercase;
750
+ letter-spacing: 0.8px;
751
  color: var(--text-muted);
752
+ margin-bottom: 8px;
753
  }
754
 
755
  .metric-value {
756
  font-size: 30px;
757
  font-weight: 700;
758
+ color: var(--purple-500);
759
  }
760
 
 
 
 
 
 
 
 
 
 
 
 
 
 
761
  /* ── Empty State ─────────────────────────────────────────────────────── */
762
  .empty-state {
 
 
 
 
 
763
  text-align: center;
764
+ padding: 60px 20px;
765
  }
766
 
767
  .empty-state-icon {
768
+ font-size: 48px;
769
+ margin-bottom: 16px;
770
+ animation: float 3s ease-in-out infinite;
771
+ }
772
+
773
+ @keyframes float {
774
+ 0%, 100% { transform: translateY(0); }
775
+ 50% { transform: translateY(-8px); }
776
  }
777
 
778
  .empty-state-title {
779
+ font-family: 'Space Grotesk', sans-serif;
780
+ font-size: 22px;
781
  font-weight: 600;
782
  color: var(--text-primary);
783
+ margin-bottom: 8px;
784
  }
785
 
786
  .empty-state-desc {
787
  font-size: 14px;
788
  color: var(--text-secondary);
 
789
  line-height: 1.6;
790
+ max-width: 400px;
791
+ margin: 0 auto;
792
  }
793
 
794
  .empty-state-hint {
795
  font-size: 12px;
796
  color: var(--text-muted);
797
+ margin-top: 8px;
798
+ }
799
+
800
+ /* ── Rationale Panel ──────────────────────────────────────────────────── */
801
+ .rationale-panel {
802
+ border-left: 4px solid var(--purple-300);
803
+ }
804
+
805
+ /* ── Analytics Distribution Cards ────────────────────────────────────── */
806
+ .dist-card-strong { background: rgba(16,185,129,0.08); border: 1px solid rgba(16,185,129,0.12); }
807
+ .dist-card-good { background: rgba(139,92,246,0.08); border: 1px solid rgba(139,92,246,0.12); }
808
+ .dist-card-potential { background: rgba(245,158,11,0.08); border: 1px solid rgba(245,158,11,0.12); }
809
+ .dist-card-weak { background: rgba(239,68,68,0.08); border: 1px solid rgba(239,68,68,0.12); }
810
+
811
+ .dist-card-strong, .dist-card-good, .dist-card-potential, .dist-card-weak {
812
+ border-radius: var(--radius-md);
813
+ transition: all 0.3s ease;
814
+ }
815
+
816
+ .dist-card-strong:hover, .dist-card-good:hover, .dist-card-potential:hover, .dist-card-weak:hover {
817
+ transform: translateY(-2px);
818
+ box-shadow: var(--shadow-hover);
819
  }
820
 
821
+ /* ── About Section ────────────────────────────────────────────────────── */
822
  .about-section {
823
+ padding: 8px 0;
 
 
 
 
824
  }
825
 
826
  .about-section h2 {
827
+ font-family: 'Space Grotesk', sans-serif;
828
+ font-size: 28px;
829
  font-weight: 700;
 
 
830
  color: var(--text-primary);
831
+ margin: 0 0 8px;
832
  }
833
 
834
  .about-section h3 {
835
+ font-family: 'Space Grotesk', sans-serif;
836
+ font-size: 18px;
837
  font-weight: 600;
838
  color: var(--text-primary);
839
+ margin: 28px 0 12px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
840
  }
841
 
842
  .about-feature-grid {
843
  display: grid;
844
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
845
+ gap: 14px;
846
  margin: 16px 0;
847
  }
848
 
849
  .about-feature-card {
850
+ background: var(--bg-card);
851
+ border: 1.5px solid var(--border);
852
  border-radius: var(--radius-md);
853
+ padding: 18px;
854
+ display: flex;
855
+ flex-direction: column;
856
+ gap: 6px;
857
+ transition: all 0.3s ease;
858
+ box-shadow: var(--shadow-sm);
859
  }
860
 
861
  .about-feature-card:hover {
862
+ border-color: var(--purple-200);
863
+ box-shadow: var(--shadow-hover);
864
+ transform: translateY(-2px);
865
  }
866
 
867
  .about-feature-card strong {
 
868
  font-size: 14px;
869
+ color: var(--purple-500);
 
870
  }
871
 
872
  .about-feature-card span {
873
+ font-size: 13px;
874
  color: var(--text-secondary);
875
  line-height: 1.5;
876
  }
877
 
878
+ /* ── Scrollbar ────────────────────────────────────────────────────────── */
879
+ ::-webkit-scrollbar {
880
+ width: 6px;
881
+ height: 6px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
882
  }
883
 
884
+ ::-webkit-scrollbar-track {
885
+ background: var(--warm-100);
886
+ border-radius: 3px;
 
887
  }
888
 
889
+ ::-webkit-scrollbar-thumb {
890
+ background: var(--purple-200);
891
+ border-radius: 3px;
 
 
 
 
892
  }
893
 
894
+ ::-webkit-scrollbar-thumb:hover {
895
+ background: var(--purple-300);
 
896
  }
897
 
898
+ /* ── Responsive ────────────────────────────────────────────────────────── */
899
  @media (max-width: 768px) {
900
+ .gradio-container {
901
+ padding: 12px 16px !important;
902
+ }
903
+
904
+ .app-title {
905
+ font-size: 28px;
906
+ }
907
+
908
+ .candidate-card {
909
+ padding: 16px;
910
+ }
911
+
912
+ .progress-steps {
913
+ flex-wrap: wrap;
914
+ gap: 8px;
915
+ }
916
+
917
+ .progress-step {
918
+ flex: 0 0 calc(50% - 4px);
919
+ }
920
  }