nwb-video-widgets 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,624 @@
1
+ /**
2
+ * Pose Widget Styles
3
+ *
4
+ * Modern styling for the NWB pose estimation video overlay widget.
5
+ * Uses BEM naming convention to avoid global scope conflicts.
6
+ *
7
+ * Reference: documentation/development/pose_video_widget.md
8
+ */
9
+
10
+ /* ==========================================================================
11
+ CSS Custom Properties
12
+ ========================================================================== */
13
+
14
+ .pose-widget {
15
+ /* Spacing */
16
+ --spacing-xs: 4px;
17
+ --spacing-sm: 8px;
18
+ --spacing-md: 12px;
19
+ --spacing-lg: 16px;
20
+ --spacing-xl: 24px;
21
+
22
+ /* Colors - Tailwind-inspired neutral palette */
23
+ --color-bg: #f7fafc;
24
+ --color-surface: #ffffff;
25
+ --color-border: #e2e8f0;
26
+ --color-border-hover: #cbd5e0;
27
+ --color-text-primary: #2d3748;
28
+ --color-text-secondary: #718096;
29
+ --color-text-muted: #a0aec0;
30
+ --color-accent: #4299e1;
31
+ --color-accent-dark: #3182ce;
32
+ --color-dark-surface: #4a5568;
33
+ --color-dark-hover: #2d3748;
34
+ --color-video-bg: #1a1a1a;
35
+
36
+ /* Shadows */
37
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.07);
38
+ --shadow-md:
39
+ 0 1px 2px rgba(0, 0, 0, 0.07),
40
+ 0 2px 4px rgba(0, 0, 0, 0.07),
41
+ 0 4px 8px rgba(0, 0, 0, 0.07);
42
+ --shadow-lg:
43
+ 0 2px 4px rgba(0, 0, 0, 0.1),
44
+ 0 4px 8px rgba(0, 0, 0, 0.1),
45
+ 0 8px 16px rgba(0, 0, 0, 0.1);
46
+ --shadow-focus: 0 0 0 3px rgba(66, 153, 225, 0.5);
47
+
48
+ /* Transitions */
49
+ --transition-fast: 150ms ease;
50
+ --transition-normal: 180ms ease-out;
51
+ }
52
+
53
+ /* ==========================================================================
54
+ Root Wrapper
55
+ ========================================================================== */
56
+
57
+ .pose-widget {
58
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
59
+ padding: var(--spacing-lg);
60
+ background: var(--color-bg);
61
+ border-radius: 12px;
62
+ color: var(--color-text-primary);
63
+ }
64
+
65
+ /* ==========================================================================
66
+ Sections (Collapsible Panels)
67
+ ========================================================================== */
68
+
69
+ .pose-widget__section {
70
+ background: var(--color-surface);
71
+ border-radius: 8px;
72
+ border: 1px solid var(--color-border);
73
+ margin-bottom: var(--spacing-md);
74
+ overflow: hidden;
75
+ }
76
+
77
+ .pose-widget__section--hidden {
78
+ display: none;
79
+ }
80
+
81
+ .pose-widget__section-header {
82
+ display: flex;
83
+ justify-content: space-between;
84
+ align-items: center;
85
+ padding: var(--spacing-sm) var(--spacing-md);
86
+ cursor: pointer;
87
+ user-select: none;
88
+ transition: background var(--transition-fast);
89
+ }
90
+
91
+ .pose-widget__section-header:hover {
92
+ background: var(--color-bg);
93
+ }
94
+
95
+ .pose-widget__section-title-wrapper {
96
+ display: flex;
97
+ align-items: center;
98
+ gap: var(--spacing-md);
99
+ }
100
+
101
+ .pose-widget__section-title {
102
+ font-weight: 600;
103
+ font-size: 14px;
104
+ color: var(--color-text-primary);
105
+ }
106
+
107
+ .pose-widget__section-selected {
108
+ font-size: 12px;
109
+ font-weight: 400;
110
+ color: var(--color-text-secondary);
111
+ }
112
+
113
+ .pose-widget__section-selected:not(:empty)::before {
114
+ content: "Selected: ";
115
+ }
116
+
117
+ .pose-widget__section-toggle {
118
+ display: flex;
119
+ align-items: center;
120
+ color: var(--color-text-secondary);
121
+ }
122
+
123
+ .pose-widget__section-content {
124
+ padding: 0 var(--spacing-md) var(--spacing-md);
125
+ transition: max-height var(--transition-normal), padding var(--transition-normal);
126
+ }
127
+
128
+ .pose-widget__section--collapsed .pose-widget__section-content {
129
+ max-height: 0;
130
+ padding-top: 0;
131
+ padding-bottom: 0;
132
+ overflow: hidden;
133
+ }
134
+
135
+ .pose-widget__section-hint {
136
+ font-size: 12px;
137
+ color: var(--color-text-secondary);
138
+ margin: 0 0 var(--spacing-sm) 0;
139
+ }
140
+
141
+ /* ==========================================================================
142
+ Empty State Text
143
+ ========================================================================== */
144
+
145
+ .pose-widget__empty-text {
146
+ color: var(--color-text-muted);
147
+ font-size: 13px;
148
+ padding: var(--spacing-sm);
149
+ margin: 0;
150
+ }
151
+
152
+ /* ==========================================================================
153
+ Pose Estimation Selection
154
+ ========================================================================== */
155
+
156
+ .pose-widget__pose-list {
157
+ display: flex;
158
+ flex-direction: column;
159
+ gap: var(--spacing-xs);
160
+ }
161
+
162
+ .pose-widget__pose-item {
163
+ display: flex;
164
+ align-items: center;
165
+ gap: var(--spacing-sm);
166
+ padding: var(--spacing-sm);
167
+ border-radius: 4px;
168
+ transition: background var(--transition-fast);
169
+ }
170
+
171
+ .pose-widget__pose-item:hover {
172
+ background: var(--color-bg);
173
+ }
174
+
175
+ .pose-widget__pose-item--selected {
176
+ background: rgba(66, 153, 225, 0.1);
177
+ }
178
+
179
+ .pose-widget__pose-item--selected:hover {
180
+ background: rgba(66, 153, 225, 0.15);
181
+ }
182
+
183
+ .pose-widget__pose-item input[type="radio"] {
184
+ width: 16px;
185
+ height: 16px;
186
+ cursor: pointer;
187
+ accent-color: var(--color-accent);
188
+ }
189
+
190
+ .pose-widget__pose-item-label {
191
+ font-size: 13px;
192
+ font-weight: 500;
193
+ color: var(--color-text-primary);
194
+ cursor: pointer;
195
+ }
196
+
197
+ .pose-widget__pose-item-info {
198
+ flex: 1;
199
+ font-family: "SF Mono", "Cascadia Code", "Fira Code", Consolas, monospace;
200
+ font-size: 11px;
201
+ color: var(--color-text-secondary);
202
+ text-align: right;
203
+ }
204
+
205
+ /* ==========================================================================
206
+ Video Selection
207
+ ========================================================================== */
208
+
209
+ .pose-widget__video-select {
210
+ width: 100%;
211
+ padding: var(--spacing-sm) var(--spacing-md);
212
+ font-size: 13px;
213
+ font-family: inherit;
214
+ border: 1px solid var(--color-border);
215
+ border-radius: 4px;
216
+ background: var(--color-surface);
217
+ color: var(--color-text-primary);
218
+ cursor: pointer;
219
+ transition: border-color var(--transition-fast);
220
+ }
221
+
222
+ .pose-widget__video-select:hover {
223
+ border-color: var(--color-border-hover);
224
+ }
225
+
226
+ .pose-widget__video-select:focus {
227
+ outline: none;
228
+ border-color: var(--color-accent);
229
+ box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.2);
230
+ }
231
+
232
+ .pose-widget__empty-text {
233
+ color: var(--color-text-muted);
234
+ font-size: 13px;
235
+ padding: var(--spacing-sm);
236
+ }
237
+
238
+ /* ==========================================================================
239
+ Keypoint Section
240
+ ========================================================================== */
241
+
242
+ .pose-widget__keypoint-toggles-wrapper {
243
+ display: flex;
244
+ flex-direction: column;
245
+ gap: var(--spacing-sm);
246
+ }
247
+
248
+ .pose-widget__keypoint-toggles {
249
+ display: flex;
250
+ flex-wrap: wrap;
251
+ align-items: center;
252
+ gap: var(--spacing-sm);
253
+ }
254
+
255
+ .pose-widget__keypoint-toggle {
256
+ border: 2px solid transparent;
257
+ border-radius: 16px;
258
+ padding: 6px 14px;
259
+ font-size: 12px;
260
+ font-weight: 500;
261
+ font-family: inherit;
262
+ cursor: pointer;
263
+ transition: all var(--transition-fast);
264
+
265
+ /* Inactive state */
266
+ background: #f5f5f5;
267
+ color: var(--color-text-secondary);
268
+ }
269
+
270
+ .pose-widget__keypoint-toggle:hover {
271
+ background: var(--color-border);
272
+ }
273
+
274
+ .pose-widget__keypoint-toggle--active {
275
+ color: #fff;
276
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
277
+ /* Background color set dynamically from keypoint color in JS */
278
+ }
279
+
280
+ /* Focus ring for keyboard navigation */
281
+ .pose-widget__keypoint-toggle:focus {
282
+ outline: none;
283
+ box-shadow: 0 0 0 2px var(--color-surface), 0 0 0 4px var(--color-accent);
284
+ }
285
+
286
+ /* Utility buttons (All/None) */
287
+ .pose-widget__keypoint-toggle--utility {
288
+ background: var(--color-border);
289
+ color: var(--color-dark-surface);
290
+ border: 1px solid var(--color-border-hover);
291
+ }
292
+
293
+ .pose-widget__keypoint-toggle--utility:hover {
294
+ background: var(--color-border-hover);
295
+ }
296
+
297
+ /* ==========================================================================
298
+ Display Options Section
299
+ ========================================================================== */
300
+
301
+ .pose-widget__label-toggle {
302
+ display: flex;
303
+ align-items: center;
304
+ gap: var(--spacing-xs);
305
+ cursor: pointer;
306
+ font-size: 13px;
307
+ color: var(--color-text-primary);
308
+ user-select: none;
309
+ }
310
+
311
+ .pose-widget__label-toggle input[type="checkbox"] {
312
+ width: 16px;
313
+ height: 16px;
314
+ cursor: pointer;
315
+ accent-color: var(--color-accent);
316
+ }
317
+
318
+ /* ==========================================================================
319
+ Debug Info Panel
320
+ ========================================================================== */
321
+
322
+ .pose-widget__debug {
323
+ font-family: "SF Mono", "Cascadia Code", "Fira Code", Consolas, monospace;
324
+ font-size: 11px;
325
+ color: var(--color-text-secondary);
326
+ background: transparent;
327
+ border-left: 2px solid var(--color-border);
328
+ padding: var(--spacing-xs) 0 var(--spacing-xs) var(--spacing-md);
329
+ margin-bottom: var(--spacing-md);
330
+ line-height: 1.4;
331
+ }
332
+
333
+ /* ==========================================================================
334
+ Playback Controls
335
+ ========================================================================== */
336
+
337
+ .pose-widget__controls {
338
+ display: flex;
339
+ align-items: center;
340
+ gap: var(--spacing-md);
341
+ padding: var(--spacing-sm);
342
+ background: var(--color-surface);
343
+ border-radius: 8px;
344
+ border: 1px solid var(--color-border);
345
+ margin-top: var(--spacing-md);
346
+ }
347
+
348
+ /* ==========================================================================
349
+ Button Styling
350
+ ========================================================================== */
351
+
352
+ .pose-widget__button {
353
+ /* Reset browser defaults */
354
+ border: none;
355
+ background-color: transparent;
356
+ font-family: inherit;
357
+ cursor: pointer;
358
+
359
+ /* Flexbox for icon + text alignment */
360
+ display: inline-flex;
361
+ align-items: center;
362
+ justify-content: center;
363
+ gap: 6px;
364
+
365
+ /* Visual styling */
366
+ background-color: var(--color-dark-surface);
367
+ color: #fff;
368
+ border-radius: 8px;
369
+ padding: 0.5em 1em;
370
+ min-height: 44px;
371
+ min-width: 44px;
372
+ font-size: 14px;
373
+
374
+ /* Layered shadows for realistic depth */
375
+ box-shadow: var(--shadow-md);
376
+ transition: all var(--transition-normal);
377
+ }
378
+
379
+ .pose-widget__button:hover {
380
+ background-color: var(--color-dark-hover);
381
+ transform: translateY(-1px);
382
+ box-shadow: var(--shadow-lg);
383
+ }
384
+
385
+ .pose-widget__button:active {
386
+ transform: translateY(0);
387
+ box-shadow: var(--shadow-sm);
388
+ }
389
+
390
+ /* Accessible focus state */
391
+ .pose-widget__button:focus {
392
+ outline: none;
393
+ box-shadow: var(--shadow-focus), var(--shadow-sm);
394
+ }
395
+
396
+ /* Settings button */
397
+ .pose-widget__settings-btn {
398
+ padding: 0.5em;
399
+ min-width: 44px;
400
+ }
401
+
402
+ /* ==========================================================================
403
+ Seek Bar (Cross-Browser)
404
+ ========================================================================== */
405
+
406
+ .pose-widget__seekbar {
407
+ -webkit-appearance: none;
408
+ appearance: none;
409
+ flex: 1;
410
+ height: 6px;
411
+ border-radius: 3px;
412
+ background: var(--color-border);
413
+ cursor: pointer;
414
+ }
415
+
416
+ /* Thumb - WebKit (Chrome, Safari, Edge) */
417
+ .pose-widget__seekbar::-webkit-slider-thumb {
418
+ -webkit-appearance: none;
419
+ width: 16px;
420
+ height: 16px;
421
+ border-radius: 50%;
422
+ background: var(--color-dark-surface);
423
+ border: 2px solid var(--color-surface);
424
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
425
+ cursor: grab;
426
+ transition: transform var(--transition-fast);
427
+ }
428
+
429
+ .pose-widget__seekbar::-webkit-slider-thumb:hover {
430
+ transform: scale(1.15);
431
+ }
432
+
433
+ .pose-widget__seekbar::-webkit-slider-thumb:active {
434
+ cursor: grabbing;
435
+ transform: scale(1.1);
436
+ }
437
+
438
+ /* Thumb - Firefox */
439
+ .pose-widget__seekbar::-moz-range-thumb {
440
+ width: 16px;
441
+ height: 16px;
442
+ border-radius: 50%;
443
+ background: var(--color-dark-surface);
444
+ border: 2px solid var(--color-surface);
445
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
446
+ cursor: grab;
447
+ }
448
+
449
+ /* Track - Firefox */
450
+ .pose-widget__seekbar::-moz-range-track {
451
+ height: 6px;
452
+ border-radius: 3px;
453
+ background: var(--color-border);
454
+ }
455
+
456
+ /* Focus state */
457
+ .pose-widget__seekbar:focus {
458
+ outline: none;
459
+ }
460
+
461
+ .pose-widget__seekbar:focus::-webkit-slider-thumb {
462
+ box-shadow: var(--shadow-focus);
463
+ }
464
+
465
+ .pose-widget__seekbar:focus::-moz-range-thumb {
466
+ box-shadow: var(--shadow-focus);
467
+ }
468
+
469
+ /* ==========================================================================
470
+ Time Label
471
+ ========================================================================== */
472
+
473
+ .pose-widget__time-label {
474
+ font-family: "SF Mono", "Cascadia Code", "Fira Code", Consolas, monospace;
475
+ font-size: 12px;
476
+ color: var(--color-text-secondary);
477
+ min-width: 120px;
478
+ text-align: right;
479
+ }
480
+
481
+ /* ==========================================================================
482
+ Video Container
483
+ ========================================================================== */
484
+
485
+ .pose-widget__video-container {
486
+ position: relative;
487
+ width: 640px;
488
+ height: 512px;
489
+ border-radius: 8px;
490
+ border: 1px solid var(--color-border);
491
+ overflow: hidden;
492
+ background: var(--color-video-bg);
493
+ }
494
+
495
+ .pose-widget__video-container--empty .pose-widget__video,
496
+ .pose-widget__video-container--empty .pose-widget__canvas {
497
+ display: none;
498
+ }
499
+
500
+ .pose-widget__video-container--empty .pose-widget__empty-msg {
501
+ display: flex;
502
+ }
503
+
504
+ .pose-widget__video {
505
+ display: block;
506
+ width: 640px;
507
+ height: 512px;
508
+ object-fit: fill;
509
+ background-color: var(--color-video-bg);
510
+ }
511
+
512
+ .pose-widget__canvas {
513
+ position: absolute;
514
+ top: 0;
515
+ left: 0;
516
+ pointer-events: none;
517
+ }
518
+
519
+ .pose-widget__empty-msg {
520
+ display: none;
521
+ position: absolute;
522
+ top: 0;
523
+ left: 0;
524
+ width: 100%;
525
+ height: 100%;
526
+ align-items: center;
527
+ justify-content: center;
528
+ color: var(--color-text-muted);
529
+ font-size: 14px;
530
+ text-align: center;
531
+ padding: var(--spacing-xl);
532
+ }
533
+
534
+ /* ==========================================================================
535
+ Loading State
536
+ ========================================================================== */
537
+
538
+ .pose-widget__loading-overlay {
539
+ position: absolute;
540
+ top: 0;
541
+ left: 0;
542
+ width: 100%;
543
+ height: 100%;
544
+ background: var(--color-video-bg);
545
+ display: none;
546
+ flex-direction: column;
547
+ align-items: center;
548
+ justify-content: center;
549
+ gap: var(--spacing-md);
550
+ z-index: 10;
551
+ }
552
+
553
+ .pose-widget__loading-overlay--visible {
554
+ display: flex;
555
+ }
556
+
557
+ .pose-widget__loading-spinner {
558
+ width: 48px;
559
+ height: 48px;
560
+ border: 4px solid rgba(255, 255, 255, 0.2);
561
+ border-top-color: var(--color-accent);
562
+ border-radius: 50%;
563
+ animation: pose-widget-spin 0.8s linear infinite;
564
+ }
565
+
566
+ .pose-widget__loading-text {
567
+ color: rgba(255, 255, 255, 0.8);
568
+ font-size: 14px;
569
+ }
570
+
571
+ @keyframes pose-widget-spin {
572
+ to {
573
+ transform: rotate(360deg);
574
+ }
575
+ }
576
+
577
+ /* Keypoint toggle loading state */
578
+ .pose-widget__keypoint-toggle--loading {
579
+ background: var(--color-border);
580
+ color: var(--color-text-muted);
581
+ cursor: not-allowed;
582
+ opacity: 0.6;
583
+ }
584
+
585
+ .pose-widget__keypoint-toggle--loading:hover {
586
+ background: var(--color-border);
587
+ transform: none;
588
+ }
589
+
590
+ /* Loading text for keypoints */
591
+ .pose-widget__keypoint-loading-text {
592
+ font-size: 12px;
593
+ color: var(--color-text-secondary);
594
+ font-style: italic;
595
+ display: inline-flex;
596
+ align-items: center;
597
+ gap: var(--spacing-sm);
598
+ }
599
+
600
+ .pose-widget__keypoint-loading-text::before {
601
+ content: "";
602
+ width: 12px;
603
+ height: 12px;
604
+ border: 2px solid var(--color-border);
605
+ border-top-color: var(--color-accent);
606
+ border-radius: 50%;
607
+ animation: pose-widget-spin 0.8s linear infinite;
608
+ }
609
+
610
+ /* ==========================================================================
611
+ Accessibility - High Contrast Mode
612
+ ========================================================================== */
613
+
614
+ @media (forced-colors: active) {
615
+ .pose-widget__button,
616
+ .pose-widget__keypoint-toggle,
617
+ .pose-widget__select {
618
+ border: 2px solid currentColor;
619
+ }
620
+
621
+ .pose-widget__video-container {
622
+ border: 2px solid currentColor;
623
+ }
624
+ }