anentrypoint-design 0.0.166 → 0.0.168

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.
@@ -1,31 +1,40 @@
1
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
2
-
1
+ /* Fonts are declared once in the canonical theme (colors_and_type.css /
2
+ vendor/fonts.css), which every .ds-247420 consumer loads first. No @import
3
+ here — a second Inter-only import risked a weight-set FOUT mismatch. */
4
+
5
+ /* The OS shell namespaces its surfaces as --os-* but those are pure ALIASES of
6
+ the canonical semantic tokens from colors_and_type.css. colors_and_type.css
7
+ is always loaded before this sheet for any .ds-247420 consumer, so the
8
+ canonical tokens are guaranteed present and the alias fallbacks are dropped —
9
+ a fallback here would silently re-introduce theme drift (a baked light value
10
+ that ignores [data-theme="ink"]). One theme drives both token namespaces. */
3
11
  :root {
4
- --ff-ui: 'Inter', system-ui, sans-serif;
5
- --ff-display: 'Inter', system-ui, sans-serif;
6
- --ff-mono: 'JetBrains Mono', ui-monospace, monospace;
7
- --os-accent: var(--panel-accent, #3F8A4A);
8
- --os-accent-2: var(--panel-accent-2, #2B6B36);
9
- --os-accent-soft: var(--panel-select, #D8ECCB);
10
- --os-bg-0: var(--panel-0, #F5F0E4);
11
- --os-bg-1: var(--panel-1, #FBF6EB);
12
- --os-bg-2: var(--panel-2, #F0E9DA);
13
- --os-bg-3: var(--panel-3, #E3DAC7);
14
- --os-fg: var(--panel-text, #1F1B16);
15
- --os-fg-2: var(--panel-text-2, #5A5246);
16
- --os-fg-3: var(--panel-text-3, #857B6C);
17
- --os-red: var(--warn, #FF6B4A);
18
- --os-amber: var(--sun, #FFD86B);
19
- --os-green: var(--green, #3F8A4A);
20
- --os-radius: var(--r-2, 10px);
21
- --os-radius-sm: var(--r-1, 6px);
12
+ /* --ff-ui is the OS-shell alias for the canonical body font; --ff-display
13
+ and --ff-mono are already canonical (colors_and_type.css), referenced
14
+ directly below do not self-redefine them here (cycle). */
15
+ --ff-ui: var(--ff-body);
16
+ --os-accent: var(--accent);
17
+ --os-accent-2: var(--accent-bright, var(--accent));
18
+ --os-accent-soft: var(--accent-tint);
19
+ --os-bg-0: var(--bg);
20
+ --os-bg-1: var(--bg-2);
21
+ --os-bg-2: var(--bg-3);
22
+ --os-bg-3: var(--panel-3);
23
+ --os-fg: var(--fg);
24
+ --os-fg-2: var(--fg-2);
25
+ --os-fg-3: var(--fg-3);
26
+ --os-red: var(--warn);
27
+ --os-amber: var(--sun);
28
+ --os-green: var(--green);
29
+ --os-radius: var(--r-2);
30
+ --os-radius-sm: var(--r-1);
22
31
  --os-bar-h: 44px;
23
32
  --os-bar-h-mobile: 52px;
24
33
  --os-rail-w: 64px;
25
34
  --os-tap: 44px;
26
- --os-font: var(--ff-ui, 'Inter', system-ui, sans-serif);
27
- --os-display: var(--ff-display, 'Inter', system-ui, sans-serif);
28
- --os-mono: var(--ff-mono, 'JetBrains Mono', ui-monospace, monospace);
35
+ --os-font: var(--ff-ui);
36
+ --os-display: var(--ff-display);
37
+ --os-mono: var(--ff-mono);
29
38
  }
30
39
 
31
40
  html, body {
@@ -348,10 +357,10 @@ html, body {
348
357
  .app-pane.mono pre { background: var(--os-bg-2); padding: 10px 12px; margin: 8px 0 0 0; max-height: 220px; overflow: auto; white-space: pre-wrap; font: 11.5px var(--os-mono); border-radius: var(--r-1, 6px); color: var(--os-fg); border: none; }
349
358
  .app-shell-pane { margin: 0; padding: 8px; font: 12px var(--os-mono); color: var(--os-fg); background: var(--os-bg-0); height: 100%; overflow: auto; white-space: pre-wrap; box-sizing: border-box; }
350
359
  .app-canvas { width: 100%; height: 100%; background: var(--os-bg-0); display: block; cursor: default; }
351
- .app-canvas.x-display { background: #0b0d10; }
360
+ .app-canvas.x-display { background: #0b0d10; } /* intentional: fake CRT/terminal black screen, not a theme surface */
352
361
  .app-frame { width: 100%; height: 100%; border: 0; background: var(--os-bg-0); }
353
362
  .app-iframe { width: 100%; height: 100%; border: 0; display: block; }
354
- .app-iframe.web { background: #ffffff; }
363
+ .app-iframe.web { background: #ffffff; } /* intentional: white canvas for embedded external web content that expects white */
355
364
  .app-text-cursor { }
356
365
 
357
366
  @media (prefers-reduced-motion: no-preference) {
@@ -429,53 +438,38 @@ html, body {
429
438
  .wm-resize { display: none !important; }
430
439
  }
431
440
 
432
- /* ---- data-attr theme/density/accent rules (ported from anentrypoint-update colors_and_type.css) ---- */
433
- :root[data-theme="ink"] {
434
- --os-bg-0: #14131a;
435
- --os-bg-1: #1a1924;
436
- --os-bg-2: #20202a;
437
- --os-bg-3: #2a2a36;
438
- --os-fg: #efece4;
439
- --os-fg-2: #c8c5bc;
440
- --os-fg-3: #8c8a80;
441
- color-scheme: dark;
442
- }
443
- :root[data-theme="paper"] {
444
- --os-bg-0: #f6f5f1;
445
- --os-bg-1: #efece4;
446
- --os-bg-2: #e7e3d8;
447
- --os-bg-3: #d8d3c4;
448
- --os-fg: #14131a;
449
- --os-fg-2: #3a3833;
450
- --os-fg-3: #6a6660;
451
- color-scheme: light;
452
- }
453
- :root[data-density="compact"] { --os-bar-h: 28px; --os-tile-pad: 6px; --os-gap: 6px; }
441
+ /* ---- data-attr theme/accent: deferred to the canonical theme ----
442
+ * The OS shell no longer redefines surface or accent colors per theme. The
443
+ * --os-* aliases above consume the canonical semantic tokens (--bg/--fg/
444
+ * --accent), and colors_and_type.css already drives [data-theme] (paper/ink/
445
+ * auto, with color-scheme + --danger tuning) and [data-accent] (green/purple/
446
+ * mascot). Re-declaring the os surface or accent tokens per theme here only
447
+ * re-introduced drift (ink vs canonical ink; purple vs canonical purple).
448
+ * Density bar-height is genuinely OS-shell-specific, so it stays;
449
+ * --os-accent-tint maps to the canonical accent tint. */
450
+ :root { --os-accent-tint: var(--accent-tint); }
451
+ :root[data-density="compact"] { --os-bar-h: 28px; --os-tile-pad: 6px; --os-gap: 6px; }
454
452
  :root[data-density="comfortable"] { --os-bar-h: 36px; --os-tile-pad: 10px; --os-gap: 10px; }
455
- :root[data-density="spacious"] { --os-bar-h: 44px; --os-tile-pad: 14px; --os-gap: 14px; }
456
- :root[data-accent="green"] { --os-accent: #247420; --os-accent-tint: color-mix(in oklab, #247420 18%, transparent); }
457
- :root[data-accent="purple"] { --os-accent: #7c5cff; --os-accent-tint: color-mix(in oklab, #7c5cff 18%, transparent); }
458
- :root[data-accent="mascot"] { --os-accent: #ff6d3f; --os-accent-tint: color-mix(in oklab, #ff6d3f 18%, transparent); }
459
- :root[data-theme="ink"][data-accent="green"] { --os-accent: #3FA93A; }
460
- :root[data-theme="ink"][data-accent="purple"] { --os-accent: #a085ff; }
461
- :root[data-theme="ink"][data-accent="mascot"] { --os-accent: #ff8a64; }
453
+ :root[data-density="spacious"] { --os-bar-h: 44px; --os-tile-pad: 14px; --os-gap: 14px; }
462
454
 
463
455
  /* ============================================================
464
- * thebird theme preset (migrated from thebird's local thebird-brand.css
456
+ * thebird brand layer (migrated from thebird's local thebird-brand.css
465
457
  * 2026-05-26). thebird ships ZERO design CSS — every rule below lives here
466
458
  * upstream and is delivered via the published package. Scoped to .ds-247420
467
- * (thebird's OS root carries that class). Brand identity: Inter +
468
- * --paper #F5F0E4 + green accent #247420 + uniform 34px bars +
469
- * Windows-style right-side window controls.
459
+ * (thebird's OS root carries that class). Brand identity: Inter + green accent
460
+ * + uniform 34px bars + Windows-style right-side window controls.
461
+ *
462
+ * NOTE: this no longer globally overrides --paper. A global :root override
463
+ * silently mutated the base theme for EVERY portfolio consumer (canonical
464
+ * --paper is #F6F5F1; thebird wanted #F5F0E4). The warm-paper variant is now a
465
+ * named preset [data-theme="thebird"] a consumer opts into, leaving the base
466
+ * theme untouched. The [data-theme="thebird"] COLOR preset now lives in the
467
+ * canonical colors_and_type.css (a first-class swappable theme); only the
468
+ * OS-shell chrome (bar geometry, typography alias) stays here scoped to
469
+ * .ds-247420.
470
470
  * ============================================================ */
471
- :root {
472
- --paper: #F5F0E4;
473
- }
474
471
  .ds-247420 {
475
- --ff-ui: 'Inter', system-ui, sans-serif !important;
476
- --ff-display: 'Inter', system-ui, sans-serif !important;
477
- --ff-prose: 'Inter', system-ui, sans-serif !important;
478
- --os-accent: #247420;
472
+ --ff-ui: var(--ff-body);
479
473
  /* uniform bar height: 22px button + 6px+6px padding = 34px */
480
474
  --os-bar-h: 34px !important;
481
475
  --os-bar-h-mobile: 34px !important;
@@ -518,8 +512,8 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
518
512
  position: fixed;
519
513
  pointer-events: none;
520
514
  z-index: 9050;
521
- background: color-mix(in oklab, var(--os-accent, #247420) 20%, transparent);
522
- border: 2px solid var(--os-accent, #247420);
515
+ background: color-mix(in oklab, var(--os-accent) 20%, transparent);
516
+ border: 2px solid var(--os-accent);
523
517
  border-radius: 8px;
524
518
  transition: all 120ms ease;
525
519
  }
@@ -534,14 +528,14 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
534
528
  top: 50%;
535
529
  transform: translate(-50%, -50%);
536
530
  padding: 16px 20px;
537
- background: var(--os-bg-2, #1a1a1a);
538
- border: 1px solid var(--os-accent, #247420);
531
+ background: var(--os-bg-2);
532
+ border: 1px solid var(--os-accent);
539
533
  border-radius: 8px;
540
534
  z-index: 9600;
541
- font-family: var(--ff-ui, 'Inter', sans-serif);
542
- color: var(--os-fg, #fff);
535
+ font-family: var(--ff-ui);
536
+ color: var(--os-fg);
543
537
  min-width: 280px;
544
- box-shadow: 0 12px 40px rgba(0,0,0,0.5);
538
+ box-shadow: var(--shadow-overlay);
545
539
  }
546
540
  .ds-247420 .wm-switcher-item {
547
541
  padding: 8px 12px;
@@ -551,8 +545,8 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
551
545
  gap: 10px;
552
546
  }
553
547
  .ds-247420 .wm-switcher-item.active {
554
- background: var(--os-accent, #247420);
555
- color: var(--paper, #fff);
548
+ background: var(--os-accent);
549
+ color: var(--paper);
556
550
  }
557
551
 
558
552
  /* freddie-chat font family (upstream still ships Nunito; brand is Inter). */
@@ -560,7 +554,7 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
560
554
  .ds-247420 freddie-chat .chat-bubble,
561
555
  .ds-247420 freddie-chat .chat-meta,
562
556
  .ds-247420 freddie-chat .chat-head {
563
- font-family: var(--ff-ui, 'Inter', system-ui, sans-serif);
557
+ font-family: var(--ff-ui);
564
558
  }
565
559
  .ds-247420 freddie-chat .chat-bubble pre,
566
560
  .ds-247420 freddie-chat .chat-bubble code {
@@ -587,31 +581,31 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
587
581
  display: inline-flex; align-items: center; gap: 6px;
588
582
  height: 22px; padding: 0 6px 0 8px;
589
583
  border-radius: var(--r-pill, 999px);
590
- background: color-mix(in oklab, var(--fg, #1a1a1a) 6%, transparent);
591
- color: var(--fg, #1a1a1a);
592
- font-family: var(--ff-ui, system-ui); font-size: 11px; font-weight: 500;
584
+ background: color-mix(in oklab, var(--fg) 6%, transparent);
585
+ color: var(--fg);
586
+ font-family: var(--ff-ui); font-size: 11px; font-weight: 500;
593
587
  cursor: pointer;
594
588
  border: 1px solid transparent;
595
589
  transition: background 120ms ease, border-color 120ms ease;
596
590
  user-select: none; flex: 0 0 auto;
597
591
  }
598
- .ds-247420 .tb-sess-chip:hover { background: color-mix(in oklab, var(--fg, #1a1a1a) 12%, transparent); }
592
+ .ds-247420 .tb-sess-chip:hover { background: color-mix(in oklab, var(--fg) 12%, transparent); }
599
593
  .ds-247420 .tb-sess-chip.active {
600
- background: color-mix(in oklab, var(--os-accent, #247420) 18%, transparent);
601
- border-color: var(--os-accent, #247420);
602
- color: var(--fg, #1a1a1a);
594
+ background: color-mix(in oklab, var(--os-accent) 18%, transparent);
595
+ border-color: var(--os-accent);
596
+ color: var(--fg);
603
597
  }
604
- .ds-247420 .tb-sess-chip.active .tb-sess-dot { background: var(--os-accent, #247420); box-shadow: 0 0 0 2px color-mix(in oklab, var(--os-accent, #247420) 30%, transparent); }
605
- .ds-247420 .tb-sess-dot { width: 6px; height: 6px; border-radius: 50%; background: color-mix(in oklab, var(--fg, #1a1a1a) 40%, transparent); flex: 0 0 6px; }
598
+ .ds-247420 .tb-sess-chip.active .tb-sess-dot { background: var(--os-accent); box-shadow: 0 0 0 2px color-mix(in oklab, var(--os-accent) 30%, transparent); }
599
+ .ds-247420 .tb-sess-dot { width: 6px; height: 6px; border-radius: 50%; background: color-mix(in oklab, var(--fg) 40%, transparent); flex: 0 0 6px; }
606
600
  .ds-247420 .tb-sess-label { max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
607
601
  .ds-247420 .tb-sess-badge {
608
602
  display: inline-flex; align-items: center; justify-content: center;
609
603
  min-width: 16px; height: 14px; padding: 0 4px;
610
604
  border-radius: 7px;
611
- background: color-mix(in oklab, var(--fg, #1a1a1a) 14%, transparent);
605
+ background: color-mix(in oklab, var(--fg) 14%, transparent);
612
606
  font-size: 9px; font-weight: 600; line-height: 1;
613
607
  }
614
- .ds-247420 .tb-sess-chip.active .tb-sess-badge { background: color-mix(in oklab, var(--os-accent, #247420) 30%, transparent); }
608
+ .ds-247420 .tb-sess-chip.active .tb-sess-badge { background: color-mix(in oklab, var(--os-accent) 30%, transparent); }
615
609
  .ds-247420 .tb-sess-x {
616
610
  width: 16px; height: 16px; line-height: 14px; text-align: center;
617
611
  border: 0; padding: 0; background: transparent;
@@ -620,45 +614,45 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
620
614
  opacity: 0.55; transition: opacity 120ms ease, background 120ms ease;
621
615
  }
622
616
  .ds-247420 .tb-sess-chip:hover .tb-sess-x { opacity: 1; }
623
- .ds-247420 .tb-sess-x:hover { background: color-mix(in oklab, #d33 30%, transparent); color: #fff; }
617
+ .ds-247420 .tb-sess-x:hover { background: color-mix(in oklab, var(--danger) 30%, transparent); color: var(--on-color); }
624
618
 
625
619
  .ds-247420 .tb-sess-add {
626
620
  display: inline-flex; align-items: center; gap: 4px;
627
621
  height: 22px; padding: 0 10px;
628
- border: 1px dashed color-mix(in oklab, var(--fg, #1a1a1a) 30%, transparent);
622
+ border: 1px dashed color-mix(in oklab, var(--fg) 30%, transparent);
629
623
  background: transparent;
630
624
  border-radius: var(--r-pill, 999px);
631
- font-family: var(--ff-ui, system-ui); font-size: 11px; font-weight: 500;
632
- color: var(--fg, #1a1a1a);
625
+ font-family: var(--ff-ui); font-size: 11px; font-weight: 500;
626
+ color: var(--fg);
633
627
  cursor: pointer;
634
628
  margin-left: 6px;
635
629
  transition: border-color 120ms ease, background 120ms ease;
636
630
  }
637
631
  .ds-247420 .tb-sess-add:hover {
638
- border-color: var(--os-accent, #247420);
639
- background: color-mix(in oklab, var(--os-accent, #247420) 8%, transparent);
632
+ border-color: var(--os-accent);
633
+ background: color-mix(in oklab, var(--os-accent) 8%, transparent);
640
634
  }
641
635
  .ds-247420 .tb-sess-add-plus { font-size: 13px; line-height: 1; }
642
636
  .ds-247420 .tb-sess-add-lbl { line-height: 1; }
643
637
 
644
638
  .tb-sess-overlay {
645
639
  position: fixed; inset: 0; z-index: 9800;
646
- background: color-mix(in oklab, #000 40%, transparent);
640
+ background: var(--scrim);
647
641
  display: flex; align-items: center; justify-content: center;
648
642
  animation: tb-sess-fade 120ms ease;
649
643
  }
650
644
  @keyframes tb-sess-fade { from { opacity: 0; } to { opacity: 1; } }
651
645
  .tb-sess-modal {
652
- background: var(--bg, #f5f0e4);
653
- color: var(--fg, #1a1a1a);
646
+ background: var(--bg);
647
+ color: var(--fg);
654
648
  border-radius: 12px;
655
- box-shadow: 0 12px 40px color-mix(in oklab, #000 30%, transparent);
649
+ box-shadow: var(--shadow-overlay);
656
650
  min-width: 320px; max-width: 480px;
657
- border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 12%, transparent);
651
+ border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent);
658
652
  overflow: hidden;
659
- font-family: var(--ff-ui, system-ui);
653
+ font-family: var(--ff-ui);
660
654
  }
661
- .tb-sess-modal-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 8%, transparent); }
655
+ .tb-sess-modal-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid color-mix(in oklab, var(--fg) 8%, transparent); }
662
656
  .tb-sess-modal-title { font-weight: 600; font-size: 14px; }
663
657
  .tb-sess-modal-x { background: transparent; border: 0; font-size: 20px; line-height: 1; cursor: pointer; color: inherit; padding: 0 4px; }
664
658
  .tb-sess-modal-body { padding: 16px; display: flex; flex-direction: column; gap: 8px; }
@@ -666,28 +660,28 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
666
660
  .tb-sess-modal-input {
667
661
  width: 100%; box-sizing: border-box;
668
662
  height: 32px; padding: 0 10px;
669
- border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 20%, transparent);
663
+ border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent);
670
664
  border-radius: 6px;
671
- background: color-mix(in oklab, var(--fg, #1a1a1a) 6%, var(--bg, #fff));
665
+ background: color-mix(in oklab, var(--fg) 6%, var(--bg));
672
666
  color: inherit;
673
667
  font-family: inherit; font-size: 13px;
674
668
  }
675
- .tb-sess-modal-input:focus { outline: none; border-color: var(--os-accent, #247420); box-shadow: 0 0 0 3px color-mix(in oklab, var(--os-accent, #247420) 20%, transparent); }
669
+ .tb-sess-modal-input:focus { outline: none; border-color: var(--os-accent); box-shadow: 0 0 0 3px color-mix(in oklab, var(--os-accent) 20%, transparent); }
676
670
  .tb-sess-modal-hint { font-size: 11px; opacity: 0.7; }
677
671
  .tb-sess-modal-msg { font-size: 13px; }
678
- .tb-sess-modal-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 16px; border-top: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 8%, transparent); }
672
+ .tb-sess-modal-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 16px; border-top: 1px solid color-mix(in oklab, var(--fg) 8%, transparent); }
679
673
  .tb-sess-modal-btn {
680
674
  height: 28px; padding: 0 14px;
681
- border-radius: 6px; border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 20%, transparent);
675
+ border-radius: 6px; border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent);
682
676
  background: transparent; color: inherit;
683
677
  font-family: inherit; font-size: 12px; font-weight: 500; cursor: pointer;
684
678
  transition: background 120ms ease, border-color 120ms ease;
685
679
  }
686
- .tb-sess-modal-btn:hover { background: color-mix(in oklab, var(--fg, #1a1a1a) 6%, transparent); }
687
- .tb-sess-modal-btn.primary { background: var(--os-accent, #247420); color: #fff; border-color: var(--os-accent, #247420); }
688
- .tb-sess-modal-btn.primary:hover { background: color-mix(in oklab, var(--os-accent, #247420) 80%, #000); }
689
- .tb-sess-modal-btn.danger { background: #d33; color: #fff; border-color: #d33; }
690
- .tb-sess-modal-btn.danger:hover { background: #b22; }
680
+ .tb-sess-modal-btn:hover { background: color-mix(in oklab, var(--fg) 6%, transparent); }
681
+ .tb-sess-modal-btn.primary { background: var(--os-accent); color: var(--on-color); border-color: var(--os-accent); }
682
+ .tb-sess-modal-btn.primary:hover { background: color-mix(in oklab, var(--os-accent) 80%, var(--ink)); }
683
+ .tb-sess-modal-btn.danger { background: var(--danger); color: var(--on-color); border-color: var(--danger); }
684
+ .tb-sess-modal-btn.danger:hover { background: color-mix(in oklab, var(--danger) 80%, var(--ink)); }
691
685
 
692
686
  .tb-sess-empty {
693
687
  position: fixed; inset: 0; z-index: 8900;
@@ -696,65 +690,65 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
696
690
  }
697
691
  .tb-sess-empty-card {
698
692
  pointer-events: auto;
699
- background: var(--bg, #f5f0e4);
700
- color: var(--fg, #1a1a1a);
701
- border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 14%, transparent);
693
+ background: var(--bg);
694
+ color: var(--fg);
695
+ border: 1px solid color-mix(in oklab, var(--fg) 14%, transparent);
702
696
  border-radius: 16px;
703
- box-shadow: 0 8px 32px color-mix(in oklab, #000 14%, transparent);
697
+ box-shadow: var(--shadow-3);
704
698
  padding: 32px 40px; text-align: center;
705
- font-family: var(--ff-ui, system-ui);
699
+ font-family: var(--ff-ui);
706
700
  max-width: 420px;
707
701
  }
708
702
  .tb-sess-empty-title { font-size: 18px; font-weight: 600; margin-bottom: 6px; }
709
703
  .tb-sess-empty-sub { font-size: 13px; opacity: 0.7; margin-bottom: 20px; }
710
704
  .tb-sess-empty-cta {
711
705
  height: 40px; padding: 0 24px;
712
- background: var(--os-accent, #247420); color: #fff;
706
+ background: var(--os-accent); color: var(--on-color);
713
707
  border: 0; border-radius: 999px;
714
708
  font-family: inherit; font-size: 14px; font-weight: 600;
715
709
  cursor: pointer;
716
710
  transition: transform 120ms ease, box-shadow 120ms ease;
717
711
  }
718
- .tb-sess-empty-cta:hover { transform: translateY(-1px); box-shadow: 0 4px 16px color-mix(in oklab, var(--os-accent, #247420) 40%, transparent); }
712
+ .tb-sess-empty-cta:hover { transform: translateY(-1px); box-shadow: 0 4px 16px color-mix(in oklab, var(--os-accent) 40%, transparent); }
719
713
 
720
714
  /* ---- Workspaces app — full-window session manager card grid ---- */
721
- .ds-247420 .tb-sessions-app { display: flex; flex-direction: column; height: 100%; font-family: var(--ff-ui, system-ui); color: var(--fg, #1a1a1a); background: var(--bg, #f5f0e4); }
722
- .ds-247420 .tb-sessions-bar { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-bottom: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 10%, transparent); }
715
+ .ds-247420 .tb-sessions-app { display: flex; flex-direction: column; height: 100%; font-family: var(--ff-ui); color: var(--fg); background: var(--bg); }
716
+ .ds-247420 .tb-sessions-bar { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-bottom: 1px solid color-mix(in oklab, var(--fg) 10%, transparent); }
723
717
  .ds-247420 .tb-sessions-title { font-weight: 600; font-size: 14px; }
724
718
  .ds-247420 .tb-sessions-count { font-size: 12px; opacity: 0.6; margin-left: 4px; }
725
719
  .ds-247420 .tb-sessions-spacer { flex: 1; }
726
- .ds-247420 .tb-sessions-btn { height: 28px; padding: 0 12px; border-radius: 6px; border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 20%, transparent); background: transparent; color: inherit; font-size: 12px; font-weight: 500; cursor: pointer; font-family: inherit; }
727
- .ds-247420 .tb-sessions-btn:hover { background: color-mix(in oklab, var(--fg, #1a1a1a) 6%, transparent); }
728
- .ds-247420 .tb-sessions-btn.primary { background: var(--os-accent, #247420); color: #fff; border-color: var(--os-accent, #247420); }
729
- .ds-247420 .tb-sessions-btn.danger { background: #d33; color: #fff; border-color: #d33; }
720
+ .ds-247420 .tb-sessions-btn { height: 28px; padding: 0 12px; border-radius: 6px; border: 1px solid color-mix(in oklab, var(--fg) 20%, transparent); background: transparent; color: inherit; font-size: 12px; font-weight: 500; cursor: pointer; font-family: inherit; }
721
+ .ds-247420 .tb-sessions-btn:hover { background: color-mix(in oklab, var(--fg) 6%, transparent); }
722
+ .ds-247420 .tb-sessions-btn.primary { background: var(--os-accent); color: var(--on-color); border-color: var(--os-accent); }
723
+ .ds-247420 .tb-sessions-btn.danger { background: var(--danger); color: var(--on-color); border-color: var(--danger); }
730
724
  .ds-247420 .tb-sessions-btn:disabled { opacity: 0.4; cursor: not-allowed; }
731
725
  .ds-247420 .tb-sessions-grid { flex: 1; overflow: auto; padding: 14px; display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; align-content: start; }
732
- .ds-247420 .tb-sessions-card { padding: 12px; border-radius: 10px; border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 12%, transparent); background: color-mix(in oklab, var(--fg, #1a1a1a) 3%, transparent); display: flex; flex-direction: column; gap: 8px; transition: border-color 120ms ease, transform 120ms ease; }
733
- .ds-247420 .tb-sessions-card:hover { border-color: var(--os-accent, #247420); }
734
- .ds-247420 .tb-sessions-card.active { border-color: var(--os-accent, #247420); box-shadow: 0 0 0 2px color-mix(in oklab, var(--os-accent, #247420) 30%, transparent); }
726
+ .ds-247420 .tb-sessions-card { padding: 12px; border-radius: 10px; border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent); background: color-mix(in oklab, var(--fg) 3%, transparent); display: flex; flex-direction: column; gap: 8px; transition: border-color 120ms ease, transform 120ms ease; }
727
+ .ds-247420 .tb-sessions-card:hover { border-color: var(--os-accent); }
728
+ .ds-247420 .tb-sessions-card.active { border-color: var(--os-accent); box-shadow: 0 0 0 2px color-mix(in oklab, var(--os-accent) 30%, transparent); }
735
729
  .ds-247420 .tb-sessions-card-head { display: flex; align-items: center; gap: 8px; }
736
730
  .ds-247420 .tb-sessions-card-check { width: 14px; height: 14px; cursor: pointer; flex: 0 0 14px; }
737
731
  .ds-247420 .tb-sessions-card-name { font-weight: 600; font-size: 13px; flex: 1; outline: none; padding: 2px 4px; border-radius: 4px; }
738
- .ds-247420 .tb-sessions-card-name[contenteditable="true"] { background: color-mix(in oklab, var(--fg, #1a1a1a) 8%, transparent); }
732
+ .ds-247420 .tb-sessions-card-name[contenteditable="true"] { background: color-mix(in oklab, var(--fg) 8%, transparent); }
739
733
  .ds-247420 .tb-sessions-card-id { font-family: var(--os-mono, monospace); font-size: 10px; opacity: 0.5; }
740
734
  .ds-247420 .tb-sessions-card-stats { font-size: 11px; opacity: 0.7; display: flex; gap: 12px; }
741
735
  .ds-247420 .tb-sessions-card-actions { display: flex; gap: 6px; margin-top: 4px; }
742
- .ds-247420 .tb-sessions-card-actions button { flex: 1; height: 24px; font-size: 11px; padding: 0 8px; border-radius: 4px; border: 1px solid color-mix(in oklab, var(--fg, #1a1a1a) 16%, transparent); background: transparent; color: inherit; cursor: pointer; font-family: inherit; }
743
- .ds-247420 .tb-sessions-card-actions button:hover { background: color-mix(in oklab, var(--fg, #1a1a1a) 6%, transparent); }
744
- .ds-247420 .tb-sessions-card-actions button.danger:hover { background: #d33; color: #fff; border-color: #d33; }
736
+ .ds-247420 .tb-sessions-card-actions button { flex: 1; height: 24px; font-size: 11px; padding: 0 8px; border-radius: 4px; border: 1px solid color-mix(in oklab, var(--fg) 16%, transparent); background: transparent; color: inherit; cursor: pointer; font-family: inherit; }
737
+ .ds-247420 .tb-sessions-card-actions button:hover { background: color-mix(in oklab, var(--fg) 6%, transparent); }
738
+ .ds-247420 .tb-sessions-card-actions button.danger:hover { background: var(--danger); color: var(--on-color); border-color: var(--danger); }
745
739
  .ds-247420 .tb-sessions-empty-mid { padding: 40px; text-align: center; opacity: 0.6; font-size: 13px; }
746
740
 
747
741
  /* ---- prefers-contrast: more — strengthen borders + focus so the translucent
748
742
  chrome stays legible under forced/high-contrast user settings. ---- */
749
743
  @media (prefers-contrast: more) {
750
- .ds-247420 .wm-win { border-color: var(--fg, #1a1a1a); }
751
- .ds-247420 .wm-bar { border-bottom: 1px solid var(--fg, #1a1a1a); }
744
+ .ds-247420 .wm-win { border-color: var(--fg); }
745
+ .ds-247420 .wm-bar { border-bottom: 1px solid var(--fg); }
752
746
  .ds-247420 .os-menubar,
753
- .ds-247420 .os-taskbar { border-color: var(--fg, #1a1a1a); }
747
+ .ds-247420 .os-taskbar { border-color: var(--fg); }
754
748
  .ds-247420 .tb-sess-chip,
755
749
  .ds-247420 .tb-sessions-card,
756
- .ds-247420 .tb-sessions-btn { border-color: var(--fg, #1a1a1a); }
757
- .ds-247420 :focus-visible { outline: 2px solid var(--fg, #1a1a1a); outline-offset: 2px; }
750
+ .ds-247420 .tb-sessions-btn { border-color: var(--fg); }
751
+ .ds-247420 :focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; }
758
752
  }
759
753
 
760
754
  /* ---- print: a web-OS desktop has no meaningful print form. Suppress the
@@ -763,6 +757,6 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
763
757
  .os-menubar, .os-taskbar, .wm-snap-preview,
764
758
  .tb-sess-overlay, .tb-switching, .wm-switcher { display: none !important; }
765
759
  .wm-root, .wm-canvas { position: static !important; transform: none !important; overflow: visible !important; }
766
- .wm-win { position: static !important; box-shadow: none !important; border: 1px solid #000 !important; page-break-inside: avoid; margin: 0 0 12px; width: auto !important; height: auto !important; }
760
+ .wm-win { position: static !important; box-shadow: none !important; border: 1px solid var(--fg) !important; page-break-inside: avoid; margin: 0 0 12px; width: auto !important; height: auto !important; }
767
761
  .wm-win.wm-min { display: none !important; }
768
762
  }
@@ -0,0 +1,8 @@
1
+ // spoint kit — paint surfaces for the spoint game client (loading screen,
2
+ // HUD, editor chrome). Each render fn returns {node, ...controls, dispose};
3
+ // the consumer owns state/events, this kit owns layout + classes. Surfaced
4
+ // through the main bundle entry so spoint can import directly from unpkg.
5
+
6
+ export { renderLoadingScreen } from './loading-screen.js';
7
+
8
+ export const themeUrl = new URL('./loading-screen.css', import.meta.url).href;
@@ -0,0 +1,67 @@
1
+ /* Loading-screen kit styles. Scoped under .ds-247420 at build time.
2
+ All colors reference design tokens (no raw literals) per the token-lint gate. */
3
+ .sp-loading {
4
+ position: fixed;
5
+ inset: 0;
6
+ z-index: 10000;
7
+ display: flex;
8
+ align-items: center;
9
+ justify-content: center;
10
+ background: var(--bg);
11
+ color: var(--fg);
12
+ font-family: var(--ff-mono);
13
+ transition: opacity var(--dur-slow) var(--ease);
14
+ }
15
+ .sp-loading-fade { opacity: 0; pointer-events: none; }
16
+ .sp-loading-container {
17
+ width: min(420px, 86vw);
18
+ display: flex;
19
+ flex-direction: column;
20
+ gap: 20px;
21
+ }
22
+ .sp-loading-header h1 {
23
+ margin: 0;
24
+ font-family: var(--ff-display);
25
+ font-size: var(--fs-h2);
26
+ letter-spacing: 0.04em;
27
+ }
28
+ .sp-loading-label {
29
+ margin: 4px 0 0;
30
+ color: var(--fg-2);
31
+ font-size: var(--fs-body);
32
+ }
33
+ .sp-loading-bars { display: flex; flex-direction: column; gap: 10px; }
34
+ .sp-loading-bar-row {
35
+ display: grid;
36
+ grid-template-columns: 88px 1fr 44px;
37
+ align-items: center;
38
+ gap: 10px;
39
+ }
40
+ .sp-loading-bar-name {
41
+ color: var(--fg-3);
42
+ font-size: var(--fs-small, 11px);
43
+ text-transform: uppercase;
44
+ letter-spacing: 0.1em;
45
+ }
46
+ .sp-loading-bar-track {
47
+ height: 6px;
48
+ border-radius: 3px;
49
+ background: var(--bg-3);
50
+ overflow: hidden;
51
+ }
52
+ .sp-loading-bar-fill {
53
+ height: 100%;
54
+ width: 0%;
55
+ background: var(--accent);
56
+ transition: width var(--dur-base) var(--ease);
57
+ }
58
+ .sp-loading-bar-pct {
59
+ color: var(--fg-2);
60
+ font-size: var(--fs-small, 11px);
61
+ text-align: right;
62
+ }
63
+ .sp-loading-detail {
64
+ min-height: 16px;
65
+ color: var(--fg-3);
66
+ font-size: var(--fs-small, 11px);
67
+ }
@@ -0,0 +1,75 @@
1
+ // Loading-screen paint surface for the spoint game client.
2
+ // renderLoadingScreen({brand, label}) -> { node, setLabel, setDownload,
3
+ // setProcessing, setDetail, hide, dispose }. The consumer (spoint
4
+ // LoadingManager) owns progress events; this module owns layout + classes.
5
+ // Two progress bars (download, processing), a label, and a detail line.
6
+
7
+ export function renderLoadingScreen(opts = {}) {
8
+ const { brand = 'spoint', label = 'Connecting...' } = opts;
9
+
10
+ const node = document.createElement('div');
11
+ node.className = 'sp-loading ds-247420';
12
+ node.dataset.component = 'loading-screen';
13
+
14
+ const container = document.createElement('div');
15
+ container.className = 'sp-loading-container';
16
+
17
+ const header = document.createElement('div');
18
+ header.className = 'sp-loading-header';
19
+ const title = document.createElement('h1');
20
+ title.textContent = brand;
21
+ const labelEl = document.createElement('p');
22
+ labelEl.className = 'sp-loading-label';
23
+ labelEl.textContent = label;
24
+ header.append(title, labelEl);
25
+
26
+ const bars = document.createElement('div');
27
+ bars.className = 'sp-loading-bars';
28
+
29
+ const mkBar = (name) => {
30
+ const row = document.createElement('div');
31
+ row.className = 'sp-loading-bar-row';
32
+ const nameEl = document.createElement('span');
33
+ nameEl.className = 'sp-loading-bar-name';
34
+ nameEl.textContent = name;
35
+ const track = document.createElement('div');
36
+ track.className = 'sp-loading-bar-track';
37
+ const fill = document.createElement('div');
38
+ fill.className = 'sp-loading-bar-fill';
39
+ track.appendChild(fill);
40
+ const pct = document.createElement('span');
41
+ pct.className = 'sp-loading-bar-pct';
42
+ pct.textContent = '0%';
43
+ row.append(nameEl, track, pct);
44
+ return { row, fill, pct };
45
+ };
46
+
47
+ const dl = mkBar('Download');
48
+ const proc = mkBar('Processing');
49
+ bars.append(dl.row, proc.row);
50
+
51
+ const detail = document.createElement('div');
52
+ detail.className = 'sp-loading-detail';
53
+
54
+ container.append(header, bars, detail);
55
+ node.appendChild(container);
56
+
57
+ const setBar = (bar, percent) => {
58
+ bar.fill.style.width = percent + '%';
59
+ bar.pct.textContent = Math.round(percent) + '%';
60
+ };
61
+
62
+ return {
63
+ node,
64
+ setLabel: (text) => { labelEl.textContent = text; },
65
+ setDownload: (percent) => setBar(dl, percent),
66
+ setProcessing: (percent) => setBar(proc, percent),
67
+ setDetail: (text) => { detail.textContent = text; },
68
+ hide: async () => {
69
+ node.classList.add('sp-loading-fade');
70
+ await new Promise((r) => setTimeout(r, 500));
71
+ node.remove();
72
+ },
73
+ dispose: () => node.remove(),
74
+ };
75
+ }
@@ -158,9 +158,9 @@ async function runAllTests() {
158
158
  const speedup = (10000 + initStats.initMs.markdown + initStats.initMs.prism) / (mdStats.avg * 100 + initStats.initMs.markdown + initStats.initMs.prism);
159
159
  console.log(`Performance improvement: ~${speedup.toFixed(1)}x faster`);
160
160
 
161
- console.log('\n✓ All tests completed successfully');
161
+ console.log('\nPASS All tests completed successfully');
162
162
  } catch (err) {
163
- console.error('\n✗ Test failed:', err.message);
163
+ console.error('\nFAIL Test failed:', err.message);
164
164
  console.error(err.stack);
165
165
  process.exit(1);
166
166
  }