fuzzyworld

north-star / files / src / style.css

style.css

17.7 KB · history · blame

1html,
2body {
3 min-height: 100%;
4 margin: 0;
5}
6
7*,
8*::before,
9*::after {
10 box-sizing: border-box;
11}
12
13body {
14 display: flex;
15 flex-direction: column;
16 align-items: center;
17 min-height: 100dvh;
18 box-sizing: border-box;
19 gap: 8px;
20 padding: max(10px, env(safe-area-inset-top)) 12px max(10px, env(safe-area-inset-bottom));
21 background: #ffffff;
22 color: #0f172a;
23 font-family: system-ui, sans-serif;
24 overflow-x: hidden;
25}
26
27a {
28 color: #1d4ed8;
29 text-shadow: none;
30}
31
32.app-icon {
33 width: 1em;
34 height: 1em;
35 vertical-align: middle;
36 margin-right: 0.15em;
37}
38
39body.dark .app-icon {
40 filter: invert(1) brightness(1.08) drop-shadow(0 0 2px rgba(255, 255, 255, 0.45));
41}
42
43.app-title {
44 margin: 0;
45 font-size: clamp(28px, 5.2vmin, 56px);
46 font-weight: 800;
47 line-height: 1;
48 letter-spacing: 0.02em;
49 position: relative;
50 z-index: 2;
51}
52
53.app-title a {
54 text-decoration: none;
55}
56
57.room-header {
58 margin: 0;
59 display: flex;
60 align-items: center;
61 justify-content: center;
62 flex-wrap: wrap;
63 gap: 10px;
64 position: relative;
65 z-index: 2;
66 text-align: center;
67}
68
69.room-header a {
70 font-size: clamp(12px, 1.8vmin, 16px);
71 font-weight: 600;
72 text-decoration: underline;
73 text-underline-offset: 0.15em;
74}
75
76.room-current {
77 margin: 0;
78 font-size: clamp(12px, 1.8vmin, 16px);
79 font-weight: 600;
80 color: #334155;
81 text-shadow: none;
82 position: relative;
83 z-index: 2;
84 text-align: center;
85}
86
87.room-links {
88 margin: 0;
89 display: flex;
90 flex-direction: column;
91 align-items: center;
92 justify-content: center;
93 gap: 8px;
94 font-size: clamp(13px, 2vmin, 18px);
95 font-weight: 600;
96 position: relative;
97 z-index: 2;
98 text-align: center;
99}
100
101.room-qr-list {
102 display: flex;
103 flex-wrap: wrap;
104 justify-content: center;
105 gap: 10px;
106}
107
108.room-links>a {
109 text-decoration: underline;
110 text-underline-offset: 0.15em;
111}
112
113.room-qr-card {
114 display: flex;
115 flex-direction: column;
116 align-items: center;
117 gap: 6px;
118 padding: 8px;
119 border: 1px solid #cbd5e1;
120 border-radius: 12px;
121 background: rgba(255, 255, 255, 0.96);
122 box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);
123 cursor: pointer;
124 user-select: none;
125}
126
127.room-qr-card.is-collapsed {
128 padding: 12px 8px;
129}
130
131.room-qr-title {
132 margin: 0;
133 font-size: 0.72em;
134 font-weight: 700;
135 color: #334155;
136}
137
138.room-qr {
139 width: 200px;
140 height: 200px;
141 display: block;
142 background: #ffffff;
143 border-radius: 0;
144 image-rendering: pixelated;
145}
146
147.room-qr-collapsed-label {
148 display: none;
149 align-items: center;
150 justify-content: center;
151 width: 200px;
152 height: 56px;
153 margin: 0;
154 border: 1px solid #e2e8f0;
155 border-radius: 10px;
156 background: #ffffff;
157 color: #0f172a;
158 font-size: 0.86em;
159 font-weight: 800;
160 letter-spacing: 0.08em;
161 text-transform: uppercase;
162}
163
164.room-qr-card.is-collapsed .room-qr,
165.room-qr-card.is-collapsed .room-qr-title,
166.room-qr-card.is-collapsed .room-link-status {
167 display: none;
168}
169
170.room-qr-card.is-collapsed .room-qr-collapsed-label {
171 display: flex;
172}
173
174.room-links span {
175 color: rgba(51, 65, 85, 0.8);
176}
177
178.room-link-status {
179 min-width: 58px;
180 color: #166534;
181 font-size: 0.78em;
182 text-shadow: none;
183 margin: 0;
184}
185
186.room-link-status.error {
187 color: #b91c1c;
188}
189
190.name-form {
191 display: flex;
192 flex-direction: column;
193 align-items: stretch;
194 justify-content: center;
195 gap: 8px;
196 padding: 10px;
197 margin-top: 4px;
198 width: min(100%, 520px);
199 box-sizing: border-box;
200 border-radius: 12px;
201 background: rgba(255, 255, 255, 0.94);
202 border: 1px solid #cbd5e1;
203 box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);
204 backdrop-filter: blur(6px);
205 position: relative;
206 z-index: 2;
207}
208
209.controls-row {
210 display: flex;
211 align-items: center;
212 justify-content: center;
213 gap: 8px;
214 flex-wrap: wrap;
215}
216
217.controls-row-main {
218 flex-wrap: nowrap;
219}
220
221.controls-row-secondary {
222 justify-content: center;
223}
224
225.name-form label {
226 font-size: 14px;
227 font-weight: 600;
228 color: #334155;
229}
230
231.name-form input {
232 width: auto;
233 min-width: 0;
234 max-width: 220px;
235 flex: 1 1 220px;
236 padding: 10px 12px;
237 border: 1px solid #64748b;
238 border-radius: 10px;
239 background: rgba(248, 250, 252, 0.96);
240 color: #0f172a;
241 font-size: 16px;
242}
243
244.name-form input[type="color"] {
245 width: 44px;
246 flex: 0 0 auto;
247 min-width: 44px;
248 height: 44px;
249 padding: 2px;
250 border-radius: 10px;
251 border: 1px solid #64748b;
252 background: rgba(248, 250, 252, 0.96);
253}
254
255.name-form button {
256 padding: 10px 12px;
257 border: 0;
258 border-radius: 10px;
259 background: #0ea5e9;
260 color: #f8fafc;
261 font-weight: 700;
262 font-size: 14px;
263}
264
265.name-form button:active {
266 transform: translateY(1px);
267}
268
269.dark-mode-toggle {
270 width: 44px;
271 flex: 0 0 auto;
272 min-width: 44px;
273 height: 44px;
274 padding: 2px;
275 border: 1px solid #64748b;
276 border-radius: 10px;
277 background: rgba(248, 250, 252, 0.96);
278 font-size: 22px;
279 line-height: 1;
280 cursor: pointer;
281}
282
283.wake-lock-toggle {
284 width: 44px;
285 flex: 0 0 auto;
286 min-width: 44px;
287 height: 44px;
288 padding: 2px;
289 border: 1px solid #64748b;
290 border-radius: 10px;
291 background: rgba(248, 250, 252, 0.96);
292 font-size: 22px;
293 line-height: 1;
294 cursor: pointer;
295}
296
297.wake-lock-toggle.is-on {
298 box-shadow: 0 0 0 2px rgba(14, 165, 233, 0.3);
299}
300
301.clean-mode-toggle {
302 flex: 0 0 auto;
303 min-width: 72px;
304 height: 44px;
305 padding: 0 10px;
306 border: 1px solid #64748b;
307 border-radius: 10px;
308 background: rgba(248, 250, 252, 0.96);
309 color: #0f172a;
310 font-size: 13px;
311 font-weight: 800;
312 cursor: pointer;
313}
314
315body.dark .dark-mode-toggle {
316 background: #0f172a;
317 border-color: #475569;
318}
319
320body.dark .wake-lock-toggle {
321 background: #0f172a;
322 border-color: #475569;
323}
324
325body.dark .wake-lock-toggle.is-on {
326 box-shadow: 0 0 0 2px rgba(56, 189, 248, 0.4);
327}
328
329body.dark .clean-mode-toggle {
330 background: #0f172a;
331 border-color: #475569;
332 color: #f1f5f9;
333}
334
335body.clean-mode {
336 gap: 0;
337 padding: 0;
338}
339
340body.clean-mode .app-title,
341body.clean-mode .room-header,
342body.clean-mode #room-links,
343body.clean-mode #debug-info,
344body.clean-mode #friends-panel,
345body.clean-mode #lobby-buttons {
346 display: none !important;
347}
348
349body.clean-mode #name-form {
350 position: fixed;
351 top: max(8px, env(safe-area-inset-top));
352 right: 8px;
353 margin: 0;
354 padding: 0;
355 width: auto;
356 border: 0;
357 background: transparent;
358 box-shadow: none;
359 backdrop-filter: none;
360 z-index: 10;
361}
362
363body.clean-mode .controls-row-main {
364 gap: 0;
365}
366
367body.clean-mode .controls-row-main> :not(.clean-mode-toggle),
368body.clean-mode .controls-row-secondary {
369 display: none !important;
370}
371
372body.clean-mode #content {
373 width: 100vw;
374 min-height: 100dvh;
375}
376
377body.clean-mode .arrow {
378 width: min(98cqw, 98cqh);
379}
380
381#content {
382 position: relative;
383 width: 100%;
384 flex: 1 1 auto;
385 min-height: 220px;
386 display: block;
387 overflow: hidden;
388 pointer-events: auto;
389 z-index: 1;
390 container-type: size;
391}
392
393.is-hidden {
394 display: none !important;
395}
396
397.wake-lock-toast {
398 position: fixed;
399 left: 50%;
400 bottom: max(14px, env(safe-area-inset-bottom));
401 transform: translate(-50%, 18px);
402 z-index: 40;
403 max-width: min(92vw, 420px);
404 padding: 10px 14px;
405 border: 1px solid #cbd5e1;
406 border-radius: 12px;
407 background: rgba(255, 255, 255, 0.96);
408 color: #0f172a;
409 font-size: 13px;
410 font-weight: 700;
411 text-align: center;
412 box-shadow: 0 12px 28px rgba(15, 23, 42, 0.22);
413 opacity: 0;
414 pointer-events: none;
415 transition: opacity 180ms ease, transform 180ms ease;
416}
417
418.wake-lock-toast.is-visible {
419 opacity: 1;
420 transform: translate(-50%, 0);
421}
422
423#lobby-buttons {
424 position: absolute;
425 top: 50%;
426 left: 50%;
427 transform: translate(-50%, -50%);
428 display: flex;
429 flex-direction: column;
430 align-items: center;
431 gap: 14px;
432 z-index: 2;
433}
434
435.start-room-button {
436 min-width: 220px;
437 padding: 18px 36px;
438 border: 0;
439 border-radius: 16px;
440 background: linear-gradient(180deg, #22c55e 0%, #16a34a 100%);
441 color: #f8fafc;
442 font-size: clamp(22px, 4.2vmin, 36px);
443 font-weight: 800;
444 letter-spacing: 0.02em;
445 box-shadow: 0 16px 32px rgba(22, 163, 74, 0.35);
446 cursor: pointer;
447}
448
449.start-room-button:active {
450 transform: translateY(2px);
451}
452
453.resume-room-button {
454 min-width: 220px;
455 padding: 18px 36px;
456 border: 0;
457 border-radius: 16px;
458 background: linear-gradient(180deg, #3b82f6 0%, #2563eb 100%);
459 color: #f8fafc;
460 font-size: clamp(22px, 4.2vmin, 36px);
461 font-weight: 800;
462 letter-spacing: 0.02em;
463 box-shadow: 0 16px 32px rgba(37, 99, 235, 0.35);
464 cursor: pointer;
465}
466
467.resume-room-button:active {
468 transform: translateY(2px);
469}
470
471.friends-toggle {
472 padding: 6px 10px;
473 border: 1px solid #cbd5e1;
474 border-radius: 8px;
475 background: rgba(255, 255, 255, 0.94);
476 color: #0f172a;
477 font-size: 12px;
478 font-weight: 700;
479 cursor: pointer;
480}
481
482.name-form .friends-toggle {
483 color: #0f172a;
484}
485
486.controls-row-secondary .friends-toggle {
487 min-width: 130px;
488}
489
490.friends-toggle:disabled {
491 cursor: not-allowed;
492 opacity: 0.75;
493}
494
495.friends-toggle.compass-required {
496 border: 2px solid #ef4444;
497 box-shadow: 0 0 0 1px rgba(239, 68, 68, 0.35);
498}
499
500.friends-toggle.compass-error {
501 border: 2px solid #f97316;
502 background: rgba(255, 237, 213, 0.96);
503 color: #7c2d12;
504}
505
506.friends-panel {
507 position: absolute;
508 right: 10px;
509 top: 50%;
510 transform: translateY(-50%);
511 width: min(44vw, 280px);
512 max-height: calc(100% - 12px);
513 overflow: auto;
514 padding: 8px;
515 border-radius: 10px;
516 background: rgba(255, 255, 255, 0.94);
517 border: 1px solid #cbd5e1;
518 box-shadow: 0 10px 28px rgba(15, 23, 42, 0.1);
519 backdrop-filter: blur(6px);
520 z-index: 3;
521}
522
523.friends-panel.is-hidden {
524 display: none;
525}
526
527.friends-panel h3 {
528 margin: 0 0 6px;
529 font-size: 14px;
530 font-weight: 700;
531}
532
533.friend-row {
534 display: grid;
535 grid-template-columns: auto auto 1fr;
536 gap: 8px;
537 align-items: center;
538 margin-bottom: 6px;
539 font-size: 13px;
540}
541
542.friend-name-badge {
543 display: flex;
544 align-items: center;
545 justify-content: space-between;
546 gap: 8px;
547 width: 100%;
548 min-width: 0;
549 padding: 5px 8px;
550 border-radius: 8px;
551 border: 1px solid rgba(255, 255, 255, 0.35);
552 font-weight: 700;
553 text-shadow: none;
554}
555
556.friend-name {
557 flex: 1 1 auto;
558 min-width: 0;
559 white-space: nowrap;
560 overflow: hidden;
561 text-overflow: ellipsis;
562}
563
564.friend-presence-status {
565 flex: 0 0 auto;
566 font-size: 13px;
567 line-height: 1;
568}
569
570.friend-drag-handle {
571 width: 24px;
572 height: 24px;
573 border: 1px solid #cbd5e1;
574 border-radius: 6px;
575 background: rgba(255, 255, 255, 0.96);
576 color: #334155;
577 font-size: 14px;
578 font-weight: 700;
579 line-height: 1;
580 cursor: grab;
581 touch-action: none;
582}
583
584.friend-drag-handle:active {
585 cursor: grabbing;
586}
587
588.friend-row.drag-over-before {
589 box-shadow: inset 0 2px 0 rgba(59, 130, 246, 0.9);
590}
591
592.friend-row.drag-over-after {
593 box-shadow: inset 0 -2px 0 rgba(59, 130, 246, 0.9);
594}
595
596.friend-row.is-dragging {
597 opacity: 0.55;
598}
599
600.arrow {
601 position: absolute;
602 top: 50%;
603 left: 50%;
604 translate: -50% -50%;
605 width: min(80cqw, 84cqh);
606 aspect-ratio: 1;
607 transform: rotate(0deg);
608 user-select: none;
609 pointer-events: none;
610 z-index: 1;
611 color: #ffffff;
612 opacity: 1;
613 transition: opacity 200ms ease-out, filter 220ms ease-out;
614}
615
616.arrow-img {
617 width: 100%;
618 height: 100%;
619 background-color: currentColor;
620 background-image: none;
621 -webkit-mask-image: url('./assets/image.png');
622 mask-image: url('./assets/image.png');
623 -webkit-mask-size: contain;
624 mask-size: contain;
625 -webkit-mask-repeat: no-repeat;
626 mask-repeat: no-repeat;
627 -webkit-mask-position: center;
628 mask-position: center;
629 filter: drop-shadow(0 0 8px rgba(0, 0, 0, 0.35));
630 transition: opacity 220ms ease-out, filter 260ms ease-out, background-image 260ms ease-out;
631}
632
633.arrow-label-anchor {
634 position: absolute;
635 top: 4%;
636 left: 50%;
637 translate: -50% -50%;
638 width: 0;
639 height: 0;
640}
641
642.arrow.is-online {
643 opacity: 1;
644}
645
646.arrow.is-online .arrow-img {
647 opacity: 1;
648}
649
650.arrow.is-recent-offline {
651 opacity: 0.58;
652}
653
654.arrow.is-recent-offline .arrow-img {
655 opacity: 0.75;
656 filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.22));
657}
658
659.arrow.is-recent-offline .arrow-label {
660 opacity: 0.84;
661}
662
663.arrow.is-stale-offline {
664 opacity: 0.42;
665}
666
667.arrow.is-stale-offline .arrow-img {
668 opacity: 0.55;
669 background-color: transparent;
670 background-image: linear-gradient(to top, transparent 0%, transparent 28%, currentColor 68%, currentColor 100%);
671 filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.12));
672}
673
674.arrow.is-stale-offline .arrow-label {
675 opacity: 0.6;
676}
677
678.arrow-label {
679 position: absolute;
680 top: 0;
681 left: 0;
682 translate: -50% -50%;
683 font-family: system-ui, sans-serif;
684 font-size: clamp(18px, 3vmin, 34px);
685 font-weight: 600;
686 line-height: 1;
687 white-space: nowrap;
688 color: #ffffff;
689 -webkit-text-stroke: 0.25px rgba(0, 0, 0, 0.9);
690 text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
691}
692
693#debug-info {
694 position: relative;
695 margin: 0;
696 width: min(100%, 720px);
697 padding: 6px 10px;
698 border-radius: 10px;
699 background: rgba(248, 250, 252, 0.96);
700 color: #334155;
701 border: 1px solid #cbd5e1;
702 text-shadow: none;
703 z-index: 2;
704 text-align: center;
705 font-size: clamp(12px, 1.8vmin, 14px);
706}
707
708#debug {
709 margin: 0;
710 display: flex;
711 align-items: center;
712 justify-content: center;
713 gap: 10px;
714 flex-wrap: wrap;
715 font-size: inherit;
716 font-weight: 400;
717 line-height: 1.35;
718}
719
720#attributions {
721 margin: 4px 0 0;
722 font-size: inherit;
723 font-weight: 400;
724 line-height: 1.35;
725}
726
727#debug a {
728 text-decoration: underline;
729 text-underline-offset: 0.15em;
730}
731
732#attributions a {
733 text-decoration: underline;
734 text-underline-offset: 0.15em;
735}
736
737.hint {
738 position: fixed;
739 bottom: 16px;
740 left: 50%;
741 transform: translateX(-50%);
742 font-size: 14px;
743 color: #94a3b8;
744}
745
746/* ── Dark mode ─────────────────────────────────────────────────── */
747body.dark {
748 background: #0f172a;
749 color: #f1f5f9;
750}
751
752body.dark a {
753 color: #60a5fa;
754}
755
756body.dark .room-current {
757 color: #94a3b8;
758}
759
760body.dark .wake-lock-toast {
761 background: rgba(30, 41, 59, 0.97);
762 border-color: #475569;
763 color: #f1f5f9;
764}
765
766body.dark .room-qr-card {
767 background: #1e293b;
768 border-color: #334155;
769}
770
771body.dark .room-qr-title {
772 color: #94a3b8;
773}
774
775body.dark .room-qr {
776 background: #1e293b;
777 filter: invert(1);
778}
779
780body.dark .name-form {
781 background: rgba(30, 41, 59, 0.96);
782 border-color: #334155;
783}
784
785body.dark .name-form label {
786 color: #94a3b8;
787}
788
789body.dark .name-form input {
790 background: #0f172a;
791 border-color: #475569;
792 color: #f1f5f9;
793}
794
795body.dark .name-form input[type="color"] {
796 background: #0f172a;
797 border-color: #475569;
798}
799
800body.dark .friends-toggle {
801 background: rgba(30, 41, 59, 0.96);
802 border-color: #94a3b8;
803 color: #f1f5f9;
804 box-shadow: inset 0 0 0 1px rgba(148, 163, 184, 0.3);
805}
806
807body.dark #friends-toggle {
808 background: linear-gradient(180deg, #1d4ed8 0%, #1e3a8a 100%);
809 border: 2px solid #93c5fd;
810 color: #eff6ff;
811 box-shadow: 0 0 0 1px rgba(147, 197, 253, 0.35), 0 8px 18px rgba(30, 58, 138, 0.45);
812}
813
814body.dark #friends-toggle:active {
815 transform: translateY(1px);
816}
817
818body.dark.clean-mode .clean-mode-toggle {
819 background: #f8fafc;
820 border: 2px solid #38bdf8;
821 color: #0f172a;
822 box-shadow: 0 6px 18px rgba(15, 23, 42, 0.45);
823}
824
825body.dark .friends-toggle.compass-error {
826 background: rgba(124, 45, 18, 0.85);
827}
828
829body.dark .friends-panel {
830 background: rgba(30, 41, 59, 0.96);
831 border-color: #334155;
832}
833
834body.dark .start-room-button {
835 background: linear-gradient(180deg, #16a34a 0%, #15803d 100%);
836 box-shadow: 0 14px 28px rgba(22, 163, 74, 0.3);
837}
838
839body.dark .resume-room-button {
840 background: linear-gradient(180deg, #2563eb 0%, #1d4ed8 100%);
841 box-shadow: 0 14px 28px rgba(37, 99, 235, 0.3);
842}
843
844body.dark .friend-drag-handle {
845 background: #0f172a;
846 border-color: #475569;
847 color: #94a3b8;
848}
849
850body.dark #debug {
851 background: transparent;
852 color: #94a3b8;
853 border: 0;
854 box-shadow: none;
855}
856
857body.dark #debug a {
858 color: #60a5fa;
859 outline: none;
860 box-shadow: none;
861}
862
863body.dark #debug a:focus-visible {
864 outline: 2px solid #38bdf8;
865 outline-offset: 2px;
866 border-radius: 4px;
867}
868
869body.dark .arrow-img {
870 filter: drop-shadow(0 0 2px #fff) drop-shadow(0 0 6px rgba(255, 255, 255, 0.5));
871}
872
873body.dark .arrow.is-recent-offline .arrow-img {
874 filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 3px rgba(255, 255, 255, 0.35));
875}
876
877body.dark .arrow.is-stale-offline .arrow-img {
878 filter: drop-shadow(0 0 1px rgba(255, 255, 255, 0.35));
879}
880
881body.dark .arrow-label {
882 -webkit-text-stroke: 0.25px rgba(255, 255, 255, 0.9);
883 text-shadow: 0 1px 4px rgba(0, 0, 0, 0.95);
884}
885
886@media (max-width: 720px) {
887 .controls-row-main {
888 flex-wrap: wrap;
889 }
890
891 .controls-row-main #self-name-input {
892 flex-basis: 100%;
893 max-width: 100%;
894 }
895
896 .friends-panel {
897 width: min(88vw, 320px);
898 right: 6px;
899 top: 6px;
900 transform: none;
901 max-height: calc(100% - 12px);
902 padding: 6px;
903 }
904
905 .friend-row {
906 grid-template-columns: auto auto minmax(0, 1fr);
907 gap: 6px;
908 }
909
910 .friend-drag-handle {
911 width: 22px;
912 height: 22px;
913 font-size: 12px;
914 }
915}