@tomorrowos/sdk 0.9.28 → 0.9.29

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.
Files changed (29) hide show
  1. package/README.md +6 -1
  2. package/VERCEL_SETUP.md +1 -1
  3. package/dist/cli.js +42 -11
  4. package/package.json +1 -1
  5. package/templates/cms-starter/package.json +2 -2
  6. package/templates/cms-starter/server.ts +2 -2
  7. package/templates/cms-starter-v0/.env.example +19 -0
  8. package/templates/cms-starter-v0/README.md +60 -0
  9. package/templates/cms-starter-v0/assets/logo.svg +4 -0
  10. package/templates/cms-starter-v0/brand.json +23 -0
  11. package/templates/cms-starter-v0/cms-panel/assets/player-download/android.svg +1 -0
  12. package/templates/cms-starter-v0/cms-panel/assets/player-download/brightsign.svg +1 -0
  13. package/templates/cms-starter-v0/cms-panel/assets/player-download/lg-webos.svg +1 -0
  14. package/templates/cms-starter-v0/cms-panel/assets/player-download/samsung.svg +1 -0
  15. package/templates/cms-starter-v0/cms-panel/assets/player-download/toolbox.svg +1 -0
  16. package/templates/cms-starter-v0/cms-panel/index.html +290 -0
  17. package/templates/cms-starter-v0/cms-panel/methods.js +2361 -0
  18. package/templates/cms-starter-v0/cms-panel/panel.css +1127 -0
  19. package/templates/cms-starter-v0/cms-panel/uploads/.gitkeep +1 -0
  20. package/templates/cms-starter-v0/package.json +35 -0
  21. package/templates/cms-starter-v0/policy.example.json +30 -0
  22. package/templates/cms-starter-v0/preview/app/layout.tsx +11 -0
  23. package/templates/cms-starter-v0/preview/app/page.tsx +3 -0
  24. package/templates/cms-starter-v0/preview/next-env.d.ts +2 -0
  25. package/templates/cms-starter-v0/preview/next.config.mjs +18 -0
  26. package/templates/cms-starter-v0/preview/tsconfig.json +20 -0
  27. package/templates/cms-starter-v0/server.ts +75 -0
  28. package/templates/cms-starter-v0/tsconfig.json +13 -0
  29. package/templates/cms-starter-v0/vercel.json +7 -0
@@ -0,0 +1,1127 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ body {
6
+ margin: 0;
7
+ font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
8
+ background: #f4f3f0;
9
+ color: #0a0908;
10
+ }
11
+
12
+ .app-header {
13
+ padding: 1rem 1.5rem;
14
+ background: #0a0908;
15
+ color: #fafaf9;
16
+ }
17
+
18
+ .app-header h1 {
19
+ margin: 0;
20
+ font-size: 1.25rem;
21
+ font-weight: 600;
22
+ }
23
+
24
+ .app-header p {
25
+ margin: 0.35rem 0 0;
26
+ font-size: 0.875rem;
27
+ opacity: 0.8;
28
+ }
29
+
30
+ .layout {
31
+ display: flex;
32
+ gap: 0;
33
+ min-height: calc(100vh - 4.5rem);
34
+ }
35
+
36
+ .panel-main {
37
+ flex: 1;
38
+ padding: 1.25rem 1.5rem 2rem;
39
+ overflow: auto;
40
+ }
41
+
42
+ .panel-playlist-nav {
43
+ width: 220px;
44
+ flex-shrink: 0;
45
+ background: #fff;
46
+ border-right: 1px solid #e4e1dc;
47
+ display: flex;
48
+ flex-direction: column;
49
+ padding: 0.75rem;
50
+ }
51
+
52
+ .playlist-nav-header {
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: space-between;
56
+ margin-bottom: 0.5rem;
57
+ }
58
+
59
+ .playlist-nav-header h2 {
60
+ margin: 0;
61
+ font-size: 0.95rem;
62
+ }
63
+
64
+ .playlist-catalog {
65
+ list-style: none;
66
+ margin: 0;
67
+ padding: 0;
68
+ overflow: auto;
69
+ flex: 1;
70
+ }
71
+
72
+ .playlist-catalog-item {
73
+ border: 1px solid #e4e1dc;
74
+ border-radius: 6px;
75
+ padding: 0.5rem 0.6rem;
76
+ margin-bottom: 0.4rem;
77
+ cursor: pointer;
78
+ font-size: 0.85rem;
79
+ }
80
+
81
+ .playlist-catalog-item--active {
82
+ border-color: #ff8a3d;
83
+ background: #fff5ee;
84
+ }
85
+
86
+ .playlist-catalog-item small {
87
+ display: block;
88
+ color: #666;
89
+ margin-top: 0.2rem;
90
+ }
91
+
92
+ .panel-playlist {
93
+ width: 300px;
94
+ flex-shrink: 0;
95
+ background: #fff;
96
+ border-left: 1px solid #e4e1dc;
97
+ display: flex;
98
+ flex-direction: column;
99
+ }
100
+
101
+ .card {
102
+ background: #fff;
103
+ border: 1px solid #e4e1dc;
104
+ border-radius: 10px;
105
+ padding: 1rem 1.1rem;
106
+ margin-bottom: 1rem;
107
+ }
108
+
109
+ .card h2 {
110
+ margin: 0 0 0.75rem;
111
+ font-size: 0.95rem;
112
+ font-weight: 600;
113
+ }
114
+
115
+ .hint {
116
+ margin: 0 0 0.75rem;
117
+ font-size: 0.8rem;
118
+ color: #666;
119
+ }
120
+
121
+ .server-status-card {
122
+ border-color: #e4e1dc;
123
+ }
124
+
125
+ .server-status-header {
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: space-between;
129
+ gap: 0.75rem;
130
+ margin-bottom: 0.35rem;
131
+ }
132
+
133
+ .server-status-header h2 {
134
+ margin: 0;
135
+ }
136
+
137
+ .server-status-header button {
138
+ font-size: 0.78rem;
139
+ padding: 0.35rem 0.65rem;
140
+ }
141
+
142
+ .server-status-overall {
143
+ margin-bottom: 0.65rem;
144
+ }
145
+
146
+ .server-status-list {
147
+ list-style: none;
148
+ margin: 0;
149
+ padding: 0;
150
+ display: grid;
151
+ gap: 0.45rem;
152
+ }
153
+
154
+ .server-status-row {
155
+ display: grid;
156
+ grid-template-columns: minmax(0, 1fr) auto;
157
+ gap: 0.35rem 0.75rem;
158
+ align-items: baseline;
159
+ padding: 0.55rem 0.65rem;
160
+ border: 1px solid #ece8e2;
161
+ border-radius: 8px;
162
+ background: #fafaf9;
163
+ }
164
+
165
+ .server-status-row-main {
166
+ display: flex;
167
+ flex-wrap: wrap;
168
+ align-items: baseline;
169
+ gap: 0.35rem 0.55rem;
170
+ min-width: 0;
171
+ }
172
+
173
+ .server-status-label {
174
+ font-size: 0.85rem;
175
+ font-weight: 600;
176
+ color: #0a0908;
177
+ }
178
+
179
+ .server-status-provider {
180
+ font-size: 0.72rem;
181
+ color: #888;
182
+ }
183
+
184
+ .server-status-detail {
185
+ grid-column: 1 / -1;
186
+ margin: 0;
187
+ font-size: 0.75rem;
188
+ color: #555;
189
+ line-height: 1.4;
190
+ }
191
+
192
+ .server-status-badge {
193
+ font-size: 0.72rem;
194
+ font-weight: 600;
195
+ letter-spacing: 0.02em;
196
+ text-transform: uppercase;
197
+ padding: 0.18rem 0.45rem;
198
+ border-radius: 999px;
199
+ border: 1px solid transparent;
200
+ white-space: nowrap;
201
+ }
202
+
203
+ .server-status-badge--ok {
204
+ color: #067647;
205
+ background: #ecfdf3;
206
+ border-color: #abefc6;
207
+ }
208
+
209
+ .server-status-badge--warn {
210
+ color: #b54708;
211
+ background: #fffaeb;
212
+ border-color: #fedf89;
213
+ }
214
+
215
+ .server-status-badge--error,
216
+ .server-status-badge--missing {
217
+ color: #b42318;
218
+ background: #fff5f5;
219
+ border-color: #fecdca;
220
+ }
221
+
222
+ .server-status-blockers {
223
+ margin-top: 0.75rem;
224
+ display: grid;
225
+ gap: 0.55rem;
226
+ }
227
+
228
+ .server-status-blocker {
229
+ padding: 0.7rem 0.8rem;
230
+ border-radius: 8px;
231
+ border: 1px solid #fecdca;
232
+ background: #fff8f7;
233
+ }
234
+
235
+ .server-status-blocker h3 {
236
+ margin: 0 0 0.3rem;
237
+ font-size: 0.85rem;
238
+ color: #b42318;
239
+ }
240
+
241
+ .server-status-blocker p {
242
+ margin: 0;
243
+ font-size: 0.78rem;
244
+ color: #444;
245
+ line-height: 1.45;
246
+ }
247
+
248
+ .server-status-blocker p + p {
249
+ margin-top: 0.35rem;
250
+ }
251
+
252
+ .server-status-blocker-fix {
253
+ color: #0a0908;
254
+ }
255
+
256
+ .server-status-card--ok {
257
+ border-color: #abefc6;
258
+ }
259
+
260
+ .server-status-card--degraded {
261
+ border-color: #fedf89;
262
+ }
263
+
264
+ .server-status-card--blocked {
265
+ border-color: #fecdca;
266
+ }
267
+
268
+ .devices-grid {
269
+ display: grid;
270
+ grid-template-columns: repeat(auto-fill, minmax(308px, 1fr));
271
+ gap: 0.85rem;
272
+ }
273
+
274
+ .devices-empty {
275
+ margin: 0;
276
+ color: #666;
277
+ font-size: 0.875rem;
278
+ grid-column: 1 / -1;
279
+ }
280
+
281
+ .device-card {
282
+ border: 1px solid #e4e1dc;
283
+ border-radius: 8px;
284
+ padding: 0.85rem 0.95rem;
285
+ background: #fafaf9;
286
+ overflow: visible;
287
+ }
288
+
289
+ .device-card-header {
290
+ display: flex;
291
+ align-items: center;
292
+ justify-content: space-between;
293
+ gap: 0.35rem;
294
+ margin-bottom: 0.65rem;
295
+ }
296
+
297
+ .device-card-header-main {
298
+ display: flex;
299
+ align-items: center;
300
+ gap: 0.5rem;
301
+ min-width: 0;
302
+ flex: 1;
303
+ }
304
+
305
+ .device-card-header-actions {
306
+ display: flex;
307
+ align-items: center;
308
+ gap: 0.35rem;
309
+ flex-shrink: 0;
310
+ }
311
+
312
+ .device-card-header-actions button {
313
+ font-size: 0.78rem;
314
+ padding: 0.35rem 0.6rem;
315
+ }
316
+
317
+ .device-card-title {
318
+ margin: 0;
319
+ font-size: 0.95rem;
320
+ font-weight: 600;
321
+ line-height: 1.2;
322
+ min-width: 0;
323
+ flex: 1;
324
+ }
325
+
326
+ .device-card-title-input {
327
+ width: 100%;
328
+ min-width: 0;
329
+ font-size: 0.95rem;
330
+ font-weight: 600;
331
+ }
332
+
333
+ .status-led {
334
+ width: 11px;
335
+ height: 11px;
336
+ border-radius: 50%;
337
+ flex-shrink: 0;
338
+ box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.06);
339
+ }
340
+
341
+ .status-led--online {
342
+ background: #12b76a;
343
+ box-shadow: 0 0 8px rgba(18, 183, 106, 0.55);
344
+ }
345
+
346
+ .status-led--offline {
347
+ background: #f04438;
348
+ box-shadow: 0 0 8px rgba(240, 68, 56, 0.45);
349
+ }
350
+
351
+ .status-led--loading {
352
+ background: transparent;
353
+ border: 2px solid #dcd9d4;
354
+ border-top-color: #6e6b67;
355
+ box-shadow: none;
356
+ animation: status-led-spin 0.75s linear infinite;
357
+ }
358
+
359
+ @keyframes status-led-spin {
360
+ to {
361
+ transform: rotate(360deg);
362
+ }
363
+ }
364
+
365
+ .device-meta {
366
+ display: grid;
367
+ gap: 0.35rem;
368
+ font-size: 0.78rem;
369
+ color: #444;
370
+ margin: 0;
371
+ }
372
+
373
+ .device-meta-block {
374
+ margin-bottom: 0.75rem;
375
+ }
376
+
377
+ .device-meta-top {
378
+ display: grid;
379
+ grid-template-columns: minmax(0, 1fr) 6.5rem;
380
+ gap: 0.5rem;
381
+ align-items: start;
382
+ margin-bottom: 0.35rem;
383
+ }
384
+
385
+ .device-meta--primary {
386
+ min-width: 0;
387
+ font-size: 0.77rem;
388
+ gap: 0.32rem;
389
+ }
390
+
391
+ .device-meta--secondary {
392
+ margin-bottom: 0;
393
+ }
394
+
395
+ .device-screenshot-slot {
396
+ width: 6.5rem;
397
+ aspect-ratio: 13 / 9;
398
+ flex-shrink: 0;
399
+ border: 1px solid transparent;
400
+ border-radius: 4px;
401
+ background: #fafaf9;
402
+ overflow: hidden;
403
+ }
404
+
405
+ .device-screenshot-thumb {
406
+ display: block;
407
+ width: 100%;
408
+ height: 100%;
409
+ padding: 0;
410
+ border: 0;
411
+ background: transparent;
412
+ cursor: pointer;
413
+ }
414
+
415
+ .device-screenshot-thumb img {
416
+ display: block;
417
+ width: 100%;
418
+ height: 100%;
419
+ object-fit: cover;
420
+ object-position: center;
421
+ }
422
+
423
+ .device-meta dt {
424
+ font-weight: 600;
425
+ color: #666;
426
+ display: inline;
427
+ }
428
+
429
+ .device-meta dt::after {
430
+ content: ": ";
431
+ }
432
+
433
+ .device-meta dd {
434
+ display: inline;
435
+ margin: 0;
436
+ word-break: break-all;
437
+ }
438
+
439
+ .device-meta-row {
440
+ display: block;
441
+ }
442
+
443
+ .device-meta-row--timer-status {
444
+ position: relative;
445
+ }
446
+
447
+ .hardware-timer-status {
448
+ position: relative;
449
+ display: inline-block;
450
+ cursor: default;
451
+ outline: none;
452
+ }
453
+
454
+ .hardware-timer-status__value--on {
455
+ color: #027a48;
456
+ font-weight: 600;
457
+ }
458
+
459
+ .hardware-timer-status__value--off {
460
+ color: #667085;
461
+ font-weight: 600;
462
+ }
463
+
464
+ .hardware-timer-status__popup {
465
+ position: absolute;
466
+ left: 0;
467
+ bottom: calc(100% + 0.45rem);
468
+ z-index: 20;
469
+ min-width: 9.5rem;
470
+ padding: 0.55rem 0.7rem;
471
+ border: 1px solid #e4e1dc;
472
+ border-radius: 6px;
473
+ background: #fff;
474
+ box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
475
+ color: #333;
476
+ font-size: 0.75rem;
477
+ font-weight: 400;
478
+ line-height: 1.45;
479
+ white-space: nowrap;
480
+ opacity: 0;
481
+ visibility: hidden;
482
+ pointer-events: none;
483
+ transform: translateY(4px);
484
+ transition: opacity 0.12s ease, transform 0.12s ease, visibility 0.12s;
485
+ }
486
+
487
+ .hardware-timer-status__popup::after {
488
+ content: "";
489
+ position: absolute;
490
+ top: 100%;
491
+ left: 0.85rem;
492
+ border: 6px solid transparent;
493
+ border-top-color: #fff;
494
+ filter: drop-shadow(0 1px 0 #e4e1dc);
495
+ }
496
+
497
+ .hardware-timer-status__popup strong {
498
+ font-weight: 600;
499
+ color: #555;
500
+ margin-right: 0.35rem;
501
+ }
502
+
503
+ .hardware-timer-status:hover .hardware-timer-status__popup,
504
+ .hardware-timer-status:focus-within .hardware-timer-status__popup {
505
+ opacity: 1;
506
+ visibility: visible;
507
+ transform: translateY(0);
508
+ }
509
+
510
+ .device-card-actions {
511
+ display: flex;
512
+ flex-wrap: wrap;
513
+ gap: 0.4rem;
514
+ }
515
+
516
+ .device-card-actions button {
517
+ font-size: 0.78rem;
518
+ padding: 0.35rem 0.6rem;
519
+ }
520
+
521
+ .row {
522
+ display: flex;
523
+ flex-wrap: wrap;
524
+ gap: 0.5rem;
525
+ align-items: center;
526
+ }
527
+
528
+ /* Match Pair Verify + code input height to device playlist Remove buttons */
529
+ .pair-code-row {
530
+ align-items: stretch;
531
+ }
532
+
533
+ .pair-code-row .pair-code-input,
534
+ .pair-code-row .pair-verify-btn {
535
+ box-sizing: border-box;
536
+ font-size: 0.78rem;
537
+ line-height: 1.2;
538
+ padding: 0.45rem 0.85rem;
539
+ min-height: 2.05rem;
540
+ height: 2.05rem;
541
+ border-radius: 6px;
542
+ }
543
+
544
+ .pair-code-row .pair-code-input {
545
+ width: 9.5rem;
546
+ }
547
+
548
+ .device-published-list button {
549
+ font-size: 0.78rem;
550
+ line-height: 1.2;
551
+ padding: 0.45rem 0.85rem;
552
+ min-height: 2.05rem;
553
+ height: 2.05rem;
554
+ box-sizing: border-box;
555
+ }
556
+
557
+ input[type="text"],
558
+ input[type="date"],
559
+ input[type="time"],
560
+ select {
561
+ font: inherit;
562
+ padding: 0.45rem 0.6rem;
563
+ border: 1px solid #d6d2cb;
564
+ border-radius: 6px;
565
+ background: #fff;
566
+ }
567
+
568
+ button {
569
+ font: inherit;
570
+ padding: 0.45rem 0.85rem;
571
+ border-radius: 6px;
572
+ border: 1px solid #d6d2cb;
573
+ background: #fff;
574
+ cursor: pointer;
575
+ }
576
+
577
+ button:hover {
578
+ background: #f5f3ef;
579
+ }
580
+
581
+ button.primary {
582
+ background: #ff8a3d;
583
+ border-color: #e67320;
584
+ color: #0a0908;
585
+ font-weight: 600;
586
+ }
587
+
588
+ button.primary:hover {
589
+ background: #ff9a57;
590
+ }
591
+
592
+ button.danger {
593
+ color: #b42318;
594
+ border-color: #fecdca;
595
+ }
596
+
597
+ .schedule-grid {
598
+ display: grid;
599
+ grid-template-columns: 1fr 1fr;
600
+ gap: 0.65rem 1rem;
601
+ }
602
+
603
+ .schedule-grid label {
604
+ display: flex;
605
+ flex-direction: column;
606
+ gap: 0.25rem;
607
+ font-size: 0.8rem;
608
+ color: #444;
609
+ }
610
+
611
+ .days-row {
612
+ grid-column: 1 / -1;
613
+ display: flex;
614
+ flex-wrap: wrap;
615
+ gap: 0.5rem 0.75rem;
616
+ font-size: 0.8rem;
617
+ }
618
+
619
+ .days-row label {
620
+ flex-direction: row;
621
+ align-items: center;
622
+ gap: 0.35rem;
623
+ color: #0a0908;
624
+ }
625
+
626
+ .playlist-header {
627
+ display: flex;
628
+ align-items: center;
629
+ justify-content: space-between;
630
+ padding: 1rem 1rem 0.75rem;
631
+ border-bottom: 1px solid #e4e1dc;
632
+ }
633
+
634
+ .playlist-header h2 {
635
+ margin: 0;
636
+ font-size: 0.95rem;
637
+ }
638
+
639
+ .playlist-list {
640
+ list-style: none;
641
+ margin: 0;
642
+ padding: 0.5rem;
643
+ flex: 1;
644
+ overflow-y: auto;
645
+ }
646
+
647
+ .upload-status {
648
+ margin: 0.25rem 0.75rem 0.5rem;
649
+ padding: 0.55rem 0.6rem;
650
+ border: 1px solid #e4e1dc;
651
+ border-radius: 8px;
652
+ background: #fafaf9;
653
+ }
654
+
655
+ .upload-status-text {
656
+ font-size: 0.78rem;
657
+ font-weight: 600;
658
+ color: #333;
659
+ margin-bottom: 0.35rem;
660
+ }
661
+
662
+ .upload-progress-track {
663
+ width: 100%;
664
+ height: 8px;
665
+ border-radius: 999px;
666
+ overflow: hidden;
667
+ background: #ece8e2;
668
+ }
669
+
670
+ .upload-progress-bar {
671
+ width: 0%;
672
+ height: 100%;
673
+ background: #ff8a3d;
674
+ transition: width 120ms linear;
675
+ }
676
+
677
+ .upload-queue-text {
678
+ margin-top: 0.35rem;
679
+ font-size: 0.72rem;
680
+ color: #666;
681
+ }
682
+
683
+ .playlist-empty {
684
+ padding: 1.5rem 1rem;
685
+ text-align: center;
686
+ color: #888;
687
+ font-size: 0.875rem;
688
+ }
689
+
690
+ .playlist-assets-hint {
691
+ margin: 0;
692
+ padding: 0.65rem 1rem 0.75rem;
693
+ font-size: 0.78rem;
694
+ line-height: 1.45;
695
+ }
696
+
697
+ .playlist-item {
698
+ border: 1px solid #e4e1dc;
699
+ border-radius: 8px;
700
+ padding: 0.65rem;
701
+ margin-bottom: 0.5rem;
702
+ background: #fafaf9;
703
+ position: relative;
704
+ min-width: 0;
705
+ overflow: hidden;
706
+ }
707
+
708
+ .playlist-item--dragging {
709
+ opacity: 0.55;
710
+ }
711
+
712
+ .playlist-item--drop-target {
713
+ border-color: #ff8a3d;
714
+ box-shadow: 0 0 0 2px rgba(255, 138, 61, 0.25);
715
+ }
716
+
717
+ .playlist-item-drag-handle {
718
+ display: block;
719
+ width: 100%;
720
+ margin: 0 0 0.45rem;
721
+ padding: 0.2rem 0;
722
+ border: 0;
723
+ border-radius: 4px;
724
+ background: transparent;
725
+ color: #888;
726
+ font-size: 0.95rem;
727
+ line-height: 1;
728
+ letter-spacing: 0.08em;
729
+ cursor: grab;
730
+ touch-action: none;
731
+ }
732
+
733
+ .playlist-item-drag-handle:active {
734
+ cursor: grabbing;
735
+ }
736
+
737
+ .playlist-item-drag-handle:hover {
738
+ color: #444;
739
+ background: #f0eeea;
740
+ }
741
+
742
+ .playlist-item-thumb {
743
+ width: 100%;
744
+ aspect-ratio: 16 / 9;
745
+ object-fit: cover;
746
+ border-radius: 4px;
747
+ background: #e4e1dc;
748
+ display: block;
749
+ margin-bottom: 0.5rem;
750
+ }
751
+
752
+ .playlist-item-name {
753
+ font-size: 0.8rem;
754
+ font-weight: 600;
755
+ word-break: break-all;
756
+ margin-bottom: 0.35rem;
757
+ }
758
+
759
+ .playlist-item-meta {
760
+ font-size: 0.75rem;
761
+ color: #666;
762
+ margin-bottom: 0.45rem;
763
+ }
764
+
765
+ .playlist-item-actions {
766
+ display: grid;
767
+ grid-template-columns: minmax(0, 4.25rem) minmax(0, 1fr) minmax(0, 1fr);
768
+ gap: 0.35rem;
769
+ align-items: stretch;
770
+ width: 100%;
771
+ min-width: 0;
772
+ }
773
+
774
+ .playlist-item-actions input[type="number"] {
775
+ width: 100%;
776
+ min-width: 0;
777
+ font: inherit;
778
+ padding: 0.28rem 0.35rem;
779
+ border: 1px solid #d6d2cb;
780
+ border-radius: 4px;
781
+ }
782
+
783
+ .playlist-item-actions button {
784
+ min-width: 0;
785
+ padding: 0.28rem 0.35rem;
786
+ font-size: 0.72rem;
787
+ line-height: 1.2;
788
+ border-radius: 4px;
789
+ white-space: nowrap;
790
+ overflow: hidden;
791
+ text-overflow: ellipsis;
792
+ }
793
+
794
+ .publish-bar {
795
+ padding: 1rem 0 0;
796
+ }
797
+
798
+ #result {
799
+ margin: 0;
800
+ padding: 0.75rem;
801
+ background: #0a0908;
802
+ color: #e8e6e3;
803
+ border-radius: 8px;
804
+ font-size: 0.75rem;
805
+ max-height: 10rem;
806
+ overflow: auto;
807
+ white-space: pre-wrap;
808
+ }
809
+
810
+ .hidden {
811
+ display: none !important;
812
+ }
813
+
814
+ .field-label {
815
+ display: block;
816
+ margin-bottom: 0.75rem;
817
+ font-size: 0.85rem;
818
+ font-weight: 600;
819
+ }
820
+
821
+ .field-label input {
822
+ display: block;
823
+ width: 100%;
824
+ margin-top: 0.35rem;
825
+ font-weight: 400;
826
+ }
827
+
828
+ .subheading {
829
+ margin: 0.5rem 0 0.35rem;
830
+ font-size: 0.9rem;
831
+ }
832
+
833
+ .editor-actions {
834
+ display: flex;
835
+ flex-wrap: wrap;
836
+ gap: 0.5rem;
837
+ margin-top: 0.75rem;
838
+ }
839
+
840
+ .device-published-list {
841
+ margin: 0 0 0.65rem;
842
+ padding: 0;
843
+ list-style: none;
844
+ font-size: 0.78rem;
845
+ }
846
+
847
+ .device-published-list li {
848
+ display: flex;
849
+ align-items: center;
850
+ justify-content: space-between;
851
+ gap: 0.35rem;
852
+ margin-bottom: 0.25rem;
853
+ }
854
+
855
+ .device-published-label {
856
+ display: inline-flex;
857
+ align-items: center;
858
+ gap: 0.35rem;
859
+ }
860
+
861
+ .playlist-playing-light {
862
+ width: 9px;
863
+ height: 9px;
864
+ border-radius: 50%;
865
+ background: #12b76a;
866
+ box-shadow: 0 0 7px rgba(18, 183, 106, 0.65);
867
+ flex-shrink: 0;
868
+ }
869
+
870
+ .modal {
871
+ position: fixed;
872
+ inset: 0;
873
+ z-index: 1000;
874
+ display: flex;
875
+ align-items: center;
876
+ justify-content: center;
877
+ }
878
+
879
+ .modal-backdrop {
880
+ position: absolute;
881
+ inset: 0;
882
+ background: rgba(0, 0, 0, 0.45);
883
+ }
884
+
885
+ .modal-card {
886
+ position: relative;
887
+ background: #fff;
888
+ border-radius: 10px;
889
+ padding: 1.25rem;
890
+ width: min(92vw, 420px);
891
+ max-height: 80vh;
892
+ overflow: auto;
893
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2);
894
+ }
895
+
896
+ .screenshot-modal-card {
897
+ width: min(94vw, 860px);
898
+ }
899
+
900
+ .on-off-timer-grid {
901
+ display: grid;
902
+ grid-template-columns: 1fr 1fr;
903
+ gap: 0.75rem;
904
+ margin-top: 0.85rem;
905
+ }
906
+
907
+ @media (max-width: 520px) {
908
+ .on-off-timer-grid {
909
+ grid-template-columns: 1fr;
910
+ }
911
+ }
912
+
913
+ .screenshot-preview {
914
+ display: block;
915
+ width: 100%;
916
+ max-height: 62vh;
917
+ object-fit: contain;
918
+ border: 1px solid #e4e1dc;
919
+ border-radius: 8px;
920
+ background: #0a0908;
921
+ }
922
+
923
+ .publish-checklist label {
924
+ display: block;
925
+ margin-bottom: 0.45rem;
926
+ font-size: 0.9rem;
927
+ }
928
+
929
+ .publish-status {
930
+ margin-top: 0.85rem;
931
+ padding: 0.55rem 0.6rem;
932
+ border: 1px solid #e4e1dc;
933
+ border-radius: 8px;
934
+ background: #fafaf9;
935
+ }
936
+
937
+ .publish-status-text {
938
+ font-size: 0.82rem;
939
+ font-weight: 600;
940
+ color: #333;
941
+ margin-bottom: 0.35rem;
942
+ }
943
+
944
+ .publish-status--error {
945
+ border-color: #fecdca;
946
+ background: #fff5f5;
947
+ }
948
+
949
+ .publish-status--error .publish-status-text {
950
+ color: #b42318;
951
+ }
952
+
953
+ .publish-status--success {
954
+ border-color: #abefc6;
955
+ background: #f3fcf6;
956
+ }
957
+
958
+ .publish-status--success .publish-status-text {
959
+ color: #067647;
960
+ }
961
+
962
+ .publish-status--success .upload-progress-bar {
963
+ background: #12b76a;
964
+ }
965
+
966
+ .modal-actions button:disabled {
967
+ opacity: 0.55;
968
+ cursor: not-allowed;
969
+ }
970
+
971
+ .modal-actions {
972
+ display: flex;
973
+ gap: 0.5rem;
974
+ margin-top: 1rem;
975
+ }
976
+
977
+ .visually-hidden {
978
+ position: absolute;
979
+ width: 1px;
980
+ height: 1px;
981
+ padding: 0;
982
+ margin: -1px;
983
+ overflow: hidden;
984
+ clip: rect(0, 0, 0, 0);
985
+ white-space: nowrap;
986
+ border: 0;
987
+ }
988
+
989
+ .download-players-nav-slot {
990
+ margin-top: auto;
991
+ display: flex;
992
+ flex-direction: column;
993
+ align-items: stretch;
994
+ gap: 0.45rem;
995
+ padding-top: 0.75rem;
996
+ }
997
+
998
+ .download-players-trigger {
999
+ font: inherit;
1000
+ font-size: 0.85rem;
1001
+ font-weight: 400;
1002
+ padding: 0.55rem 0.95rem;
1003
+ border-radius: 8px;
1004
+ border: 1px solid #d6d2cb;
1005
+ background: #fff;
1006
+ color: #0a0908;
1007
+ cursor: pointer;
1008
+ width: 100%;
1009
+ text-align: center;
1010
+ }
1011
+
1012
+ .download-players-trigger:hover {
1013
+ background: #f5f3ef;
1014
+ }
1015
+
1016
+ .update-sdk-modal-card {
1017
+ width: min(92vw, 480px);
1018
+ }
1019
+
1020
+ .update-sdk-version {
1021
+ margin: 0 0 1rem;
1022
+ font-size: 1.35rem;
1023
+ font-weight: 600;
1024
+ letter-spacing: 0.02em;
1025
+ color: #0a0908;
1026
+ }
1027
+
1028
+ .update-sdk-prompt {
1029
+ margin: 0;
1030
+ padding: 0.75rem 0.85rem;
1031
+ border: 1px solid #e4e1dc;
1032
+ border-radius: 8px;
1033
+ background: #fafaf9;
1034
+ font-size: 0.8rem;
1035
+ line-height: 1.45;
1036
+ white-space: pre-wrap;
1037
+ word-break: break-word;
1038
+ color: #0a0908;
1039
+ }
1040
+
1041
+ .update-sdk-modal-actions {
1042
+ justify-content: flex-end;
1043
+ }
1044
+
1045
+ .download-players-modal-card {
1046
+ width: min(92vw, 560px);
1047
+ padding: 1.5rem 1.75rem 1.25rem;
1048
+ }
1049
+
1050
+ .player-platform-grid {
1051
+ display: grid;
1052
+ padding:1.5rem;
1053
+
1054
+ grid-template-columns: 1fr 1fr;
1055
+ gap: 1.75rem 2rem;
1056
+ align-items: start;
1057
+ }
1058
+
1059
+ .player-platform-cell {
1060
+ display: flex;
1061
+ flex-direction: column;
1062
+ align-items: center;
1063
+ gap: 0.45rem;
1064
+ min-height: 5.5rem;
1065
+ }
1066
+
1067
+ .player-platform-link {
1068
+ display: inline-flex;
1069
+ align-items: center;
1070
+ text-decoration: none;
1071
+ border-radius: 6px;
1072
+ transition: opacity 120ms ease, transform 120ms ease;
1073
+ }
1074
+
1075
+ .player-platform-link:hover {
1076
+ opacity: 0.82;
1077
+ transform: translateY(-1px);
1078
+ }
1079
+
1080
+ .player-platform-link:focus-visible {
1081
+ outline: 2px solid #ff8a3d;
1082
+ outline-offset: 3px;
1083
+ }
1084
+
1085
+ .player-platform-logo {
1086
+ display: block;
1087
+ object-fit: contain;
1088
+ }
1089
+
1090
+ .player-platform-logo--wide {
1091
+ height: 2.25rem;
1092
+ width: auto;
1093
+ max-width: 100%;
1094
+ }
1095
+
1096
+ .player-platform-caption {
1097
+ margin: 0;
1098
+ font-size: 0.78rem;
1099
+ line-height: 1.35;
1100
+ color: #444;
1101
+ }
1102
+
1103
+ .player-platform-caption--muted {
1104
+ color: #888;
1105
+ }
1106
+
1107
+ .player-platform-diy {
1108
+ margin-top: 1.35rem;
1109
+ padding-top: 1.35rem;
1110
+ border-top: 1px solid #e4e1dc;
1111
+ display: flex;
1112
+ flex-direction: column;
1113
+ align-items: center;
1114
+ gap: 0.55rem;
1115
+ text-align: center;
1116
+ }
1117
+
1118
+ .player-platform-toolbox {
1119
+ width: 5.5rem;
1120
+ height: auto;
1121
+ display: block;
1122
+ }
1123
+
1124
+ .download-players-modal-actions {
1125
+ justify-content: center;
1126
+ margin-top: 1.15rem;
1127
+ }