anentrypoint-design 0.0.280 → 0.0.281

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -52,7 +52,7 @@ mount(document.getElementById('app'), () => C.AppShell({
52
52
  - **chrome** — `Topbar`, `Crumb`, `Side`, `Status`, `AppShell`, `Brand`, `Chip`, `Btn`, `Glyph`, `Heading`, `Lede`
53
53
  - **content** — `Panel`, `Row`, `RowLink`, `Hero`, `Install`, `Receipt`, `Changelog`, `WorksList`, `WritingList`, `Manifesto`, `Section`, `Kpi`, `Table`, `HomeView`, `ProjectView`
54
54
  - **chat** — `Chat`, `ChatMessage`, `ChatComposer`, `AICat`, `AICatPortrait`
55
- - **multi-agent chat shell** — `WorkspaceShell`, `WorkspaceRail`, `ConversationList`, `AgentChat`, `SessionDashboard` — the flagship desktop-class chat-agent product surface (persistent rail + resizable columns + full turn/tool-call thread + live multi-session dashboard). See `COMPONENT_API.md` for the full prop contract; the canonical real-world wiring ships at [`agentgui`](https://github.com/AnEntrypoint/agentgui).
55
+ - **multi-agent chat shell** — `WorkspaceShell`, `WorkspaceRail`, `ConversationList`, `AgentChat`, `SessionDashboard` — the flagship desktop-class chat-agent product surface (persistent rail + resizable columns + full turn/tool-call thread + live multi-session dashboard). See `COMPONENT_API.md` for the full prop contract; a runnable mock-data demo lives at `ui_kits/workspace/`; the canonical real-world wiring ships at [`agentgui`](https://github.com/AnEntrypoint/agentgui).
56
56
  - **file browser** — `FileRow`, `FileGrid`, `FileToolbar`, `FileIcon`, `DropZone`, `UploadProgress`, `EmptyState`, `BreadcrumbPath`, plus modal pieces `FileViewer`, `FilePreviewMedia`, `FilePreviewCode`, `FilePreviewText`, `ConfirmDialog`, `PromptDialog`
57
57
  - **ui_kits** — `homepage`, `project_page`, `docs`, `blog`, `chat`, `aicat`, `file_browser`. Each is a fully-working buildless example loading the SDK from this repo.
58
58
 
package/app-shell.css CHANGED
@@ -148,7 +148,7 @@ pre {
148
148
  pre .k { color: var(--code-str-alt, var(--mascot)); }
149
149
  pre .s { color: var(--code-string, var(--green)); }
150
150
  pre .c { color: var(--fg-3); }
151
- pre .n { color: var(--green-2); }
151
+ pre .n { color: var(--code-num); }
152
152
 
153
153
  /* ============================================================
154
154
  AppShell — page frame. The topbar floats above a soft background;
@@ -427,6 +427,19 @@ body.canvas-host { background: transparent !important; }
427
427
  .app-status .item:last-of-type:not(:only-of-type) { display: none; }
428
428
  }
429
429
 
430
+ /* The "dateline" — ASCII bar used at the top of every preview/brand page.
431
+ 3-4 flex slots; a .spread filler pushes the trailing slot to the far
432
+ edge instead of every span running together with no gap. */
433
+ .dateline {
434
+ display: flex; align-items: center; gap: var(--space-3);
435
+ flex-wrap: nowrap; overflow: hidden;
436
+ font-family: var(--ff-mono); font-size: var(--fs-xs); line-height: 1.2;
437
+ letter-spacing: 0.02em;
438
+ color: var(--fg-3);
439
+ }
440
+ .dateline span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
441
+ .dateline .spread { flex: 1 1 auto; min-width: var(--space-3); }
442
+
430
443
  /* ============================================================
431
444
  Primitives
432
445
  ============================================================ */
@@ -457,15 +470,15 @@ body.canvas-host { background: transparent !important; }
457
470
  an ink block with the lead as text, a confident two-tone flip. */
458
471
  .btn-primary {
459
472
  background: var(--accent); color: var(--accent-fg);
460
- font-weight: 700; letter-spacing: var(--tr-caps);
473
+ font-weight: 700;
461
474
  }
462
475
  .btn-primary:hover { background: var(--fg); color: var(--accent-ink); transform: translateY(-1px); box-shadow: var(--shadow-2); }
463
476
  .btn-ghost { background: transparent; color: var(--fg); box-shadow: inset 0 0 0 2px var(--fg); }
464
477
  .btn-ghost:hover { background: var(--fg); color: var(--bg); transform: translateY(-1px); }
465
478
  .btn:active, .btn-primary:active, .btn-ghost:active { transform: translateY(1px); box-shadow: none; }
466
479
  .btn:focus-visible, .btn-primary:focus-visible, .btn-ghost:focus-visible, .ds-icon-btn:focus-visible {
467
- outline: 2px solid var(--accent-ink);
468
- outline-offset: 2px;
480
+ outline: var(--focus-w) solid var(--focus-color);
481
+ outline-offset: var(--focus-offset);
469
482
  }
470
483
 
471
484
  /* ============================================================
@@ -484,12 +497,12 @@ body.canvas-host { background: transparent !important; }
484
497
  .ds-icon-btn-lg { width: 40px; height: 40px; }
485
498
  .ds-icon-btn-xl { width: 48px; height: 48px; }
486
499
  .ds-icon-btn-ghost { background: transparent; }
487
- .ds-icon-btn-ghost:hover { background: var(--bg-2); }
500
+ .ds-icon-btn-ghost:hover { background: var(--fg); color: var(--bg); }
488
501
  .ds-icon-btn-primary { background: var(--accent); color: var(--accent-fg); }
489
502
  .ds-icon-btn-primary:hover { background: var(--fg); color: var(--bg); }
490
503
  /* warn = destructive ACTION tone; flame stays exclusively error STATUS. */
491
504
  .ds-icon-btn-danger { background: var(--warn); color: var(--on-color); }
492
- .ds-icon-btn-danger:hover { filter: brightness(1.1); }
505
+ .ds-icon-btn-danger:hover { filter: brightness(0.92); }
493
506
  .ds-icon-btn:active { transform: translateY(1px); }
494
507
  .ds-icon-btn:disabled, .ds-icon-btn.is-disabled {
495
508
  opacity: 0.5; cursor: not-allowed; pointer-events: none;
@@ -639,7 +652,7 @@ body.canvas-host { background: transparent !important; }
639
652
  white-space: pre-wrap;
640
653
  font-family: var(--ff-mono);
641
654
  font-size: var(--fs-sm);
642
- line-height: var(--lh-snug, 1.3);
655
+ line-height: var(--lh-snug);
643
656
  margin-top: 8px;
644
657
  padding: 10px 12px;
645
658
  background: var(--bg);
@@ -695,7 +708,7 @@ a.row:hover .meta, .row[role="button"]:hover .meta { color: var(--accent-ink); t
695
708
  .row.row-nocode { grid-template-columns: minmax(0, 1fr) auto; }
696
709
 
697
710
  .row .code { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); font-variant-numeric: tabular-nums; letter-spacing: 0.01em; }
698
- .row .title { font-family: var(--ff-body); font-weight: 600; font-size: var(--fs-lg); line-height: var(--lh-snug, 1.3); display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; }
711
+ .row .title { font-family: var(--ff-body); font-weight: 600; font-size: var(--fs-lg); line-height: var(--lh-snug); display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; }
699
712
  .row .title .sub { font-family: var(--ff-body); font-weight: 400; font-size: var(--fs-sm); color: var(--fg-3); }
700
713
  /* App typescale: list rows are quiet working chrome (the 18px/600 default is a
701
714
  marketing-surface voice). One size for ALL app list rows - matches
@@ -1139,6 +1152,10 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1139
1152
  flex: 1 1 100%; margin-left: 0; order: 3; min-width: 0; max-width: 100%;
1140
1153
  display: flex; gap: 2px; flex-wrap: nowrap;
1141
1154
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
1155
+ /* Fade the trailing edge so a clipped last item (e.g. "source ->" cut to
1156
+ "sour") reads as scrollable content, not a broken/truncated label. */
1157
+ mask-image: linear-gradient(90deg, var(--fg) 0 calc(100% - 28px), transparent 100%);
1158
+ -webkit-mask-image: linear-gradient(90deg, var(--fg) 0 calc(100% - 28px), transparent 100%);
1142
1159
  }
1143
1160
  .app-topbar nav::-webkit-scrollbar { display: none; }
1144
1161
  .app-topbar nav a {
@@ -1495,6 +1512,12 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1495
1512
  .ds-file-row .ds-file-meta {
1496
1513
  font-family: var(--ff-mono); font-size: var(--fs-xs);
1497
1514
  color: var(--fg-3); white-space: nowrap;
1515
+ /* Never shrink below content: a flex sibling with white-space:nowrap and
1516
+ the default flex-shrink:1 silently overflows its own box (no ellipsis)
1517
+ when the row runs out of width, painting the date/size over the title
1518
+ and action icons at mobile widths. Fixed-size the meta column instead
1519
+ and let .title (flex:1, min-width:0, ellipsis) absorb the squeeze. */
1520
+ flex-shrink: 0;
1498
1521
  }
1499
1522
 
1500
1523
  /* File icon — glyph chip, tinted per type. */
@@ -1964,6 +1987,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
1964
1987
  border-color: var(--warn);
1965
1988
  color: var(--on-color);
1966
1989
  }
1990
+ .btn-primary.danger:hover { filter: brightness(0.92); border-color: var(--warn); }
1967
1991
 
1968
1992
  /* -- Preview ------------------------------------------------ */
1969
1993
  .ds-preview-head {
@@ -2773,6 +2797,14 @@ input[type="checkbox"], input[type="radio"] {
2773
2797
  transform var(--dur-snap) var(--ease);
2774
2798
  }
2775
2799
 
2800
+ /* Native checkbox/radio tint — browser default is UA blue, which fights the
2801
+ single lime lead accent wherever a raw control lands outside a bespoke
2802
+ toggle (e.g. signin's "remember me"). accent-color re-tints the native
2803
+ control box without hand-drawing a replacement. */
2804
+ input[type="checkbox"], input[type="radio"] {
2805
+ accent-color: var(--accent-ink);
2806
+ }
2807
+
2776
2808
  /* Prevent double-tap zoom on buttons (iOS) */
2777
2809
  .btn, .btn-primary, .btn-ghost, button {
2778
2810
  -webkit-user-select: none;
@@ -2936,6 +2968,35 @@ textarea::placeholder {
2936
2968
  color: var(--fg-3);
2937
2969
  }
2938
2970
 
2971
+ /* Structural hairlines — "no boxes, no cards, structure comes from rules."
2972
+ Three weights: .rule (default separator), .rule-double (major section
2973
+ break), .rule-dotted (optional/skippable). Applied to a bare <hr>, which
2974
+ otherwise falls back to the browser's default inset groove line. */
2975
+ hr.rule, hr.rule-double, hr.rule-dotted {
2976
+ width: 100%; height: 0; border: 0;
2977
+ }
2978
+ hr.rule { border-top: 1px solid var(--rule); }
2979
+ hr.rule-double { border-top: 3px double var(--rule-strong); }
2980
+ hr.rule-dotted { border-top: 1px dotted var(--rule-strong); }
2981
+
2982
+ /* Hairline-only text input — no box, no fill. A single bottom rule that
2983
+ thickens to 2px on focus, matching the row/rule zero-border aesthetic
2984
+ instead of a browser-default boxed field. */
2985
+ .input {
2986
+ display: block; width: 100%; box-sizing: border-box;
2987
+ border: 0; border-bottom: 1px solid var(--rule-strong);
2988
+ border-radius: var(--r-0);
2989
+ background: transparent;
2990
+ padding: var(--space-2) var(--space-1);
2991
+ font: inherit; color: var(--fg);
2992
+ }
2993
+ .input::placeholder { color: var(--fg-3); }
2994
+ .input:focus-visible {
2995
+ outline: none;
2996
+ border-bottom-width: 2px;
2997
+ border-bottom-color: var(--accent-ink);
2998
+ }
2999
+
2939
3000
  /* -- Field controls: themed base for TextField / Select / SearchInput --
2940
3001
  Root fix: previously only `transition` was set, so themed apps got
2941
3002
  browser-default white boxes in dark mode and labels collided with inputs
@@ -439,7 +439,7 @@ select:focus-visible {
439
439
  --fg: var(--ink); --fg-2: var(--ink-2); --fg-3: var(--ink-3);
440
440
  --accent: var(--acid); --accent-fg: var(--ink); --accent-ink: var(--acid-deep);
441
441
  /* A paper island under a dark ancestor must not inherit the dark signal pair. */
442
- --flame: #C53E00; --amber: #8A6512; --warn: #E0241A; --sky: #3A6EFF;
442
+ --flame: #C53E00; --amber: #7C570F; --warn: #E0241A; --sky: #3A6EFF;
443
443
  }
444
444
 
445
445
  /* thebird — warm-paper brand preset. A first-class swappable theme: it lives
package/community.css CHANGED
@@ -353,9 +353,9 @@
353
353
  }
354
354
 
355
355
  .cm-channel-item.voice-active {
356
- color: var(--green-2);
356
+ color: var(--green);
357
357
  }
358
- .cm-channel-item.voice-active .cm-ch-icon { color: var(--green-2); }
358
+ .cm-channel-item.voice-active .cm-ch-icon { color: var(--green); }
359
359
  .cm-channel-item.voice-active:hover {
360
360
  background: color-mix(in oklab, var(--green) 12%, transparent);
361
361
  }
@@ -401,7 +401,7 @@
401
401
  }
402
402
 
403
403
  .cm-ch-icon.voice-active-badge {
404
- color: var(--green-2);
404
+ color: var(--green);
405
405
  text-shadow: 0 0 8px var(--green-2);
406
406
  }
407
407
 
@@ -508,7 +508,7 @@
508
508
  color: var(--fg);
509
509
  }
510
510
  .cm-ch-voice-user.speaking {
511
- color: var(--green-2);
511
+ color: var(--green);
512
512
  }
513
513
  .cm-ch-voice-user.speaking .cm-ch-voice-user-avatar {
514
514
  box-shadow: 0 0 0 2px var(--green-2);
@@ -564,7 +564,7 @@
564
564
  font-size: var(--fs-micro);
565
565
  text-transform: uppercase;
566
566
  letter-spacing: var(--tr-caps);
567
- color: var(--green-2);
567
+ color: var(--green);
568
568
  font-weight: 700;
569
569
  display: inline-flex;
570
570
  align-items: center;
package/dist/247420.css CHANGED
@@ -441,7 +441,7 @@
441
441
  --fg: var(--ink); --fg-2: var(--ink-2); --fg-3: var(--ink-3);
442
442
  --accent: var(--acid); --accent-fg: var(--ink); --accent-ink: var(--acid-deep);
443
443
  /* A paper island under a dark ancestor must not inherit the dark signal pair. */
444
- --flame: #C53E00; --amber: #8A6512; --warn: #E0241A; --sky: #3A6EFF;
444
+ --flame: #C53E00; --amber: #7C570F; --warn: #E0241A; --sky: #3A6EFF;
445
445
  }
446
446
 
447
447
  /* thebird — warm-paper brand preset. A first-class swappable theme: it lives
@@ -664,7 +664,7 @@
664
664
  .ds-247420 pre .k { color: var(--code-str-alt, var(--mascot)); }
665
665
  .ds-247420 pre .s { color: var(--code-string, var(--green)); }
666
666
  .ds-247420 pre .c { color: var(--fg-3); }
667
- .ds-247420 pre .n { color: var(--green-2); }
667
+ .ds-247420 pre .n { color: var(--code-num); }
668
668
 
669
669
  /* ============================================================
670
670
  AppShell — page frame. The topbar floats above a soft background;
@@ -943,6 +943,19 @@
943
943
  .ds-247420 .app-status .item:last-of-type:not(:only-of-type) { display: none; }
944
944
  }
945
945
 
946
+ /* The "dateline" — ASCII bar used at the top of every preview/brand page.
947
+ 3-4 flex slots; a .spread filler pushes the trailing slot to the far
948
+ edge instead of every span running together with no gap. */
949
+ .ds-247420 .dateline {
950
+ display: flex; align-items: center; gap: var(--space-3);
951
+ flex-wrap: nowrap; overflow: hidden;
952
+ font-family: var(--ff-mono); font-size: var(--fs-xs); line-height: 1.2;
953
+ letter-spacing: 0.02em;
954
+ color: var(--fg-3);
955
+ }
956
+ .ds-247420 .dateline span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
957
+ .ds-247420 .dateline .spread { flex: 1 1 auto; min-width: var(--space-3); }
958
+
946
959
  /* ============================================================
947
960
  Primitives
948
961
  ============================================================ */
@@ -973,15 +986,15 @@
973
986
  an ink block with the lead as text, a confident two-tone flip. */
974
987
  .ds-247420 .btn-primary {
975
988
  background: var(--accent); color: var(--accent-fg);
976
- font-weight: 700; letter-spacing: var(--tr-caps);
989
+ font-weight: 700;
977
990
  }
978
991
  .ds-247420 .btn-primary:hover { background: var(--fg); color: var(--accent-ink); transform: translateY(-1px); box-shadow: var(--shadow-2); }
979
992
  .ds-247420 .btn-ghost { background: transparent; color: var(--fg); box-shadow: inset 0 0 0 2px var(--fg); }
980
993
  .ds-247420 .btn-ghost:hover { background: var(--fg); color: var(--bg); transform: translateY(-1px); }
981
994
  .ds-247420 .btn:active, .ds-247420 .btn-primary:active, .ds-247420 .btn-ghost:active { transform: translateY(1px); box-shadow: none; }
982
995
  .ds-247420 .btn:focus-visible, .ds-247420 .btn-primary:focus-visible, .ds-247420 .btn-ghost:focus-visible, .ds-247420 .ds-icon-btn:focus-visible {
983
- outline: 2px solid var(--accent-ink);
984
- outline-offset: 2px;
996
+ outline: var(--focus-w) solid var(--focus-color);
997
+ outline-offset: var(--focus-offset);
985
998
  }
986
999
 
987
1000
  /* ============================================================
@@ -1000,12 +1013,12 @@
1000
1013
  .ds-247420 .ds-icon-btn-lg { width: 40px; height: 40px; }
1001
1014
  .ds-247420 .ds-icon-btn-xl { width: 48px; height: 48px; }
1002
1015
  .ds-247420 .ds-icon-btn-ghost { background: transparent; }
1003
- .ds-247420 .ds-icon-btn-ghost:hover { background: var(--bg-2); }
1016
+ .ds-247420 .ds-icon-btn-ghost:hover { background: var(--fg); color: var(--bg); }
1004
1017
  .ds-247420 .ds-icon-btn-primary { background: var(--accent); color: var(--accent-fg); }
1005
1018
  .ds-247420 .ds-icon-btn-primary:hover { background: var(--fg); color: var(--bg); }
1006
1019
  /* warn = destructive ACTION tone; flame stays exclusively error STATUS. */
1007
1020
  .ds-247420 .ds-icon-btn-danger { background: var(--warn); color: var(--on-color); }
1008
- .ds-247420 .ds-icon-btn-danger:hover { filter: brightness(1.1); }
1021
+ .ds-247420 .ds-icon-btn-danger:hover { filter: brightness(0.92); }
1009
1022
  .ds-247420 .ds-icon-btn:active { transform: translateY(1px); }
1010
1023
  .ds-247420 .ds-icon-btn:disabled, .ds-247420 .ds-icon-btn.is-disabled {
1011
1024
  opacity: 0.5; cursor: not-allowed; pointer-events: none;
@@ -1155,7 +1168,7 @@
1155
1168
  white-space: pre-wrap;
1156
1169
  font-family: var(--ff-mono);
1157
1170
  font-size: var(--fs-sm);
1158
- line-height: var(--lh-snug, 1.3);
1171
+ line-height: var(--lh-snug);
1159
1172
  margin-top: 8px;
1160
1173
  padding: 10px 12px;
1161
1174
  background: var(--bg);
@@ -1211,7 +1224,7 @@
1211
1224
  .ds-247420 .row.row-nocode { grid-template-columns: minmax(0, 1fr) auto; }
1212
1225
 
1213
1226
  .ds-247420 .row .code { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); font-variant-numeric: tabular-nums; letter-spacing: 0.01em; }
1214
- .ds-247420 .row .title { font-family: var(--ff-body); font-weight: 600; font-size: var(--fs-lg); line-height: var(--lh-snug, 1.3); display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; }
1227
+ .ds-247420 .row .title { font-family: var(--ff-body); font-weight: 600; font-size: var(--fs-lg); line-height: var(--lh-snug); display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; }
1215
1228
  .ds-247420 .row .title .sub { font-family: var(--ff-body); font-weight: 400; font-size: var(--fs-sm); color: var(--fg-3); }
1216
1229
  /* App typescale: list rows are quiet working chrome (the 18px/600 default is a
1217
1230
  marketing-surface voice). One size for ALL app list rows - matches
@@ -1655,6 +1668,10 @@
1655
1668
  flex: 1 1 100%; margin-left: 0; order: 3; min-width: 0; max-width: 100%;
1656
1669
  display: flex; gap: 2px; flex-wrap: nowrap;
1657
1670
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
1671
+ /* Fade the trailing edge so a clipped last item (e.g. "source ->" cut to
1672
+ "sour") reads as scrollable content, not a broken/truncated label. */
1673
+ mask-image: linear-gradient(90deg, var(--fg) 0 calc(100% - 28px), transparent 100%);
1674
+ -webkit-mask-image: linear-gradient(90deg, var(--fg) 0 calc(100% - 28px), transparent 100%);
1658
1675
  }
1659
1676
  .ds-247420 .app-topbar nav::-webkit-scrollbar { display: none; }
1660
1677
  .ds-247420 .app-topbar nav a {
@@ -2011,6 +2028,12 @@
2011
2028
  .ds-247420 .ds-file-row .ds-file-meta {
2012
2029
  font-family: var(--ff-mono); font-size: var(--fs-xs);
2013
2030
  color: var(--fg-3); white-space: nowrap;
2031
+ /* Never shrink below content: a flex sibling with white-space:nowrap and
2032
+ the default flex-shrink:1 silently overflows its own box (no ellipsis)
2033
+ when the row runs out of width, painting the date/size over the title
2034
+ and action icons at mobile widths. Fixed-size the meta column instead
2035
+ and let .title (flex:1, min-width:0, ellipsis) absorb the squeeze. */
2036
+ flex-shrink: 0;
2014
2037
  }
2015
2038
 
2016
2039
  /* File icon — glyph chip, tinted per type. */
@@ -2480,6 +2503,7 @@
2480
2503
  border-color: var(--warn);
2481
2504
  color: var(--on-color);
2482
2505
  }
2506
+ .ds-247420 .btn-primary.danger:hover { filter: brightness(0.92); border-color: var(--warn); }
2483
2507
 
2484
2508
  /* -- Preview ------------------------------------------------ */
2485
2509
  .ds-247420 .ds-preview-head {
@@ -3281,6 +3305,14 @@
3281
3305
  transform var(--dur-snap) var(--ease);
3282
3306
  }
3283
3307
 
3308
+ /* Native checkbox/radio tint — browser default is UA blue, which fights the
3309
+ single lime lead accent wherever a raw control lands outside a bespoke
3310
+ toggle (e.g. signin's "remember me"). accent-color re-tints the native
3311
+ control box without hand-drawing a replacement. */
3312
+ .ds-247420 input[type="checkbox"], .ds-247420 input[type="radio"] {
3313
+ accent-color: var(--accent-ink);
3314
+ }
3315
+
3284
3316
  /* Prevent double-tap zoom on buttons (iOS) */
3285
3317
  .ds-247420 .btn, .ds-247420 .btn-primary, .ds-247420 .btn-ghost, .ds-247420 button {
3286
3318
  -webkit-user-select: none;
@@ -3444,6 +3476,35 @@
3444
3476
  color: var(--fg-3);
3445
3477
  }
3446
3478
 
3479
+ /* Structural hairlines — "no boxes, no cards, structure comes from rules."
3480
+ Three weights: .rule (default separator), .rule-double (major section
3481
+ break), .rule-dotted (optional/skippable). Applied to a bare <hr>, which
3482
+ otherwise falls back to the browser's default inset groove line. */
3483
+ .ds-247420 hr.rule, .ds-247420 hr.rule-double, .ds-247420 hr.rule-dotted {
3484
+ width: 100%; height: 0; border: 0;
3485
+ }
3486
+ .ds-247420 hr.rule { border-top: 1px solid var(--rule); }
3487
+ .ds-247420 hr.rule-double { border-top: 3px double var(--rule-strong); }
3488
+ .ds-247420 hr.rule-dotted { border-top: 1px dotted var(--rule-strong); }
3489
+
3490
+ /* Hairline-only text input — no box, no fill. A single bottom rule that
3491
+ thickens to 2px on focus, matching the row/rule zero-border aesthetic
3492
+ instead of a browser-default boxed field. */
3493
+ .ds-247420 .input {
3494
+ display: block; width: 100%; box-sizing: border-box;
3495
+ border: 0; border-bottom: 1px solid var(--rule-strong);
3496
+ border-radius: var(--r-0);
3497
+ background: transparent;
3498
+ padding: var(--space-2) var(--space-1);
3499
+ font: inherit; color: var(--fg);
3500
+ }
3501
+ .ds-247420 .input::placeholder { color: var(--fg-3); }
3502
+ .ds-247420 .input:focus-visible {
3503
+ outline: none;
3504
+ border-bottom-width: 2px;
3505
+ border-bottom-color: var(--accent-ink);
3506
+ }
3507
+
3447
3508
  /* -- Field controls: themed base for TextField / Select / SearchInput --
3448
3509
  Root fix: previously only `transition` was set, so themed apps got
3449
3510
  browser-default white boxes in dark mode and labels collided with inputs
@@ -5262,9 +5323,9 @@
5262
5323
  }
5263
5324
 
5264
5325
  .ds-247420 .cm-channel-item.voice-active {
5265
- color: var(--green-2);
5326
+ color: var(--green);
5266
5327
  }
5267
- .ds-247420 .cm-channel-item.voice-active .cm-ch-icon { color: var(--green-2); }
5328
+ .ds-247420 .cm-channel-item.voice-active .cm-ch-icon { color: var(--green); }
5268
5329
  .ds-247420 .cm-channel-item.voice-active:hover {
5269
5330
  background: color-mix(in oklab, var(--green) 12%, transparent);
5270
5331
  }
@@ -5310,7 +5371,7 @@
5310
5371
  }
5311
5372
 
5312
5373
  .ds-247420 .cm-ch-icon.voice-active-badge {
5313
- color: var(--green-2);
5374
+ color: var(--green);
5314
5375
  text-shadow: 0 0 8px var(--green-2);
5315
5376
  }
5316
5377
 
@@ -5417,7 +5478,7 @@
5417
5478
  color: var(--fg);
5418
5479
  }
5419
5480
  .ds-247420 .cm-ch-voice-user.speaking {
5420
- color: var(--green-2);
5481
+ color: var(--green);
5421
5482
  }
5422
5483
  .ds-247420 .cm-ch-voice-user.speaking .cm-ch-voice-user-avatar {
5423
5484
  box-shadow: 0 0 0 2px var(--green-2);
@@ -5473,7 +5534,7 @@
5473
5534
  font-size: var(--fs-micro);
5474
5535
  text-transform: uppercase;
5475
5536
  letter-spacing: var(--tr-caps);
5476
- color: var(--green-2);
5537
+ color: var(--green);
5477
5538
  font-weight: 700;
5478
5539
  display: inline-flex;
5479
5540
  align-items: center;