TomLii Claude Sonnet 4.6 commited on
Commit
5312454
·
1 Parent(s): 8e8119b

Redesign Space UI to match the Quest paper microsite

Browse files

Replaces the blue-heavy Gradio theme with the Quest palette from the
OSU-NLP microsite: soft off-white page, paper-white cards with low-
opacity borders/shadows, terracotta accent, Manrope + Source Serif 4
typography. Swaps the centered-logo banner for a dark hero cover with
kicker panels, reworks section headings into the paper's kicker +
serif-display pattern, restyles icon links as pill badges, and adds a
footer block echoing the paper's site footer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +455 -402
app.py CHANGED
@@ -4,7 +4,6 @@ import re
4
  import time
5
  from dataclasses import dataclass, field
6
  from datetime import date
7
- from pathlib import Path
8
  from typing import Any, Dict, List, Optional, Set, Tuple, Union
9
 
10
  import gradio as gr
@@ -89,19 +88,15 @@ TOOL_RESPONSE_TEMPLATE = """<tool_response>
89
 
90
  SEARCH_CACHE: Dict[str, Dict[str, Any]] = {}
91
  VISIT_CACHE: Dict[str, Dict[str, Any]] = {}
92
- ASSETS_DIR = Path(__file__).resolve().parent / "assets"
93
- LOGO_PATH = str(ASSETS_DIR / "quest-logo.png")
94
- OSU_NLP_LOGO_PATH = str(ASSETS_DIR / "osu-nlp-logo.png")
95
- OSU_NLP_URL = "https://nlp.osu.edu/"
96
-
97
- # Gradio 5 default themes pull greys from the neutral palette; Base + explicit overrides keep
98
- # the whole UI on a strict blue/white scheme without unwanted slate panels.
99
  APP_THEME = gr.themes.Base(
100
- primary_hue=gr.themes.colors.blue,
101
- secondary_hue=gr.themes.colors.sky,
102
- neutral_hue=gr.themes.colors.blue,
103
  font=[
104
- gr.themes.GoogleFont("Plus Jakarta Sans"),
105
  "ui-sans-serif",
106
  "system-ui",
107
  "sans-serif",
@@ -112,69 +107,91 @@ APP_THEME = gr.themes.Base(
112
  "monospace",
113
  ],
114
  ).set(
115
- body_background_fill="#f5f9ff",
116
- body_text_color="#0f2744",
117
- body_text_color_subdued="#4a6a8c",
118
- color_accent="*primary_600",
119
- color_accent_soft="#dbeafe",
120
- background_fill_primary="#ffffff",
121
- background_fill_secondary="#f0f6ff",
122
- border_color_primary="#dbeafe",
123
- border_color_accent="*primary_500",
124
- block_background_fill="#ffffff",
125
- block_border_width="0px",
126
- block_border_color="transparent",
127
- block_shadow="0 1px 2px rgba(15,39,68,0.04), 0 10px 30px rgba(37,99,235,0.06)",
128
- block_radius="18px",
129
  block_label_background_fill="transparent",
130
  block_label_border_width="0px",
131
- block_label_text_color="#3b5b7a",
132
- block_label_text_weight="600",
133
- block_title_text_color="#0f2744",
134
  block_title_text_weight="700",
135
  block_title_border_width="0px",
136
  panel_background_fill="transparent",
137
  panel_border_width="0px",
138
  panel_border_color="transparent",
139
- input_background_fill="#ffffff",
140
- input_background_fill_focus="#ffffff",
141
- input_border_color="#bfdbfe",
142
- input_border_color_focus="*primary_500",
143
  input_border_width="1px",
144
- input_radius="14px",
145
  input_shadow="none",
146
- input_shadow_focus="0 0 0 3px rgba(59,130,246,0.18)",
147
- code_background_fill="#f0f7ff",
148
- slider_color="*primary_500",
149
- button_primary_background_fill="linear-gradient(135deg,#1d4ed8 0%,#3b82f6 100%)",
150
- button_primary_background_fill_hover="linear-gradient(135deg,#1e40af 0%,#2563eb 100%)",
151
- button_primary_text_color="#ffffff",
152
  button_primary_border_color="transparent",
153
- button_primary_shadow="0 8px 22px rgba(37,99,235,0.28)",
154
- button_secondary_background_fill="#ffffff",
155
- button_secondary_background_fill_hover="#eff6ff",
156
- button_secondary_text_color="*primary_700",
157
- button_secondary_border_color="#bfdbfe",
158
- button_cancel_background_fill="#ffffff",
159
- button_cancel_background_fill_hover="#eff6ff",
160
- button_cancel_text_color="*primary_700",
161
- button_cancel_border_color="#bfdbfe",
162
- table_border_color="#dbeafe",
163
- table_even_background_fill="#fafdff",
164
- table_odd_background_fill="#ffffff",
165
  )
166
 
167
  CUSTOM_CSS = """
168
- /* Gradio 5 uses versioned root classes (gradio-container-5-29-0). Match all of them and
169
- replace every neutral grey surface with white / soft-blue tints. */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
  html, body, gradio-app, [class*="gradio-container"] {
172
- background: #f5f9ff !important;
173
  }
174
 
175
- /* HF Space iframe wraps Gradio in <gradio-app>. Force every wrapper to stretch to
176
- the full viewport from the FIRST paint so the page doesn't visibly grow after
177
- the first answer arrives. */
178
  html, body { width: 100% !important; min-height: 100vh !important; margin: 0 !important; }
179
  gradio-app {
180
  display: block !important;
@@ -192,41 +209,30 @@ gradio-app > div {
192
  }
193
 
194
  [class*="gradio-container"] {
195
- max-width: 1480px !important;
196
  width: 100% !important;
197
  min-width: 320px !important;
198
  margin-left: auto !important;
199
  margin-right: auto !important;
200
- padding-left: 28px !important;
201
- padding-right: 28px !important;
202
- color: #0f2744;
203
  box-sizing: border-box !important;
 
204
  }
205
 
206
- /* Lock the inner two-column row so the right panel doesn't shrink before content
207
- arrives, then snap back when results appear. */
208
- [class*="gradio-container"] .layout-gap {
209
- width: 100% !important;
210
- }
211
  [class*="gradio-container"] .layout-gap > .gr-column,
212
- [class*="gradio-container"] .layout-gap > div {
213
- min-width: 0 !important;
214
- }
215
 
216
- /* Reserve vertical space for the Result/Record area so the first answer doesn't
217
- trigger a visible vertical jump either. */
218
  [class*="gradio-container"] .gradio-markdown,
219
- [class*="gradio-container"] [data-testid="markdown"] {
220
- min-height: 220px !important;
221
- }
222
  [class*="gradio-container"] .codemirror-wrapper,
223
- [class*="gradio-container"] .cm-editor {
224
- min-height: 220px !important;
225
- }
226
 
227
- /* Prevent Code / Markdown / Tabs from pushing the page wider than the container.
228
- Every wrapper in the chain is locked to max-width: 100%; only the innermost
229
- .cm-scroller scrolls horizontally. */
230
  [class*="gradio-container"] .gradio-code,
231
  [class*="gradio-container"] .gradio-markdown,
232
  [class*="gradio-container"] .prose,
@@ -243,22 +249,11 @@ gradio-app > div {
243
  }
244
  [class*="gradio-container"] .codemirror-wrapper {
245
  max-width: 100% !important;
246
- width: 100% !important;
247
- min-width: 0 !important;
248
  border-radius: 14px !important;
249
  overflow: hidden !important;
250
  }
251
- [class*="gradio-container"] .cm-editor {
252
- max-width: 100% !important;
253
- width: 100% !important;
254
- min-width: 0 !important;
255
- overflow: hidden !important;
256
- }
257
- [class*="gradio-container"] .cm-scroller {
258
- max-width: 100% !important;
259
- width: 100% !important;
260
- overflow-x: auto !important;
261
- }
262
  [class*="gradio-container"] .cm-content,
263
  [class*="gradio-container"] .cm-line {
264
  max-width: 100% !important;
@@ -272,118 +267,114 @@ gradio-app > div {
272
  white-space: pre-wrap !important;
273
  }
274
 
275
- /* Some Gradio builds wrap the app in `.main` or `.app`; center those too. */
276
- [class*="gradio-container"] .main,
277
- [class*="gradio-container"] .app,
278
- [class*="gradio-container"] .contain {
279
- margin-left: auto !important;
280
- margin-right: auto !important;
281
- }
282
-
283
- [class*="gradio-container"] *::selection { background: rgba(37,99,235,0.18); }
284
-
285
- /* --- TOP BANNER --- */
286
- .top-banner {
287
- align-items: center !important;
288
- padding: 28px 0 16px 0;
289
- margin-bottom: 8px;
290
- gap: 0 !important;
291
  }
292
- .top-banner .banner-side { min-width: 0; }
293
- .top-banner .banner-center {
294
- display: flex !important;
295
- flex-direction: column !important;
296
- align-items: center !important;
297
- gap: 10px !important;
298
- }
299
- .banner-subtitle {
300
- color: #4a6a8c;
301
- font-size: 15px;
302
- font-weight: 500;
303
- letter-spacing: 0.01em;
304
- text-align: center;
305
- margin: 0;
306
- }
307
-
308
- /* Shared logo chrome: both Quest and OSU NLP get the same rounded frame so they
309
- look like a pair. Height is fixed so their visual weight matches. */
310
- .banner-quest-logo,
311
- .banner-quest-logo .image-container,
312
- .banner-quest-logo .image-frame,
313
- .banner-quest-logo > div,
314
- .banner-quest-logo button,
315
- .osu-nlp-logo,
316
- .osu-nlp-logo .image-container,
317
- .osu-nlp-logo .image-frame,
318
- .osu-nlp-logo > div,
319
- .osu-nlp-logo button {
320
- background: transparent !important;
321
- border: none !important;
322
- box-shadow: none !important;
 
323
  }
324
- .banner-quest-logo .icon-button-wrapper,
325
- .banner-quest-logo [aria-label*="hare" i],
326
- .banner-quest-logo [aria-label*="ownload" i],
327
- .banner-quest-logo [aria-label*="ullscreen" i],
328
- .osu-nlp-logo .icon-button-wrapper,
329
- .osu-nlp-logo [aria-label*="hare" i],
330
- .osu-nlp-logo [aria-label*="ownload" i],
331
- .osu-nlp-logo [aria-label*="ullscreen" i] {
332
- display: none !important;
333
- }
334
- /* Both logos share the same fixed height so they visually line up. Width is
335
- auto so each logo keeps its natural aspect ratio. */
336
- .banner-quest-logo img,
337
- .osu-nlp-logo img {
338
- height: 140px !important;
339
- width: auto !important;
340
- max-width: 100% !important;
341
- object-fit: contain !important;
342
- background: transparent !important;
343
- border: none !important;
344
- box-shadow: none !important;
345
- border-radius: 0 !important;
346
- padding: 0 !important;
347
- margin: 0 auto !important;
348
- display: block !important;
349
  }
350
- .banner-right {
351
- display: flex !important;
352
- justify-content: flex-end !important;
353
- align-items: center !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  }
355
- .osu-nlp-logo img { margin-left: auto !important; }
356
- .osu-nlp-logo {
357
- cursor: pointer;
358
- transition: transform .15s ease;
 
 
 
 
359
  }
360
- .osu-nlp-logo:hover img { transform: translateY(-1px); }
361
-
362
- /* --- LEFT/RIGHT layout --- */
363
- .layout-gap { gap: 24px !important; align-items: flex-start; }
364
- .right-stack > * { margin-bottom: 12px; }
365
- .action-row { gap: 10px !important; margin-top: 12px; }
366
- .action-row button { min-width: 0; flex: 1; }
367
-
368
- .hero-heading {
369
- font-size: 1.1rem !important;
370
- font-weight: 700 !important;
371
- letter-spacing: 0.005em !important;
372
- text-transform: none !important;
373
- color: #0f2744 !important;
374
- margin-bottom: 14px !important;
375
  }
 
376
 
377
- /* --- SECTION CARDS --- */
378
- /* `section-card` becomes a real white rounded card with soft blue shadow, no grey. */
379
  .section-card {
380
- background: #ffffff !important;
381
- border: 1px solid rgba(191,219,254,0.55) !important;
382
- border-radius: 20px !important;
383
- box-shadow: 0 1px 2px rgba(15,39,68,0.03), 0 16px 40px rgba(37,99,235,0.07) !important;
384
- padding: 18px !important;
385
  }
386
- /* `no-frame` opts a card out of all chrome (used for logo + icon grid). */
387
  .no-frame {
388
  background: transparent !important;
389
  border: none !important;
@@ -391,78 +382,111 @@ gradio-app > div {
391
  padding: 0 !important;
392
  }
393
 
 
394
  .section-heading {
395
- font-size: 0.72rem;
396
- font-weight: 700;
397
- letter-spacing: 0.1em;
398
  text-transform: uppercase;
399
- color: #2563eb;
400
- margin: 0 0 12px 0;
401
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
 
403
- /* --- ICON GRID (Paper / Code / Dataset / Model) --- */
404
  .icon-grid {
405
  display: grid;
406
  grid-template-columns: repeat(2, minmax(0, 1fr));
407
- gap: 12px;
408
  width: 100%;
409
- margin: 0;
410
- box-sizing: border-box;
411
  }
412
  .icon-link {
413
  display: flex;
414
  align-items: center;
415
  justify-content: center;
416
  gap: 8px;
417
- padding: 14px 10px;
418
- border-radius: 16px;
419
  text-decoration: none !important;
420
- color: #1d4ed8 !important;
421
- background: #ffffff;
422
  font-weight: 600;
423
- font-size: 15px;
424
  white-space: nowrap;
425
- border: 1px solid rgba(191,219,254,0.7);
426
- box-shadow: 0 1px 2px rgba(15,39,68,0.03), 0 10px 28px rgba(37,99,235,0.07);
427
- transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
428
  }
429
  .icon-link:hover {
 
 
 
430
  transform: translateY(-1px);
431
- border-color: #93c5fd;
432
- box-shadow: 0 4px 18px rgba(37,99,235,0.14);
433
  }
434
 
435
- /* --- BUTTONS --- */
436
  [class*="gradio-container"] button.primary,
437
  [class*="gradio-container"] .gr-button-primary {
438
- background: linear-gradient(135deg,#1d4ed8 0%,#3b82f6 100%) !important;
439
  color: #ffffff !important;
440
- border: none !important;
441
- box-shadow: 0 8px 22px rgba(37,99,235,0.28) !important;
 
 
442
  }
443
  [class*="gradio-container"] button.primary:hover,
444
  [class*="gradio-container"] .gr-button-primary:hover {
445
- background: linear-gradient(135deg,#1e40af 0%,#2563eb 100%) !important;
446
- box-shadow: 0 10px 26px rgba(37,99,235,0.34) !important;
447
  }
448
  [class*="gradio-container"] button.secondary,
 
 
 
 
 
 
 
 
 
 
 
 
 
449
  [class*="gradio-container"] button.stop,
450
- [class*="gradio-container"] .gr-button-secondary,
451
  [class*="gradio-container"] .gr-button-stop {
452
- background: #ffffff !important;
453
- color: #1d4ed8 !important;
454
- border: 1px solid #bfdbfe !important;
455
- box-shadow: 0 1px 2px rgba(15,39,68,0.04) !important;
 
456
  }
457
- [class*="gradio-container"] button.secondary:hover,
458
  [class*="gradio-container"] button.stop:hover,
459
- [class*="gradio-container"] .gr-button-secondary:hover,
460
  [class*="gradio-container"] .gr-button-stop:hover {
461
- background: #eff6ff !important;
462
- border-color: #93c5fd !important;
463
  }
464
 
465
- /* --- KILL DEFAULT GREY BLOCKS / FORMS / PANELS --- */
466
  [class*="gradio-container"] .gr-group,
467
  [class*="gradio-container"] fieldset,
468
  [class*="gradio-container"] .gr-box,
@@ -472,11 +496,6 @@ gradio-app > div {
472
  [class*="gradio-container"] .container {
473
  background: transparent !important;
474
  }
475
-
476
- /* Inside our white section-cards, every nested Gradio wrapper must be FLAT
477
- (no border / shadow / background), otherwise the auto-form Gradio inserts
478
- around consecutive Dropdown+Slider components shows up as a "card inside card".
479
- We override the relevant CSS variables locally + add explicit overrides. */
480
  .section-card {
481
  --block-shadow: none;
482
  --block-shadow-dark: none;
@@ -486,17 +505,9 @@ gradio-app > div {
486
  --panel-background-fill: transparent;
487
  --panel-border-width: 0px;
488
  --background-fill-secondary: transparent;
489
- /* Gradio 5's auto-form uses `background: var(--border-color-primary)`; making
490
- that transparent inside a section-card eliminates the inner blue rectangle
491
- around Dropdown + Slider groups. Inputs use --input-border-color instead,
492
- so they keep their blue border. */
493
  --border-color-primary: transparent;
494
- /* Allow dropdown popups / overflowing content to escape the card. */
495
  overflow: visible !important;
496
  }
497
- /* Catch the auto-form and its immediate wrappers regardless of svelte hash:
498
- they are direct descendant divs of a section-card that have `display:flex`
499
- from Gradio defaults. Strip all visual chrome, but keep spacing. */
500
  .section-card > div,
501
  .section-card > div > div,
502
  .section-card > div > div > div {
@@ -521,16 +532,12 @@ gradio-app > div {
521
  box-shadow: none !important;
522
  overflow: visible !important;
523
  }
524
-
525
- /* Auto-form (consecutive form components) needs to lay its kids out vertically. */
526
  .section-card .form,
527
  .section-card .gr-form {
528
  display: flex !important;
529
  flex-direction: column !important;
530
  gap: 14px !important;
531
  }
532
-
533
- /* gr.Row must STAY horizontal even inside a section-card (Run / Stop / Clear). */
534
  [class*="gradio-container"] .section-card .row,
535
  [class*="gradio-container"] .section-card [class*="row"] {
536
  display: flex !important;
@@ -542,39 +549,35 @@ gradio-app > div {
542
  display: flex !important;
543
  flex-direction: row !important;
544
  gap: 10px !important;
545
- margin-top: 12px;
546
  }
547
  .action-row > * { flex: 1 1 0; min-width: 0; }
548
-
549
- /* Direct children of a card get vertical rhythm without extra chrome. */
550
  .section-card > * + * { margin-top: 14px; }
551
 
552
- /* --- INPUTS / TEXTAREA --- */
553
  [class*="gradio-container"] textarea,
554
  [class*="gradio-container"] input:not([type="checkbox"]):not([type="radio"]):not([type="range"]) {
555
- background: #ffffff !important;
556
- border: 1px solid #bfdbfe !important;
557
  box-shadow: none !important;
558
- border-radius: 14px !important;
559
- color: #0f2744 !important;
 
560
  }
561
  [class*="gradio-container"] textarea::placeholder,
562
- [class*="gradio-container"] input::placeholder { color: #7591b3 !important; }
563
  [class*="gradio-container"] textarea:focus,
564
  [class*="gradio-container"] input:focus {
565
- border-color: #3b82f6 !important;
566
- box-shadow: 0 0 0 3px rgba(59,130,246,0.2) !important;
567
  outline: none !important;
568
  }
569
 
570
- /* --- DROPDOWN --- */
571
- /* The visible "Model" pill is the [data-testid="dropdown"] wrap; it's the only
572
- thing that should carry the blue border. The <input> inside it must be
573
- transparent/borderless or we get "border inside border" nesting. */
574
  [class*="gradio-container"] [data-testid="dropdown"] {
575
- background: #ffffff !important;
576
- border: 1px solid #bfdbfe !important;
577
- border-radius: 14px !important;
578
  box-shadow: none !important;
579
  padding: 2px 4px !important;
580
  }
@@ -587,37 +590,37 @@ gradio-app > div {
587
  background: transparent !important;
588
  border: none !important;
589
  box-shadow: none !important;
590
- border-radius: 12px !important;
591
  }
592
  [class*="gradio-container"] .options ul,
593
  [class*="gradio-container"] .options {
594
- background: #ffffff !important;
595
- border: 1px solid #bfdbfe !important;
596
- border-radius: 12px !important;
597
- box-shadow: 0 12px 30px rgba(37,99,235,0.12) !important;
598
  }
599
  [class*="gradio-container"] .options li[aria-selected="true"],
600
  [class*="gradio-container"] .options li:hover {
601
- background: #eff6ff !important;
602
- color: #1d4ed8 !important;
603
  }
604
 
605
- /* Small "info / help" labels under inputs */
606
  [class*="gradio-container"] .info,
607
  [class*="gradio-container"] [data-testid*="info"],
608
  [class*="gradio-container"] .gr-info {
609
- color: #6b86a6 !important;
610
  background: transparent !important;
611
  font-size: 12px !important;
612
  }
613
 
614
- /* --- SLIDERS (Gradio uses native input[type=range], not noUi) --- */
615
  [class*="gradio-container"] input[type="range"] {
616
  -webkit-appearance: none;
617
  appearance: none;
618
  width: 100%;
619
  height: 6px;
620
- background: #dbeafe;
621
  border-radius: 999px;
622
  outline: none;
623
  box-shadow: none !important;
@@ -625,7 +628,7 @@ gradio-app > div {
625
  }
626
  [class*="gradio-container"] input[type="range"]::-webkit-slider-runnable-track {
627
  height: 6px;
628
- background: linear-gradient(90deg,#2563eb var(--val,50%), #dbeafe var(--val,50%));
629
  border-radius: 999px;
630
  }
631
  [class*="gradio-container"] input[type="range"]::-webkit-slider-thumb {
@@ -635,19 +638,19 @@ gradio-app > div {
635
  height: 18px;
636
  border-radius: 50%;
637
  background: #ffffff;
638
- border: 2px solid #2563eb;
639
- box-shadow: 0 2px 6px rgba(37,99,235,0.25);
640
  margin-top: -6px;
641
  cursor: pointer;
642
  }
643
  [class*="gradio-container"] input[type="range"]::-moz-range-track {
644
  height: 6px;
645
- background: #dbeafe;
646
  border-radius: 999px;
647
  }
648
  [class*="gradio-container"] input[type="range"]::-moz-range-progress {
649
  height: 6px;
650
- background: #2563eb;
651
  border-radius: 999px;
652
  }
653
  [class*="gradio-container"] input[type="range"]::-moz-range-thumb {
@@ -655,57 +658,86 @@ gradio-app > div {
655
  height: 16px;
656
  border-radius: 50%;
657
  background: #ffffff;
658
- border: 2px solid #2563eb;
659
- box-shadow: 0 2px 6px rgba(37,99,235,0.25);
660
  }
661
- /* The legacy noUi slider, kept just in case */
662
- [class*="gradio-container"] .noUi-target { background: #dbeafe !important; border: none !important; box-shadow: none !important; }
663
- [class*="gradio-container"] .noUi-connect { background: #2563eb !important; }
664
- [class*="gradio-container"] .noUi-handle { background: #ffffff !important; border: 2px solid #2563eb !important; box-shadow: 0 2px 8px rgba(37,99,235,0.2) !important; }
665
 
666
- /* --- TABS --- */
667
  [class*="gradio-container"] .tabs,
668
  [class*="gradio-container"] .tab-container,
669
- [class*="gradio-container"] .tab-wrapper {
670
- background: transparent !important;
671
- }
672
- [class*="gradio-container"] .tab-container::after {
673
- background: rgba(37,99,235,0.18) !important;
674
- }
675
  [class*="gradio-container"] .tab-wrapper button {
676
- color: #4a6a8c !important;
677
- font-weight: 600 !important;
678
- }
679
- [class*="gradio-container"] .tab-wrapper button.selected {
680
- color: #1d4ed8 !important;
681
- }
682
- [class*="gradio-container"] .tab-wrapper button.selected::after {
683
- background: #2563eb !important;
 
 
 
 
 
 
 
 
 
 
 
684
  }
685
 
686
- /* --- MARKDOWN / PROSE --- */
687
  [class*="gradio-container"] .gr-markdown,
688
  [class*="gradio-container"] .prose,
689
- [class*="gradio-container"] .markdown { color: #0f2744 !important; }
 
 
 
 
690
  [class*="gradio-container"] .gr-markdown a,
691
- [class*="gradio-container"] .prose a { color: #1d4ed8 !important; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
692
 
693
- /* --- CODE BLOCK (Trace tab) --- */
694
  [class*="gradio-container"] .codemirror-wrapper,
695
  [class*="gradio-container"] .cm-editor,
696
  [class*="gradio-container"] .cm-scroller,
697
  [class*="gradio-container"] .cm-gutters,
698
  [class*="gradio-container"] .cm-content {
699
- background: #f3f8ff !important;
700
- color: #0f2744 !important;
701
  border: none !important;
 
702
  }
703
  [class*="gradio-container"] .cm-gutters {
704
- border-right: 1px solid #dbeafe !important;
705
- color: #6b86a6 !important;
706
  }
707
 
708
- /* --- GLOBAL ROUNDED CORNERS: kill any leftover right-angle frames --- */
709
  [class*="gradio-container"] .block,
710
  [class*="gradio-container"] .form,
711
  [class*="gradio-container"] .gr-box,
@@ -716,28 +748,13 @@ gradio-app > div {
716
  [class*="gradio-container"] .tabitem,
717
  [class*="gradio-container"] .tab-content,
718
  [class*="gradio-container"] .gradio-markdown,
719
- [class*="gradio-container"] .gradio-code {
720
- border-radius: 16px !important;
721
- }
722
- [class*="gradio-container"] button {
723
- border-radius: 12px !important;
724
- }
725
 
726
- /* --- "Try Examples" preset buttons --- */
727
- .inline-example-title {
728
- font-size: 0.72rem;
729
- font-weight: 700;
730
- letter-spacing: 0.1em;
731
- text-transform: uppercase;
732
- color: #2563eb;
733
- margin: 0 0 4px 0;
734
- }
735
- .example-note { color: #4a6a8c; font-size: 12px; margin: 0 0 10px 0; }
736
  .example-buttons { display: grid; gap: 10px; margin-top: 4px; }
737
 
738
- /* Each Example button shows "<emoji> <Category> — <query text>". Left-align the
739
- label so multi-line examples read like cards, and tint the category prefix in
740
- blue via a CSS gradient (more robust across Gradio versions than inline HTML). */
741
  [class*="gradio-container"] .example-btn {
742
  text-align: left !important;
743
  justify-content: flex-start !important;
@@ -745,16 +762,19 @@ gradio-app > div {
745
  line-height: 1.5 !important;
746
  padding: 14px 16px !important;
747
  font-size: 14px !important;
748
- color: #0f2744 !important;
749
- background: linear-gradient(180deg, #ffffff 0%, #f7fbff 100%) !important;
750
- border: 1px solid #bfdbfe !important;
751
- border-radius: 14px !important;
752
- box-shadow: 0 1px 2px rgba(15,39,68,0.03) !important;
 
 
 
753
  }
754
  [class*="gradio-container"] .example-btn:hover {
755
- background: #eff6ff !important;
756
- border-color: #93c5fd !important;
757
- box-shadow: 0 4px 14px rgba(37,99,235,0.12) !important;
758
  }
759
  [class*="gradio-container"] .example-btn > * {
760
  color: inherit !important;
@@ -762,37 +782,38 @@ gradio-app > div {
762
  display: inline !important;
763
  }
764
 
765
- /* --- gr.Examples component (currently unused but defensively styled) --- */
766
- [class*="gradio-container"] [data-testid="block-examples"] {
767
- background: #f0f6ff !important;
768
- border: 1px solid #dbeafe !important;
769
- border-radius: 16px !important;
770
- padding: 12px !important;
771
- box-shadow: none !important;
772
- }
773
- [class*="gradio-container"] [data-testid="block-examples"] table,
774
- [class*="gradio-container"] [data-testid="block-examples"] thead,
775
- [class*="gradio-container"] [data-testid="block-examples"] tbody,
776
- [class*="gradio-container"] [data-testid="block-examples"] tr,
777
- [class*="gradio-container"] [data-testid="block-examples"] td {
778
- border: none !important;
779
- background: transparent !important;
780
- }
781
- [class*="gradio-container"] [data-testid="block-examples"] button {
782
- background: #ffffff !important;
783
- color: #1d4ed8 !important;
784
- border: 1px solid #bfdbfe !important;
785
- border-radius: 12px !important;
786
- box-shadow: none !important;
787
- font-size: 13px !important;
788
- }
789
- [class*="gradio-container"] [data-testid="block-examples"] button:hover {
790
- background: #eff6ff !important;
791
- border-color: #93c5fd !important;
792
  }
 
 
 
793
 
794
- /* Hide the small "footer" branding so nothing grey leaks in below the app */
795
  footer { display: none !important; }
 
 
 
 
 
 
 
 
 
 
796
  """
797
 
798
 
@@ -1587,38 +1608,55 @@ with gr.Blocks(
1587
  css=CUSTOM_CSS,
1588
  fill_width=True,
1589
  ) as demo:
1590
- # --- Top banner with the Quest logo centered and the OSU NLP mark on the right ---
1591
- with gr.Row(elem_classes="top-banner"):
1592
- with gr.Column(scale=1, elem_classes="banner-side"):
1593
- pass
1594
- with gr.Column(scale=4, elem_classes="banner-center"):
1595
- gr.Image(
1596
- value=LOGO_PATH,
1597
- show_label=False,
1598
- container=False,
1599
- interactive=False,
1600
- show_download_button=False,
1601
- show_fullscreen_button=False,
1602
- show_share_button=False,
1603
- elem_classes="banner-quest-logo",
1604
- )
1605
- with gr.Column(scale=1, elem_classes="banner-side banner-right"):
1606
- gr.Image(
1607
- value=OSU_NLP_LOGO_PATH,
1608
- show_label=False,
1609
- container=False,
1610
- interactive=False,
1611
- show_download_button=False,
1612
- show_fullscreen_button=False,
1613
- show_share_button=False,
1614
- elem_classes="osu-nlp-logo",
1615
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
1616
 
1617
  # --- Main two-column layout ---
1618
  with gr.Row(elem_classes="layout-gap"):
1619
  with gr.Column(scale=6, min_width=420):
1620
  with gr.Group(elem_classes="section-card"):
1621
- gr.HTML('<div class="section-heading hero-heading">What can I search for you?</div>')
 
 
 
 
1622
  question = gr.Textbox(
1623
  show_label=False,
1624
  placeholder="Ask anything you want to research in depth...",
@@ -1630,9 +1668,9 @@ with gr.Blocks(
1630
  clear_btn = gr.Button("Clear", variant="secondary", size="lg")
1631
 
1632
  with gr.Group(elem_classes="section-card"):
1633
- gr.HTML('<div class="section-heading">Try Examples</div>')
1634
  gr.HTML(
1635
- '<div class="example-note">Each example shows the kind of query it represents. Click one to auto-fill.</div>'
 
1636
  )
1637
  with gr.Column(elem_classes="example-buttons"):
1638
  example_buttons = [
@@ -1641,6 +1679,7 @@ with gr.Blocks(
1641
  ]
1642
 
1643
  with gr.Group(elem_classes="section-card"):
 
1644
  with gr.Tabs():
1645
  with gr.TabItem("Result"):
1646
  answer = gr.Markdown(label="Final Answer")
@@ -1648,14 +1687,16 @@ with gr.Blocks(
1648
  trace = gr.Code(label="Execution Trace (JSON)", language="json")
1649
 
1650
  with gr.Column(scale=4, min_width=340, elem_classes="right-stack"):
1651
- with gr.Group(elem_classes=["section-card", "no-frame"]):
1652
  gr.HTML(
1653
  f"""
 
 
1654
  <div class="icon-grid">
1655
- <a class="icon-link" href="{PAPER_URL}" target="_blank" rel="noopener noreferrer">📄 Paper</a>
1656
- <a class="icon-link" href="{CODE_URL}" target="_blank" rel="noopener noreferrer">💻 Code</a>
1657
- <a class="icon-link" href="{DATASET_URL}" target="_blank" rel="noopener noreferrer">🗂️ Dataset</a>
1658
- <a class="icon-link" href="{MODEL_URL}" target="_blank" rel="noopener noreferrer">🧠 Model</a>
1659
  </div>
1660
  """
1661
  )
@@ -1690,6 +1731,18 @@ with gr.Blocks(
1690
  step=0.1,
1691
  )
1692
 
 
 
 
 
 
 
 
 
 
 
 
 
1693
  run_event = run_btn.click(
1694
  fn=run_ui,
1695
  inputs=[question, model, max_turns, max_search_results, temperature],
 
4
  import time
5
  from dataclasses import dataclass, field
6
  from datetime import date
 
7
  from typing import Any, Dict, List, Optional, Set, Tuple, Union
8
 
9
  import gradio as gr
 
88
 
89
  SEARCH_CACHE: Dict[str, Dict[str, Any]] = {}
90
  VISIT_CACHE: Dict[str, Dict[str, Any]] = {}
91
+ # Quest paper palette. The Gradio shell is themed to match the OSU-NLP Quest
92
+ # microsite: soft off-white page, paper-white cards, terracotta accent, mint
93
+ # secondary, Manrope for UI type and Source Serif 4 for display headings.
 
 
 
 
94
  APP_THEME = gr.themes.Base(
95
+ primary_hue=gr.themes.colors.orange,
96
+ secondary_hue=gr.themes.colors.teal,
97
+ neutral_hue=gr.themes.colors.slate,
98
  font=[
99
+ gr.themes.GoogleFont("Manrope"),
100
  "ui-sans-serif",
101
  "system-ui",
102
  "sans-serif",
 
107
  "monospace",
108
  ],
109
  ).set(
110
+ body_background_fill="#F2F4F8",
111
+ body_text_color="#0D1117",
112
+ body_text_color_subdued="#64748B",
113
+ color_accent="#BE5B2B",
114
+ color_accent_soft="rgba(190,91,43,0.09)",
115
+ background_fill_primary="#FFFFFF",
116
+ background_fill_secondary="#EEF1F7",
117
+ border_color_primary="rgba(10,15,40,0.08)",
118
+ border_color_accent="#BE5B2B",
119
+ block_background_fill="#FFFFFF",
120
+ block_border_width="1px",
121
+ block_border_color="rgba(10,15,40,0.08)",
122
+ block_shadow="0 1px 2px rgba(10,15,40,0.05), 0 2px 10px rgba(10,15,40,0.06)",
123
+ block_radius="16px",
124
  block_label_background_fill="transparent",
125
  block_label_border_width="0px",
126
+ block_label_text_color="#64748B",
127
+ block_label_text_weight="700",
128
+ block_title_text_color="#0D1117",
129
  block_title_text_weight="700",
130
  block_title_border_width="0px",
131
  panel_background_fill="transparent",
132
  panel_border_width="0px",
133
  panel_border_color="transparent",
134
+ input_background_fill="#FFFFFF",
135
+ input_background_fill_focus="#FFFFFF",
136
+ input_border_color="rgba(10,15,40,0.12)",
137
+ input_border_color_focus="#BE5B2B",
138
  input_border_width="1px",
139
+ input_radius="12px",
140
  input_shadow="none",
141
+ input_shadow_focus="0 0 0 3px rgba(190,91,43,0.15)",
142
+ code_background_fill="#EEF1F7",
143
+ slider_color="#BE5B2B",
144
+ button_primary_background_fill="#0D1117",
145
+ button_primary_background_fill_hover="#1F2A37",
146
+ button_primary_text_color="#FFFFFF",
147
  button_primary_border_color="transparent",
148
+ button_primary_shadow="0 1px 2px rgba(10,15,40,0.08), 0 6px 18px rgba(10,15,40,0.12)",
149
+ button_secondary_background_fill="#FFFFFF",
150
+ button_secondary_background_fill_hover="rgba(190,91,43,0.09)",
151
+ button_secondary_text_color="#BE5B2B",
152
+ button_secondary_border_color="rgba(10,15,40,0.16)",
153
+ button_cancel_background_fill="#FFFFFF",
154
+ button_cancel_background_fill_hover="#FEE2E2",
155
+ button_cancel_text_color="#DC2626",
156
+ button_cancel_border_color="#FCA5A5",
157
+ table_border_color="rgba(10,15,40,0.08)",
158
+ table_even_background_fill="#FAFBFD",
159
+ table_odd_background_fill="#FFFFFF",
160
  )
161
 
162
  CUSTOM_CSS = """
163
+ /* === Quest paper palette applied to the Gradio shell ==================== */
164
+ /* Brings the OSU-NLP Quest microsite aesthetic into the live Space: soft
165
+ off-white background, paper-white cards with subtle 1px borders and
166
+ low-opacity shadows, terracotta accent, Source Serif 4 for display
167
+ headings, Manrope for everything else. */
168
+
169
+ :root {
170
+ --q-bg: #F2F4F8;
171
+ --q-paper: #FFFFFF;
172
+ --q-surface-alt: #EEF1F7;
173
+ --q-line: rgba(10, 15, 40, 0.08);
174
+ --q-line-strong: rgba(10, 15, 40, 0.16);
175
+ --q-text: #0D1117;
176
+ --q-muted: #64748B;
177
+ --q-accent: #BE5B2B;
178
+ --q-accent-soft: rgba(190, 91, 43, 0.09);
179
+ --q-accent-line: rgba(190, 91, 43, 0.55);
180
+ --q-mint: #0B9E8A;
181
+ --q-mint-deep: #0A8070;
182
+ --q-cover-bg: #0D1117;
183
+ --q-shadow: 0 1px 3px rgba(10,15,40,0.04), 0 8px 32px rgba(10,15,40,0.08);
184
+ --q-shadow-card: 0 1px 2px rgba(10,15,40,0.05), 0 2px 10px rgba(10,15,40,0.06);
185
+ --q-radius-xl: 20px;
186
+ --q-radius-lg: 16px;
187
+ --q-radius-md: 12px;
188
+ }
189
 
190
  html, body, gradio-app, [class*="gradio-container"] {
191
+ background: var(--q-bg) !important;
192
  }
193
 
194
+ /* Full-height shell ------------------------------------------------------- */
 
 
195
  html, body { width: 100% !important; min-height: 100vh !important; margin: 0 !important; }
196
  gradio-app {
197
  display: block !important;
 
209
  }
210
 
211
  [class*="gradio-container"] {
212
+ max-width: 1400px !important;
213
  width: 100% !important;
214
  min-width: 320px !important;
215
  margin-left: auto !important;
216
  margin-right: auto !important;
217
+ padding: 24px 28px 64px !important;
218
+ color: var(--q-text);
 
219
  box-sizing: border-box !important;
220
+ font-family: "Manrope", ui-sans-serif, system-ui, sans-serif;
221
  }
222
 
223
+ [class*="gradio-container"] *::selection { background: rgba(190,91,43,0.18); }
224
+
225
+ /* Prevent inner wrappers from collapsing when streaming content first arrives. */
226
+ [class*="gradio-container"] .layout-gap { width: 100% !important; }
 
227
  [class*="gradio-container"] .layout-gap > .gr-column,
228
+ [class*="gradio-container"] .layout-gap > div { min-width: 0 !important; }
 
 
229
 
 
 
230
  [class*="gradio-container"] .gradio-markdown,
231
+ [class*="gradio-container"] [data-testid="markdown"] { min-height: 220px !important; }
 
 
232
  [class*="gradio-container"] .codemirror-wrapper,
233
+ [class*="gradio-container"] .cm-editor { min-height: 220px !important; }
 
 
234
 
235
+ /* Long code / markdown cannot push the layout sideways. */
 
 
236
  [class*="gradio-container"] .gradio-code,
237
  [class*="gradio-container"] .gradio-markdown,
238
  [class*="gradio-container"] .prose,
 
249
  }
250
  [class*="gradio-container"] .codemirror-wrapper {
251
  max-width: 100% !important;
 
 
252
  border-radius: 14px !important;
253
  overflow: hidden !important;
254
  }
255
+ [class*="gradio-container"] .cm-editor { max-width: 100% !important; overflow: hidden !important; }
256
+ [class*="gradio-container"] .cm-scroller { max-width: 100% !important; overflow-x: auto !important; }
 
 
 
 
 
 
 
 
 
257
  [class*="gradio-container"] .cm-content,
258
  [class*="gradio-container"] .cm-line {
259
  max-width: 100% !important;
 
267
  white-space: pre-wrap !important;
268
  }
269
 
270
+ /* === Quest-style hero cover ============================================== */
271
+ .quest-cover {
272
+ position: relative;
273
+ border: 1px solid var(--q-line);
274
+ border-radius: var(--q-radius-xl);
275
+ background: var(--q-cover-bg);
276
+ box-shadow: var(--q-shadow);
277
+ padding: 14px;
278
+ margin: 8px 0 24px;
279
+ color: #F1F5F9;
280
+ overflow: hidden;
 
 
 
 
 
281
  }
282
+ .quest-cover-inner {
283
+ display: grid;
284
+ grid-template-columns: repeat(3, minmax(0, 1fr));
285
+ gap: 10px;
286
+ }
287
+ .quest-cover-panel {
288
+ padding: 18px 20px;
289
+ border: 1px solid rgba(255, 255, 255, 0.07);
290
+ border-radius: 14px;
291
+ background: rgba(255, 255, 255, 0.04);
292
+ min-height: 110px;
293
+ }
294
+ .quest-cover-panel.wide {
295
+ grid-column: span 3;
296
+ min-height: 220px;
297
+ display: flex;
298
+ flex-direction: column;
299
+ justify-content: space-between;
300
+ background:
301
+ radial-gradient(ellipse at top right, rgba(190, 91, 43, 0.22), transparent 48%),
302
+ radial-gradient(ellipse at bottom left, rgba(11, 158, 138, 0.18), transparent 48%),
303
+ rgba(255, 255, 255, 0.04);
304
+ }
305
+ .quest-cover-kicker {
306
+ display: flex;
307
+ align-items: center;
308
+ gap: 12px;
309
+ color: rgba(255, 255, 255, 0.55);
310
+ font-size: 0.68rem;
311
+ font-weight: 700;
312
+ letter-spacing: 0.14em;
313
+ text-transform: uppercase;
314
  }
315
+ .quest-cover-kicker .dot {
316
+ width: 8px; height: 8px; border-radius: 999px;
317
+ background: var(--q-accent);
318
+ box-shadow: 0 0 0 3px rgba(190, 91, 43, 0.22);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
  }
320
+ .quest-cover-title {
321
+ font-family: "Source Serif 4", "Source Serif Pro", ui-serif, Georgia, serif;
322
+ font-weight: 600;
323
+ font-size: clamp(1.8rem, 3.5vw, 2.8rem);
324
+ line-height: 1.05;
325
+ letter-spacing: -0.02em;
326
+ color: #FFFFFF;
327
+ margin: 14px 0 8px;
328
+ max-width: 26ch;
329
+ }
330
+ .quest-cover-subtitle {
331
+ color: rgba(255, 255, 255, 0.72);
332
+ font-size: 1rem;
333
+ line-height: 1.6;
334
+ max-width: 48ch;
335
+ }
336
+ .quest-cover-panel span.label {
337
+ display: block;
338
+ margin-bottom: 8px;
339
+ color: rgba(255, 255, 255, 0.45);
340
+ font-size: 0.66rem;
341
+ font-weight: 700;
342
+ letter-spacing: 0.14em;
343
+ text-transform: uppercase;
344
  }
345
+ .quest-cover-panel strong.headline {
346
+ display: block;
347
+ font-family: "Source Serif 4", "Source Serif Pro", ui-serif, Georgia, serif;
348
+ font-weight: 600;
349
+ font-size: 1.15rem;
350
+ line-height: 1.15;
351
+ color: #FFFFFF;
352
+ max-width: 20ch;
353
  }
354
+ .quest-cover-byline {
355
+ display: inline-flex;
356
+ align-items: center;
357
+ gap: 10px;
358
+ padding: 6px 14px;
359
+ border: 1px solid rgba(255, 255, 255, 0.16);
360
+ border-radius: 999px;
361
+ color: rgba(255, 255, 255, 0.82);
362
+ font-size: 0.78rem;
363
+ font-weight: 600;
364
+ letter-spacing: 0.04em;
365
+ text-decoration: none;
366
+ width: fit-content;
 
 
367
  }
368
+ .quest-cover-byline:hover { background: rgba(255, 255, 255, 0.08); color: #fff; }
369
 
370
+ /* === Cards (section-card) =============================================== */
 
371
  .section-card {
372
+ background: var(--q-paper) !important;
373
+ border: 1px solid var(--q-line) !important;
374
+ border-radius: var(--q-radius-xl) !important;
375
+ box-shadow: var(--q-shadow-card) !important;
376
+ padding: 22px !important;
377
  }
 
378
  .no-frame {
379
  background: transparent !important;
380
  border: none !important;
 
382
  padding: 0 !important;
383
  }
384
 
385
+ /* Section kicker + hero heading follow the paper treatment. */
386
  .section-heading {
387
+ font-size: 0.7rem;
388
+ font-weight: 800;
389
+ letter-spacing: 0.14em;
390
  text-transform: uppercase;
391
+ color: var(--q-accent);
392
+ margin: 0 0 14px 0;
393
  }
394
+ .hero-heading {
395
+ font-family: "Source Serif 4", "Source Serif Pro", ui-serif, Georgia, serif !important;
396
+ font-weight: 600 !important;
397
+ font-size: 1.6rem !important;
398
+ letter-spacing: -0.01em !important;
399
+ text-transform: none !important;
400
+ color: var(--q-text) !important;
401
+ margin: 4px 0 14px 0 !important;
402
+ }
403
+ .hero-subtitle {
404
+ color: var(--q-muted);
405
+ font-size: 0.95rem;
406
+ line-height: 1.6;
407
+ margin: -6px 0 16px 0;
408
+ }
409
+
410
+ /* Layout gap: mirror the paper's column rhythm. */
411
+ .layout-gap { gap: 24px !important; align-items: flex-start; }
412
+ .right-stack > * { margin-bottom: 14px; }
413
+ .action-row { gap: 10px !important; margin-top: 14px; }
414
+ .action-row button { min-width: 0; flex: 1; }
415
 
416
+ /* === Icon grid (Paper / Code / Dataset / Model) ========================= */
417
  .icon-grid {
418
  display: grid;
419
  grid-template-columns: repeat(2, minmax(0, 1fr));
420
+ gap: 10px;
421
  width: 100%;
 
 
422
  }
423
  .icon-link {
424
  display: flex;
425
  align-items: center;
426
  justify-content: center;
427
  gap: 8px;
428
+ padding: 11px 14px;
429
+ border-radius: 999px;
430
  text-decoration: none !important;
431
+ color: var(--q-text) !important;
432
+ background: var(--q-paper);
433
  font-weight: 600;
434
+ font-size: 0.88rem;
435
  white-space: nowrap;
436
+ border: 1px solid var(--q-line-strong);
437
+ transition: background 140ms ease, border-color 140ms ease, color 140ms ease, transform 140ms ease;
 
438
  }
439
  .icon-link:hover {
440
+ background: var(--q-accent-soft);
441
+ border-color: var(--q-accent-line);
442
+ color: var(--q-accent) !important;
443
  transform: translateY(-1px);
 
 
444
  }
445
 
446
+ /* === Buttons ============================================================ */
447
  [class*="gradio-container"] button.primary,
448
  [class*="gradio-container"] .gr-button-primary {
449
+ background: var(--q-text) !important;
450
  color: #ffffff !important;
451
+ border: 1px solid var(--q-text) !important;
452
+ box-shadow: 0 1px 2px rgba(10,15,40,0.08), 0 6px 18px rgba(10,15,40,0.12) !important;
453
+ font-weight: 700 !important;
454
+ letter-spacing: 0.01em !important;
455
  }
456
  [class*="gradio-container"] button.primary:hover,
457
  [class*="gradio-container"] .gr-button-primary:hover {
458
+ background: #1F2A37 !important;
459
+ border-color: #1F2A37 !important;
460
  }
461
  [class*="gradio-container"] button.secondary,
462
+ [class*="gradio-container"] .gr-button-secondary {
463
+ background: var(--q-paper) !important;
464
+ color: var(--q-text) !important;
465
+ border: 1px solid var(--q-line-strong) !important;
466
+ box-shadow: none !important;
467
+ font-weight: 600 !important;
468
+ }
469
+ [class*="gradio-container"] button.secondary:hover,
470
+ [class*="gradio-container"] .gr-button-secondary:hover {
471
+ background: var(--q-accent-soft) !important;
472
+ border-color: var(--q-accent-line) !important;
473
+ color: var(--q-accent) !important;
474
+ }
475
  [class*="gradio-container"] button.stop,
 
476
  [class*="gradio-container"] .gr-button-stop {
477
+ background: var(--q-paper) !important;
478
+ color: #DC2626 !important;
479
+ border: 1px solid #FCA5A5 !important;
480
+ box-shadow: none !important;
481
+ font-weight: 600 !important;
482
  }
 
483
  [class*="gradio-container"] button.stop:hover,
 
484
  [class*="gradio-container"] .gr-button-stop:hover {
485
+ background: #FEE2E2 !important;
486
+ color: #B91C1C !important;
487
  }
488
 
489
+ /* Flatten every grey block Gradio drops inside our cards. */
490
  [class*="gradio-container"] .gr-group,
491
  [class*="gradio-container"] fieldset,
492
  [class*="gradio-container"] .gr-box,
 
496
  [class*="gradio-container"] .container {
497
  background: transparent !important;
498
  }
 
 
 
 
 
499
  .section-card {
500
  --block-shadow: none;
501
  --block-shadow-dark: none;
 
505
  --panel-background-fill: transparent;
506
  --panel-border-width: 0px;
507
  --background-fill-secondary: transparent;
 
 
 
 
508
  --border-color-primary: transparent;
 
509
  overflow: visible !important;
510
  }
 
 
 
511
  .section-card > div,
512
  .section-card > div > div,
513
  .section-card > div > div > div {
 
532
  box-shadow: none !important;
533
  overflow: visible !important;
534
  }
 
 
535
  .section-card .form,
536
  .section-card .gr-form {
537
  display: flex !important;
538
  flex-direction: column !important;
539
  gap: 14px !important;
540
  }
 
 
541
  [class*="gradio-container"] .section-card .row,
542
  [class*="gradio-container"] .section-card [class*="row"] {
543
  display: flex !important;
 
549
  display: flex !important;
550
  flex-direction: row !important;
551
  gap: 10px !important;
552
+ margin-top: 14px;
553
  }
554
  .action-row > * { flex: 1 1 0; min-width: 0; }
 
 
555
  .section-card > * + * { margin-top: 14px; }
556
 
557
+ /* === Inputs ============================================================= */
558
  [class*="gradio-container"] textarea,
559
  [class*="gradio-container"] input:not([type="checkbox"]):not([type="radio"]):not([type="range"]) {
560
+ background: var(--q-paper) !important;
561
+ border: 1px solid var(--q-line-strong) !important;
562
  box-shadow: none !important;
563
+ border-radius: var(--q-radius-md) !important;
564
+ color: var(--q-text) !important;
565
+ font-family: "Manrope", ui-sans-serif, system-ui, sans-serif !important;
566
  }
567
  [class*="gradio-container"] textarea::placeholder,
568
+ [class*="gradio-container"] input::placeholder { color: #94A3B8 !important; }
569
  [class*="gradio-container"] textarea:focus,
570
  [class*="gradio-container"] input:focus {
571
+ border-color: var(--q-accent) !important;
572
+ box-shadow: 0 0 0 3px rgba(190,91,43,0.15) !important;
573
  outline: none !important;
574
  }
575
 
576
+ /* === Dropdown =========================================================== */
 
 
 
577
  [class*="gradio-container"] [data-testid="dropdown"] {
578
+ background: var(--q-paper) !important;
579
+ border: 1px solid var(--q-line-strong) !important;
580
+ border-radius: var(--q-radius-md) !important;
581
  box-shadow: none !important;
582
  padding: 2px 4px !important;
583
  }
 
590
  background: transparent !important;
591
  border: none !important;
592
  box-shadow: none !important;
593
+ border-radius: 10px !important;
594
  }
595
  [class*="gradio-container"] .options ul,
596
  [class*="gradio-container"] .options {
597
+ background: var(--q-paper) !important;
598
+ border: 1px solid var(--q-line) !important;
599
+ border-radius: var(--q-radius-md) !important;
600
+ box-shadow: 0 10px 30px rgba(10,15,40,0.12) !important;
601
  }
602
  [class*="gradio-container"] .options li[aria-selected="true"],
603
  [class*="gradio-container"] .options li:hover {
604
+ background: var(--q-accent-soft) !important;
605
+ color: var(--q-accent) !important;
606
  }
607
 
608
+ /* Info hint text under inputs */
609
  [class*="gradio-container"] .info,
610
  [class*="gradio-container"] [data-testid*="info"],
611
  [class*="gradio-container"] .gr-info {
612
+ color: var(--q-muted) !important;
613
  background: transparent !important;
614
  font-size: 12px !important;
615
  }
616
 
617
+ /* === Sliders ============================================================ */
618
  [class*="gradio-container"] input[type="range"] {
619
  -webkit-appearance: none;
620
  appearance: none;
621
  width: 100%;
622
  height: 6px;
623
+ background: var(--q-surface-alt);
624
  border-radius: 999px;
625
  outline: none;
626
  box-shadow: none !important;
 
628
  }
629
  [class*="gradio-container"] input[type="range"]::-webkit-slider-runnable-track {
630
  height: 6px;
631
+ background: linear-gradient(90deg,var(--q-accent) var(--val,50%), var(--q-surface-alt) var(--val,50%));
632
  border-radius: 999px;
633
  }
634
  [class*="gradio-container"] input[type="range"]::-webkit-slider-thumb {
 
638
  height: 18px;
639
  border-radius: 50%;
640
  background: #ffffff;
641
+ border: 2px solid var(--q-accent);
642
+ box-shadow: 0 2px 6px rgba(190,91,43,0.25);
643
  margin-top: -6px;
644
  cursor: pointer;
645
  }
646
  [class*="gradio-container"] input[type="range"]::-moz-range-track {
647
  height: 6px;
648
+ background: var(--q-surface-alt);
649
  border-radius: 999px;
650
  }
651
  [class*="gradio-container"] input[type="range"]::-moz-range-progress {
652
  height: 6px;
653
+ background: var(--q-accent);
654
  border-radius: 999px;
655
  }
656
  [class*="gradio-container"] input[type="range"]::-moz-range-thumb {
 
658
  height: 16px;
659
  border-radius: 50%;
660
  background: #ffffff;
661
+ border: 2px solid var(--q-accent);
662
+ box-shadow: 0 2px 6px rgba(190,91,43,0.25);
663
  }
 
 
 
 
664
 
665
+ /* === Tabs =============================================================== */
666
  [class*="gradio-container"] .tabs,
667
  [class*="gradio-container"] .tab-container,
668
+ [class*="gradio-container"] .tab-wrapper { background: transparent !important; }
669
+ [class*="gradio-container"] .tab-container::after { background: var(--q-line) !important; }
 
 
 
 
670
  [class*="gradio-container"] .tab-wrapper button {
671
+ color: var(--q-muted) !important;
672
+ font-weight: 700 !important;
673
+ letter-spacing: 0.04em !important;
674
+ text-transform: uppercase !important;
675
+ font-size: 0.78rem !important;
676
+ }
677
+ [class*="gradio-container"] .tab-wrapper button.selected { color: var(--q-accent) !important; }
678
+ [class*="gradio-container"] .tab-wrapper button.selected::after { background: var(--q-accent) !important; }
679
+
680
+ /* Block labels above components */
681
+ [class*="gradio-container"] .gr-block label,
682
+ [class*="gradio-container"] .gradio-slider label,
683
+ [class*="gradio-container"] .gradio-dropdown label,
684
+ [class*="gradio-container"] .gradio-textbox label {
685
+ color: var(--q-muted) !important;
686
+ font-weight: 700 !important;
687
+ font-size: 0.74rem !important;
688
+ letter-spacing: 0.08em !important;
689
+ text-transform: uppercase !important;
690
  }
691
 
692
+ /* === Markdown / prose =================================================== */
693
  [class*="gradio-container"] .gr-markdown,
694
  [class*="gradio-container"] .prose,
695
+ [class*="gradio-container"] .markdown {
696
+ color: var(--q-text) !important;
697
+ font-family: "Manrope", ui-sans-serif, system-ui, sans-serif !important;
698
+ line-height: 1.75;
699
+ }
700
  [class*="gradio-container"] .gr-markdown a,
701
+ [class*="gradio-container"] .prose a { color: var(--q-accent) !important; text-decoration: underline; text-decoration-color: rgba(190,91,43,0.35); }
702
+ [class*="gradio-container"] .gr-markdown a:hover,
703
+ [class*="gradio-container"] .prose a:hover { text-decoration-color: var(--q-accent); }
704
+ [class*="gradio-container"] .gr-markdown h1,
705
+ [class*="gradio-container"] .gr-markdown h2,
706
+ [class*="gradio-container"] .gr-markdown h3,
707
+ [class*="gradio-container"] .prose h1,
708
+ [class*="gradio-container"] .prose h2,
709
+ [class*="gradio-container"] .prose h3 {
710
+ font-family: "Source Serif 4", "Source Serif Pro", ui-serif, Georgia, serif !important;
711
+ font-weight: 600 !important;
712
+ letter-spacing: -0.01em !important;
713
+ color: var(--q-text) !important;
714
+ }
715
+ [class*="gradio-container"] .gr-markdown code,
716
+ [class*="gradio-container"] .prose code {
717
+ background: var(--q-surface-alt);
718
+ border: 1px solid var(--q-line);
719
+ padding: 1px 6px;
720
+ border-radius: 6px;
721
+ font-size: 0.9em;
722
+ }
723
 
724
+ /* === Code block (Record tab) ============================================ */
725
  [class*="gradio-container"] .codemirror-wrapper,
726
  [class*="gradio-container"] .cm-editor,
727
  [class*="gradio-container"] .cm-scroller,
728
  [class*="gradio-container"] .cm-gutters,
729
  [class*="gradio-container"] .cm-content {
730
+ background: var(--q-surface-alt) !important;
731
+ color: var(--q-text) !important;
732
  border: none !important;
733
+ font-family: "JetBrains Mono", ui-monospace, monospace !important;
734
  }
735
  [class*="gradio-container"] .cm-gutters {
736
+ border-right: 1px solid var(--q-line) !important;
737
+ color: var(--q-muted) !important;
738
  }
739
 
740
+ /* === Rounded corners on everything ====================================== */
741
  [class*="gradio-container"] .block,
742
  [class*="gradio-container"] .form,
743
  [class*="gradio-container"] .gr-box,
 
748
  [class*="gradio-container"] .tabitem,
749
  [class*="gradio-container"] .tab-content,
750
  [class*="gradio-container"] .gradio-markdown,
751
+ [class*="gradio-container"] .gradio-code { border-radius: var(--q-radius-md) !important; }
752
+ [class*="gradio-container"] button { border-radius: 999px !important; }
 
 
 
 
753
 
754
+ /* === Example buttons ==================================================== */
755
+ .example-note { color: var(--q-muted); font-size: 13px; margin: 0 0 12px 0; line-height: 1.5; }
 
 
 
 
 
 
 
 
756
  .example-buttons { display: grid; gap: 10px; margin-top: 4px; }
757
 
 
 
 
758
  [class*="gradio-container"] .example-btn {
759
  text-align: left !important;
760
  justify-content: flex-start !important;
 
762
  line-height: 1.5 !important;
763
  padding: 14px 16px !important;
764
  font-size: 14px !important;
765
+ color: var(--q-text) !important;
766
+ background: var(--q-paper) !important;
767
+ border: 1px solid var(--q-line) !important;
768
+ border-radius: var(--q-radius-md) !important;
769
+ box-shadow: none !important;
770
+ font-weight: 500 !important;
771
+ letter-spacing: normal !important;
772
+ text-transform: none !important;
773
  }
774
  [class*="gradio-container"] .example-btn:hover {
775
+ background: var(--q-accent-soft) !important;
776
+ border-color: var(--q-accent-line) !important;
777
+ color: var(--q-accent) !important;
778
  }
779
  [class*="gradio-container"] .example-btn > * {
780
  color: inherit !important;
 
782
  display: inline !important;
783
  }
784
 
785
+ /* Footer tagline block */
786
+ .quest-footer {
787
+ margin-top: 28px;
788
+ padding: 18px 24px;
789
+ border: 1px solid var(--q-line);
790
+ border-radius: var(--q-radius-xl);
791
+ background: var(--q-paper);
792
+ box-shadow: var(--q-shadow-card);
793
+ display: flex;
794
+ align-items: center;
795
+ justify-content: space-between;
796
+ gap: 20px;
797
+ color: var(--q-muted);
798
+ font-size: 0.86rem;
799
+ line-height: 1.65;
 
 
 
 
 
 
 
 
 
 
 
 
800
  }
801
+ .quest-footer a { color: var(--q-muted); text-decoration: none; }
802
+ .quest-footer a:hover { color: var(--q-text); }
803
+ .quest-footer-links { display: flex; gap: 16px; flex-wrap: wrap; }
804
 
805
+ /* Tiny mark that replaces the HF watermark block. */
806
  footer { display: none !important; }
807
+
808
+ /* === Responsive ========================================================= */
809
+ @media (max-width: 1100px) {
810
+ .quest-cover-inner { grid-template-columns: 1fr; }
811
+ .quest-cover-panel.wide { grid-column: auto; min-height: 180px; }
812
+ }
813
+ @media (max-width: 760px) {
814
+ [class*="gradio-container"] { padding: 16px !important; }
815
+ .quest-footer { flex-direction: column; align-items: flex-start; }
816
+ }
817
  """
818
 
819
 
 
1608
  css=CUSTOM_CSS,
1609
  fill_width=True,
1610
  ) as demo:
1611
+ # --- Quest-style hero cover (mirrors the Quest paper microsite cover) ---
1612
+ gr.HTML(
1613
+ """
1614
+ <section class="quest-cover" aria-label="Quest hero">
1615
+ <div class="quest-cover-inner">
1616
+ <div class="quest-cover-panel wide">
1617
+ <div class="quest-cover-kicker">
1618
+ <span class="dot" aria-hidden="true"></span>
1619
+ <span>Quest &nbsp;·&nbsp; OSU NLP Group</span>
1620
+ </div>
1621
+ <div>
1622
+ <h1 class="quest-cover-title">Deep Research Agent, live in your browser.</h1>
1623
+ <p class="quest-cover-subtitle">
1624
+ A fully open recipe for training deep research agents &mdash; now
1625
+ hosted as an interactive Space. Ask a question, watch the agent
1626
+ search, read, and reason across sources, then return a grounded
1627
+ answer.
1628
+ </p>
1629
+ </div>
1630
+ <a class="quest-cover-byline" href="https://nlp.osu.edu/" target="_blank" rel="noopener noreferrer">
1631
+ <span>Built by OSU NLP &rarr;</span>
1632
+ </a>
1633
+ </div>
1634
+ <div class="quest-cover-panel">
1635
+ <span class="label">Data synthesis</span>
1636
+ <strong class="headline">Objective and open-ended tasks</strong>
1637
+ </div>
1638
+ <div class="quest-cover-panel">
1639
+ <span class="label">Memory management</span>
1640
+ <strong class="headline">Structured long-horizon reasoning</strong>
1641
+ </div>
1642
+ <div class="quest-cover-panel">
1643
+ <span class="label">Training recipe</span>
1644
+ <strong class="headline">Mid-training, SFT, and RL</strong>
1645
+ </div>
1646
+ </div>
1647
+ </section>
1648
+ """
1649
+ )
1650
 
1651
  # --- Main two-column layout ---
1652
  with gr.Row(elem_classes="layout-gap"):
1653
  with gr.Column(scale=6, min_width=420):
1654
  with gr.Group(elem_classes="section-card"):
1655
+ gr.HTML(
1656
+ '<div class="section-heading">Ask the agent</div>'
1657
+ '<div class="hero-heading">What can I research for you?</div>'
1658
+ '<p class="hero-subtitle">Describe a question, claim, or open-ended prompt. The agent will search the web, visit sources, and synthesize a grounded answer.</p>'
1659
+ )
1660
  question = gr.Textbox(
1661
  show_label=False,
1662
  placeholder="Ask anything you want to research in depth...",
 
1668
  clear_btn = gr.Button("Clear", variant="secondary", size="lg")
1669
 
1670
  with gr.Group(elem_classes="section-card"):
 
1671
  gr.HTML(
1672
+ '<div class="section-heading">Section 02 · Try examples</div>'
1673
+ '<div class="example-note">Each prompt shows the kind of query it represents. Click one to auto-fill.</div>'
1674
  )
1675
  with gr.Column(elem_classes="example-buttons"):
1676
  example_buttons = [
 
1679
  ]
1680
 
1681
  with gr.Group(elem_classes="section-card"):
1682
+ gr.HTML('<div class="section-heading">Section 03 · Output</div>')
1683
  with gr.Tabs():
1684
  with gr.TabItem("Result"):
1685
  answer = gr.Markdown(label="Final Answer")
 
1687
  trace = gr.Code(label="Execution Trace (JSON)", language="json")
1688
 
1689
  with gr.Column(scale=4, min_width=340, elem_classes="right-stack"):
1690
+ with gr.Group(elem_classes="section-card"):
1691
  gr.HTML(
1692
  f"""
1693
+ <div class="section-heading">Open release</div>
1694
+ <div class="hero-heading" style="font-size:1.2rem;margin-bottom:12px;">Data, code, and weights &mdash; all public.</div>
1695
  <div class="icon-grid">
1696
+ <a class="icon-link" href="{PAPER_URL}" target="_blank" rel="noopener noreferrer">Paper</a>
1697
+ <a class="icon-link" href="{CODE_URL}" target="_blank" rel="noopener noreferrer">Code</a>
1698
+ <a class="icon-link" href="{DATASET_URL}" target="_blank" rel="noopener noreferrer">Dataset</a>
1699
+ <a class="icon-link" href="{MODEL_URL}" target="_blank" rel="noopener noreferrer">Model</a>
1700
  </div>
1701
  """
1702
  )
 
1731
  step=0.1,
1732
  )
1733
 
1734
+ gr.HTML(
1735
+ """
1736
+ <footer class="quest-footer">
1737
+ <p>Quest is a fully open recipe for training deep research agents from scratch &mdash; covering data synthesis, memory management, infrastructure, and long-horizon training.</p>
1738
+ <div class="quest-footer-links">
1739
+ <a href="https://nlp.osu.edu/" target="_blank" rel="noopener noreferrer">OSU NLP</a>
1740
+ <a href="https://huggingface.co/osunlp" target="_blank" rel="noopener noreferrer">Hugging Face</a>
1741
+ </div>
1742
+ </footer>
1743
+ """
1744
+ )
1745
+
1746
  run_event = run_btn.click(
1747
  fn=run_ui,
1748
  inputs=[question, model, max_turns, max_search_results, temperature],