agentgui 1.0.948 → 1.0.950

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.
@@ -54,8 +54,32 @@
54
54
 
55
55
  --accent: var(--green);
56
56
  --accent-fg: var(--paper);
57
+ --accent-bright: var(--green-2); /* base value so var(--accent-bright) never falls back empty; ink + [data-accent] retune it */
57
58
  --accent-tint: color-mix(in oklab, var(--accent) 26%, var(--bg));
58
59
 
60
+ /* On-color foregrounds — text/icons that sit ON a saturated fill (accent,
61
+ danger, category chips). Theme-driven so white-on-color never hard-codes
62
+ #fff. --on-accent tracks --accent-fg; --on-color is the generic light
63
+ foreground for any colored fill. */
64
+ --on-accent: var(--accent-fg);
65
+ --on-color: #fff;
66
+
67
+ /* Scrims — modal/overlay backdrops. Derived from --fg so a dark theme dims
68
+ with its own ink rather than a baked rgba(0,0,0). */
69
+ --scrim: color-mix(in oklab, var(--fg) 40%, transparent);
70
+ --scrim-strong: color-mix(in oklab, var(--fg) 72%, transparent);
71
+ --scrim-media: color-mix(in oklab, var(--fg) 85%, transparent);
72
+
73
+ /* Category palette — surfaces (forum tags, project cards) that color-code by
74
+ category. Canonical so a theme/accent swap recolors categories instead of
75
+ drifting from a private --cat-* block. Derived from the base palette. */
76
+ --cat-green: var(--green-2);
77
+ --cat-purple: var(--purple-2);
78
+ --cat-mascot: var(--mascot);
79
+ --cat-sun: var(--sun);
80
+ --cat-flame: var(--flame);
81
+ --cat-sky: var(--sky);
82
+
59
83
  --panel-bg: var(--bg);
60
84
  --panel-bg-2: var(--bg-2);
61
85
  --panel-accent: var(--accent);
@@ -277,6 +301,47 @@
277
301
  --panel-text-3: inherit;
278
302
  --panel-accent-2: inherit;
279
303
  --panel-shadow: inherit;
304
+ --on-accent: inherit;
305
+ --on-color: inherit;
306
+ --scrim: inherit;
307
+ --scrim-strong: inherit;
308
+ --scrim-media: inherit;
309
+ --cat-green: inherit;
310
+ --cat-purple: inherit;
311
+ --cat-mascot: inherit;
312
+ --cat-sun: inherit;
313
+ --cat-flame: inherit;
314
+ --cat-sky: inherit;
315
+ }
316
+
317
+ /* ============================================================
318
+ Named-theme preset contract
319
+ ------------------------------------------------------------
320
+ A theme is one [data-theme="X"] block that overrides ONLY the semantic
321
+ surface tokens — never component rules, never raw literals in component
322
+ sheets. The base :root above IS the "paper" theme; [data-theme="paper"]
323
+ restates it so the attribute is explicit and round-trippable. To add a
324
+ theme: copy a block, rename the attr, retune the ~8 semantic tokens.
325
+ ============================================================ */
326
+ .ds-247420[data-theme="paper"] {
327
+ color-scheme: light;
328
+ --bg: var(--paper); --bg-2: var(--paper-2); --bg-3: var(--paper-3);
329
+ --fg: var(--ink); --fg-2: var(--ink-2); --fg-3: var(--ink-3);
330
+ --accent: var(--green); --accent-fg: var(--paper);
331
+ }
332
+
333
+ /* thebird — warm-paper brand preset. A first-class swappable theme: it lives
334
+ here in the canonical layer (not as a global :root override) so any consumer
335
+ can opt in with data-theme="thebird". The OS-shell chrome (bar heights,
336
+ window controls) stays in src/kits/os/theme.css; only color lives here. */
337
+ .ds-247420[data-theme="thebird"] {
338
+ color-scheme: light;
339
+ --paper: #F5F0E4;
340
+ --paper-2: #EFE9DB;
341
+ --paper-3: #E3DAC7;
342
+ --bg: var(--paper); --bg-2: var(--paper-2); --bg-3: var(--paper-3);
343
+ --fg: var(--ink); --fg-2: var(--ink-2); --fg-3: var(--ink-3);
344
+ --accent: var(--green); --accent-fg: var(--paper);
280
345
  }
281
346
 
282
347
  .ds-247420[data-density="compact"] { --density: 0.75; }
@@ -322,6 +387,10 @@
322
387
  0 2px 4px color-mix(in oklab, var(--fg) 6%, transparent);
323
388
  --shadow-3: 0 12px 32px color-mix(in oklab, var(--fg) 14%, transparent),
324
389
  0 4px 8px color-mix(in oklab, var(--fg) 8%, transparent);
390
+ /* Overlay elevation — the float for dialogs/lightboxes that sit above a
391
+ scrim; heavier than --shadow-3 and theme-driven (was raw rgba(0,0,0,.4)). */
392
+ --shadow-overlay: 0 12px 40px color-mix(in oklab, var(--fg) 28%, transparent),
393
+ 0 4px 12px color-mix(in oklab, var(--fg) 16%, transparent);
325
394
  --z-dropdown: 600;
326
395
  --z-popover: 700;
327
396
  --z-modal: 800;
@@ -466,7 +535,7 @@
466
535
 
467
536
  .ds-247420 pre {
468
537
  font-family: var(--ff-mono);
469
- background: var(--panel-bg, #15151a);
538
+ background: var(--panel-bg);
470
539
  color: var(--panel-text, inherit);
471
540
  padding: var(--space-5);
472
541
  overflow-x: auto;
@@ -477,7 +546,7 @@
477
546
  }
478
547
  .ds-247420 pre .k { color: var(--mascot); }
479
548
  .ds-247420 pre .s { color: var(--sun); }
480
- .ds-247420 pre .c { color: #9A9AA2; }
549
+ .ds-247420 pre .c { color: var(--fg-3); }
481
550
  .ds-247420 pre .n { color: var(--green-2); }
482
551
 
483
552
  /* ============================================================
@@ -662,7 +731,14 @@
662
731
  align-self: stretch;
663
732
  height: 100%;
664
733
  }
665
- .ds-247420 .app-main > * { min-height: 0; }
734
+ /* Document children (hero, sections, panels) keep their natural height in the
735
+ scrolling flex column. Without flex-shrink:0 the flex algorithm shrinks them
736
+ toward min-height:0 once total content exceeds the fixed-height .app-main,
737
+ collapsing every section to 0 and piling content on top of itself — the
738
+ failure mode any long-scroll page (a marketing/landing route) hits. Grow
739
+ children (.chat/.grow/etc.) re-assert flex:1 1 auto below via higher
740
+ specificity, so a single full-height pane still fills the region. */
741
+ .ds-247420 .app-main > * { min-height: 0; flex-shrink: 0; }
666
742
  /* The main region scrolls its own overflow at every breakpoint (previously
667
743
  only ≥901px), so a fixed-height .app never clips route content and inner
668
744
  panels don't fight the page scroll. */
@@ -864,6 +940,11 @@
864
940
  .ds-247420 .row.row-state-disabled { opacity: 0.5; pointer-events: none; }
865
941
  .ds-247420 .row.row-state-error { background: color-mix(in oklab, var(--flame) 10%, var(--bg-2)); }
866
942
  .ds-247420 .row.row-state-error::before { background: var(--flame); }
943
+ /* rail tones — a persistent status colour on the leading rail (the ::before
944
+ bar). Active/hover/error still win via their own rules below source order. */
945
+ .ds-247420 .row.rail-green::before { background: var(--accent); }
946
+ .ds-247420 .row.rail-purple::before { background: var(--purple-2, #7F18A4); }
947
+ .ds-247420 .row.rail-flame::before { background: var(--flame); }
867
948
  .ds-247420 .row-grid { /* explicit grid-template-columns set inline */ }
868
949
 
869
950
  .ds-247420 .row .code { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); }
@@ -921,10 +1002,10 @@
921
1002
  .ds-247420 .cli .copy {
922
1003
  padding: 8px 16px; background: transparent; color: var(--paper);
923
1004
  font-size: var(--fs-tiny); text-transform: uppercase; letter-spacing: var(--tr-caps);
924
- cursor: pointer; box-shadow: inset 0 0 0 1px #6A6A70;
1005
+ cursor: pointer; box-shadow: inset 0 0 0 1px var(--rule-strong);
925
1006
  border-radius: var(--r-pill);
926
1007
  }
927
- .ds-247420 .cli .copy:hover { background: #6A6A70; }
1008
+ .ds-247420 .cli .copy:hover { background: var(--fg-3); }
928
1009
 
929
1010
  /* Multi-line CLI block: when .cli holds .cli-line / .cli-cmt children
930
1011
  (quickstart scripts, multi-command snippets) it stacks as a column
@@ -1026,6 +1107,7 @@
1026
1107
  /* ============================================================
1027
1108
  Currently shipping dots
1028
1109
  ============================================================ */
1110
+ .ds-247420 .ds-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex-shrink: 0; vertical-align: middle; }
1029
1111
  .ds-247420 .ds-dot-on { color: var(--green-2); }
1030
1112
  .ds-247420 .ds-dot-off { color: var(--fg-3); }
1031
1113
  .ds-247420 .ds-dot-live { color: var(--green-2); }
@@ -1118,8 +1200,13 @@
1118
1200
  .ds-247420 .app-topbar {
1119
1201
  gap: var(--space-2); padding: 12px var(--space-3);
1120
1202
  }
1203
+ /* When the topbar is folded into .app-chrome it is a flex:0 0 auto child, so
1204
+ it sizes to its nav's content and overflows the viewport instead of letting
1205
+ the nav's own overflow-x:auto engage. Constrain it to the chrome width so
1206
+ the horizontally-scrolling nav stays inside the screen. */
1207
+ .ds-247420 .app-chrome > .app-topbar { max-width: 100%; min-width: 0; flex-basis: 100%; }
1121
1208
  .ds-247420 .app-topbar > nav {
1122
- flex: 1 1 100%; margin-left: 0; order: 3;
1209
+ flex: 1 1 100%; margin-left: 0; order: 3; min-width: 0; max-width: 100%;
1123
1210
  display: flex; gap: 2px; flex-wrap: nowrap;
1124
1211
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
1125
1212
  }
@@ -1617,7 +1704,7 @@
1617
1704
  .ds-247420 .btn-primary.danger {
1618
1705
  background: var(--warn);
1619
1706
  border-color: var(--warn);
1620
- color: #fff;
1707
+ color: var(--on-color);
1621
1708
  }
1622
1709
 
1623
1710
  /* ── Preview ──────────────────────────────────────────────── */
@@ -1801,7 +1888,7 @@
1801
1888
  .ds-247420 .ds-segmented .ds-seg-btn:hover { color: var(--fg); }
1802
1889
  .ds-247420 .ds-segmented .ds-seg-btn.is-on {
1803
1890
  background: var(--bg); color: var(--fg);
1804
- box-shadow: 0 1px 2px rgba(0,0,0,0.08);
1891
+ box-shadow: var(--shadow-1);
1805
1892
  }
1806
1893
  .ds-247420 .ds-theme-toggle.btn {
1807
1894
  font-family: var(--ff-mono); font-size: var(--fs-xs);
@@ -2276,11 +2363,13 @@
2276
2363
  .ds-247420 .chat-composer textarea { padding: 10px 12px; }
2277
2364
  }
2278
2365
 
2279
- /* ── landscape orientation: reduce vertical space for composer ──────────── */
2366
+ /* --- landscape orientation: reduce vertical space for composer --- */
2280
2367
  @media (max-height: 500px) and (orientation: landscape) {
2281
2368
  .ds-247420 .chat-composer { padding: 6px 0; }
2282
- .ds-247420 .chat-composer textarea { min-height: 36px; max-height: 120px; }
2283
- .ds-247420 .chat-composer .send, .ds-247420 .chat-composer button { width: 36px; height: 36px; font-size: 14px; }
2369
+ .ds-247420 .chat-composer textarea { min-height: 44px; max-height: 120px; }
2370
+ /* Keep the send button at the 44x44 minimum tap target even in the
2371
+ space-constrained landscape layout. */
2372
+ .ds-247420 .chat-composer .send, .ds-247420 .chat-composer button { width: 44px; height: 44px; font-size: 14px; }
2284
2373
  }
2285
2374
 
2286
2375
  /* ============================================================
@@ -2571,7 +2660,7 @@
2571
2660
  }
2572
2661
  .ds-247420 .ds-field input[aria-invalid="true"],
2573
2662
  .ds-247420 .ds-field textarea[aria-invalid="true"] {
2574
- box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--flame, #d64545);
2663
+ box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--flame);
2575
2664
  }
2576
2665
 
2577
2666
  /* Clear button for text inputs */
@@ -2864,6 +2953,7 @@
2864
2953
  font-size: var(--fs-sm);
2865
2954
  color: var(--fg-2);
2866
2955
  }
2956
+ .ds-247420 .ds-alert-retry { margin-top: var(--space-2); }
2867
2957
 
2868
2958
  .ds-247420 .ds-alert-dismiss {
2869
2959
  flex-shrink: 0;
@@ -2940,9 +3030,11 @@
2940
3030
  /* Mobile nav toggle (hamburger) — hidden on desktop, shown ≤900px */
2941
3031
  .ds-247420 .app-side-toggle {
2942
3032
  display: none;
2943
- position: fixed; top: calc((var(--app-topbar-h) - 32px) / 2); left: 10px;
3033
+ position: fixed; top: calc((var(--app-topbar-h) - 44px) / 2); left: 10px;
2944
3034
  z-index: 51;
2945
- width: 36px; height: 36px;
3035
+ /* 44x44 minimum hit area (WCAG 2.5.5 / Apple HIG) - 36px is below the
3036
+ reliable-tap threshold on touch. */
3037
+ width: 44px; height: 44px;
2946
3038
  align-items: center; justify-content: center;
2947
3039
  font-size: 18px; line-height: 1;
2948
3040
  background: var(--bg-2); color: var(--fg);
@@ -4433,9 +4525,9 @@
4433
4525
  cursor: pointer; font-size: 16px; line-height: 1;
4434
4526
  }
4435
4527
  .ds-247420 .vx-vc-btn:hover { background: var(--bg-4, var(--bg-3)); }
4436
- .ds-247420 .vx-vc-on { background: var(--accent); color: var(--accent-fg, #fff); border-color: var(--accent); }
4528
+ .ds-247420 .vx-vc-on { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
4437
4529
  .ds-247420 .vx-vc-disabled, .ds-247420 .vx-vc-btn:disabled { opacity: .4; cursor: not-allowed; }
4438
- .ds-247420 .vx-vc-leave { margin-left: auto; background: var(--danger, #d04545); color: #fff; border-color: var(--danger, #d04545); }
4530
+ .ds-247420 .vx-vc-leave { margin-left: auto; background: var(--danger); color: var(--on-color); border-color: var(--danger); }
4439
4531
  .ds-247420 .vx-vc-glyph { pointer-events: none; }
4440
4532
 
4441
4533
  /* ThreadPanel — cm-thread-panel / cm-tp-* */
@@ -4471,14 +4563,14 @@
4471
4563
  .ds-247420 .cm-tp-item-title { font-size: var(--fs-1, 14px); }
4472
4564
  .ds-247420 .cm-tp-item-snippet { font-size: var(--fs-0, 12px); color: var(--fg-2, var(--fg)); opacity: .8; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
4473
4565
  .ds-247420 .cm-tp-item-meta { display: flex; gap: var(--space-2); font-size: var(--fs-micro, 11px); color: var(--fg-2, var(--fg)); opacity: .7; }
4474
- .ds-247420 .cm-tp-empty, .ds-247420 .cm-forum-empty { padding: var(--space-3); text-align: center; color: var(--fg-2, var(--fg)); opacity: .7; }
4566
+ .ds-247420 .cm-tp-empty, .ds-247420 .cm-forum-empty, .ds-247420 .cm-channel-empty, .ds-247420 .cm-member-empty { padding: var(--space-3); text-align: center; color: var(--fg-2, var(--fg)); opacity: .7; font-size: var(--fs-sm); }
4475
4567
 
4476
4568
  /* ForumView — cm-forum / cm-forum-* */
4477
4569
  .ds-247420 .cm-forum { display: flex; flex-direction: column; height: 100%; min-height: 0; background: var(--bg-1, var(--bg-2)); color: var(--fg); }
4478
4570
  .ds-247420 .cm-forum-toolbar { display: flex; gap: var(--space-2); align-items: center; padding: var(--space-2); border-bottom: var(--bw-hair) solid var(--rule); }
4479
4571
  .ds-247420 .cm-forum-search { flex: 1; padding: var(--space-1) var(--space-2); border: var(--bw-hair) solid var(--rule-strong); border-radius: var(--r-1); background: var(--bg-3); color: var(--fg); }
4480
4572
  .ds-247420 .cm-forum-sort { padding: var(--space-1); border: var(--bw-hair) solid var(--rule-strong); border-radius: var(--r-1); background: var(--bg-3); color: var(--fg); }
4481
- .ds-247420 .cm-forum-new { padding: var(--space-1) var(--space-2); border: none; border-radius: var(--r-1); background: var(--accent); color: var(--accent-fg, #fff); cursor: pointer; }
4573
+ .ds-247420 .cm-forum-new { padding: var(--space-1) var(--space-2); border: none; border-radius: var(--r-1); background: var(--accent); color: var(--accent-fg); cursor: pointer; }
4482
4574
  .ds-247420 .cm-forum-list { flex: 1; min-height: 0; overflow-y: auto; }
4483
4575
  .ds-247420 .cm-forum-item { display: flex; flex-direction: column; gap: var(--space-1); width: 100%; text-align: left; cursor: pointer; padding: var(--space-2) var(--space-3); border: none; background: transparent; border-bottom: var(--bw-hair) solid var(--rule); color: var(--fg); }
4484
4576
  .ds-247420 .cm-forum-item:hover { background: var(--bg-3); }
@@ -4522,8 +4614,200 @@
4522
4614
  }
4523
4615
 
4524
4616
  /* chat.css */
4525
- /* chat.css — chat-specific styles. Currently empty; all chat styles live in
4526
- app-shell.css under the .chat-* prefix. Reserved for future split. */
4617
+ /* chat.css — chat-specific styles. Most chat styles live in app-shell.css under
4618
+ the .chat-* prefix. This file carries the AgentChat kit styles (the reusable
4619
+ multi-agent orchestration chat surface). */
4620
+
4621
+ .ds-247420 .agentchat {
4622
+ display: flex;
4623
+ flex-direction: column;
4624
+ min-height: 0;
4625
+ flex: 1;
4626
+ gap: var(--space-2, 8px);
4627
+ }
4628
+
4629
+ /* agent + model picker, new/stop, status — wraps on narrow widths */
4630
+ .ds-247420 .agentchat-controls {
4631
+ display: flex;
4632
+ align-items: center;
4633
+ flex-wrap: wrap;
4634
+ gap: var(--space-2, 8px);
4635
+ }
4636
+ .ds-247420 .agentchat-controls .select,
4637
+ .ds-247420 .agentchat-controls [role="combobox"] { min-width: 130px; max-width: 240px; }
4638
+ .ds-247420 .agentchat-controls .ds-select { min-width: 130px; max-width: 240px; }
4639
+
4640
+ /* Narrow viewports: let the agent/model selects share the row two-up, then
4641
+ stack full-width on the smallest screens, and drop the status to its own
4642
+ line so nothing is squeezed below a usable tap size. */
4643
+ @media (max-width: 640px) {
4644
+ .ds-247420 .agentchat-controls .select,
4645
+ .ds-247420 .agentchat-controls .ds-select,
4646
+ .ds-247420 .agentchat-controls [role="combobox"] { flex: 1 1 45%; max-width: none; }
4647
+ .ds-247420 .agentchat-status { margin-left: 0; flex-basis: 100%; }
4648
+ }
4649
+ @media (max-width: 360px) {
4650
+ .ds-247420 .agentchat-controls .select,
4651
+ .ds-247420 .agentchat-controls .ds-select,
4652
+ .ds-247420 .agentchat-controls [role="combobox"] { flex-basis: 100%; }
4653
+ }
4654
+
4655
+ .ds-247420 .agentchat-status {
4656
+ display: inline-flex;
4657
+ align-items: center;
4658
+ gap: .4em;
4659
+ white-space: nowrap;
4660
+ margin-left: auto;
4661
+ font-size: .85em;
4662
+ color: var(--fg-3);
4663
+ }
4664
+ /* status disc — a CSS-drawn dot, not a glyph; pulses while streaming */
4665
+ .ds-247420 .agentchat-status .status-dot-disc {
4666
+ flex: none; width: 8px; height: 8px; border-radius: 50%;
4667
+ background: var(--fg-3);
4668
+ }
4669
+ .ds-247420 .agentchat-status .status-dot-disc.status-dot-live {
4670
+ background: var(--accent);
4671
+ animation: agentchat-pulse 2s infinite;
4672
+ }
4673
+ @keyframes agentchat-pulse {
4674
+ 0% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--accent) 50%, transparent); }
4675
+ 70% { box-shadow: 0 0 0 6px color-mix(in oklab, var(--accent) 0%, transparent); }
4676
+ 100% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--accent) 0%, transparent); }
4677
+ }
4678
+ @media (prefers-reduced-motion: reduce) {
4679
+ .ds-247420 .agentchat-status .status-dot-disc { animation: none !important; }
4680
+ }
4681
+
4682
+ /* working-directory bar */
4683
+ .ds-247420 .agentchat-cwd {
4684
+ display: flex;
4685
+ align-items: center;
4686
+ gap: var(--space-2, 8px);
4687
+ font-size: .85em;
4688
+ color: var(--fg-3);
4689
+ flex-wrap: wrap;
4690
+ }
4691
+ .ds-247420 .agentchat-cwd-text {
4692
+ overflow: hidden;
4693
+ text-overflow: ellipsis;
4694
+ white-space: nowrap;
4695
+ /* 60ch overflows narrow phones; clamp to the viewport so the path ellipsizes
4696
+ instead of pushing the row wider than the screen. */
4697
+ max-width: min(60ch, 60vw);
4698
+ }
4699
+ .ds-247420 .agentchat-cwd-btn {
4700
+ background: none;
4701
+ border: 1px solid var(--rule);
4702
+ color: inherit;
4703
+ border-radius: 6px;
4704
+ padding: 2px 8px;
4705
+ cursor: pointer;
4706
+ font: inherit;
4707
+ }
4708
+ .ds-247420 .agentchat-cwd-btn:hover { border-color: var(--accent); }
4709
+ .ds-247420 .agentchat-cwd-btn:focus-visible { outline: 2px solid var(--accent, var(--fg)); outline-offset: 2px; }
4710
+ .ds-247420 .agentchat-cwd-input {
4711
+ flex: 1;
4712
+ min-width: 12ch;
4713
+ background: var(--bg-2);
4714
+ border: 1px solid var(--rule);
4715
+ color: var(--fg);
4716
+ border-radius: 6px;
4717
+ padding: 4px 8px;
4718
+ font: inherit;
4719
+ }
4720
+
4721
+ /* head + thread */
4722
+ .ds-247420 .agentchat-head {
4723
+ display: flex;
4724
+ align-items: baseline;
4725
+ gap: .5em;
4726
+ }
4727
+ .ds-247420 .agentchat-title { font-size: 1em; margin: 0; }
4728
+ .ds-247420 .agentchat-sub { font-size: .85em; color: var(--fg-3); }
4729
+ .ds-247420 .agentchat-thread {
4730
+ flex: 1;
4731
+ min-height: 0;
4732
+ overflow-y: auto;
4733
+ display: flex;
4734
+ flex-direction: column;
4735
+ gap: var(--space-2, 8px);
4736
+ }
4737
+
4738
+ /* Empty state: a fresh thread is an invitation, not a void. */
4739
+ .ds-247420 .agentchat-empty {
4740
+ margin: auto;
4741
+ display: flex;
4742
+ flex-direction: column;
4743
+ align-items: center;
4744
+ gap: .4em;
4745
+ text-align: center;
4746
+ padding: var(--space-6, 32px) var(--space-4, 16px);
4747
+ color: var(--fg-3);
4748
+ max-width: 46ch;
4749
+ }
4750
+ .ds-247420 .agentchat-empty-title { margin: 0; font-size: 1.05em; color: var(--fg-2, var(--fg)); }
4751
+ .ds-247420 .agentchat-empty-sub { margin: 0; font-size: .9em; }
4752
+ .ds-247420 .agentchat-empty-suggestions {
4753
+ display: flex;
4754
+ flex-wrap: wrap;
4755
+ gap: .5em;
4756
+ justify-content: center;
4757
+ margin-top: .5em;
4758
+ }
4759
+ .ds-247420 .agentchat-empty-suggestion {
4760
+ cursor: pointer;
4761
+ font: inherit;
4762
+ font-size: .85em;
4763
+ padding: .4em .8em;
4764
+ border-radius: 999px;
4765
+ border: 1px solid color-mix(in srgb, var(--fg) 16%, transparent);
4766
+ background: color-mix(in srgb, var(--fg) 5%, transparent);
4767
+ color: var(--fg-2, var(--fg));
4768
+ }
4769
+ .ds-247420 .agentchat-empty-suggestion:hover { background: color-mix(in srgb, var(--accent, var(--fg)) 12%, transparent); }
4770
+ .ds-247420 .agentchat-empty-suggestion:focus-visible { outline: 2px solid var(--accent, var(--fg)); outline-offset: 2px; }
4771
+
4772
+ /* "working" tail: a long silent tool call shouldn't read as frozen. */
4773
+ .ds-247420 .agentchat-working {
4774
+ display: flex;
4775
+ align-items: center;
4776
+ gap: .5em;
4777
+ padding: .3em .2em;
4778
+ color: var(--fg-3);
4779
+ font-size: .85em;
4780
+ }
4781
+ .ds-247420 .agentchat-working-text { color: var(--fg-3); }
4782
+ /* Self-contained dots (chat-thinking-dots lives in a kit sheet not bundled
4783
+ into this DS distribution, so the agentchat tail draws its own). */
4784
+ .ds-247420 .agentchat-working .chat-thinking-dots { display: inline-flex; gap: 3px; }
4785
+ .ds-247420 .agentchat-working .chat-thinking-dots span {
4786
+ width: 5px; height: 5px; border-radius: 50%;
4787
+ background: var(--fg); opacity: .4;
4788
+ animation: agentchat-dot-bounce 1.2s infinite ease-in-out;
4789
+ }
4790
+ .ds-247420 .agentchat-working .chat-thinking-dots span:nth-child(2) { animation-delay: .15s; }
4791
+ .ds-247420 .agentchat-working .chat-thinking-dots span:nth-child(3) { animation-delay: .3s; }
4792
+ @keyframes agentchat-dot-bounce {
4793
+ 0%, 80%, 100% { transform: scale(.6); opacity: .3; }
4794
+ 40% { transform: scale(1); opacity: .9; }
4795
+ }
4796
+ @media (prefers-reduced-motion: reduce) {
4797
+ .ds-247420 .agentchat-working .chat-thinking-dots span { animation: none; opacity: .7; }
4798
+ }
4799
+
4800
+ /* Responsive: the control cluster + cwd bar must stay usable on phones/tablets.
4801
+ The cwd path can't eat the row beside its label + buttons on a narrow screen. */
4802
+ .ds-247420 .agentchat-controls { flex-wrap: wrap; }
4803
+ .ds-247420 .agentchat-cwd-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: min(60ch, 60vw); }
4804
+ @media (max-width: 900px) {
4805
+ .ds-247420 .agentchat-controls .ds-select { min-width: 110px; max-width: 180px; }
4806
+ }
4807
+ @media (max-width: 640px) {
4808
+ .ds-247420 .agentchat-cwd-text { max-width: 42vw; }
4809
+ .ds-247420 .agentchat-controls { gap: .4em; }
4810
+ }
4527
4811
 
4528
4812
  /* editor-primitives.css */
4529
4813
  /* editor-primitives.css — chrome for in-engine editors, inspectors, IDEs,
@@ -4531,6 +4815,71 @@
4531
4815
  resolved from colors_and_type.css: --panel-{0..3}, --panel-text(-2/-3),
4532
4816
  --accent, --accent-fg, --rule, --rule-strong, --r-1/-2, --ff-mono. */
4533
4817
 
4818
+ /* ---------------------------------------------------------------
4819
+ Docked panel — the engine-editor idiom: flush, square, dense,
4820
+ full-height. Unlike the dashboard .panel card (rounded, margined,
4821
+ shadowed) this docks edge-to-edge with a 1px --rule seam. Use for
4822
+ inspector / hierarchy / apps / events columns inside an editor.
4823
+ --------------------------------------------------------------- */
4824
+ .ds-247420 .ds-ep-panel {
4825
+ display: flex; flex-direction: column;
4826
+ min-height: 0; height: 100%;
4827
+ margin: 0; border-radius: 0; box-shadow: none;
4828
+ background: var(--panel-1);
4829
+ color: var(--panel-text);
4830
+ font: var(--fs-tiny, 12px)/var(--lh-base, 1.4) var(--ff-mono, monospace);
4831
+ overflow: hidden;
4832
+ }
4833
+ .ds-247420 .ds-ep-panel-head {
4834
+ flex-shrink: 0;
4835
+ display: flex; align-items: center; justify-content: space-between; gap: 8px;
4836
+ padding: 6px 10px;
4837
+ border-bottom: 1px solid var(--rule);
4838
+ font-size: var(--fs-micro, 11px); font-weight: 600;
4839
+ text-transform: uppercase; letter-spacing: 0.1em;
4840
+ color: var(--panel-text-3);
4841
+ white-space: nowrap;
4842
+ }
4843
+ .ds-247420 .ds-ep-panel-head > :last-child {
4844
+ font-weight: 500; letter-spacing: 0;
4845
+ color: var(--panel-text-2);
4846
+ overflow: hidden; text-overflow: ellipsis;
4847
+ }
4848
+ .ds-247420 .ds-ep-panel-body {
4849
+ flex: 1; min-height: 0; overflow: auto;
4850
+ padding: 6px 8px;
4851
+ }
4852
+ .ds-247420 .ds-ep-panel-body.flush { padding: 0; }
4853
+ /* A sub-section divider inside a docked panel (e.g. app-prop mount). Only
4854
+ shows its top seam when it actually has content — an empty section is
4855
+ collapsed so no stray dashed rule floats over an empty inspector. */
4856
+ .ds-247420 .ds-ep-panel-section {
4857
+ flex-shrink: 0;
4858
+ border-top: 1px solid var(--rule);
4859
+ overflow: auto;
4860
+ }
4861
+ .ds-247420 .ds-ep-panel-section:empty { display: none; border-top: 0; }
4862
+
4863
+ /* Dense status strip for editor chrome — thin, flush, bordered top. */
4864
+ .ds-247420 .ds-ep-statusbar {
4865
+ flex-shrink: 0;
4866
+ display: flex; align-items: center; justify-content: space-between; gap: 8px;
4867
+ min-height: 0; height: 26px;
4868
+ padding: 0 10px;
4869
+ border-top: 1px solid var(--rule);
4870
+ background: var(--panel-1);
4871
+ color: var(--panel-text-2);
4872
+ font: var(--fs-micro, 11px)/1 var(--ff-mono, monospace);
4873
+ }
4874
+ .ds-247420 .ds-ep-statusbar-left, .ds-247420 .ds-ep-statusbar-right { display: flex; align-items: center; gap: 8px; min-width: 0; }
4875
+ .ds-247420 .ds-ep-statusbar-left { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
4876
+ /* Buttons inside the dense strip shrink to fit the 26px band. */
4877
+ .ds-247420 .ds-ep-statusbar button {
4878
+ min-height: 0; height: 20px; padding: 0 8px;
4879
+ border-radius: var(--r-1, 4px);
4880
+ font: var(--fs-micro, 11px)/1 var(--ff-mono, monospace);
4881
+ }
4882
+
4534
4883
  /* Toolbar */
4535
4884
  .ds-247420 .ds-ep-toolbar {
4536
4885
  display: flex; align-items: center; gap: 6px;
@@ -4568,7 +4917,24 @@
4568
4917
  color: var(--accent);
4569
4918
  border-bottom-color: var(--accent);
4570
4919
  }
4571
- .ds-247420 .ds-ep-tabs-body { flex: 1; min-height: 0; overflow: auto; }
4920
+ /* Flex column so a full-height docked child (e.g. an inspector panel) fills
4921
+ the tab body instead of collapsing under a block container. */
4922
+ .ds-247420 .ds-ep-tabs-body { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; }
4923
+
4924
+ /* EventLog — dense console-style log rows (one event per line). */
4925
+ .ds-247420 .ds-ep-eventlog {
4926
+ display: flex; flex-direction: column;
4927
+ font: var(--fs-tiny, 12px)/1.4 var(--ff-mono, monospace);
4928
+ color: var(--panel-text);
4929
+ }
4930
+ .ds-247420 .ds-ep-eventrow {
4931
+ display: flex; align-items: baseline; gap: 8px;
4932
+ padding: 3px 8px;
4933
+ border-bottom: 1px solid color-mix(in oklab, var(--rule) 50%, transparent);
4934
+ }
4935
+ .ds-247420 .ds-ep-eventrow:hover { background: color-mix(in oklab, var(--accent) 6%, transparent); }
4936
+ .ds-247420 .ds-ep-eventrow-type { color: var(--panel-text); font-weight: 600; flex-shrink: 0; }
4937
+ .ds-247420 .ds-ep-eventrow-sub { color: var(--panel-text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
4572
4938
 
4573
4939
  /* TreeView / TreeItem */
4574
4940
  .ds-247420 .ds-ep-tree {
@@ -4656,6 +5022,84 @@
4656
5022
  font-size: 0.8em;
4657
5023
  color: var(--panel-text-3);
4658
5024
  }
5025
+ /* x/y/z packed on one row, each field equal width, no horizontal overflow. */
5026
+ .ds-247420 .ds-ep-vec3 {
5027
+ display: flex; gap: 4px; width: 100%; min-width: 0;
5028
+ }
5029
+ .ds-247420 .ds-ep-vec3 > * { flex: 1 1 0; min-width: 0; }
5030
+ /* Each axis cell (axis letter + scrub input) must show its full 3-decimal value
5031
+ without clipping. The axis letter is a fixed micro-glyph; the input flexes to
5032
+ fill the rest with tight padding and centered text so 0.000 / -0.0 / 1.000 are
5033
+ always legible even in the narrow 3-up layout. */
5034
+ .ds-247420 .ds-ep-vec3 > * {
5035
+ display: flex; align-items: center; gap: 2px;
5036
+ }
5037
+ .ds-247420 .ds-ep-vec3 .ds-ep-propfield-hint {
5038
+ flex: 0 0 auto; width: 9px; text-align: center;
5039
+ grid-column: auto; font-size: 0.8em; opacity: 0.7;
5040
+ }
5041
+ .ds-247420 .ds-ep-vec3 .ds-input-bare {
5042
+ flex: 1 1 auto; min-width: 0; width: auto;
5043
+ padding: 2px 4px; text-align: center; text-overflow: clip;
5044
+ }
5045
+ /* Dense numeric inputs in the inspector — compact, tight radius, mono. */
5046
+ .ds-247420 .ds-ep-propfield-value input,
5047
+ .ds-247420 .ds-ep-propfield-value .ds-input-bare {
5048
+ padding: 2px 6px;
5049
+ border-radius: var(--r-1, 4px);
5050
+ font: var(--fs-tiny, 12px)/1.3 var(--ff-mono, monospace);
5051
+ }
5052
+ .ds-247420 .ds-input-bare {
5053
+ appearance: none;
5054
+ background: var(--panel-2);
5055
+ color: var(--panel-text);
5056
+ border: 1px solid var(--rule);
5057
+ border-radius: var(--r-1, 4px);
5058
+ padding: 2px 6px;
5059
+ font: var(--fs-tiny, 12px)/1.3 var(--ff-mono, monospace);
5060
+ min-width: 0;
5061
+ }
5062
+ .ds-247420 .ds-input-bare:focus { outline: none; border-color: var(--accent); }
5063
+ /* A property field whose control spans the full panel width (label above,
5064
+ control below) — used for wide segmented controls that would clip in the
5065
+ narrow value column. */
5066
+ .ds-247420 .ds-ep-propfield.block {
5067
+ display: flex; flex-direction: column; align-items: stretch; gap: 4px;
5068
+ }
5069
+ .ds-247420 .ds-ep-propfield.block > .ds-ep-propfield-value { width: 100%; }
5070
+ .ds-247420 .ds-ep-propfield.block .ds-ep-btngrp { width: 100%; }
5071
+ .ds-247420 .ds-ep-propfield.block .ds-ep-btngrp-btn { flex: 1 1 0; text-align: center; }
5072
+
5073
+ /* Flush dense action bar docked at a panel bottom (inspector Edit/Delete etc.).
5074
+ Compact buttons, square-ish, bordered top — not big floating pills. */
5075
+ .ds-247420 .ds-ep-actionbar {
5076
+ flex-shrink: 0;
5077
+ display: flex; align-items: center; gap: 6px;
5078
+ padding: 6px 8px;
5079
+ border-top: 1px solid var(--rule);
5080
+ background: var(--panel-1);
5081
+ }
5082
+ .ds-247420 .ds-ep-actionbar > * { flex: 1 1 0; }
5083
+ .ds-247420 .ds-ep-actionbar button {
5084
+ width: 100%;
5085
+ min-height: 28px; height: 28px; padding: 0 10px;
5086
+ border-radius: var(--r-1, 4px);
5087
+ font: var(--fs-tiny, 12px)/1 var(--ff-mono, monospace);
5088
+ }
5089
+
5090
+ /* Inline buttons inside a tree row (e.g. app-list Place) and the editor toolbars
5091
+ are compact — small, square-ish, not big pills. Excludes the segmented
5092
+ IconButtonGroup which manages its own sizing. */
5093
+ .ds-247420 .ds-ep-tree-row button:not(.ds-ep-btngrp-btn),
5094
+ .ds-247420 .ds-ep-toolbar button:not(.ds-ep-btngrp-btn) {
5095
+ min-height: 24px; height: 24px; padding: 0 8px;
5096
+ border-radius: var(--r-1, 4px);
5097
+ font: var(--fs-tiny, 12px)/1 var(--ff-mono, monospace);
5098
+ }
5099
+ @media (pointer: coarse) {
5100
+ .ds-247420 .ds-ep-tree-row button:not(.ds-ep-btngrp-btn),
5101
+ .ds-247420 .ds-ep-toolbar button:not(.ds-ep-btngrp-btn) { min-height: 36px; height: 36px; }
5102
+ }
4659
5103
 
4660
5104
  /* Dock — 3x3 grid for in-engine overlay (canvas pass-through center) */
4661
5105
  .ds-247420 .ds-ep-dock {
@@ -4765,7 +5209,7 @@
4765
5209
  color: var(--panel-text, var(--fg-text));
4766
5210
  border: 1px solid var(--rule);
4767
5211
  border-radius: var(--r-2, 8px);
4768
- box-shadow: 0 8px 28px rgba(0,0,0,0.18);
5212
+ box-shadow: var(--shadow-2);
4769
5213
  padding: 4px;
4770
5214
  display: flex; flex-direction: column;
4771
5215
  outline: none;
@@ -4782,7 +5226,7 @@
4782
5226
  .ds-247420 .ds-ep-ctxmenu-item:focus-visible {
4783
5227
  background: var(--panel-2, var(--rule));
4784
5228
  }
4785
- .ds-247420 .ds-ep-ctxmenu-item.danger { color: var(--danger, #c33); }
5229
+ .ds-247420 .ds-ep-ctxmenu-item.danger { color: var(--danger); }
4786
5230
  .ds-247420 .ds-ep-ctxmenu-item.disabled { opacity: 0.45; cursor: not-allowed; }
4787
5231
  .ds-247420 .ds-ep-ctxmenu-icon { width: 16px; display: inline-flex; justify-content: center; }
4788
5232
  .ds-247420 .ds-ep-ctxmenu-sep { height: 1px; background: var(--rule); margin: 4px 6px; }
@@ -4792,13 +5236,13 @@
4792
5236
  --------------------------------------------------------------- */
4793
5237
  .ds-247420 .ds-ep-drawer-backdrop {
4794
5238
  position: fixed; inset: 0; z-index: 8500;
4795
- background: rgba(0,0,0,0.42);
5239
+ background: var(--scrim);
4796
5240
  }
4797
5241
  .ds-247420 .ds-ep-drawer {
4798
5242
  position: absolute;
4799
5243
  background: var(--panel-1, var(--panel-bg));
4800
5244
  color: var(--panel-text, var(--fg-text));
4801
- box-shadow: 0 12px 40px rgba(0,0,0,0.28);
5245
+ box-shadow: var(--shadow-overlay);
4802
5246
  outline: none;
4803
5247
  transition: transform 180ms ease;
4804
5248
  padding: 12px;
@@ -4819,7 +5263,7 @@
4819
5263
  --------------------------------------------------------------- */
4820
5264
  .ds-247420 .ds-ep-dialog-backdrop {
4821
5265
  position: fixed; inset: 0; z-index: 9500;
4822
- background: rgba(0,0,0,0.5);
5266
+ background: var(--scrim-strong);
4823
5267
  display: flex; align-items: center; justify-content: center;
4824
5268
  padding: 16px;
4825
5269
  }
@@ -4828,7 +5272,7 @@
4828
5272
  color: var(--panel-text, var(--fg-text));
4829
5273
  border: 1px solid var(--rule);
4830
5274
  border-radius: var(--r-2, 10px);
4831
- box-shadow: 0 20px 60px rgba(0,0,0,0.36);
5275
+ box-shadow: var(--shadow-overlay);
4832
5276
  min-width: 280px; max-width: min(560px, 100%);
4833
5277
  max-height: 90vh; overflow: auto;
4834
5278
  display: flex; flex-direction: column;
@@ -4852,7 +5296,7 @@
4852
5296
  background: var(--accent); color: var(--accent-fg); border-color: var(--accent);
4853
5297
  }
4854
5298
  .ds-247420 .ds-ep-dialog-btn.kind-danger {
4855
- background: var(--danger, #c33); color: #fff; border-color: var(--danger, #c33);
5299
+ background: var(--danger); color: var(--on-accent); border-color: var(--danger);
4856
5300
  }
4857
5301
 
4858
5302
  /* ---------------------------------------------------------------
@@ -4874,14 +5318,14 @@
4874
5318
  border-left: 3px solid var(--accent);
4875
5319
  border-radius: var(--r-1, 6px);
4876
5320
  padding: 10px 14px;
4877
- box-shadow: 0 8px 24px rgba(0,0,0,0.22);
5321
+ box-shadow: var(--shadow-3);
4878
5322
  min-width: 220px; max-width: 360px;
4879
5323
  opacity: 1;
4880
5324
  transition: opacity 180ms ease, transform 180ms ease;
4881
5325
  }
4882
- .ds-247420 .ds-ep-toast.kind-success { border-left-color: var(--success, #2a8); }
4883
- .ds-247420 .ds-ep-toast.kind-warn { border-left-color: var(--warn, #d90); }
4884
- .ds-247420 .ds-ep-toast.kind-error { border-left-color: var(--danger, #c33); }
5326
+ .ds-247420 .ds-ep-toast.kind-success { border-left-color: var(--success); }
5327
+ .ds-247420 .ds-ep-toast.kind-warn { border-left-color: var(--warn); }
5328
+ .ds-247420 .ds-ep-toast.kind-error { border-left-color: var(--danger); }
4885
5329
  .ds-247420 .ds-ep-toast.leaving { opacity: 0; transform: translateY(-6px); }
4886
5330
  @media (max-width: 480px) {
4887
5331
  .ds-247420 .ds-ep-toast-host { left: 16px; right: 16px; align-items: center; }
@@ -5041,7 +5485,7 @@
5041
5485
  font-weight: 500;
5042
5486
  }
5043
5487
  .ds-247420 .ds-field-required {
5044
- color: var(--danger, oklch(0.55 0.18 25));
5488
+ color: var(--danger);
5045
5489
  font-weight: 700;
5046
5490
  margin-left: 2px;
5047
5491
  }
@@ -5050,12 +5494,12 @@
5050
5494
  font-size: var(--fs-tiny, 12px);
5051
5495
  }
5052
5496
  .ds-247420 .ds-field-error {
5053
- color: var(--danger, oklch(0.55 0.18 25));
5497
+ color: var(--danger);
5054
5498
  font-size: var(--fs-tiny, 12px);
5055
5499
  font-weight: 500;
5056
5500
  }
5057
5501
  .ds-247420 .ds-field-wrap [aria-invalid="true"] {
5058
- border-color: var(--danger, oklch(0.55 0.18 25)) !important;
5502
+ border-color: var(--danger) !important;
5059
5503
  }
5060
5504
 
5061
5505
  .ds-247420 .sr-only {
@@ -5083,10 +5527,10 @@
5083
5527
  font-size: 12px;
5084
5528
  line-height: 1.4;
5085
5529
  max-width: 280px;
5086
- box-shadow: 0 6px 18px rgba(0,0,0,0.22);
5530
+ box-shadow: var(--shadow-3);
5087
5531
  pointer-events: none;
5088
5532
  }
5089
- .ds-247420 .ds-tooltip.kind-danger { border-color: var(--danger, #c33); color: var(--danger, #c33); }
5533
+ .ds-247420 .ds-tooltip.kind-danger { border-color: var(--danger); color: var(--danger); }
5090
5534
  @media (prefers-reduced-motion: no-preference) {
5091
5535
  .ds-247420 .ds-tooltip { transition: opacity 120ms ease; }
5092
5536
  }
@@ -5102,7 +5546,7 @@
5102
5546
  color: var(--panel-text, var(--fg-text));
5103
5547
  border: 1px solid var(--rule);
5104
5548
  border-radius: var(--r-2, 8px);
5105
- box-shadow: 0 8px 28px rgba(0,0,0,0.22);
5549
+ box-shadow: var(--shadow-3);
5106
5550
  padding: 0;
5107
5551
  outline: none;
5108
5552
  min-width: 160px;
@@ -5139,7 +5583,7 @@
5139
5583
  pointer-events: none;
5140
5584
  cursor: not-allowed;
5141
5585
  }
5142
- .ds-247420 .ds-dropdown-item.is-danger { color: var(--danger, #c33); }
5586
+ .ds-247420 .ds-dropdown-item.is-danger { color: var(--danger); }
5143
5587
  .ds-247420 .ds-dropdown-glyph { width: 16px; display: inline-flex; justify-content: center; flex-shrink: 0; }
5144
5588
  .ds-247420 .ds-dropdown-label { flex: 1; min-width: 0; }
5145
5589
  .ds-247420 .ds-dropdown-separator { height: 1px; background: var(--rule); margin: 4px 6px; }
@@ -5219,7 +5663,7 @@
5219
5663
  background: var(--bg-2); color: var(--fg);
5220
5664
  border: 1px solid var(--rule);
5221
5665
  border-radius: var(--r-2, 14px);
5222
- box-shadow: var(--shadow-3, 0 12px 32px rgba(0,0,0,0.3));
5666
+ box-shadow: var(--shadow-3);
5223
5667
  overflow: hidden;
5224
5668
  }
5225
5669
  .ds-247420 .ov-cmd-input {
@@ -5267,7 +5711,7 @@
5267
5711
  background: var(--bg-2); color: var(--fg);
5268
5712
  border: 1px solid var(--rule);
5269
5713
  border-radius: var(--r-2, 14px);
5270
- box-shadow: var(--shadow-3, 0 12px 32px rgba(0,0,0,0.3));
5714
+ box-shadow: var(--shadow-3);
5271
5715
  outline: none; overflow: hidden;
5272
5716
  }
5273
5717
  .ds-247420 .ov-emoji-tabs {
@@ -5347,7 +5791,7 @@
5347
5791
  background: var(--bg-2); color: var(--fg);
5348
5792
  border: 1px solid var(--rule);
5349
5793
  border-radius: var(--r-2, 14px);
5350
- box-shadow: var(--shadow-3, 0 12px 32px rgba(0,0,0,0.3));
5794
+ box-shadow: var(--shadow-3);
5351
5795
  outline: none; overflow: hidden;
5352
5796
  }
5353
5797
  .ds-247420 .ov-set-head {
@@ -5392,14 +5836,14 @@
5392
5836
  .ds-247420 .ov-auth-backdrop {
5393
5837
  position: fixed; inset: 0; z-index: var(--z-overlay, 1000);
5394
5838
  display: flex; align-items: center; justify-content: center;
5395
- background: rgba(0,0,0,.55);
5839
+ background: var(--scrim-strong);
5396
5840
  }
5397
5841
  .ds-247420 .ov-auth-panel {
5398
5842
  width: min(420px, 92vw);
5399
5843
  display: flex; flex-direction: column;
5400
5844
  background: var(--bg-2); color: var(--fg);
5401
5845
  border: 1px solid var(--rule); border-radius: var(--r-2, 8px);
5402
- box-shadow: var(--shadow-2, 0 12px 40px rgba(0,0,0,.4));
5846
+ box-shadow: var(--shadow-overlay);
5403
5847
  overflow: hidden;
5404
5848
  }
5405
5849
  .ds-247420 .ov-auth-head { display: flex; align-items: center; justify-content: space-between; padding: var(--space-3); border-bottom: 1px solid var(--rule); }
@@ -5412,18 +5856,486 @@
5412
5856
  .ds-247420 .ov-auth-body { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-3); }
5413
5857
  .ds-247420 .ov-auth-hint { margin: 0; font-size: var(--fs-0, 12px); color: var(--fg-2, var(--fg)); }
5414
5858
  .ds-247420 .ov-auth-input { padding: var(--space-2); border: 1px solid var(--rule-strong); border-radius: var(--r-1); background: var(--bg-3); color: var(--fg); }
5415
- .ds-247420 .ov-auth-primary { padding: var(--space-2); border: none; border-radius: var(--r-1); background: var(--accent); color: var(--accent-fg, #fff); font-weight: 700; cursor: pointer; }
5859
+ .ds-247420 .ov-auth-primary { padding: var(--space-2); border: none; border-radius: var(--r-1); background: var(--accent); color: var(--on-accent); font-weight: 700; cursor: pointer; }
5416
5860
  .ds-247420 .ov-auth-primary:disabled { opacity: .6; cursor: progress; }
5417
- .ds-247420 .ov-auth-error { margin: 0 var(--space-3) var(--space-3); padding: var(--space-2); border-radius: var(--r-1); background: var(--danger-bg, rgba(208,69,69,.15)); color: var(--danger, #d04545); font-size: var(--fs-0, 12px); }
5861
+ .ds-247420 .ov-auth-error { margin: 0 var(--space-3) var(--space-3); padding: var(--space-2); border-radius: var(--r-1); background: color-mix(in oklab, var(--danger) 15%, transparent); color: var(--danger); font-size: var(--fs-0, 12px); }
5418
5862
 
5419
5863
  /* VideoLightbox — ov-lightbox-* */
5420
5864
  .ds-247420 .ov-lightbox-backdrop {
5421
5865
  position: fixed; inset: 0; z-index: var(--z-overlay-top, 1100);
5422
5866
  display: flex; align-items: center; justify-content: center;
5423
- background: rgba(0,0,0,.85);
5867
+ background: var(--scrim-media);
5424
5868
  }
5425
- .ds-247420 .ov-lightbox-x { position: absolute; top: 16px; right: 16px; width: 40px; height: 40px; border: none; border-radius: 50%; background: rgba(255,255,255,.12); color: #fff; font-size: 24px; line-height: 1; cursor: pointer; }
5426
- .ds-247420 .ov-lightbox-x:hover { background: rgba(255,255,255,.24); }
5869
+ .ds-247420 .ov-lightbox-x { position: absolute; top: 16px; right: 16px; width: 40px; height: 40px; border: none; border-radius: 50%; background: color-mix(in oklab, var(--on-color) 12%, transparent); color: var(--on-color); font-size: 24px; line-height: 1; cursor: pointer; }
5870
+ .ds-247420 .ov-lightbox-x:hover { background: color-mix(in oklab, var(--on-color) 24%, transparent); }
5427
5871
  .ds-247420 .ov-lightbox-stage { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); max-width: 92vw; max-height: 90vh; }
5428
- .ds-247420 .ov-lightbox-video { max-width: 92vw; max-height: 82vh; border-radius: var(--r-1); background: #000; }
5429
- .ds-247420 .ov-lightbox-label { color: #fff; font-size: var(--fs-0, 12px); opacity: .85; }
5872
+ .ds-247420 .ov-lightbox-video { max-width: 92vw; max-height: 82vh; border-radius: var(--r-1); background: #000; /* true black media letterbox, intentional */ }
5873
+ .ds-247420 .ov-lightbox-label { color: var(--on-color); font-size: var(--fs-0, 12px); opacity: .85; }
5874
+
5875
+ /* ---------------------------------------------------------------
5876
+ Editor-primitive scrollbars — thin, dark, themed so docked panels
5877
+ don't show a fat light OS scrollbar over the dark engine chrome.
5878
+ --------------------------------------------------------------- */
5879
+ .ds-247420 .ds-ep-panel,
5880
+ .ds-247420 .ds-ep-panel-body,
5881
+ .ds-247420 .ds-ep-tree,
5882
+ .ds-247420 .ds-ep-eventlog,
5883
+ .ds-247420 .ds-ep-drawer { scrollbar-width: thin; scrollbar-color: var(--rule) transparent; }
5884
+ .ds-247420 .ds-ep-panel ::-webkit-scrollbar,
5885
+ .ds-247420 .ds-ep-panel-body::-webkit-scrollbar,
5886
+ .ds-247420 .ds-ep-tree::-webkit-scrollbar,
5887
+ .ds-247420 .ds-ep-eventlog::-webkit-scrollbar { width: 8px; height: 8px; }
5888
+ .ds-247420 .ds-ep-panel ::-webkit-scrollbar-track,
5889
+ .ds-247420 .ds-ep-panel-body::-webkit-scrollbar-track,
5890
+ .ds-247420 .ds-ep-tree::-webkit-scrollbar-track,
5891
+ .ds-247420 .ds-ep-eventlog::-webkit-scrollbar-track { background: transparent; }
5892
+ .ds-247420 .ds-ep-panel ::-webkit-scrollbar-thumb,
5893
+ .ds-247420 .ds-ep-panel-body::-webkit-scrollbar-thumb,
5894
+ .ds-247420 .ds-ep-tree::-webkit-scrollbar-thumb,
5895
+ .ds-247420 .ds-ep-eventlog::-webkit-scrollbar-thumb {
5896
+ background: var(--rule); border-radius: var(--r-pill, 999px);
5897
+ border: 2px solid transparent; background-clip: padding-box;
5898
+ }
5899
+ .ds-247420 .ds-ep-panel ::-webkit-scrollbar-thumb:hover,
5900
+ .ds-247420 .ds-ep-panel-body::-webkit-scrollbar-thumb:hover {
5901
+ background: var(--panel-text-3, var(--rule)); background-clip: padding-box;
5902
+ }
5903
+
5904
+ /* ---------------------------------------------------------------
5905
+ Dense app-prop inputs — color swatch + checkbox sized to match the
5906
+ engine-editor density (raw browser controls otherwise read as jank).
5907
+ --------------------------------------------------------------- */
5908
+ /* Specificity bump (.ds-ep-propfield-value prefix) so the sized swatch/check win
5909
+ over the generic `.ds-ep-propfield-value input { width:100% }` rule — otherwise
5910
+ a color/checkbox app-prop stretches to the full field width and reads as jank. */
5911
+ .ds-247420 .ds-ep-propfield-value input.ds-input-color { width: 28px; flex: 0 0 auto; }
5912
+ .ds-247420 .ds-ep-propfield-value input.ds-input-check { width: 16px; flex: 0 0 auto; }
5913
+ .ds-247420 .ds-input-color {
5914
+ appearance: none; -webkit-appearance: none;
5915
+ width: 28px; height: 22px; padding: 0;
5916
+ border: 1px solid var(--rule); border-radius: var(--r-1, 4px);
5917
+ background: var(--panel-2); cursor: pointer; flex-shrink: 0;
5918
+ }
5919
+ .ds-247420 .ds-input-color::-webkit-color-swatch-wrapper { padding: 2px; }
5920
+ .ds-247420 .ds-input-color::-webkit-color-swatch { border: none; border-radius: 2px; }
5921
+ .ds-247420 .ds-input-color:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
5922
+ .ds-247420 .ds-input-check {
5923
+ appearance: none; -webkit-appearance: none;
5924
+ width: 16px; height: 16px; flex-shrink: 0;
5925
+ border: 1px solid var(--rule); border-radius: var(--r-1, 4px);
5926
+ background: var(--panel-2); cursor: pointer; position: relative;
5927
+ }
5928
+ .ds-247420 .ds-input-check:checked { background: var(--accent); border-color: var(--accent); }
5929
+ .ds-247420 .ds-input-check:checked::after {
5930
+ content: ''; position: absolute; left: 4px; top: 1px;
5931
+ width: 4px; height: 8px; border: solid var(--accent-fg, #fff);
5932
+ border-width: 0 2px 2px 0; transform: rotate(45deg);
5933
+ }
5934
+ .ds-247420 .ds-input-check:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
5935
+
5936
+ /* ---------------------------------------------------------------
5937
+ Tree drag-reparent affordance — clear drop target + dragging row.
5938
+ useDropTarget marks the active row with [data-drop-target-active]; the
5939
+ dragged source carries [data-dragging]. Both surfaced as visible state so a
5940
+ reparent drag shows exactly where it will land.
5941
+ --------------------------------------------------------------- */
5942
+ .ds-247420 .ds-ep-tree-item[data-drop-target-active] > .ds-ep-tree-row,
5943
+ .ds-247420 .ds-ep-tree-row[data-drop-target-active],
5944
+ .ds-247420 .ds-ep-tree-row.drag-over {
5945
+ background: color-mix(in oklab, var(--accent) 22%, transparent);
5946
+ box-shadow: inset 0 0 0 1px var(--accent);
5947
+ }
5948
+ .ds-247420 .ds-ep-panel-body[data-drop-target-active] {
5949
+ box-shadow: inset 0 0 0 2px color-mix(in oklab, var(--accent) 50%, transparent);
5950
+ }
5951
+ .ds-247420 .ds-ep-tree-item[data-dragging] > .ds-ep-tree-row,
5952
+ .ds-247420 .ds-ep-tree-item.dragging > .ds-ep-tree-row { opacity: 0.5; }
5953
+
5954
+ /* ---------------------------------------------------------------
5955
+ Floating editor docks — the non-occluding idiom. The game/3D
5956
+ viewport fills the whole editor stage; the hierarchy + inspector
5957
+ ride over it as translucent, backdrop-blurred, collapsible cards
5958
+ so the play area stays visible (and clickable) behind them. The
5959
+ dock layer is pointer-events:none; only the dock cards capture
5960
+ input, so the exposed viewport gutter clicks through to the canvas.
5961
+ --------------------------------------------------------------- */
5962
+ .ds-247420 .ds-ep-stage { position: relative; flex: 1; min-height: 0; overflow: hidden; }
5963
+ .ds-247420 .ds-ep-dock-layer { display: block; }
5964
+ .ds-247420 .ds-ep-dock {
5965
+ position: absolute; top: 8px; bottom: 8px;
5966
+ display: flex; flex-direction: column;
5967
+ width: 280px; max-width: calc(50% - 12px);
5968
+ pointer-events: all;
5969
+ background: color-mix(in oklab, var(--panel-1) 82%, transparent);
5970
+ -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
5971
+ border: 1px solid var(--rule);
5972
+ border-radius: var(--r-2, 8px);
5973
+ box-shadow: 0 6px 24px color-mix(in oklab, #000 28%, transparent);
5974
+ color: var(--panel-text);
5975
+ overflow: hidden;
5976
+ }
5977
+ .ds-247420 .ds-ep-dock-left { left: 8px; }
5978
+ .ds-247420 .ds-ep-dock-right { right: 8px; }
5979
+ /* Collapsed: shrink to just the header strip, freeing the viewport. */
5980
+ .ds-247420 .ds-ep-dock.collapsed { bottom: auto; height: auto; }
5981
+ .ds-247420 .ds-ep-dock-head {
5982
+ display: flex; align-items: center; gap: 6px;
5983
+ flex: 0 0 auto; padding: 4px 6px 4px 10px;
5984
+ border-bottom: 1px solid var(--rule);
5985
+ background: color-mix(in oklab, var(--panel-1) 60%, transparent);
5986
+ }
5987
+ .ds-247420 .ds-ep-dock.collapsed .ds-ep-dock-head { border-bottom: 0; }
5988
+ .ds-247420 .ds-ep-dock-title {
5989
+ flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
5990
+ font: 8px/1 var(--ff-mono, monospace); text-transform: uppercase; letter-spacing: 0.12em;
5991
+ color: var(--panel-text-3);
5992
+ }
5993
+ .ds-247420 .ds-ep-dock-body { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; background: transparent; }
5994
+ .ds-247420 .ds-ep-dock-body.hidden { display: none; }
5995
+ /* The right dock's body reuses .ds-ep-panel but must stay transparent so the
5996
+ dock's own translucency/blur shows the game view through. */
5997
+ .ds-247420 .ds-ep-dock-body.ds-ep-panel { background: transparent; }
5998
+
5999
+ /* Mobile: docks become full-width bottom-anchored sheets so they don't crowd
6000
+ the narrow viewport side-by-side; the viewport still fills the stage behind. */
6001
+ @media (max-width: 760px) {
6002
+ .ds-247420 .ds-ep-dock { width: auto; max-width: none; left: 6px; right: 6px; top: auto; bottom: 6px; max-height: 46vh; }
6003
+ .ds-247420 .ds-ep-dock-left { bottom: calc(46vh + 12px); max-height: 40vh; }
6004
+ .ds-247420 .ds-ep-dock.collapsed { bottom: auto; }
6005
+ .ds-247420 .ds-ep-dock-left.collapsed { top: 6px; bottom: auto; }
6006
+ }
6007
+
6008
+ /* community-app.css */
6009
+ /* community-app.css — layout glue for mountCommunityApp (the full chat/community
6010
+ app GUI). Reuses the canonical app/body/main classes from app-shell.css and
6011
+ the community + voice component classes from community.css; this part only adds
6012
+ the app-composition wrapper, the server+channel rail pills, the voice view grid,
6013
+ and the category-color tokens the consumer avatars use. All scoped under
6014
+ .ds-247420. Additive — defines only the ca- prefix, group, rail-empty, vx-view
6015
+ classes plus the cat color tokens. */
6016
+
6017
+ .ds-247420.ds-247420 .ca-app {
6018
+ display: flex;
6019
+ flex-direction: column;
6020
+ height: 100vh;
6021
+ min-height: 0;
6022
+ overflow: hidden;
6023
+ }
6024
+ .ds-247420.ds-247420 .ca-app > .app-body {
6025
+ display: flex;
6026
+ flex-direction: row;
6027
+ flex: 1;
6028
+ min-height: 0;
6029
+ overflow: hidden;
6030
+ }
6031
+ .ds-247420.ds-247420 .ca-app > .app-body > .app-main {
6032
+ display: flex;
6033
+ flex-direction: column;
6034
+ flex: 1;
6035
+ min-width: 0;
6036
+ min-height: 0;
6037
+ overflow: hidden;
6038
+ padding: 0;
6039
+ }
6040
+
6041
+ /* server + channel rail */
6042
+ .ds-247420.ds-247420 .ca-rail {
6043
+ display: flex;
6044
+ flex-direction: column;
6045
+ gap: 2px;
6046
+ width: 220px;
6047
+ min-width: 220px;
6048
+ padding: 8px;
6049
+ overflow-y: auto;
6050
+ overflow-x: hidden;
6051
+ background: var(--bg-2, color-mix(in oklab, var(--bg) 92%, var(--fg)));
6052
+ scrollbar-width: thin;
6053
+ }
6054
+ .ds-247420.ds-247420 .ca-rail .group {
6055
+ font-size: 11px;
6056
+ font-weight: 600;
6057
+ letter-spacing: 0.04em;
6058
+ text-transform: uppercase;
6059
+ color: var(--fg-3, color-mix(in oklab, var(--fg) 55%, transparent));
6060
+ padding: 10px 8px 4px;
6061
+ }
6062
+ .ds-247420.ds-247420 .ca-rail a {
6063
+ display: flex;
6064
+ align-items: center;
6065
+ gap: 8px;
6066
+ padding: 6px 8px;
6067
+ border-radius: 6px;
6068
+ color: var(--fg-2, color-mix(in oklab, var(--fg) 78%, transparent));
6069
+ text-decoration: none;
6070
+ font-size: var(--fs-sm, 14px);
6071
+ line-height: 1.2;
6072
+ transition: background 0.1s, color 0.1s;
6073
+ }
6074
+ .ds-247420.ds-247420 .ca-rail a:hover { background: color-mix(in oklab, var(--fg) 8%, transparent); color: var(--fg); }
6075
+ .ds-247420.ds-247420 .ca-rail a.active { background: color-mix(in oklab, var(--accent) 22%, transparent); color: var(--fg); }
6076
+ .ds-247420.ds-247420 .ca-rail a .glyph {
6077
+ display: inline-flex;
6078
+ align-items: center;
6079
+ justify-content: center;
6080
+ width: 18px;
6081
+ flex-shrink: 0;
6082
+ color: var(--fg-3, currentColor);
6083
+ }
6084
+ .ds-247420.ds-247420 .ca-rail a > span:nth-child(2) { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
6085
+ .ds-247420.ds-247420 .ca-rail a .count {
6086
+ flex-shrink: 0;
6087
+ min-width: 18px;
6088
+ padding: 0 5px;
6089
+ border-radius: 9px;
6090
+ background: var(--accent);
6091
+ color: var(--on-accent);
6092
+ font-size: 11px;
6093
+ font-weight: 600;
6094
+ text-align: center;
6095
+ }
6096
+ .ds-247420.ds-247420 .ca-rail .rail-empty {
6097
+ padding: 8px;
6098
+ color: var(--fg-3, color-mix(in oklab, var(--fg) 50%, transparent));
6099
+ font-size: var(--fs-sm, 14px);
6100
+ font-style: italic;
6101
+ }
6102
+
6103
+ /* voice channel view */
6104
+ .ds-247420.ds-247420 .vx-view {
6105
+ display: flex;
6106
+ flex-direction: column;
6107
+ flex: 1;
6108
+ min-height: 0;
6109
+ overflow: hidden;
6110
+ }
6111
+ .ds-247420.ds-247420 .vx-view .vx-grid {
6112
+ display: grid;
6113
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
6114
+ gap: 12px;
6115
+ flex: 1;
6116
+ min-height: 0;
6117
+ padding: 16px;
6118
+ overflow-y: auto;
6119
+ align-content: start;
6120
+ }
6121
+
6122
+ /* spoint/loading-screen.css */
6123
+ /* Loading-screen kit styles. Scoped under .ds-247420 at build time.
6124
+ All colors reference design tokens (no raw literals) per the token-lint gate. */
6125
+ .ds-247420 .sp-loading {
6126
+ position: fixed;
6127
+ inset: 0;
6128
+ z-index: 10000;
6129
+ display: flex;
6130
+ align-items: center;
6131
+ justify-content: center;
6132
+ background: var(--bg);
6133
+ color: var(--fg);
6134
+ font-family: var(--ff-mono);
6135
+ transition: opacity var(--dur-slow) var(--ease);
6136
+ }
6137
+ .ds-247420 .sp-loading-fade { opacity: 0; pointer-events: none; }
6138
+ .ds-247420 .sp-loading-container {
6139
+ width: min(420px, 86vw);
6140
+ display: flex;
6141
+ flex-direction: column;
6142
+ gap: 20px;
6143
+ }
6144
+ .ds-247420 .sp-loading-header h1 {
6145
+ margin: 0;
6146
+ font-family: var(--ff-display);
6147
+ font-size: var(--fs-h2);
6148
+ letter-spacing: 0.04em;
6149
+ }
6150
+ .ds-247420 .sp-loading-label {
6151
+ margin: 4px 0 0;
6152
+ color: var(--fg-2);
6153
+ font-size: var(--fs-body);
6154
+ }
6155
+ .ds-247420 .sp-loading-bars { display: flex; flex-direction: column; gap: 10px; }
6156
+ .ds-247420 .sp-loading-bar-row {
6157
+ display: grid;
6158
+ grid-template-columns: 88px 1fr 44px;
6159
+ align-items: center;
6160
+ gap: 10px;
6161
+ }
6162
+ .ds-247420 .sp-loading-bar-name {
6163
+ color: var(--fg-3);
6164
+ font-size: var(--fs-small, 11px);
6165
+ text-transform: uppercase;
6166
+ letter-spacing: 0.1em;
6167
+ }
6168
+ .ds-247420 .sp-loading-bar-track {
6169
+ height: 6px;
6170
+ border-radius: 3px;
6171
+ background: var(--bg-3);
6172
+ overflow: hidden;
6173
+ }
6174
+ .ds-247420 .sp-loading-bar-fill {
6175
+ height: 100%;
6176
+ width: 0%;
6177
+ background: var(--accent);
6178
+ transition: width var(--dur-base) var(--ease);
6179
+ }
6180
+ .ds-247420 .sp-loading-bar-pct {
6181
+ color: var(--fg-2);
6182
+ font-size: var(--fs-small, 11px);
6183
+ text-align: right;
6184
+ }
6185
+ .ds-247420 .sp-loading-detail {
6186
+ min-height: 16px;
6187
+ color: var(--fg-3);
6188
+ font-size: var(--fs-small, 11px);
6189
+ }
6190
+
6191
+ /* spoint/game-hud.css */
6192
+ /* Game-HUD kit styles. Scoped under .ds-247420 at build time.
6193
+ Colors from semantic tokens (no raw literals) per the token-lint gate. */
6194
+ .ds-247420 .sp-hud { pointer-events: none; font-family: var(--ff-mono); }
6195
+ .ds-247420 .sp-hud-crosshair {
6196
+ position: fixed;
6197
+ top: 50%;
6198
+ left: 50%;
6199
+ transform: translate(-50%, -50%);
6200
+ font-size: 24px;
6201
+ color: var(--fg);
6202
+ text-shadow: 0 0 2px var(--bg);
6203
+ }
6204
+ .ds-247420 .sp-hud-ammo {
6205
+ position: fixed;
6206
+ bottom: 50px;
6207
+ right: 20px;
6208
+ font-size: 24px;
6209
+ font-weight: bold;
6210
+ color: var(--fg);
6211
+ text-shadow: 0 0 4px var(--bg);
6212
+ }
6213
+ .ds-247420 .sp-hud-ammo-reloading { color: var(--warn); }
6214
+ .ds-247420 .sp-hud-health {
6215
+ position: fixed;
6216
+ bottom: 20px;
6217
+ left: 50%;
6218
+ transform: translateX(-50%);
6219
+ width: 200px;
6220
+ height: 20px;
6221
+ background: var(--bg-3);
6222
+ border-radius: 4px;
6223
+ overflow: hidden;
6224
+ }
6225
+ .ds-247420 .sp-hud-health-fill {
6226
+ height: 100%;
6227
+ transition: width var(--dur-snap) var(--ease);
6228
+ }
6229
+ .ds-247420 .sp-hud-hp-high { background: var(--success); }
6230
+ .ds-247420 .sp-hud-hp-mid { background: var(--warn); }
6231
+ .ds-247420 .sp-hud-hp-low { background: var(--danger); }
6232
+ .ds-247420 .sp-hud-health-num {
6233
+ position: absolute;
6234
+ width: 100%;
6235
+ text-align: center;
6236
+ color: var(--fg);
6237
+ font-size: 12px;
6238
+ line-height: 20px;
6239
+ }
6240
+ .ds-247420 .sp-hud-boost {
6241
+ position: fixed;
6242
+ top: 80px;
6243
+ right: 20px;
6244
+ padding: 8px 16px;
6245
+ background: var(--accent);
6246
+ color: var(--accent-fg);
6247
+ font-weight: bold;
6248
+ border-radius: 6px;
6249
+ font-size: 14px;
6250
+ }
6251
+
6252
+ /* spoint/host-join-lobby.css */
6253
+ /* Host/join lobby kit styles. Scoped under .ds-247420 at build time.
6254
+ Token-only colors (no raw literals) per the token-lint gate. */
6255
+ .ds-247420 .sp-lobby {
6256
+ position: fixed;
6257
+ inset: 0;
6258
+ z-index: 9500;
6259
+ display: flex;
6260
+ align-items: center;
6261
+ justify-content: center;
6262
+ background: color-mix(in srgb, var(--bg) 70%, transparent);
6263
+ font-family: var(--ff-mono);
6264
+ }
6265
+ .ds-247420 .sp-lobby-card {
6266
+ position: relative;
6267
+ width: min(360px, 88vw);
6268
+ display: flex;
6269
+ flex-direction: column;
6270
+ gap: 12px;
6271
+ padding: 24px;
6272
+ background: var(--bg-2);
6273
+ border: 1px solid var(--bw-rule, var(--rule));
6274
+ border-radius: var(--r-2, 10px);
6275
+ color: var(--fg);
6276
+ }
6277
+ .ds-247420 .sp-lobby-title {
6278
+ margin: 0;
6279
+ font-family: var(--ff-display);
6280
+ font-size: var(--fs-h3);
6281
+ }
6282
+ .ds-247420 .sp-lobby-sub {
6283
+ margin: 0;
6284
+ color: var(--fg-3);
6285
+ font-size: var(--fs-small, 12px);
6286
+ }
6287
+ .ds-247420 .sp-lobby-btn {
6288
+ appearance: none;
6289
+ border: 1px solid var(--bw-rule, var(--rule));
6290
+ background: var(--bg-3);
6291
+ color: var(--fg);
6292
+ font-family: var(--ff-mono);
6293
+ font-size: var(--fs-body);
6294
+ padding: 10px 14px;
6295
+ border-radius: var(--r-1, 6px);
6296
+ cursor: pointer;
6297
+ }
6298
+ .ds-247420 .sp-lobby-btn:hover { background: var(--bg-2); }
6299
+ .ds-247420 .sp-lobby-btn:disabled { opacity: 0.6; cursor: default; }
6300
+ .ds-247420 .sp-lobby-btn-primary {
6301
+ background: var(--accent);
6302
+ color: var(--accent-fg);
6303
+ border-color: var(--accent);
6304
+ }
6305
+ .ds-247420 .sp-lobby-join { display: flex; gap: 8px; }
6306
+ .ds-247420 .sp-lobby-input {
6307
+ flex: 1;
6308
+ min-width: 0;
6309
+ background: var(--bg);
6310
+ color: var(--fg);
6311
+ border: 1px solid var(--bw-rule, var(--rule));
6312
+ border-radius: var(--r-1, 6px);
6313
+ padding: 8px 10px;
6314
+ font: var(--fs-body) var(--ff-mono);
6315
+ outline: none;
6316
+ }
6317
+ .ds-247420 .sp-lobby-input:focus { border-color: var(--accent); }
6318
+ .ds-247420 .sp-lobby-link { font-size: var(--fs-small, 11px); }
6319
+ .ds-247420 .sp-lobby-code {
6320
+ font-family: var(--ff-display);
6321
+ font-size: var(--fs-h2);
6322
+ letter-spacing: 0.12em;
6323
+ text-align: center;
6324
+ color: var(--accent);
6325
+ padding: 8px;
6326
+ background: var(--bg);
6327
+ border-radius: var(--r-1, 6px);
6328
+ }
6329
+ .ds-247420 .sp-lobby-err { min-height: 16px; color: var(--danger); font-size: var(--fs-small, 11px); }
6330
+ .ds-247420 .sp-lobby-close {
6331
+ position: absolute;
6332
+ top: 10px;
6333
+ right: 12px;
6334
+ appearance: none;
6335
+ background: none;
6336
+ border: none;
6337
+ color: var(--fg-3);
6338
+ font-size: 16px;
6339
+ cursor: pointer;
6340
+ line-height: 1;
6341
+ }