@signalk/app-dock 1.4.0 → 1.4.2

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.
package/public/dock.css CHANGED
@@ -1,610 +1 @@
1
- /* ─── Reset & base ─────────────────────────────────────────────────────────── */
2
- *,
3
- *::before,
4
- *::after {
5
- box-sizing: border-box;
6
- margin: 0;
7
- padding: 0;
8
- }
9
-
10
- html,
11
- body {
12
- width: 100%;
13
- height: 100%;
14
- overflow: hidden;
15
- background: #000;
16
- font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', Arial, sans-serif;
17
- -webkit-font-smoothing: antialiased;
18
- touch-action: none;
19
- }
20
-
21
- /* ─── iFrame container ──────────────────────────────────────────────────────── */
22
- #iframe-container {
23
- position: fixed;
24
- inset: 0;
25
- z-index: 1;
26
- }
27
-
28
- #iframe-container iframe {
29
- position: absolute;
30
- inset: 0;
31
- width: 100%;
32
- height: 100%;
33
- border: none;
34
- display: none;
35
- touch-action: auto;
36
- }
37
-
38
- #iframe-container iframe.active {
39
- display: block;
40
- }
41
-
42
- /* ─── Welcome screen ───────────────────────────────────────────────────────── */
43
- #idle-hint {
44
- position: fixed;
45
- inset: 0;
46
- z-index: 2;
47
- display: flex;
48
- flex-direction: column;
49
- align-items: center;
50
- justify-content: center;
51
- gap: 12px;
52
- pointer-events: none;
53
- opacity: 0;
54
- animation: idle-fade-in 1.2s ease 0.6s forwards;
55
- }
56
-
57
- #idle-hint.hidden {
58
- display: none;
59
- }
60
-
61
- #idle-logo {
62
- width: 72px;
63
- height: 72px;
64
- border-radius: 16px;
65
- opacity: 0.85;
66
- margin-bottom: 4px;
67
- }
68
-
69
- #idle-title {
70
- color: rgba(255, 255, 255, 0.7);
71
- font-size: 22px;
72
- font-weight: 700;
73
- letter-spacing: 0.02em;
74
- }
75
-
76
- #idle-version {
77
- color: rgba(255, 255, 255, 0.35);
78
- font-size: 11px;
79
- font-weight: 500;
80
- letter-spacing: 0.05em;
81
- margin-top: -8px;
82
- }
83
-
84
- #idle-hint-text {
85
- color: rgba(255, 255, 255, 0.55);
86
- font-size: 15px;
87
- font-weight: 500;
88
- letter-spacing: 0.02em;
89
- text-align: center;
90
- padding: 0 32px;
91
- max-width: 480px;
92
- line-height: 1.6;
93
- margin-top: 12px;
94
- }
95
-
96
- @keyframes idle-fade-in {
97
- to {
98
- opacity: 1;
99
- }
100
- }
101
-
102
- /* ─── Handle over an app on another origin ─────────────────────────────────── */
103
- /* The padding is the touch target; the bar itself is drawn by ::before. */
104
- #dock-handle {
105
- position: fixed;
106
- z-index: 5;
107
- display: none;
108
- padding: 12px 18px;
109
- border: none;
110
- background: transparent;
111
- -webkit-appearance: none;
112
- appearance: none;
113
- cursor: pointer;
114
- touch-action: manipulation;
115
- -webkit-tap-highlight-color: transparent;
116
- }
117
-
118
- #dock-handle.visible {
119
- display: block;
120
- }
121
-
122
- #dock-handle::before {
123
- content: '';
124
- display: block;
125
- width: 56px;
126
- height: 6px;
127
- border-radius: 3px;
128
- background: rgba(255, 255, 255, 0.6);
129
- box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35);
130
- }
131
-
132
- #dock-handle.pos-bottom {
133
- bottom: env(safe-area-inset-bottom, 0px);
134
- left: 50%;
135
- transform: translateX(-50%);
136
- }
137
-
138
- #dock-handle.pos-top {
139
- top: env(safe-area-inset-top, 0px);
140
- left: 50%;
141
- transform: translateX(-50%);
142
- }
143
-
144
- #dock-handle.pos-left {
145
- left: env(safe-area-inset-left, 0px);
146
- top: 50%;
147
- transform: translateY(-50%);
148
- padding: 18px 12px;
149
- }
150
-
151
- #dock-handle.pos-right {
152
- right: env(safe-area-inset-right, 0px);
153
- top: 50%;
154
- transform: translateY(-50%);
155
- padding: 18px 12px;
156
- }
157
-
158
- #dock-handle.pos-left::before,
159
- #dock-handle.pos-right::before {
160
- width: 6px;
161
- height: 56px;
162
- }
163
-
164
- /* ─── Backdrop ──────────────────────────────────────────────────────────────── */
165
- #dock-backdrop {
166
- position: fixed;
167
- inset: 0;
168
- z-index: 10;
169
- background: rgba(0, 0, 0, 0.45);
170
- opacity: 0;
171
- pointer-events: none;
172
- transition: opacity 0.28s ease;
173
- backdrop-filter: blur(2px);
174
- -webkit-backdrop-filter: blur(2px);
175
- }
176
-
177
- #dock-backdrop.visible {
178
- opacity: 1;
179
- pointer-events: auto;
180
- }
181
-
182
- /* ─── Dock shell ────────────────────────────────────────────────────────────── */
183
- #dock {
184
- position: fixed;
185
- z-index: 40;
186
- opacity: 0;
187
- pointer-events: none;
188
- transition:
189
- transform 0.42s cubic-bezier(0.34, 1.45, 0.64, 1),
190
- opacity 0.25s ease;
191
- }
192
-
193
- #dock.visible {
194
- opacity: 1;
195
- pointer-events: auto;
196
- }
197
-
198
- /* --- Position: bottom (default) --- */
199
- #dock.pos-bottom {
200
- bottom: max(16px, env(safe-area-inset-bottom, 16px));
201
- left: 50%;
202
- transform: translateX(-50%) translateY(calc(100% + 32px)) scale(0.92);
203
- }
204
- #dock.pos-bottom.visible {
205
- transform: translateX(-50%) translateY(0) scale(1);
206
- }
207
-
208
- /* --- Position: top --- */
209
- #dock.pos-top {
210
- top: max(16px, env(safe-area-inset-top, 16px));
211
- left: 50%;
212
- transform: translateX(-50%) translateY(calc(-100% - 32px)) scale(0.92);
213
- }
214
- #dock.pos-top.visible {
215
- transform: translateX(-50%) translateY(0) scale(1);
216
- }
217
-
218
- /* --- Position: left --- */
219
- #dock.pos-left {
220
- left: max(16px, env(safe-area-inset-left, 16px));
221
- top: 50%;
222
- transform: translateY(-50%) translateX(calc(-100% - 32px)) scale(0.92);
223
- }
224
- #dock.pos-left.visible {
225
- transform: translateY(-50%) translateX(0) scale(1);
226
- }
227
-
228
- /* --- Position: right --- */
229
- #dock.pos-right {
230
- right: max(16px, env(safe-area-inset-right, 16px));
231
- top: 50%;
232
- transform: translateY(-50%) translateX(calc(100% + 32px)) scale(0.92);
233
- }
234
- #dock.pos-right.visible {
235
- transform: translateY(-50%) translateX(0) scale(1);
236
- }
237
-
238
- /* ─── Dock pill ─────────────────────────────────────────────────────────────── */
239
- #dock-inner {
240
- display: flex;
241
- flex-direction: row;
242
- gap: 10px;
243
- padding: 12px 18px;
244
-
245
- /* Frosted glass - macOS Sequoia style */
246
- background: rgba(30, 30, 32, 0.55);
247
- backdrop-filter: blur(60px) saturate(180%);
248
- -webkit-backdrop-filter: blur(60px) saturate(180%);
249
-
250
- border: 1px solid rgba(255, 255, 255, 0.18);
251
- border-radius: 26px;
252
-
253
- box-shadow:
254
- 0 16px 48px rgba(0, 0, 0, 0.5),
255
- 0 2px 6px rgba(0, 0, 0, 0.25),
256
- inset 0 0.5px 0 rgba(255, 255, 255, 0.15);
257
- }
258
-
259
- /* Alignment: icons grow away from the dock edge */
260
- #dock-inner.align-bottom {
261
- align-items: flex-end;
262
- }
263
- #dock-inner.align-top {
264
- align-items: flex-start;
265
- }
266
- #dock-inner.align-left,
267
- #dock-inner.align-right {
268
- align-items: center;
269
- }
270
-
271
- #dock-inner.layout-vertical {
272
- flex-direction: column;
273
- }
274
-
275
- /* ─── Individual dock item ──────────────────────────────────────────────────── */
276
- .dock-item {
277
- position: relative;
278
- display: flex;
279
- flex-direction: column;
280
- align-items: center;
281
- gap: 5px;
282
- cursor: pointer;
283
- -webkit-tap-highlight-color: transparent;
284
- user-select: none;
285
- touch-action: manipulation;
286
- }
287
-
288
- /* ─── Icon box ──────────────────────────────────────────────────────────────── */
289
- .dock-icon {
290
- display: flex;
291
- align-items: center;
292
- justify-content: center;
293
- overflow: hidden;
294
- position: relative;
295
- background: rgba(58, 58, 62, 0.9);
296
- will-change: width, height;
297
- transition:
298
- width 0.08s ease,
299
- height 0.08s ease,
300
- border-radius 0.08s ease,
301
- box-shadow 0.18s ease,
302
- filter 0.18s ease;
303
- box-shadow:
304
- 0 2px 10px rgba(0, 0, 0, 0.4),
305
- inset 0 1px 0 rgba(255, 255, 255, 0.08);
306
- }
307
-
308
- /* Settle-back transition when pointer leaves the dock */
309
- .dock-icon.settling {
310
- transition:
311
- width 0.28s cubic-bezier(0.34, 1.2, 0.64, 1),
312
- height 0.28s cubic-bezier(0.34, 1.2, 0.64, 1),
313
- border-radius 0.28s ease,
314
- box-shadow 0.18s ease,
315
- filter 0.18s ease;
316
- }
317
-
318
- /* Icon reflection glow */
319
- .dock-icon::after {
320
- content: '';
321
- position: absolute;
322
- bottom: -4px;
323
- left: 15%;
324
- right: 15%;
325
- height: 6px;
326
- background: radial-gradient(ellipse, rgba(255, 255, 255, 0.06) 0%, transparent 70%);
327
- pointer-events: none;
328
- opacity: 0;
329
- transition: opacity 0.2s ease;
330
- }
331
-
332
- .dock-item.active .dock-icon::after,
333
- .dock-item.mag-closest .dock-icon::after {
334
- opacity: 1;
335
- }
336
-
337
- .dock-icon img {
338
- width: 100%;
339
- height: 100%;
340
- object-fit: contain;
341
- padding: 10px;
342
- pointer-events: none;
343
- }
344
-
345
- /* Press feedback */
346
- .dock-item.pressing .dock-icon {
347
- filter: brightness(0.88);
348
- }
349
-
350
- /* Active app glow */
351
- .dock-item.active .dock-icon {
352
- box-shadow:
353
- 0 4px 18px rgba(0, 0, 0, 0.5),
354
- 0 0 0 2px rgba(255, 255, 255, 0.22),
355
- inset 0 1px 0 rgba(255, 255, 255, 0.12);
356
- }
357
-
358
- /* ─── Active dot ────────────────────────────────────────────────────────────── */
359
- .dock-dot {
360
- width: 4px;
361
- height: 4px;
362
- border-radius: 50%;
363
- background: rgba(255, 255, 255, 0.85);
364
- flex-shrink: 0;
365
- opacity: 0;
366
- transition: opacity 0.2s ease;
367
- }
368
-
369
- .dock-item.active .dock-dot {
370
- opacity: 1;
371
- }
372
-
373
- /* ─── Label tooltip ─────────────────────────────────────────────────────────── */
374
- .dock-label {
375
- position: absolute;
376
- bottom: calc(100% + 10px);
377
- left: 50%;
378
- transform: translateX(-50%);
379
-
380
- background: rgba(22, 22, 24, 0.92);
381
- color: rgba(255, 255, 255, 0.95);
382
- font-size: 11px;
383
- font-weight: 600;
384
- letter-spacing: 0.02em;
385
- padding: 5px 10px;
386
- border-radius: 7px;
387
- white-space: nowrap;
388
- pointer-events: none;
389
- border: 1px solid rgba(255, 255, 255, 0.1);
390
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
391
-
392
- opacity: 0;
393
- transition: opacity 0.12s ease;
394
- z-index: 1;
395
- }
396
-
397
- /* Show label on press or when closest during magnification scrub */
398
- .dock-item.pressing .dock-label,
399
- .dock-item.mag-closest .dock-label {
400
- opacity: 1;
401
- }
402
-
403
- /* Label positions for other dock positions */
404
- .dock-label-below {
405
- bottom: auto;
406
- top: calc(100% + 10px);
407
- }
408
-
409
- .dock-label-right {
410
- bottom: auto;
411
- top: 50%;
412
- left: calc(100% + 10px);
413
- transform: translateY(-50%);
414
- }
415
-
416
- .dock-label-left {
417
- bottom: auto;
418
- top: 50%;
419
- left: auto;
420
- right: calc(100% + 10px);
421
- transform: translateY(-50%);
422
- }
423
-
424
- /* ─── Dock separator ───────────────────────────────────────────────────────── */
425
- .dock-separator {
426
- width: 1px;
427
- height: 32px;
428
- background: rgba(255, 255, 255, 0.15);
429
- flex-shrink: 0;
430
- align-self: center;
431
- margin: 0 2px;
432
- border-radius: 1px;
433
- }
434
-
435
- .layout-vertical .dock-separator {
436
- width: 32px;
437
- height: 1px;
438
- margin: 2px 0;
439
- }
440
-
441
- /* ─── Utility buttons (night mode, exit) ───────────────────────────────────── */
442
- .dock-icon-utility {
443
- background: rgba(255, 255, 255, 0.08);
444
- border: 1px solid rgba(255, 255, 255, 0.12);
445
- box-shadow: none;
446
- }
447
-
448
- .dock-item-utility .dock-dot {
449
- display: none;
450
- }
451
-
452
- .dock-item-utility:hover .dock-icon-utility,
453
- .dock-item-utility.pressing .dock-icon-utility {
454
- background: rgba(255, 255, 255, 0.15);
455
- }
456
-
457
- .dock-item-exit:hover .dock-icon-utility {
458
- background: rgba(239, 68, 68, 0.25);
459
- }
460
-
461
- /* ─── Loading overlay ───────────────────────────────────────────────────────── */
462
- #loading-overlay {
463
- position: fixed;
464
- inset: 0;
465
- z-index: 8;
466
- display: flex;
467
- flex-direction: column;
468
- align-items: center;
469
- justify-content: center;
470
- gap: 16px;
471
- background: rgba(0, 0, 0, 0.6);
472
- color: rgba(255, 255, 255, 0.75);
473
- font-size: 14px;
474
- font-weight: 500;
475
- opacity: 0;
476
- pointer-events: none;
477
- transition: opacity 0.2s ease;
478
- }
479
-
480
- #loading-overlay.visible {
481
- opacity: 1;
482
- pointer-events: auto;
483
- }
484
-
485
- .spinner {
486
- width: 32px;
487
- height: 32px;
488
- border: 3px solid rgba(255, 255, 255, 0.15);
489
- border-top-color: rgba(255, 255, 255, 0.75);
490
- border-radius: 50%;
491
- animation: spin 0.75s linear infinite;
492
- }
493
-
494
- @keyframes spin {
495
- to {
496
- transform: rotate(360deg);
497
- }
498
- }
499
-
500
- /* ─── Welcome tour ─────────────────────────────────────────────────────────── */
501
- #tour-overlay {
502
- position: fixed;
503
- inset: 0;
504
- z-index: 30;
505
- display: flex;
506
- align-items: center;
507
- justify-content: center;
508
- background: rgba(0, 0, 0, 0.6);
509
- backdrop-filter: blur(4px);
510
- -webkit-backdrop-filter: blur(4px);
511
- opacity: 0;
512
- pointer-events: none;
513
- transition: opacity 0.3s ease;
514
- padding: 24px;
515
- }
516
-
517
- #tour-overlay.visible {
518
- opacity: 1;
519
- pointer-events: auto;
520
- }
521
-
522
- #tour-card {
523
- max-width: 520px;
524
- width: 100%;
525
- background: rgba(30, 30, 32, 0.9);
526
- backdrop-filter: blur(40px) saturate(180%);
527
- -webkit-backdrop-filter: blur(40px) saturate(180%);
528
- border: 1px solid rgba(255, 255, 255, 0.18);
529
- border-radius: 22px;
530
- padding: 32px;
531
- color: rgba(255, 255, 255, 0.92);
532
- box-shadow:
533
- 0 24px 64px rgba(0, 0, 0, 0.6),
534
- inset 0 0.5px 0 rgba(255, 255, 255, 0.15);
535
- /* Position above the dock so user can see both */
536
- margin-bottom: 180px;
537
- }
538
-
539
- #tour-title {
540
- font-size: 22px;
541
- font-weight: 700;
542
- letter-spacing: 0.01em;
543
- margin-bottom: 16px;
544
- }
545
-
546
- #tour-body {
547
- font-size: 15px;
548
- line-height: 1.55;
549
- color: rgba(255, 255, 255, 0.78);
550
- }
551
-
552
- #tour-body p {
553
- margin-bottom: 12px;
554
- }
555
-
556
- #tour-body p:last-child {
557
- margin-bottom: 0;
558
- }
559
-
560
- #tour-link {
561
- color: #60a5fa;
562
- text-decoration: none;
563
- font-weight: 600;
564
- }
565
-
566
- #tour-link:hover {
567
- text-decoration: underline;
568
- }
569
-
570
- #tour-buttons {
571
- display: flex;
572
- gap: 10px;
573
- margin-top: 24px;
574
- justify-content: flex-end;
575
- }
576
-
577
- .tour-btn {
578
- padding: 10px 20px;
579
- border: none;
580
- border-radius: 10px;
581
- font-size: 14px;
582
- font-weight: 600;
583
- cursor: pointer;
584
- font-family: inherit;
585
- transition:
586
- background 0.15s ease,
587
- transform 0.1s ease;
588
- }
589
-
590
- .tour-btn-primary {
591
- background: #3b82f6;
592
- color: #fff;
593
- }
594
-
595
- .tour-btn-primary:hover {
596
- background: #2563eb;
597
- }
598
-
599
- .tour-btn-dismiss {
600
- background: rgba(255, 255, 255, 0.08);
601
- color: rgba(255, 255, 255, 0.8);
602
- }
603
-
604
- .tour-btn-dismiss:hover {
605
- background: rgba(255, 255, 255, 0.15);
606
- }
607
-
608
- .tour-btn:active {
609
- transform: scale(0.97);
610
- }
1
+ *,:before,:after{box-sizing:border-box;margin:0;padding:0}html,body{-webkit-font-smoothing:antialiased;touch-action:none;background:#000;width:100%;height:100%;font-family:-apple-system,BlinkMacSystemFont,SF Pro Display,Helvetica Neue,Arial,sans-serif;overflow:hidden}#iframe-container{z-index:1;position:fixed;inset:0}#iframe-container iframe{touch-action:auto;border:none;width:100%;height:100%;display:none;position:absolute;inset:0}#iframe-container iframe.active{display:block}#idle-hint{z-index:2;pointer-events:none;opacity:0;flex-direction:column;justify-content:center;align-items:center;gap:12px;animation:1.2s .6s forwards idle-fade-in;display:flex;position:fixed;inset:0}#idle-hint.hidden{display:none}#idle-logo{opacity:.85;border-radius:16px;width:72px;height:72px;margin-bottom:4px}#idle-title{color:#ffffffb3;letter-spacing:.02em;font-size:22px;font-weight:700}#idle-version{color:#ffffff59;letter-spacing:.05em;margin-top:-8px;font-size:11px;font-weight:500}#idle-hint-text{color:#ffffff8c;letter-spacing:.02em;text-align:center;max-width:480px;margin-top:12px;padding:0 32px;font-size:15px;font-weight:500;line-height:1.6}@keyframes idle-fade-in{to{opacity:1}}#dock-handle{z-index:5;appearance:none;cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent;background:0 0;border:none;padding:12px 18px;display:none;position:fixed}#dock-handle.visible{display:block}#dock-handle:before{content:"";background:#fff9;border-radius:3px;width:56px;height:6px;display:block;box-shadow:0 0 0 1px #00000059}#dock-handle.pos-bottom{bottom:env(safe-area-inset-bottom,0px);left:50%;transform:translate(-50%)}#dock-handle.pos-top{top:env(safe-area-inset-top,0px);left:50%;transform:translate(-50%)}#dock-handle.pos-left{left:env(safe-area-inset-left,0px);padding:18px 12px;top:50%;transform:translateY(-50%)}#dock-handle.pos-right{right:env(safe-area-inset-right,0px);padding:18px 12px;top:50%;transform:translateY(-50%)}#dock-handle.pos-left:before,#dock-handle.pos-right:before{width:6px;height:56px}#dock-backdrop{z-index:10;opacity:0;pointer-events:none;-webkit-backdrop-filter:blur(2px);background:#00000073;transition:opacity .28s;position:fixed;inset:0}#dock-backdrop.visible{opacity:1;pointer-events:auto}#dock{z-index:40;opacity:0;pointer-events:none;transition:transform .42s cubic-bezier(.34,1.45,.64,1),opacity .25s;position:fixed}#dock.visible{opacity:1;pointer-events:auto}#dock.pos-bottom{bottom:max(16px, env(safe-area-inset-bottom,16px));left:50%;transform:translate(-50%)translateY(calc(100% + 32px))scale(.92)}#dock.pos-bottom.visible{transform:translate(-50%)translateY(0)scale(1)}#dock.pos-top{top:max(16px, env(safe-area-inset-top,16px));left:50%;transform:translate(-50%)translateY(calc(-100% - 32px))scale(.92)}#dock.pos-top.visible{transform:translate(-50%)translateY(0)scale(1)}#dock.pos-left{left:max(16px, env(safe-area-inset-left,16px));top:50%;transform:translateY(-50%)translate(calc(-100% - 32px))scale(.92)}#dock.pos-left.visible{transform:translateY(-50%)translate(0)scale(1)}#dock.pos-right{right:max(16px, env(safe-area-inset-right,16px));top:50%;transform:translateY(-50%)translate(calc(100% + 32px))scale(.92)}#dock.pos-right.visible{transform:translateY(-50%)translate(0)scale(1)}#dock-inner{-webkit-backdrop-filter:blur(60px)saturate(180%);background:#1e1e208c;border:1px solid #ffffff2e;border-radius:26px;flex-direction:row;gap:10px;padding:12px 18px;display:flex;box-shadow:0 16px 48px #00000080,0 2px 6px #00000040,inset 0 .5px #ffffff26}#dock-inner.align-bottom{align-items:flex-end}#dock-inner.align-top{align-items:flex-start}#dock-inner.align-left,#dock-inner.align-right{align-items:center}#dock-inner.layout-vertical{flex-direction:column}.dock-item{cursor:pointer;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;user-select:none;touch-action:manipulation;flex-direction:column;align-items:center;gap:5px;display:flex;position:relative}.dock-icon{will-change:width, height;background:#3a3a3ee6;justify-content:center;align-items:center;transition:width 80ms,height 80ms,border-radius 80ms,box-shadow .18s,filter .18s;display:flex;position:relative;overflow:hidden;box-shadow:0 2px 10px #0006,inset 0 1px #ffffff14}.dock-icon.settling{transition:width .28s cubic-bezier(.34,1.2,.64,1),height .28s cubic-bezier(.34,1.2,.64,1),border-radius .28s,box-shadow .18s,filter .18s}.dock-icon:after{content:"";pointer-events:none;opacity:0;background:radial-gradient(#ffffff0f 0%,#0000 70%);height:6px;transition:opacity .2s;position:absolute;bottom:-4px;left:15%;right:15%}.dock-item.active .dock-icon:after,.dock-item.mag-closest .dock-icon:after{opacity:1}.dock-icon img{object-fit:contain;pointer-events:none;width:100%;height:100%;padding:10px}.dock-item.pressing .dock-icon{filter:brightness(.88)}.dock-item.active .dock-icon{box-shadow:0 4px 18px #00000080,0 0 0 2px #ffffff38,inset 0 1px #ffffff1f}.dock-dot{opacity:0;background:#ffffffd9;border-radius:50%;flex-shrink:0;width:4px;height:4px;transition:opacity .2s}.dock-item.active .dock-dot{opacity:1}.dock-label{color:#fffffff2;letter-spacing:.02em;white-space:nowrap;pointer-events:none;opacity:0;z-index:1;background:#161618eb;border:1px solid #ffffff1a;border-radius:7px;padding:5px 10px;font-size:11px;font-weight:600;transition:opacity .12s;position:absolute;bottom:calc(100% + 10px);left:50%;transform:translate(-50%);box-shadow:0 4px 12px #0006}.dock-item.pressing .dock-label,.dock-item.mag-closest .dock-label{opacity:1}.dock-label-below{top:calc(100% + 10px);bottom:auto}.dock-label-right{top:50%;bottom:auto;left:calc(100% + 10px);transform:translateY(-50%)}.dock-label-left{inset:50% calc(100% + 10px) auto auto;transform:translateY(-50%)}.dock-separator{background:#ffffff26;border-radius:1px;flex-shrink:0;align-self:center;width:1px;height:32px;margin:0 2px}.layout-vertical .dock-separator{width:32px;height:1px;margin:2px 0}.dock-icon-utility{box-shadow:none;background:#ffffff14;border:1px solid #ffffff1f}.dock-item-utility .dock-dot{display:none}.dock-item-utility:hover .dock-icon-utility,.dock-item-utility.pressing .dock-icon-utility{background:#ffffff26}.dock-item-exit:hover .dock-icon-utility{background:#ef444440}.dock-svg-icon{color:#ffffffe6;flex-shrink:0;width:55%;height:55%}.dock-svg-sun{color:#fbbf24}.dock-svg-moon{color:#c7d2fe}#loading-overlay{z-index:8;color:#ffffffbf;opacity:0;pointer-events:none;background:#0009;flex-direction:column;justify-content:center;align-items:center;gap:16px;font-size:14px;font-weight:500;transition:opacity .2s;display:flex;position:fixed;inset:0}#loading-overlay.visible{opacity:1;pointer-events:auto}.spinner{border:3px solid #ffffff26;border-top-color:#ffffffbf;border-radius:50%;width:32px;height:32px;animation:.75s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}#tour-overlay{z-index:30;-webkit-backdrop-filter:blur(4px);opacity:0;pointer-events:none;background:#0009;justify-content:center;align-items:center;padding:24px;transition:opacity .3s;display:flex;position:fixed;inset:0}#tour-overlay.visible{opacity:1;pointer-events:auto}#tour-card{-webkit-backdrop-filter:blur(40px)saturate(180%);color:#ffffffeb;background:#1e1e20e6;border:1px solid #ffffff2e;border-radius:22px;width:100%;max-width:520px;margin-bottom:180px;padding:32px;box-shadow:0 24px 64px #0009,inset 0 .5px #ffffff26}#tour-title{letter-spacing:.01em;margin-bottom:16px;font-size:22px;font-weight:700}#tour-body{color:#ffffffc7;font-size:15px;line-height:1.55}#tour-body p{margin-bottom:12px}#tour-body p:last-child{margin-bottom:0}#tour-link{color:#60a5fa;font-weight:600;text-decoration:none}#tour-link:hover{text-decoration:underline}#tour-buttons{justify-content:flex-end;gap:10px;margin-top:24px;display:flex}.tour-btn{cursor:pointer;border:none;border-radius:10px;padding:10px 20px;font-family:inherit;font-size:14px;font-weight:600;transition:background .15s,transform .1s}.tour-btn-primary{color:#fff;background:#3b82f6}.tour-btn-primary:hover{background:#2563eb}.tour-btn-dismiss{color:#fffc;background:#ffffff14}.tour-btn-dismiss:hover{background:#ffffff26}.tour-btn:active{transform:scale(.97)}