Oviya commited on
Commit
b509c12
·
1 Parent(s): 0c1769d
src/app/case-details-page/case-details-page.component.css CHANGED
@@ -1,9 +1,5 @@
1
  @import '../recordpage/recordpage.component.css';
2
 
3
- body, html {
4
- overflow: auto !important;
5
- }
6
-
7
  body, main.content {
8
  background: #f4f6fa;
9
  min-height: 100vh;
@@ -425,15 +421,6 @@ hr {
425
  max-width: 320px;
426
  }
427
 
428
- .next-action-col {
429
- text-align: left;
430
- min-width: 120px;
431
- padding-left: 0;
432
- padding-right: 0;
433
- font-weight: 500;
434
- color: #2563eb;
435
- }
436
-
437
  @media (max-width: 700px) {
438
  .actions .btn {
439
  min-width: 120px;
@@ -462,49 +449,19 @@ hr {
462
  }
463
  }
464
 
465
- /* table layout for case details page */
466
- .record-table {
 
467
  width: 100%;
468
- table-layout: auto;
469
- border-collapse: collapse;
470
- overflow-x: hidden;
471
- box-sizing: border-box;
472
- }
473
-
474
- .record-table th, .record-table td {
475
- padding-left: 12px;
476
- padding-right: 12px;
477
- word-break: break-word;
478
- white-space: normal;
479
- box-sizing: border-box;
480
- border-bottom: 1px solid #e5e7eb; /* consistent row border */
481
- }
482
-
483
- .record-table tr:last-child td {
484
- border-bottom: none;
485
  }
486
-
487
- th.actions, td.actions {
488
- text-align: left;
489
- padding-left: 0;
490
- padding-right: 0;
491
- }
492
-
493
- td.actions {
494
  vertical-align: middle;
495
- }
496
-
497
- .icon-btn.view {
498
- margin: 0;
499
- padding: 0;
500
- background: none;
501
- border: none;
502
- cursor: pointer;
503
- color: #2563eb;
504
- font-size: 1.4em;
505
- display: flex;
506
- align-items: center;
507
- justify-content: flex-start;
508
  }
509
 
510
  .custom-active-cases-label {
@@ -518,353 +475,4 @@ td.actions {
518
  right: 32vw;
519
  }
520
 
521
- .filter-bar select,
522
- .filter-bar .filter-date {
523
- padding: 6px 18px;
524
- border-radius: 6px;
525
- border: 1.5px solid #cbd5e1;
526
- font-size: 1em;
527
- color: #2563eb;
528
- background: #fff;
529
- font-weight: 600;
530
- outline: none;
531
- transition: border 0.15s;
532
- min-width: 160px;
533
- margin-right: 4px;
534
- }
535
- .filter-bar select:focus,
536
- .filter-bar .filter-date:focus {
537
- border: 1.5px solid #38bdf8;
538
- }
539
- .date-group {
540
- display: inline-flex;
541
- align-items: center;
542
- font-family: inherit;
543
- color: #a86a00;
544
- font-size: 1.08em;
545
- font-weight: 500;
546
- margin-right: 8px;
547
- gap: 2px;
548
- }
549
- .date-label {
550
- margin: 0 4px 0 4px;
551
- display: inline-flex;
552
- align-items: center;
553
- gap: 2px;
554
- }
555
- .calendar-ico {
556
- font-size: 1.1em;
557
- margin-left: 2px;
558
- vertical-align: middle;
559
- }
560
- .filter-date {
561
- border: none;
562
- background: transparent;
563
- color: #a86a00;
564
- font-size: 1em;
565
- font-weight: 600;
566
- outline: none;
567
- min-width: 90px;
568
- margin-left: 2px;
569
- }
570
- .filter-date::-webkit-input-placeholder { color: #a86a00; }
571
- .filter-date:-moz-placeholder { color: #a86a00; }
572
- .filter-date::-moz-placeholder { color: #a86a00; }
573
- .filter-date:-ms-input-placeholder { color: #a86a00; }
574
-
575
- .fullpage-details {
576
- width: 100vw;
577
- min-height: 100vh;
578
- background: #f8fafc;
579
- padding: 32px 0 32px 0;
580
- position: relative;
581
- z-index: 1;
582
- }
583
- .details-content {
584
- max-width: 1200px;
585
- margin: 0 auto;
586
- background: #fff;
587
- border-radius: 18px;
588
- box-shadow: 0 8px 32px rgba(30,41,59,0.12);
589
- padding: 32px 48px;
590
- }
591
- .btn.back-btn {
592
- margin: 0 0 24px 0;
593
- background: #64748b;
594
- color: #fff;
595
- border-radius: 8px;
596
- font-weight: 600;
597
- font-size: 1.1rem;
598
- padding: 10px 28px;
599
- border: none;
600
- cursor: pointer;
601
- }
602
-
603
- .fullpage-popup-overlay {
604
- position: fixed;
605
- top: 0; left: 0; right: 0; bottom: 0;
606
- width: 100vw;
607
- height: 100vh;
608
- background: #f8fafc;
609
- z-index: 9999;
610
- display: flex;
611
- align-items: flex-start;
612
- justify-content: center;
613
- overflow-y: auto;
614
- overscroll-behavior: contain;
615
- }
616
- body.popup-open {
617
- overflow: hidden !important;
618
- }
619
-
620
- .fullpage-popup-content {
621
- background: #fff;
622
- border-radius: 18px;
623
- box-shadow: 0 8px 32px rgba(30,41,59,0.18);
624
- margin: 40px 0;
625
- max-width: 1200px;
626
- width: 90vw;
627
- min-height: 80vh;
628
- padding: 32px 48px;
629
- position: relative;
630
- }
631
-
632
- /* --- Section Card Styles --- */
633
- .details-section-card {
634
- background: #fff;
635
- border-radius: 22px;
636
- box-shadow: 0 4px 24px rgba(30,41,59,0.10);
637
- border-left: 6px solid #38bdf8;
638
- border-right: 2px solid #e0f2fe;
639
- padding: 32px 36px 32px 36px;
640
- margin-bottom: 0;
641
- margin-top: 32px;
642
- animation: fadeInUp 0.6s cubic-bezier(.23,1.01,.32,1) both;
643
- }
644
- @keyframes fadeInUp {
645
- from { opacity: 0; transform: translateY(32px); }
646
- to { opacity: 1; transform: translateY(0); }
647
- }
648
-
649
- .section-title {
650
- font-size: 1.5rem;
651
- font-weight: 700;
652
- color: #2563eb;
653
- margin-bottom: 18px;
654
- letter-spacing: 0.5px;
655
- }
656
-
657
- .subgroup-pills {
658
- display: flex;
659
- gap: 18px;
660
- margin-bottom: 28px;
661
- flex-wrap: wrap;
662
- }
663
- .subgroup-pills button {
664
- background: linear-gradient(90deg, #2563eb 0%, #38bdf8 100%);
665
- color: #fff;
666
- font-weight: 700;
667
- border: none;
668
- border-radius: 22px;
669
- padding: 10px 32px;
670
- font-size: 1.08em;
671
- box-shadow: 0 2px 12px rgba(56,189,248,0.13);
672
- cursor: pointer;
673
- transition: background 0.18s, box-shadow 0.18s, transform 0.18s;
674
- outline: none;
675
- margin-bottom: 4px;
676
- }
677
- .subgroup-pills button.active,
678
- .subgroup-pills button:focus {
679
- background: linear-gradient(90deg, #38bdf8 0%, #2563eb 100%);
680
- box-shadow: 0 4px 16px rgba(56,189,248,0.18);
681
- transform: translateY(-2px) scale(1.04);
682
- }
683
-
684
- .fields-table-2col {
685
- display: flex;
686
- flex-direction: row;
687
- gap: 0;
688
- margin-top: 8px;
689
- margin-bottom: 8px;
690
- }
691
- .fields-col {
692
- display: flex;
693
- flex-direction: column;
694
- gap: 6px;
695
- }
696
- .fields-col-labels {
697
- min-width: 260px;
698
- text-align: left;
699
- }
700
- .fields-col-values {
701
- min-width: 220px;
702
- text-align: right;
703
- }
704
- .field-label {
705
- color: #22223b;
706
- font-weight: 500;
707
- font-size: 1.08em;
708
- padding: 2px 0;
709
- }
710
- .field-value {
711
- color: #22223b;
712
- font-weight: 700;
713
- font-size: 1.08em;
714
- padding: 2px 0;
715
- letter-spacing: 0.5px;
716
- }
717
-
718
- /* --- Card Container and Title --- */
719
- .case-details-title {
720
- font-size: 2.2rem;
721
- font-weight: 700;
722
- color: #22223b;
723
- margin-bottom: 32px;
724
- margin-left: 8px;
725
- display: flex;
726
- align-items: center;
727
- justify-content: space-between;
728
- position: relative;
729
- }
730
-
731
- .btn.close-btn {
732
- background: none;
733
- color: #64748b;
734
- border: none;
735
- font-size: 2.2rem;
736
- font-weight: 700;
737
- cursor: pointer;
738
- position: absolute;
739
- right: 0;
740
- top: 0;
741
- line-height: 1;
742
- padding: 0 16px;
743
- transition: color 0.15s;
744
- }
745
- .btn.close-btn:hover {
746
- color: #2563eb;
747
- }
748
-
749
- .btn.close-btn-bottom {
750
- position: absolute;
751
- right: 32px;
752
- top: 32px;
753
- background: #2563eb;
754
- color: #fff;
755
- border: none;
756
- border-radius: 50%;
757
- width: 48px;
758
- height: 48px;
759
- font-size: 2.2rem;
760
- font-weight: 700;
761
- box-shadow: 0 4px 16px rgba(56,189,248,0.18);
762
- cursor: pointer;
763
- z-index: 10001;
764
- display: flex;
765
- align-items: center;
766
- justify-content: center;
767
- transition: background 0.18s, color 0.18s, box-shadow 0.18s;
768
- }
769
- .btn.close-btn-bottom:hover {
770
- background: #38bdf8;
771
- color: #22223b;
772
- }
773
-
774
- .progress-col {
775
- text-align: left;
776
- min-width: 90px;
777
- padding-left: 0;
778
- padding-right: 0;
779
- }
780
-
781
- .progress-dot {
782
- width: 18px;
783
- height: 18px;
784
- border-radius: 50%;
785
- display: inline-block;
786
- margin-right: 6px;
787
- vertical-align: middle;
788
- box-shadow: 0 2px 8px rgba(56,189,248,0.10);
789
- }
790
- .progress-dot.blue {
791
- background: linear-gradient(135deg, #2563eb 0%, #38bdf8 100%);
792
- }
793
- .progress-dot.green {
794
- background: linear-gradient(135deg, #34d399 0%, #6ee7b7 100%);
795
- }
796
- .progress-check {
797
- font-size: 1.2em;
798
- color: #34d399;
799
- background: #d1fae5;
800
- border-radius: 4px;
801
- padding: 2px 4px;
802
- display: inline-block;
803
- margin-right: 6px;
804
- vertical-align: middle;
805
- }
806
- .progress-value {
807
- font-weight: 700;
808
- font-size: 1em;
809
- color: #22223b;
810
- vertical-align: middle;
811
- }
812
-
813
- .priority-pill {
814
- display: inline-flex;
815
- align-items: center;
816
- font-weight: bold;
817
- font-size: 0.98em;
818
- padding: 2px 12px 2px 8px;
819
- border-radius: 16px;
820
- margin-right: 2px;
821
- letter-spacing: 0.02em;
822
- }
823
- .priority-high {
824
- background: #fee2e2;
825
- color: #b91c1c;
826
- }
827
- .priority-medium {
828
- background: #fef9c3;
829
- color: #ca8a04;
830
- }
831
- .priority-low {
832
- background: #dcfce7;
833
- color: #15803d;
834
- }
835
-
836
- .evidence-upload-section {
837
- margin-top: 32px;
838
- padding: 16px;
839
- background: #f3f4f6;
840
- border-radius: 12px;
841
- box-shadow: 0 1px 4px rgba(0,0,0,0.04);
842
- }
843
- .evidence-upload-section h3 {
844
- margin-bottom: 12px;
845
- font-size: 1.1em;
846
- color: #2563eb;
847
- }
848
- .evidence-list {
849
- margin-top: 10px;
850
- }
851
- .evidence-file {
852
- display: flex;
853
- align-items: center;
854
- font-size: 0.98em;
855
- margin-bottom: 6px;
856
- color: #374151;
857
- }
858
- .evidence-file i {
859
- margin-right: 8px;
860
- color: #2563eb;
861
- }
862
-
863
-
864
-
865
-
866
-
867
-
868
-
869
-
870
 
 
1
  @import '../recordpage/recordpage.component.css';
2
 
 
 
 
 
3
  body, main.content {
4
  background: #f4f6fa;
5
  min-height: 100vh;
 
421
  max-width: 320px;
422
  }
423
 
 
 
 
 
 
 
 
 
 
424
  @media (max-width: 700px) {
425
  .actions .btn {
426
  min-width: 120px;
 
449
  }
450
  }
451
 
452
+ /* Make all table columns equal width */
453
+ .records {
454
+ table-layout: fixed;
455
  width: 100%;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456
  }
457
+ .records th,
458
+ .records td {
459
+ width: 16.66%; /* 6 columns, 100/6 = 16.66% */
460
+ text-align: center;
 
 
 
 
461
  vertical-align: middle;
462
+ white-space: nowrap;
463
+ overflow: hidden;
464
+ text-overflow: ellipsis;
 
 
 
 
 
 
 
 
 
 
465
  }
466
 
467
  .custom-active-cases-label {
 
475
  right: 32vw;
476
  }
477
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
478
 
src/app/case-details-page/case-details-page.component.html CHANGED
@@ -43,69 +43,30 @@
43
  <div class="summary-label">Closed</div>
44
  <div class="summary-value">{{ closedCases }}</div>
45
  </div>
46
- <div class="summary-card review">
47
- <div class="summary-label">Pending Review</div>
48
- <div class="summary-value">{{ reviewCases }}</div>
49
- </div>
50
  </div>
51
 
52
  <div class="record-meta" style="padding: 8px 24px 0 24px; color: #6b7280; font-size: 0.98em;">
53
  {{ filteredCases.length }} items • Updated a few seconds ago
54
  </div>
55
 
56
- <div class="filter-bar">
57
- <select [(ngModel)]="filterStatus">
58
- <option value="">Status</option>
59
- <option *ngFor="let status of statusTypes">{{ status }}</option>
60
- </select>
61
- <select [(ngModel)]="filterCrimeType">
62
- <option value="">Crime Type</option>
63
- <option *ngFor="let type of crimeTypes">{{ type }}</option>
64
- </select>
65
- <button (click)="applyFilters()">Apply</button>
66
- <button (click)="resetFilters()">Reset</button>
67
- </div>
68
-
69
- <!-- Table/list view always visible -->
70
  <table class="record-table">
71
  <thead>
72
  <tr>
73
  <th>#</th>
74
  <th>Case ID</th>
75
- <th>Priority</th>
76
  <th>Status</th>
77
  <th>Crime Type</th>
78
  <th>Date &amp; Time</th>
79
  <th>Location</th>
80
  <th>Suspect Name</th>
81
  <th>Last Updated</th>
82
- <th class="progress-col">Progress</th>
83
- <th class="next-action-col">Next Action</th>
84
- <th class="actions">Actions</th>
85
  </tr>
86
  </thead>
87
  <tbody>
88
  <tr *ngFor="let c of filteredCases; let i = index">
89
  <td>{{ i + 1 }}</td>
90
- <td class="mono">
91
- <a (click)="openDetails(c)" style="cursor:pointer; color:#2563eb; text-decoration:underline;">
92
- {{ c.caseId || '—' }}
93
- </a>
94
- </td>
95
- <td>
96
- <ng-container [ngSwitch]="getCasePriority(c)">
97
- <span *ngSwitchCase="'High'" class="priority-pill priority-high" title="High Priority">
98
- 🔴 High
99
- </span>
100
- <span *ngSwitchCase="'Medium'" class="priority-pill priority-medium" title="Medium Priority">
101
- 🟡 Medium
102
- </span>
103
- <span *ngSwitchCase="'Low'" class="priority-pill priority-low" title="Low Priority">
104
- 🟢 Low
105
- </span>
106
- <span *ngSwitchDefault style="color:#6b7280;">—</span>
107
- </ng-container>
108
- </td>
109
  <td>
110
  <span class="status-label"
111
  [ngClass]="{
@@ -118,117 +79,41 @@
118
  </td>
119
  <td>{{ c.crime || '—' }}</td>
120
  <td>{{ c.dateTime ? (c.dateTime | date:'M/d/yyyy HH:mm') : '—' }}</td>
121
- <td>{{ c.police.address || '—' }}</td>
122
- <td>{{ c.accused.name || '—' }}</td>
123
  <td>{{ c.lastUpdated ? (c.lastUpdated | date:'M/d/yyyy HH:mm') : '—' }}</td>
124
- <td class="progress-col">
125
- <ng-container [ngSwitch]="getProgressValue(c)">
126
- <ng-container *ngSwitchCase="100">
127
- <span class="progress-check">&#x2714;</span>
128
- <span class="progress-value">100%</span>
129
- </ng-container>
130
- <ng-container *ngSwitchCase="75">
131
- <span class="progress-dot green"></span>
132
- <span class="progress-value">75%</span>
133
- </ng-container>
134
- <ng-container *ngSwitchDefault>
135
- <span class="progress-dot blue"></span>
136
- <span class="progress-value">{{ getProgressValue(c) }}%</span>
137
- </ng-container>
138
- </ng-container>
139
- </td>
140
- <td class="next-action-col">
141
- {{ getNextActionMessage(c) }}
142
- </td>
143
  <td class="actions">
144
- <button type="button" class="icon-btn view" (click)="openDetails(c)" title="View Case Details" aria-label="View Case Details">
145
  <i class="fas fa-eye"></i>
146
  </button>
147
- <button *ngIf="isInvestigator()" type="button" class="icon-btn upload" (click)="showEvidencePanel(c)" title="Upload Evidence" aria-label="Upload Evidence">
148
- <i class="fas fa-upload"></i>
149
- </button>
150
  </td>
151
  </tr>
152
  <tr *ngIf="filteredCases.length === 0">
153
- <td colspan="12" class="empty">No records found.</td>
154
  </tr>
155
  </tbody>
156
  </table>
 
157
 
158
- <!-- Evidence Upload Section for Investigators only, below the table -->
159
- <div *ngIf="isInvestigator() && selectedCase" class="evidence-upload-section">
160
- <h3>Upload Evidence for Case: {{ selectedCase.caseId }}</h3>
161
- <input type="file" multiple (change)="onEvidenceUpload($event)" />
162
- <div class="evidence-list" *ngIf="uploadedEvidence.length">
163
- <div *ngFor="let file of uploadedEvidence" class="evidence-file">
164
- <i class="fas fa-file-upload"></i> {{ file.name }}
165
- </div>
166
- </div>
167
  </div>
168
-
169
- <!-- Evidence Upload Panel for selected case -->
170
- <div *ngIf="isInvestigator() && evidencePanelCase && evidencePanelCase.caseId" class="evidence-upload-section">
171
- <hr class="evidence-hr" />
172
- <div class="evidence-title">
173
- <i class="fas fa-folder-open evidence-folder"></i>
174
- Evidence Upload for Case: {{ evidencePanelCase.caseId }}
175
- </div>
176
- <hr class="evidence-hr" />
177
- <div class="evidence-type-tabs">
178
- <button [class.active]="evidenceType === 'Document'" (click)="setEvidenceType('Document')">Document</button>
179
- <button [class.active]="evidenceType === 'Photo'" (click)="setEvidenceType('Photo')">Photo</button>
180
- </div>
181
- <div class="evidence-actions">
182
- <label class="evidence-file-label">
183
- [Choose File]
184
- <input type="file" multiple (change)="onEvidenceFileSelectType($event)" style="display:none;" />
185
- </label>
186
- </div>
187
- <hr class="evidence-hr" />
188
- <div class="evidence-list-block">
189
- <div class="evidence-list-title">Uploaded Evidence ({{ evidenceType }}):</div>
190
- <div *ngFor="let file of evidenceFiles[evidencePanelCase.caseId][evidenceType]" class="evidence-file-row">
191
- <i [ngClass]="getEvidenceIcon(file.name)" class="evidence-file-icon"></i>
192
- <span class="evidence-file-name">{{ file.name }}</span>
193
- <a class="evidence-view-link" href="#" (click)="viewEvidenceFile(file)">(View)</a>
194
- </div>
195
- </div>
196
- <hr class="evidence-hr" />
197
  </div>
198
-
199
- <!-- Full-page overlay for details (no evidence upload here) -->
200
- <div *ngIf="selectedCase" class="fullpage-popup-overlay">
201
- <div class="fullpage-popup-content">
202
- <div class="case-details-title">Case Details</div>
203
- <div class="details-sections">
204
- <ng-container *ngFor="let sectionKey of ['crime', 'suspect', 'notes']">
205
- <div class="details-section-card">
206
- <div class="section-title">{{ sections[sectionKey].title }}</div>
207
- <div class="subgroup-pills">
208
- <button *ngFor="let subgroup of getSubgroups(sectionKey)"
209
- [class.active]="selectedSubgroup[sectionKey] === subgroup"
210
- (click)="selectSubgroup(sectionKey, subgroup)">
211
- {{ subgroup }}
212
- </button>
213
- </div>
214
- <div class="fields-table-2col">
215
- <div class="fields-col fields-col-labels">
216
- <div class="field-label" *ngFor="let field of getFieldsForSubgroup(sectionKey, selectedSubgroup[sectionKey])">
217
- {{ field }}
218
- </div>
219
- </div>
220
- <div class="fields-col fields-col-values">
221
- <div class="field-value" *ngFor="let field of getFieldsForSubgroup(sectionKey, selectedSubgroup[sectionKey])">
222
- {{ getFieldValue(selectedCase, sectionKey, field) }}
223
- </div>
224
- </div>
225
- </div>
226
- </div>
227
- </ng-container>
228
- </div>
229
- <button class="btn close-btn-bottom" (click)="closeDetails()" title="Close">&times;</button>
230
- </div>
231
  </div>
232
  </div>
233
- <!-- End of record-card -->
234
 
 
43
  <div class="summary-label">Closed</div>
44
  <div class="summary-value">{{ closedCases }}</div>
45
  </div>
 
 
 
 
46
  </div>
47
 
48
  <div class="record-meta" style="padding: 8px 24px 0 24px; color: #6b7280; font-size: 0.98em;">
49
  {{ filteredCases.length }} items • Updated a few seconds ago
50
  </div>
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  <table class="record-table">
53
  <thead>
54
  <tr>
55
  <th>#</th>
56
  <th>Case ID</th>
 
57
  <th>Status</th>
58
  <th>Crime Type</th>
59
  <th>Date &amp; Time</th>
60
  <th>Location</th>
61
  <th>Suspect Name</th>
62
  <th>Last Updated</th>
63
+ <th>Actions</th>
 
 
64
  </tr>
65
  </thead>
66
  <tbody>
67
  <tr *ngFor="let c of filteredCases; let i = index">
68
  <td>{{ i + 1 }}</td>
69
+ <td class="mono">{{ c.caseId || '—' }}</td>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  <td>
71
  <span class="status-label"
72
  [ngClass]="{
 
79
  </td>
80
  <td>{{ c.crime || '—' }}</td>
81
  <td>{{ c.dateTime ? (c.dateTime | date:'M/d/yyyy HH:mm') : '—' }}</td>
82
+ <td>{{ c.police?.address || '—' }}</td>
83
+ <td>{{ c.accused?.name || '—' }}</td>
84
  <td>{{ c.lastUpdated ? (c.lastUpdated | date:'M/d/yyyy HH:mm') : '—' }}</td>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  <td class="actions">
86
+ <button type="button" class="icon-btn view" (click)="openDetails(c)" title="View Details">
87
  <i class="fas fa-eye"></i>
88
  </button>
 
 
 
89
  </td>
90
  </tr>
91
  <tr *ngIf="filteredCases.length === 0">
92
+ <td colspan="9" class="empty">No records found.</td>
93
  </tr>
94
  </tbody>
95
  </table>
96
+ </div>
97
 
98
+ <!-- Modal white blur overlay for background -->
99
+ <div class="modal-blur-overlay" *ngIf="showDetails"></div>
100
+ <div class="modal" *ngIf="showDetails" role="dialog" aria-modal="true" aria-labelledby="detailsTitle">
101
+ <div class="modal-header">
102
+ <h2 id="detailsTitle">Case Details</h2>
 
 
 
 
103
  </div>
104
+ <div class="modal-body" *ngIf="selectedCase as sc">
105
+ <div class="detail-row"><span>Case ID</span><b>{{ sc.caseId || '—' }}</b></div>
106
+ <div class="detail-row"><span>Status</span><b>{{ sc.status || '—' }}</b></div>
107
+ <div class="detail-row"><span>Crime Type</span><b>{{ sc.crime || '—' }}</b></div>
108
+ <div class="detail-row"><span>Date & Time</span><b>{{ sc.dateTime ? (sc.dateTime | date:'M/d/yyyy HH:mm') : '—' }}</b></div>
109
+ <div class="detail-row"><span>Location</span><b>{{ sc.police.address || '—' }}</b></div>
110
+ <div class="detail-row"><span>Suspect Name</span><b>{{ sc.accused.name || '—' }}</b></div>
111
+ <div class="detail-row"><span>Last Updated</span><b>{{ sc.lastUpdated ? (sc.lastUpdated | date:'M/d/yyyy HH:mm') : '—' }}</b></div>
112
+ <hr />
113
+ <div class="detail-row"><span>Notes / Explanation</span><b>{{ sc.police.information || '—' }}</b></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  </div>
115
+ <div class="modal-footer">
116
+ <button type="button" class="btn" (click)="closeDetails()">Close</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  </div>
118
  </div>
 
119
 
src/app/case-details-page/case-details-page.component.ts CHANGED
@@ -2,8 +2,6 @@ import { Component, OnInit } from '@angular/core';
2
  import { Router } from '@angular/router';
3
  import { CaseStoreService, PoliceCase } from '../shared/case-store.service';
4
 
5
- type EvidenceType = 'Document' | 'Photo';
6
-
7
  @Component({
8
  selector: 'app-case-details-page',
9
  templateUrl: './case-details-page.component.html',
@@ -16,58 +14,6 @@ export class CaseDetailsPageComponent implements OnInit {
16
  username: string = '';
17
  q: string = '';
18
 
19
- filterStatus: string = '';
20
- filterCrimeType: string = '';
21
- filterDateFrom: string = '';
22
- filterDateTo: string = '';
23
-
24
- sections: any = {
25
- crime: {
26
- title: 'Crime Details',
27
- subgroups: {
28
- 'Identification & Timing': ['Case ID', 'FIR / Ref #', 'Crime Type', 'Case Category', 'Date & Time (Entry)', 'Occurred From', 'Occurred To', 'Time Reported', 'Time Discovered', 'Country', 'State', 'District', 'Number of Victims', 'Brief Description'],
29
- 'Location & People': ['Location', 'Jurisdiction / PS', 'Scene Type', 'Reported By', 'Reported Contact', 'Witness Count', 'Victim Name', 'Victim Contact', 'Victim Summary', 'Suspected Offender Known?', 'Suspect Link'],
30
- 'Offence & Context': ['Legal Sections / Charges', 'Offence Category', 'Offence Description', 'Suspected Motive', 'Confirmed Motive', 'Weapon Involved', 'Property Loss / Damage'],
31
- 'Evidence & Scene': ['Evidence Collected', 'Forensic Tests Required', 'Scene Condition', 'Photos / Video?', 'CCTV Present?', 'CCTV Sources / IDs', 'Physical Evidence (list)', 'Chain of Custody?', 'Digital Evidence', 'Evidence Storage Reference'],
32
- 'Operational Notes': ['Investigating Officer', 'Duty Person', 'Supervising Officer', 'Patrol Notes', 'Arrest Made', 'Arrest Location', 'Initial Actions Taken', 'riskLevel', 'Confidentiality'],
33
- 'Status & Linkage': ['Biometric / Forensic IDs', 'DNA Ref ID', 'Fingerprint ID', 'Case Status', 'Linked Cases', 'arrestCount', 'Case Priority', 'Follow-up Date', 'Court Case ID', 'Next Hearing Date', 'Final Summary'],
34
- 'Remark': ['Remark']
35
- }
36
- },
37
- suspect: {
38
- title: 'Suspect Details',
39
- subgroups: {
40
- 'Identity': ['Suspect ID', 'Suspect Name', 'Alias / Nickname', 'Age', 'Gender', 'Nationality', 'Nationality ID / Passport Number', 'Languages', 'Address', 'Known Aliases', 'Government ID'],
41
- 'Physical Description': ['Height (cm)', 'Weight (kg)', 'Build', 'Hair Color', 'Eye Color', 'Distinguishing Marks', 'Tattoo Details', 'Scar Details', 'Photo Upload'],
42
- 'Background': ['Employment', 'Education', 'Occupation', 'Company', 'Workplace Address', 'Marital Status', 'Known Habits', 'Known Financial Details'],
43
- 'Known Associates': ['Associate Names', 'Gang Affiliation', 'Family Connections', 'Social Media Handles'],
44
- 'Prior Records': ['Criminal History', 'Prior Arrests', 'Probation/Parole Status'],
45
- 'Remark': ['Remark']
46
- }
47
- },
48
- notes: {
49
- title: 'Evidence and Documents',
50
- subgroups: {
51
- 'Investigation Notes': ['Initial Findings', 'Detailed Notes', 'Status', 'Version History / Updates'],
52
- 'Evidence Files': ['Evidence Photos', 'Evidence Videos', 'Evidence Documents'],
53
- 'Links and Recommendation': ['Links to Evidence', 'Final Recommendations'],
54
- 'Remark': ['Remark']
55
- }
56
- }
57
- };
58
-
59
- selectedSubgroup: any = {
60
- crime: 'Identification & Timing',
61
- suspect: 'Identity',
62
- notes: 'Investigation Notes'
63
- };
64
-
65
- uploadedEvidence: File[] = [];
66
-
67
- evidencePanelCase: PoliceCase | null = null;
68
- evidenceType: EvidenceType = 'Document';
69
- evidenceFiles: { [caseId: string]: { Document: File[]; Photo: File[] } } = {};
70
-
71
  constructor(private caseStore: CaseStoreService, private router: Router) {}
72
 
73
  ngOnInit(): void {
@@ -76,19 +22,9 @@ export class CaseDetailsPageComponent implements OnInit {
76
  }
77
 
78
  get filteredCases(): PoliceCase[] {
79
- let filtered = this.cases;
80
-
81
- if (this.filterStatus) {
82
- filtered = filtered.filter(c => c.status === this.filterStatus);
83
- }
84
- if (this.filterCrimeType) {
85
- filtered = filtered.filter(c => c.crime === this.filterCrimeType);
86
- }
87
- // Add date filtering logic here if needed
88
-
89
- if (!this.q?.trim()) return filtered;
90
  const qLower = this.q.trim().toLowerCase();
91
- return filtered.filter(c =>
92
  (c.caseId || '').toLowerCase().includes(qLower) ||
93
  (c.status || '').toLowerCase().includes(qLower) ||
94
  (c.crime || '').toLowerCase().includes(qLower) ||
@@ -107,27 +43,14 @@ export class CaseDetailsPageComponent implements OnInit {
107
  return this.cases.filter(c => c.status === 'Closed').length;
108
  }
109
 
110
- get reviewCases(): number {
111
- return this.cases.filter(c => c.status === 'Under Investigation').length;
112
- }
113
-
114
- get statusTypes(): string[] {
115
- return Array.from(new Set(this.cases.map(c => c.status).filter(s => !!s))) as string[];
116
- }
117
- get crimeTypes(): string[] {
118
- return Array.from(new Set(this.cases.map(c => c.crime).filter(s => !!s))) as string[];
119
- }
120
-
121
  openDetails(c: PoliceCase): void {
122
  this.selectedCase = c;
123
  this.showDetails = true;
124
- document.body.classList.add('popup-open');
125
  }
126
 
127
  closeDetails(): void {
128
  this.showDetails = false;
129
  this.selectedCase = null;
130
- document.body.classList.remove('popup-open');
131
  }
132
 
133
  goToDetect(): void {
@@ -137,246 +60,4 @@ export class CaseDetailsPageComponent implements OnInit {
137
  navigateHome(): void {
138
  this.router.navigate(['/']);
139
  }
140
-
141
- applyFilters() {
142
- // No-op: filteredCases getter will use filters
143
- }
144
- resetFilters() {
145
- this.filterStatus = '';
146
- this.filterCrimeType = '';
147
- this.filterDateFrom = '';
148
- this.filterDateTo = '';
149
- this.q = '';
150
- }
151
- getSubgroups(sectionKey: string): string[] {
152
- return Object.keys(this.sections[sectionKey].subgroups);
153
- }
154
-
155
- getFieldsForSubgroup(sectionKey: string, subgroup: string): string[] {
156
- return this.sections[sectionKey].subgroups[subgroup] || [];
157
- }
158
-
159
- selectSubgroup(sectionKey: string, subgroup: string) {
160
- this.selectedSubgroup[sectionKey] = subgroup;
161
- }
162
-
163
- getFieldValue(sc: any, sectionKey: string, field: string): any {
164
- // Map field labels to PoliceCase property paths (copied from recordpage.component.ts)
165
- const fieldMap: { [key: string]: string | string[] } = {
166
- // Crime Details
167
- 'Case ID': 'caseId',
168
- 'FIR / Ref #': 'firRef',
169
- 'Crime Type': 'crime',
170
- 'Case Category': 'caseCategory',
171
- 'Date & Time (Entry)': 'dateTime',
172
- 'Occurred From': 'occurredFrom',
173
- 'Occurred To': 'occurredTo',
174
- 'Time Reported': 'timeReported',
175
- 'Time Discovered': 'timeDiscovered',
176
- 'Country': 'country',
177
- 'State': 'state',
178
- 'District': 'district',
179
- 'Number of Victims': 'numberOfVictims',
180
- 'Brief Description': 'briefDescription',
181
- 'Location': ['police', 'address'],
182
- 'Jurisdiction / PS': 'jurisdiction',
183
- 'Scene Type': 'sceneType',
184
- 'Reported By': 'reportedBy',
185
- 'Reported Contact': 'reportedContact',
186
- 'Witness Count': 'witnessCount',
187
- 'Victim Name': 'victimName',
188
- 'Victim Contact': 'victimContact',
189
- 'Victim Summary': 'victimSummary',
190
- 'Suspected Offender Known?': 'suspectedOffenderKnown',
191
- 'Suspect Link': 'suspectLink',
192
- 'Legal Sections / Charges': 'legalSections',
193
- 'Offence Category': 'offenceCategory',
194
- 'Offence Description': 'offenceDescription',
195
- 'Suspected Motive': 'suspectedMotive',
196
- 'Confirmed Motive': 'confirmedMotive',
197
- 'Weapon Involved': 'weaponInvolved',
198
- 'Property Loss / Damage': 'propertyLoss',
199
- 'Evidence Collected': 'evidenceCollected',
200
- 'Forensic Tests Required': 'forensicTestsRequired',
201
- 'Scene Condition': 'sceneCondition',
202
- 'Photos / Video?': 'photosVideo',
203
- 'CCTV Present?': 'cctvPresent',
204
- 'CCTV Sources / IDs': 'cctvSources',
205
- 'Physical Evidence (list)': 'physicalEvidence',
206
- 'Chain of Custody?': 'chainOfCustody',
207
- 'Digital Evidence': 'digitalEvidence',
208
- 'Evidence Storage Reference': 'evidenceStorageReference',
209
- 'Investigating Officer': ['police', 'name'],
210
- 'Duty Person': ['police', 'dutyPerson'],
211
- 'Supervising Officer': ['police', 'supervisingOfficer'],
212
- 'Patrol Notes': ['police', 'patrolNotes'],
213
- 'Arrest Made': 'arrestMade',
214
- 'Arrest Location': 'arrestLocation',
215
- 'Initial Actions Taken': 'initialActionsTaken',
216
- 'riskLevel': 'riskLevel',
217
- 'Confidentiality': 'confidentiality',
218
- 'Biometric / Forensic IDs': 'biometricIds',
219
- 'DNA Ref ID': 'dnaRefId',
220
- 'Fingerprint ID': 'fingerprintId',
221
- 'Case Status': 'status',
222
- 'Linked Cases': 'linkedCases',
223
- 'arrestCount': 'arrestCount',
224
- 'Case Priority': 'casePriority',
225
- 'Follow-up Date': 'followUpDate',
226
- 'Court Case ID': 'courtCaseId',
227
- 'Next Hearing Date': 'nextHearingDate',
228
- 'Final Summary': 'finalSummary',
229
- 'Remark': 'remark',
230
- // Suspect Details
231
- 'Suspect ID': ['accused', 'suspectId'],
232
- 'Suspect Name': ['accused', 'name'],
233
- 'Alias / Nickname': ['accused', 'alias'],
234
- 'Age': ['accused', 'age'],
235
- 'Gender': ['accused', 'gender'],
236
- 'Nationality': ['accused', 'nationality'],
237
- 'Nationality ID / Passport Number': ['accused', 'passportNumber'],
238
- 'Languages': ['accused', 'languages'],
239
- 'Address': ['accused', 'address'],
240
- 'Known Aliases': ['accused', 'knownAliases'],
241
- 'Government ID': ['accused', 'governmentId'],
242
- 'Height (cm)': ['accused', 'height'],
243
- 'Weight (kg)': ['accused', 'weight'],
244
- 'Build': ['accused', 'build'],
245
- 'Hair Color': ['accused', 'hairColor'],
246
- 'Eye Color': ['accused', 'eyeColor'],
247
- 'Distinguishing Marks': ['accused', 'distinguishingMarks'],
248
- 'Tattoo Details': ['accused', 'tattooDetails'],
249
- 'Scar Details': ['accused', 'scarDetails'],
250
- 'Photo Upload': ['accused', 'photoUpload'],
251
- 'Employment': ['accused', 'employment'],
252
- 'Education': ['accused', 'education'],
253
- 'Occupation': ['accused', 'occupation'],
254
- 'Company': ['accused', 'company'],
255
- 'Workplace Address': ['accused', 'workplaceAddress'],
256
- 'Marital Status': ['accused', 'maritalStatus'],
257
- 'Known Habits': ['accused', 'knownHabits'],
258
- 'Known Financial Details': ['accused', 'knownFinancialDetails'],
259
- 'Associate Names': ['accused', 'associateNames'],
260
- 'Gang Affiliation': ['accused', 'gangAffiliation'],
261
- 'Family Connections': ['accused', 'familyConnections'],
262
- 'Social Media Handles': ['accused', 'socialMediaHandles'],
263
- 'Criminal History': ['accused', 'criminalHistory'],
264
- 'Prior Arrests': ['accused', 'priorArrests'],
265
- 'Probation/Parole Status': ['accused', 'probationStatus'],
266
- // Notes/Evidence
267
- 'Initial Findings': ['police', 'information'],
268
- 'Detailed Notes': ['notes', 'detailedNotes'],
269
- 'Status': 'status',
270
- 'Version History / Updates': ['notes', 'versionHistory'],
271
- 'Evidence Photos': ['legal', 'evidencePhotos'],
272
- 'Evidence Videos': ['legal', 'evidenceVideos'],
273
- 'Evidence Documents': ['legal', 'evidenceDocuments'],
274
- 'Links to Evidence': ['legal', 'linksToEvidence'],
275
- 'Final Recommendations': ['legal', 'finalRecommendations'],
276
- 'Witness Statements': ['legal', 'witnessStatements'],
277
- 'Confessions': ['legal', 'confessions'],
278
- // Audit Fields
279
- 'Created By': 'createdBy',
280
- 'Creation Date': 'creationDate',
281
- 'Last Updated': 'lastUpdated',
282
- 'Verified By': 'verifiedBy'
283
- };
284
-
285
- const path = fieldMap[field] || field;
286
- if (Array.isArray(path)) {
287
- let value = sc;
288
- for (const p of path) {
289
- if (value && value[p] !== undefined) value = value[p];
290
- else return '—';
291
- }
292
- return value !== undefined && value !== null && value !== '' ? value : '—';
293
- } else {
294
- return sc[path] !== undefined && sc[path] !== null && sc[path] !== '' ? sc[path] : '—';
295
- }
296
- }
297
-
298
- getProgressValue(caseObj: any): number {
299
- let total = 0, filled = 0;
300
- ['crime', 'suspect', 'notes'].forEach(sectionKey => {
301
- const subgroups = this.getSubgroups(sectionKey);
302
- subgroups.forEach(subgroup => {
303
- const fields = this.getFieldsForSubgroup(sectionKey, subgroup);
304
- total += fields.length;
305
- fields.forEach(field => {
306
- const value = this.getFieldValue(caseObj, sectionKey, field);
307
- if (value && value !== '—') filled++;
308
- });
309
- });
310
- });
311
- return total ? Math.round((filled / total) * 100) : 0;
312
- }
313
- getNextActionMessage(c: any): string {
314
- // Example logic based on status and progress
315
- const progress = this.getProgressValue(c);
316
- if (c.status === 'Closed' || progress === 100) {
317
- return 'Case completed';
318
- }
319
- if (c.status === 'Under Review' || progress >= 75) {
320
- return 'Await supervisor approval';
321
- }
322
- if (c.status === 'Open' || progress < 75) {
323
- return 'Collect evidence';
324
- }
325
- return '—';
326
- }
327
- getCasePriority(c: PoliceCase): 'High' | 'Medium' | 'Low' {
328
- // Automatic logic based on crime type and status
329
- const highCrimes = ['Murder', 'Robbery'];
330
- const mediumCrimes = ['Theft', 'Assault'];
331
- if (highCrimes.includes(c.crime) || c.status === 'Open') {
332
- return 'High';
333
- }
334
- if (mediumCrimes.includes(c.crime) || c.status === 'Under Investigation') {
335
- return 'Medium';
336
- }
337
- return 'Low';
338
- }
339
-
340
- isInvestigator(): boolean {
341
- // Simple role check: username contains 'investigator' (customize as needed)
342
- return this.username.toLowerCase().includes('investigator');
343
- }
344
-
345
- onEvidenceUpload(event: any): void {
346
- const files = Array.from(event.target.files) as File[];
347
- this.uploadedEvidence = [...this.uploadedEvidence, ...files];
348
- // You can add logic to save evidence to the case or backend here
349
- }
350
-
351
- showEvidencePanel(c: PoliceCase): void {
352
- if (!c.caseId) return;
353
- this.evidencePanelCase = c;
354
- this.evidenceType = 'Document';
355
- if (!this.evidenceFiles[c.caseId]) {
356
- this.evidenceFiles[c.caseId] = { Document: [], Photo: [] };
357
- }
358
- }
359
-
360
- setEvidenceType(type: EvidenceType): void {
361
- this.evidenceType = type;
362
- }
363
-
364
- onEvidenceFileSelectType(event: any): void {
365
- const files = Array.from(event.target.files) as File[];
366
- if (this.evidencePanelCase && this.evidencePanelCase.caseId) {
367
- this.evidenceFiles[this.evidencePanelCase.caseId][this.evidenceType].push(...files);
368
- }
369
- }
370
-
371
- getEvidenceIcon(filename: string): string {
372
- if (filename.match(/\.(jpg|jpeg|png|gif)$/i)) return 'fas fa-camera';
373
- if (filename.match(/\.(mp4|avi|mov)$/i)) return 'fas fa-film';
374
- if (filename.match(/\.(pdf)$/i)) return 'fas fa-file-pdf';
375
- return 'fas fa-file';
376
- }
377
-
378
- viewEvidenceFile(file: File): void {
379
- const url = URL.createObjectURL(file);
380
- window.open(url, '_blank');
381
- }
382
  }
 
2
  import { Router } from '@angular/router';
3
  import { CaseStoreService, PoliceCase } from '../shared/case-store.service';
4
 
 
 
5
  @Component({
6
  selector: 'app-case-details-page',
7
  templateUrl: './case-details-page.component.html',
 
14
  username: string = '';
15
  q: string = '';
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  constructor(private caseStore: CaseStoreService, private router: Router) {}
18
 
19
  ngOnInit(): void {
 
22
  }
23
 
24
  get filteredCases(): PoliceCase[] {
25
+ if (!this.q?.trim()) return this.cases;
 
 
 
 
 
 
 
 
 
 
26
  const qLower = this.q.trim().toLowerCase();
27
+ return this.cases.filter(c =>
28
  (c.caseId || '').toLowerCase().includes(qLower) ||
29
  (c.status || '').toLowerCase().includes(qLower) ||
30
  (c.crime || '').toLowerCase().includes(qLower) ||
 
43
  return this.cases.filter(c => c.status === 'Closed').length;
44
  }
45
 
 
 
 
 
 
 
 
 
 
 
 
46
  openDetails(c: PoliceCase): void {
47
  this.selectedCase = c;
48
  this.showDetails = true;
 
49
  }
50
 
51
  closeDetails(): void {
52
  this.showDetails = false;
53
  this.selectedCase = null;
 
54
  }
55
 
56
  goToDetect(): void {
 
60
  navigateHome(): void {
61
  this.router.navigate(['/']);
62
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  }
src/app/recordpage/recordpage.component.css CHANGED
@@ -245,7 +245,6 @@
245
  max-width: 100vw;
246
  min-width: 1000px;
247
  }
248
-
249
  .table-wrap {
250
  max-width: 100vw;
251
  min-height: 400px;
@@ -258,16 +257,13 @@
258
  width: 100%;
259
  max-width: 100vw;
260
  }
261
-
262
  .table-wrap {
263
  min-height: 200px;
264
  }
265
-
266
  .padded-table-wrap {
267
  padding-left: 4px;
268
  padding-right: 4px;
269
  }
270
-
271
  .records-header-row {
272
  flex-direction: column;
273
  align-items: stretch;
@@ -275,12 +271,10 @@
275
  padding-left: 4px;
276
  padding-right: 4px;
277
  }
278
-
279
  .page-title {
280
  text-align: center;
281
  margin-right: 0;
282
  }
283
-
284
  .toolbar {
285
  position: static;
286
  transform: none;
@@ -330,11 +324,6 @@
330
 
331
  .records th.actions-col, .records td.actions {
332
  color: #fff;
333
- text-align: left;
334
- padding-left: 18px;
335
- padding-right: 18px;
336
- width: 1%;
337
- white-space: nowrap;
338
  }
339
 
340
  .records tbody tr:last-child td {
@@ -418,17 +407,14 @@
418
  background: #e5e7eb;
419
  color: #22223b;
420
  }
421
-
422
  .status-open {
423
  background: #d1fae5;
424
  color: #059669;
425
  }
426
-
427
  .status-under {
428
  background: #dbeafe;
429
  color: #2563eb;
430
  }
431
-
432
  .status-closed {
433
  background: #fee2e2;
434
  color: #dc2626;
@@ -470,18 +456,17 @@
470
  border-color: #805ad5;
471
  }
472
 
473
- .btn.delete {
474
- background: #ef4444;
475
- color: #fff;
476
- border-color: #ef4444;
477
- box-shadow: 0 2px 8px #ef444422;
478
- transition: background 0.18s, color 0.18s;
479
- }
480
-
481
- .btn.delete:hover {
482
- background: #991b1b;
483
- color: #fff;
484
- }
485
 
486
  /* Icon buttons */
487
  .icon-btn {
@@ -499,56 +484,38 @@
499
  align-items: center;
500
  justify-content: center;
501
  }
502
-
503
- .icon-btn.view {
504
- margin: 0;
505
- padding: 0 8px;
506
- background: none;
507
- border: none;
508
- cursor: pointer;
509
- color: #2563eb;
510
- font-size: 1.2em;
511
- display: inline-flex;
512
- align-items: center;
513
- justify-content: center;
514
- }
515
-
516
- .icon-btn.edit {
517
- color: #7c3aed;
518
- }
519
-
520
- .icon-btn.delete {
521
- color: #ef4444;
522
- }
523
-
524
- .icon-btn:hover {
525
- background: #f0f7ff;
526
- box-shadow: 0 2px 8px #2563eb22;
527
- }
528
-
529
- .icon-btn.delete:hover {
530
- background: #fff0f0;
531
- color: #b91c1c;
532
- }
533
-
534
- .icon-btn.edit:hover {
535
- background: #f3e8ff;
536
- color: #5b21b6;
537
- }
538
-
539
- .icon-btn.view:hover {
540
- background: #e0f2fe;
541
- color: #0ea5e9;
542
- }
543
-
544
- .icon-btn.verify {
545
- color: #22c55e;
546
- }
547
-
548
- .icon-btn.verify:hover {
549
- background: #e0ffe6;
550
- color: #15803d;
551
- }
552
 
553
  .empty {
554
  text-align: center;
@@ -584,7 +551,6 @@
584
  display: flex;
585
  flex-direction: column;
586
  }
587
-
588
  .modal-header, .modal-footer {
589
  padding: 24px 40px 18px 40px;
590
  background: #f8fafc;
@@ -592,7 +558,6 @@
592
  font-size: 1.18rem;
593
  color: #23272b;
594
  }
595
-
596
  .modal-body {
597
  flex: 1 1 auto;
598
  padding: 32px 48px 32px 48px;
@@ -610,33 +575,33 @@
610
  border-bottom: 1px solid #e5e7eb;
611
  }
612
 
613
- .detail-row:last-child {
614
- border-bottom: none;
615
- }
616
 
617
- .detail-row span {
618
- color: #2563eb;
619
- font-weight: 600;
620
- font-size: 1.07em;
621
- }
622
 
623
- .detail-row b {
624
- color: #23272b;
625
- font-weight: 500;
626
- font-size: 1.07em;
627
- }
628
 
629
  .detail-block {
630
  margin-top: 18px;
631
  margin-bottom: 8px;
632
  }
633
 
634
- .detail-block .label {
635
- font-weight: 700;
636
- color: #2563eb;
637
- margin-bottom: 6px;
638
- font-size: 1.09em;
639
- }
640
 
641
  .explain {
642
  white-space: pre-wrap;
@@ -659,9 +624,9 @@
659
  margin-left: 8px;
660
  }
661
 
662
- .btn:hover {
663
- background: #e0e7ef;
664
- }
665
 
666
  .records-center {
667
  display: flex;
@@ -760,11 +725,11 @@
760
  z-index: 10;
761
  }
762
 
763
- .modern-searchbar-container.compact {
764
- width: auto;
765
- margin: 0 0 0 24px;
766
- align-items: center;
767
- }
768
 
769
  .modern-searchbar-form {
770
  display: flex;
@@ -778,12 +743,12 @@
778
  position: relative;
779
  }
780
 
781
- .modern-searchbar-form.compact {
782
- height: 44px;
783
- min-width: 260px;
784
- width: 320px;
785
- padding: 0 8px 0 10px;
786
- }
787
 
788
  .modern-searchbar-icon {
789
  display: flex;
@@ -804,11 +769,11 @@
804
  height: 32px;
805
  }
806
 
807
- .modern-searchbar-input::placeholder {
808
- color: #e0e7ef;
809
- opacity: 1;
810
- font-weight: 400;
811
- }
812
 
813
  .modern-searchbar-btn {
814
  background: #fff;
@@ -825,10 +790,10 @@
825
  transition: background 0.18s, color 0.18s;
826
  }
827
 
828
- .modern-searchbar-btn:hover {
829
- background: #ede9fe;
830
- color: #4f46e5;
831
- }
832
 
833
  .modern-searchbar-form.white-bg {
834
  background: #fff !important;
@@ -840,10 +805,10 @@
840
  color: #23272b !important;
841
  }
842
 
843
- .modern-searchbar-input.white-bg::placeholder {
844
- color: #64748b !important;
845
- opacity: 1;
846
- }
847
 
848
  .modern-searchbar-icon svg {
849
  stroke: #64748b !important;
@@ -864,10 +829,10 @@
864
  transition: background 0.18s, color 0.18s;
865
  }
866
 
867
- .modern-searchbar-btn:hover {
868
- background: #38bdf8;
869
- color: #fff;
870
- }
871
 
872
 
873
  .back-colo {
@@ -900,11 +865,11 @@
900
  width: 95vw;
901
  justify-content: flex-end;
902
  }
903
-
904
  .modern-searchbar-form.compact {
905
  width: 100%;
906
  min-width: 0;
907
  }
 
908
  }
909
 
910
  /* Modern UI header styles from infopage */
@@ -916,7 +881,6 @@
916
  z-index: 10;
917
  padding-bottom: 0;
918
  }
919
-
920
  .header-inner {
921
  display: flex;
922
  align-items: center;
@@ -924,13 +888,11 @@
924
  padding: 18px 32px 0 32px;
925
  position: relative;
926
  }
927
-
928
  .logo-cluster {
929
  display: flex;
930
  align-items: center;
931
  gap: 18px;
932
  }
933
-
934
  .logo-img-header {
935
  width: 54px;
936
  height: 54px;
@@ -941,7 +903,6 @@
941
  margin-top: -6px;
942
  margin-bottom: 1vh;
943
  }
944
-
945
  .py-detect-title-header {
946
  font-size: 2.1rem;
947
  font-family: 'Segoe UI', 'Arial', 'Roboto', sans-serif;
@@ -954,58 +915,15 @@
954
  margin-bottom: 1.5vh;
955
  }
956
 
957
- .py-detect-title-header .py-letter.p {
958
- color: #e3f6ff;
959
- text-shadow: 0 0 6px #38bdf8;
960
- }
961
-
962
- .py-detect-title-header .py-letter.y {
963
- color: #38bdf8;
964
- text-shadow: 0 0 6px #38bdf8;
965
- }
966
-
967
- .py-detect-title-header .py-shape {
968
- color: #e3f6ff;
969
- background: #e3f6ff;
970
- text-shadow: 0 0 6px #38bdf8;
971
- box-shadow: 0 0 6px #38bdf8, 0 0 2px #fff;
972
- border: 2px solid #23272b;
973
- width: 18px;
974
- height: 4px;
975
- display: inline-block;
976
- margin: 0 8px;
977
- border-radius: 2px;
978
- }
979
-
980
- .py-detect-title-header .py-letter.d {
981
- color: #e3f6ff;
982
- text-shadow: 0 0 6px #38bdf8;
983
- }
984
-
985
- .py-detect-title-header .py-letter.e {
986
- color: #38bdf8;
987
- text-shadow: 0 0 6px #38bdf8;
988
- }
989
-
990
- .py-detect-title-header .py-letter.t {
991
- color: #e3f6ff;
992
- text-shadow: 0 0 6px #38bdf8;
993
- }
994
-
995
- .py-detect-title-header .py-letter.e2 {
996
- color: #38bdf8;
997
- text-shadow: 0 0 6px #38bdf8;
998
- }
999
-
1000
- .py-detect-title-header .py-letter.c {
1001
- color: #e3f6ff;
1002
- text-shadow: 0 0 6px #38bdf8;
1003
- }
1004
-
1005
- .py-detect-title-header .py-letter.t2 {
1006
- color: #38bdf8;
1007
- text-shadow: 0 0 6px #38bdf8;
1008
- }
1009
 
1010
  body, main.content {
1011
  background: #f4f6fa;
@@ -1088,10 +1006,9 @@ body, main.content {
1088
  cursor: pointer;
1089
  transition: background 0.18s;
1090
  }
1091
-
1092
- .record-new-btn:hover {
1093
- background: #1e40af;
1094
- }
1095
 
1096
  .record-table {
1097
  width: 100%;
@@ -1100,52 +1017,50 @@ body, main.content {
1100
  background: #fff;
1101
  }
1102
 
1103
- .record-table th, .record-table td {
1104
- border-bottom: 1.5px solid #e5e7eb;
1105
- padding: 12px 16px;
1106
- text-align: left;
1107
- font-size: 1.05rem;
1108
- }
1109
-
1110
- .record-table th {
1111
- background: #f4f6fa;
1112
- color: #222b45;
1113
- font-weight: 700;
1114
- }
1115
 
1116
- .record-table tr:last-child td {
1117
- border-bottom: none;
1118
- }
 
 
1119
 
1120
- .record-table tr {
1121
- transition: background 0.15s;
1122
- }
1123
 
1124
- .record-table tr:hover {
1125
- background: #f1f5f9;
1126
- }
 
 
 
1127
 
1128
- .record-table a {
1129
- color: #2563eb;
1130
- text-decoration: underline;
1131
- cursor: pointer;
1132
- }
1133
 
1134
- .record-table .record-status {
1135
- font-weight: 500;
1136
- border-radius: 6px;
1137
- padding: 2px 10px;
1138
- background: #f1f5f9;
1139
- color: #2563eb;
1140
- font-size: 0.98em;
1141
- }
1142
 
1143
  .vertical-sections {
1144
  display: flex;
1145
  flex-direction: column;
1146
  gap: 32px;
1147
  }
1148
-
1149
  .horizontal-sections {
1150
  display: flex;
1151
  flex-direction: column;
@@ -1155,7 +1070,6 @@ body, main.content {
1155
  box-shadow: 0 8px 32px #2563eb22;
1156
  padding: 32px 0 32px 0;
1157
  }
1158
-
1159
  .section-block {
1160
  background: rgba(255,255,255,0.98);
1161
  border-radius: 18px;
@@ -1168,12 +1082,10 @@ body, main.content {
1168
  border-left: 6px solid #38bdf8;
1169
  transition: box-shadow 0.2s, border 0.2s;
1170
  }
1171
-
1172
- .section-block:hover {
1173
- box-shadow: 0 8px 32px #2563eb33;
1174
- border-left: 6px solid #2563eb;
1175
- }
1176
-
1177
  .section-title {
1178
  font-size: 1.32em;
1179
  font-weight: 900;
@@ -1185,14 +1097,12 @@ body, main.content {
1185
  align-items: center;
1186
  gap: 10px;
1187
  }
1188
-
1189
  .subgroup-row {
1190
  display: flex;
1191
  flex-direction: row;
1192
  gap: 36px;
1193
  overflow-x: auto;
1194
  }
1195
-
1196
  .subgroup-block {
1197
  min-width: 260px;
1198
  flex: 1 1 0;
@@ -1208,13 +1118,11 @@ body, main.content {
1208
  border: 1.5px solid #e0e7ef;
1209
  transition: box-shadow 0.18s, border 0.18s, background 0.18s;
1210
  }
1211
-
1212
- .subgroup-block:hover {
1213
- box-shadow: 0 4px 16px #38bdf855;
1214
- border: 1.5px solid #38bdf8;
1215
- background: #e0f2fe;
1216
- }
1217
-
1218
  .subgroup-title {
1219
  font-size: 1.11em;
1220
  font-weight: 700;
@@ -1226,7 +1134,6 @@ body, main.content {
1226
  align-items: center;
1227
  gap: 8px;
1228
  }
1229
-
1230
  .fields-table {
1231
  display: flex;
1232
  flex-direction: column;
@@ -1236,7 +1143,6 @@ body, main.content {
1236
  border-radius: 0;
1237
  padding: 0;
1238
  }
1239
-
1240
  .field-row {
1241
  display: flex;
1242
  flex-direction: row;
@@ -1250,36 +1156,32 @@ body, main.content {
1250
  transition: background 0.18s;
1251
  gap: 32px;
1252
  }
1253
-
1254
- .field-row:last-child {
1255
- border-bottom: none;
1256
- }
1257
-
1258
- .field-row span {
1259
- color: #1e293b;
1260
- font-weight: 700;
1261
- letter-spacing: 0.2px;
1262
- min-width: 180px;
1263
- font-size: 1.08em;
1264
- margin-right: 32px;
1265
- text-align: left;
1266
- display: inline-block;
1267
- }
1268
-
1269
- .field-row b {
1270
- color: #2563eb;
1271
- font-weight: 700;
1272
- word-break: break-word;
1273
- letter-spacing: 0.1px;
1274
- font-size: 1.13em;
1275
- margin-left: 8px;
1276
- text-align: left;
1277
- display: inline-block;
1278
- }
1279
-
1280
- .field-row b:hover {
1281
- color: #0ea5e9;
1282
- }
1283
 
1284
  /* Stylish pills for subgroups */
1285
  .subgroup-pills {
@@ -1288,32 +1190,29 @@ body, main.content {
1288
  gap: 12px;
1289
  margin-bottom: 18px;
1290
  }
1291
-
1292
- .subgroup-pills button {
1293
- background: linear-gradient(90deg, #38bdf8 0%, #2563eb 100%);
1294
- border: none;
1295
- border-radius: 20px;
1296
- padding: 7px 22px;
1297
- font-size: 1em;
1298
- color: #fff;
1299
- font-weight: 700;
1300
- cursor: pointer;
1301
- box-shadow: 0 2px 8px #2563eb22;
1302
- transition: background 0.18s, color 0.18s, box-shadow 0.18s;
1303
- outline: none;
1304
- }
1305
-
1306
- .subgroup-pills button.active,
1307
- .subgroup-pills button:focus {
1308
- background: linear-gradient(90deg, #2563eb 0%, #38bdf8 100%);
1309
- color: #fff;
1310
- box-shadow: 0 4px 16px #38bdf855;
1311
- }
1312
-
1313
- .subgroup-pills button:hover {
1314
- background: linear-gradient(90deg, #0ea5e9 0%, #2563eb 100%);
1315
- color: #fff;
1316
- }
1317
 
1318
  .field-card {
1319
  display: flex;
@@ -1327,32 +1226,26 @@ body, main.content {
1327
  .section-block {
1328
  padding: 18px 8vw 12px 8vw;
1329
  }
1330
-
1331
  .subgroup-block {
1332
  min-width: 180px;
1333
  padding: 12px 8px 8px 8px;
1334
  }
1335
-
1336
  .field-row span {
1337
  min-width: 120px;
1338
  }
1339
  }
1340
-
1341
  @media (max-width: 600px) {
1342
  .section-block {
1343
  padding: 10px 2vw 8px 2vw;
1344
  }
1345
-
1346
  .subgroup-block {
1347
  min-width: 120px;
1348
  padding: 8px 2px 6px 2px;
1349
  }
1350
-
1351
  .field-row span {
1352
  min-width: 80px;
1353
  font-size: 0.98em;
1354
  }
1355
-
1356
  .field-row b {
1357
  font-size: 1em;
1358
  }
@@ -1369,55 +1262,48 @@ body, main.content {
1369
  border-radius: 12px;
1370
  box-shadow: 0 2px 8px #2563eb11;
1371
  }
1372
-
1373
- .filter-bar select {
1374
- padding: 6px 18px;
1375
- border-radius: 6px;
1376
- border: 1.5px solid #cbd5e1;
1377
- font-size: 1em;
1378
- color: #2563eb;
1379
- background: #fff;
1380
- font-weight: 600;
1381
- outline: none;
1382
- transition: border 0.15s;
1383
- }
1384
-
1385
- .filter-bar select:focus {
1386
- border: 1.5px solid #38bdf8;
1387
- }
1388
-
1389
- .filter-bar button {
1390
- padding: 6px 18px;
1391
- border-radius: 6px;
1392
- border: none;
1393
- font-size: 1em;
1394
- font-weight: 700;
1395
- cursor: pointer;
1396
- background: #2563eb;
1397
- color: #fff;
1398
- transition: background 0.15s;
1399
- }
1400
-
1401
- .filter-bar button:hover {
1402
- background: #0ea5e9;
1403
- }
1404
-
1405
- .filter-bar button:last-child {
1406
- background: #f87171;
1407
- color: #fff;
1408
- margin-left: 4px;
1409
- }
1410
-
1411
- .filter-bar button:last-child:hover {
1412
- background: #ef4444;
1413
- }
1414
 
1415
  .analytics-summary {
1416
  display: flex;
1417
  gap: 32px;
1418
  margin: 18px 0 8px 0;
1419
  }
1420
-
1421
  .summary-card {
1422
  background: #f8fafc;
1423
  border-radius: 12px;
@@ -1426,27 +1312,23 @@ body, main.content {
1426
  min-width: 120px;
1427
  text-align: center;
1428
  }
1429
-
1430
- .summary-card .summary-label {
1431
- font-size: 1em;
1432
- color: #64748b;
1433
- font-weight: 600;
1434
- margin-bottom: 6px;
1435
- }
1436
-
1437
- .summary-card .summary-value {
1438
- font-size: 2em;
1439
- font-weight: 900;
1440
- color: #2563eb;
1441
- }
1442
-
1443
- .summary-card.open .summary-value {
1444
- color: #059669;
1445
- }
1446
-
1447
- .summary-card.closed .summary-value {
1448
- color: #dc2626;
1449
- }
1450
 
1451
  .record-meta {
1452
  color: #64748b;
@@ -1456,3 +1338,5 @@ body, main.content {
1456
  font-weight: 500;
1457
  letter-spacing: 0.1px;
1458
  }
 
 
 
245
  max-width: 100vw;
246
  min-width: 1000px;
247
  }
 
248
  .table-wrap {
249
  max-width: 100vw;
250
  min-height: 400px;
 
257
  width: 100%;
258
  max-width: 100vw;
259
  }
 
260
  .table-wrap {
261
  min-height: 200px;
262
  }
 
263
  .padded-table-wrap {
264
  padding-left: 4px;
265
  padding-right: 4px;
266
  }
 
267
  .records-header-row {
268
  flex-direction: column;
269
  align-items: stretch;
 
271
  padding-left: 4px;
272
  padding-right: 4px;
273
  }
 
274
  .page-title {
275
  text-align: center;
276
  margin-right: 0;
277
  }
 
278
  .toolbar {
279
  position: static;
280
  transform: none;
 
324
 
325
  .records th.actions-col, .records td.actions {
326
  color: #fff;
 
 
 
 
 
327
  }
328
 
329
  .records tbody tr:last-child td {
 
407
  background: #e5e7eb;
408
  color: #22223b;
409
  }
 
410
  .status-open {
411
  background: #d1fae5;
412
  color: #059669;
413
  }
 
414
  .status-under {
415
  background: #dbeafe;
416
  color: #2563eb;
417
  }
 
418
  .status-closed {
419
  background: #fee2e2;
420
  color: #dc2626;
 
456
  border-color: #805ad5;
457
  }
458
 
459
+ .btn.delete {
460
+ background: #ef4444;
461
+ color: #fff;
462
+ border-color: #ef4444;
463
+ box-shadow: 0 2px 8px #ef444422;
464
+ transition: background 0.18s, color 0.18s;
465
+ }
466
+ .btn.delete:hover {
467
+ background: #991b1b;
468
+ color: #fff;
469
+ }
 
470
 
471
  /* Icon buttons */
472
  .icon-btn {
 
484
  align-items: center;
485
  justify-content: center;
486
  }
487
+ .icon-btn.view {
488
+ color: #2563eb;
489
+ }
490
+ .icon-btn.edit {
491
+ color: #7c3aed;
492
+ }
493
+ .icon-btn.delete {
494
+ color: #ef4444;
495
+ }
496
+ .icon-btn:hover {
497
+ background: #f0f7ff;
498
+ box-shadow: 0 2px 8px #2563eb22;
499
+ }
500
+ .icon-btn.delete:hover {
501
+ background: #fff0f0;
502
+ color: #b91c1c;
503
+ }
504
+ .icon-btn.edit:hover {
505
+ background: #f3e8ff;
506
+ color: #5b21b6;
507
+ }
508
+ .icon-btn.view:hover {
509
+ background: #e0f2fe;
510
+ color: #0ea5e9;
511
+ }
512
+ .icon-btn.verify {
513
+ color: #22c55e;
514
+ }
515
+ .icon-btn.verify:hover {
516
+ background: #e0ffe6;
517
+ color: #15803d;
518
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
519
 
520
  .empty {
521
  text-align: center;
 
551
  display: flex;
552
  flex-direction: column;
553
  }
 
554
  .modal-header, .modal-footer {
555
  padding: 24px 40px 18px 40px;
556
  background: #f8fafc;
 
558
  font-size: 1.18rem;
559
  color: #23272b;
560
  }
 
561
  .modal-body {
562
  flex: 1 1 auto;
563
  padding: 32px 48px 32px 48px;
 
575
  border-bottom: 1px solid #e5e7eb;
576
  }
577
 
578
+ .detail-row:last-child {
579
+ border-bottom: none;
580
+ }
581
 
582
+ .detail-row span {
583
+ color: #2563eb;
584
+ font-weight: 600;
585
+ font-size: 1.07em;
586
+ }
587
 
588
+ .detail-row b {
589
+ color: #23272b;
590
+ font-weight: 500;
591
+ font-size: 1.07em;
592
+ }
593
 
594
  .detail-block {
595
  margin-top: 18px;
596
  margin-bottom: 8px;
597
  }
598
 
599
+ .detail-block .label {
600
+ font-weight: 700;
601
+ color: #2563eb;
602
+ margin-bottom: 6px;
603
+ font-size: 1.09em;
604
+ }
605
 
606
  .explain {
607
  white-space: pre-wrap;
 
624
  margin-left: 8px;
625
  }
626
 
627
+ .btn:hover {
628
+ background: #e0e7ef;
629
+ }
630
 
631
  .records-center {
632
  display: flex;
 
725
  z-index: 10;
726
  }
727
 
728
+ .modern-searchbar-container.compact {
729
+ width: auto;
730
+ margin: 0 0 0 24px;
731
+ align-items: center;
732
+ }
733
 
734
  .modern-searchbar-form {
735
  display: flex;
 
743
  position: relative;
744
  }
745
 
746
+ .modern-searchbar-form.compact {
747
+ height: 44px;
748
+ min-width: 260px;
749
+ width: 320px;
750
+ padding: 0 8px 0 10px;
751
+ }
752
 
753
  .modern-searchbar-icon {
754
  display: flex;
 
769
  height: 32px;
770
  }
771
 
772
+ .modern-searchbar-input::placeholder {
773
+ color: #e0e7ef;
774
+ opacity: 1;
775
+ font-weight: 400;
776
+ }
777
 
778
  .modern-searchbar-btn {
779
  background: #fff;
 
790
  transition: background 0.18s, color 0.18s;
791
  }
792
 
793
+ .modern-searchbar-btn:hover {
794
+ background: #ede9fe;
795
+ color: #4f46e5;
796
+ }
797
 
798
  .modern-searchbar-form.white-bg {
799
  background: #fff !important;
 
805
  color: #23272b !important;
806
  }
807
 
808
+ .modern-searchbar-input.white-bg::placeholder {
809
+ color: #64748b !important;
810
+ opacity: 1;
811
+ }
812
 
813
  .modern-searchbar-icon svg {
814
  stroke: #64748b !important;
 
829
  transition: background 0.18s, color 0.18s;
830
  }
831
 
832
+ .modern-searchbar-btn:hover {
833
+ background: #38bdf8;
834
+ color: #fff;
835
+ }
836
 
837
 
838
  .back-colo {
 
865
  width: 95vw;
866
  justify-content: flex-end;
867
  }
 
868
  .modern-searchbar-form.compact {
869
  width: 100%;
870
  min-width: 0;
871
  }
872
+
873
  }
874
 
875
  /* Modern UI header styles from infopage */
 
881
  z-index: 10;
882
  padding-bottom: 0;
883
  }
 
884
  .header-inner {
885
  display: flex;
886
  align-items: center;
 
888
  padding: 18px 32px 0 32px;
889
  position: relative;
890
  }
 
891
  .logo-cluster {
892
  display: flex;
893
  align-items: center;
894
  gap: 18px;
895
  }
 
896
  .logo-img-header {
897
  width: 54px;
898
  height: 54px;
 
903
  margin-top: -6px;
904
  margin-bottom: 1vh;
905
  }
 
906
  .py-detect-title-header {
907
  font-size: 2.1rem;
908
  font-family: 'Segoe UI', 'Arial', 'Roboto', sans-serif;
 
915
  margin-bottom: 1.5vh;
916
  }
917
 
918
+ .py-detect-title-header .py-letter.p { color: #e3f6ff; text-shadow: 0 0 6px #38bdf8; }
919
+ .py-detect-title-header .py-letter.y { color: #38bdf8; text-shadow: 0 0 6px #38bdf8; }
920
+ .py-detect-title-header .py-shape { color: #e3f6ff; background: #e3f6ff; text-shadow: 0 0 6px #38bdf8; box-shadow: 0 0 6px #38bdf8, 0 0 2px #fff; border: 2px solid #23272b; width: 18px; height: 4px; display: inline-block; margin: 0 8px; border-radius: 2px; }
921
+ .py-detect-title-header .py-letter.d { color: #e3f6ff; text-shadow: 0 0 6px #38bdf8; }
922
+ .py-detect-title-header .py-letter.e { color: #38bdf8; text-shadow: 0 0 6px #38bdf8; }
923
+ .py-detect-title-header .py-letter.t { color: #e3f6ff; text-shadow: 0 0 6px #38bdf8; }
924
+ .py-detect-title-header .py-letter.e2 { color: #38bdf8; text-shadow: 0 0 6px #38bdf8; }
925
+ .py-detect-title-header .py-letter.c { color: #e3f6ff; text-shadow: 0 0 6px #38bdf8; }
926
+ .py-detect-title-header .py-letter.t2 { color: #38bdf8; text-shadow: 0 0 6px #38bdf8; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
927
 
928
  body, main.content {
929
  background: #f4f6fa;
 
1006
  cursor: pointer;
1007
  transition: background 0.18s;
1008
  }
1009
+ .record-new-btn:hover {
1010
+ background: #1e40af;
1011
+ }
 
1012
 
1013
  .record-table {
1014
  width: 100%;
 
1017
  background: #fff;
1018
  }
1019
 
1020
+ .record-table th, .record-table td {
1021
+ border-bottom: 1.5px solid #e5e7eb;
1022
+ padding: 12px 16px;
1023
+ text-align: left;
1024
+ font-size: 1.05rem;
1025
+ }
 
 
 
 
 
 
1026
 
1027
+ .record-table th {
1028
+ background: #f4f6fa;
1029
+ color: #222b45;
1030
+ font-weight: 700;
1031
+ }
1032
 
1033
+ .record-table tr:last-child td {
1034
+ border-bottom: none;
1035
+ }
1036
 
1037
+ .record-table tr {
1038
+ transition: background 0.15s;
1039
+ }
1040
+ .record-table tr:hover {
1041
+ background: #f1f5f9;
1042
+ }
1043
 
1044
+ .record-table a {
1045
+ color: #2563eb;
1046
+ text-decoration: underline;
1047
+ cursor: pointer;
1048
+ }
1049
 
1050
+ .record-table .record-status {
1051
+ font-weight: 500;
1052
+ border-radius: 6px;
1053
+ padding: 2px 10px;
1054
+ background: #f1f5f9;
1055
+ color: #2563eb;
1056
+ font-size: 0.98em;
1057
+ }
1058
 
1059
  .vertical-sections {
1060
  display: flex;
1061
  flex-direction: column;
1062
  gap: 32px;
1063
  }
 
1064
  .horizontal-sections {
1065
  display: flex;
1066
  flex-direction: column;
 
1070
  box-shadow: 0 8px 32px #2563eb22;
1071
  padding: 32px 0 32px 0;
1072
  }
 
1073
  .section-block {
1074
  background: rgba(255,255,255,0.98);
1075
  border-radius: 18px;
 
1082
  border-left: 6px solid #38bdf8;
1083
  transition: box-shadow 0.2s, border 0.2s;
1084
  }
1085
+ .section-block:hover {
1086
+ box-shadow: 0 8px 32px #2563eb33;
1087
+ border-left: 6px solid #2563eb;
1088
+ }
 
 
1089
  .section-title {
1090
  font-size: 1.32em;
1091
  font-weight: 900;
 
1097
  align-items: center;
1098
  gap: 10px;
1099
  }
 
1100
  .subgroup-row {
1101
  display: flex;
1102
  flex-direction: row;
1103
  gap: 36px;
1104
  overflow-x: auto;
1105
  }
 
1106
  .subgroup-block {
1107
  min-width: 260px;
1108
  flex: 1 1 0;
 
1118
  border: 1.5px solid #e0e7ef;
1119
  transition: box-shadow 0.18s, border 0.18s, background 0.18s;
1120
  }
1121
+ .subgroup-block:hover {
1122
+ box-shadow: 0 4px 16px #38bdf855;
1123
+ border: 1.5px solid #38bdf8;
1124
+ background: #e0f2fe;
1125
+ }
 
 
1126
  .subgroup-title {
1127
  font-size: 1.11em;
1128
  font-weight: 700;
 
1134
  align-items: center;
1135
  gap: 8px;
1136
  }
 
1137
  .fields-table {
1138
  display: flex;
1139
  flex-direction: column;
 
1143
  border-radius: 0;
1144
  padding: 0;
1145
  }
 
1146
  .field-row {
1147
  display: flex;
1148
  flex-direction: row;
 
1156
  transition: background 0.18s;
1157
  gap: 32px;
1158
  }
1159
+ .field-row:last-child {
1160
+ border-bottom: none;
1161
+ }
1162
+ .field-row span {
1163
+ color: #1e293b;
1164
+ font-weight: 700;
1165
+ letter-spacing: 0.2px;
1166
+ min-width: 180px;
1167
+ font-size: 1.08em;
1168
+ margin-right: 32px;
1169
+ text-align: left;
1170
+ display: inline-block;
1171
+ }
1172
+ .field-row b {
1173
+ color: #2563eb;
1174
+ font-weight: 700;
1175
+ word-break: break-word;
1176
+ letter-spacing: 0.1px;
1177
+ font-size: 1.13em;
1178
+ margin-left: 8px;
1179
+ text-align: left;
1180
+ display: inline-block;
1181
+ }
1182
+ .field-row b:hover {
1183
+ color: #0ea5e9;
1184
+ }
 
 
 
 
1185
 
1186
  /* Stylish pills for subgroups */
1187
  .subgroup-pills {
 
1190
  gap: 12px;
1191
  margin-bottom: 18px;
1192
  }
1193
+ .subgroup-pills button {
1194
+ background: linear-gradient(90deg, #38bdf8 0%, #2563eb 100%);
1195
+ border: none;
1196
+ border-radius: 20px;
1197
+ padding: 7px 22px;
1198
+ font-size: 1em;
1199
+ color: #fff;
1200
+ font-weight: 700;
1201
+ cursor: pointer;
1202
+ box-shadow: 0 2px 8px #2563eb22;
1203
+ transition: background 0.18s, color 0.18s, box-shadow 0.18s;
1204
+ outline: none;
1205
+ }
1206
+ .subgroup-pills button.active,
1207
+ .subgroup-pills button:focus {
1208
+ background: linear-gradient(90deg, #2563eb 0%, #38bdf8 100%);
1209
+ color: #fff;
1210
+ box-shadow: 0 4px 16px #38bdf855;
1211
+ }
1212
+ .subgroup-pills button:hover {
1213
+ background: linear-gradient(90deg, #0ea5e9 0%, #2563eb 100%);
1214
+ color: #fff;
1215
+ }
 
 
 
1216
 
1217
  .field-card {
1218
  display: flex;
 
1226
  .section-block {
1227
  padding: 18px 8vw 12px 8vw;
1228
  }
 
1229
  .subgroup-block {
1230
  min-width: 180px;
1231
  padding: 12px 8px 8px 8px;
1232
  }
 
1233
  .field-row span {
1234
  min-width: 120px;
1235
  }
1236
  }
 
1237
  @media (max-width: 600px) {
1238
  .section-block {
1239
  padding: 10px 2vw 8px 2vw;
1240
  }
 
1241
  .subgroup-block {
1242
  min-width: 120px;
1243
  padding: 8px 2px 6px 2px;
1244
  }
 
1245
  .field-row span {
1246
  min-width: 80px;
1247
  font-size: 0.98em;
1248
  }
 
1249
  .field-row b {
1250
  font-size: 1em;
1251
  }
 
1262
  border-radius: 12px;
1263
  box-shadow: 0 2px 8px #2563eb11;
1264
  }
1265
+ .filter-bar select {
1266
+ padding: 6px 18px;
1267
+ border-radius: 6px;
1268
+ border: 1.5px solid #cbd5e1;
1269
+ font-size: 1em;
1270
+ color: #2563eb;
1271
+ background: #fff;
1272
+ font-weight: 600;
1273
+ outline: none;
1274
+ transition: border 0.15s;
1275
+ }
1276
+ .filter-bar select:focus {
1277
+ border: 1.5px solid #38bdf8;
1278
+ }
1279
+ .filter-bar button {
1280
+ padding: 6px 18px;
1281
+ border-radius: 6px;
1282
+ border: none;
1283
+ font-size: 1em;
1284
+ font-weight: 700;
1285
+ cursor: pointer;
1286
+ background: #2563eb;
1287
+ color: #fff;
1288
+ transition: background 0.15s;
1289
+ }
1290
+ .filter-bar button:hover {
1291
+ background: #0ea5e9;
1292
+ }
1293
+ .filter-bar button:last-child {
1294
+ background: #f87171;
1295
+ color: #fff;
1296
+ margin-left: 4px;
1297
+ }
1298
+ .filter-bar button:last-child:hover {
1299
+ background: #ef4444;
1300
+ }
 
 
 
 
 
 
1301
 
1302
  .analytics-summary {
1303
  display: flex;
1304
  gap: 32px;
1305
  margin: 18px 0 8px 0;
1306
  }
 
1307
  .summary-card {
1308
  background: #f8fafc;
1309
  border-radius: 12px;
 
1312
  min-width: 120px;
1313
  text-align: center;
1314
  }
1315
+ .summary-card .summary-label {
1316
+ font-size: 1em;
1317
+ color: #64748b;
1318
+ font-weight: 600;
1319
+ margin-bottom: 6px;
1320
+ }
1321
+ .summary-card .summary-value {
1322
+ font-size: 2em;
1323
+ font-weight: 900;
1324
+ color: #2563eb;
1325
+ }
1326
+ .summary-card.open .summary-value {
1327
+ color: #059669;
1328
+ }
1329
+ .summary-card.closed .summary-value {
1330
+ color: #dc2626;
1331
+ }
 
 
 
 
1332
 
1333
  .record-meta {
1334
  color: #64748b;
 
1338
  font-weight: 500;
1339
  letter-spacing: 0.1px;
1340
  }
1341
+
1342
+
src/app/recordpage/recordpage.component.html CHANGED
@@ -110,9 +110,9 @@
110
  </td>
111
  <td>{{ c.crime || '—' }}</td>
112
  <td>{{ c.dateTime ? (c.dateTime | date:'M/d/yyyy HH:mm') : '—' }}</td>
113
- <td>{{ c.police.address || '—' }}</td>
114
- <td>{{ c.police.name || '—' }}</td>
115
- <td>{{ c.accused.name || '—' }}</td>
116
  <td>{{ c.reportedBy || '—' }}</td>
117
  <td>{{ c.lastUpdated ? (c.lastUpdated | date:'M/d/yyyy HH:mm') : '—' }}</td>
118
  <td>{{ c.verifiedBy || '—' }}</td>
 
110
  </td>
111
  <td>{{ c.crime || '—' }}</td>
112
  <td>{{ c.dateTime ? (c.dateTime | date:'M/d/yyyy HH:mm') : '—' }}</td>
113
+ <td>{{ c.police?.address || '—' }}</td>
114
+ <td>{{ c.police?.name || '—' }}</td>
115
+ <td>{{ c.accused?.name || '—' }}</td>
116
  <td>{{ c.reportedBy || '—' }}</td>
117
  <td>{{ c.lastUpdated ? (c.lastUpdated | date:'M/d/yyyy HH:mm') : '—' }}</td>
118
  <td>{{ c.verifiedBy || '—' }}</td>
src/app/recordpage/recordpage.component.ts CHANGED
@@ -285,14 +285,12 @@ export class RecordpageComponent implements OnInit {
285
  this.selectedCase = c;
286
  this.selectedIndex = i;
287
  this.showDetails = true;
288
- document.body.classList.add('modal-open');
289
  }
290
 
291
  closeDetails(): void {
292
  this.showDetails = false;
293
  this.selectedCase = null;
294
  this.selectedIndex = -1;
295
- document.body.classList.remove('modal-open');
296
  }
297
 
298
  editCase(c: PoliceCase, i: number): void {
 
285
  this.selectedCase = c;
286
  this.selectedIndex = i;
287
  this.showDetails = true;
 
288
  }
289
 
290
  closeDetails(): void {
291
  this.showDetails = false;
292
  this.selectedCase = null;
293
  this.selectedIndex = -1;
 
294
  }
295
 
296
  editCase(c: PoliceCase, i: number): void {
src/app/shared/case-store.service.ts CHANGED
@@ -23,8 +23,6 @@ export interface PoliceCase {
23
  occupation?: string;
24
  };
25
  lastUpdated?: string;
26
- nextAction?: string;
27
- casePriority?: 'High' | 'Medium' | 'Low';
28
  }
29
 
30
  @Injectable({ providedIn: 'root' })
 
23
  occupation?: string;
24
  };
25
  lastUpdated?: string;
 
 
26
  }
27
 
28
  @Injectable({ providedIn: 'root' })