anentrypoint-design 0.0.312 → 0.0.314

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/dist/247420.css CHANGED
@@ -186,7 +186,9 @@
186
186
  --space-1-75: 6px;
187
187
  --space-2: 8px;
188
188
  --space-2-5: 10px;
189
+ --space-2-75: 12px; /* fills the 10->16 hole (row-form gap, dense cell pad) */
189
190
  --space-3: 16px;
191
+ --space-3-5: 20px; /* fills the 16->24 hole (settings body, mono block pad) */
190
192
  --space-4: 24px;
191
193
  --space-5: 32px;
192
194
  --space-6: 48px;
@@ -260,6 +262,19 @@
260
262
  --size-base: 42px;
261
263
  --size-lg: 56px;
262
264
 
265
+ /* Dense control-height ladder — the actual heights front-door controls
266
+ (buttons, fields, rows) snap to, one rung tighter than the --size-*
267
+ chrome scale so app UI reads compact instead of marketing-scale. Density
268
+ scales them so [data-density=compact/spacious] moves every control at once.
269
+ Mirrors webgeist's 30/38/46 button ladder, retuned for this system. */
270
+ --ctl-sm: calc(28px * var(--density));
271
+ --ctl-md: calc(34px * var(--density));
272
+ --ctl-lg: calc(42px * var(--density));
273
+ /* The canonical single-line input/select/searchfield height (== --ctl-md)
274
+ and the default list-row min-height, both density-aware. */
275
+ --field-height: var(--ctl-md);
276
+ --row-height: calc(40px * var(--density));
277
+
263
278
  /* Unified focus-ring tokens (single source for the design system). Outset
264
279
  rings (the default) tokenize colour+width+offset; bordered text fields use
265
280
  the inset variant. Deliberate negative offsets on edge-flush/clipping
@@ -289,25 +304,26 @@
289
304
  outline-offset: var(--focus-offset);
290
305
  }
291
306
 
292
- /* Link focus-visible */
307
+ /* Link focus-visible — all route through the single --focus-* token set so a
308
+ focus retune (colour/width/offset) happens in one place, never per selector. */
293
309
  .ds-247420 a:focus-visible,
294
310
  .ds-247420[role="link"]:focus-visible {
295
- outline: 2px solid var(--accent-ink);
296
- outline-offset: 2px;
311
+ outline: var(--focus-w) solid var(--focus-color);
312
+ outline-offset: var(--focus-offset);
297
313
  }
298
314
 
299
315
  /* Form inputs with focus-visible */
300
316
  .ds-247420 input:focus-visible,
301
317
  .ds-247420 textarea:focus-visible,
302
318
  .ds-247420 select:focus-visible {
303
- outline: 2px solid var(--accent-ink);
304
- outline-offset: 2px;
319
+ outline: var(--focus-w) solid var(--focus-color);
320
+ outline-offset: var(--focus-offset);
305
321
  }
306
322
 
307
323
  /* Interactive element focus-visible */
308
324
  .ds-247420[tabindex]:focus-visible {
309
- outline: 2px solid var(--accent-ink);
310
- outline-offset: 2px;
325
+ outline: var(--focus-w) solid var(--focus-color);
326
+ outline-offset: var(--focus-offset);
311
327
  }
312
328
 
313
329
  .ds-247420[data-theme="ink"],
@@ -777,11 +793,15 @@
777
793
  .ds-247420 .app-topbar nav a { flex: 0 0 auto; }
778
794
  .ds-247420 .app-topbar nav a {
779
795
  color: var(--fg-2);
780
- padding: 12px 14px;
781
- min-height: 44px;
796
+ /* Dense desktop chrome (was a 44px pill with 12px 14px pad — marketing-scale
797
+ touch target in the top bar). Matches the .app-side a treatment: ~34px,
798
+ --r-1 rounded rect, tighter padding. The 44px tap target is restored under
799
+ @media(pointer:coarse) (the existing .app-topbar nav a rule further down). */
800
+ padding: var(--space-2) var(--space-2-5);
801
+ min-height: 34px;
782
802
  display: flex;
783
803
  align-items: center;
784
- border-radius: var(--r-pill);
804
+ border-radius: var(--r-1);
785
805
  transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
786
806
  }
787
807
  .ds-247420 .app-topbar nav a:hover { background: var(--bg-2); color: var(--fg); }
@@ -855,13 +875,19 @@
855
875
  }
856
876
  .ds-247420 .app-side a {
857
877
  display: grid; grid-template-columns: 18px 1fr auto;
858
- gap: 10px; align-items: center;
859
- padding: 12px 14px;
860
- min-height: 44px;
861
- border-radius: var(--r-pill);
878
+ gap: var(--space-2-5); align-items: center;
879
+ /* Dense rounded-rect nav row (was a 44px pill with 12px 14px padding — tall
880
+ and consumer-shaped). A --r-1 rounded rect at ~34px reads as compact app
881
+ chrome; the full 44px touch target is restored under pointer:coarse below. */
882
+ padding: var(--space-2) var(--space-2-5);
883
+ min-height: 34px;
884
+ border-radius: var(--r-1);
862
885
  color: var(--fg-2);
863
886
  margin-bottom: 2px;
864
887
  }
888
+ @media (pointer: coarse) {
889
+ .ds-247420 .app-side a { min-height: 44px; padding: var(--space-2-75) var(--space-3); }
890
+ }
865
891
  .ds-247420 .app-side a:hover { background: var(--bg-2); color: var(--fg); }
866
892
  .ds-247420 .app-side a:focus-visible {
867
893
  outline: var(--focus-w) solid var(--focus-color);
@@ -984,10 +1010,16 @@
984
1010
  ============================================================ */
985
1011
  .ds-247420 .btn, .ds-247420 .btn-primary, .ds-247420 .btn-ghost {
986
1012
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
987
- padding: 8px 14px; min-height: 32px;
1013
+ /* Fixed height + horizontal-only padding: the control height is exact and
1014
+ alignable (flex centres the label vertically), the way webgeist snaps every
1015
+ control to a height ladder. Default is the --ctl-md rung; --btn-sm/--btn-lg
1016
+ retune height + h-padding + font per size. Density scales the ladder. */
1017
+ height: var(--ctl-md); min-height: var(--ctl-md);
1018
+ padding: 0 var(--space-2-75);
988
1019
  font-family: var(--ff-body);
989
1020
  font-weight: 600; font-size: var(--fs-sm);
990
1021
  text-decoration: none;
1022
+ white-space: nowrap;
991
1023
  cursor: pointer;
992
1024
  /* Rounded-rect app chrome, not a marketing-page stadium CTA.
993
1025
  Shape vocabulary: r-1/r-2 = actionable buttons, icon-buttons, and
@@ -1020,6 +1052,33 @@
1020
1052
  outline-offset: var(--focus-offset);
1021
1053
  }
1022
1054
 
1055
+ /* Button size ladder — the size prop on Btn() (sm | md | lg). md is the base
1056
+ rule above; sm/lg retune height (off the --ctl-* ladder), horizontal padding,
1057
+ and font-size so a size swap is one class, never inline padding overrides
1058
+ (the old preview faked sizes with style=). Applies to every variant. */
1059
+ .ds-247420 .btn-sm, .ds-247420 .btn-sm.btn-primary, .ds-247420 .btn-sm.btn-ghost {
1060
+ height: var(--ctl-sm); min-height: var(--ctl-sm);
1061
+ padding: 0 var(--space-2); font-size: var(--fs-tiny); gap: var(--space-1);
1062
+ }
1063
+ .ds-247420 .btn-lg, .ds-247420 .btn-lg.btn-primary, .ds-247420 .btn-lg.btn-ghost {
1064
+ height: var(--ctl-lg); min-height: var(--ctl-lg);
1065
+ padding: 0 var(--space-4); font-size: var(--fs-body); gap: var(--space-2);
1066
+ }
1067
+
1068
+ /* App-mode quiet interactions — the marketing hover-lift (translateY + shadow)
1069
+ and the .row .meta slide read as decorative float on a dense working surface.
1070
+ Under [data-typescale="app"], state changes are background/border-only: crisp,
1071
+ no motion, no elevation. Marketing surfaces (no data-typescale) keep the lift. */
1072
+ .ds-247420[data-typescale="app"] .btn:hover,
1073
+ .ds-247420[data-typescale="app"] .btn-primary:hover,
1074
+ .ds-247420[data-typescale="app"] .btn-ghost:hover { transform: none; box-shadow: none; }
1075
+ .ds-247420[data-typescale="app"] .btn:active,
1076
+ .ds-247420[data-typescale="app"] .btn-primary:active,
1077
+ .ds-247420[data-typescale="app"] .btn-ghost:active { transform: none; }
1078
+ .ds-247420[data-typescale="app"] .panel { transition: box-shadow var(--dur-snap) var(--ease), border-color var(--dur-snap) var(--ease); }
1079
+ .ds-247420[data-typescale="app"] a.row:hover .meta,
1080
+ .ds-247420[data-typescale="app"] .row[role="button"]:hover .meta { transform: none; }
1081
+
1023
1082
  /* ============================================================
1024
1083
  IconButton — square icon-only button
1025
1084
  ============================================================ */
@@ -1057,6 +1116,10 @@
1057
1116
  border-radius: var(--r-pill);
1058
1117
  background: var(--bg-3); color: var(--fg-2);
1059
1118
  }
1119
+ /* Badge size ladder — sm for dense inline counts, lg for prominent markers.
1120
+ Base (above) stays the 18px default. */
1121
+ .ds-247420 .ds-badge.ds-badge--sm { min-width: 14px; height: 14px; padding: 0 var(--space-1); font-size: 10px; }
1122
+ .ds-247420 .ds-badge.ds-badge--lg { min-width: 22px; height: 22px; padding: 0 var(--space-2); font-size: var(--fs-tiny); }
1060
1123
  /* Canonical tone names are tone-success / tone-error / tone-neutral. Every
1061
1124
  other tone name grouped into the same rule below (tone-green/tone-live,
1062
1125
  tone-flame, tone-wip, tone-sun/tone-yellow, tone-ok/tone-miss) is a
@@ -1080,7 +1143,7 @@
1080
1143
  .ds-247420 .ds-badge.tone-orange { background: color-mix(in oklab, var(--flame) 30%, var(--sun) 70%); color: var(--ink); }
1081
1144
 
1082
1145
  .ds-247420 .chip {
1083
- display: inline-flex; align-items: center; gap: 6px;
1146
+ display: inline-flex; align-items: center; gap: var(--space-1-75);
1084
1147
  padding: 3px 10px;
1085
1148
  background: var(--bg-2); color: var(--fg-2);
1086
1149
  font-family: var(--ff-body);
@@ -1088,6 +1151,17 @@
1088
1151
  letter-spacing: var(--tr-caps); text-transform: uppercase;
1089
1152
  border-radius: var(--r-pill);
1090
1153
  }
1154
+ /* Chip size ladder — sm for dense toolbars/table cells, lg for prominent
1155
+ status. tone-* colouring (below) is orthogonal to size. */
1156
+ .ds-247420 .chip.chip--sm { padding: var(--space-half) var(--space-2); font-size: var(--fs-micro); gap: var(--space-1); }
1157
+ .ds-247420 .chip.chip--lg { padding: var(--space-1-75) var(--space-2-75); font-size: var(--fs-xs); }
1158
+ /* Tag variant — a rectangular, sentence-case chip for dense data (table cells,
1159
+ inline labels) where the all-caps pill reads too shouty and space-hungry.
1160
+ Keeps the tone-* palette; drops the caps + pill for a tight --r-0 corner. */
1161
+ .ds-247420 .chip.chip--tag {
1162
+ text-transform: none; letter-spacing: 0; font-weight: 500;
1163
+ border-radius: var(--r-0); padding: var(--space-half) var(--space-2);
1164
+ }
1091
1165
  /* Same canonical/legacy-alias grouping as .ds-badge above. */
1092
1166
  .ds-247420 .chip.tone-green, .ds-247420 .chip.tone-live, .ds-247420 .chip.tone-success, .ds-247420 .chip.tone-ok {
1093
1167
  background: var(--green-tint); color: var(--green-deep);
@@ -1157,6 +1231,17 @@
1157
1231
  }
1158
1232
  .ds-247420 .panel.panel-inline { background: var(--bg-2); padding: var(--space-3) var(--space-3); }
1159
1233
  .ds-247420 .panel.panel-wide { background: transparent; box-shadow: none; border: none; }
1234
+ /* Dense panel — a compact container for app surfaces (inspector sections,
1235
+ sidebars) that want the .panel look without the roomy 16px pad + 24px stack
1236
+ gap. Tighter corner + padding + head, so it sits between .panel and the
1237
+ flush editor .ds-ep-panel. */
1238
+ .ds-247420 .panel.panel--dense {
1239
+ padding: var(--space-2); margin-bottom: var(--space-2-75);
1240
+ border-radius: var(--r-1);
1241
+ }
1242
+ .ds-247420 .panel.panel--dense .panel-head { padding: var(--space-1-5) var(--space-2); }
1243
+ .ds-247420 .panel.panel--dense .panel-body { padding: var(--space-1-5) var(--space-2) var(--space-2); }
1244
+ .ds-247420 .panel.panel--dense .panel-body > * + * { margin-top: var(--space-2); }
1160
1245
  .ds-247420 .panel-head {
1161
1246
  display: flex; align-items: baseline; justify-content: space-between;
1162
1247
  /* Shares the .panel-body 16px side padding so the caps label and the body
@@ -1186,9 +1271,13 @@
1186
1271
  grid-template-columns: minmax(80px, 12ch) minmax(0, 1fr) auto;
1187
1272
  gap: var(--space-3);
1188
1273
  align-items: baseline;
1189
- padding: var(--space-3) var(--space-4);
1274
+ /* App density is the BASE: a list row is quiet working chrome, so it defaults
1275
+ to the compact 12px/16px rhythm (density-scaled) rather than the old
1276
+ 16px/24px marketing padding. .row--lede restores the roomier marketing
1277
+ voice for editorial index pages. */
1278
+ padding: calc(var(--space-2-75) * var(--density)) var(--space-3);
1190
1279
  background: var(--bg);
1191
- border-radius: var(--r-2);
1280
+ border-radius: var(--r-1);
1192
1281
  color: var(--fg);
1193
1282
  position: relative;
1194
1283
  /* Only background + the leading rail animate; padding/size never change on
@@ -1266,8 +1355,14 @@
1266
1355
  .ds-247420 .row.row-nocode { grid-template-columns: minmax(0, 1fr) auto; }
1267
1356
 
1268
1357
  .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; }
1269
- .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; }
1358
+ /* Title defaults to the quiet app voice (fs-sm/500) — the 18px/600 marketing
1359
+ voice is now opt-in via .row--lede. */
1360
+ .ds-247420 .row .title { font-family: var(--ff-body); font-weight: 500; font-size: var(--fs-sm); line-height: var(--lh-snug); display: flex; align-items: baseline; gap: var(--space-2-5); flex-wrap: wrap; min-width: 0; }
1270
1361
  .ds-247420 .row .title .sub { font-family: var(--ff-body); font-weight: 400; font-size: var(--fs-sm); color: var(--fg-3); }
1362
+ /* Marketing/editorial index row — restores the roomier padding + larger title
1363
+ the default carried before app-scale became the base. */
1364
+ .ds-247420 .row--lede { padding: var(--space-3) var(--space-4); }
1365
+ .ds-247420 .row--lede .title { font-size: var(--fs-lg); font-weight: 600; }
1271
1366
  /* App typescale: list rows are quiet working chrome (the 18px/600 default is a
1272
1367
  marketing-surface voice). One size for ALL app list rows - matches
1273
1368
  .ds-file-row/.ds-session-title at fs-sm/500; values mirror the kit's own
@@ -1506,16 +1601,19 @@
1506
1601
  .ds-247420 table {
1507
1602
  width: 100%; border-collapse: collapse;
1508
1603
  font-family: var(--ff-body); font-size: var(--fs-sm);
1509
- border-radius: var(--r-3); overflow: hidden;
1604
+ /* A data grid, not a card: a tight --r-0 corner (was --r-3/22px, which read
1605
+ as a rounded card). Cells drop to 8px 12px for a dense, scannable row
1606
+ (was 12/14 x 16 => ~43px rows). Density scales the vertical padding. */
1607
+ border-radius: var(--r-0); overflow: hidden;
1510
1608
  }
1511
1609
  .ds-247420 table th {
1512
1610
  text-align: left;
1513
- padding: 12px 16px;
1611
+ padding: calc(var(--space-2) * var(--density)) var(--space-2-75);
1514
1612
  font-size: var(--fs-tiny); font-weight: 600;
1515
1613
  color: var(--fg-3); text-transform: uppercase; letter-spacing: var(--tr-caps);
1516
1614
  background: var(--bg-2);
1517
1615
  }
1518
- .ds-247420 table td { padding: 14px 16px; border-top: 1px solid var(--rule); }
1616
+ .ds-247420 table td { padding: calc(var(--space-2) * var(--density)) var(--space-2-75); border-top: 1px solid var(--rule); }
1519
1617
  .ds-247420 table tr.clickable { cursor: pointer; }
1520
1618
  .ds-247420 table tr.clickable:hover td { background: var(--bg-2); }
1521
1619
  .ds-247420 table tr.clickable:focus-visible {
@@ -1583,13 +1681,16 @@
1583
1681
  gap: var(--space-2);
1584
1682
  }
1585
1683
  .ds-247420 .kpi-card {
1586
- padding: var(--space-5);
1684
+ /* Was --space-5 (32px) pad + --r-3 (22px) — four cards ate a full fold. A
1685
+ 16px pad on a --r-1 corner keeps them prominent but dense; the number drops
1686
+ from a 48px marketing display to a 32px app-scale figure. */
1687
+ padding: var(--space-3);
1587
1688
  background: var(--bg-2);
1588
- border-radius: var(--r-3);
1689
+ border-radius: var(--r-1);
1589
1690
  }
1590
1691
  .ds-247420 .kpi-card .num {
1591
1692
  font-family: var(--ff-body); font-weight: 600;
1592
- font-size: clamp(30px, 3.6cqi, 48px); line-height: 1;
1693
+ font-size: clamp(22px, 3cqi, 32px); line-height: 1;
1593
1694
  letter-spacing: var(--tr-tight);
1594
1695
  }
1595
1696
  .ds-247420 .kpi-card .lbl {
@@ -1638,11 +1739,14 @@
1638
1739
  Empty state
1639
1740
  ============================================================ */
1640
1741
  .ds-247420 .empty {
1641
- padding: var(--space-8);
1742
+ /* Was --space-8 (96px) — an empty list spent 192px of vertical space on
1743
+ nothing. --space-6 (48px) still centres a message with air, without the
1744
+ empty state dominating the fold. Mobile drops it further (below). */
1745
+ padding: var(--space-6);
1642
1746
  text-align: center;
1643
1747
  color: var(--fg-3);
1644
1748
  background: var(--bg-2);
1645
- border-radius: var(--r-3);
1749
+ border-radius: var(--r-1);
1646
1750
  font-size: var(--fs-sm);
1647
1751
  }
1648
1752
 
@@ -2655,6 +2759,54 @@
2655
2759
  .ds-247420 .ds-preview-meta { display: none; }
2656
2760
  }
2657
2761
 
2762
+ /* ============================================================
2763
+ Catalog / demo shell — a shared, compact framing for the preview/*.html
2764
+ component galleries, so each preview stops hand-rolling its own \3c style>
2765
+ (body padding, section margins, demo boxes). Mirrors webgeist's dense
2766
+ catalog: a 240px sticky sidebar + capped main + a hairline-bordered,
2767
+ flex-wrapping .ds-demo cell that packs variants inline and reflows.
2768
+ ============================================================ */
2769
+ .ds-247420 .ds-catalog { display: flex; min-height: 100vh; gap: 0; }
2770
+ .ds-247420 .ds-catalog-side {
2771
+ width: 240px; flex-shrink: 0;
2772
+ border-right: var(--bw-hair) solid var(--rule);
2773
+ padding: var(--space-3);
2774
+ position: sticky; top: 0; height: 100vh; overflow-y: auto;
2775
+ }
2776
+ .ds-247420 .ds-catalog-side h1 { font-size: var(--fs-lg); margin: 0 0 var(--space-1); }
2777
+ .ds-247420 .ds-catalog-side .subtitle { font-size: var(--fs-micro); color: var(--fg-3); margin: 0 0 var(--space-4); }
2778
+ .ds-247420 .ds-catalog-side nav h4 {
2779
+ font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: var(--tr-label);
2780
+ color: var(--fg-3); margin: var(--space-3) 0 var(--space-1);
2781
+ }
2782
+ .ds-247420 .ds-catalog-side nav a {
2783
+ display: block; padding: var(--space-half) 0; font-size: var(--fs-tiny);
2784
+ color: var(--fg-2); text-decoration: none;
2785
+ }
2786
+ .ds-247420 .ds-catalog-side nav a:hover { color: var(--accent-ink); }
2787
+ .ds-247420 .ds-catalog-main { flex: 1; padding: var(--space-5); max-width: var(--measure-wide); min-width: 0; }
2788
+ .ds-247420 .ds-catalog-section { margin-bottom: var(--space-5); padding-top: var(--space-3); border-top: var(--bw-hair) solid var(--rule); }
2789
+ .ds-247420 .ds-catalog-section > h2 { font-size: var(--fs-h3-app); margin: 0 0 var(--space-3); }
2790
+
2791
+ /* The gallery cell: a hairline-bordered, flex-wrapping bin that packs a
2792
+ component's variants inline and reflows — the signature "showcase" frame. */
2793
+ .ds-247420 .ds-demo {
2794
+ border: var(--bw-hair) solid var(--rule);
2795
+ border-radius: var(--r-1);
2796
+ padding: var(--space-3);
2797
+ display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
2798
+ background: var(--bg);
2799
+ }
2800
+ .ds-247420 .ds-demo + .ds-demo { margin-top: var(--space-2-75); }
2801
+ .ds-247420 .ds-demo-label { font-size: var(--fs-xs); font-weight: 500; margin: 0 0 var(--space-1); }
2802
+ .ds-247420 .ds-demo-desc { font-size: var(--fs-tiny); color: var(--fg-3); margin: 0 0 var(--space-2); }
2803
+
2804
+ @media (max-width: 768px) {
2805
+ .ds-247420 .ds-catalog { flex-direction: column; }
2806
+ .ds-247420 .ds-catalog-side { width: 100%; height: auto; position: static; border-right: 0; border-bottom: var(--bw-hair) solid var(--rule); }
2807
+ .ds-247420 .ds-catalog-main { padding: var(--space-3); }
2808
+ }
2809
+
2658
2810
  /* -- File browser UX affordances ---------------------------- */
2659
2811
  /* Toolbar filter input — compact search box. */
2660
2812
  .ds-247420 .ds-filter-input {
@@ -3514,19 +3666,61 @@
3514
3666
  Enhanced Form Inputs
3515
3667
  -------------------------------------------------------------- */
3516
3668
 
3517
- .ds-247420 input[type="text"],
3518
- .ds-247420 input[type="email"],
3519
- .ds-247420 input[type="password"],
3520
- .ds-247420 input[type="number"],
3521
- .ds-247420 input[type="search"],
3522
- .ds-247420 input[type="url"],
3523
- .ds-247420 input[type="tel"],
3524
- .ds-247420 textarea,
3525
- .ds-247420 select {
3669
+ /* Base chrome for any BARE native control (outside .ds-field/.row-form/.input):
3670
+ the same editorial tonal-fill + printed-baseline-rule as .ds-field, so a raw
3671
+ <input> is never a browser-default white box in dark mode. The guards are
3672
+ wrapped in :where() so they add ZERO specificity — the whole selector stays
3673
+ at (0,1,1), exactly like `.ds-field input`, so the later .ds-field / .ds-field--sm
3674
+ / .row-form descendant rules win by source order instead of being out-specified
3675
+ (a bare :not(.input) counts as a class and would beat every .ds-field rule,
3676
+ which clobbered the size variants). */
3677
+ .ds-247420 input[type="text"]:where(:not(.input):not(.ds-search-input)),
3678
+ .ds-247420 input[type="email"]:where(:not(.input):not(.ds-search-input)),
3679
+ .ds-247420 input[type="password"]:where(:not(.input):not(.ds-search-input)),
3680
+ .ds-247420 input[type="number"]:where(:not(.input):not(.ds-search-input)),
3681
+ .ds-247420 input[type="search"]:where(:not(.input):not(.ds-search-input)),
3682
+ .ds-247420 input[type="url"]:where(:not(.input):not(.ds-search-input)),
3683
+ .ds-247420 input[type="tel"]:where(:not(.input):not(.ds-search-input)),
3684
+ .ds-247420 textarea:where(:not(.input)),
3685
+ .ds-247420 select:where(:not(.ds-select)) {
3686
+ font: inherit; color: var(--fg);
3687
+ background: var(--bg-2);
3688
+ border: 0;
3689
+ box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--rule),
3690
+ inset 0 calc(-1 * var(--bw-rule)) 0 var(--rule-strong);
3691
+ border-radius: var(--r-1);
3692
+ padding: 0 var(--space-3);
3526
3693
  transition: background var(--dur-snap) var(--ease),
3527
3694
  border-color var(--dur-snap) var(--ease),
3528
3695
  box-shadow var(--dur-snap) var(--ease);
3529
3696
  }
3697
+ /* Single-line bare controls snap to the field height; textarea keeps auto
3698
+ height with symmetric padding (its content decides the box). */
3699
+ .ds-247420 input[type="text"]:where(:not(.input):not(.ds-search-input)),
3700
+ .ds-247420 input[type="email"]:where(:not(.input):not(.ds-search-input)),
3701
+ .ds-247420 input[type="password"]:where(:not(.input):not(.ds-search-input)),
3702
+ .ds-247420 input[type="number"]:where(:not(.input):not(.ds-search-input)),
3703
+ .ds-247420 input[type="search"]:where(:not(.input):not(.ds-search-input)),
3704
+ .ds-247420 input[type="url"]:where(:not(.input):not(.ds-search-input)),
3705
+ .ds-247420 input[type="tel"]:where(:not(.input):not(.ds-search-input)),
3706
+ .ds-247420 select:where(:not(.ds-select)) {
3707
+ height: var(--field-height);
3708
+ }
3709
+ .ds-247420 textarea:where(:not(.input)) { padding: var(--space-2) var(--space-3); min-height: calc(4 * 1.5em); }
3710
+ .ds-247420 input[type="text"]:where(:not(.input):not(.ds-search-input)):focus-visible,
3711
+ .ds-247420 input[type="email"]:where(:not(.input):not(.ds-search-input)):focus-visible,
3712
+ .ds-247420 input[type="password"]:where(:not(.input):not(.ds-search-input)):focus-visible,
3713
+ .ds-247420 input[type="number"]:where(:not(.input):not(.ds-search-input)):focus-visible,
3714
+ .ds-247420 input[type="search"]:where(:not(.input):not(.ds-search-input)):focus-visible,
3715
+ .ds-247420 input[type="url"]:where(:not(.input):not(.ds-search-input)):focus-visible,
3716
+ .ds-247420 input[type="tel"]:where(:not(.input):not(.ds-search-input)):focus-visible,
3717
+ .ds-247420 textarea:where(:not(.input)):focus-visible,
3718
+ .ds-247420 select:where(:not(.ds-select)):focus-visible {
3719
+ outline: none;
3720
+ background: var(--bg);
3721
+ box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--rule),
3722
+ inset 0 calc(-1 * var(--bw-chunk)) 0 var(--accent);
3723
+ }
3530
3724
 
3531
3725
  .ds-247420 input[type="text"]::placeholder,
3532
3726
  .ds-247420 input[type="email"]::placeholder,
@@ -3659,11 +3853,29 @@
3659
3853
  the electric lead on focus, instead of a uniform hairline box. */
3660
3854
  box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--rule),
3661
3855
  inset 0 calc(-1 * var(--bw-rule)) 0 var(--rule-strong);
3662
- border-radius: var(--r-2, 10px);
3663
- padding: 10px 14px;
3856
+ /* Tighter corner than the old --r-2 (14px): a dense pro control, not a soft
3857
+ consumer box. Single-line controls snap to --field-height with h-only
3858
+ padding so they align pixel-exact with buttons on the same --ctl-md rung. */
3859
+ border-radius: var(--r-1);
3860
+ height: var(--field-height);
3861
+ padding: 0 var(--space-3);
3664
3862
  transition: box-shadow var(--dur-snap) var(--ease), background var(--dur-snap) var(--ease);
3665
3863
  }
3666
- .ds-247420 .ds-field textarea { min-height: calc(4 * 1.5em); resize: vertical; }
3864
+ /* textarea is multi-line: height is auto (min-height instead), keep symmetric
3865
+ vertical padding so text doesn't sit flush to the top edge. */
3866
+ .ds-247420 .ds-field textarea { height: auto; min-height: calc(4 * 1.5em); padding: var(--space-2) var(--space-3); resize: vertical; }
3867
+
3868
+ /* Field size ladder (size prop on TextField/Select/SearchInput). md == base.
3869
+ sm/lg retune height + h-padding + font off the --ctl-* ladder, matching the
3870
+ button ladder so a form of mixed controls stays on one rhythm. */
3871
+ .ds-247420 .ds-field--sm input, .ds-247420 .ds-field--sm .ds-select, .ds-247420 .ds-field--sm .ds-search-input {
3872
+ height: var(--ctl-sm); padding: 0 var(--space-2-5); font-size: var(--fs-tiny);
3873
+ }
3874
+ .ds-247420 .ds-field--sm textarea { height: auto; padding: var(--space-1-75) var(--space-2-5); font-size: var(--fs-tiny); }
3875
+ .ds-247420 .ds-field--lg input, .ds-247420 .ds-field--lg .ds-select, .ds-247420 .ds-field--lg .ds-search-input {
3876
+ height: var(--ctl-lg); padding: 0 var(--space-4); font-size: var(--fs-body);
3877
+ }
3878
+ .ds-247420 .ds-field--lg textarea { height: auto; padding: var(--space-2-5) var(--space-4); font-size: var(--fs-body); }
3667
3879
  .ds-247420 .ds-search-input::placeholder { color: var(--fg-3); }
3668
3880
  /* Only present when SearchInput is passed resultCount - transparent to any
3669
3881
  flex/grid layout the bare input previously sat in directly. */
@@ -5361,7 +5573,7 @@
5361
5573
  background: color-mix(in oklab, var(--fg) 8%, transparent);
5362
5574
  }
5363
5575
  .ds-247420 .cm-cat-add:focus-visible {
5364
- outline: 2px solid var(--accent-ink);
5576
+ outline: var(--focus-w) solid var(--focus-color);
5365
5577
  outline-offset: 2px;
5366
5578
  }
5367
5579
 
@@ -5544,7 +5756,7 @@
5544
5756
  background: color-mix(in oklab, var(--fg) 10%, transparent);
5545
5757
  }
5546
5758
  .ds-247420 .cm-ch-action-btn:focus-visible {
5547
- outline: 2px solid var(--accent-ink);
5759
+ outline: var(--focus-w) solid var(--focus-color);
5548
5760
  outline-offset: 2px;
5549
5761
  }
5550
5762
 
@@ -6127,44 +6339,44 @@
6127
6339
  .ds-247420 .cm-server-icon:focus-visible,
6128
6340
  .ds-247420 .cm-server-back:focus-visible,
6129
6341
  .ds-247420 .cm-server-add:focus-visible {
6130
- outline: 2px solid var(--accent-ink);
6342
+ outline: var(--focus-w) solid var(--focus-color);
6131
6343
  outline-offset: 2px;
6132
6344
  border-radius: var(--r-2);
6133
6345
  }
6134
6346
 
6135
6347
  .ds-247420 .cm-channel-item:focus-visible {
6136
- outline: 2px solid var(--accent-ink);
6348
+ outline: var(--focus-w) solid var(--focus-color);
6137
6349
  outline-offset: -2px;
6138
6350
  border-radius: var(--r-1);
6139
6351
  }
6140
6352
 
6141
6353
  .ds-247420 .cm-server-header:focus-visible,
6142
6354
  .ds-247420 .cm-category-header:focus-visible {
6143
- outline: 2px solid var(--accent-ink);
6355
+ outline: var(--focus-w) solid var(--focus-color);
6144
6356
  outline-offset: -2px;
6145
6357
  }
6146
6358
 
6147
6359
  .ds-247420 .cm-member-item:focus-visible {
6148
- outline: 2px solid var(--accent-ink);
6360
+ outline: var(--focus-w) solid var(--focus-color);
6149
6361
  outline-offset: -2px;
6150
6362
  border-radius: var(--r-1);
6151
6363
  }
6152
6364
 
6153
6365
  .ds-247420 .cm-vs-btn:focus-visible,
6154
6366
  .ds-247420 .cm-user-btn:focus-visible {
6155
- outline: 2px solid var(--accent-ink);
6367
+ outline: var(--focus-w) solid var(--focus-color);
6156
6368
  outline-offset: 2px;
6157
6369
  border-radius: var(--r-1);
6158
6370
  }
6159
6371
 
6160
6372
  /* ThreadPanel / Forum / Page interactive elements */
6161
6373
  .ds-247420 .cm-tp-item:focus-visible,
6162
- .ds-247420 .cm-forum-item:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; border-radius: var(--r-1); }
6374
+ .ds-247420 .cm-forum-item:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: -2px; border-radius: var(--r-1); }
6163
6375
  .ds-247420 .cm-tp-new:focus-visible,
6164
6376
  .ds-247420 .cm-tp-close:focus-visible,
6165
6377
  .ds-247420 .cm-forum-new:focus-visible,
6166
6378
  .ds-247420 .cm-forum-sort:focus-visible,
6167
- .ds-247420 .cm-page-edit:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; border-radius: var(--r-1); }
6379
+ .ds-247420 .cm-page-edit:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: 2px; border-radius: var(--r-1); }
6168
6380
  .ds-247420 .cm-forum-search:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent-ink); }
6169
6381
 
6170
6382
  /* ---------- mobile header ---------- */
@@ -6193,7 +6405,7 @@
6193
6405
  border-radius: var(--r-1);
6194
6406
  }
6195
6407
  .ds-247420 .cm-mh-btn:hover { background: var(--panel-3); }
6196
- .ds-247420 .cm-mh-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
6408
+ .ds-247420 .cm-mh-btn:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: 2px; }
6197
6409
  .ds-247420 .cm-mh-title {
6198
6410
  flex: 1 1 auto;
6199
6411
  min-width: 0;
@@ -6238,7 +6450,7 @@
6238
6450
  border-radius: var(--r-1);
6239
6451
  }
6240
6452
  .ds-247420 .cm-rb-cancel:hover { background: var(--panel-3); color: var(--fg); }
6241
- .ds-247420 .cm-rb-cancel:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }
6453
+ .ds-247420 .cm-rb-cancel:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: 1px; }
6242
6454
 
6243
6455
  /* ---------- banner ---------- */
6244
6456
  .ds-247420 .cm-banner {
@@ -7893,12 +8105,36 @@
7893
8105
  }
7894
8106
 
7895
8107
  /* Tabs */
7896
- .ds-247420 .ds-ep-tabs { display: flex; flex-direction: column; min-height: 0; height: 100%; }
8108
+ .ds-247420 .ds-ep-tabs { display: flex; flex-direction: column; min-height: 0; height: 100%; position: relative; }
7897
8109
  .ds-247420 .ds-ep-tabs-head {
7898
8110
  display: flex; flex-shrink: 0; flex-wrap: nowrap;
7899
8111
  overflow-x: auto; scroll-behavior: smooth;
7900
8112
  background: var(--panel-1);
7901
8113
  border-bottom: 1px solid var(--rule);
8114
+ position: relative;
8115
+ }
8116
+ /* Sliding indicator — a single 2px bar under the active tab that animates its
8117
+ left/width between tabs (webgeist's "expensive" underline-slide), instead of
8118
+ each tab toggling its own static border. A REAL child element positioned by
8119
+ the Tabs ref (inline left/width/top). It lives as a child of the OUTER
8120
+ .ds-ep-tabs column (position:relative), NOT the .ds-ep-tabs-head, because an
8121
+ absolutely-positioned child of a horizontal flex container mis-sizes to 0 in
8122
+ Chromium; the outer column is a vertical flex, which sizes it correctly.
8123
+ The ref sets top to the head's height so it sits on the head's bottom edge.
8124
+ .has-slider gates the static per-tab border off (below). */
8125
+ .ds-247420 .ds-ep-tab-indicator {
8126
+ /* Sized by left+right insets (set inline by positionSlider), NOT width — an
8127
+ abspos element's `width` computes to 0 in some flex-sibling layouts in
8128
+ Chromium, whereas insets size reliably. left+right at the same value
8129
+ collapse it to 0 until positioned (no-JS: invisible). */
8130
+ position: absolute; top: 0; left: 0; right: 100%; height: 2px;
8131
+ background: var(--accent);
8132
+ transition: left var(--dur-base, 160ms) var(--ease, ease),
8133
+ right var(--dur-base, 160ms) var(--ease, ease);
8134
+ pointer-events: none;
8135
+ }
8136
+ @media (prefers-reduced-motion: reduce) {
8137
+ .ds-247420 .ds-ep-tab-indicator { transition: none; }
7902
8138
  }
7903
8139
  .ds-247420 .ds-ep-tab {
7904
8140
  flex: 1; appearance: none; background: transparent; border: 0;
@@ -7913,6 +8149,9 @@
7913
8149
  color: var(--accent);
7914
8150
  border-bottom-color: var(--accent);
7915
8151
  }
8152
+ /* When the JS slider is active, the active tab's own static border is
8153
+ redundant (the sliding bar draws it) — hide it so they don't double up. */
8154
+ .ds-247420 .ds-ep-tabs-head.has-slider .ds-ep-tab.active { border-bottom-color: transparent; }
7916
8155
  /* Flex column so a full-height docked child (e.g. an inspector panel) fills
7917
8156
  the tab body instead of collapsing under a block container. */
7918
8157
  .ds-247420 .ds-ep-tabs-body { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; }
@@ -8118,7 +8357,8 @@
8118
8357
  .ds-247420 .ds-ep-actionbar > * { flex: 1 1 0; }
8119
8358
  .ds-247420 .ds-ep-actionbar button {
8120
8359
  width: 100%;
8121
- min-height: 28px; height: 28px; padding: 0 10px;
8360
+ /* Snapped to --ctl-sm (was a lone 28px literal that happened to match). */
8361
+ min-height: var(--ctl-sm); height: var(--ctl-sm); padding: 0 var(--space-2-5);
8122
8362
  border-radius: var(--r-1, 4px);
8123
8363
  font: var(--fs-tiny, 12px)/1 var(--ff-mono, monospace);
8124
8364
  }
@@ -8488,15 +8728,19 @@
8488
8728
  display: flex; flex-direction: column;
8489
8729
  outline: none;
8490
8730
  }
8491
- .ds-247420 .ds-ep-dialog-head { padding: 14px 16px 6px; border-bottom: 1px solid var(--rule); }
8492
- .ds-247420 .ds-ep-dialog-title { margin: 0; font-size: 16px; font-weight: 600; }
8493
- .ds-247420 .ds-ep-dialog-body { padding: 14px 16px; }
8731
+ /* Padding tokenized to the --space-* scale (was raw 14/16/10/6) and shaved to
8732
+ app density — a dialog is working chrome, not a marketing card. */
8733
+ .ds-247420 .ds-ep-dialog-head { padding: var(--space-2-75) var(--space-3) var(--space-1-5); border-bottom: 1px solid var(--rule); }
8734
+ .ds-247420 .ds-ep-dialog-title { margin: 0; font-size: var(--fs-body); font-weight: 600; }
8735
+ .ds-247420 .ds-ep-dialog-body { padding: var(--space-2-75) var(--space-3); }
8494
8736
  .ds-247420 .ds-ep-dialog-actions {
8495
- display: flex; gap: 8px; justify-content: flex-end;
8496
- padding: 10px 14px; border-top: 1px solid var(--rule);
8737
+ display: flex; gap: var(--space-2); justify-content: flex-end;
8738
+ padding: var(--space-2) var(--space-2-75); border-top: 1px solid var(--rule);
8497
8739
  }
8498
8740
  .ds-247420 .ds-ep-dialog-btn {
8499
- padding: 8px 14px;
8741
+ /* Snapped to the --ctl-sm rung + tokenized padding (was 8px 14px). */
8742
+ min-height: var(--ctl-sm); padding: 0 var(--space-3);
8743
+ display: inline-flex; align-items: center; justify-content: center;
8500
8744
  border: 1px solid var(--rule);
8501
8745
  border-radius: var(--r-1, 6px);
8502
8746
  background: var(--panel-2, transparent);
@@ -8530,7 +8774,7 @@
8530
8774
  border: 1px solid var(--rule);
8531
8775
  border-left: 3px solid var(--accent);
8532
8776
  border-radius: var(--r-1, 6px);
8533
- padding: 10px 14px;
8777
+ padding: var(--space-2) var(--space-2-75);
8534
8778
  box-shadow: var(--shadow-3);
8535
8779
  min-width: 220px; max-width: 360px;
8536
8780
  opacity: 1;
@@ -8623,7 +8867,10 @@
8623
8867
  .ds-247420 .ds-radio-row,
8624
8868
  .ds-247420 .ds-toggle-row {
8625
8869
  display: inline-flex; align-items: center; gap: var(--space-2, 8px);
8626
- min-height: 44px;
8870
+ /* Desktop density: ~30px rows, not the 44px touch target (which stacked a
8871
+ lot of dead vertical space in inspector/settings forms). The full 44px
8872
+ target is restored under pointer:coarse below. */
8873
+ min-height: 30px;
8627
8874
  padding: var(--space-1, 4px) var(--space-2, 8px);
8628
8875
  cursor: pointer;
8629
8876
  color: var(--fg);
@@ -8632,6 +8879,10 @@
8632
8879
  .ds-247420 .ds-check-row:has(input:disabled),
8633
8880
  .ds-247420 .ds-radio-row:has(input:disabled),
8634
8881
  .ds-247420 .ds-toggle-row:has(button:disabled) { opacity: 0.5; cursor: not-allowed; }
8882
+ /* Touch devices: restore the 44px minimum tap target. */
8883
+ @media (pointer: coarse) {
8884
+ .ds-247420 .ds-check-row, .ds-247420 .ds-radio-row, .ds-247420 .ds-toggle-row { min-height: 44px; }
8885
+ }
8635
8886
 
8636
8887
  .ds-247420 .ds-check, .ds-247420 .ds-radio {
8637
8888
  width: 18px; height: 18px;
@@ -8787,8 +9038,12 @@
8787
9038
  .ds-247420 .ds-dropdown-list { display: flex; flex-direction: column; }
8788
9039
  .ds-247420 .ds-dropdown-item {
8789
9040
  display: flex; align-items: center; gap: 8px;
8790
- min-height: 44px;
8791
- padding: 8px 12px;
9041
+ /* Dense desktop row (was an unconditional 44px touch target — a menu of
9042
+ these was very tall on desktop). ~30px here; the 44px tap target is
9043
+ restored under @media(pointer:coarse) below, matching the .ds-check-row
9044
+ treatment. */
9045
+ min-height: 30px;
9046
+ padding: var(--space-1-5) var(--space-2-75);
8792
9047
  background: transparent; border: 0;
8793
9048
  color: inherit; font: inherit; text-align: left;
8794
9049
  border-radius: var(--r-1, 4px);
@@ -8799,6 +9054,9 @@
8799
9054
  background: var(--panel-2, var(--rule));
8800
9055
  outline: none;
8801
9056
  }
9057
+ @media (pointer: coarse) {
9058
+ .ds-247420 .ds-dropdown-item { min-height: 44px; padding: var(--space-2) var(--space-3); }
9059
+ }
8802
9060
  .ds-247420 .ds-dropdown-item:focus-visible {
8803
9061
  outline: var(--focus-w) solid var(--focus-color);
8804
9062
  outline-offset: calc(var(--focus-offset) * -1);
@@ -8818,9 +9076,12 @@
8818
9076
  color: inherit; font: inherit;
8819
9077
  border: 1px solid var(--rule);
8820
9078
  border-radius: var(--r-1, 6px);
8821
- padding: 6px 12px;
9079
+ padding: 0 var(--space-2-75);
8822
9080
  cursor: pointer;
8823
- min-height: 32px;
9081
+ /* Snapped to the --ctl-sm rung so this small control shares the height
9082
+ ladder with buttons/fields instead of a lone 32px literal. */
9083
+ min-height: var(--ctl-sm); height: var(--ctl-sm);
9084
+ display: inline-flex; align-items: center;
8824
9085
  }
8825
9086
  @media (pointer: coarse) {
8826
9087
  .ds-247420 .ds-dropdown-trigger { min-height: 44px; }