anentrypoint-design 0.0.381 → 0.0.383

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.
Files changed (54) hide show
  1. package/dist/247420.css +406 -180
  2. package/dist/247420.js +26 -26
  3. package/package.json +1 -1
  4. package/src/components/content/avatar.js +31 -0
  5. package/src/components/content/charts.js +50 -0
  6. package/src/components/content/cli.js +46 -0
  7. package/src/components/content/feedback.js +77 -0
  8. package/src/components/content/fields.js +136 -0
  9. package/src/components/content/hero.js +146 -0
  10. package/src/components/content/lists.js +85 -0
  11. package/src/components/content/panel.js +79 -0
  12. package/src/components/content/row.js +115 -0
  13. package/src/components/content/table.js +97 -0
  14. package/src/components/content/views.js +81 -0
  15. package/src/components/content.js +29 -861
  16. package/src/components/editor-primitives/batch.js +60 -0
  17. package/src/components/editor-primitives/chrome.js +146 -0
  18. package/src/components/editor-primitives/collapse.js +46 -0
  19. package/src/components/editor-primitives/context-menu.js +127 -0
  20. package/src/components/editor-primitives/diagnostics.js +44 -0
  21. package/src/components/editor-primitives/focus-trap.js +26 -0
  22. package/src/components/editor-primitives/json-viewer.js +123 -0
  23. package/src/components/editor-primitives/layout.js +89 -0
  24. package/src/components/editor-primitives/modals.js +89 -0
  25. package/src/components/editor-primitives/pager.js +74 -0
  26. package/src/components/editor-primitives/property-grid.js +57 -0
  27. package/src/components/editor-primitives/shared.js +18 -0
  28. package/src/components/editor-primitives/split-panel.js +101 -0
  29. package/src/components/editor-primitives/toast.js +59 -0
  30. package/src/components/editor-primitives/tree.js +75 -0
  31. package/src/components/editor-primitives.js +35 -1048
  32. package/src/components/files-modals.js +1 -1
  33. package/src/components/overlay-primitives/approval-prompt.js +38 -0
  34. package/src/components/overlay-primitives/auth-modal.js +89 -0
  35. package/src/components/overlay-primitives/command-palette.js +101 -0
  36. package/src/components/overlay-primitives/emoji-picker.js +103 -0
  37. package/src/components/overlay-primitives/floating.js +146 -0
  38. package/src/components/overlay-primitives/full-screen.js +45 -0
  39. package/src/components/overlay-primitives/menus.js +135 -0
  40. package/src/components/overlay-primitives/popover.js +51 -0
  41. package/src/components/overlay-primitives/roving-menu.js +73 -0
  42. package/src/components/overlay-primitives/settings-popover.js +85 -0
  43. package/src/components/overlay-primitives/tooltip.js +55 -0
  44. package/src/components/overlay-primitives.js +33 -855
  45. package/src/css/app-shell/base.css +54 -1
  46. package/src/css/app-shell/chat-polish.css +39 -32
  47. package/src/css/app-shell/data-density.css +25 -21
  48. package/src/css/app-shell/files.css +37 -29
  49. package/src/css/app-shell/kits-appended.css +92 -50
  50. package/src/css/app-shell/responsive.css +73 -35
  51. package/src/css/app-shell/responsive2-workspace.css +16 -4
  52. package/src/css/app-shell/states-interactions.css +21 -4
  53. package/src/css/app-shell/topbar.css +5 -1
  54. package/src/kits/os/freddie-dashboard.css +2 -2
package/dist/247420.css CHANGED
@@ -681,7 +681,7 @@
681
681
  left: 0;
682
682
  background: var(--accent);
683
683
  color: var(--accent-fg);
684
- padding: 8px 16px;
684
+ padding: var(--space-2) var(--space-3);
685
685
  text-decoration: none;
686
686
  /* Must outrank every layer of chrome once focused, or the first Tab press
687
687
  lands on a control hidden behind the sticky header (was z-index:100,
@@ -696,6 +696,35 @@
696
696
  outline: var(--focus-w) solid var(--focus-color);
697
697
  outline-offset: var(--focus-offset);
698
698
  }
699
+ /* Visually-hidden but still in the accessibility tree. Emitted by Row() (the
700
+ rail status word), FilterBar()/FileGrid() (aria-live result counts) and
701
+ form-primitives' required marker — all of which shipped BEFORE this rule
702
+ existed anywhere the app shell loads. The only other definitions live in
703
+ app-surfaces.css (pre-scoped to `.ds-247420`, so it never reaches a kit that
704
+ does not mount that root) and editor-primitives.css (a separate opt-in
705
+ <link>), which left every app-shell consumer rendering screen-reader-only
706
+ text VISIBLY the moment it passed `rail`/`resultCount`.
707
+ Deliberately NOT `display:none` / `visibility:hidden` / `width:0`: those
708
+ remove the node from the accessibility tree too, which defeats the entire
709
+ purpose — the text exists only for AT. The clip + 1px box is what keeps it
710
+ announced while occupying no visible area.
711
+ `margin: -1px` is OFF-SCALE ON PURPOSE — it is not rhythm, it is one half of
712
+ the canonical visually-hidden idiom: the negative margin cancels the 1px box
713
+ so the clipped element contributes zero layout. Snapping it to a --space-*
714
+ rung would reintroduce a measurable gap. `clip` is deprecated but retained
715
+ alongside `clip-path` for older AT/browser pairs that ignore the latter. */
716
+ .ds-247420 .sr-only {
717
+ position: absolute;
718
+ width: 1px;
719
+ height: 1px;
720
+ padding: 0;
721
+ margin: -1px;
722
+ overflow: hidden;
723
+ clip: rect(0, 0, 0, 0);
724
+ clip-path: inset(50%);
725
+ white-space: nowrap;
726
+ border: 0;
727
+ }
699
728
  .ds-247420 body {
700
729
  background: var(--bg);
701
730
  color: var(--fg);
@@ -784,6 +813,30 @@
784
813
  .ds-247420 .ds-prose h1 { font-size: clamp(34px, 5.4cqi, 64px); margin-bottom: var(--space-3); }
785
814
  .ds-247420 .ds-prose h2 { margin: var(--space-6) 0 var(--space-3); }
786
815
  .ds-247420 .ds-prose h3 { margin: var(--space-5) 0 var(--space-2); font-size: var(--fs-lg); font-weight: 600; }
816
+ /* Closing line of an article ("end. reply by opening a pr."), set off from the
817
+ body it terminates. Quieter and smaller than the prose around it: it takes
818
+ the mono face and the --fg-3 tone the house uses for ancillary voices
819
+ (.t-micro, .dim), so the endnote reads as chrome around the article rather
820
+ than a final paragraph of it. The --space-5 lead does the "set off" — it
821
+ breaks the paragraph rhythm so the eye registers the piece has ended before
822
+ reading the words; margin-bottom:0 overrides .ds-prose p's --space-4 so the
823
+ article does not end on dead space.
824
+ Lives here, beside the rest of the .ds-prose family, NOT in gm-prose.css:
825
+ the blog kit that uses this class links only colors_and_type.css +
826
+ app-shell.css, so a rule in that separately-<link>-ed export would be exactly
827
+ as undefined as the class was before. Sized at --fs-xs, not the --fs-micro
828
+ label rung: this is a readable sentence with a link in it, not a micro-label.
829
+ The link inherits .ds-prose a's --accent-ink treatment (a readable TEXT tone;
830
+ the bare --accent fill is ~1.07:1 on paper) — deliberately not re-stated. */
831
+ .ds-247420 .ds-prose .ds-prose-endnote,
832
+ .ds-247420 .ds-prose-endnote {
833
+ margin-top: var(--space-5);
834
+ margin-bottom: 0;
835
+ font-family: var(--ff-mono);
836
+ font-size: var(--fs-xs);
837
+ line-height: var(--lh-base);
838
+ color: var(--fg-3);
839
+ }
787
840
 
788
841
  .ds-247420 .dim { color: var(--fg-3); }
789
842
 
@@ -1028,7 +1081,11 @@
1028
1081
  border-radius: var(--r-pill);
1029
1082
  }
1030
1083
  /* The lime active pill is the sidebar's one accent moment; its own count
1031
- chip rides the ink-on-accent pair instead of a second competing hue. */
1084
+ chip rides the ink-on-accent pair instead of a second competing hue.
1085
+ The bare --accent here is deliberate and is NOT the usual accent-as-text
1086
+ defect: the chip's own background is --accent-fg (ink), so this is the
1087
+ INVERTED pair -- lime on ink, which is the high-contrast direction. Only
1088
+ accent-coloured text on a normal background needs --accent-ink. */
1032
1089
  .ds-247420 .app-side a.active .count {
1033
1090
  background: color-mix(in oklab, var(--accent-fg) 82%, transparent);
1034
1091
  color: var(--accent);
@@ -1963,7 +2020,7 @@
1963
2020
  brand and let it scroll horizontally. The brand stays on the first row;
1964
2021
  nav wraps to a second row at 100% width (flex-wrap on .app-topbar). */
1965
2022
  .ds-247420 .app-topbar {
1966
- gap: var(--space-2); padding: 12px var(--space-3);
2023
+ gap: var(--space-2); padding: var(--space-2-75) var(--space-3);
1967
2024
  }
1968
2025
  /* When the topbar is folded into .app-chrome it is a flex:0 0 auto child, so
1969
2026
  it sizes to its nav's content and overflows the viewport instead of letting
@@ -1972,7 +2029,7 @@
1972
2029
  .ds-247420 .app-chrome > .app-topbar { max-width: 100%; min-width: 0; flex-basis: 100%; }
1973
2030
  .ds-247420 .app-topbar > nav {
1974
2031
  flex: 1 1 100%; margin-left: 0; order: 3; min-width: 0; max-width: 100%;
1975
- display: flex; gap: 2px; flex-wrap: nowrap;
2032
+ display: flex; gap: var(--space-hair); flex-wrap: nowrap;
1976
2033
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
1977
2034
  /* Fade the trailing edge so a clipped last item (e.g. "source ->" cut to
1978
2035
  "sour") reads as scrollable content, not a broken/truncated label. */
@@ -1981,7 +2038,7 @@
1981
2038
  }
1982
2039
  .ds-247420 .app-topbar nav::-webkit-scrollbar { display: none; }
1983
2040
  .ds-247420 .app-topbar nav a {
1984
- flex: 0 0 auto; padding: 10px 12px; min-height: 44px; white-space: nowrap;
2041
+ flex: 0 0 auto; padding: var(--space-2-5) var(--space-2-75); min-height: 44px; white-space: nowrap;
1985
2042
  }
1986
2043
  .ds-247420 .brand { font-size: var(--fs-tiny); font-weight: 600; }
1987
2044
 
@@ -2002,21 +2059,36 @@
2002
2059
  .ds-247420 .panel-body { padding: var(--space-2); overflow-x: auto; -webkit-overflow-scrolling: touch; }
2003
2060
  .ds-247420 .panel-body > table { min-width: 100%; }
2004
2061
 
2005
- .ds-247420 .row {
2006
- grid-template-columns: minmax(0, 1fr) auto !important;
2007
- gap: var(--space-2); padding: 12px 16px;
2008
- row-gap: 4px !important;
2062
+ /* Scoped to the `.app` shell so this wins on SPECIFICITY (0,2,0) rather than
2063
+ on an !important flag. Three rules would otherwise beat a bare `.row`
2064
+ (0,1,0) here: `.row.row-nocode` (0,2,0, panel-row.css) out-specifies it,
2065
+ and the `@media(481-1024)` + `@media(max-width:768px)` `.row` rules later
2066
+ in THIS file win on source order (a media query adds no specificity).
2067
+ `.app` is safe to require: `.app-body`/`.row` only ever render inside it
2068
+ (single call site, shell.js AppShell). */
2069
+ .ds-247420 .app .row {
2070
+ grid-template-columns: minmax(0, 1fr) auto;
2071
+ gap: var(--space-2); padding: var(--space-2-75) var(--space-3);
2072
+ row-gap: var(--space-1);
2009
2073
  }
2010
2074
  .ds-247420 .row .sub { grid-column: 1 / -1; order: 3; }
2011
2075
  .ds-247420 .row .title { font-size: var(--fs-sm); }
2012
2076
  /* Changelog carries 3 children: give date+ver line one, message wraps below
2013
- (the generic 2-col .row override staggers it into an implicit row). */
2014
- .ds-247420 .ds-changelog-row { grid-template-columns: minmax(70px, 10ch) minmax(0, 1fr) !important; }
2077
+ (the generic 2-col .row override staggers it into an implicit row).
2078
+ Needs (0,3,0) to clear BOTH the `.app .row` rule directly above and
2079
+ `.ds-changelog-row`'s own !important base in hero-content.css — an
2080
+ !important base can only be beaten by another !important, so this one
2081
+ stays until that upstream flag is removed (hero-content.css is outside
2082
+ this change's scope). */
2083
+ .ds-247420 .app .row.ds-changelog-row { grid-template-columns: minmax(70px, 10ch) minmax(0, 1fr) !important; }
2015
2084
  .ds-247420 .ds-changelog-row .title { grid-column: 1 / -1; }
2016
2085
 
2017
2086
  /* Buttons */
2018
2087
  .ds-247420 .btn, .ds-247420 .btn-primary, .ds-247420 .btn-ghost {
2019
- padding: 11px 16px; font-size: var(--fs-tiny);
2088
+ /* 11px vertical is optical, not scale drift: --space-2-75 (12) would tip
2089
+ the intrinsic box past the 44px min-height floor below and make the
2090
+ floor dead, changing the mobile button rhythm. */
2091
+ padding: 11px var(--space-3); font-size: var(--fs-tiny);
2020
2092
  min-height: 44px; /* Touch target minimum */
2021
2093
  }
2022
2094
 
@@ -2024,13 +2096,13 @@
2024
2096
  .ds-247420 .ds-file-grid {
2025
2097
  display: flex;
2026
2098
  flex-direction: column;
2027
- gap: 3px;
2099
+ gap: var(--space-half);
2028
2100
  }
2029
2101
  .ds-247420 .ds-file-row {
2030
- gap: 8px; padding: 10px 12px;
2102
+ gap: var(--space-2); padding: var(--space-2-5) var(--space-2-75);
2031
2103
  font-size: var(--fs-xs);
2032
2104
  }
2033
- .ds-247420 .ds-file-open { gap: 10px; }
2105
+ .ds-247420 .ds-file-open { gap: var(--space-2-5); }
2034
2106
  /* At mobile row widths, a fixed-size meta column (date/size) plus the
2035
2107
  always-visible action buttons leave the flexible title only a few px —
2036
2108
  not enough for even one legible character before the two collide. Drop
@@ -2047,12 +2119,12 @@
2047
2119
  /* Chat */
2048
2120
  .ds-247420 .chat-stack { max-width: 100%; min-width: 0; }
2049
2121
  .ds-247420 .chat-bubble {
2050
- padding: 10px 12px; font-size: var(--fs-sm);
2122
+ padding: var(--space-2-5) var(--space-2-75); font-size: var(--fs-sm);
2051
2123
  }
2052
2124
  .ds-247420 .chat-avatar { width: 28px; height: 28px; font-size: 11px; }
2053
- .ds-247420 .chat-msg:hover { padding: 4px 0; margin: 0; background: transparent; }
2054
- .ds-247420 .chat-composer { padding: 8px; gap: 6px; }
2055
- .ds-247420 .chat-composer textarea { padding: 10px 12px; font-size: var(--fs-sm); }
2125
+ .ds-247420 .chat-msg:hover { padding: var(--space-1) 0; margin: 0; background: transparent; }
2126
+ .ds-247420 .chat-composer { padding: var(--space-2); gap: var(--space-1-75); }
2127
+ .ds-247420 .chat-composer textarea { padding: var(--space-2-5) var(--space-2-75); font-size: var(--fs-sm); }
2056
2128
 
2057
2129
  /* KPI Cards */
2058
2130
  .ds-247420 .kpi {
@@ -2068,9 +2140,10 @@
2068
2140
  .ds-247420 .empty { padding: var(--space-5); font-size: var(--fs-xs); }
2069
2141
 
2070
2142
  /* Form */
2071
- .ds-247420 .row-form { gap: 10px; padding: var(--space-3); }
2143
+ .ds-247420 .row-form { gap: var(--space-2-5); padding: var(--space-3); }
2072
2144
  .ds-247420 .row-form input,
2073
- .ds-247420 .row-form textarea { padding: 11px 12px; font-size: var(--fs-sm); }
2145
+
2146
+ .ds-247420 .row-form textarea { padding: 11px var(--space-2-75); font-size: var(--fs-sm); }
2074
2147
 
2075
2148
  /* Hero Section — keep fluid base font-size, just unconstrain width on mobile. */
2076
2149
  .ds-247420 .ds-hero { padding: var(--space-6) 0 var(--space-5); }
@@ -2080,26 +2153,34 @@
2080
2153
  /* Table Responsiveness */
2081
2154
  .ds-247420 table { font-size: var(--fs-xs); }
2082
2155
  .ds-247420 table th,
2083
- .ds-247420 table td { padding: 10px 12px; }
2156
+ .ds-247420 table td { padding: var(--space-2-5) var(--space-2-75); }
2084
2157
 
2085
2158
  /* CLI Block */
2086
2159
  .ds-247420 .cli {
2087
- flex-direction: column; align-items: flex-start; gap: 10px;
2088
- padding: 16px 12px; font-size: var(--fs-xs);
2160
+ flex-direction: column; align-items: flex-start; gap: var(--space-2-5);
2161
+ padding: var(--space-3) var(--space-2-75); font-size: var(--fs-xs);
2089
2162
  }
2090
- .ds-247420 .cli .copy { padding: 6px 12px; font-size: var(--fs-micro); }
2163
+ .ds-247420 .cli .copy { padding: var(--space-1-75) var(--space-2-75); font-size: var(--fs-micro); }
2091
2164
  }
2092
2165
 
2093
2166
  /* --------------------------------------------------------------------
2094
2167
  Container Query Responsive (720px and below)
2095
2168
  ---------------------------------------------------------------------- */
2096
2169
  @container (max-width: 760px) {
2097
- .ds-247420 .app-body { grid-template-columns: 1fr !important; }
2170
+ /* `.app`-scoped for specificity, not an !important flag: the bare `.app-body`
2171
+ (0,1,0) was out-specified by `.app-body.no-side` (0,2,0) in topbar.css, so
2172
+ a sidebar-less shell kept its base template. `.app .app-body` is (0,2,0)
2173
+ and lands later in source, beating both topbar.css rules on merit. */
2174
+ .ds-247420 .app .app-body { grid-template-columns: 1fr; }
2098
2175
  .ds-247420 .app-side-shell { border-right: 0; border-bottom: 1px solid var(--rule); }
2099
- .ds-247420 .app-topbar nav { font-size: var(--fs-xs); gap: 14px; }
2100
- .ds-247420 .row { grid-template-columns: minmax(0, 1fr) auto !important; row-gap: 4px !important; }
2176
+ .ds-247420 .app-topbar nav { font-size: var(--fs-xs); gap: var(--space-2-75); }
2177
+ /* Same (0,2,0) lift as the 480px block above — clears `.row.row-nocode` and
2178
+ the later `@media` `.row` rules in this file without a flag. */
2179
+ .ds-247420 .app .row { grid-template-columns: minmax(0, 1fr) auto; row-gap: var(--space-1); }
2101
2180
  .ds-247420 .row .sub { grid-column: 1 / -1; order: 3; }
2102
- .ds-247420 .ds-changelog-row { grid-template-columns: minmax(70px, 10ch) minmax(0, 1fr) !important; }
2181
+ /* (0,3,0) + !important: still required to beat `.ds-changelog-row`'s
2182
+ !important base in hero-content.css (see the 480px block). */
2183
+ .ds-247420 .app .row.ds-changelog-row { grid-template-columns: minmax(70px, 10ch) minmax(0, 1fr) !important; }
2103
2184
  .ds-247420 .ds-changelog-row .title { grid-column: 1 / -1; }
2104
2185
  }
2105
2186
 
@@ -2109,7 +2190,7 @@
2109
2190
  @media (min-width: 481px) and (max-width: 1024px) {
2110
2191
  /* App Layout — side handled by 900px drawer block; restore for 901-1024 */
2111
2192
  .ds-247420 .app-side a {
2112
- padding: 12px 12px; gap: 8px;
2193
+ padding: var(--space-2-75) var(--space-2-75); gap: var(--space-2);
2113
2194
  grid-template-columns: 16px 1fr auto;
2114
2195
  font-size: var(--fs-xs);
2115
2196
  min-height: 44px;
@@ -2117,14 +2198,14 @@
2117
2198
 
2118
2199
  /* Topbar Navigation (flex container — no grid-template here) */
2119
2200
  .ds-247420 .app-topbar {
2120
- gap: var(--space-3); padding: 12px var(--space-4);
2201
+ gap: var(--space-3); padding: var(--space-2-75) var(--space-4);
2121
2202
  }
2122
2203
  .ds-247420 .app-topbar nav {
2123
- display: flex; gap: 8px; font-size: var(--fs-xs);
2204
+ display: flex; gap: var(--space-2); font-size: var(--fs-xs);
2124
2205
  flex-wrap: wrap;
2125
2206
  }
2126
2207
  .ds-247420 .app-topbar nav a {
2127
- padding: 12px 12px; font-size: var(--fs-xs);
2208
+ padding: var(--space-2-75) var(--space-2-75); font-size: var(--fs-xs);
2128
2209
  min-height: 44px;
2129
2210
  }
2130
2211
  .ds-247420 .brand { font-size: var(--fs-sm); }
@@ -2133,7 +2214,10 @@
2133
2214
  .ds-247420 .app-search {
2134
2215
  display: inline-flex;
2135
2216
  max-width: 280px; font-size: var(--fs-xs);
2136
- padding: 8px 14px;
2217
+ /* 14px inline is between --space-2-75 (12) and --space-3 (16) with no tier;
2218
+ it is the width that centers the search glyph against the 280px max-width
2219
+ field. Snapping either way reads as a mis-centered control. */
2220
+ padding: var(--space-2) 14px;
2137
2221
  }
2138
2222
 
2139
2223
  /* Main Content */
@@ -2145,12 +2229,17 @@
2145
2229
  /* File list — single column rows on tablet (cards only via data-columns) */
2146
2230
  .ds-247420 .ds-file-row {
2147
2231
  grid-template-columns: 24px minmax(0, 1fr) auto auto;
2148
- gap: 12px; padding: 12px 14px;
2232
+ /* 14px inline (no tier between 12 and 16) is the tablet row inset that
2233
+ keeps the 24px icon column optically flush with the panel edge. */
2234
+ gap: var(--space-2-75); padding: var(--space-2-75) 14px;
2149
2235
  }
2150
2236
 
2151
2237
  /* Chat Bubbles */
2152
2238
  .ds-247420 .chat-stack { max-width: min(75%, 420px); }
2153
2239
  .ds-247420 .chat-bubble {
2240
+ /* 11px/14px are the tuned tablet bubble insets; neither is on the scale
2241
+ (11 sits between --space-2-5 and --space-2-75, 14 between --space-2-75
2242
+ and --space-3) and snapping visibly re-pitches every bubble in a thread. */
2154
2243
  padding: 11px 14px; font-size: var(--fs-sm);
2155
2244
  }
2156
2245
  .ds-247420 .chat-avatar { width: 32px; height: 32px; font-size: 12px; }
@@ -2163,7 +2252,10 @@
2163
2252
 
2164
2253
  /* Buttons */
2165
2254
  .ds-247420 .btn, .ds-247420 .btn-primary, .ds-247420 .btn-ghost {
2166
- padding: 12px 18px; font-size: var(--fs-sm);
2255
+ /* 18px inline has no tier (--space-3 is 16, --space-3-5 is 20); it is the
2256
+ tablet CTA width tuned against the 12px vertical, so snapping changes
2257
+ the button aspect on the most visible control in the kit. */
2258
+ padding: var(--space-2-75) 18px; font-size: var(--fs-sm);
2167
2259
  }
2168
2260
 
2169
2261
  /* Panel - keep the head on the body's left axis at laptop widths too. */
@@ -2177,7 +2269,9 @@
2177
2269
  /* Row */
2178
2270
  .ds-247420 .row {
2179
2271
  grid-template-columns: minmax(90px, 12ch) minmax(0, 1fr) auto;
2180
- gap: var(--space-2); padding: 14px 16px;
2272
+ /* 14px block (no tier between 12 and 16) is the tablet row height tuned
2273
+ against the 12ch code column; snapping re-pitches the whole list. */
2274
+ gap: var(--space-2); padding: 14px var(--space-3);
2181
2275
  }
2182
2276
  }
2183
2277
 
@@ -2235,7 +2329,7 @@
2235
2329
  .ds-247420 .ds-file-grid {
2236
2330
  display: flex;
2237
2331
  flex-direction: column;
2238
- gap: 4px;
2332
+ gap: var(--space-1);
2239
2333
  }
2240
2334
  .ds-247420 .ds-file-grid:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); border-radius: var(--r-2); }
2241
2335
 
@@ -2246,7 +2340,7 @@
2246
2340
  /* The filter is now an inline item in the single .ds-file-controls toolbar row
2247
2341
  (the standalone right-aligned .ds-file-filter strip was removed). */
2248
2342
  .ds-247420 .ds-file-filter-input {
2249
- width: min(280px, 100%); padding: 6px 12px; font-size: var(--fs-sm);
2343
+ width: min(280px, 100%); padding: var(--space-1-75) var(--space-2-75); font-size: var(--fs-sm);
2250
2344
  background: var(--bg); color: var(--fg);
2251
2345
  border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1);
2252
2346
  }
@@ -2256,7 +2350,7 @@
2256
2350
  .ds-247420 .ds-file-sort { display: flex; gap: var(--space-2); padding: 0 var(--space-2) var(--space-1); }
2257
2351
  .ds-247420 .ds-file-sort-btn {
2258
2352
  font-size: var(--fs-tiny); font-family: var(--ff-mono); color: var(--fg-3);
2259
- background: none; border: none; cursor: pointer; padding: 2px 4px; border-radius: var(--r-1);
2353
+ background: none; border: none; cursor: pointer; padding: var(--space-hair) var(--space-1); border-radius: var(--r-1);
2260
2354
  }
2261
2355
  .ds-247420 .ds-file-sort-btn:hover { color: var(--fg-2); background: var(--bg-2); }
2262
2356
  .ds-247420 .ds-file-sort-btn.active { color: var(--accent-ink); }
@@ -2271,9 +2365,9 @@
2271
2365
  .ds-247420 .ds-file-grid { transition: opacity .15s var(--ease); }
2272
2366
  }
2273
2367
  /* EventList loading skeleton (shares the .ds-skel shimmer base above). */
2274
- .ds-247420 .ds-event-row-skeleton { display: flex; align-items: center; gap: var(--space-3); padding: 12px 16px; pointer-events: none; }
2368
+ .ds-247420 .ds-event-row-skeleton { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2-75) var(--space-3); pointer-events: none; }
2275
2369
  .ds-247420 .ds-skel-rank { height: 12px; width: 2.5ch; }
2276
- .ds-247420 .ds-event-state { padding: var(--space-2) 16px; }
2370
+ .ds-247420 .ds-event-state { padding: var(--space-2) var(--space-3); }
2277
2371
  .ds-247420 .ds-skel { display: inline-block; border-radius: var(--r-1); background: var(--bg-2); position: relative; overflow: hidden; }
2278
2372
  .ds-247420 .ds-skel::after {
2279
2373
  content: ''; position: absolute; inset: 0;
@@ -2292,8 +2386,13 @@
2292
2386
  because FileRow wraps the row content in a real button for native keyboard
2293
2387
  semantics. */
2294
2388
  .ds-247420 .ds-file-row {
2295
- display: flex; align-items: center; gap: 10px;
2296
- padding: 11px 16px; background: var(--bg);
2389
+ display: flex; align-items: center; gap: var(--space-2-5);
2390
+ /* 11px vertical is an optical half-step between --space-2-5 (10) and
2391
+ --space-2-75 (12), deliberately off-scale: with the 26px .ds-file-icon
2392
+ and the hairline borders it lands the row at ~50px, comfortably over the
2393
+ 44px touch floor without the 52px a 12px pad would give. Snapping either
2394
+ way visibly re-pitches every row in a long listing. */
2395
+ padding: 11px var(--space-3); background: var(--bg);
2297
2396
  border: var(--bw-hair) solid transparent;
2298
2397
  border-radius: var(--r-2); color: var(--fg);
2299
2398
  cursor: pointer;
@@ -2302,7 +2401,7 @@
2302
2401
  transform var(--dur-snap) var(--ease);
2303
2402
  }
2304
2403
  .ds-247420 .ds-file-open {
2305
- display: flex; align-items: center; gap: 14px;
2404
+ display: flex; align-items: center; gap: var(--space-2-75);
2306
2405
  flex: 1 1 auto; min-width: 0;
2307
2406
  background: none; border: 0; padding: 0; margin: 0;
2308
2407
  color: inherit; font: inherit; text-align: left; cursor: pointer;
@@ -2365,7 +2464,7 @@
2365
2464
  hidden, which left mouse/trackpad users unable to find rename/move/delete
2366
2465
  without accidentally hovering a row), full opacity on hover/focus. */
2367
2466
  .ds-247420 .ds-file-actions {
2368
- display: inline-flex; gap: 2px; align-items: center;
2467
+ display: inline-flex; gap: var(--space-hair); align-items: center;
2369
2468
  opacity: 0.35; transition: opacity var(--dur-base) var(--ease);
2370
2469
  }
2371
2470
  .ds-247420 .ds-file-row:hover .ds-file-actions,
@@ -2410,7 +2509,7 @@
2410
2509
 
2411
2510
  .ds-247420 .ds-file-check {
2412
2511
  display: inline-flex; align-items: center; justify-content: center;
2413
- min-width: 28px; height: 28px; padding: 0 4px;
2512
+ min-width: 28px; height: 28px; padding: 0 var(--space-1);
2414
2513
  background: transparent; border: 0; border-radius: var(--r-1);
2415
2514
  color: var(--fg-3);
2416
2515
  cursor: pointer;
@@ -2442,7 +2541,7 @@
2442
2541
  quiet destructive outline - the app arm-confirms destructive bulk actions
2443
2542
  via ConfirmDialog, so the strip never needs a loud CTA. */
2444
2543
  .ds-247420 .ds-bulkbar .btn, .ds-247420 .ds-bulkbar .btn-primary {
2445
- padding: 5px 12px; min-height: 32px; border-radius: var(--r-1); font-weight: 500;
2544
+ padding: var(--space-1-5) var(--space-2-75); min-height: 32px; border-radius: var(--r-1); font-weight: 500;
2446
2545
  }
2447
2546
  .ds-247420 .ds-bulkbar .btn { background: transparent; border: var(--bw-hair) solid var(--rule); color: var(--fg-2); }
2448
2547
  .ds-247420 .ds-bulkbar .btn:hover { background: var(--bg-2); color: var(--fg); }
@@ -2454,7 +2553,7 @@
2454
2553
 
2455
2554
  /* Density picker — list / compact / thumbnails. */
2456
2555
  .ds-247420 .ds-density {
2457
- display: inline-flex; gap: 2px; padding: 2px;
2556
+ display: inline-flex; gap: var(--space-hair); padding: var(--space-hair);
2458
2557
  background: var(--bg-2); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1);
2459
2558
  }
2460
2559
  .ds-247420 .ds-density-btn {
@@ -2469,8 +2568,8 @@
2469
2568
  .ds-247420 .ds-density-btn:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
2470
2569
 
2471
2570
  /* Compact density — tighter rows for long listings. */
2472
- .ds-247420 .ds-file-grid[data-density="compact"] { gap: 2px; }
2473
- .ds-247420 .ds-file-grid[data-density="compact"] .ds-file-row { padding: 5px 12px; gap: 10px; }
2571
+ .ds-247420 .ds-file-grid[data-density="compact"] { gap: var(--space-hair); }
2572
+ .ds-247420 .ds-file-grid[data-density="compact"] .ds-file-row { padding: var(--space-1-5) var(--space-2-75); gap: var(--space-2-5); }
2474
2573
  .ds-247420 .ds-file-grid[data-density="compact"] .ds-file-row .title { font-size: var(--fs-xs); }
2475
2574
  .ds-247420 .ds-file-grid[data-density="compact"] .ds-file-row .ds-file-meta { font-size: var(--fs-micro); }
2476
2575
  .ds-247420 .ds-file-grid[data-density="compact"] .ds-file-icon { width: 20px; height: 20px; font-size: 13px; }
@@ -2492,11 +2591,14 @@
2492
2591
  .ds-247420 .ds-file-cell.is-locked { opacity: 0.6; }
2493
2592
  .ds-247420 .ds-file-row.is-locked { opacity: 0.6; }
2494
2593
  .ds-247420 .ds-file-row.is-restricted .title { color: var(--fg-2); }
2495
- /* A fourth, deliberately bordered/mono tag variant for file-permission tags
2594
+ /* 1px vertical pad is deliberately below --space-hair (2px): this mono tag
2595
+ sits inline in a file row and must not add height to it; --space-hair would
2596
+ double the vertical pad and push the tag past the row cap height.
2597
+ A fourth, deliberately bordered/mono tag variant for file-permission tags
2496
2598
  specifically (distinct from .ds-badge for numeric counts and .chip for
2497
2599
  status/label words) - is-noaccess reuses the shared --flame tone token
2498
2600
  so 'no access' reads the same red as chip.tone-error/miss elsewhere. */
2499
- .ds-247420 .ds-file-perm-tag { font-family: var(--ff-mono); font-size: var(--fs-micro); color: var(--fg-3); padding: 1px 6px; border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1); white-space: nowrap; }
2601
+ .ds-247420 .ds-file-perm-tag { font-family: var(--ff-mono); font-size: var(--fs-micro); color: var(--fg-3); padding: 1px var(--space-1-75); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1); white-space: nowrap; }
2500
2602
  .ds-247420 .ds-file-perm-tag.is-noaccess { color: var(--flame); border-color: var(--flame); }
2501
2603
  .ds-247420 .ds-file-cell-open {
2502
2604
  display: flex; flex-direction: column; align-items: stretch; gap: var(--space-1);
@@ -2565,12 +2667,12 @@
2565
2667
 
2566
2668
  /* Breadcrumb path */
2567
2669
  .ds-247420 .ds-crumb-path {
2568
- display: flex; align-items: center; flex-wrap: wrap; gap: 2px;
2670
+ display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-hair);
2569
2671
  font-size: var(--fs-sm);
2570
2672
  }
2571
2673
  .ds-247420 .ds-crumb-seg {
2572
2674
  background: transparent; border: 0; cursor: pointer;
2573
- padding: 4px 8px; border-radius: var(--r-1);
2675
+ padding: var(--space-1) var(--space-2); border-radius: var(--r-1);
2574
2676
  color: var(--fg-3); font-family: inherit; font-size: var(--fs-sm);
2575
2677
  transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
2576
2678
  /* A single long unbroken segment (hash-named dir) must never force the
@@ -2618,7 +2720,7 @@
2618
2720
  /* Toolbar-scoped buttons: quiet, compact, rectangular - a toolbar is chrome,
2619
2721
  not a CTA row; the stadium pill stays for real page-level actions. */
2620
2722
  .ds-247420 .ds-file-toolbar .btn, .ds-247420 .ds-file-toolbar .btn-ghost {
2621
- padding: 5px 12px; min-height: 32px;
2723
+ padding: var(--space-1-5) var(--space-2-75); min-height: 32px;
2622
2724
  border-radius: var(--r-1);
2623
2725
  font-weight: 500;
2624
2726
  background: transparent;
@@ -2635,7 +2737,7 @@
2635
2737
 
2636
2738
  /* Error banner — dismissible toast row. */
2637
2739
  .ds-247420 .ds-error-banner {
2638
- padding: 10px 14px; border-radius: var(--r-2);
2740
+ padding: var(--space-2-5) var(--space-2-75); border-radius: var(--r-2);
2639
2741
  background: color-mix(in oklab, var(--warn) 14%, var(--bg));
2640
2742
  border: var(--bw-hair) solid color-mix(in oklab, var(--warn) 40%, transparent);
2641
2743
  color: var(--warn); font-size: var(--fs-sm); cursor: pointer;
@@ -2692,11 +2794,11 @@
2692
2794
  }
2693
2795
 
2694
2796
  /* Upload progress */
2695
- .ds-247420 .ds-upload-progress { display: flex; flex-direction: column; gap: 6px; }
2797
+ .ds-247420 .ds-upload-progress { display: flex; flex-direction: column; gap: var(--space-1-75); }
2696
2798
  .ds-247420 .ds-upload-item {
2697
2799
  display: grid; grid-template-columns: minmax(0, 1fr) 120px 44px;
2698
2800
  gap: var(--space-2); align-items: center;
2699
- padding: 8px 12px; border-radius: var(--r-2);
2801
+ padding: var(--space-2) var(--space-2-75); border-radius: var(--r-2);
2700
2802
  background: var(--bg-2); font-size: var(--fs-xs);
2701
2803
  }
2702
2804
  .ds-247420 .ds-upload-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@@ -2740,7 +2842,7 @@
2740
2842
  }
2741
2843
  .ds-247420 .ds-upload-actions { display: inline-flex; gap: var(--space-1); justify-content: flex-end; }
2742
2844
  .ds-247420 .ds-upload-act {
2743
- padding: 2px 10px; min-height: 24px; cursor: pointer;
2845
+ padding: var(--space-hair) var(--space-2-5); min-height: 24px; cursor: pointer;
2744
2846
  background: var(--bg); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1);
2745
2847
  color: var(--fg-2); font-family: var(--ff-body); font-size: var(--fs-micro);
2746
2848
  }
@@ -2810,7 +2912,7 @@
2810
2912
  border-top: var(--bw-hair) solid var(--rule);
2811
2913
  }
2812
2914
  .ds-247420 .ds-modal-input {
2813
- width: 100%; padding: 10px 12px;
2915
+ width: 100%; padding: var(--space-2-5) var(--space-2-75);
2814
2916
  background: var(--bg-2); border: var(--bw-hair) solid var(--rule);
2815
2917
  border-radius: var(--r-2); color: var(--fg);
2816
2918
  font-family: inherit; font-size: var(--fs-sm);
@@ -2822,10 +2924,10 @@
2822
2924
  }
2823
2925
  /* PromptDialog's optional roots-chip row (destination-path prompts with more
2824
2926
  than one allowed root) - same chip idiom the cwd editor's roots row uses. */
2825
- .ds-247420 .ds-prompt-roots { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
2927
+ .ds-247420 .ds-prompt-roots { display: flex; align-items: center; gap: var(--space-1-75); flex-wrap: wrap; margin-top: var(--space-2); }
2826
2928
  .ds-247420 .ds-prompt-root-chip {
2827
2929
  background: var(--bg-2); border: var(--bw-hair) solid var(--rule); color: var(--fg-2);
2828
- border-radius: var(--r-pill); padding: 3px 10px; font: inherit; font-size: var(--fs-tiny);
2930
+ border-radius: var(--r-pill); padding: var(--space-half) var(--space-2-5); font: inherit; font-size: var(--fs-tiny);
2829
2931
  cursor: pointer;
2830
2932
  }
2831
2933
  .ds-247420 .ds-prompt-root-chip:hover { border-color: var(--accent); color: var(--fg); }
@@ -2834,7 +2936,7 @@
2834
2936
  /* In-body modal error (role=alert): mutation failures (409/403) surface INSIDE
2835
2937
  the dialog, not behind the fixed overlay. */
2836
2938
  .ds-247420 .ds-modal-error {
2837
- margin: var(--space-2) 0 0; padding: 8px 10px;
2939
+ margin: var(--space-2) 0 0; padding: var(--space-2) var(--space-2-5);
2838
2940
  border: var(--bw-hair) solid var(--flame); border-radius: var(--r-2);
2839
2941
  background: color-mix(in oklab, var(--flame) 12%, var(--bg));
2840
2942
  color: var(--flame); font-size: var(--fs-xs);
@@ -2862,7 +2964,7 @@
2862
2964
  color: var(--fg-3); white-space: nowrap;
2863
2965
  flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
2864
2966
  }
2865
- .ds-247420 .ds-preview-actions { display: inline-flex; gap: 2px; margin-left: auto; }
2967
+ .ds-247420 .ds-preview-actions { display: inline-flex; gap: var(--space-hair); margin-left: auto; }
2866
2968
  .ds-247420 .ds-preview-body {
2867
2969
  flex: 1; min-height: 0; overflow: auto;
2868
2970
  padding: var(--space-3) var(--space-4);
@@ -2949,7 +3051,7 @@
2949
3051
  .ds-247420 .ds-file-stage { padding: var(--space-3) var(--space-2); }
2950
3052
  /* Preview head: let it wrap and drop the nowrap meta (duplicated in body)
2951
3053
  so the close button can never be pushed past the modal edge. */
2952
- .ds-247420 .ds-preview-head { flex-wrap: wrap; row-gap: 4px; }
3054
+ .ds-247420 .ds-preview-head { flex-wrap: wrap; row-gap: var(--space-1); }
2953
3055
  .ds-247420 .ds-preview-meta { display: none; }
2954
3056
  }
2955
3057
 
@@ -3109,7 +3211,7 @@
3109
3211
  flex: 1; min-height: 0; gap: var(--space-3);
3110
3212
  }
3111
3213
  .ds-247420 .chat-head {
3112
- display: flex; align-items: baseline; gap: 8px;
3214
+ display: flex; align-items: baseline; gap: var(--space-2);
3113
3215
  padding: var(--space-3) 0 var(--space-2);
3114
3216
  font-family: var(--ff-mono); font-size: var(--fs-xs);
3115
3217
  color: var(--fg-3); text-transform: lowercase; letter-spacing: 0.02em;
@@ -3147,10 +3249,10 @@
3147
3249
  .ds-247420 .chat-empty-title { font-size: var(--fs-sm); margin: 0 0 var(--space-1); }
3148
3250
  .ds-247420 .chat-empty-sub { font-size: var(--fs-tiny); margin: 0; opacity: .7; }
3149
3251
 
3150
- .ds-247420 .chat-msg { display: flex; gap: 12px; align-items: flex-start; padding: 6px 0; position: relative; min-width: 0; }
3252
+ .ds-247420 .chat-msg { display: flex; gap: var(--space-2-75); align-items: flex-start; padding: var(--space-1-75) 0; position: relative; min-width: 0; }
3151
3253
  .ds-247420 .chat-msg.you { flex-direction: row-reverse; }
3152
3254
  .ds-247420 .chat-msg.you .chat-stack { align-items: flex-end; }
3153
- .ds-247420 .chat-msg:hover { background: color-mix(in oklab, var(--fg) 4%, transparent); padding: 6px 0; margin: 0; border-radius: var(--r-0); transition: background var(--dur-base) var(--ease); }
3255
+ .ds-247420 .chat-msg:hover { background: color-mix(in oklab, var(--fg) 4%, transparent); padding: var(--space-1-75) 0; margin: 0; border-radius: var(--r-0); transition: background var(--dur-base) var(--ease); }
3154
3256
 
3155
3257
  .ds-247420 .chat-avatar {
3156
3258
  width: 36px; height: 36px; flex-shrink: 0;
@@ -3172,13 +3274,16 @@
3172
3274
  }
3173
3275
 
3174
3276
  .ds-247420 .chat-stack {
3175
- display: flex; flex-direction: column; gap: 4px;
3277
+ display: flex; flex-direction: column; gap: var(--space-1);
3176
3278
  max-width: min(70%, 56ch); min-width: 0;
3177
3279
  flex: 0 1 auto; overflow: hidden;
3178
3280
  }
3179
3281
 
3180
3282
  .ds-247420 .chat-bubble {
3181
- padding: 10px 14px; background: var(--bg-2); color: var(--fg);
3283
+ /* 14px inline has no tier (--space-2-75 is 12, --space-3 is 16). It is the
3284
+ shared bubble/attachment inset used by .chat-file/.chat-pdf-head below;
3285
+ snapping only this one would visibly desync the bubble from its cards. */
3286
+ padding: var(--space-2-5) 14px; background: var(--bg-2); color: var(--fg);
3182
3287
  max-width: 100%;
3183
3288
  border-radius: var(--r-2); line-height: 1.55;
3184
3289
  word-wrap: break-word; overflow-wrap: anywhere;
@@ -3196,7 +3301,9 @@
3196
3301
  .ds-247420 .chat-bubble code {
3197
3302
  font-family: var(--ff-mono); font-size: 0.92em;
3198
3303
  background: color-mix(in oklab, var(--fg) 10%, transparent);
3199
- padding: 1px 6px; border-radius: var(--r-0);
3304
+ /* 1px block is deliberately under --space-hair (2px): inline <code> must not
3305
+ grow the line box of the prose it sits inside. */
3306
+ padding: 1px var(--space-1-75); border-radius: var(--r-0);
3200
3307
  }
3201
3308
  .ds-247420 .chat-msg.you .chat-bubble code { background: color-mix(in oklab, var(--fg) 10%, transparent); }
3202
3309
  .ds-247420 .chat-bubble a {
@@ -3223,10 +3330,11 @@
3223
3330
  .ds-247420 .chat-bubble.chat-md h3 { font-size: 1.04em; }
3224
3331
  .ds-247420 .chat-bubble.chat-md p { margin: var(--space-2) 0; }
3225
3332
  .ds-247420 .chat-bubble.chat-md ul,
3333
+
3226
3334
  .ds-247420 .chat-bubble.chat-md ol { margin: var(--space-2) 0; padding-left: 22px; }
3227
3335
  .ds-247420 .chat-bubble.chat-md li { margin: var(--space-1) 0; }
3228
3336
  .ds-247420 .chat-bubble.chat-md blockquote {
3229
- margin: var(--space-2) 0; padding: 4px 12px;
3337
+ margin: var(--space-2) 0; padding: var(--space-1) var(--space-2-75);
3230
3338
  /* DELIBERATE, but slimmed to the --bw-rule tier. This is a real markdown
3231
3339
  <blockquote> inside a chat bubble: the left rule is the standard
3232
3340
  typographic quotation mark, not a colored alert stripe (the tone is a
@@ -3238,7 +3346,7 @@
3238
3346
  .ds-247420 .chat-bubble.chat-md pre {
3239
3347
  background: var(--bg);
3240
3348
  border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent);
3241
- padding: 12px 16px; border-radius: var(--r-1); overflow-x: auto;
3349
+ padding: var(--space-2-75) var(--space-3); border-radius: var(--r-1); overflow-x: auto;
3242
3350
  font-family: var(--ff-mono); font-size: var(--fs-xs); line-height: 1.55;
3243
3351
  color: var(--fg); margin: var(--space-2) 0;
3244
3352
  }
@@ -3252,11 +3360,11 @@
3252
3360
  }
3253
3361
  /* Markdown tables + horizontal rules: agents routinely emit them, but they were
3254
3362
  unstyled (bare unspaced cells, vanished rules). */
3255
- .ds-247420 .chat-bubble.chat-md table { border-collapse: collapse; width: auto; max-width: 100%; margin: 8px 0; font-size: .95em; display: block; overflow-x: auto; }
3363
+ .ds-247420 .chat-bubble.chat-md table { border-collapse: collapse; width: auto; max-width: 100%; margin: var(--space-2) 0; font-size: .95em; display: block; overflow-x: auto; }
3256
3364
  .ds-247420 .chat-bubble.chat-md th,
3257
- .ds-247420 .chat-bubble.chat-md td { border: var(--bw-hair) solid var(--rule); padding: 4px 10px; text-align: left; }
3365
+ .ds-247420 .chat-bubble.chat-md td { border: var(--bw-hair) solid var(--rule); padding: var(--space-1) var(--space-2-5); text-align: left; }
3258
3366
  .ds-247420 .chat-bubble.chat-md th { background: color-mix(in oklab, var(--fg) 5%, transparent); font-weight: 600; }
3259
- .ds-247420 .chat-bubble.chat-md hr { border: 0; border-top: var(--bw-hair) solid var(--rule); margin: 12px 0; }
3367
+ .ds-247420 .chat-bubble.chat-md hr { border: 0; border-top: var(--bw-hair) solid var(--rule); margin: var(--space-2-75) 0; }
3260
3368
 
3261
3369
  /* Mermaid diagram blocks — rendered SVG swapped in over the fenced source by
3262
3370
  src/mermaid.js's renderMermaidBlocksUnder(); the source .pre stays in the
@@ -3264,7 +3372,7 @@
3264
3372
  .ds-247420 .ds-mermaid-block {
3265
3373
  position: relative; margin: var(--space-2) 0;
3266
3374
  border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent);
3267
- border-radius: var(--r-1); background: var(--bg); padding: 12px 16px;
3375
+ border-radius: var(--r-1); background: var(--bg); padding: var(--space-2-75) var(--space-3);
3268
3376
  }
3269
3377
  .ds-247420 .ds-mermaid-diagram { overflow-x: auto; display: flex; justify-content: center; }
3270
3378
  .ds-247420 .ds-mermaid-diagram svg { max-width: 100%; height: auto; }
@@ -3273,7 +3381,7 @@
3273
3381
  font: inherit; font-size: var(--fs-xs); line-height: 1;
3274
3382
  background: color-mix(in oklab, var(--fg) 8%, transparent);
3275
3383
  color: var(--fg); border: none; border-radius: var(--r-1);
3276
- padding: 4px 8px; cursor: pointer;
3384
+ padding: var(--space-1) var(--space-2); cursor: pointer;
3277
3385
  }
3278
3386
  .ds-247420 .ds-mermaid-toggle:hover { background: color-mix(in oklab, var(--fg) 14%, transparent); }
3279
3387
 
@@ -3306,8 +3414,8 @@
3306
3414
  min-width: 0;
3307
3415
  }
3308
3416
  .ds-247420 .chat-code-head {
3309
- display: flex; align-items: center; gap: 10px;
3310
- padding: 8px 12px;
3417
+ display: flex; align-items: center; gap: var(--space-2-5);
3418
+ padding: var(--space-2) var(--space-2-75);
3311
3419
  background: color-mix(in oklab, var(--fg) 6%, var(--bg-2));
3312
3420
  border-bottom: 1px solid color-mix(in oklab, var(--fg) 12%, transparent);
3313
3421
  font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3);
@@ -3317,7 +3425,7 @@
3317
3425
  .ds-247420 .chat-code-head .name { color: var(--fg-2); font-weight: 500; }
3318
3426
  .ds-247420 .chat-code-head .spread { flex: 1; }
3319
3427
  .ds-247420 .chat-bubble.chat-code pre {
3320
- margin: 0; padding: 12px 16px; background: transparent;
3428
+ margin: 0; padding: var(--space-2-75) var(--space-3); background: transparent;
3321
3429
  font-family: var(--ff-mono); font-size: var(--fs-xs); line-height: 1.55;
3322
3430
  overflow-x: auto; color: var(--fg); border-radius: 0;
3323
3431
  }
@@ -3349,12 +3457,12 @@
3349
3457
  }
3350
3458
  .ds-247420 .chat-image img { display: block; width: 100%; height: auto; max-height: 360px; object-fit: cover; }
3351
3459
  .ds-247420 .chat-image .cap,
3352
- .ds-247420 .chat-image .caption { display: block; padding: 8px 12px; font-size: var(--fs-xs); color: var(--fg-3); font-family: var(--ff-mono); }
3460
+ .ds-247420 .chat-image .caption { display: block; padding: var(--space-2) var(--space-2-75); font-size: var(--fs-xs); color: var(--fg-3); font-family: var(--ff-mono); }
3353
3461
 
3354
3462
  .ds-247420 .chat-msg.you .chat-file,
3355
3463
  .ds-247420 .chat-msg .chat-file,
3356
3464
  .ds-247420 .chat-file {
3357
- display: flex; align-items: center; gap: 12px; padding: 12px 14px;
3465
+ display: flex; align-items: center; gap: var(--space-2-75); padding: var(--space-2-75) 14px;
3358
3466
  background: var(--bg-2); border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
3359
3467
  border-radius: var(--r-1); text-decoration: none; color: var(--fg);
3360
3468
  max-width: min(100%, 360px);
@@ -3367,12 +3475,12 @@
3367
3475
  background: var(--bg-3);
3368
3476
  color: var(--fg-2); border-radius: var(--r-0); flex-shrink: 0; font-family: var(--ff-mono);
3369
3477
  }
3370
- .ds-247420 .chat-file > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
3478
+ .ds-247420 .chat-file > div { display: flex; flex-direction: column; gap: var(--space-hair); min-width: 0; }
3371
3479
  .ds-247420 .chat-file .name {
3372
3480
  font-weight: 600; font-size: var(--fs-sm);
3373
3481
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
3374
3482
  }
3375
- .ds-247420 .chat-file .meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
3483
+ .ds-247420 .chat-file .meta { display: flex; flex-direction: column; gap: var(--space-hair); min-width: 0; flex: 1; }
3376
3484
  .ds-247420 .chat-file .size { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); }
3377
3485
  .ds-247420 .chat-file .go { font-family: var(--ff-mono); font-size: 16px; color: var(--fg-3); flex-shrink: 0; }
3378
3486
  .ds-247420 .chat-file:hover .go { color: var(--accent-ink); }
@@ -3388,7 +3496,7 @@
3388
3496
  }
3389
3497
  .ds-247420 .chat-msg:hover .chat-pdf { border-color: var(--rule); }
3390
3498
  .ds-247420 .chat-pdf-head {
3391
- display: flex; align-items: center; gap: 10px; padding: 10px 14px;
3499
+ display: flex; align-items: center; gap: var(--space-2-5); padding: var(--space-2-5) 14px;
3392
3500
  background: color-mix(in oklab, var(--fg) 5%, var(--bg-2));
3393
3501
  border-bottom: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
3394
3502
  }
@@ -3403,7 +3511,7 @@
3403
3511
  .ds-247420 .chat-msg.you .chat-link,
3404
3512
  .ds-247420 .chat-msg .chat-link,
3405
3513
  .ds-247420 .chat-link {
3406
- display: grid; grid-template-columns: 80px 1fr; gap: 12px; padding: 10px;
3514
+ display: grid; grid-template-columns: 80px 1fr; gap: var(--space-2-75); padding: var(--space-2-5);
3407
3515
  background: var(--bg-2);
3408
3516
  border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
3409
3517
  border-radius: var(--r-1); text-decoration: none; color: var(--fg);
@@ -3417,28 +3525,28 @@
3417
3525
  .ds-247420 .chat-link:not(:has(.thumb)):not(:has(img)) { grid-template-columns: 1fr; }
3418
3526
  .ds-247420 .chat-link .thumb,
3419
3527
  .ds-247420 .chat-link img.thumb { width: 80px; height: 80px; border-radius: var(--r-0); object-fit: cover; background: var(--bg-3) center/cover no-repeat; }
3420
- .ds-247420 .chat-link .meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
3528
+ .ds-247420 .chat-link .meta { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
3421
3529
  .ds-247420 .chat-link .host { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); text-transform: lowercase; }
3422
3530
  .ds-247420 .chat-link .title { font-weight: 600; font-size: var(--fs-sm); line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
3423
3531
  .ds-247420 .chat-link .desc { font-size: var(--fs-xs); color: var(--fg-2); line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
3424
3532
 
3425
3533
  .ds-247420 .chat-meta {
3426
- display: flex; align-items: center; gap: 6px;
3534
+ display: flex; align-items: center; gap: var(--space-1-75);
3427
3535
  font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3);
3428
- padding: 0 6px; letter-spacing: 0.02em;
3536
+ padding: 0 var(--space-1-75); letter-spacing: 0.02em;
3429
3537
  }
3430
3538
  .ds-247420 .chat-meta .who { font-weight: 600; color: var(--fg-2); }
3431
3539
  .ds-247420 .chat-meta .who::after { content: ' ·'; color: var(--fg-3); font-weight: 400; }
3432
3540
  .ds-247420 .chat-meta .t { color: var(--fg-3); }
3433
- .ds-247420 .chat-meta .tick { color: var(--fg-3); margin-left: 2px; letter-spacing: -2px; font-family: var(--ff-mono); }
3541
+ .ds-247420 .chat-meta .tick { color: var(--fg-3); margin-left: var(--space-hair); letter-spacing: -2px; font-family: var(--ff-mono); }
3434
3542
  .ds-247420 .chat-meta .tick.read { color: var(--accent-ink); }
3435
3543
 
3436
3544
  .ds-247420 .chat-reactions {
3437
- display: flex; gap: 4px; flex-wrap: wrap; margin-top: 2px;
3545
+ display: flex; gap: var(--space-1); flex-wrap: wrap; margin-top: var(--space-hair);
3438
3546
  }
3439
3547
  .ds-247420 .chat-reactions .rxn {
3440
- display: inline-flex; align-items: center; gap: 4px;
3441
- padding: 2px 8px; background: var(--bg-2);
3548
+ display: inline-flex; align-items: center; gap: var(--space-1);
3549
+ padding: var(--space-hair) var(--space-2); background: var(--bg-2);
3442
3550
  border: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
3443
3551
  border-radius: var(--r-pill); font-size: var(--fs-xs);
3444
3552
  cursor: pointer; user-select: none;
@@ -3455,7 +3563,7 @@
3455
3563
  .ds-247420 .chat-reactions .rxn .n { font-family: var(--ff-mono); font-weight: 600; font-size: 11px; color: var(--fg-2); }
3456
3564
  .ds-247420 .chat-reactions .rxn.you .n { color: var(--accent-ink); }
3457
3565
 
3458
- .ds-247420 .chat-typing { display: inline-flex; gap: 4px; align-items: center; }
3566
+ .ds-247420 .chat-typing { display: inline-flex; gap: var(--space-1); align-items: center; }
3459
3567
  .ds-247420 .chat-typing span {
3460
3568
  width: 6px; height: 6px; border-radius: 50%; background: var(--fg-3);
3461
3569
  }
@@ -3523,7 +3631,7 @@
3523
3631
  box-shadow: 0 0 0 2px color-mix(in oklab, var(--flame) 22%, transparent);
3524
3632
  }
3525
3633
  .ds-247420 .chat-composer textarea {
3526
- flex: 1; min-width: 0; padding: 8px 4px;
3634
+ flex: 1; min-width: 0; padding: var(--space-2) var(--space-1);
3527
3635
  background: none; color: var(--fg);
3528
3636
  border: none; border-radius: 0;
3529
3637
  font-family: inherit; font-size: var(--fs-sm);
@@ -3577,7 +3685,7 @@
3577
3685
  .ds-247420 .composer-btn { transition: none; }
3578
3686
  }
3579
3687
 
3580
- .ds-247420 .aicat-portrait { display: inline-flex; align-items: center; gap: 10px; padding: 4px 0; }
3688
+ .ds-247420 .aicat-portrait { display: inline-flex; align-items: center; gap: var(--space-2-5); padding: var(--space-1) 0; }
3581
3689
  .ds-247420 .aicat-face {
3582
3690
  width: 32px; height: 32px; font-size: 24px;
3583
3691
  display: inline-flex; align-items: center; justify-content: center;
@@ -3723,9 +3831,14 @@
3723
3831
  animation: spinner-rotate 0.8s linear infinite;
3724
3832
  }
3725
3833
 
3726
- /* Error state */
3834
+ /* Error state.
3835
+ No !important: the only rule in the kit that also resets a matching element's
3836
+ border-color is the bare-control base below (`textarea:where(:not(.input))`
3837
+ et al, which use the `border: 0` shorthand). Those selectors are (0,0,1) —
3838
+ the :where() guard adds nothing — so every selector in this list out-specifies
3839
+ them on merit, and specificity beats the later source position. */
3727
3840
  .ds-247420 .error, .ds-247420[data-state="error"], .ds-247420 .row.error, .ds-247420 input.error, .ds-247420 textarea.error {
3728
- border-color: var(--warn) !important;
3841
+ border-color: var(--warn);
3729
3842
  background-color: color-mix(in oklab, var(--warn) 6%, var(--bg));
3730
3843
  }
3731
3844
  .ds-247420 .error::placeholder { color: color-mix(in oklab, var(--warn) 60%, var(--fg-3)); }
@@ -4237,7 +4350,17 @@
4237
4350
  .ds-247420 .skip-to-main:focus { top: 10px; }
4238
4351
 
4239
4352
  /* Reduced motion preferences — scoped to the DS surface so it doesn't reach
4240
- into and neutralize the host document's own motion. */
4353
+ into and neutralize the host document's own motion.
4354
+ The !important flags here are LOAD-BEARING and must not be "cleaned up":
4355
+ `.ds-247420 *` / `.app *` is only (0,1,0) — the universal selector adds
4356
+ nothing — yet it has to defeat every animation/transition declaration in the
4357
+ kit, many of which are strictly more specific. Concrete rules it would
4358
+ otherwise lose to: `.ds-dropzone.dragover` (0,2,0, files.css),
4359
+ `.ds-upload-bar.indeterminate .ds-upload-fill` (0,3,0, files.css),
4360
+ `.list-item.drag-after::after` (0,2,1, this file). Raising this selector to
4361
+ out-specify an open-ended set of future component rules is not possible, so
4362
+ the flag is the only correct mechanism — this is a WCAG 2.3.3 guarantee,
4363
+ not a stylistic preference. */
4241
4364
  @media (prefers-reduced-motion: reduce) {
4242
4365
  .ds-247420 *, .ds-247420 .app * {
4243
4366
  animation-duration: 0.01ms !important;
@@ -4245,7 +4368,9 @@
4245
4368
  transition-duration: 0.01ms !important;
4246
4369
  }
4247
4370
  /* Kill the residual paint frame of looping skeleton/shimmer placeholders and
4248
- give reduced-motion users a steady placeholder fill instead. */
4371
+ give reduced-motion users a steady placeholder fill instead.
4372
+ Also load-bearing: `.skeleton` is (0,1,0) and must override
4373
+ `.ds-session-row-skeleton .ds-skel` (0,2,0), which sets its own shimmer. */
4249
4374
  .ds-247420 .skeleton, .ds-247420 .ds-skeleton, .ds-247420 .ds-session-row-skeleton .ds-skel {
4250
4375
  animation: none !important;
4251
4376
  background: var(--bg-2) !important;
@@ -4514,8 +4639,16 @@
4514
4639
  even on a wide desktop. Drawer/scrim/toggle are absolute (anchored to .app), so
4515
4640
  they overlay the window, not the page. */
4516
4641
  @container (max-width: 900px) {
4517
- .ds-247420 .app-body,
4518
- .ds-247420 .app-body.no-side { grid-template-columns: 1fr !important; }
4642
+ /* `.app`-scoped for specificity instead of an !important flag. The bare
4643
+ `.app-body` half of this list is (0,1,0) and was out-specified by
4644
+ `.app-body.no-side` (0,2,0) in topbar.css; scoping lifts both halves to
4645
+ (0,2,0)/(0,3,0), which also lands later in source than topbar.css, so the
4646
+ drawer collapse wins on merit. `.app` is guaranteed: `.app-body` is
4647
+ emitted only as a direct child of `.app` (single call site, shell.js
4648
+ AppShell), and this @container query already requires `.app` as its
4649
+ container ancestor. */
4650
+ .ds-247420 .app .app-body,
4651
+ .ds-247420 .app .app-body.no-side { grid-template-columns: 1fr; }
4519
4652
  .ds-247420 .app-side-shell {
4520
4653
  position: absolute;
4521
4654
  /* Full-height overlay drawer: the merged .app-chrome wraps and its real
@@ -4540,9 +4673,13 @@
4540
4673
  .ds-247420 .app-side-shell.open,
4541
4674
  .ds-247420 .app-side.open,
4542
4675
  .ds-247420 .app-body.side-open .app-side-shell { transform: translateX(0); }
4676
+ /* No flags needed: the ONLY other rule that touches these properties is the
4677
+ `.app-side` base in topbar.css, which already sets `flex-direction: column`
4678
+ and never sets `flex-wrap` (nowrap is the initial value anyway). This rule
4679
+ is equal-specificity and later in source, so it wins unaided. */
4543
4680
  .ds-247420 .app-side {
4544
- flex-direction: column !important;
4545
- flex-wrap: nowrap !important;
4681
+ flex-direction: column;
4682
+ flex-wrap: nowrap;
4546
4683
  gap: var(--space-2);
4547
4684
  padding: var(--space-3);
4548
4685
  font-size: var(--fs-sm);
@@ -5061,7 +5198,7 @@
5061
5198
  }
5062
5199
 
5063
5200
  /* PhaseWalk */
5064
- .ds-247420 .ds-phasewalk { display: inline-flex; gap: 2px; vertical-align: middle; }
5201
+ .ds-247420 .ds-phasewalk { display: inline-flex; gap: var(--space-hair); vertical-align: middle; }
5065
5202
  .ds-247420 .ds-phasewalk-seg {
5066
5203
  width: 18px; height: 10px; border-radius: var(--r-hair);
5067
5204
  background: var(--bg-3); position: relative;
@@ -5070,6 +5207,10 @@
5070
5207
  .ds-247420 .ds-phasewalk-seg.is-gap { background: var(--warn); }
5071
5208
  /* Standalone PhaseWalk reserves headroom for the labels instead of letting
5072
5209
  them escape upward and overlap the element above. */
5210
+ /* 15px is load-bearing, not off-scale drift: it must equal the absolute
5211
+ `top: -15px` the label below is lifted by, so the label clears the segments
5212
+ without a gap. Snapping the pad to --space-3 (16px) alone would desync the
5213
+ pair. */
5073
5214
  .ds-247420 .ds-phasewalk { padding-top: 15px; }
5074
5215
  .ds-247420 .ds-phasewalk-lbl {
5075
5216
  position: absolute; top: -15px; left: 0;
@@ -5082,25 +5223,25 @@
5082
5223
 
5083
5224
  /* TreeNode */
5084
5225
  .ds-247420 .ds-tree-node {
5085
- padding: 5px 10px; border-left: var(--bw-rule) solid var(--bg-3);
5086
- margin: 2px 0 2px 16px; font-size: var(--fs-tiny);
5226
+ padding: var(--space-1-5) var(--space-2-5); border-left: var(--bw-rule) solid var(--bg-3);
5227
+ margin: var(--space-hair) 0 var(--space-hair) var(--space-3); font-size: var(--fs-tiny);
5087
5228
  min-width: 0; overflow-wrap: anywhere;
5088
5229
  }
5089
5230
  @media (max-width: 400px) {
5090
- .ds-247420 .ds-tree-node { margin-left: 8px; padding-left: 8px; }
5231
+ .ds-247420 .ds-tree-node { margin-left: var(--space-2); padding-left: var(--space-2); }
5091
5232
  }
5092
5233
  .ds-247420 .ds-tree-node.is-phase { border-color: var(--accent); background: var(--bg-3); font-weight: 600; }
5093
5234
  .ds-247420 .ds-tree-node.is-deviation { border-color: var(--warn); background: var(--danger-surface); color: var(--warn); }
5094
5235
  .ds-247420 .ds-tree-node.is-mutable-resolve { border-color: var(--success); }
5095
5236
  .ds-247420 .ds-tree-node.is-prd-add { border-color: var(--amber); }
5096
- .ds-247420 .ds-tree-node-ts { margin-right: 8px; color: var(--fg-3); }
5097
- .ds-247420 .ds-tree-node-pills { margin-left: 6px; }
5098
- .ds-247420 .ds-tree-node-reason { margin-top: 2px; color: var(--fg-2); }
5099
- .ds-247420 .ds-tree-node-deviation { margin-top: 2px; }
5100
- .ds-247420 .ds-tree-node-residuals { margin-top: 2px; color: var(--fg-3); }
5237
+ .ds-247420 .ds-tree-node-ts { margin-right: var(--space-2); color: var(--fg-3); }
5238
+ .ds-247420 .ds-tree-node-pills { margin-left: var(--space-1-75); }
5239
+ .ds-247420 .ds-tree-node-reason { margin-top: var(--space-hair); color: var(--fg-2); }
5240
+ .ds-247420 .ds-tree-node-deviation { margin-top: var(--space-hair); }
5241
+ .ds-247420 .ds-tree-node-residuals { margin-top: var(--space-hair); color: var(--fg-3); }
5101
5242
 
5102
5243
  /* BarRow */
5103
- .ds-247420 .ds-bar-row { display: flex; align-items: center; gap: 8px; margin: 3px 0; font-size: var(--fs-tiny); }
5244
+ .ds-247420 .ds-bar-row { display: flex; align-items: center; gap: var(--space-2); margin: var(--space-half) 0; font-size: var(--fs-tiny); }
5104
5245
  .ds-247420 .ds-bar-row-label { width: 100px; flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
5105
5246
  .ds-247420 .ds-bar-bg { flex: 1; min-width: 60px; background: var(--bg-3); border-radius: var(--r-hair); height: 6px; overflow: hidden; }
5106
5247
  .ds-247420 .ds-bar-fill { background: var(--fg-3); height: 100%; border-radius: var(--r-hair); }
@@ -5119,11 +5260,11 @@
5119
5260
  .ds-247420 .ds-stats-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-1); }
5120
5261
  }
5121
5262
  .ds-247420 .ds-stats-grid-empty { padding: var(--space-3); color: var(--fg-3); font-size: var(--fs-tiny); }
5122
- .ds-247420 .ds-stat { min-width: 0; background: var(--bg-3); border-radius: var(--r-0); padding: 10px 12px; }
5263
+ .ds-247420 .ds-stat { min-width: 0; background: var(--bg-3); border-radius: var(--r-0); padding: var(--space-2-5) var(--space-2-75); }
5123
5264
  .ds-247420 .ds-stat-val { font-size: clamp(18px, 5cqi, 22px); font-weight: 700; color: var(--accent-ink); overflow-wrap: anywhere; }
5124
5265
  .ds-247420 .ds-stat-val.rate-big { font-size: clamp(24px, 7cqi, 32px); color: var(--success); }
5125
5266
  .ds-247420 .ds-stat-val.err-rate { font-size: clamp(24px, 7cqi, 32px); color: var(--warn); }
5126
- .ds-247420 .ds-stat-lbl { font-size: var(--fs-micro); color: var(--fg-3); margin-top: 2px; }
5267
+ .ds-247420 .ds-stat-lbl { font-size: var(--fs-micro); color: var(--fg-3); margin-top: var(--space-hair); }
5127
5268
 
5128
5269
  /* RateCell — tone-colored numeric table cell (success-rate / percentile-latency
5129
5270
  columns), ported from docstudio's endpointsView() success-rate coloring.
@@ -5140,10 +5281,10 @@
5140
5281
  .ds-247420 .ds-inline-row { display: flex; align-items: center; gap: var(--space-2, 8px); }
5141
5282
 
5142
5283
  /* SubGrid */
5143
- .ds-247420 .ds-sub-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 6px; margin-top: 8px; }
5284
+ .ds-247420 .ds-sub-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: var(--space-1-75); margin-top: var(--space-2); }
5144
5285
  .ds-247420 .ds-sub-grid-empty { padding: var(--space-3); color: var(--fg-3); font-size: var(--fs-tiny); }
5145
5286
  .ds-247420 .ds-sub-btn {
5146
- padding: 6px 10px; background: var(--bg-3); border: var(--bw-hair) solid var(--bg-3);
5287
+ padding: var(--space-1-75) var(--space-2-5); background: var(--bg-3); border: var(--bw-hair) solid var(--bg-3);
5147
5288
  border-radius: var(--r-0); font-size: var(--fs-tiny); cursor: pointer; color: var(--fg);
5148
5289
  text-align: left; font-family: var(--ff-body);
5149
5290
  }
@@ -5162,7 +5303,7 @@
5162
5303
  identical to the ones there, so a kit loading both gets the same result. */
5163
5304
  .ds-247420 .ds-session-row {
5164
5305
  position: relative; display: flex; align-items: center; gap: var(--space-2);
5165
- width: 100%; padding: var(--space-2); min-height: 52px; margin-bottom: 2px;
5306
+ width: 100%; padding: var(--space-2); min-height: 52px; margin-bottom: var(--space-hair);
5166
5307
  background: transparent; border: none; border-radius: var(--r-1);
5167
5308
  text-align: left; color: var(--fg);
5168
5309
  }
@@ -5190,7 +5331,7 @@
5190
5331
  /* DevRow */
5191
5332
  .ds-247420 .ds-dev-row {
5192
5333
  background: var(--danger-surface); border-left: var(--bw-chunk) solid var(--warn);
5193
- padding: 8px 12px; margin: 4px 0; border-radius: var(--r-hair); font-size: var(--fs-tiny);
5334
+ padding: var(--space-2) var(--space-2-75); margin: var(--space-1) 0; border-radius: var(--r-hair); font-size: var(--fs-tiny);
5194
5335
  }
5195
5336
  .ds-247420 .ds-dev-row strong { color: var(--warn); }
5196
5337
 
@@ -5207,17 +5348,17 @@
5207
5348
  /* Embedded in a WM window the viewport calc is meaningless — fill the container. */
5208
5349
  .ds-247420 .fd-root .ds-live-log { height: 100%; max-height: none; min-height: 0; flex: 1 1 auto; }
5209
5350
  .ds-247420 .ds-live-log-empty { height: auto; min-height: 0; padding: var(--space-3); color: var(--fg-3); }
5210
- .ds-247420 .ds-live-log-entry { padding: 2px 8px; border-bottom: var(--bw-hair) solid var(--bg-3); overflow-wrap: anywhere; }
5351
+ .ds-247420 .ds-live-log-entry { padding: var(--space-hair) var(--space-2); border-bottom: var(--bw-hair) solid var(--bg-3); overflow-wrap: anywhere; }
5211
5352
  .ds-247420 .ds-live-log-entry:hover { background: var(--bg-3); }
5212
- .ds-247420 .ds-live-log-ts { margin-right: 6px; color: var(--fg-3); }
5213
- .ds-247420 .ds-live-log-subtag { margin-right: 6px; padding: 0 5px; border-radius: var(--r-hair); font-size: var(--fs-micro); }
5214
- .ds-247420 .ds-live-log-preview { margin-left: 6px; color: var(--fg-3); word-break: break-word; }
5353
+ .ds-247420 .ds-live-log-ts { margin-right: var(--space-1-75); color: var(--fg-3); }
5354
+ .ds-247420 .ds-live-log-subtag { margin-right: var(--space-1-75); padding: 0 var(--space-1-5); border-radius: var(--r-hair); font-size: var(--fs-micro); }
5355
+ .ds-247420 .ds-live-log-preview { margin-left: var(--space-1-75); color: var(--fg-3); word-break: break-word; }
5215
5356
 
5216
5357
  /* Touch floors for the dense controls (not covered by the mobile width blocks). */
5217
5358
  @media (pointer: coarse) {
5218
5359
  .ds-247420 .ds-sub-btn { min-height: 44px; }
5219
5360
  .ds-247420 .ds-session-row { min-height: 44px; }
5220
- .ds-247420 .ds-live-log-entry { padding-block: 6px; }
5361
+ .ds-247420 .ds-live-log-entry { padding-block: var(--space-1-75); }
5221
5362
  }
5222
5363
 
5223
5364
 
@@ -5253,9 +5394,15 @@
5253
5394
  app scale (--fs-h1-app, 22-30px) is what these tokens exist for. Applied
5254
5395
  here rather than as a data-attribute on each kit shell so any surface using
5255
5396
  this root gets the app voice without a per-kit opt-in that kits forget. */
5256
- .ds-247420 .ds-app-surface > h1, .ds-247420 .ds-app-surface > .t-h1 { font-size: var(--fs-h1-app); line-height: 1.15; }
5257
- .ds-247420 .ds-app-surface > h2, .ds-247420 .ds-app-surface > .t-h2 { font-size: var(--fs-h2-app); }
5258
- .ds-247420 .ds-app-surface > h3, .ds-247420 .ds-app-surface > .t-h3 { font-size: var(--fs-h3-app); }
5397
+ /* Descendant, not direct-child: a kit that wraps its title in a head row (an
5398
+ h1 beside a theme toggle, say) still gets the app voice. The direct-child
5399
+ form silently missed exactly that shape and left those titles at the 64px
5400
+ display ceiling -- the surface opted in but the rule did not reach the
5401
+ heading. Nested .ds-section content is unaffected because nothing re-raises
5402
+ the size below this point. */
5403
+ .ds-247420 .ds-app-surface h1, .ds-247420 .ds-app-surface .t-h1 { font-size: var(--fs-h1-app); line-height: 1.15; }
5404
+ .ds-247420 .ds-app-surface h2, .ds-247420 .ds-app-surface .t-h2 { font-size: var(--fs-h2-app); }
5405
+ .ds-247420 .ds-app-surface h3, .ds-247420 .ds-app-surface .t-h3 { font-size: var(--fs-h3-app); }
5259
5406
  /* The lede is supporting chrome under an app title, not a marketing stand-first:
5260
5407
  it drops to body size and keeps a readable measure instead of --fs-xl. */
5261
5408
  .ds-247420 .ds-app-surface > .lede, .ds-247420 .ds-app-surface > .t-lede { font-size: var(--fs-body); max-width: 60ch; }
@@ -5361,7 +5508,7 @@
5361
5508
  margin: var(--space-3) auto;
5362
5509
  background: var(--bg-2);
5363
5510
  border-radius: var(--r-2);
5364
- padding: clamp(16px, 5vw, 64px);
5511
+ padding: clamp(var(--space-3), 5vw, var(--space-7));
5365
5512
  box-sizing: border-box;
5366
5513
  display: flex;
5367
5514
  overflow: hidden;
@@ -5376,8 +5523,10 @@
5376
5523
  }
5377
5524
  .ds-247420 .ds-deck-slide { flex: 1; display: flex; min-width: 0; }
5378
5525
  .ds-247420 .ds-deck-controls {
5526
+ /* 14px sits between --space-2-75 (12) and --space-3 (16) with no tier; it is
5527
+ the deck control spacing tuned against the mono glyph run. */
5379
5528
  display: flex; align-items: center; justify-content: center; gap: 14px;
5380
- padding: 8px; font-family: var(--ff-mono); font-size: var(--fs-sm);
5529
+ padding: var(--space-2); font-family: var(--ff-mono); font-size: var(--fs-sm);
5381
5530
  }
5382
5531
  .ds-247420 .ds-deck-count { color: var(--fg-3); }
5383
5532
  @media (pointer: coarse) {
@@ -5404,9 +5553,9 @@
5404
5553
  full-bleed slide chrome, not panel chrome) and owns its own bottom gutter. */
5405
5554
  .ds-247420 .ds-slide-eyebrow {
5406
5555
  color: var(--fg-3);
5407
- margin-bottom: clamp(12px, 2.5cqw, 24px);
5556
+ margin-bottom: clamp(var(--space-2-75), 2.5cqw, var(--space-4));
5408
5557
  }
5409
- .ds-247420 .ds-slide-col { display: flex; flex-direction: column; justify-content: center; gap: clamp(12px, 2.5cqw, 24px); min-width: 0; }
5558
+ .ds-247420 .ds-slide-col { display: flex; flex-direction: column; justify-content: center; gap: clamp(var(--space-2-75), 2.5cqw, var(--space-4)); min-width: 0; }
5410
5559
  .ds-247420 .ds-slide-col--start { align-items: flex-start; }
5411
5560
  .ds-247420 .ds-slide-col--narrow { max-width: 38ch; }
5412
5561
  .ds-247420 .ds-slide-col--quote { max-width: 42ch; }
@@ -5420,15 +5569,17 @@
5420
5569
  font-size: clamp(var(--fs-h3), 4.5cqw, var(--fs-h1));
5421
5570
  line-height: var(--lh-snug); color: var(--fg); font-weight: 500; min-width: 0;
5422
5571
  }
5423
- .ds-247420 .ds-slide-h1--lead { margin-bottom: 12px; }
5572
+ .ds-247420 .ds-slide-h1--lead { margin-bottom: var(--space-2-75); }
5424
5573
  .ds-247420 .ds-slide-quote-body {
5425
5574
  font-size: clamp(var(--fs-lg), 3.5cqw, var(--fs-h2));
5426
5575
  line-height: var(--lh-snug); color: var(--fg); font-weight: 400; font-style: italic;
5427
5576
  }
5428
5577
  .ds-247420 .ds-slide-cite { font-family: var(--ff-mono); font-size: var(--fs-sm); color: var(--fg-3); }
5429
5578
  .ds-247420 .ds-slide-bullet {
5430
- display: flex; gap: clamp(8px, 2vw, 18px); align-items: baseline;
5431
- border-bottom: 1px solid var(--rule); padding: 12px 0; flex-wrap: wrap;
5579
+ /* 18px ceiling has no tier (--space-3 is 16, --space-3-5 is 20); it is the
5580
+ bullet key/value split tuned against the clamp(56px,18%,100px) key column. */
5581
+ display: flex; gap: clamp(var(--space-2), 2vw, 18px); align-items: baseline;
5582
+ border-bottom: 1px solid var(--rule); padding: var(--space-2-75) 0; flex-wrap: wrap;
5432
5583
  }
5433
5584
  .ds-247420 .ds-slide-bullet-key {
5434
5585
  flex: 0 1 clamp(56px, 18%, 100px); min-width: 0;
@@ -5436,7 +5587,7 @@
5436
5587
  color: var(--slide-accent, var(--accent-ink));
5437
5588
  }
5438
5589
  .ds-247420 .ds-slide-bullet-val { color: var(--fg-2); font-size: var(--fs-lg); min-width: 0; }
5439
- .ds-247420 .ds-slide-split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(12px, 3vw, 32px); margin-top: 12px; }
5590
+ .ds-247420 .ds-slide-split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(var(--space-2-75), 3vw, var(--space-5)); margin-top: var(--space-2-75); }
5440
5591
  @media (max-width: 760px) {
5441
5592
  .ds-247420 .ds-slide-split { grid-template-columns: 1fr; }
5442
5593
  }
@@ -5462,7 +5613,10 @@
5462
5613
 
5463
5614
  /* --- error 404 --------------------------------------------- */
5464
5615
  .ds-247420 .ds-err-hero {
5465
- padding: clamp(16px, 5vw, 36px) clamp(12px, 4vw, 22px);
5616
+ /* 36px/22px clamp ceilings and the 14px gap are off-scale on purpose: this
5617
+ hero is centred around a clamp(56px,20vw,120px) numeral and the insets are
5618
+ tuned to it, not to the panel rhythm the --space-* scale encodes. */
5619
+ padding: clamp(var(--space-3), 5vw, 36px) clamp(var(--space-2-75), 4vw, 22px);
5466
5620
  text-align: center; display: flex; flex-direction: column; gap: 14px; align-items: center;
5467
5621
  }
5468
5622
  .ds-247420 .ds-err-numeral {
@@ -5470,25 +5624,25 @@
5470
5624
  line-height: 1; color: var(--panel-text-3); letter-spacing: -0.03em;
5471
5625
  }
5472
5626
  .ds-247420 .ds-err-path {
5473
- display: inline-flex; gap: 6px; align-items: baseline; flex-wrap: wrap; max-width: 100%;
5627
+ display: inline-flex; gap: var(--space-1-75); align-items: baseline; flex-wrap: wrap; max-width: 100%;
5474
5628
  font-family: var(--ff-mono); font-size: 13px; color: var(--panel-text-2);
5475
- background: var(--panel-1); padding: 6px 12px; border-radius: var(--r-0);
5629
+ background: var(--panel-1); padding: var(--space-1-75) var(--space-2-75); border-radius: var(--r-0);
5476
5630
  overflow-wrap: anywhere; word-break: break-all;
5477
5631
  }
5478
5632
 
5479
5633
  /* --- gallery ------------------------------------------------ */
5480
5634
  .ds-247420 .ds-tile-grid {
5481
- padding: clamp(8px, 2.5vw, 16px);
5482
- display: grid; grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 1fr)); gap: 8px;
5635
+ padding: clamp(var(--space-2), 2.5vw, var(--space-3));
5636
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 1fr)); gap: var(--space-2);
5483
5637
  }
5484
5638
  .ds-247420 .ds-tile-grid--tight { grid-template-columns: repeat(auto-fill, minmax(min(140px, 100%), 1fr)); }
5485
5639
  .ds-247420 .ds-swatch-grid {
5486
- padding: clamp(8px, 2.5vw, 16px);
5487
- display: grid; grid-template-columns: repeat(auto-fill, minmax(min(160px, 100%), 1fr)); gap: 12px;
5640
+ padding: clamp(var(--space-2), 2.5vw, var(--space-3));
5641
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(min(160px, 100%), 1fr)); gap: var(--space-2-75);
5488
5642
  }
5489
5643
  .ds-247420 .ds-gallery-tile {
5490
- cursor: pointer; display: flex; flex-direction: column; gap: 6px;
5491
- padding: 12px; border-radius: var(--r-1); min-height: clamp(120px, 18vw, 160px);
5644
+ cursor: pointer; display: flex; flex-direction: column; gap: var(--space-1-75);
5645
+ padding: var(--space-2-75); border-radius: var(--r-1); min-height: clamp(120px, 18vw, 160px);
5492
5646
  border: 0; text-align: left; font: inherit; color: inherit;
5493
5647
  background: var(--tile-tone, var(--panel-1));
5494
5648
  transition: transform var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease);
@@ -5502,20 +5656,23 @@
5502
5656
  .ds-247420 .ds-lightbox {
5503
5657
  position: fixed; inset: 0; background: var(--scrim);
5504
5658
  display: flex; align-items: center; justify-content: center;
5505
- padding: clamp(12px, 4vw, 32px);
5506
- padding-bottom: max(clamp(12px, 4vw, 32px), env(safe-area-inset-bottom));
5659
+ padding: clamp(var(--space-2-75), 4vw, var(--space-5));
5660
+ padding-bottom: max(clamp(var(--space-2-75), 4vw, var(--space-5)), env(safe-area-inset-bottom));
5507
5661
  z-index: var(--z-modal);
5508
5662
  }
5509
5663
  .ds-247420 .ds-lightbox-card {
5510
- background: var(--panel-0); border-radius: var(--r-2); padding: clamp(16px, 4vw, 28px);
5664
+ /* 28px ceiling has no tier (--space-4 is 24, --space-5 is 32); it is the
5665
+ lightbox card inset tuned against the min(520px,100%) card width. */
5666
+ background: var(--panel-0); border-radius: var(--r-2); padding: clamp(var(--space-3), 4vw, 28px);
5511
5667
  width: min(520px, 100%); min-width: 0;
5512
5668
  max-height: calc(100vh - 24px);
5513
5669
  max-height: calc(100dvh - 24px);
5514
5670
  overflow: auto;
5515
- display: flex; flex-direction: column; gap: 14px;
5671
+ display: flex; flex-direction: column; gap: 14px; /* off-scale, matches the card inset above */
5516
5672
  }
5517
5673
  .ds-247420 .ds-lightbox-preview {
5518
- padding: clamp(16px, 6vw, 36px); border-radius: var(--r-1); text-align: center;
5674
+ /* 36px ceiling has no tier (--space-5 is 32, --space-6 is 48). */
5675
+ padding: clamp(var(--space-3), 6vw, 36px); border-radius: var(--r-1); text-align: center;
5519
5676
  font-family: var(--ff-mono); white-space: pre-line; font-size: clamp(16px, 5vw, 24px);
5520
5677
  background: var(--tile-tone, var(--panel-1));
5521
5678
  }
@@ -5525,25 +5682,31 @@
5525
5682
  @media (max-width: 480px) {
5526
5683
  .ds-247420 .ds-topbar-search { flex-basis: 100%; }
5527
5684
  }
5528
- .ds-247420 .ds-empty-state { padding: clamp(16px, 5vw, 24px); text-align: center; color: var(--panel-text-3); }
5685
+ .ds-247420 .ds-empty-state { padding: clamp(var(--space-3), 5vw, var(--space-4)); text-align: center; color: var(--panel-text-3); }
5529
5686
  .ds-247420 .ds-empty-state-glyph { font-size: clamp(24px, 6vw, 32px); }
5530
- .ds-247420 .ds-empty-state-msg { margin: 6px 0; }
5687
+ .ds-247420 .ds-empty-state-msg { margin: var(--space-1-75) 0; }
5531
5688
  .ds-247420 .ds-empty-state-hint { margin: 0; font-size: var(--fs-sm); }
5532
5689
 
5533
5690
  /* --- system primer ------------------------------------------ */
5691
+ /* The three primer panels below share one fluid inset,
5692
+ clamp(10px, 2.5vw, 14px) clamp(10px, 3vw, 18px), and a 14/18px gap. None of
5693
+ 10/14/18 is a --space-* tier (the scale jumps 8 -> 10 -> 12 -> 16 -> 20) and
5694
+ the three values are tuned as a set against the 64px label columns, so the
5695
+ panels stay optically identical to each other. Snapping any one of them
5696
+ desyncs the family; they are deliberate literals, not un-migrated drift. */
5534
5697
  .ds-247420 .ds-swatch-grid-sm {
5535
5698
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(110px, 100%), 1fr));
5536
- gap: 12px; padding: clamp(10px, 2.5vw, 14px) clamp(10px, 3vw, 18px);
5699
+ gap: var(--space-2-75); padding: clamp(10px, 2.5vw, 14px) clamp(10px, 3vw, 18px);
5537
5700
  }
5538
5701
  .ds-247420 .ds-swatch-grid-lg { grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr)); }
5539
- .ds-247420 .ds-swatch-col { display: flex; flex-direction: column; gap: 6px; }
5702
+ .ds-247420 .ds-swatch-col { display: flex; flex-direction: column; gap: var(--space-1-75); }
5540
5703
  .ds-247420 .ds-swatch-chip { height: 48px; border-radius: var(--r-1); border: 1px solid var(--rule); background: var(--swatch, var(--panel-1)); }
5541
5704
  .ds-247420 .ds-swatch-chip--big { height: 64px; }
5542
5705
  .ds-247420 .ds-swatch-name { font-family: var(--ff-mono); font-size: 11px; color: var(--fg-3); }
5543
5706
  .ds-247420 .ds-type-panel { padding: clamp(10px, 2.5vw, 14px) clamp(10px, 3vw, 18px); display: flex; flex-direction: column; gap: 14px; }
5544
5707
  .ds-247420 .ds-type-row {
5545
5708
  display: flex; align-items: baseline; gap: 14px;
5546
- border-bottom: 1px solid var(--rule); padding-bottom: 8px; flex-wrap: wrap;
5709
+ border-bottom: 1px solid var(--rule); padding-bottom: var(--space-2); flex-wrap: wrap;
5547
5710
  }
5548
5711
  .ds-247420 .ds-type-row-label { flex: 0 0 64px; font-family: var(--ff-mono); font-size: 11px; color: var(--fg-3); }
5549
5712
  .ds-247420 .ds-type-sample {
@@ -5551,7 +5714,7 @@
5551
5714
  font-size: var(--sample-size, var(--fs-body));
5552
5715
  }
5553
5716
  .ds-247420 .ds-prim-panel { padding: clamp(10px, 2.5vw, 14px) clamp(10px, 3vw, 18px); display: flex; flex-direction: column; gap: 18px; }
5554
- .ds-247420 .ds-prim-row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
5717
+ .ds-247420 .ds-prim-row { display: flex; gap: var(--space-2-5); flex-wrap: wrap; align-items: center; }
5555
5718
  .ds-247420 .ds-prim-label { flex: 0 0 64px; font-family: var(--ff-mono); font-size: 11px; color: var(--fg-3); }
5556
5719
 
5557
5720
  /* == appended: content-site == */
@@ -5607,7 +5770,7 @@
5607
5770
  matching the "color reserved for meaning, not decoration" pattern seen in
5608
5771
  docstudio's admin table. */
5609
5772
  .ds-247420 .ds-table-sort-btn {
5610
- display: inline-flex; align-items: center; gap: 4px;
5773
+ display: inline-flex; align-items: center; gap: var(--space-1);
5611
5774
  background: none; border: none; padding: 0; margin: 0;
5612
5775
  font: inherit; font-weight: inherit; color: inherit; cursor: pointer;
5613
5776
  }
@@ -5680,55 +5843,56 @@
5680
5843
  /* == appended: signin kit cleanup == */
5681
5844
  /* -- signin kit (ui_kits/signin) -- */
5682
5845
  .ds-247420 .ds-auth-wrap { padding: var(--space-2, 8px); display: flex; flex-direction: column; align-items: center; }
5683
- .ds-247420 .ds-auth-col { width: 100%; max-width: 440px; display: flex; flex-direction: column; gap: 8px; margin: clamp(12px, 4vw, 24px) 0; min-width: 0; }
5684
- .ds-247420 .ds-auth-form { padding: clamp(12px, 3vw, 18px); display: flex; flex-direction: column; gap: 10px; }
5846
+ .ds-247420 .ds-auth-col { width: 100%; max-width: 440px; display: flex; flex-direction: column; gap: var(--space-2); margin: clamp(var(--space-2-75), 4vw, var(--space-4)) 0; min-width: 0; }
5847
+ /* 18px ceiling: no tier between --space-3 (16) and --space-3-5 (20). */
5848
+ .ds-247420 .ds-auth-form { padding: clamp(var(--space-2-75), 3vw, 18px); display: flex; flex-direction: column; gap: var(--space-2-5); }
5685
5849
  .ds-247420 .ds-auth-sent { align-items: center; text-align: center; }
5686
5850
  .ds-247420 .ds-auth-sent-glyph { font-size: 32px; color: var(--panel-accent); }
5687
5851
  .ds-247420 .ds-auth-sent-title { margin: 0; font-weight: 600; }
5688
5852
  .ds-247420 .ds-auth-sent-sub { margin: 0; color: var(--panel-text-2); overflow-wrap: anywhere; }
5689
- .ds-247420 .ds-auth-field { display: flex; flex-direction: column; gap: 4px; }
5853
+ .ds-247420 .ds-auth-field { display: flex; flex-direction: column; gap: var(--space-1); }
5690
5854
  /* .ds-auth-field-label joins the kit small-label voice above, no overrides. */
5691
- .ds-247420 .ds-auth-row-between { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
5692
- .ds-247420 .ds-auth-remember { display: flex; align-items: center; gap: 6px; cursor: pointer; }
5855
+ .ds-247420 .ds-auth-row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; }
5856
+ .ds-247420 .ds-auth-remember { display: flex; align-items: center; gap: var(--space-1-75); cursor: pointer; }
5693
5857
  .ds-247420 .ds-auth-remember-text { color: var(--panel-text-2); font-size: 13px; }
5694
5858
  .ds-247420 .ds-auth-forgot { font-size: 13px; }
5695
- .ds-247420 .ds-auth-error { padding: 8px 10px; background: var(--panel-1); border-radius: var(--r-0); color: var(--danger); font-size: 13px; overflow-wrap: anywhere; }
5696
- .ds-247420 .ds-auth-providers { display: flex; gap: 8px; flex-wrap: wrap; }
5697
- .ds-247420 .ds-auth-provider-btn { flex: 1 1 100px; min-width: 0; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 10px; }
5859
+ .ds-247420 .ds-auth-error { padding: var(--space-2) var(--space-2-5); background: var(--panel-1); border-radius: var(--r-0); color: var(--danger); font-size: 13px; overflow-wrap: anywhere; }
5860
+ .ds-247420 .ds-auth-providers { display: flex; gap: var(--space-2); flex-wrap: wrap; }
5861
+ .ds-247420 .ds-auth-provider-btn { flex: 1 1 100px; min-width: 0; display: flex; align-items: center; justify-content: center; gap: var(--space-2); padding: var(--space-2-5); }
5698
5862
  .ds-247420 .ds-auth-provider-btn--loading { opacity: 0.7; pointer-events: none; }
5699
5863
  .ds-247420 .ds-auth-provider-glyph { font-family: var(--ff-mono); color: var(--panel-text-3); display: inline-flex; }
5700
- .ds-247420 .ds-auth-modes { display: flex; justify-content: center; gap: 14px; margin-top: 8px; font-size: 13px; flex-wrap: wrap; }
5864
+ .ds-247420 .ds-auth-modes { display: flex; justify-content: center; gap: 14px; /* off-scale, matches the auth form inset */ margin-top: var(--space-2); font-size: 13px; flex-wrap: wrap; }
5701
5865
  .ds-247420 .ds-auth-mode-link { color: var(--panel-text-3); text-decoration: none; }
5702
5866
  .ds-247420 .ds-auth-mode-link--active { color: var(--panel-text); text-decoration: underline; }
5703
- .ds-247420 .ds-auth-fineprint { text-align: center; font-size: 12px; color: var(--panel-text-3); margin: 6px 0; }
5867
+ .ds-247420 .ds-auth-fineprint { text-align: center; font-size: 12px; color: var(--panel-text-3); margin: var(--space-1-75) 0; }
5704
5868
 
5705
5869
  /* == appended: gallery-misc kit cleanup == */
5706
5870
  /* --- shared helpers (converted from inline styles) --- */
5707
5871
  .ds-247420 .ds-m0 { margin: 0; }
5708
5872
  .ds-247420 .ds-text-2 { color: var(--panel-text-2); }
5709
5873
  .ds-247420 .ds-text-3 { color: var(--panel-text-3); }
5710
- .ds-247420 .ds-kit-head { display: flex; align-items: center; justify-content: space-between; gap: clamp(8px, 2vw, 16px); flex-wrap: wrap; }
5874
+ .ds-247420 .ds-kit-head { display: flex; align-items: center; justify-content: space-between; gap: clamp(var(--space-2), 2vw, var(--space-3)); flex-wrap: wrap; }
5711
5875
 
5712
5876
  /* --- gallery kit --- */
5713
5877
  .ds-247420 .ds-tile-cap { flex: 1; display: flex; align-items: center; justify-content: center; font-family: var(--ff-mono); white-space: pre-line; color: var(--panel-text-2); font-size: 18px; min-width: 0; text-align: center; }
5714
- .ds-247420 .ds-tile-meta { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 12px; flex-wrap: wrap; min-width: 0; }
5878
+ .ds-247420 .ds-tile-meta { display: flex; align-items: center; justify-content: space-between; gap: var(--space-1-75); font-size: 12px; flex-wrap: wrap; min-width: 0; }
5715
5879
  .ds-247420 .ds-tile-glyph { font-family: var(--ff-mono); color: var(--panel-text-3); }
5716
5880
  .ds-247420 .ds-tile-label { color: var(--panel-text); overflow-wrap: anywhere; }
5717
5881
  .ds-247420 .ds-gal-swatch { height: 64px; border-radius: var(--r-0); background: var(--swatch, var(--panel-1)); }
5718
- .ds-247420 .ds-gal-swatch-meta { display: flex; justify-content: space-between; gap: 6px; flex-wrap: wrap; font-family: var(--ff-mono); font-size: 11px; min-width: 0; }
5882
+ .ds-247420 .ds-gal-swatch-meta { display: flex; justify-content: space-between; gap: var(--space-1-75); flex-wrap: wrap; font-family: var(--ff-mono); font-size: 11px; min-width: 0; }
5719
5883
  .ds-247420 .ds-gal-swatch-name { color: var(--panel-text); }
5720
5884
  .ds-247420 .ds-gal-swatch-hint { color: var(--panel-text-3); overflow-wrap: anywhere; }
5721
- .ds-247420 .ds-lightbox-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; }
5885
+ .ds-247420 .ds-lightbox-head { display: flex; justify-content: space-between; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
5722
5886
  /* .ds-lightbox-tag joins the kit small-label voice above, no overrides. */
5723
5887
 
5724
5888
  /* --- error_404 kit --- */
5725
- .ds-247420 .ds-err-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-top: 6px; }
5726
- .ds-247420 .ds-err-chips { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; margin-top: 4px; }
5889
+ .ds-247420 .ds-err-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; justify-content: center; margin-top: var(--space-1-75); }
5890
+ .ds-247420 .ds-err-chips { display: flex; gap: var(--space-1-75); flex-wrap: wrap; justify-content: center; margin-top: var(--space-1); }
5727
5891
 
5728
5892
  /* == appended: terminal-capp kit cleanup == */
5729
5893
  /* --- terminal kit ------------------------------------------ */
5730
- .ds-247420 .ds-section-pad-sm { padding: 8px; }
5731
- .ds-247420 .ds-kit-head-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
5894
+ .ds-247420 .ds-section-pad-sm { padding: var(--space-2); }
5895
+ .ds-247420 .ds-kit-head-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }
5732
5896
  .ds-247420 .ds-cli-cmt .cmd { color: var(--fg-3); }
5733
5897
  .ds-247420 .ds-cli-out .cmd { color: var(--fg-2); }
5734
5898
  .ds-247420 .ds-cli-ok .prompt, .ds-247420 .ds-cli-ok .cmd { color: var(--accent-ink); }
@@ -6006,6 +6170,25 @@
6006
6170
  .ds-247420 .cursor-blink { animation: ds-cursor-blink 1s step-end infinite; }
6007
6171
  @keyframes ds-cursor-blink { 50% { opacity: 0; } }
6008
6172
  }
6173
+
6174
+ /* == appended: panel width modifier == */
6175
+ /* .panel.panel-inline-wide — a width-capped inline note panel. Companion to
6176
+ the .panel-inline / .panel-wide modifiers in panel-row.css: those two change
6177
+ the panel's SURFACE (tonal fill / chrome-stripped), this one changes only
6178
+ its MEASURE, so it composes with either. Introduced when ui_kits/docs's
6179
+ `[!] note` panel traded `style="max-width:640px"` for a class (the inline-
6180
+ style sweep) but never got a rule written, leaving that panel to run the
6181
+ full column width. 640px is the note measure, deliberately narrower than
6182
+ --measure-narrow (760px): the aside is meant to read as a set-aside block
6183
+ against the surrounding prose, not to match its column. It is a literal
6184
+ rather than a new token because it has exactly one consumer — promote it to
6185
+ --measure-note the moment a second surface wants the same cap.
6186
+ `margin-right: auto` (not `margin: 0 auto`) keeps the panel left-aligned to
6187
+ the prose it interrupts and preserves .panel's own --space-4 stack margin. */
6188
+ .ds-247420 .panel.panel-inline-wide {
6189
+ max-width: 640px;
6190
+ margin-right: auto;
6191
+ }
6009
6192
  /* ============================================================
6010
6193
  Git status panel + diff view — changed-file list, unified diff.
6011
6194
  ============================================================ */
@@ -9630,7 +9813,12 @@
9630
9813
  .ds-247420 .ds-ep-tab-close:hover { background: var(--panel-2); color: var(--panel-text-1); }
9631
9814
  .ds-247420 .ds-ep-tab-close:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; opacity: 1; }
9632
9815
  .ds-247420 .ds-ep-tab.active {
9633
- color: var(--accent);
9816
+ /* --accent-ink for the TEXT, bare --accent for the RULE. The lime fill
9817
+ measures 1.07:1 against paper, so as a text colour it is invisible in
9818
+ light theme; --accent-ink is 8.85:1. Both resolve to the same value in
9819
+ dark, which is exactly why this class of bug hides until someone opens
9820
+ the light theme. Borders are fills and keep the lead accent. */
9821
+ color: var(--accent-ink);
9634
9822
  border-bottom-color: var(--accent);
9635
9823
  }
9636
9824
  /* When the JS slider is active, the active tab's own static border is
@@ -9677,8 +9865,12 @@
9677
9865
  color: var(--panel-text);
9678
9866
  }
9679
9867
  .ds-247420 .ds-ep-tree-item.selected > .ds-ep-tree-row {
9868
+ /* The 22% accent wash is a FILL and stays on the lead accent; the label on
9869
+ top of it is text and takes --accent-ink (bare --accent is 1.07:1 on
9870
+ paper -- invisible in light theme, identical to --accent-ink in dark,
9871
+ which is why it reads fine until someone switches themes). */
9680
9872
  background: color-mix(in oklab, var(--accent) 22%, transparent);
9681
- color: var(--accent);
9873
+ color: var(--accent-ink);
9682
9874
  }
9683
9875
  .ds-247420 .ds-ep-tree-twist {
9684
9876
  width: 12px; flex-shrink: 0; text-align: center;
@@ -11641,7 +11833,15 @@
11641
11833
 
11642
11834
  /* Event-list row hover + search-result flash. */
11643
11835
  .ds-247420 .ds-event-list .row[role="button"]:hover { background: color-mix(in srgb, var(--fg) 5%, transparent); }
11644
- .ds-247420 .ds-event-list .row.event-flash { animation: agentgui-event-flash 2s ease-out; }
11836
+ /* Opt-in like every other animation in the kit: the flash is declared only
11837
+ under no-preference, so a reduced-motion user gets the row without a 2s
11838
+ pulsing highlight. It animates background rather than transform, so the
11839
+ vestibular risk is low, but a repeating attention pull is still exactly the
11840
+ kind of thing the preference exists to suppress. The row is located by the
11841
+ scroll-into-view that accompanies it, so nothing is lost when it is absent. */
11842
+ @media (prefers-reduced-motion: no-preference) {
11843
+ .ds-247420 .ds-event-list .row.event-flash { animation: agentgui-event-flash 2s ease-out; }
11844
+ }
11645
11845
 
11646
11846
 
11647
11847
  /* Generic interactive focus ring for app-emitted controls. */
@@ -11935,6 +12135,32 @@
11935
12135
  margin-bottom: var(--space-1);
11936
12136
  }
11937
12137
 
12138
+ /* .ds-prose-endnote — the closing line of an article ("end. reply by opening a
12139
+ pr."), set off from the body it terminates. Quieter and smaller than prose:
12140
+ it takes the mono face and the --panel-text-2 tone that this sheet's other
12141
+ ancillary voices use (.toc a, .gm-callout .who, .card .desc), so the endnote
12142
+ reads as chrome around the article rather than a final paragraph of it. The
12143
+ generous --space-5 lead is what does the "set off" — it breaks the paragraph
12144
+ rhythm so the eye registers the piece has ended before reading the words.
12145
+ Sized at --fs-xs rather than the --fs-nano label rung: this is a readable
12146
+ sentence with a link in it, not an uppercase micro-label.
12147
+ Replaces the inline style ui_kits/blog carried before the inline-style
12148
+ sweep, which named this class without ever defining it. */
12149
+ .ds-247420 .ds-prose .ds-prose-endnote,
12150
+ .ds-247420 .ds-prose-endnote {
12151
+ margin-top: var(--space-5);
12152
+ margin-bottom: 0;
12153
+ font-family: var(--ff-mono);
12154
+ font-size: var(--fs-xs);
12155
+ line-height: 1.6;
12156
+ color: var(--panel-text-2);
12157
+ }
12158
+ /* The endnote's link keeps the prose accent but stays in the quiet register —
12159
+ --panel-accent is the panel-ramp counterpart of --accent-ink (a readable
12160
+ TEXT tone), never the bare --accent fill, which is ~1.07:1 on paper. */
12161
+ .ds-247420 .ds-prose-endnote a { color: var(--panel-accent); text-decoration: none; }
12162
+ .ds-247420 .ds-prose-endnote a:hover { text-decoration: underline; }
12163
+
11938
12164
  /* marketing.css */
11939
12165
  /* marketing.css — landing / docs site surface family (the agentgui flatspace
11940
12166
  * site renderer composes these instead of carrying inline style= props). Every