Nischal Subedi commited on
Commit
2e6a585
·
1 Parent(s): 9e81792

updated UI

Browse files
Files changed (1) hide show
  1. app.py +539 -449
app.py CHANGED
@@ -57,7 +57,7 @@ Statutes from context:
57
  Context information:
58
  --- START CONTEXT ---
59
  {context}
60
- --- END CONTEXT ---
61
  Answer:"""
62
  self.prompt_template = PromptTemplate(
63
  input_variables=["query", "context", "state", "statutes"],
@@ -237,7 +237,7 @@ Answer:"""
237
  logging.error(f"Failed to load or process PDF '{pdf_path}': {str(e)}", exc_info=True)
238
  raise RuntimeError(f"Failed to process PDF '{pdf_path}': {e}") from e
239
 
240
- # --- GRADIO INTERFACE (Completely Redesigned UI) ---
241
  def gradio_interface(self):
242
  def query_interface_wrapper(api_key: str, query: str, state: str) -> str:
243
  # Basic client-side validation for immediate feedback
@@ -277,6 +277,7 @@ Answer:"""
277
  example_queries = []
278
  if available_states_list and "Error" not in available_states_list[0] and len(available_states_list) > 0:
279
  loaded_states_set = set(available_states_list)
 
280
  example_queries = [ex for ex in example_queries_base if ex[1] in loaded_states_set]
281
  # Add a generic example if no specific state examples match or if list is empty
282
  if not example_queries:
@@ -285,665 +286,741 @@ Answer:"""
285
  example_queries.append(["What basic rights do tenants have?", "California"])
286
 
287
 
288
- # --- Custom CSS for "Legal Lumen" Theme ---
289
  custom_css = """
290
- /* New Theme: Legal Lumen */
291
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Montserrat:wght@600;700;800&display=swap');
292
 
293
  :root {
294
- /* Light Theme Colors */
295
- --app-bg-light: #F8F9FA; /* Very light gray */
296
- --surface-bg-light: #FFFFFF; /* Pure white for cards */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  --text-primary-light: #212529; /* Dark charcoal */
298
  --text-secondary-light: #6C757D; /* Muted gray */
299
- --accent-main-light: #007bff; /* Vibrant professional blue */
300
  --accent-hover-light: #0056b3; /* Darker blue on hover */
301
- --accent-secondary-light: #6C757D; /* For secondary buttons, similar to text secondary */
302
- --accent-secondary-hover-light: #5A6268; /* Darker secondary hover */
303
  --border-light: #DEE2E6; /* Light border */
304
- --shadow-light: 0 0.5rem 1rem rgba(0,0,0,0.08); /* Subtle shadow */
305
- --focus-ring-light: rgba(0, 123, 255, 0.25); /* Blue focus ring */
306
- --error-bg-light: #F8D7DA; /* Light red for error backgrounds */
307
- --error-text-light: #721C24; /* Dark red for error text */
308
- --error-border-light: #F5C6CB; /* Red border for errors */
309
-
310
- /* Dark Theme Colors */
311
- --app-bg-dark: #212529; /* Deep dark gray */
312
- --surface-bg-dark: #343A40; /* Slightly lighter dark gray for cards */
313
- --text-primary-dark: #F8F9FA; /* Off-white */
314
- --text-secondary-dark: #ADB5BD; /* Muted light gray */
315
- --accent-main-dark: #8AB4F8; /* Lighter blue for dark mode */
316
- --accent-hover-dark: #669DF6; /* Darker blue on hover for dark mode */
317
- --accent-secondary-dark: #ADB5BD; /* For secondary buttons in dark mode */
318
- --accent-secondary-hover-dark: #97A0A8; /* Darker secondary hover in dark mode */
319
- --border-dark: #495057; /* Dark border */
320
- --shadow-dark: 0 0.5rem 1rem rgba(0,0,0,0.3); /* Darker shadow */
321
- --focus-ring-dark: rgba(138, 180, 248, 0.35); /* Muted blue focus ring for dark mode */
322
- --error-bg-dark: #721C24; /* Dark red for error backgrounds */
323
- --error-text-dark: #F8D7DA; /* Light red for error text */
324
- --error-border-dark: #F5C6CB; /* Red border for errors */
325
 
326
  /* General Styling Variables */
327
  --font-family-main: 'Inter', sans-serif;
328
- --font-family-header: 'Montserrat', sans-serif;
329
- --radius-sm: 4px; /* Small border radius */
330
- --radius-md: 8px; /* Medium border radius */
331
- --radius-lg: 12px; /* Large border radius */
332
- --transition-speed: 0.25s; /* Standard transition duration */
333
- }
334
-
335
- /* Base styles for the entire app */
 
 
 
 
336
  body, .gradio-container {
337
  font-family: var(--font-family-main) !important;
338
- background: var(--app-bg-light) !important;
339
- color: var(--text-primary-light) !important;
340
  margin: 0;
341
  padding: 0;
342
  min-height: 100vh;
343
  font-size: 16px;
344
- line-height: 1.6; /* Improved readability */
345
- -webkit-font-smoothing: antialiased; /* Smoother fonts */
346
  -moz-osx-font-smoothing: grayscale;
 
347
  }
348
- * { box-sizing: border-box; } /* Ensure consistent box model */
349
 
350
- /* Dark mode preference (applies styles when user's system is in dark mode) */
351
- @media (prefers-color-scheme: dark) {
352
  body, .gradio-container {
353
- background: var(--app-bg-dark) !important;
354
- color: var(--text-primary-dark) !important;
355
  }
356
  }
357
 
358
- /* Global container styling: max-width for content, centering, and padding */
359
  .gradio-container > .flex.flex-col {
360
- max-width: 900px; /* Slightly wider for better content flow */
361
- margin: 0 auto !important; /* Center the container */
362
- padding: 2rem 1.5rem 4rem 1.5rem !important; /* Generous top, side, and bottom padding */
363
- gap: 0 !important; /* Remove Gradio's default gap, manage spacing with element margins */
 
364
  }
365
 
366
- /* Header section styling: prominent, rounded banner */
367
  .app-header-wrapper {
368
- background: linear-gradient(135deg, var(--accent-main-light) 0%, var(--accent-hover-light) 100%); /* Gradient background for depth */
369
- color: #FFFFFF !important; /* White text for light theme header */
370
- padding: 3rem 2rem 4rem 2rem !important; /* More vertical padding for impact */
371
  text-align: center !important;
372
- border-radius: var(--radius-lg); /* Rounded corners for the header card */
373
- box-shadow: var(--shadow-light);
374
- margin-bottom: 3.5rem; /* Spacing between header and first content card */
375
- position: relative; /* For animation context */
376
- overflow: hidden; /* Ensure content stays within rounded corners */
 
 
 
 
377
  }
 
 
 
 
 
 
 
 
378
  .app-header {
379
  display: flex;
380
  flex-direction: column;
381
  align-items: center;
382
  position: relative;
383
- z-index: 1; /* Keep content above any potential background effects */
384
  }
385
  .app-header-logo {
386
- font-size: 4rem; /* Larger icon */
387
- margin-bottom: 1rem;
388
- display: block;
389
- line-height: 1; /* Prevent extra space below emoji */
390
- animation: bounceIn 0.8s ease-out; /* Simple entry animation for logo */
 
 
391
  }
 
 
392
  .app-header-title {
393
  font-family: var(--font-family-header) !important;
394
- font-size: 2.8rem; /* Much larger and bolder */
395
- font-weight: 800; /* Extra bold */
396
- margin: 0 0 0.75rem 0;
397
- letter-spacing: -0.04em; /* Tighter letter spacing for a modern look */
398
- text-shadow: 0 2px 4px rgba(0,0,0,0.2); /* Subtle text shadow for depth */
399
- animation: fadeInDown 1s ease-out; /* Entry animation for title */
 
 
400
  }
 
 
401
  .app-header-tagline {
402
  font-family: var(--font-family-main) !important;
403
- font-size: 1.25rem; /* Slightly larger tagline */
404
  font-weight: 300;
405
  opacity: 0.9;
406
- max-width: 600px;
407
- animation: fadeInUp 1s ease-out; /* Entry animation for tagline */
408
- }
409
-
410
- /* Dark mode header adjustments */
411
- @media (prefers-color-scheme: dark) {
412
- .app-header-wrapper {
413
- background: linear-gradient(135deg, var(--accent-main-dark) 0%, var(--accent-hover-dark) 100%);
414
- box-shadow: var(--shadow-dark);
415
- }
416
- .app-header-title { color: var(--text-primary-dark) !important; } /* Ensure title color adjusts for dark theme */
417
  }
418
 
419
  /* Keyframe animations for header elements */
420
- @keyframes bounceIn {
421
- 0%, 20%, 40%, 60%, 80%, 100% {
422
- -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
423
- transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
424
- }
425
- 0% { opacity: 0; -webkit-transform: scale3d(0.3, 0.3, 0.3); transform: scale3d(0.3, 0.3, 0.3); }
426
- 20% { -webkit-transform: scale3d(1.1, 1.1, 1.1); transform: scale3d(1.1, 1.1, 1.1); }
427
- 40% { -webkit-transform: scale3d(0.9, 0.9, 0.9); transform: scale3d(0.9, 0.9, 0.9); }
428
- 60% { opacity: 1; -webkit-transform: scale3d(1.03, 1.03, 1.03); transform: scale3d(1.03, 1.03, 1.03); }
429
- 80% { -webkit-transform: scale3d(0.97, 0.97, 0.97); transform: scale3d(0.97, 0.97, 0.97); }
430
- 100% { opacity: 1; -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); }
431
- }
432
-
433
- @keyframes fadeInDown {
434
- from { opacity: 0; transform: translate3d(0, -20px, 0); }
435
- to { opacity: 1; transform: translate3d(0, 0, 0); }
436
  }
437
 
438
- @keyframes fadeInUp {
439
- from { opacity: 0; transform: translate3d(0, 20px, 0); }
440
- to { opacity: 1; transform: translate3d(0, 0, 0); }
441
- }
442
-
443
-
444
- /* Styling for general content cards (surface elements) */
445
- .content-surface {
446
- background: var(--surface-bg-light) !important;
447
- border-radius: var(--radius-lg) !important;
448
- padding: 3rem !important; /* Consistent padding */
449
- box-shadow: var(--shadow-light) !important;
450
- border: 1px solid var(--border-light) !important;
451
- margin-bottom: 3rem; /* Spacing between cards */
 
 
 
452
  transition: background var(--transition-speed), border-color var(--transition-speed), box-shadow var(--transition-speed);
453
  }
454
- .content-surface:last-child { margin-bottom: 0; } /* No bottom margin for the last surface */
455
- @media (prefers-color-scheme: dark) {
456
- .content-surface {
457
- background: var(--surface-bg-dark) !important;
458
- box-shadow: var(--shadow-dark) !important;
459
- border: 1px solid var(--border-dark) !important;
460
  }
461
  }
462
 
463
- /* Section titles within content cards: centered, bold, with a clear separator */
464
- .section-title, .input-form-card h3, .examples-card .gr-examples-header {
465
  font-family: var(--font-family-header) !important;
466
- font-size: 1.65rem !important; /* Slightly larger than before */
467
- font-weight: 600 !important;
468
- color: var(--text-primary-light) !important;
469
- margin: 0 auto 2.2rem auto !important; /* Centered, with more space below title */
470
- padding-bottom: 1rem !important;
471
- border-bottom: 2px solid var(--border-light) !important; /* Thicker separator for emphasis */
472
  text-align: center !important;
 
 
 
473
  width: 100%;
 
474
  }
475
- @media (prefers-color-scheme: dark) {
476
- .section-title, .input-form-card h3, .examples-card .gr-examples-header {
477
- color: var(--text-primary-dark) !important;
478
- border-bottom-color: var(--border-dark) !important;
 
 
 
 
 
 
 
 
 
 
479
  }
480
  }
481
 
482
- /* General text styling within content surfaces */
483
- .content-surface p {
484
- font-size: 1.05rem; /* Slightly larger body text for readability */
485
- line-height: 1.7; /* Generous line height */
486
- color: var(--text-secondary-light);
487
- margin-bottom: 1rem;
 
488
  }
489
- .content-surface a {
490
- color: var(--accent-main-light);
491
  text-decoration: none;
492
  font-weight: 500;
493
  transition: color var(--transition-speed), text-decoration var(--transition-speed);
494
  }
495
- .content-surface a:hover {
496
- color: var(--accent-hover-light);
497
  text-decoration: underline;
498
  }
499
- .content-surface strong {
500
- font-weight: 600;
501
- color: var(--text-primary-light);
 
502
  }
503
- @media (prefers-color-scheme: dark) {
504
- .content-surface p { color: var(--text-secondary-dark); }
505
- .content-surface a { color: var(--accent-main-dark); }
506
- .content-surface a:hover { color: var(--accent-hover-dark); }
507
- .content-surface strong { color: var(--text-primary-dark); }
508
  }
509
 
510
- /* Input field group and layout: organized and symmetric */
511
- .input-field-group { margin-bottom: 2rem; }
 
 
 
 
 
 
 
 
 
512
  .input-row {
513
  display: flex;
514
- gap: 2rem; /* Increased gap for better spacing */
515
- flex-wrap: wrap; /* Allow wrapping on smaller screens */
516
- margin-bottom: 2.5rem; /* More space before buttons */
517
  }
518
  .input-field {
519
- flex: 1; /* Distribute space evenly */
520
- min-width: 280px; /* Adjusted minimum width before wrapping */
521
  }
522
 
523
- /* Input labels and info text */
524
  .gradio-input-label {
525
- font-size: 1rem !important; /* Slightly larger label */
526
  font-weight: 500 !important;
527
- color: var(--text-primary-light) !important;
528
- margin-bottom: 0.6rem !important;
529
  display: block !important;
 
530
  }
531
  .gradio-input-info {
532
- font-size: 0.85rem !important;
533
- color: var(--text-secondary-light) !important;
534
- margin-top: 0.4rem;
 
535
  }
536
- @media (prefers-color-scheme: dark) {
537
- .gradio-input-label { color: var(--text-primary-dark) !important; }
538
- .gradio-input-info { color: var(--text-secondary-dark) !important; }
539
  }
540
 
541
- /* Textbox, Dropdown, Password input styling: larger and more padded */
542
  .gradio-textbox textarea,
543
  .gradio-dropdown select,
544
  .gradio-textbox input[type=password] {
545
- border: 1px solid var(--border-light) !important;
546
  border-radius: var(--radius-md) !important;
547
- padding: 1rem 1.2rem !important; /* More padding */
548
- font-size: 1.05rem !important; /* Larger font size */
549
- background: var(--surface-bg-light) !important;
550
- color: var(--text-primary-light) !important;
551
  width: 100% !important;
552
- box-shadow: none !important;
553
- transition: border-color var(--transition-speed), box-shadow var(--transition-speed);
554
  }
555
- .gradio-textbox textarea { min-height: 140px; } /* Taller textarea for more input visibility */
556
  .gradio-textbox textarea::placeholder,
557
- .gradio-textbox input[type=password]::placeholder {
558
- color: #A0AEC0 !important; /* Consistent placeholder color */
559
- }
560
  .gradio-textbox textarea:focus,
561
  .gradio-dropdown select:focus,
562
  .gradio-textbox input[type=password]:focus {
563
- border-color: var(--accent-main-light) !important;
564
- box-shadow: 0 0 0 3px var(--focus-ring-light) !important; /* Accent color focus ring */
565
  outline: none !important;
566
  }
567
- @media (prefers-color-scheme: dark) {
568
  .gradio-textbox textarea,
569
  .gradio-dropdown select,
570
  .gradio-textbox input[type=password] {
571
- border: 1px solid var(--border-dark) !important;
572
- background: var(--surface-bg-dark) !important;
573
- color: var(--text-primary-dark) !important;
 
574
  }
575
  .gradio-textbox textarea::placeholder,
576
- .gradio-textbox input[type=password]::placeholder {
577
- color: #718096 !important;
578
- }
579
  .gradio-textbox textarea:focus,
580
  .gradio-dropdown select:focus,
581
  .gradio-textbox input[type=password]:focus {
582
- border-color: var(--accent-main-dark) !important;
583
- box-shadow: 0 0 0 3px var(--focus-ring-dark) !important;
584
  }
585
  }
586
 
587
- /* Custom dropdown arrow for consistent look (re-applied for new colors) */
588
  .gradio-dropdown select {
589
- appearance: none; /* Remove native arrow */
590
- -webkit-appearance: none;
591
- -moz-appearance: none;
592
- background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2020%2020%22%20fill%3D%22%236C757D%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M5.293%207.293a1%201%200%20011.414%200L10%2010.586l3.293-3.293a1%201%200%20111.414%201.414l-4%204a1%201%200%2001-1.414%200l-4-4a1%201%200%20010-1.414z%22%20clip-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E');
593
  background-repeat: no-repeat;
594
- background-position: right 1.2rem center; /* Adjusted position */
595
- background-size: 1.1em; /* Slightly larger arrow */
596
- padding-right: 3.5rem !important; /* Make space for arrow */
597
  }
598
- @media (prefers-color-scheme: dark) {
599
  .gradio-dropdown select {
600
- background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2020%2020%22%20fill%3D%22%23ADB5BD%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M5.293%207.293a1%201%200%20011.414%200L10%2010.586l3.293-3.293a1%201%200%20111.414%201.414l-4%204a1%201%200%2001-1.414%200l-4-4a1%201%200%20010-1.414z%22%20clip-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E');
601
  }
602
  }
603
 
604
  /* Button group and styling: dynamic and clear actions */
605
  .button-row {
606
  display: flex;
607
- gap: 1.5rem; /* More space between buttons */
608
- margin-top: 2rem;
609
  flex-wrap: wrap;
610
- justify-content: flex-end; /* Align buttons to the right */
611
  }
612
  .gradio-button {
613
  border-radius: var(--radius-md) !important;
614
- padding: 0.9rem 2rem !important; /* More padding */
615
- font-size: 1.05rem !important; /* Larger font */
616
- font-weight: 500 !important;
617
  border: 1px solid transparent !important;
618
- box-shadow: 0 2px 5px rgba(0,0,0,0.1); /* Subtle shadow for primary */
619
- transition: all var(--transition-speed) ease; /* Smooth transition for hover/active states */
620
  }
621
  .gradio-button:hover:not(:disabled) {
622
- transform: translateY(-3px); /* More pronounced lift on hover */
623
- box-shadow: 0 6px 12px rgba(0,0,0,0.15) !important;
624
  }
625
- .gradio-button:active:not(:disabled) { transform: translateY(-1px); } /* Slight press effect */
626
  .gradio-button:disabled {
627
- background: #E9ECEF !important;
628
- color: #ADB5BD !important;
629
  box-shadow: none !important;
630
- border-color: #DEE2E6 !important;
631
  cursor: not-allowed;
632
  }
633
 
634
- /* Primary button (Submit Query) */
635
  .gr-button-primary {
636
- background: var(--accent-main-light) !important;
637
- color: #FFFFFF !important;
638
- border-color: var(--accent-main-light) !important;
639
  }
640
  .gr-button-primary:hover:not(:disabled) {
641
- background: var(--accent-hover-light) !important;
642
- border-color: var(--accent-hover-light) !important;
643
  }
644
 
645
- /* Secondary button (Clear) */
646
  .gr-button-secondary {
647
- background: transparent !important; /* Transparent background */
648
- color: var(--accent-secondary-light) !important;
649
- border-color: var(--accent-secondary-light) !important; /* Border in accent color */
650
- box-shadow: none !important; /* No shadow for secondary button */
651
  }
652
  .gr-button-secondary:hover:not(:disabled) {
653
- background: rgba(0, 123, 255, 0.05) !important; /* Very light hover background */
654
- color: var(--accent-hover-light) !important;
655
- border-color: var(--accent-hover-light) !important;
656
- box-shadow: none !important;
657
  }
658
 
659
- @media (prefers-color-scheme: dark) {
660
- .gradio-button { box-shadow: 0 2px 5px rgba(0,0,0,0.2) !important; }
661
- .gradio-button:hover:not(:disabled) { box-shadow: 0 6px 12px rgba(0,0,0,0.3) !important; }
662
  .gradio-button:disabled {
663
- background: #495057 !important;
664
- color: #6C757D !important;
665
- border-color: #6C757D !important;
666
  }
667
  .gr-button-primary {
668
- background: var(--accent-main-dark) !important;
669
- color: var(--text-primary-dark) !important; /* Text color contrasts with dark accent */
670
- border-color: var(--accent-main-dark) !important;
671
  }
672
  .gr-button-primary:hover:not(:disabled) {
673
- background: var(--accent-hover-dark) !important;
674
- border-color: var(--accent-hover-dark) !important;
675
  }
676
  .gr-button-secondary {
677
  background: transparent !important;
678
- color: var(--accent-secondary-dark) !important;
679
- border-color: var(--accent-secondary-dark) !important;
680
  }
681
  .gr-button-secondary:hover:not(:disabled) {
682
- background: rgba(138, 180, 248, 0.1) !important; /* Light blue hover for dark secondary */
683
- color: var(--accent-hover-dark) !important;
684
- border-color: var(--accent-hover-dark) !important;
685
  }
686
  }
687
 
688
- /* Output Card Styling: clear structure for answers */
689
  .output-card .response-header {
690
- font-size: 1.4rem; /* Larger header */
691
- font-weight: 600;
692
- color: var(--text-primary-light);
693
- margin: 0 0 1.2rem 0;
694
  display: flex;
695
  align-items: center;
696
- gap: 0.8rem; /* Space between icon and text */
 
697
  }
698
  .output-card .response-icon {
699
- font-size: 1.6rem;
700
- color: var(--accent-main-light); /* Accent color for icon */
 
701
  }
702
  .output-card .divider {
703
  border: none;
704
- border-top: 1px solid var(--border-light);
705
- margin: 1.5rem 0 2rem 0; /* More spacing around divider */
 
706
  }
707
  .output-card .output-content-wrapper {
708
- font-size: 1.05rem;
709
- line-height: 1.7;
710
- color: var(--text-primary-light);
 
711
  }
712
  .output-card .output-content-wrapper p { margin-bottom: 1rem; }
713
  .output-card .output-content-wrapper ul,
714
  .output-card .output-content-wrapper ol {
715
- margin-left: 1.8rem; /* More indentation for lists */
716
- margin-bottom: 1rem;
717
  padding-left: 0;
718
- list-style-type: disc; /* Ensure consistent bullet style */
719
  }
720
- .output-card .output-content-wrapper ol { list-style-type: decimal; } /* Numbered lists */
721
- .output-card .output-content-wrapper li { margin-bottom: 0.6rem; }
722
- .output-card .output-content-wrapper strong { font-weight: 700; } /* Bolder strong text within output */
723
  .output-card .output-content-wrapper a {
724
- color: var(--accent-main-light);
725
- text-decoration: underline; /* Links in output should be underlined for clarity */
726
  }
727
  .output-card .output-content-wrapper a:hover {
728
- color: var(--accent-hover-light);
729
  }
730
 
731
- @media (prefers-color-scheme: dark) {
732
- .output-card .response-header { color: var(--text-primary-dark); }
733
- .output-card .response-icon { color: var(--accent-main-dark); }
734
- .output-card .divider { border-top: 1px solid var(--border-dark); }
735
- .output-card .output-content-wrapper { color: var(--text-primary-dark); }
736
- .output-card .output-content-wrapper a { color: var(--accent-main-dark); }
737
- .output-card .output-content-wrapper a:hover { color: var(--accent-hover-dark); }
738
  }
739
 
740
- /* Error and Success Messages: visually distinct and informative */
741
  .output-card .error-message {
742
- padding: 1rem 1.5rem;
743
- margin-top: 1.5rem;
744
- font-size: 1rem;
745
  border-radius: var(--radius-md);
746
- background: var(--error-bg-light);
747
- color: var(--error-text-light);
748
- border: 1px solid var(--error-border-light);
749
- display: flex; /* Use flexbox for icon and text alignment */
750
- align-items: flex-start; /* Align text to top if icon is taller */
751
- gap: 0.8em;
 
752
  }
753
  .output-card .error-message .error-icon {
754
- font-size: 1.4rem;
755
- line-height: 1; /* Ensure icon is vertically centered */
756
- padding-top: 0.1em; /* Fine tune vertical alignment */
757
  }
758
  .output-card .error-details {
759
- font-size: 0.9rem;
760
- margin-top: 0.6rem;
761
  opacity: 0.9;
762
- word-break: break-word; /* Prevent long URLs/messages from overflowing */
763
  }
764
- @media (prefers-color-scheme: dark) {
765
  .output-card .error-message {
766
- background: var(--error-bg-dark);
767
- color: var(--error-text-dark);
768
- border: 1px solid var(--error-border-dark);
769
  }
770
  }
771
 
772
- /* Placeholder styling for empty output area */
773
  .output-card .placeholder {
774
- padding: 3.5rem 1.5rem; /* More vertical padding */
775
- font-size: 1.15rem; /* Larger placeholder text */
776
- border-radius: var(--radius-lg);
777
- border: 2px dashed var(--border-light);
778
- color: var(--text-secondary-light);
779
  text-align: center;
780
  opacity: 0.8;
 
781
  }
782
- @media (prefers-color-scheme: dark) {
783
  .output-card .placeholder {
784
- border-color: var(--border-dark);
785
- color: var(--text-secondary-dark);
786
  }
787
  }
788
 
789
- /* Examples table styling: clean and interactive */
790
- .examples-card .gr-examples-table {
791
- border-radius: var(--radius-lg) !important;
792
- border: 1px solid var(--border-light) !important;
793
- overflow: hidden; /* Ensures border-radius is applied to table */
794
  }
795
- .examples-card .gr-examples-table th,
796
- .examples-card .gr-examples-table td {
797
- padding: 1rem 1.2rem !important; /* More padding */
798
- font-size: 0.98rem !important;
799
- border: none !important; /* Remove individual cell borders */
 
 
 
 
 
 
 
 
 
800
  }
801
- .examples-card .gr-examples-table th {
802
- background: var(--app-bg-light) !important; /* Match app background for table header for seamless look */
803
- color: var(--text-primary-light) !important;
 
 
 
 
 
 
 
804
  font-weight: 600 !important;
805
  text-align: left;
 
806
  }
807
- .examples-card .gr-examples-table td {
808
- background: var(--surface-bg-light) !important;
809
- color: var(--text-primary-light) !important;
810
- border-top: 1px solid var(--border-light) !important; /* Add horizontal rule between rows */
811
- cursor: pointer; /* Indicate clickable rows */
812
- transition: background var(--transition-speed);
813
  }
814
- .examples-card .gr-examples-table tr:hover td {
815
- background: rgba(0, 123, 255, 0.03) !important; /* Very light hover effect */
816
  }
817
- .examples-card .gr-examples-table tr:first-child td { border-top: none !important; } /* No top border for first row's cells */
818
 
819
- @media (prefers-color-scheme: dark) {
820
- .examples-card .gr-examples-table { border: 1px solid var(--border-dark) !important;}
821
- .examples-card .gr-examples-table th {
822
- background: var(--app-bg-dark) !important;
823
- color: var(--text-primary-dark) !important;
824
- }
825
- .examples-card .gr-examples-table td {
826
- background: var(--surface-bg-dark) !important;
827
- color: var(--text-primary-dark) !important;
828
- border-top: 1px solid var(--border-dark) !important;
829
- }
830
- .examples-card .gr-examples-table tr:hover td {
831
- background: rgba(138, 180, 248, 0.1) !important; /* Light blue hover for dark table */
832
- }
833
  }
834
 
835
- /* Footer styling: clean and informative */
 
836
  .app-footer-wrapper {
837
- border-top: 1px solid var(--border-light) !important;
838
- margin-top: 3.5rem; /* Spacing from last content card */
839
- padding-top: 3rem; /* Padding above footer content */
 
 
 
 
 
 
840
  }
 
 
 
 
 
 
 
 
841
  .app-footer {
842
- padding: 0 1.5rem !important;
843
  text-align: center !important;
844
  display: flex;
845
  flex-direction: column;
846
  align-items: center;
847
  }
848
  .app-footer p {
849
- font-size: 0.95rem !important;
850
- color: var(--text-secondary-light) !important;
851
- margin-bottom: 0.8rem;
852
- max-width: 650px; /* Constrain text width for readability */
 
853
  }
854
  .app-footer a {
855
- color: var(--accent-main-light) !important;
856
  font-weight: 500;
857
  transition: color var(--transition-speed), text-decoration var(--transition-speed);
858
  }
859
  .app-footer a:hover {
860
- color: var(--accent-hover-light) !important;
861
  text-decoration: underline;
862
  }
863
- @media (prefers-color-scheme: dark) {
864
- .app-footer-wrapper { border-top-color: var(--border-dark) !important; }
865
- .app-footer p { color: var(--text-secondary-dark) !important; }
866
- .app-footer a { color: var(--accent-main-dark) !important; }
867
- .app-footer a:hover { color: var(--accent-hover-dark) !important; }
868
  }
869
 
870
- /* Accessibility: Focus styles for keyboard navigation */
871
  :focus-visible {
872
- outline: 2px solid var(--accent-main-light) !important;
873
- outline-offset: 2px;
874
- box-shadow: 0 0 0 4px var(--focus-ring-light) !important; /* Thicker, more visible focus ring */
 
875
  }
876
- @media (prefers-color-scheme: dark) {
877
  :focus-visible {
878
- outline-color: var(--accent-main-dark) !important;
879
- box-shadow: 0 0 0 4px var(--focus-ring-dark) !important;
880
  }
881
  }
882
- /* Prevent double focus outline on Gradio buttons' internal span */
883
  .gradio-button span:focus { outline: none !important; }
884
 
885
-
886
- /* Essential overrides to ensure custom styles take precedence over Gradio defaults */
887
- .gradio-container > .flex { gap: 0 !important; } /* Remove main container gap */
888
- .gradio-markdown > *:first-child { margin-top: 0; } /* Remove top margin from first element in Markdown */
889
- .gradio-markdown > *:last-child { margin-bottom: 0; } /* Remove bottom margin from last element in Markdown */
890
- /* Remove default Gradio component borders/padding that interfere with custom styling */
891
  .gradio-dropdown, .gradio-textbox { border: none !important; padding: 0 !important; background: transparent !important; }
892
-
893
- /* Responsive adjustments for various screen sizes */
894
- @media (max-width: 992px) {
895
- .gradio-container > .flex.flex-col { max-width: 760px; padding: 1.5rem 1.25rem 3.5rem 1.25rem !important; }
896
- .content-surface { padding: 2.5rem !important; margin-bottom: 2.5rem; }
897
- .app-header-wrapper { padding: 2.5rem 1.5rem 3.5rem 1.5rem !important; margin-bottom: 3rem; }
898
- .app-header-title { font-size: 2.5rem; }
899
- .app-header-tagline { font-size: 1.15rem; }
900
- .section-title, .input-form-card h3, .examples-card .gr-examples-header { font-size: 1.5rem !important; margin-bottom: 2rem !important; }
901
- .input-row { gap: 1.5rem; }
902
- .gradio-textbox textarea { min-height: 120px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
903
  }
904
 
905
  @media (max-width: 768px) {
906
- .gradio-container > .flex.flex-col { padding: 1rem 1rem 3rem 1rem !important; }
907
- .content-surface { padding: 2rem !important; margin-bottom: 2rem; }
908
- .app-header-wrapper { padding: 2rem 1.25rem 3rem 1.25rem !important; margin-bottom: 2.5rem; }
909
- .app-header-logo { font-size: 3.5rem; }
910
- .app-header-title { font-size: 2.2rem; letter-spacing: -0.03em; }
911
- .app-header-tagline { font-size: 1.05rem; }
912
- .section-title, .input-form-card h3, .examples-card .gr-examples-header { font-size: 1.4rem !important; margin-bottom: 1.8rem !important; }
913
- .input-row { flex-direction: column; gap: 1.25rem; } /* Stack inputs vertically */
 
 
 
 
914
  .input-field { min-width: 100%; }
915
- .button-row { justify-content: stretch; } /* Stretch buttons to full width */
916
- .gradio-button { width: 100%; }
917
- .output-card .response-header { font-size: 1.25rem; }
918
- .output-card .response-icon { font-size: 1.4rem; }
919
- .output-card .placeholder { padding: 3rem 1rem; font-size: 1.1rem; }
920
- .examples-card .gr-examples-table th, .examples-card .gr-examples-table td { padding: 0.8rem 1rem !important; font-size: 0.95rem !important; }
921
- .app-footer-wrapper { margin-top: 3rem; padding-top: 2.5rem; }
922
- .app-footer p { font-size: 0.9rem !important; }
 
923
  }
924
 
925
  @media (max-width: 480px) {
926
- .gradio-container > .flex.flex-col { padding: 0.75rem 0.75rem 2.5rem 0.75rem !important; }
927
- .content-surface { padding: 1.5rem !important; margin-bottom: 1.5rem; border-radius: var(--radius-md) !important; }
928
- .app-header-wrapper { padding: 1.5rem 1rem 2rem 1rem !important; margin-bottom: 2rem; border-radius: var(--radius-md); }
929
- .app-header-logo { font-size: 3rem; margin-bottom: 0.75rem; }
930
- .app-header-title { font-size: 2rem; letter-spacing: -0.02em; }
931
- .app-header-tagline { font-size: 0.95rem; }
932
- .section-title, .input-form-card h3, .examples-card .gr-examples-header { font-size: 1.25rem !important; margin-bottom: 1.5rem !important; padding-bottom: 0.75rem !important; }
933
- .gradio-textbox textarea, .gradio-dropdown select, .gradio-textbox input[type=password] { font-size: 0.95rem !important; padding: 0.8rem 1rem !important; }
934
- .gradio-textbox textarea { min-height: 100px; }
935
- .gradio-button { padding: 0.8rem 1.2rem !important; font-size: 0.95rem !important; }
936
- .output-card .response-header { font-size: 1.15rem; }
937
- .output-card .response-icon { font-size: 1.3rem; }
938
- .output-card .placeholder { padding: 2.5rem 0.8rem; font-size: 1rem; }
939
- .examples-card .gr-examples-table th, .examples-card .gr-examples-table td { padding: 0.6rem 0.8rem !important; font-size: 0.85rem !important; }
940
- .app-footer-wrapper { margin-top: 2.5rem; padding-top: 2rem; }
941
- .app-footer p { font-size: 0.85rem !important; }
 
 
 
 
942
  }
943
  """
944
 
945
  with gr.Blocks(theme=None, css=custom_css, title="Landlord-Tenant Rights Assistant") as demo:
946
- # --- Header Section: Prominent, dynamic banner ---
947
  with gr.Group(elem_classes="app-header-wrapper"):
948
  gr.Markdown(
949
  """
@@ -955,8 +1032,11 @@ Answer:"""
955
  """
956
  )
957
 
958
- # --- "Know Your Rights" Section: Informational card ---
959
- with gr.Group(elem_classes="content-surface"):
 
 
 
960
  gr.Markdown("<h3 class='section-title'>Know Your Rights</h3>")
961
  gr.Markdown(
962
  """
@@ -966,21 +1046,22 @@ Answer:"""
966
  """
967
  )
968
 
969
- # --- "Ask Your Question" Section (Input Form): Structured and clear inputs ---
970
- with gr.Group(elem_classes="content-surface input-form-card"):
971
- gr.Markdown("<h3>Ask Your Question</h3>")
 
972
  with gr.Column(elem_classes="input-field-group"):
973
  api_key_input = gr.Textbox(
974
  label="OpenAI API Key", type="password", placeholder="Enter your API key (e.g., sk-...)",
975
  info="Required to process your query. Securely used per request, not stored.", lines=1
976
  )
977
  with gr.Row(elem_classes="input-row"):
978
- with gr.Column(elem_classes="input-field", min_width="58%"): # Allocate more width for the question
979
  query_input = gr.Textbox(
980
  label="Your Question", placeholder="E.g., What are the rules for security deposit returns in my state?",
981
  lines=5, max_lines=10
982
  )
983
- with gr.Column(elem_classes="input-field", min_width="38%"): # Allocate less width for the dropdown
984
  state_input = gr.Dropdown(
985
  label="Select State", choices=dropdown_choices, value=initial_value,
986
  allow_custom_value=False
@@ -989,25 +1070,30 @@ Answer:"""
989
  clear_button = gr.Button("Clear", variant="secondary", elem_classes=["gr-button-secondary"])
990
  submit_button = gr.Button("Submit Query", variant="primary", elem_classes=["gr-button-primary"])
991
 
992
- # --- Output Section: Clearly formatted answers or messages ---
993
- with gr.Group(elem_classes="content-surface output-card"):
 
 
994
  output = gr.Markdown(
995
- value="<div class='placeholder'>Your answer will appear here after submitting your query.</div>",
996
- elem_classes="output-content-wrapper" # This div will be replaced by the answer HTML
997
  )
998
 
999
- # --- "Explore Sample Questions" Section: Interactive examples ---
1000
- if example_queries:
1001
- with gr.Group(elem_classes="content-surface examples-card"):
1002
- gr.Examples(
1003
- examples=example_queries, inputs=[query_input, state_input],
1004
- label="Explore Sample Questions", examples_per_page=5
1005
- )
1006
- else:
1007
- with gr.Group(elem_classes="content-surface"):
1008
- gr.Markdown("<div class='placeholder'>Sample questions could not be loaded.</div>")
 
 
1009
 
1010
- # --- Footer Section: Disclaimer and author info ---
 
1011
  with gr.Group(elem_classes="app-footer-wrapper"):
1012
  gr.Markdown(
1013
  """
@@ -1020,7 +1106,7 @@ Answer:"""
1020
  """
1021
  )
1022
 
1023
- # --- Event Listeners ---
1024
  submit_button.click(
1025
  fn=query_interface_wrapper, inputs=[api_key_input, query_input, state_input], outputs=output, api_name="submit_query"
1026
  )
@@ -1029,11 +1115,11 @@ Answer:"""
1029
  "", # Clear API key input
1030
  "", # Clear query input
1031
  initial_value, # Reset state dropdown to initial value
1032
- "<div class='placeholder'>Inputs cleared. Ready for your next question.</div>" # Reset output to placeholder
1033
  ),
1034
  inputs=[], outputs=[api_key_input, query_input, state_input, output]
1035
  )
1036
- logging.info("Advanced UI (Legal Lumen theme) Gradio interface created.")
1037
  return demo
1038
 
1039
  # --- Main Execution Block (remains untouched from original logic) ---
@@ -1041,8 +1127,8 @@ if __name__ == "__main__":
1041
  logging.info("Starting Landlord-Tenant Rights Bot application...")
1042
  try:
1043
  SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
1044
- DEFAULT_PDF_PATH = os.path.join(SCRIPT_DIR, "tenant-landlord.pdf")
1045
- DEFAULT_DB_PATH = os.path.join(SCRIPT_DIR, "chroma_db")
1046
 
1047
  # Use environment variables if set, otherwise default paths
1048
  PDF_PATH = os.getenv("PDF_PATH", DEFAULT_PDF_PATH)
@@ -1050,17 +1136,21 @@ if __name__ == "__main__":
1050
 
1051
  # Ensure directories exist
1052
  os.makedirs(os.path.dirname(VECTOR_DB_PATH), exist_ok=True)
1053
- # If PDF_PATH could point to a file in a non-existent subdirectory, uncomment:
1054
- # if os.path.dirname(PDF_PATH):
1055
- # os.makedirs(os.path.dirname(PDF_PATH), exist_ok=True)
1056
 
1057
-
1058
- # Validate PDF file existence before proceeding
1059
  if not os.path.exists(PDF_PATH):
1060
  logging.error(f"FATAL: PDF file not found at the specified path: {PDF_PATH}")
1061
- print(f"\n--- CONFIGURATION ERROR ---\nPDF file ('{os.path.basename(PDF_PATH)}') not found at: {PDF_PATH}\nPlease ensure it exists or set 'PDF_PATH' environment variable.\n---------------------------\n")
 
 
 
 
 
1062
  exit(1)
1063
 
 
 
1064
  # Initialize Vector Database and RAG System
1065
  vector_db_instance = VectorDatabase(persist_directory=VECTOR_DB_PATH)
1066
  rag = RAGSystem(vector_db=vector_db_instance)
 
57
  Context information:
58
  --- START CONTEXT ---
59
  {context}
60
+ --- END CONCONTEXT ---
61
  Answer:"""
62
  self.prompt_template = PromptTemplate(
63
  input_variables=["query", "context", "state", "statutes"],
 
237
  logging.error(f"Failed to load or process PDF '{pdf_path}': {str(e)}", exc_info=True)
238
  raise RuntimeError(f"Failed to process PDF '{pdf_path}': {e}") from e
239
 
240
+ # --- GRADIO INTERFACE (Complete Overhaul for Cohesion, Legibility, and Advanced Look) ---
241
  def gradio_interface(self):
242
  def query_interface_wrapper(api_key: str, query: str, state: str) -> str:
243
  # Basic client-side validation for immediate feedback
 
277
  example_queries = []
278
  if available_states_list and "Error" not in available_states_list[0] and len(available_states_list) > 0:
279
  loaded_states_set = set(available_states_list)
280
+ # Filter for examples whose state is in the loaded states
281
  example_queries = [ex for ex in example_queries_base if ex[1] in loaded_states_set]
282
  # Add a generic example if no specific state examples match or if list is empty
283
  if not example_queries:
 
286
  example_queries.append(["What basic rights do tenants have?", "California"])
287
 
288
 
289
+ # --- Custom CSS for "Legal Noir" Theme (Dark Mode First) ---
290
  custom_css = """
291
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:wght@700;800;900&display=swap');
 
292
 
293
  :root {
294
+ /* Dark Theme Colors (Default: Legal Noir) */
295
+ --app-bg-dark: #12121A; /* Deep, muted black/purple */
296
+ --header-bg-dark: #0A0A10; /* Even darker header background */
297
+ --main-content-bg-dark: #1E1E2A; /* Slightly lighter surface for main content */
298
+ --text-primary-dark: #EAEAF0; /* Crisp off-white for main text */
299
+ --text-secondary-dark: #A0A0B0; /* Muted light gray for secondary text */
300
+ --accent-main-dark: #FFC107; /* Vibrant Gold/Amber for primary accents */
301
+ --accent-hover-dark: #E0A800; /* Darker gold on hover */
302
+ --border-dark: #333345; /* Subtle dark border */
303
+ --shadow-dark: 0 1rem 3rem rgba(0,0,0,0.6); /* Deep, soft shadow for rich contrast */
304
+ --focus-ring-dark: rgba(255, 193, 7, 0.4); /* Gold focus ring */
305
+ --error-bg-dark: #4D001A; /* Deep red for errors */
306
+ --error-text-dark: #FFB3C2; /* Light pink for error text */
307
+ --error-border-dark: #990026;
308
+
309
+ /* Light Theme Colors (Alternative: Legal Lumen) */
310
+ --app-bg-light: #F8F9FA; /* Soft light gray background */
311
+ --header-bg-light: #E9ECEF; /* Lighter header background */
312
+ --main-content-bg-light: #FFFFFF; /* Pure white for main content */
313
  --text-primary-light: #212529; /* Dark charcoal */
314
  --text-secondary-light: #6C757D; /* Muted gray */
315
+ --accent-main-light: #007bff; /* Professional blue */
316
  --accent-hover-light: #0056b3; /* Darker blue on hover */
 
 
317
  --border-light: #DEE2E6; /* Light border */
318
+ --shadow-light: 0 0.8rem 2.5rem rgba(0,0,0,0.15); /* Soft shadow */
319
+ --focus-ring-light: rgba(0, 123, 255, 0.3);
320
+ --error-bg-light: #F8D7DA;
321
+ --error-text-light: #721C24;
322
+ --error-border-light: #F5C6CB;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
 
324
  /* General Styling Variables */
325
  --font-family-main: 'Inter', sans-serif;
326
+ --font-family-header: 'Playfair Display', serif; /* Elegant serif for titles */
327
+ --radius-sm: 8px;
328
+ --radius-md: 12px;
329
+ --radius-lg: 24px; /* Larger radius for a premium, soft feel */
330
+ --transition-speed: 0.5s ease-in-out; /* Slower, smoother transitions */
331
+ --padding-xl: 4.5rem; /* Extra large padding for spaciousness */
332
+ --padding-lg: 3.5rem;
333
+ --padding-md: 2.5rem;
334
+ --padding-sm: 1.8rem;
335
+ }
336
+
337
+ /* Apply theme based on system preference */
338
  body, .gradio-container {
339
  font-family: var(--font-family-main) !important;
340
+ background: var(--app-bg-dark) !important; /* Default to dark theme */
341
+ color: var(--text-primary-dark) !important;
342
  margin: 0;
343
  padding: 0;
344
  min-height: 100vh;
345
  font-size: 16px;
346
+ line-height: 1.75; /* Enhanced line spacing for legibility */
347
+ -webkit-font-smoothing: antialiased;
348
  -moz-osx-font-smoothing: grayscale;
349
+ transition: background var(--transition-speed), color var(--transition-speed);
350
  }
351
+ * { box-sizing: border-box; }
352
 
353
+ @media (prefers-color-scheme: light) {
 
354
  body, .gradio-container {
355
+ background: var(--app-bg-light) !important;
356
+ color: var(--text-primary-light) !important;
357
  }
358
  }
359
 
360
+ /* Global container for content alignment and padding */
361
  .gradio-container > .flex.flex-col {
362
+ max-width: 1080px; /* Even wider for a more expansive dashboard feel */
363
+ margin: 0 auto !important;
364
+ padding: 0 !important; /* Managed by custom classes */
365
+ gap: 0 !important;
366
+ transition: padding var(--transition-speed);
367
  }
368
 
369
+ /* Header styling: dynamic, centralized, and visually connecting */
370
  .app-header-wrapper {
371
+ background: var(--header-bg-dark); /* Solid color for header, based on theme */
372
+ color: var(--text-primary-dark) !important;
373
+ padding: var(--padding-xl) var(--padding-lg) !important;
374
  text-align: center !important;
375
+ border-bottom-left-radius: var(--radius-lg);
376
+ border-bottom-right-radius: var(--radius-lg);
377
+ box-shadow: var(--shadow-dark);
378
+ position: relative;
379
+ overflow: hidden;
380
+ z-index: 10;
381
+ transition: background var(--transition-speed), box-shadow var(--transition-speed);
382
+ /* NEW: Blend with main content by overlapping its own radius */
383
+ margin-bottom: calc(-1 * var(--radius-lg));
384
  }
385
+ @media (prefers-color-scheme: light) {
386
+ .app-header-wrapper {
387
+ background: var(--header-bg-light);
388
+ color: var(--text-primary-light) !important;
389
+ box-shadow: var(--shadow-light);
390
+ }
391
+ }
392
+
393
  .app-header {
394
  display: flex;
395
  flex-direction: column;
396
  align-items: center;
397
  position: relative;
398
+ z-index: 1;
399
  }
400
  .app-header-logo {
401
+ font-size: 5.5rem; /* Even larger icon for maximum impact */
402
+ margin-bottom: 1.5rem;
403
+ line-height: 1;
404
+ filter: drop-shadow(0 0 15px var(--accent-main-dark)); /* Stronger glow effect for icon */
405
+ transform: translateY(-40px); opacity: 0; /* Initial state for animation */
406
+ animation: fadeInSlideDown 1.5s ease-out forwards; animation-delay: 0.3s;
407
+ transition: filter var(--transition-speed);
408
  }
409
+ @media (prefers-color-scheme: light) { .app-header-logo { filter: drop-shadow(0 0 10px var(--accent-main-light)); } }
410
+
411
  .app-header-title {
412
  font-family: var(--font-family-header) !important;
413
+ font-size: 4.2rem; /* The main title: massive, bold, and dynamic */
414
+ font-weight: 900; /* Extra, extra bold */
415
+ margin: 0 0 1.2rem 0;
416
+ letter-spacing: -0.07em; /* Tighter for a strong presence */
417
+ text-shadow: 0 8px 16px rgba(0,0,0,0.5); /* Deepest shadow for depth */
418
+ transform: translateY(-40px); opacity: 0;
419
+ animation: fadeInSlideDown 1.5s ease-out forwards; animation-delay: 0.6s;
420
+ transition: text-shadow var(--transition-speed), color var(--transition-speed);
421
  }
422
+ @media (prefers-color-scheme: light) { .app-header-title { text-shadow: 0 6px 12px rgba(0,0,0,0.25); } }
423
+
424
  .app-header-tagline {
425
  font-family: var(--font-family-main) !important;
426
+ font-size: 1.6rem; /* Larger, more inviting tagline */
427
  font-weight: 300;
428
  opacity: 0.9;
429
+ max-width: 900px;
430
+ transform: translateY(-40px); opacity: 0;
431
+ animation: fadeInSlideDown 1.5s ease-out forwards; animation-delay: 0.9s;
432
+ transition: opacity var(--transition-speed);
 
 
 
 
 
 
 
433
  }
434
 
435
  /* Keyframe animations for header elements */
436
+ @keyframes fadeInSlideDown {
437
+ from { opacity: 0; transform: translateY(-40px); }
438
+ to { opacity: 1; transform: translateY(0); }
 
 
 
 
 
 
 
 
 
 
 
 
 
439
  }
440
 
441
+ /* Main content area: The single, unified block containing all core functionality */
442
+ .main-content-area {
443
+ background: var(--main-content-bg-dark) !important;
444
+ border-radius: var(--radius-lg);
445
+ box-shadow: var(--shadow-dark);
446
+ border: 1px solid var(--border-dark) !important;
447
+ /* Match header's bottom radius on its top */
448
+ border-top-left-radius: var(--radius-lg);
449
+ border-top-right-radius: var(--radius-lg);
450
+ margin: 0 auto 5rem auto; /* General spacing to the footer */
451
+ /* New: compensate for header's margin-bottom overlap */
452
+ padding-top: calc(var(--padding-xl) + var(--radius-lg)); /* Add back the space lost by header's overlap */
453
+ padding-left: var(--padding-xl) !important;
454
+ padding-right: var(--padding-xl) !important;
455
+ padding-bottom: var(--padding-lg) !important; /* Bottom padding for the whole area */
456
+ z-index: 1; /* Ensure it's behind header, but visually seamless */
457
+ position: relative;
458
  transition: background var(--transition-speed), border-color var(--transition-speed), box-shadow var(--transition-speed);
459
  }
460
+ @media (prefers-color-scheme: light) {
461
+ .main-content-area {
462
+ background: var(--main-content-bg-light) !important;
463
+ box-shadow: var(--shadow-light);
464
+ border: 1px solid var(--border-light) !important;
 
465
  }
466
  }
467
 
468
+ /* Section titles within the unified main content area */
469
+ .section-title { /* For 'Know Your Rights' */
470
  font-family: var(--font-family-header) !important;
471
+ font-size: 2.5rem !important; /* Larger section titles */
472
+ font-weight: 800 !important; /* Extra bold */
473
+ color: var(--text-primary-dark) !important;
 
 
 
474
  text-align: center !important;
475
+ margin: 0 auto 3.5rem auto !important; /* More space below */
476
+ padding-bottom: 1.5rem !important;
477
+ border-bottom: 2px solid var(--border-dark) !important;
478
  width: 100%;
479
+ transition: color var(--transition-speed), border-color var(--transition-speed);
480
  }
481
+ .sub-section-title { /* For 'Ask Your Question', 'Answer', 'Explore Sample Questions' */
482
+ font-family: var(--font-family-header) !important;
483
+ font-size: 2rem !important; /* Slightly smaller for sub-sections */
484
+ font-weight: 700 !important;
485
+ color: var(--text-primary-dark) !important;
486
+ text-align: center !important;
487
+ margin-top: 3rem !important; /* Tighter vertical spacing for more cohesive display */
488
+ margin-bottom: 1.5rem !important; /* Tighter coupling to content */
489
+ transition: color var(--transition-speed);
490
+ }
491
+ @media (prefers-color-scheme: light) {
492
+ .section-title, .sub-section-title {
493
+ color: var(--text-primary-light) !important;
494
+ border-bottom-color: var(--border-light) !important;
495
  }
496
  }
497
 
498
+ /* General text styling within main content: highly legible */
499
+ .main-content-area p {
500
+ font-size: 1.15rem; /* Larger, more readable body text */
501
+ line-height: 1.8; /* Generous line height for comfort */
502
+ color: var(--text-secondary-dark);
503
+ margin-bottom: 1.5rem;
504
+ transition: color var(--transition-speed);
505
  }
506
+ .main-content-area a {
507
+ color: var(--accent-main-dark);
508
  text-decoration: none;
509
  font-weight: 500;
510
  transition: color var(--transition-speed), text-decoration var(--transition-speed);
511
  }
512
+ .main-content-area a:hover {
513
+ color: var(--accent-hover-dark);
514
  text-decoration: underline;
515
  }
516
+ .main-content-area strong {
517
+ font-weight: 700;
518
+ color: var(--text-primary-dark);
519
+ transition: color var(--transition-speed);
520
  }
521
+ @media (prefers-color-scheme: light) {
522
+ .main-content-area p { color: var(--text-secondary-light); }
523
+ .main-content-area a { color: var(--accent-main-light); }
524
+ .main-content-area a:hover { color: var(--accent-hover-light); }
525
+ .main-content-area strong { color: var(--text-primary-light); }
526
  }
527
 
528
+ /* Horizontal rule for visual separation within the main block */
529
+ .section-divider {
530
+ border: none;
531
+ border-top: 1px solid var(--border-dark); /* Subtle, but present for structure */
532
+ margin: 4rem 0; /* Adjusted for better overall flow */
533
+ transition: border-color var(--transition-speed);
534
+ }
535
+ @media (prefers-color-scheme: light) { .section-divider { border-top: 1px solid var(--border-light); } }
536
+
537
+ /* Input field groups and layout: spacious and clear */
538
+ .input-field-group { margin-bottom: 2rem; } /* Adjusted for tighter coupling */
539
  .input-row {
540
  display: flex;
541
+ gap: 3rem; /* Still generous space between inputs */
542
+ flex-wrap: wrap;
543
+ margin-bottom: 3rem; /* Adjusted for tighter coupling to buttons */
544
  }
545
  .input-field {
546
+ flex: 1;
547
+ min-width: 350px; /* Wider min-width for larger inputs */
548
  }
549
 
550
+ /* Input labels and info text: prominent and clear */
551
  .gradio-input-label {
552
+ font-size: 1.2rem !important; /* Larger, more prominent labels */
553
  font-weight: 500 !important;
554
+ color: var(--text-primary-dark) !important;
555
+ margin-bottom: 1rem !important;
556
  display: block !important;
557
+ transition: color var(--transition-speed);
558
  }
559
  .gradio-input-info {
560
+ font-size: 1rem !important;
561
+ color: var(--text-secondary-dark) !important;
562
+ margin-top: 0.6rem;
563
+ transition: color var(--transition-speed);
564
  }
565
+ @media (prefers-color-scheme: light) {
566
+ .gradio-input-label { color: var(--text-primary-light) !important; }
567
+ .gradio-input-info { color: var(--text-secondary-light) !important; }
568
  }
569
 
570
+ /* Textbox, Dropdown, Password input styling: larger, more refined */
571
  .gradio-textbox textarea,
572
  .gradio-dropdown select,
573
  .gradio-textbox input[type=password] {
574
+ border: 2px solid var(--border-dark) !important; /* Thicker border for visibility */
575
  border-radius: var(--radius-md) !important;
576
+ padding: 1.3rem 1.6rem !important; /* Even more padding */
577
+ font-size: 1.15rem !important; /* Larger font size */
578
+ background: var(--main-content-bg-dark) !important;
579
+ color: var(--text-primary-dark) !important;
580
  width: 100% !important;
581
+ box-shadow: inset 0 1px 3px rgba(0,0,0,0.3); /* Inner shadow for depth */
582
+ transition: border-color var(--transition-speed), box-shadow var(--transition-speed), background var(--transition-speed), color var(--transition-speed);
583
  }
584
+ .gradio-textbox textarea { min-height: 180px; } /* Taller textarea */
585
  .gradio-textbox textarea::placeholder,
586
+ .gradio-textbox input[type=password]::placeholder { color: #808090 !important; } /* Improved placeholder color */
 
 
587
  .gradio-textbox textarea:focus,
588
  .gradio-dropdown select:focus,
589
  .gradio-textbox input[type=password]:focus {
590
+ border-color: var(--accent-main-dark) !important;
591
+ box-shadow: 0 0 0 6px var(--focus-ring-dark) !important, inset 0 1px 3px rgba(0,0,0,0.4); /* Stronger focus ring and inner shadow */
592
  outline: none !important;
593
  }
594
+ @media (prefers-color-scheme: light) {
595
  .gradio-textbox textarea,
596
  .gradio-dropdown select,
597
  .gradio-textbox input[type=password] {
598
+ border: 2px solid var(--border-light) !important;
599
+ background: var(--main-content-bg-light) !important;
600
+ color: var(--text-primary-light) !important;
601
+ box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);
602
  }
603
  .gradio-textbox textarea::placeholder,
604
+ .gradio-textbox input[type=password]::placeholder { color: #A0AEC0 !important; }
 
 
605
  .gradio-textbox textarea:focus,
606
  .gradio-dropdown select:focus,
607
  .gradio-textbox input[type=password]:focus {
608
+ border-color: var(--accent-main-light) !important;
609
+ box-shadow: 0 0 0 6px var(--focus-ring-light) !important, inset 0 1px 3px rgba(0,0,0,0.2);
610
  }
611
  }
612
 
613
+ /* Custom dropdown arrow */
614
  .gradio-dropdown select {
615
+ appearance: none; -webkit-appearance: none; -moz-appearance: none;
616
+ background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2020%2020%22%20fill%3D%22%23A0A0B0%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M5.293%207.293a1%201%200%20011.414%200L10%2010.586l3.293-3.293a1%201%200%20111.414%201.414l-4%204a1%201%200%2001-1.414%200l-4-4a1%201%200%20010-1.414z%22%20clip-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E');
 
 
617
  background-repeat: no-repeat;
618
+ background-position: right 1.8rem center;
619
+ background-size: 1.4em; /* Larger arrow */
620
+ padding-right: 5rem !important;
621
  }
622
+ @media (prefers-color-scheme: light) {
623
  .gradio-dropdown select {
624
+ background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2020%2020%22%20fill%3D%22%236C757D%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M5.293%207.293a1%201%200%20011.414%200L10%2010.586l3.293-3.293a1%201%200%20111.414%201.414l-4%204a1%201%200%2001-1.414%200l-4-4a1%201%200%20010-1.414z%22%20clip-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E');
625
  }
626
  }
627
 
628
  /* Button group and styling: dynamic and clear actions */
629
  .button-row {
630
  display: flex;
631
+ gap: 2.5rem;
632
+ margin-top: 2.5rem;
633
  flex-wrap: wrap;
634
+ justify-content: flex-end;
635
  }
636
  .gradio-button {
637
  border-radius: var(--radius-md) !important;
638
+ padding: 1.2rem 2.8rem !important; /* More padding */
639
+ font-size: 1.15rem !important; /* Larger font */
640
+ font-weight: 600 !important; /* Bolder text */
641
  border: 1px solid transparent !important;
642
+ box-shadow: 0 6px 20px rgba(0,0,0,0.35); /* Deeper shadow */
643
+ transition: all var(--transition-speed) cubic-bezier(0.0, 0.0, 0.2, 1); /* Enhanced cubic-bezier for springy feel */
644
  }
645
  .gradio-button:hover:not(:disabled) {
646
+ transform: translateY(-6px); /* More pronounced lift */
647
+ box-shadow: 0 12px 28px rgba(0,0,0,0.45) !important;
648
  }
649
+ .gradio-button:active:not(:disabled) { transform: translateY(-3px); }
650
  .gradio-button:disabled {
651
+ background: #3A3A50 !important;
652
+ color: #6A6A80 !important;
653
  box-shadow: none !important;
654
+ border-color: #4A4A60 !important;
655
  cursor: not-allowed;
656
  }
657
 
658
+ /* Primary button */
659
  .gr-button-primary {
660
+ background: var(--accent-main-dark) !important;
661
+ color: #12121A !important; /* Dark text on gold */
662
+ border-color: var(--accent-main-dark) !important;
663
  }
664
  .gr-button-primary:hover:not(:disabled) {
665
+ background: var(--accent-hover-dark) !important;
666
+ border-color: var(--accent-hover-dark) !important;
667
  }
668
 
669
+ /* Secondary button */
670
  .gr-button-secondary {
671
+ background: transparent !important;
672
+ color: var(--text-secondary-dark) !important;
673
+ border: 2px solid var(--border-dark) !important; /* More prominent border */
674
+ box-shadow: none !important;
675
  }
676
  .gr-button-secondary:hover:not(:disabled) {
677
+ background: rgba(255, 193, 7, 0.15) !important; /* Gold tint on hover */
678
+ color: var(--accent-main-dark) !important;
679
+ border-color: var(--accent-main-dark) !important;
 
680
  }
681
 
682
+ @media (prefers-color-scheme: light) {
683
+ .gradio-button { box-shadow: 0 6px 20px rgba(0,0,0,0.1); }
684
+ .gradio-button:hover:not(:disabled) { box-shadow: 0 12px 28px rgba(0,0,0,0.2) !important; }
685
  .gradio-button:disabled {
686
+ background: #E9ECEF !important;
687
+ color: #ADB5BD !important;
688
+ border-color: #DEE2E6 !important;
689
  }
690
  .gr-button-primary {
691
+ background: var(--accent-main-light) !important;
692
+ color: #FFFFFF !important;
693
+ border-color: var(--accent-main-light) !important;
694
  }
695
  .gr-button-primary:hover:not(:disabled) {
696
+ background: var(--accent-hover-light) !important;
697
+ border-color: var(--accent-hover-light) !important;
698
  }
699
  .gr-button-secondary {
700
  background: transparent !important;
701
+ color: var(--text-secondary-light) !important;
702
+ border: 2px solid var(--border-light) !important;
703
  }
704
  .gr-button-secondary:hover:not(:disabled) {
705
+ background: rgba(0, 123, 255, 0.1) !important;
706
+ color: var(--accent-main-light) !important;
707
+ border-color: var(--accent-main-light) !important;
708
  }
709
  }
710
 
711
+ /* Output Styling within the main content area */
712
  .output-card .response-header {
713
+ font-size: 1.8rem; /* Larger and clearer */
714
+ font-weight: 700;
715
+ color: var(--text-primary-dark);
716
+ margin: 0 0 1.5rem 0;
717
  display: flex;
718
  align-items: center;
719
+ gap: 1.2rem;
720
+ transition: color var(--transition-speed);
721
  }
722
  .output-card .response-icon {
723
+ font-size: 2rem; /* Larger icon */
724
+ color: var(--accent-main-dark);
725
+ transition: color var(--transition-speed);
726
  }
727
  .output-card .divider {
728
  border: none;
729
+ border-top: 1px solid var(--border-dark);
730
+ margin: 2rem 0 2.5rem 0;
731
+ transition: border-color var(--transition-speed);
732
  }
733
  .output-card .output-content-wrapper {
734
+ font-size: 1.15rem; /* Highly legible output text */
735
+ line-height: 1.8;
736
+ color: var(--text-primary-dark);
737
+ transition: color var(--transition-speed);
738
  }
739
  .output-card .output-content-wrapper p { margin-bottom: 1rem; }
740
  .output-card .output-content-wrapper ul,
741
  .output-card .output-content-wrapper ol {
742
+ margin-left: 2.2rem; /* More indentation */
743
+ margin-bottom: 1.2rem;
744
  padding-left: 0;
745
+ list-style-type: disc;
746
  }
747
+ .output-card .output-content-wrapper ol { list-style-type: decimal; }
748
+ .output-card .output-content-wrapper li { margin-bottom: 0.8rem; }
749
+ .output-card .output-content-wrapper strong { font-weight: 700; }
750
  .output-card .output-content-wrapper a {
751
+ color: var(--accent-main-dark);
752
+ text-decoration: underline;
753
  }
754
  .output-card .output-content-wrapper a:hover {
755
+ color: var(--accent-hover-dark);
756
  }
757
 
758
+ @media (prefers-color-scheme: light) {
759
+ .output-card .response-header { color: var(--text-primary-light); }
760
+ .output-card .response-icon { color: var(--accent-main-light); }
761
+ .output-card .divider { border-top: 1px solid var(--border-light); }
762
+ .output-card .output-content-wrapper { color: var(--text-primary-light); }
763
+ .output-card .output-content-wrapper a { color: var(--accent-main-light); }
764
+ .output-card .output-content-wrapper a:hover { color: var(--accent-hover-light); }
765
  }
766
 
767
+ /* Error messages: clear, prominent, and legible */
768
  .output-card .error-message {
769
+ padding: 1.8rem 2.5rem;
770
+ margin-top: 2.5rem;
771
+ font-size: 1.1rem;
772
  border-radius: var(--radius-md);
773
+ background: var(--error-bg-dark);
774
+ color: var(--error-text-dark);
775
+ border: 2px solid var(--error-border-dark);
776
+ display: flex;
777
+ align-items: flex-start;
778
+ gap: 1.5em;
779
+ transition: background var(--transition-speed), color var(--transition-speed), border-color var(--transition-speed);
780
  }
781
  .output-card .error-message .error-icon {
782
+ font-size: 1.8rem;
783
+ line-height: 1;
784
+ padding-top: 0.1em;
785
  }
786
  .output-card .error-details {
787
+ font-size: 0.95rem;
788
+ margin-top: 0.8rem;
789
  opacity: 0.9;
790
+ word-break: break-word;
791
  }
792
+ @media (prefers-color-scheme: light) {
793
  .output-card .error-message {
794
+ background: var(--error-bg-light);
795
+ color: var(--error-text-light);
796
+ border: 2px solid var(--error-border-light);
797
  }
798
  }
799
 
800
+ /* Output placeholder styling: inviting and distinct */
801
  .output-card .placeholder {
802
+ padding: 5rem 2rem;
803
+ font-size: 1.3rem; /* Larger, more inviting placeholder */
804
+ border-radius: var(--radius-md);
805
+ border: 3px dashed var(--border-dark); /* Thicker dashed border */
806
+ color: var(--text-secondary-dark);
807
  text-align: center;
808
  opacity: 0.8;
809
+ transition: border-color var(--transition-speed), color var(--transition-speed);
810
  }
811
+ @media (prefers-color-scheme: light) {
812
  .output-card .placeholder {
813
+ border-color: var(--border-light);
814
+ color: var(--text-secondary-light);
815
  }
816
  }
817
 
818
+ /* Examples table styling: integrated within the main content block, but with clear visual identity */
819
+ /* Applied to the gr.Column that wraps the examples */
820
+ .examples-section {
821
+ padding-top: 4.5rem; /* Generous top padding to separate from Answer section */
822
+ /* No background/border/shadow here, as it's part of the main-content-area */
823
  }
824
+ .examples-section .gr-examples-table {
825
+ border-radius: var(--radius-md) !important;
826
+ border: 1px solid var(--border-dark) !important;
827
+ overflow: hidden;
828
+ background: var(--main-content-bg-dark) !important; /* Ensure table matches main content background */
829
+ box-shadow: inset 0 0 10px rgba(0,0,0,0.2); /* Subtle inner shadow */
830
+ transition: border-color var(--transition-speed), background var(--transition-speed), box-shadow var(--transition-speed);
831
+ }
832
+ @media (prefers-color-scheme: light) {
833
+ .examples-section .gr-examples-table {
834
+ border: 1px solid var(--border-light) !important;
835
+ background: var(--main-content-bg-light) !important;
836
+ box-shadow: inset 0 0 8px rgba(0,0,0,0.05);
837
+ }
838
  }
839
+
840
+ .examples-section .gr-examples-table th,
841
+ .examples-section .gr-examples-table td {
842
+ padding: 1.1rem 1.4rem !important; /* Slightly reduced padding for tighter coupling */
843
+ font-size: 1.05rem !important;
844
+ border: none !important;
845
+ }
846
+ .examples-section .gr-examples-table th {
847
+ background: var(--app-bg-dark) !important; /* Match app background for table header */
848
+ color: var(--text-primary-dark) !important;
849
  font-weight: 600 !important;
850
  text-align: left;
851
+ transition: background var(--transition-speed), color var(--transition-speed);
852
  }
853
+ .examples-section .gr-examples-table td {
854
+ background: var(--main-content-bg-dark) !important;
855
+ color: var(--text-primary-dark) !important;
856
+ border-top: 1px solid var(--border-dark) !important;
857
+ cursor: pointer;
858
+ transition: background var(--transition-speed), color var(--transition-speed), border-color var(--transition-speed);
859
  }
860
+ .examples-section .gr-examples-table tr:hover td {
861
+ background: rgba(255, 193, 7, 0.1) !important; /* Gold tint on hover */
862
  }
863
+ .examples-section .gr-examples-table tr:first-child td { border-top: none !important; }
864
 
865
+ @media (prefers-color-scheme: light) {
866
+ .examples-section .gr-examples-table { border: 1px solid var(--border-light) !important; background: var(--main-content-bg-light) !important; }
867
+ .examples-section .gr-examples-table th { background: var(--app-bg-light) !important; color: var(--text-primary-light) !important; }
868
+ .examples-section .gr-examples-table td { background: var(--main-content-bg-light) !important; color: var(--text-primary-light) !important; border-top: 1px solid var(--border-light) !important; }
869
+ .examples-section .gr-examples-table tr:hover td { background: rgba(0, 123, 255, 0.08) !important; }
 
 
 
 
 
 
 
 
 
870
  }
871
 
872
+
873
+ /* Footer styling: clean and informative, integrated at the very bottom */
874
  .app-footer-wrapper {
875
+ background: var(--header-bg-dark); /* Match header/app background for consistency */
876
+ border-top: 1px solid var(--border-dark) !important;
877
+ margin-top: 5rem; /* Reduced space from last content for cohesion */
878
+ padding-top: 4rem;
879
+ padding-bottom: 4rem;
880
+ border-top-left-radius: var(--radius-lg);
881
+ border-top-right-radius: var(--radius-lg);
882
+ box-shadow: inset 0 8px 15px rgba(0,0,0,0.2); /* Inset shadow for depth */
883
+ transition: background var(--transition-speed), border-color var(--transition-speed), box-shadow var(--transition-speed);
884
  }
885
+ @media (prefers-color-scheme: light) {
886
+ .app-footer-wrapper {
887
+ background: var(--header-bg-light);
888
+ border-top: 1px solid var(--border-light) !important;
889
+ box-shadow: inset 0 6px 12px rgba(0,0,0,0.1);
890
+ }
891
+ }
892
+
893
  .app-footer {
894
+ padding: 0 var(--padding-lg) !important;
895
  text-align: center !important;
896
  display: flex;
897
  flex-direction: column;
898
  align-items: center;
899
  }
900
  .app-footer p {
901
+ font-size: 1.05rem !important;
902
+ color: var(--text-secondary-dark) !important;
903
+ margin-bottom: 1rem;
904
+ max-width: 900px;
905
+ transition: color var(--transition-speed);
906
  }
907
  .app-footer a {
908
+ color: var(--accent-main-dark) !important;
909
  font-weight: 500;
910
  transition: color var(--transition-speed), text-decoration var(--transition-speed);
911
  }
912
  .app-footer a:hover {
913
+ color: var(--accent-hover-dark) !important;
914
  text-decoration: underline;
915
  }
916
+ @media (prefers-color-scheme: light) {
917
+ .app-footer-wrapper { border-top-color: var(--border-light) !important; }
918
+ .app-footer p { color: var(--text-secondary-light) !important; }
919
+ .app-footer a { color: var(--accent-main-light) !important; }
920
+ .app-footer a:hover { color: var(--accent-hover-light) !important; }
921
  }
922
 
923
+ /* Accessibility: Focus styles */
924
  :focus-visible {
925
+ outline: 5px solid var(--accent-main-dark) !important; /* Even thicker for accessibility */
926
+ outline-offset: 5px;
927
+ box-shadow: 0 0 0 8px var(--focus-ring-dark) !important;
928
+ border-radius: var(--radius-md) !important; /* Ensure border-radius for focus */
929
  }
930
+ @media (prefers-color-scheme: light) {
931
  :focus-visible {
932
+ outline-color: var(--accent-main-light) !important;
933
+ box_shadow: 0 0 0 8px var(--focus-ring-light) !important;
934
  }
935
  }
 
936
  .gradio-button span:focus { outline: none !important; }
937
 
938
+ /* Gradio Overrides for full control - PERMANENTLY HIDE UNWANTED LABELS */
939
+ .gradio-container > .flex { gap: 0 !important; }
940
+ .gradio-markdown > *:first-child { margin-top: 0; }
941
+ .gradio-markdown > *:last-child { margin-bottom: 0; }
 
 
942
  .gradio-dropdown, .gradio-textbox { border: none !important; padding: 0 !important; background: transparent !important; }
943
+
944
+ /* MOST AGGRESSIVE "FALSE" REMOVAL - GRADIO'S INTERNAL LABELS ARE PURE EVIL */
945
+ /* These cover various Gradio versions and nesting patterns */
946
+ .gr-box.gr-component.gradio-example { position: relative !important; } /* Needed for absolute positioning if child is default label */
947
+ .gr-examples .gradio-html div[dir="auto"].primary span { display: none !important; } /* Hides "false" directly */
948
+ .gr-examples-header { display: none !important; } /* Hides default Gradio example header */
949
+ .gr-examples .label-wrap { display: none !important; } /* Targets another common label wrapper */
950
+ .gr-label { display: none !important; } /* General label suppression for Gradio 4.0+ if it's generic */
951
+
952
+
953
+ /* Responsive Adjustments (meticulously refined) */
954
+ @media (max-width: 1024px) {
955
+ .gradio-container > .flex.flex-col { max-width: 960px; padding: 0 1.5rem !important; }
956
+ .app-header-title { font-size: 3.8rem; }
957
+ .app-header-tagline { font-size: 1.5rem; }
958
+ .app-header-wrapper { margin-bottom: calc(-1 * var(--radius-md)); /* Smaller radius for smaller screens */ }
959
+ .main-content-area { padding: var(--padding-lg) var(--padding-lg) !important; border-top-left-radius: var(--radius-md); border-top-right-radius: var(--radius-md); }
960
+ .main-content-area { padding-top: calc(var(--padding-lg) + var(--radius-md)); }
961
+ .section-title { font-size: 2.2rem !important; margin-bottom: 3rem !important; }
962
+ .sub-section-title { font-size: 1.8rem !important; margin-top: 3rem !important; margin-bottom: 1.5rem !important; }
963
+ .section-divider { margin: 3.5rem 0; }
964
+ .input-row { gap: 2.5rem; }
965
+ .input-field { min-width: 300px; }
966
+ .gradio-textbox textarea { min-height: 160px; }
967
+ .output-card .response-header { font-size: 1.7rem; }
968
+ .examples-section { padding-top: 4rem; }
969
+ .examples-section .gr-examples-table th, .examples-section .gr-examples-table td { padding: 1.1rem 1.4rem !important; }
970
+ .app-footer-wrapper { margin-top: 4rem; border-top-left-radius: var(--radius-md); border-top-right-radius: var(--radius-md); }
971
  }
972
 
973
  @media (max-width: 768px) {
974
+ .gradio-container > .flex.flex-col { padding: 0 1rem !important; }
975
+ .app-header-wrapper { padding: var(--padding-md) var(--padding-md) !important; border-bottom-left-radius: var(--radius-md); border-bottom-right-radius: var(--radius-md); }
976
+ .app-header-logo { font-size: 4.5rem; margin-bottom: 1rem; }
977
+ .app-header-title { font-size: 3.2rem; letter-spacing: -0.06em; }
978
+ .app-header-tagline { font-size: 1.3rem; }
979
+ .app-header-wrapper { margin-bottom: calc(-1 * var(--radius-md)); }
980
+ .main-content-area { padding: var(--padding-md) var(--padding-md) !important; border-radius: var(--radius-md); border-top-left-radius: var(--radius-md); border-top-right-radius: var(--radius-md); }
981
+ .main-content-area { padding-top: calc(var(--padding-md) + var(--radius-md)); }
982
+ .section-title { font-size: 2rem !important; margin-bottom: 2.5rem !important; padding-bottom: 1.2rem !important; }
983
+ .sub-section-title { font-size: 1.6rem !important; margin-top: 3rem !important; margin-bottom: 1.5rem !important; }
984
+ .section-divider { margin: 3rem 0; }
985
+ .input-row { flex-direction: column; gap: 2rem; }
986
  .input-field { min-width: 100%; }
987
+ .gradio-textbox textarea { min-height: 140px; }
988
+ .button-row { justify-content: stretch; gap: 1.5rem; }
989
+ .gradio-button { width: 100%; padding: 1.1rem 2rem !important; font-size: 1.1rem !important; }
990
+ .output-card .response-header { font-size: 1.5rem; }
991
+ .output-card .response-icon { font-size: 1.7rem; }
992
+ .output-card .placeholder { padding: 4rem 1.5rem; font-size: 1.2rem; }
993
+ .examples-section { padding-top: 3rem; }
994
+ .examples-section .gr-examples-table th, .examples-section .gr-examples-table td { padding: 1rem 1.2rem !important; font-size: 1.0rem !important; }
995
+ .app-footer-wrapper { margin-top: 3.5rem; padding-top: 2.5rem; padding-bottom: 2.5rem; border-top-left-radius: var(--radius-md); border-top-right-radius: var(--radius-md); }
996
  }
997
 
998
  @media (max-width: 480px) {
999
+ .gradio-container > .flex.flex-col { padding: 0 0.8rem !important; }
1000
+ .app-header-wrapper { padding: var(--padding-sm) 1rem !important; border-bottom-left-radius: var(--radius-sm); border-bottom-right-radius: var(--radius-sm); }
1001
+ .app-header-logo { font-size: 3.8rem; margin-bottom: 0.8rem; }
1002
+ .app-header-title { font-size: 2.8rem; }
1003
+ .app-header-tagline { font-size: 1.1rem; }
1004
+ .app-header-wrapper { margin-bottom: calc(-1 * var(--radius-sm)); }
1005
+ .main-content-area { padding: var(--padding-sm) 1rem !important; border-radius: var(--radius-sm); border-top-left-radius: var(--radius-sm); border-top-right-radius: var(--radius-sm); }
1006
+ .main-content-area { padding-top: calc(var(--padding-sm) + var(--radius-sm)); }
1007
+ .section-title { font-size: 1.8rem !important; margin-bottom: 2rem !important; padding-bottom: 1rem !important; }
1008
+ .sub-section-title { font-size: 1.4rem !important; margin-top: 2.5rem !important; margin-bottom: 1.2rem !important; }
1009
+ .section-divider { margin: 2.5rem 0; }
1010
+ .gradio-textbox textarea, .gradio-dropdown select, .gradio-textbox input[type=password] { font-size: 1.05rem !important; padding: 1rem 1.2rem !important; }
1011
+ .gradio-textbox textarea { min-height: 120px; }
1012
+ .gradio-button { padding: 1rem 1.5rem !important; font-size: 1rem !important; }
1013
+ .output-card .response-header { font-size: 1.4rem; }
1014
+ .output-card .response-icon { font-size: 1.5rem; }
1015
+ .output-card .placeholder { padding: 3.5rem 1rem; font-size: 1.1rem; }
1016
+ .examples-section { padding-top: 2.5rem; }
1017
+ .examples-section .gr-examples-table th, .examples-section .gr-examples-table td { padding: 0.8rem 1rem !important; font-size: 0.95rem !important; }
1018
+ .app-footer-wrapper { margin-top: 3rem; padding-top: 2rem; padding-bottom: 2rem; border-top-left-radius: var(--radius-sm); border-top-right-radius: var(--radius-sm); }
1019
  }
1020
  """
1021
 
1022
  with gr.Blocks(theme=None, css=custom_css, title="Landlord-Tenant Rights Assistant") as demo:
1023
+ # --- Header Section: Truly dynamic and bold, with animations ---
1024
  with gr.Group(elem_classes="app-header-wrapper"):
1025
  gr.Markdown(
1026
  """
 
1032
  """
1033
  )
1034
 
1035
+ # --- Main Content Area: A single, unified block containing all core functionality ---
1036
+ # This is the key change for cohesion. All inner sections are now part of this one group.
1037
+ with gr.Group(elem_classes="main-content-area"):
1038
+
1039
+ # "Know Your Rights" Section
1040
  gr.Markdown("<h3 class='section-title'>Know Your Rights</h3>")
1041
  gr.Markdown(
1042
  """
 
1046
  """
1047
  )
1048
 
1049
+ gr.HTML("<hr class='section-divider'>") # Aesthetic divider for internal separation
1050
+
1051
+ # "Ask Your Question" Section (Input Form)
1052
+ gr.Markdown("<h3>Ask Your Question</h3>", elem_classes="sub-section-title")
1053
  with gr.Column(elem_classes="input-field-group"):
1054
  api_key_input = gr.Textbox(
1055
  label="OpenAI API Key", type="password", placeholder="Enter your API key (e.g., sk-...)",
1056
  info="Required to process your query. Securely used per request, not stored.", lines=1
1057
  )
1058
  with gr.Row(elem_classes="input-row"):
1059
+ with gr.Column(elem_classes="input-field", min_width="58%"):
1060
  query_input = gr.Textbox(
1061
  label="Your Question", placeholder="E.g., What are the rules for security deposit returns in my state?",
1062
  lines=5, max_lines=10
1063
  )
1064
+ with gr.Column(elem_classes="input-field", min_width="38%"):
1065
  state_input = gr.Dropdown(
1066
  label="Select State", choices=dropdown_choices, value=initial_value,
1067
  allow_custom_value=False
 
1070
  clear_button = gr.Button("Clear", variant="secondary", elem_classes=["gr-button-secondary"])
1071
  submit_button = gr.Button("Submit Query", variant="primary", elem_classes=["gr-button-primary"])
1072
 
1073
+ gr.HTML("<hr class='section-divider'>") # Another divider for separation
1074
+
1075
+ # Output Section
1076
+ gr.Markdown("<h3>Answer</h3>", elem_classes="sub-section-title")
1077
  output = gr.Markdown(
1078
+ value="<div class='placeholder output-card'>Your answer will appear here after submitting your query.</div>",
1079
+ elem_classes="output-content-wrapper output-card" # Apply these classes for styling
1080
  )
1081
 
1082
+ # --- "Explore Sample Questions" Section: Integrated within the main unified block ---
1083
+ # Fixed: Wrap gr.Examples in a gr.Column to apply elem_classes correctly.
1084
+ with gr.Column(elem_classes="examples-section"): # Apply 'examples-section' class to this wrapper
1085
+ gr.Markdown("<h3>Explore Sample Questions</h3>", elem_classes="sub-section-title")
1086
+ if example_queries:
1087
+ gr.Examples(
1088
+ examples=example_queries, inputs=[query_input, state_input],
1089
+ examples_per_page=5,
1090
+ label=False, # This is crucial to hide the default "false" label
1091
+ )
1092
+ else:
1093
+ gr.Markdown("<div class='placeholder'>Sample questions could not be loaded.</div>")
1094
 
1095
+ # --- Footer Section: Designed to blend harmoniously with header's aesthetic ---
1096
+ # It matches the header's background, creating a top-bottom "frame" around the main content.
1097
  with gr.Group(elem_classes="app-footer-wrapper"):
1098
  gr.Markdown(
1099
  """
 
1106
  """
1107
  )
1108
 
1109
+ # --- Event Listeners (Logic remains identical) ---
1110
  submit_button.click(
1111
  fn=query_interface_wrapper, inputs=[api_key_input, query_input, state_input], outputs=output, api_name="submit_query"
1112
  )
 
1115
  "", # Clear API key input
1116
  "", # Clear query input
1117
  initial_value, # Reset state dropdown to initial value
1118
+ "<div class='placeholder output-card'>Inputs cleared. Ready for your next question.</div>" # Reset output to placeholder
1119
  ),
1120
  inputs=[], outputs=[api_key_input, query_input, state_input, output]
1121
  )
1122
+ logging.info("Fully cohesive, dynamic, and legible Gradio interface created with Legal Noir theme.")
1123
  return demo
1124
 
1125
  # --- Main Execution Block (remains untouched from original logic) ---
 
1127
  logging.info("Starting Landlord-Tenant Rights Bot application...")
1128
  try:
1129
  SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
1130
+ DEFAULT_PDF_PATH = os.path.join(SCRIPT_DIR, "data/tenant-landlord.pdf")
1131
+ DEFAULT_DB_PATH = os.path.join(SCRIPT_DIR, "data/chroma_db")
1132
 
1133
  # Use environment variables if set, otherwise default paths
1134
  PDF_PATH = os.getenv("PDF_PATH", DEFAULT_PDF_PATH)
 
1136
 
1137
  # Ensure directories exist
1138
  os.makedirs(os.path.dirname(VECTOR_DB_PATH), exist_ok=True)
 
 
 
1139
 
1140
+ # Validate PDF file existence and readability before proceeding
1141
+ logging.info(f"Attempting to load PDF from: {PDF_PATH}")
1142
  if not os.path.exists(PDF_PATH):
1143
  logging.error(f"FATAL: PDF file not found at the specified path: {PDF_PATH}")
1144
+ print(f"\n--- CONFIGURATION ERROR ---\nPDF file ('{os.path.basename(PDF_PATH)}') not found at: {PDF_PATH}.\nPlease ensure it exists or set 'PDF_PATH' environment variable.\n---------------------------\n")
1145
+ exit(1)
1146
+
1147
+ if not os.access(PDF_PATH, os.R_OK):
1148
+ logging.error(f"FATAL: PDF file at '{PDF_PATH}' exists but is not readable. Check file permissions.")
1149
+ print(f"\n--- PERMISSION ERROR ---\nPDF file ('{os.path.basename(PDF_PATH)}') found but not readable at: {PDF_PATH}\nPlease check file permissions (e.g., using 'chmod +r' in terminal).\n---------------------------\n")
1150
  exit(1)
1151
 
1152
+ logging.info(f"PDF file '{os.path.basename(PDF_PATH)}' found and is readable.")
1153
+
1154
  # Initialize Vector Database and RAG System
1155
  vector_db_instance = VectorDatabase(persist_directory=VECTOR_DB_PATH)
1156
  rag = RAGSystem(vector_db=vector_db_instance)