SRVCP commited on
Commit
d46e9be
·
verified ·
1 Parent(s): 1c7c1ae

Upload review-interface.html

Browse files
Files changed (1) hide show
  1. review-interface.html +1607 -0
review-interface.html ADDED
@@ -0,0 +1,1607 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Traffic Violation Review System</title>
7
+ <style>
8
+ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Sora:wght@300;400;600;700&display=swap');
9
+
10
+ :root {
11
+ /* Dark theme - industrial/utilitarian aesthetic */
12
+ --bg-primary: #0a0b0d;
13
+ --bg-secondary: #13151a;
14
+ --bg-tertiary: #1c1f26;
15
+ --bg-card: #1e2229;
16
+ --bg-elevated: #24272f;
17
+
18
+ /* Accent colors - high contrast for speed */
19
+ --accent-approve: #00ff88;
20
+ --accent-reject: #ff3366;
21
+ --accent-escalate: #ffaa00;
22
+ --accent-info: #00d4ff;
23
+ --accent-warning: #ff6b00;
24
+
25
+ /* Text */
26
+ --text-primary: #ffffff;
27
+ --text-secondary: #9ca3af;
28
+ --text-tertiary: #6b7280;
29
+ --text-dim: #4b5563;
30
+
31
+ /* Borders */
32
+ --border-subtle: rgba(255, 255, 255, 0.06);
33
+ --border-medium: rgba(255, 255, 255, 0.12);
34
+ --border-strong: rgba(255, 255, 255, 0.2);
35
+
36
+ /* Confidence indicators */
37
+ --confidence-high: #00ff88;
38
+ --confidence-medium: #ffaa00;
39
+ --confidence-low: #ff3366;
40
+
41
+ /* Shadows */
42
+ --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3);
43
+ --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.4);
44
+ --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.5);
45
+ --shadow-glow: 0 0 24px rgba(0, 212, 255, 0.2);
46
+
47
+ /* Typography */
48
+ --font-display: 'Sora', sans-serif;
49
+ --font-mono: 'JetBrains Mono', monospace;
50
+
51
+ /* Transitions */
52
+ --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
53
+ --transition-base: 250ms cubic-bezier(0.4, 0, 0.2, 1);
54
+ --transition-slow: 400ms cubic-bezier(0.4, 0, 0.2, 1);
55
+ }
56
+
57
+ * {
58
+ margin: 0;
59
+ padding: 0;
60
+ box-sizing: border-box;
61
+ }
62
+
63
+ body {
64
+ font-family: var(--font-display);
65
+ background: var(--bg-primary);
66
+ color: var(--text-primary);
67
+ overflow: hidden;
68
+ height: 100vh;
69
+ position: relative;
70
+ }
71
+
72
+ /* Animated grid background */
73
+ body::before {
74
+ content: '';
75
+ position: fixed;
76
+ inset: 0;
77
+ background-image:
78
+ linear-gradient(to right, rgba(255, 255, 255, 0.02) 1px, transparent 1px),
79
+ linear-gradient(to bottom, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
80
+ background-size: 40px 40px;
81
+ pointer-events: none;
82
+ animation: gridPulse 20s ease-in-out infinite;
83
+ }
84
+
85
+ @keyframes gridPulse {
86
+ 0%, 100% { opacity: 0.3; }
87
+ 50% { opacity: 0.6; }
88
+ }
89
+
90
+ /* Main container */
91
+ .review-container {
92
+ display: flex;
93
+ height: 100vh;
94
+ position: relative;
95
+ z-index: 1;
96
+ }
97
+
98
+ /* Left panel - Video and Evidence */
99
+ .evidence-panel {
100
+ flex: 1;
101
+ padding: 24px;
102
+ display: flex;
103
+ flex-direction: column;
104
+ gap: 20px;
105
+ overflow-y: auto;
106
+ }
107
+
108
+ /* Video card with swipe functionality */
109
+ .video-card {
110
+ position: relative;
111
+ border-radius: 16px;
112
+ overflow: hidden;
113
+ background: var(--bg-card);
114
+ border: 2px solid var(--border-medium);
115
+ box-shadow: var(--shadow-lg);
116
+ transition: all var(--transition-base);
117
+ cursor: grab;
118
+ user-select: none;
119
+ }
120
+
121
+ .video-card.dragging {
122
+ cursor: grabbing;
123
+ transform: scale(0.98);
124
+ }
125
+
126
+ .video-card.swipe-approve {
127
+ border-color: var(--accent-approve);
128
+ box-shadow: 0 0 40px rgba(0, 255, 136, 0.3);
129
+ }
130
+
131
+ .video-card.swipe-reject {
132
+ border-color: var(--accent-reject);
133
+ box-shadow: 0 0 40px rgba(255, 51, 102, 0.3);
134
+ }
135
+
136
+ .video-card.swipe-escalate {
137
+ border-color: var(--accent-escalate);
138
+ box-shadow: 0 0 40px rgba(255, 170, 0, 0.3);
139
+ }
140
+
141
+ .video-wrapper {
142
+ position: relative;
143
+ aspect-ratio: 16 / 9;
144
+ background: #000;
145
+ }
146
+
147
+ .video-player {
148
+ width: 100%;
149
+ height: 100%;
150
+ object-fit: cover;
151
+ }
152
+
153
+ /* Video overlay controls */
154
+ .video-overlay {
155
+ position: absolute;
156
+ inset: 0;
157
+ background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent 50%);
158
+ pointer-events: none;
159
+ opacity: 0;
160
+ transition: opacity var(--transition-fast);
161
+ }
162
+
163
+ .video-card:hover .video-overlay {
164
+ opacity: 1;
165
+ }
166
+
167
+ .video-controls {
168
+ position: absolute;
169
+ bottom: 16px;
170
+ left: 16px;
171
+ right: 16px;
172
+ display: flex;
173
+ align-items: center;
174
+ gap: 12px;
175
+ pointer-events: all;
176
+ }
177
+
178
+ .control-btn {
179
+ width: 40px;
180
+ height: 40px;
181
+ border-radius: 50%;
182
+ background: rgba(255, 255, 255, 0.1);
183
+ backdrop-filter: blur(10px);
184
+ border: 1px solid rgba(255, 255, 255, 0.2);
185
+ display: flex;
186
+ align-items: center;
187
+ justify-content: center;
188
+ cursor: pointer;
189
+ transition: all var(--transition-fast);
190
+ color: white;
191
+ }
192
+
193
+ .control-btn:hover {
194
+ background: rgba(255, 255, 255, 0.2);
195
+ transform: scale(1.1);
196
+ }
197
+
198
+ .control-btn:active {
199
+ transform: scale(0.95);
200
+ }
201
+
202
+ .timeline {
203
+ flex: 1;
204
+ height: 4px;
205
+ background: rgba(255, 255, 255, 0.2);
206
+ border-radius: 2px;
207
+ position: relative;
208
+ cursor: pointer;
209
+ }
210
+
211
+ .timeline-progress {
212
+ height: 100%;
213
+ background: var(--accent-info);
214
+ border-radius: 2px;
215
+ width: 0%;
216
+ transition: width 100ms linear;
217
+ }
218
+
219
+ .timeline-marker {
220
+ position: absolute;
221
+ top: -4px;
222
+ height: 12px;
223
+ width: 3px;
224
+ background: var(--accent-warning);
225
+ border-radius: 2px;
226
+ box-shadow: 0 0 8px rgba(255, 170, 0, 0.6);
227
+ }
228
+
229
+ /* Confidence badge */
230
+ .confidence-badge {
231
+ position: absolute;
232
+ top: 16px;
233
+ right: 16px;
234
+ padding: 8px 16px;
235
+ border-radius: 20px;
236
+ font-size: 13px;
237
+ font-weight: 600;
238
+ font-family: var(--font-mono);
239
+ backdrop-filter: blur(10px);
240
+ border: 1px solid;
241
+ display: flex;
242
+ align-items: center;
243
+ gap: 6px;
244
+ animation: badgePulse 2s ease-in-out infinite;
245
+ }
246
+
247
+ @keyframes badgePulse {
248
+ 0%, 100% { transform: scale(1); }
249
+ 50% { transform: scale(1.05); }
250
+ }
251
+
252
+ .confidence-badge.high {
253
+ background: rgba(0, 255, 136, 0.15);
254
+ border-color: var(--confidence-high);
255
+ color: var(--confidence-high);
256
+ }
257
+
258
+ .confidence-badge.medium {
259
+ background: rgba(255, 170, 0, 0.15);
260
+ border-color: var(--confidence-medium);
261
+ color: var(--confidence-medium);
262
+ }
263
+
264
+ .confidence-badge.low {
265
+ background: rgba(255, 51, 102, 0.15);
266
+ border-color: var(--confidence-low);
267
+ color: var(--confidence-low);
268
+ }
269
+
270
+ .confidence-dot {
271
+ width: 6px;
272
+ height: 6px;
273
+ border-radius: 50%;
274
+ background: currentColor;
275
+ animation: dotPulse 1.5s ease-in-out infinite;
276
+ }
277
+
278
+ @keyframes dotPulse {
279
+ 0%, 100% { opacity: 1; }
280
+ 50% { opacity: 0.4; }
281
+ }
282
+
283
+ /* Swipe direction hints */
284
+ .swipe-hint {
285
+ position: absolute;
286
+ top: 50%;
287
+ transform: translateY(-50%);
288
+ font-size: 48px;
289
+ opacity: 0;
290
+ transition: opacity var(--transition-fast);
291
+ pointer-events: none;
292
+ display: flex;
293
+ flex-direction: column;
294
+ align-items: center;
295
+ gap: 8px;
296
+ }
297
+
298
+ .swipe-hint-left {
299
+ left: 40px;
300
+ }
301
+
302
+ .swipe-hint-right {
303
+ right: 40px;
304
+ }
305
+
306
+ .swipe-hint-up {
307
+ top: 40px;
308
+ left: 50%;
309
+ transform: translateX(-50%);
310
+ }
311
+
312
+ .swipe-hint span {
313
+ font-size: 14px;
314
+ font-weight: 600;
315
+ text-transform: uppercase;
316
+ letter-spacing: 1px;
317
+ }
318
+
319
+ .video-card.swipe-approve .swipe-hint-right {
320
+ opacity: 1;
321
+ color: var(--accent-approve);
322
+ }
323
+
324
+ .video-card.swipe-reject .swipe-hint-left {
325
+ opacity: 1;
326
+ color: var(--accent-reject);
327
+ }
328
+
329
+ .video-card.swipe-escalate .swipe-hint-up {
330
+ opacity: 1;
331
+ color: var(--accent-escalate);
332
+ }
333
+
334
+ /* Key frames section */
335
+ .keyframes-section {
336
+ display: grid;
337
+ grid-template-columns: repeat(4, 1fr);
338
+ gap: 12px;
339
+ }
340
+
341
+ .keyframe {
342
+ position: relative;
343
+ aspect-ratio: 16 / 9;
344
+ border-radius: 12px;
345
+ overflow: hidden;
346
+ border: 2px solid var(--border-subtle);
347
+ cursor: pointer;
348
+ transition: all var(--transition-fast);
349
+ background: var(--bg-secondary);
350
+ }
351
+
352
+ .keyframe:hover {
353
+ border-color: var(--accent-info);
354
+ transform: scale(1.05);
355
+ box-shadow: var(--shadow-glow);
356
+ }
357
+
358
+ .keyframe.active {
359
+ border-color: var(--accent-info);
360
+ box-shadow: var(--shadow-glow);
361
+ }
362
+
363
+ .keyframe img {
364
+ width: 100%;
365
+ height: 100%;
366
+ object-fit: cover;
367
+ }
368
+
369
+ .keyframe-step {
370
+ position: absolute;
371
+ top: 8px;
372
+ left: 8px;
373
+ width: 24px;
374
+ height: 24px;
375
+ border-radius: 50%;
376
+ background: var(--accent-info);
377
+ color: var(--bg-primary);
378
+ display: flex;
379
+ align-items: center;
380
+ justify-content: center;
381
+ font-size: 12px;
382
+ font-weight: 700;
383
+ font-family: var(--font-mono);
384
+ box-shadow: 0 2px 8px rgba(0, 212, 255, 0.4);
385
+ }
386
+
387
+ .keyframe-pulse {
388
+ position: absolute;
389
+ inset: 0;
390
+ border-radius: 12px;
391
+ animation: framePulse 2s ease-in-out infinite;
392
+ pointer-events: none;
393
+ }
394
+
395
+ .keyframe.active .keyframe-pulse {
396
+ border: 2px solid var(--accent-info);
397
+ }
398
+
399
+ @keyframes framePulse {
400
+ 0%, 100% { opacity: 1; transform: scale(1); }
401
+ 50% { opacity: 0.3; transform: scale(1.02); }
402
+ }
403
+
404
+ /* License plate card */
405
+ .license-plate-card {
406
+ background: var(--bg-card);
407
+ border: 2px solid var(--border-medium);
408
+ border-radius: 12px;
409
+ padding: 20px;
410
+ display: flex;
411
+ justify-content: space-between;
412
+ align-items: center;
413
+ box-shadow: var(--shadow-md);
414
+ }
415
+
416
+ .plate-display {
417
+ flex: 1;
418
+ }
419
+
420
+ .plate-label {
421
+ font-size: 12px;
422
+ color: var(--text-secondary);
423
+ text-transform: uppercase;
424
+ letter-spacing: 1px;
425
+ margin-bottom: 8px;
426
+ }
427
+
428
+ .plate-number {
429
+ font-size: 32px;
430
+ font-weight: 700;
431
+ font-family: var(--font-mono);
432
+ letter-spacing: 4px;
433
+ color: var(--text-primary);
434
+ text-transform: uppercase;
435
+ }
436
+
437
+ .plate-confidence {
438
+ text-align: right;
439
+ }
440
+
441
+ .plate-confidence-label {
442
+ font-size: 12px;
443
+ color: var(--text-secondary);
444
+ text-transform: uppercase;
445
+ letter-spacing: 1px;
446
+ margin-bottom: 8px;
447
+ }
448
+
449
+ .plate-confidence-value {
450
+ font-size: 28px;
451
+ font-weight: 700;
452
+ font-family: var(--font-mono);
453
+ }
454
+
455
+ /* Right panel - Context and Actions */
456
+ .action-panel {
457
+ width: 420px;
458
+ background: var(--bg-secondary);
459
+ border-left: 1px solid var(--border-medium);
460
+ display: flex;
461
+ flex-direction: column;
462
+ overflow-y: auto;
463
+ }
464
+
465
+ /* Violation info header */
466
+ .violation-header {
467
+ padding: 24px;
468
+ background: var(--bg-card);
469
+ border-bottom: 1px solid var(--border-medium);
470
+ }
471
+
472
+ .violation-type {
473
+ font-size: 20px;
474
+ font-weight: 700;
475
+ color: var(--text-primary);
476
+ margin-bottom: 8px;
477
+ text-transform: uppercase;
478
+ letter-spacing: 0.5px;
479
+ }
480
+
481
+ .violation-meta {
482
+ display: flex;
483
+ flex-direction: column;
484
+ gap: 4px;
485
+ font-size: 13px;
486
+ color: var(--text-secondary);
487
+ }
488
+
489
+ .violation-meta-item {
490
+ display: flex;
491
+ align-items: center;
492
+ gap: 8px;
493
+ }
494
+
495
+ .meta-icon {
496
+ width: 16px;
497
+ height: 16px;
498
+ opacity: 0.6;
499
+ }
500
+
501
+ /* Context section */
502
+ .context-section {
503
+ padding: 20px 24px;
504
+ }
505
+
506
+ .context-toggle {
507
+ width: 100%;
508
+ background: var(--bg-elevated);
509
+ border: 1px solid var(--border-subtle);
510
+ border-radius: 10px;
511
+ padding: 16px;
512
+ display: flex;
513
+ justify-content: space-between;
514
+ align-items: center;
515
+ cursor: pointer;
516
+ transition: all var(--transition-fast);
517
+ color: var(--text-primary);
518
+ font-size: 14px;
519
+ font-weight: 600;
520
+ }
521
+
522
+ .context-toggle:hover {
523
+ background: var(--bg-card);
524
+ border-color: var(--border-medium);
525
+ }
526
+
527
+ .context-toggle.active {
528
+ border-color: var(--accent-info);
529
+ background: rgba(0, 212, 255, 0.05);
530
+ }
531
+
532
+ .context-content {
533
+ max-height: 0;
534
+ overflow: hidden;
535
+ transition: max-height var(--transition-slow);
536
+ }
537
+
538
+ .context-content.expanded {
539
+ max-height: 500px;
540
+ }
541
+
542
+ .context-grid {
543
+ display: grid;
544
+ gap: 12px;
545
+ padding: 16px 0 0;
546
+ }
547
+
548
+ .context-item {
549
+ display: flex;
550
+ justify-content: space-between;
551
+ padding: 12px;
552
+ background: var(--bg-tertiary);
553
+ border-radius: 8px;
554
+ border: 1px solid var(--border-subtle);
555
+ }
556
+
557
+ .context-label {
558
+ font-size: 13px;
559
+ color: var(--text-secondary);
560
+ }
561
+
562
+ .context-value {
563
+ font-size: 13px;
564
+ font-weight: 600;
565
+ color: var(--text-primary);
566
+ font-family: var(--font-mono);
567
+ }
568
+
569
+ .context-alert {
570
+ display: flex;
571
+ align-items: center;
572
+ gap: 8px;
573
+ padding: 12px;
574
+ background: rgba(255, 170, 0, 0.1);
575
+ border: 1px solid var(--accent-warning);
576
+ border-radius: 8px;
577
+ color: var(--accent-warning);
578
+ font-size: 13px;
579
+ }
580
+
581
+ /* Notes section */
582
+ .notes-section {
583
+ padding: 20px 24px;
584
+ flex: 1;
585
+ }
586
+
587
+ .notes-header {
588
+ display: flex;
589
+ justify-content: space-between;
590
+ align-items: center;
591
+ margin-bottom: 12px;
592
+ }
593
+
594
+ .notes-label {
595
+ font-size: 14px;
596
+ font-weight: 600;
597
+ color: var(--text-primary);
598
+ }
599
+
600
+ .voice-btn {
601
+ width: 36px;
602
+ height: 36px;
603
+ border-radius: 50%;
604
+ border: none;
605
+ background: var(--accent-info);
606
+ color: var(--bg-primary);
607
+ display: flex;
608
+ align-items: center;
609
+ justify-content: center;
610
+ cursor: pointer;
611
+ transition: all var(--transition-fast);
612
+ }
613
+
614
+ .voice-btn:hover {
615
+ transform: scale(1.1);
616
+ box-shadow: 0 4px 16px rgba(0, 212, 255, 0.4);
617
+ }
618
+
619
+ .voice-btn.recording {
620
+ background: var(--accent-reject);
621
+ animation: recording-pulse 1s ease-in-out infinite;
622
+ }
623
+
624
+ @keyframes recording-pulse {
625
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(255, 51, 102, 0.7); }
626
+ 50% { box-shadow: 0 0 0 10px rgba(255, 51, 102, 0); }
627
+ }
628
+
629
+ .notes-textarea {
630
+ width: 100%;
631
+ min-height: 120px;
632
+ background: var(--bg-tertiary);
633
+ border: 1px solid var(--border-subtle);
634
+ border-radius: 10px;
635
+ padding: 14px;
636
+ color: var(--text-primary);
637
+ font-size: 14px;
638
+ font-family: var(--font-display);
639
+ resize: vertical;
640
+ transition: all var(--transition-fast);
641
+ }
642
+
643
+ .notes-textarea:focus {
644
+ outline: none;
645
+ border-color: var(--accent-info);
646
+ background: var(--bg-card);
647
+ }
648
+
649
+ .recording-indicator {
650
+ display: flex;
651
+ align-items: center;
652
+ gap: 8px;
653
+ margin-top: 8px;
654
+ color: var(--accent-reject);
655
+ font-size: 13px;
656
+ font-weight: 600;
657
+ }
658
+
659
+ .recording-dot {
660
+ width: 8px;
661
+ height: 8px;
662
+ border-radius: 50%;
663
+ background: var(--accent-reject);
664
+ animation: dotPulse 1s ease-in-out infinite;
665
+ }
666
+
667
+ /* Decision buttons */
668
+ .decision-section {
669
+ padding: 24px;
670
+ background: var(--bg-card);
671
+ border-top: 1px solid var(--border-medium);
672
+ }
673
+
674
+ .decision-btn {
675
+ width: 100%;
676
+ padding: 18px;
677
+ border: none;
678
+ border-radius: 12px;
679
+ font-size: 16px;
680
+ font-weight: 700;
681
+ text-transform: uppercase;
682
+ letter-spacing: 1px;
683
+ cursor: pointer;
684
+ transition: all var(--transition-fast);
685
+ display: flex;
686
+ align-items: center;
687
+ justify-content: center;
688
+ gap: 10px;
689
+ margin-bottom: 12px;
690
+ position: relative;
691
+ overflow: hidden;
692
+ font-family: var(--font-display);
693
+ }
694
+
695
+ .decision-btn::before {
696
+ content: '';
697
+ position: absolute;
698
+ inset: 0;
699
+ background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent);
700
+ transform: translateX(-100%);
701
+ transition: transform 0.6s;
702
+ }
703
+
704
+ .decision-btn:hover::before {
705
+ transform: translateX(100%);
706
+ }
707
+
708
+ .decision-btn:active {
709
+ transform: scale(0.97);
710
+ }
711
+
712
+ .btn-approve {
713
+ background: var(--accent-approve);
714
+ color: var(--bg-primary);
715
+ box-shadow: 0 4px 16px rgba(0, 255, 136, 0.3);
716
+ }
717
+
718
+ .btn-approve:hover {
719
+ background: #00dd77;
720
+ box-shadow: 0 6px 24px rgba(0, 255, 136, 0.5);
721
+ }
722
+
723
+ .btn-reject {
724
+ background: var(--accent-reject);
725
+ color: white;
726
+ box-shadow: 0 4px 16px rgba(255, 51, 102, 0.3);
727
+ }
728
+
729
+ .btn-reject:hover {
730
+ background: #ee2255;
731
+ box-shadow: 0 6px 24px rgba(255, 51, 102, 0.5);
732
+ }
733
+
734
+ .btn-escalate {
735
+ background: var(--accent-escalate);
736
+ color: var(--bg-primary);
737
+ box-shadow: 0 4px 16px rgba(255, 170, 0, 0.3);
738
+ }
739
+
740
+ .btn-escalate:hover {
741
+ background: #ee9900;
742
+ box-shadow: 0 6px 24px rgba(255, 170, 0, 0.5);
743
+ }
744
+
745
+ .btn-shortcut {
746
+ font-size: 11px;
747
+ opacity: 0.7;
748
+ font-weight: 400;
749
+ letter-spacing: 0.5px;
750
+ }
751
+
752
+ /* Keyboard shortcuts help */
753
+ .shortcuts-help {
754
+ margin-top: 12px;
755
+ padding: 16px;
756
+ background: rgba(255, 255, 255, 0.02);
757
+ border: 1px solid var(--border-subtle);
758
+ border-radius: 10px;
759
+ }
760
+
761
+ .shortcuts-title {
762
+ font-size: 12px;
763
+ font-weight: 600;
764
+ color: var(--text-secondary);
765
+ margin-bottom: 10px;
766
+ text-transform: uppercase;
767
+ letter-spacing: 1px;
768
+ }
769
+
770
+ .shortcuts-grid {
771
+ display: grid;
772
+ grid-template-columns: 1fr 1fr;
773
+ gap: 8px;
774
+ font-size: 12px;
775
+ color: var(--text-tertiary);
776
+ }
777
+
778
+ .shortcut-item {
779
+ display: flex;
780
+ align-items: center;
781
+ gap: 6px;
782
+ }
783
+
784
+ .shortcut-key {
785
+ padding: 2px 6px;
786
+ background: var(--bg-tertiary);
787
+ border: 1px solid var(--border-subtle);
788
+ border-radius: 4px;
789
+ font-family: var(--font-mono);
790
+ font-size: 11px;
791
+ font-weight: 600;
792
+ color: var(--text-secondary);
793
+ }
794
+
795
+ /* Progress indicator */
796
+ .progress-bar {
797
+ position: fixed;
798
+ top: 0;
799
+ left: 0;
800
+ right: 0;
801
+ height: 3px;
802
+ background: var(--bg-secondary);
803
+ z-index: 1000;
804
+ }
805
+
806
+ .progress-fill {
807
+ height: 100%;
808
+ background: linear-gradient(90deg, var(--accent-info), var(--accent-approve));
809
+ width: 0%;
810
+ transition: width var(--transition-slow);
811
+ }
812
+
813
+ /* Stats overlay */
814
+ .stats-overlay {
815
+ position: fixed;
816
+ top: 24px;
817
+ left: 24px;
818
+ background: rgba(0, 0, 0, 0.8);
819
+ backdrop-filter: blur(20px);
820
+ border: 1px solid var(--border-medium);
821
+ border-radius: 12px;
822
+ padding: 16px 20px;
823
+ display: flex;
824
+ gap: 24px;
825
+ z-index: 100;
826
+ box-shadow: var(--shadow-lg);
827
+ }
828
+
829
+ .stat-item {
830
+ display: flex;
831
+ flex-direction: column;
832
+ gap: 4px;
833
+ }
834
+
835
+ .stat-label {
836
+ font-size: 11px;
837
+ color: var(--text-secondary);
838
+ text-transform: uppercase;
839
+ letter-spacing: 1px;
840
+ }
841
+
842
+ .stat-value {
843
+ font-size: 20px;
844
+ font-weight: 700;
845
+ font-family: var(--font-mono);
846
+ color: var(--text-primary);
847
+ }
848
+
849
+ .stat-value.highlight {
850
+ color: var(--accent-info);
851
+ }
852
+
853
+ /* Review timer */
854
+ .review-timer {
855
+ position: fixed;
856
+ bottom: 24px;
857
+ left: 50%;
858
+ transform: translateX(-50%);
859
+ background: rgba(0, 0, 0, 0.9);
860
+ backdrop-filter: blur(20px);
861
+ border: 2px solid var(--border-medium);
862
+ border-radius: 30px;
863
+ padding: 12px 24px;
864
+ display: flex;
865
+ align-items: center;
866
+ gap: 12px;
867
+ z-index: 100;
868
+ box-shadow: var(--shadow-lg);
869
+ }
870
+
871
+ .timer-icon {
872
+ width: 20px;
873
+ height: 20px;
874
+ color: var(--accent-info);
875
+ }
876
+
877
+ .timer-value {
878
+ font-size: 24px;
879
+ font-weight: 700;
880
+ font-family: var(--font-mono);
881
+ color: var(--text-primary);
882
+ min-width: 80px;
883
+ text-align: center;
884
+ }
885
+
886
+ .timer-value.warning {
887
+ color: var(--accent-warning);
888
+ }
889
+
890
+ .timer-value.danger {
891
+ color: var(--accent-reject);
892
+ animation: timerBlink 1s ease-in-out infinite;
893
+ }
894
+
895
+ @keyframes timerBlink {
896
+ 0%, 100% { opacity: 1; }
897
+ 50% { opacity: 0.5; }
898
+ }
899
+
900
+ .timer-target {
901
+ font-size: 12px;
902
+ color: var(--text-tertiary);
903
+ font-weight: 500;
904
+ }
905
+
906
+ /* Success/completion animation */
907
+ .completion-overlay {
908
+ position: fixed;
909
+ inset: 0;
910
+ background: rgba(0, 0, 0, 0.95);
911
+ display: none;
912
+ align-items: center;
913
+ justify-content: center;
914
+ z-index: 2000;
915
+ animation: fadeIn var(--transition-base);
916
+ }
917
+
918
+ .completion-overlay.show {
919
+ display: flex;
920
+ }
921
+
922
+ @keyframes fadeIn {
923
+ from { opacity: 0; }
924
+ to { opacity: 1; }
925
+ }
926
+
927
+ .completion-content {
928
+ text-align: center;
929
+ animation: scaleIn var(--transition-slow);
930
+ }
931
+
932
+ @keyframes scaleIn {
933
+ from { transform: scale(0.8); opacity: 0; }
934
+ to { transform: scale(1); opacity: 1; }
935
+ }
936
+
937
+ .completion-icon {
938
+ font-size: 80px;
939
+ margin-bottom: 20px;
940
+ }
941
+
942
+ .completion-title {
943
+ font-size: 32px;
944
+ font-weight: 700;
945
+ margin-bottom: 12px;
946
+ }
947
+
948
+ .completion-subtitle {
949
+ font-size: 18px;
950
+ color: var(--text-secondary);
951
+ margin-bottom: 32px;
952
+ }
953
+
954
+ .completion-stats {
955
+ display: flex;
956
+ gap: 40px;
957
+ justify-content: center;
958
+ margin-bottom: 32px;
959
+ }
960
+
961
+ .completion-stat {
962
+ text-align: center;
963
+ }
964
+
965
+ .completion-stat-value {
966
+ font-size: 36px;
967
+ font-weight: 700;
968
+ font-family: var(--font-mono);
969
+ margin-bottom: 8px;
970
+ }
971
+
972
+ .completion-stat-label {
973
+ font-size: 13px;
974
+ color: var(--text-secondary);
975
+ text-transform: uppercase;
976
+ letter-spacing: 1px;
977
+ }
978
+
979
+ .next-case-btn {
980
+ padding: 18px 36px;
981
+ background: var(--accent-info);
982
+ border: none;
983
+ border-radius: 12px;
984
+ color: var(--bg-primary);
985
+ font-size: 16px;
986
+ font-weight: 700;
987
+ text-transform: uppercase;
988
+ letter-spacing: 1px;
989
+ cursor: pointer;
990
+ transition: all var(--transition-fast);
991
+ font-family: var(--font-display);
992
+ }
993
+
994
+ .next-case-btn:hover {
995
+ background: #00bbee;
996
+ transform: translateY(-2px);
997
+ box-shadow: 0 8px 24px rgba(0, 212, 255, 0.4);
998
+ }
999
+
1000
+ /* Scrollbar styling */
1001
+ ::-webkit-scrollbar {
1002
+ width: 8px;
1003
+ }
1004
+
1005
+ ::-webkit-scrollbar-track {
1006
+ background: var(--bg-primary);
1007
+ }
1008
+
1009
+ ::-webkit-scrollbar-thumb {
1010
+ background: var(--border-strong);
1011
+ border-radius: 4px;
1012
+ }
1013
+
1014
+ ::-webkit-scrollbar-thumb:hover {
1015
+ background: var(--border-medium);
1016
+ }
1017
+ </style>
1018
+ </head>
1019
+ <body>
1020
+ <!-- Progress bar -->
1021
+ <div class="progress-bar">
1022
+ <div class="progress-fill" id="progressFill"></div>
1023
+ </div>
1024
+
1025
+ <!-- Stats overlay -->
1026
+ <div class="stats-overlay">
1027
+ <div class="stat-item">
1028
+ <div class="stat-label">Reviewed Today</div>
1029
+ <div class="stat-value" id="reviewedCount">127</div>
1030
+ </div>
1031
+ <div class="stat-item">
1032
+ <div class="stat-label">Avg Time</div>
1033
+ <div class="stat-value highlight" id="avgTime">8.4s</div>
1034
+ </div>
1035
+ <div class="stat-item">
1036
+ <div class="stat-label">Remaining</div>
1037
+ <div class="stat-value" id="remainingCount">43</div>
1038
+ </div>
1039
+ </div>
1040
+
1041
+ <!-- Review timer -->
1042
+ <div class="review-timer">
1043
+ <svg class="timer-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1044
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
1045
+ </svg>
1046
+ <div class="timer-value" id="timerValue">00.0s</div>
1047
+ <div class="timer-target">Target: <10s</div>
1048
+ </div>
1049
+
1050
+ <!-- Main review container -->
1051
+ <div class="review-container">
1052
+ <!-- Left panel -->
1053
+ <div class="evidence-panel">
1054
+ <!-- Video card with swipe -->
1055
+ <div class="video-card" id="videoCard">
1056
+ <div class="video-wrapper">
1057
+ <video class="video-player" id="videoPlayer" loop>
1058
+ <source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4" type="video/mp4">
1059
+ </video>
1060
+
1061
+ <div class="video-overlay">
1062
+ <div class="video-controls">
1063
+ <button class="control-btn" id="playPauseBtn">
1064
+ <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
1065
+ <path d="M8 5v14l11-7z"/>
1066
+ </svg>
1067
+ </button>
1068
+ <div class="timeline" id="timeline">
1069
+ <div class="timeline-progress" id="timelineProgress"></div>
1070
+ <div class="timeline-marker" style="left: 35%;"></div>
1071
+ </div>
1072
+ <button class="control-btn" id="muteBtn">
1073
+ <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
1074
+ <path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02z"/>
1075
+ </svg>
1076
+ </button>
1077
+ </div>
1078
+ </div>
1079
+
1080
+ <div class="confidence-badge high" id="confidenceBadge">
1081
+ <span class="confidence-dot"></span>
1082
+ <span id="confidenceText">94.2%</span>
1083
+ </div>
1084
+
1085
+ <!-- Swipe hints -->
1086
+ <div class="swipe-hint swipe-hint-left">
1087
+ ✕<br><span>Reject</span>
1088
+ </div>
1089
+ <div class="swipe-hint swipe-hint-right">
1090
+ ✓<br><span>Approve</span>
1091
+ </div>
1092
+ <div class="swipe-hint swipe-hint-up">
1093
+ ⬆<br><span>Escalate</span>
1094
+ </div>
1095
+ </div>
1096
+ </div>
1097
+
1098
+ <!-- Key frames -->
1099
+ <div class="keyframes-section">
1100
+ <div class="keyframe active">
1101
+ <img src="https://placehold.co/320x180/1a1a2e/00ff88?text=Frame+1" alt="Key frame 1">
1102
+ <div class="keyframe-step">1</div>
1103
+ <div class="keyframe-pulse"></div>
1104
+ </div>
1105
+ <div class="keyframe">
1106
+ <img src="https://placehold.co/320x180/1a1a2e/ffaa00?text=Violation" alt="Key frame 2">
1107
+ <div class="keyframe-step">2</div>
1108
+ </div>
1109
+ <div class="keyframe">
1110
+ <img src="https://placehold.co/320x180/1a1a2e/ff3366?text=License" alt="Key frame 3">
1111
+ <div class="keyframe-step">3</div>
1112
+ </div>
1113
+ <div class="keyframe">
1114
+ <img src="https://placehold.co/320x180/1a1a2e/00d4ff?text=Context" alt="Key frame 4">
1115
+ <div class="keyframe-step">4</div>
1116
+ </div>
1117
+ </div>
1118
+
1119
+ <!-- License plate -->
1120
+ <div class="license-plate-card">
1121
+ <div class="plate-display">
1122
+ <div class="plate-label">License Plate</div>
1123
+ <div class="plate-number" id="plateNumber">MH 02 AB 1234</div>
1124
+ </div>
1125
+ <div class="plate-confidence">
1126
+ <div class="plate-confidence-label">OCR Confidence</div>
1127
+ <div class="plate-confidence-value" style="color: var(--confidence-high);" id="plateConfidence">97.8%</div>
1128
+ </div>
1129
+ </div>
1130
+ </div>
1131
+
1132
+ <!-- Right panel -->
1133
+ <div class="action-panel">
1134
+ <!-- Violation header -->
1135
+ <div class="violation-header">
1136
+ <div class="violation-type" id="violationType">Red Light Running</div>
1137
+ <div class="violation-meta">
1138
+ <div class="violation-meta-item">
1139
+ <svg class="meta-icon" fill="currentColor" viewBox="0 0 24 24">
1140
+ <path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/>
1141
+ </svg>
1142
+ <span id="location">MG Road Junction, Bangalore</span>
1143
+ </div>
1144
+ <div class="violation-meta-item">
1145
+ <svg class="meta-icon" fill="currentColor" viewBox="0 0 24 24">
1146
+ <path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"/>
1147
+ </svg>
1148
+ <span id="timestamp">Today, 14:23:45</span>
1149
+ </div>
1150
+ <div class="violation-meta-item">
1151
+ <svg class="meta-icon" fill="currentColor" viewBox="0 0 24 24">
1152
+ <path d="M12 2C8.13 2 5 5.13 5 9c0 2.38 2.19 5.44 5 9.88 2.81-4.44 5-7.5 5-9.88 0-3.87-3.13-7-7-7z"/>
1153
+ </svg>
1154
+ <span id="camera">Camera: CAM_BLR_001</span>
1155
+ </div>
1156
+ </div>
1157
+ </div>
1158
+
1159
+ <!-- Context section -->
1160
+ <div class="context-section">
1161
+ <button class="context-toggle" id="contextToggle">
1162
+ <span>Contextual Factors</span>
1163
+ <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24" id="contextIcon">
1164
+ <path d="M7 10l5 5 5-5z"/>
1165
+ </svg>
1166
+ </button>
1167
+ <div class="context-content" id="contextContent">
1168
+ <div class="context-grid">
1169
+ <div class="context-item">
1170
+ <span class="context-label">Weather</span>
1171
+ <span class="context-value">Clear</span>
1172
+ </div>
1173
+ <div class="context-item">
1174
+ <span class="context-label">Visibility</span>
1175
+ <span class="context-value">5000m</span>
1176
+ </div>
1177
+ <div class="context-item">
1178
+ <span class="context-label">Traffic Density</span>
1179
+ <span class="context-value">Moderate</span>
1180
+ </div>
1181
+ <div class="context-item">
1182
+ <span class="context-label">Time of Day</span>
1183
+ <span class="context-value">Afternoon</span>
1184
+ </div>
1185
+ <div class="context-alert">
1186
+ <svg width="16" height="16" fill="currentColor" viewBox="0 0 24 24">
1187
+ <path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>
1188
+ </svg>
1189
+ <span>Road construction nearby</span>
1190
+ </div>
1191
+ </div>
1192
+ </div>
1193
+ </div>
1194
+
1195
+ <!-- Notes section -->
1196
+ <div class="notes-section">
1197
+ <div class="notes-header">
1198
+ <div class="notes-label">Notes</div>
1199
+ <button class="voice-btn" id="voiceBtn">
1200
+ <svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
1201
+ <path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z"/>
1202
+ <path d="M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z"/>
1203
+ </svg>
1204
+ </button>
1205
+ </div>
1206
+ <textarea class="notes-textarea" id="notesTextarea" placeholder="Add notes or use voice recording..."></textarea>
1207
+ <div class="recording-indicator" id="recordingIndicator" style="display: none;">
1208
+ <span class="recording-dot"></span>
1209
+ <span>Recording...</span>
1210
+ </div>
1211
+ </div>
1212
+
1213
+ <!-- Decision buttons -->
1214
+ <div class="decision-section">
1215
+ <button class="decision-btn btn-approve" id="approveBtn">
1216
+ <svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
1217
+ <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
1218
+ </svg>
1219
+ <span>Approve Citation</span>
1220
+ <span class="btn-shortcut">→ or D</span>
1221
+ </button>
1222
+
1223
+ <button class="decision-btn btn-reject" id="rejectBtn">
1224
+ <svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
1225
+ <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
1226
+ </svg>
1227
+ <span>Dismiss</span>
1228
+ <span class="btn-shortcut">← or A</span>
1229
+ </button>
1230
+
1231
+ <button class="decision-btn btn-escalate" id="escalateBtn">
1232
+ <svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
1233
+ <path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>
1234
+ </svg>
1235
+ <span>Escalate to Senior</span>
1236
+ <span class="btn-shortcut">↑ or W</span>
1237
+ </button>
1238
+
1239
+ <!-- Keyboard shortcuts -->
1240
+ <div class="shortcuts-help">
1241
+ <div class="shortcuts-title">Keyboard Shortcuts</div>
1242
+ <div class="shortcuts-grid">
1243
+ <div class="shortcut-item">
1244
+ <span class="shortcut-key">Space</span>
1245
+ <span>Play/Pause</span>
1246
+ </div>
1247
+ <div class="shortcut-item">
1248
+ <span class="shortcut-key">M</span>
1249
+ <span>Mute</span>
1250
+ </div>
1251
+ <div class="shortcut-item">
1252
+ <span class="shortcut-key">→</span>
1253
+ <span>Approve</span>
1254
+ </div>
1255
+ <div class="shortcut-item">
1256
+ <span class="shortcut-key">←</span>
1257
+ <span>Reject</span>
1258
+ </div>
1259
+ <div class="shortcut-item">
1260
+ <span class="shortcut-key">↑</span>
1261
+ <span>Escalate</span>
1262
+ </div>
1263
+ <div class="shortcut-item">
1264
+ <span class="shortcut-key">C</span>
1265
+ <span>Context</span>
1266
+ </div>
1267
+ </div>
1268
+ </div>
1269
+ </div>
1270
+ </div>
1271
+ </div>
1272
+
1273
+ <!-- Completion overlay -->
1274
+ <div class="completion-overlay" id="completionOverlay">
1275
+ <div class="completion-content">
1276
+ <div class="completion-icon" id="completionIcon">✓</div>
1277
+ <div class="completion-title" id="completionTitle">Citation Approved</div>
1278
+ <div class="completion-subtitle">Review completed successfully</div>
1279
+ <div class="completion-stats">
1280
+ <div class="completion-stat">
1281
+ <div class="completion-stat-value" id="reviewTime">7.2s</div>
1282
+ <div class="completion-stat-label">Review Time</div>
1283
+ </div>
1284
+ <div class="completion-stat">
1285
+ <div class="completion-stat-value" id="sessionCount">128</div>
1286
+ <div class="completion-stat-label">Session Total</div>
1287
+ </div>
1288
+ </div>
1289
+ <button class="next-case-btn" id="nextCaseBtn">Next Case →</button>
1290
+ </div>
1291
+ </div>
1292
+
1293
+ <script>
1294
+ // State
1295
+ let reviewStartTime = Date.now();
1296
+ let isRecording = false;
1297
+ let isDragging = false;
1298
+ let startX = 0;
1299
+ let startY = 0;
1300
+ let currentX = 0;
1301
+ let currentY = 0;
1302
+ let reviewedToday = 127;
1303
+ let avgReviewTime = 8.4;
1304
+ let remainingCases = 43;
1305
+
1306
+ // Elements
1307
+ const videoCard = document.getElementById('videoCard');
1308
+ const videoPlayer = document.getElementById('videoPlayer');
1309
+ const playPauseBtn = document.getElementById('playPauseBtn');
1310
+ const muteBtn = document.getElementById('muteBtn');
1311
+ const timeline = document.getElementById('timeline');
1312
+ const timelineProgress = document.getElementById('timelineProgress');
1313
+ const contextToggle = document.getElementById('contextToggle');
1314
+ const contextContent = document.getElementById('contextContent');
1315
+ const contextIcon = document.getElementById('contextIcon');
1316
+ const voiceBtn = document.getElementById('voiceBtn');
1317
+ const recordingIndicator = document.getElementById('recordingIndicator');
1318
+ const approveBtn = document.getElementById('approveBtn');
1319
+ const rejectBtn = document.getElementById('rejectBtn');
1320
+ const escalateBtn = document.getElementById('escalateBtn');
1321
+ const timerValue = document.getElementById('timerValue');
1322
+ const completionOverlay = document.getElementById('completionOverlay');
1323
+ const nextCaseBtn = document.getElementById('nextCaseBtn');
1324
+
1325
+ // Timer update
1326
+ function updateTimer() {
1327
+ const elapsed = (Date.now() - reviewStartTime) / 1000;
1328
+ timerValue.textContent = elapsed.toFixed(1) + 's';
1329
+
1330
+ if (elapsed < 10) {
1331
+ timerValue.className = 'timer-value';
1332
+ } else if (elapsed < 15) {
1333
+ timerValue.className = 'timer-value warning';
1334
+ } else {
1335
+ timerValue.className = 'timer-value danger';
1336
+ }
1337
+ }
1338
+
1339
+ setInterval(updateTimer, 100);
1340
+
1341
+ // Video controls
1342
+ playPauseBtn.addEventListener('click', () => {
1343
+ if (videoPlayer.paused) {
1344
+ videoPlayer.play();
1345
+ playPauseBtn.innerHTML = '<svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24"><path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/></svg>';
1346
+ } else {
1347
+ videoPlayer.pause();
1348
+ playPauseBtn.innerHTML = '<svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>';
1349
+ }
1350
+ });
1351
+
1352
+ muteBtn.addEventListener('click', () => {
1353
+ videoPlayer.muted = !videoPlayer.muted;
1354
+ if (videoPlayer.muted) {
1355
+ muteBtn.innerHTML = '<svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/></svg>';
1356
+ } else {
1357
+ muteBtn.innerHTML = '<svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02z"/></svg>';
1358
+ }
1359
+ });
1360
+
1361
+ videoPlayer.addEventListener('timeupdate', () => {
1362
+ const progress = (videoPlayer.currentTime / videoPlayer.duration) * 100;
1363
+ timelineProgress.style.width = progress + '%';
1364
+ });
1365
+
1366
+ timeline.addEventListener('click', (e) => {
1367
+ const rect = timeline.getBoundingClientRect();
1368
+ const pos = (e.clientX - rect.left) / rect.width;
1369
+ videoPlayer.currentTime = pos * videoPlayer.duration;
1370
+ });
1371
+
1372
+ // Auto-play video
1373
+ videoPlayer.play();
1374
+
1375
+ // Context toggle
1376
+ contextToggle.addEventListener('click', () => {
1377
+ const isExpanded = contextContent.classList.toggle('expanded');
1378
+ contextToggle.classList.toggle('active');
1379
+ contextIcon.style.transform = isExpanded ? 'rotate(180deg)' : 'rotate(0)';
1380
+ });
1381
+
1382
+ // Voice recording
1383
+ voiceBtn.addEventListener('click', () => {
1384
+ isRecording = !isRecording;
1385
+ voiceBtn.classList.toggle('recording', isRecording);
1386
+ recordingIndicator.style.display = isRecording ? 'flex' : 'none';
1387
+
1388
+ if (isRecording) {
1389
+ // Simulate recording
1390
+ setTimeout(() => {
1391
+ const note = document.getElementById('notesTextarea');
1392
+ note.value += (note.value ? '\n' : '') + '[Voice note recorded at ' + new Date().toLocaleTimeString() + ']';
1393
+ voiceBtn.classList.remove('recording');
1394
+ recordingIndicator.style.display = 'none';
1395
+ isRecording = false;
1396
+ }, 3000);
1397
+ }
1398
+ });
1399
+
1400
+ // Swipe gesture
1401
+ let swipeStartX = 0;
1402
+ let swipeStartY = 0;
1403
+
1404
+ videoCard.addEventListener('mousedown', (e) => {
1405
+ isDragging = true;
1406
+ swipeStartX = e.clientX;
1407
+ swipeStartY = e.clientY;
1408
+ videoCard.classList.add('dragging');
1409
+ });
1410
+
1411
+ document.addEventListener('mousemove', (e) => {
1412
+ if (!isDragging) return;
1413
+
1414
+ const deltaX = e.clientX - swipeStartX;
1415
+ const deltaY = e.clientY - swipeStartY;
1416
+
1417
+ videoCard.style.transform = `translateX(${deltaX}px) translateY(${deltaY}px) rotate(${deltaX * 0.05}deg)`;
1418
+
1419
+ // Visual feedback
1420
+ if (deltaX > 100) {
1421
+ videoCard.className = 'video-card dragging swipe-approve';
1422
+ } else if (deltaX < -100) {
1423
+ videoCard.className = 'video-card dragging swipe-reject';
1424
+ } else if (deltaY < -100) {
1425
+ videoCard.className = 'video-card dragging swipe-escalate';
1426
+ } else {
1427
+ videoCard.className = 'video-card dragging';
1428
+ }
1429
+ });
1430
+
1431
+ document.addEventListener('mouseup', (e) => {
1432
+ if (!isDragging) return;
1433
+
1434
+ const deltaX = e.clientX - swipeStartX;
1435
+ const deltaY = e.clientY - swipeStartY;
1436
+
1437
+ if (deltaX > 150) {
1438
+ handleDecision('approve');
1439
+ } else if (deltaX < -150) {
1440
+ handleDecision('reject');
1441
+ } else if (deltaY < -150) {
1442
+ handleDecision('escalate');
1443
+ } else {
1444
+ videoCard.style.transform = '';
1445
+ videoCard.className = 'video-card';
1446
+ }
1447
+
1448
+ isDragging = false;
1449
+ });
1450
+
1451
+ // Touch support
1452
+ videoCard.addEventListener('touchstart', (e) => {
1453
+ swipeStartX = e.touches[0].clientX;
1454
+ swipeStartY = e.touches[0].clientY;
1455
+ videoCard.classList.add('dragging');
1456
+ });
1457
+
1458
+ videoCard.addEventListener('touchmove', (e) => {
1459
+ const deltaX = e.touches[0].clientX - swipeStartX;
1460
+ const deltaY = e.touches[0].clientY - swipeStartY;
1461
+
1462
+ videoCard.style.transform = `translateX(${deltaX}px) translateY(${deltaY}px) rotate(${deltaX * 0.05}deg)`;
1463
+
1464
+ if (deltaX > 100) {
1465
+ videoCard.className = 'video-card dragging swipe-approve';
1466
+ } else if (deltaX < -100) {
1467
+ videoCard.className = 'video-card dragging swipe-reject';
1468
+ } else if (deltaY < -100) {
1469
+ videoCard.className = 'video-card dragging swipe-escalate';
1470
+ } else {
1471
+ videoCard.className = 'video-card dragging';
1472
+ }
1473
+ });
1474
+
1475
+ videoCard.addEventListener('touchend', (e) => {
1476
+ const touch = e.changedTouches[0];
1477
+ const deltaX = touch.clientX - swipeStartX;
1478
+ const deltaY = touch.clientY - swipeStartY;
1479
+
1480
+ if (deltaX > 150) {
1481
+ handleDecision('approve');
1482
+ } else if (deltaX < -150) {
1483
+ handleDecision('reject');
1484
+ } else if (deltaY < -150) {
1485
+ handleDecision('escalate');
1486
+ } else {
1487
+ videoCard.style.transform = '';
1488
+ videoCard.className = 'video-card';
1489
+ }
1490
+ });
1491
+
1492
+ // Decision handlers
1493
+ function handleDecision(decision) {
1494
+ const reviewTime = ((Date.now() - reviewStartTime) / 1000).toFixed(1);
1495
+
1496
+ // Update stats
1497
+ reviewedToday++;
1498
+ remainingCases--;
1499
+ avgReviewTime = ((avgReviewTime * (reviewedToday - 1)) + parseFloat(reviewTime)) / reviewedToday;
1500
+
1501
+ document.getElementById('reviewedCount').textContent = reviewedToday;
1502
+ document.getElementById('avgTime').textContent = avgReviewTime.toFixed(1) + 's';
1503
+ document.getElementById('remainingCount').textContent = remainingCases;
1504
+
1505
+ // Update progress
1506
+ const progress = (reviewedToday / (reviewedToday + remainingCases)) * 100;
1507
+ document.getElementById('progressFill').style.width = progress + '%';
1508
+
1509
+ // Show completion overlay
1510
+ const icons = {
1511
+ approve: '✓',
1512
+ reject: '✕',
1513
+ escalate: '⬆'
1514
+ };
1515
+
1516
+ const titles = {
1517
+ approve: 'Citation Approved',
1518
+ reject: 'Citation Dismissed',
1519
+ escalate: 'Escalated to Senior Review'
1520
+ };
1521
+
1522
+ const colors = {
1523
+ approve: 'var(--accent-approve)',
1524
+ reject: 'var(--accent-reject)',
1525
+ escalate: 'var(--accent-escalate)'
1526
+ };
1527
+
1528
+ document.getElementById('completionIcon').textContent = icons[decision];
1529
+ document.getElementById('completionIcon').style.color = colors[decision];
1530
+ document.getElementById('completionTitle').textContent = titles[decision];
1531
+ document.getElementById('reviewTime').textContent = reviewTime + 's';
1532
+ document.getElementById('sessionCount').textContent = reviewedToday;
1533
+
1534
+ completionOverlay.classList.add('show');
1535
+
1536
+ // Reset card position
1537
+ setTimeout(() => {
1538
+ videoCard.style.transform = '';
1539
+ videoCard.className = 'video-card';
1540
+ }, 300);
1541
+ }
1542
+
1543
+ approveBtn.addEventListener('click', () => handleDecision('approve'));
1544
+ rejectBtn.addEventListener('click', () => handleDecision('reject'));
1545
+ escalateBtn.addEventListener('click', () => handleDecision('escalate'));
1546
+
1547
+ // Next case
1548
+ nextCaseBtn.addEventListener('click', () => {
1549
+ completionOverlay.classList.remove('show');
1550
+ reviewStartTime = Date.now();
1551
+
1552
+ // Load next case (simulated)
1553
+ videoPlayer.currentTime = 0;
1554
+ videoPlayer.play();
1555
+
1556
+ // Clear notes
1557
+ document.getElementById('notesTextarea').value = '';
1558
+ });
1559
+
1560
+ // Keyboard shortcuts
1561
+ document.addEventListener('keydown', (e) => {
1562
+ if (e.target.tagName === 'TEXTAREA') return;
1563
+
1564
+ switch(e.key.toLowerCase()) {
1565
+ case 'arrowright':
1566
+ case 'd':
1567
+ e.preventDefault();
1568
+ handleDecision('approve');
1569
+ break;
1570
+ case 'arrowleft':
1571
+ case 'a':
1572
+ e.preventDefault();
1573
+ handleDecision('reject');
1574
+ break;
1575
+ case 'arrowup':
1576
+ case 'w':
1577
+ e.preventDefault();
1578
+ handleDecision('escalate');
1579
+ break;
1580
+ case ' ':
1581
+ e.preventDefault();
1582
+ playPauseBtn.click();
1583
+ break;
1584
+ case 'm':
1585
+ e.preventDefault();
1586
+ muteBtn.click();
1587
+ break;
1588
+ case 'c':
1589
+ e.preventDefault();
1590
+ contextToggle.click();
1591
+ break;
1592
+ }
1593
+ });
1594
+
1595
+ // Key frame navigation
1596
+ document.querySelectorAll('.keyframe').forEach((frame, index) => {
1597
+ frame.addEventListener('click', () => {
1598
+ document.querySelectorAll('.keyframe').forEach(f => f.classList.remove('active'));
1599
+ frame.classList.add('active');
1600
+
1601
+ // Simulate jumping to that frame in video
1602
+ videoPlayer.currentTime = (index / 4) * videoPlayer.duration;
1603
+ });
1604
+ });
1605
+ </script>
1606
+ </body>
1607
+ </html>