@apliteni/apliteni-ui 0.92.0 → 0.93.0

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/README.md +5 -7
  2. package/package.json +1 -1
  3. package/react/README.md +2 -2
  4. package/react/dist/index.d.ts +3 -3
  5. package/src/assets/icons.js +1 -1
  6. package/src/components/account-nav.js +2 -2
  7. package/src/components/back.js +2 -2
  8. package/src/components/command-palette.js +2 -2
  9. package/src/components/drawer.js +1 -1
  10. package/src/components/dropdown.js +12 -12
  11. package/src/components/filter-bar.js +2 -2
  12. package/src/components/footer.js +1 -1
  13. package/src/components/index.js +1 -1
  14. package/src/components/loading.js +1 -1
  15. package/src/components/shell.js +19 -19
  16. package/src/components/stat.js +3 -3
  17. package/src/components/success.js +3 -3
  18. package/src/components/tooltip.js +1 -1
  19. package/src/components/topbar.js +1 -1
  20. package/src/html.js +1 -1
  21. package/src/index.css +1 -1
  22. package/src/index.d.ts +1 -1
  23. package/src/logic/accents.js +1 -1
  24. package/src/logic/filter-bar.js +4 -4
  25. package/src/styles/back.css +3 -3
  26. package/src/styles/base.css +3 -3
  27. package/src/styles/button.css +3 -3
  28. package/src/styles/callout.css +2 -2
  29. package/src/styles/card.css +8 -8
  30. package/src/styles/command-palette.css +14 -14
  31. package/src/styles/confirm.css +7 -7
  32. package/src/styles/drawer.css +8 -8
  33. package/src/styles/dropdown.css +21 -21
  34. package/src/styles/feedback.css +2 -2
  35. package/src/styles/field-zoom.css +1 -1
  36. package/src/styles/file-drop.css +1 -1
  37. package/src/styles/filter-bar.css +6 -6
  38. package/src/styles/footer.css +1 -1
  39. package/src/styles/input.css +6 -6
  40. package/src/styles/layout.css +32 -32
  41. package/src/styles/loading.css +1 -1
  42. package/src/styles/motion.css +1 -1
  43. package/src/styles/nav.css +4 -4
  44. package/src/styles/pagination.css +2 -2
  45. package/src/styles/reduced-motion.css +2 -2
  46. package/src/styles/segmented.css +3 -3
  47. package/src/styles/stat.css +3 -3
  48. package/src/styles/success.css +1 -1
  49. package/src/styles/table.css +6 -6
  50. package/src/styles/tap-zone.css +1 -1
  51. package/src/styles/tooltip.css +3 -3
  52. package/src/styles/topbar.css +8 -8
  53. package/src/tokens/accents.css +1 -1
  54. package/src/tokens/tokens.css +25 -25
@@ -14,13 +14,13 @@
14
14
 
15
15
  /* Shut, a panel is the trigger's width, never the 240px floor a standalone
16
16
  dropdown gets: it is laid out while hidden, so a wider one widened the page
17
- (#467). why: docs/specification.md#a-filter-row-holds-its-panels */
17
+ (#467). why: docs/components.md#a-filter-row-holds-its-panels */
18
18
  .ui-filter-bar .ui-dropdown__panel { min-width: 100%; max-width: 100%; overflow-wrap: anywhere; }
19
19
  /* The clear action takes the kit's bordered skin minus its fill: words belong on
20
20
  the page, not on a grey block, in any state — Artur, round r28. Rest stays at
21
21
  (0,1,1) so `.ui-btn:hover`'s accent wash still outranks it; the rules under it
22
22
  answer each state that paints a NEUTRAL fill, one step above the kit rule
23
- writing it. Held by filter-bar.test.js. why: docs/specification.md#a-filter-row-holds-its-panels */
23
+ writing it. Held by filter-bar.test.js. why: docs/components.md#a-filter-row-holds-its-panels */
24
24
  [data-filter-clear] button { background: transparent; }
25
25
  .ui-filter-bar [data-filter-clear] button:disabled,
26
26
  .ui-filter-bar [data-filter-clear] button[aria-disabled="true"],
@@ -35,7 +35,7 @@
35
35
 
36
36
  /* Open, a chip's menu takes the kit's menu floor, measured and slid by
37
37
  filterPanelFit(); `is-closing` holds that geometry through the fade. #549
38
- why: docs/specification.md#a-filter-row-holds-its-panels */
38
+ why: docs/components.md#a-filter-row-holds-its-panels */
39
39
  .ui-filter-bar__chip .ui-dropdown.open .ui-dropdown__panel,
40
40
  .ui-filter-bar__chip .ui-dropdown__panel.is-closing {
41
41
  min-width: min(var(--ui-filter-panel-floor, 240px), var(--ui-filter-panel-room, 100%));
@@ -57,7 +57,7 @@
57
57
  open menu too and left 9.8px of the check in a 240px menu — a chevron, not a
58
58
  tick. Open the menu is at the floor with room for the mark, and `is-closing`
59
59
  holds the open geometry through the fade, so it is open for this as well. #550
60
- why: docs/specification.md#a-filter-row-holds-its-panels */
60
+ why: docs/components.md#a-filter-row-holds-its-panels */
61
61
  .ui-filter-bar__chip .ui-dropdown:not(.open) .ui-dropdown__panel:not(.is-closing) .ui-dropdown__tick {
62
62
  flex-shrink: 1;
63
63
  min-width: 0;
@@ -68,7 +68,7 @@
68
68
  tab you are on, and keeps the kit's 16px check. The wash is a 1.2:1 tint, so the
69
69
  check is what identifies the state under WCAG 1.4.1; Apple, Material, Carbon,
70
70
  Primer and Radix all tick a chosen menu row. #549
71
- why: docs/specification.md#a-filter-row-holds-its-panels */
71
+ why: docs/components.md#a-filter-row-holds-its-panels */
72
72
  .ui-filter-bar .ui-dropdown__item.is-selected { background: var(--glow-purple); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */ }
73
73
  /* Kit-wide a chosen label steps down to --text, which left the row in force the
74
74
  faintest in the panel. Under the wash it holds --strong. */
@@ -82,5 +82,5 @@
82
82
  /* Hover's other paint is a 1px edge, 1.06:1 on the wash, which left the row in force
83
83
  the one row a pointer got no answer from. Selection is a background highlight, so
84
84
  hover deepens it: 9% more accent, the step .ui-table--zebra gives a hovered row.
85
- why: docs/specification.md#a-filter-row-holds-its-panels */
85
+ why: docs/components.md#a-filter-row-holds-its-panels */
86
86
  .ui-filter-bar .ui-dropdown__item.is-selected:hover { background: color-mix(in srgb, var(--glow-purple), var(--accent) 9%); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */ }
@@ -121,7 +121,7 @@
121
121
 
122
122
  /* Responsive — columns collapse to a stacked layout on narrow screens. Two of
123
123
  the kit's three steps, and the second one is the phone step rather than a
124
- fourth value of the footer's own: docs/specification.md#breakpoints. */
124
+ fourth value of the footer's own: docs/foundations.md#breakpoints. */
125
125
  @media (max-width: 720px) {
126
126
  .ui-footer__top { flex-direction: column; gap: 30px; }
127
127
  .ui-footer__nav { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 26px 30px; }
@@ -24,7 +24,7 @@
24
24
  font-size: var(--text-base);
25
25
  color: var(--strong);
26
26
  /* Fields use the card surface and an edge in both themes.
27
- why: docs/specification.md#elevation */
27
+ why: docs/foundations.md#elevation */
28
28
  background: var(--field-bg); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */
29
29
  border: 1px solid var(--field-edge);
30
30
  border-radius: var(--radius-md);
@@ -57,8 +57,8 @@
57
57
  longhands the chevron is drawn with (#511). Held by stories/select-chevron.test.js.
58
58
  `opacity` is the other half of that grey-out, and no colour here outranks it, so
59
59
  the fade is reset below — it took the edge and the words down together. #564,
60
- argued at docs/specification.md#colour-and-contrast.
61
- why: docs/specification.md#icons-and-glyphs */
60
+ argued at docs/foundations.md#colour-and-contrast.
61
+ why: docs/foundations.md#icons-and-glyphs */
62
62
  .ui-input:disabled,
63
63
  .ui-select:disabled,
64
64
  .ui-textarea:disabled {
@@ -81,7 +81,7 @@
81
81
  `search` glyph and no clear button, so a field without one is what the
82
82
  design already says. Measured in Chromium; Firefox draws nothing here and
83
83
  Edge is untested.
84
- why: docs/specification.md#colour-and-contrast */
84
+ why: docs/foundations.md#colour-and-contrast */
85
85
  .ui-input[type="search"]::-webkit-search-cancel-button {
86
86
  appearance: none;
87
87
  display: none;
@@ -106,7 +106,7 @@
106
106
  which is the colour every other quiet glyph on a field takes. It was one frozen
107
107
  hex until #295, dark --muted's old value, which the ladder's re-pick left behind
108
108
  at 2.49:1 on the light field. Held by stories/colour-tokens.test.js.
109
- why: docs/specification.md#colour-and-contrast */
109
+ why: docs/foundations.md#colour-and-contrast */
110
110
  .ui-select {
111
111
  appearance: none;
112
112
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23a29db6' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
@@ -233,7 +233,7 @@
233
233
  /* --shadow-sm was the knob's only edge until #295, and a white knob on a light
234
234
  off-track has 1.20:1 to spare. --border-strong and not --border, which measures
235
235
  1.03:1 against that track and draws nothing — the checkbox above edges itself
236
- the same way. why: docs/specification.md#elevation */
236
+ the same way. why: docs/foundations.md#elevation */
237
237
  border: 1px solid var(--border-strong);
238
238
  box-sizing: border-box;
239
239
  border-radius: 50%;
@@ -18,7 +18,7 @@
18
18
  font-family: var(--font-sans);
19
19
  /* The rail's width, and the one property the fold moves: the nav's own column
20
20
  plus the inset either side plus the rule, so the shell has no geometry of its
21
- own to drift from the rows inside it. why: docs/specification.md#the-page-shell */
21
+ own to drift from the rows inside it. why: docs/components.md#the-page-shell */
22
22
  --ui-rail-rule: 1px;
23
23
  --ui-rail-w: calc(var(--ui-nav-col) + 2 * var(--space-4) + var(--ui-rail-rule));
24
24
  }
@@ -30,7 +30,7 @@
30
30
  /* The rail uses the card surface so its labels stay on a reading ground.
31
31
  Dark keeps its edge (--rail-edge); light casts --elev-rail, sideways, because the rail
32
32
  is flush to a screen edge. Reopens the light half of #454.
33
- why: docs/specification.md#elevation
33
+ why: docs/foundations.md#elevation
34
34
  overflow-y, because the box is pinned at the viewport's height for the whole
35
35
  scroll of .ui-app — without it a row past that height paints below the fold
36
36
  and no amount of document scrolling brings it back. The rail's own padding is
@@ -49,7 +49,7 @@
49
49
  width: var(--ui-rail-w);
50
50
  /* hidden across, auto down: the fold clips what leaves the screen rather than
51
51
  laying it out again. Two longhands, not the shorthand — the gates' CSS engine
52
- does not read the pair. why: docs/specification.md#the-page-shell */
52
+ does not read the pair. why: docs/components.md#the-page-shell */
53
53
  overflow-x: hidden;
54
54
  overflow-y: auto;
55
55
  transition: width var(--dur-med) var(--ease);
@@ -58,7 +58,7 @@
58
58
  nav declares its own; these are the three that are not the nav. Scoped to the rail,
59
59
  because the topbar layout draws the reader's block in its band instead and a column
60
60
  the rail's width is no measurement for a box on a 52px line.
61
- why: docs/specification.md#the-page-shell */
61
+ why: docs/components.md#the-page-shell */
62
62
  .ui-app__rail > .ui-app__head,
63
63
  .ui-app__rail > .ui-app__user,
64
64
  .ui-app__rail > .ui-app__foot { width: var(--ui-nav-col); flex: none; }
@@ -75,7 +75,7 @@
75
75
  text-decoration: none;
76
76
  /* The lockup leaves on the words' clock, `visibility` with it so the link leaves
77
77
  the tab order — `linear`, as every discrete property in the kit is.
78
- why: docs/specification.md#the-page-shell */
78
+ why: docs/components.md#the-page-shell */
79
79
  transition: opacity var(--dur-fast) var(--ease), visibility var(--dur-fast) linear;
80
80
  /* display: brand — the rail's lockup is the same mark topbar.css sets, and the
81
81
  two have to be the same face or the shell reads as two products. */
@@ -91,7 +91,7 @@
91
91
 
92
92
  /* The head band: the product's mark, and the rail's own control at the far end of
93
93
  the same line. `min-width: 0` so a long word shrinks the lockup rather than pushing
94
- the control off the band. why: docs/specification.md#the-page-shell */
94
+ the control off the band. why: docs/components.md#the-page-shell */
95
95
  .ui-app__head {
96
96
  display: flex;
97
97
  align-items: center;
@@ -139,7 +139,7 @@
139
139
  }
140
140
  /* The other thing that can close a rail: where the reader's block is in the band,
141
141
  the fold's control takes its place under the same rule.
142
- why: docs/specification.md#the-page-shell */
142
+ why: docs/components.md#the-page-shell */
143
143
  .ui-app__foot {
144
144
  display: flex;
145
145
  align-items: center;
@@ -152,7 +152,7 @@
152
152
  /* The avatar is the reader block's own glyph, so half the difference between the
153
153
  glyph column and itself is the inset that centres it on the line every glyph above
154
154
  it stands on. The arithmetic and not the 5.5 it comes to: both numbers are declared
155
- elsewhere. why: docs/specification.md#the-page-shell */
155
+ elsewhere. why: docs/components.md#the-page-shell */
156
156
  .ui-app { --ui-app-av: 30px; }
157
157
  .ui-app__av {
158
158
  width: var(--ui-app-av); height: var(--ui-app-av); flex: none;
@@ -173,7 +173,7 @@
173
173
  /* -- the reader's menu ---------------------------------------------------- */
174
174
  /* The account block is a dropdown() trigger, so it takes the rail's own row skin
175
175
  rather than the dropdown's pill — in place it is the last row of the rail. The
176
- dropdown's own ring is left standing. why: docs/specification.md#the-page-shell */
176
+ dropdown's own ring is left standing. why: docs/components.md#the-page-shell */
177
177
  .ui-app__user .ui-dropdown { width: 100%; }
178
178
  .ui-app .ui-app__user-trigger {
179
179
  width: 100%;
@@ -196,7 +196,7 @@
196
196
  .ui-app__user-trigger .ui-app__who { flex: 1 1 auto; text-align: left; }
197
197
  /* The panel is portalled onto <body>, so nothing here may hang off .ui-app: by the
198
198
  time it is open it is no longer inside the rail that drew it.
199
- why: docs/specification.md#the-dropdown-panel */
199
+ why: docs/components.md#the-dropdown-panel */
200
200
  .ui-app__user-panel .ui-dropdown__head { display: flex; flex-direction: column; gap: 2px; }
201
201
  .ui-app__user-panel .ui-dropdown__head b { display: block; color: var(--strong); font-size: calc(var(--text-sm) - 0.5px); font-weight: var(--weight-semibold); }
202
202
  /* The address wraps rather than truncating: nothing bounds this line, so
@@ -208,7 +208,7 @@
208
208
  /* The toggle's cell, at the far end of the brand row: the auto margin puts it there
209
209
  with or without a wordmark beside it, and the offset below rides it back onto the
210
210
  glyph column as the rail closes. `position: relative` and not a transform, because
211
- the chip inside is `position: fixed`. why: docs/specification.md#the-page-shell */
211
+ the chip inside is `position: fixed`. why: docs/components.md#the-page-shell */
212
212
  .ui-app__fold-row {
213
213
  flex: none;
214
214
  margin-inline-start: auto;
@@ -219,12 +219,12 @@
219
219
  /* One box on the glyph column at both widths — --ui-nav-strip, the width nav.css
220
220
  derives the closed rail from. `gap: 0` leaves that column the whole of the
221
221
  content box, so the label below is squeezed to nothing until the chip rule lifts
222
- it out. why: docs/specification.md#the-page-shell */
222
+ it out. why: docs/components.md#the-page-shell */
223
223
  .ui-app__fold { width: var(--ui-nav-strip); gap: 0; }
224
224
  /* The chip rule lifts the name out of the flow, and a 17px glyph is shorter than
225
225
  the line the name occupied — so the button lost 0.39px on hover and moved every
226
226
  row under it. The glyph box carries the line instead, in both states.
227
- why: docs/specification.md#the-page-shell */
227
+ why: docs/components.md#the-page-shell */
228
228
  .ui-app__fold .ui-nav__ic { height: 1lh; }
229
229
  .ui-app .ui-app__fold { color: var(--text); }
230
230
  .ui-app .ui-app__fold:hover,
@@ -243,7 +243,7 @@
243
243
 
244
244
  The width's own clock, not the words', so the mark and the closing edge arrive
245
245
  together; no `!important`, so the reduced-motion net still takes it.
246
- why: docs/specification.md#the-page-shell */
246
+ why: docs/components.md#the-page-shell */
247
247
  .ui-app__fold .ui-app__fold-arrow {
248
248
  transform-box: view-box;
249
249
  transform-origin: 15px 12px;
@@ -253,7 +253,7 @@
253
253
 
254
254
  /* -- The collapsed rail --------------------------------------------------- */
255
255
  /* Each rule here has its twin in the 720px block below; nothing lays a row out
256
- again. why: docs/specification.md#the-page-shell */
256
+ again. why: docs/components.md#the-page-shell */
257
257
  .ui-app.is-collapsed { --ui-rail-w: calc(var(--ui-nav-strip) + 2 * var(--space-4) + var(--ui-rail-rule)); }
258
258
  :where(.ui-app.is-collapsed) .ui-app__rail .ui-nav__cap,
259
259
  :where(.ui-app.is-collapsed) .ui-app__rail .ui-nav__label,
@@ -266,14 +266,14 @@
266
266
  lockup goes whole, since that column is where its mark stood. The mark may only go
267
267
  where the control arrives: below 720px the toggle is not drawn, so the 720px block
268
268
  gives the lockup back rather than leaving an empty band with a hairline under it.
269
- why: docs/specification.md#the-page-shell */
269
+ why: docs/components.md#the-page-shell */
270
270
  :where(.ui-app.is-collapsed) .ui-app__head > .ui-app__fold-row { inset-inline-start: calc(var(--ui-nav-strip) - var(--ui-nav-col)); }
271
271
  /* …and only in the layout where something arrives on the mark's column. In the
272
272
  topbar layout the toggle is at the rail's foot, nothing lands where the mark
273
273
  stands, and a lockup faded out there leaves a band with nothing in it and its
274
274
  hairline still under it — the defect the 720px block below exists to avoid. So
275
275
  that layout keeps the mark and lets the shared rule above fold away its words.
276
- why: docs/specification.md#the-page-shell */
276
+ why: docs/components.md#the-page-shell */
277
277
  :where(.ui-app:not(.ui-app--topbar).is-collapsed) .ui-app__brand { opacity: 0; visibility: hidden; pointer-events: none; }
278
278
  :where(.ui-app.is-collapsed) .ui-app__rail .ui-nav__sub { margin-inline-start: 0; padding-inline-start: 0; border-inline-start-width: 0; }
279
279
  :where(.ui-app.is-collapsed) .ui-app__rail .ui-nav__item:not(:has(.ui-nav__ic))::after { opacity: 0.62; }
@@ -282,7 +282,7 @@
282
282
  row's own left padding, which on the strip is the rail's edge; the hairline is
283
283
  drawn on a row that keeps the open column, so its right edge is off the strip;
284
284
  and --ui-nav-strip is twice the glyph's centre, so a box that wide at the row's
285
- edge is centred on the glyph. why: docs/specification.md#the-page-shell */
285
+ edge is centred on the glyph. why: docs/components.md#the-page-shell */
286
286
  :where(.ui-app.is-collapsed) .ui-app__rail .ui-nav__item.is-active { isolation: isolate; background: none; }
287
287
  :where(.ui-app.is-collapsed) .ui-app__rail .ui-nav__item.is-active:not(:focus-visible) { box-shadow: none; }
288
288
  :where(.ui-app.is-collapsed) .ui-app__rail .ui-nav__item.is-active::before { left: 0; width: var(--ui-nav-strip); height: 100%; border-radius: 10px; background: var(--surface-3); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ z-index: -1; }
@@ -295,8 +295,8 @@
295
295
  It floats by role — a readout placed over the page for as long as a pointer
296
296
  rests on a row — so it takes the floating treatment the hover readout takes,
297
297
  which is the same shape on the same step: the two-step edge and the drops.
298
- why: docs/specification.md#the-page-shell
299
- why: docs/specification.md#elevation */
298
+ why: docs/components.md#the-page-shell
299
+ why: docs/foundations.md#elevation */
300
300
  :where(.ui-app.is-collapsed) .ui-app__rail .ui-nav__item:is(:hover, :focus-visible) > .ui-nav__label,
301
301
  :where(.ui-app.is-collapsed) .ui-app__rail .ui-app__user-trigger:is(:hover, :focus-visible) > .ui-app__who,
302
302
  .ui-app__rail .ui-app__fold:is(:hover, :focus-visible) > .ui-nav__label { position: fixed; left: calc(var(--ui-rail-w) + var(--space-2)); z-index: var(--z-dropdown); width: max-content; max-width: 15rem; margin-block: -7px; padding: 6px 10px; border: 1px solid var(--float-edge); box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop); border-radius: var(--radius-xs); background: var(--surface); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ color: var(--strong); opacity: 1; pointer-events: none; }
@@ -330,7 +330,7 @@
330
330
  padding: 40px clamp(24px, 4vw, 56px) 72px;
331
331
  }
332
332
  /* The whole of the difference: `centered` is the rule above and `wide` takes its cap
333
- off. `maxWidth` is the number under either name. why: docs/specification.md#widths */
333
+ off. `maxWidth` is the number under either name. why: docs/foundations.md#widths */
334
334
  .ui-app__main--wide { max-width: var(--ui-app-main, none); }
335
335
 
336
336
  /* -- The topbar layout ----------------------------------------------------- */
@@ -338,7 +338,7 @@
338
338
  arrangement where the rail's head band and the band close at the same height — what
339
339
  the three heights below are for. Level, not one continuous stroke: the rail insets
340
340
  its own rule, and in light that half is 1.009:1 on the rail's ground.
341
- why: docs/specification.md#the-second-layout */
341
+ why: docs/components.md#the-second-layout */
342
342
  .ui-app { --ui-app-band: 52px; }
343
343
  .ui-app__well { display: flex; flex-direction: column; min-width: 0; }
344
344
  .ui-app__bar {
@@ -368,7 +368,7 @@
368
368
  like is the point. The STEP is not, and that is the one thing this control does
369
369
  differently from every other field in the kit: the reason is on the declaration
370
370
  below. It gives way before anything else on the band.
371
- why: docs/specification.md#the-page-shell */
371
+ why: docs/components.md#the-page-shell */
372
372
  .ui-app__search {
373
373
  display: flex;
374
374
  align-items: center;
@@ -383,7 +383,7 @@
383
383
  text-align: start;
384
384
  color: var(--text);
385
385
  /* The band search uses the same reading surface as other text controls.
386
- why: docs/specification.md#elevation */
386
+ why: docs/foundations.md#elevation */
387
387
  background: var(--surface); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */
388
388
  border: 1px solid var(--border);
389
389
  border-radius: var(--radius-md);
@@ -394,7 +394,7 @@
394
394
  /* Every other control on the band takes the kit's ring. This one is a <button>
395
395
  without `.ui-btn`, so base.css's shared rule never reached it and focus fell
396
396
  through to the browser's own square outline, drawn around a 12px radius.
397
- why: docs/specification.md#the-focus-ring */
397
+ why: docs/foundations.md#the-focus-ring */
398
398
  .ui-app__search:focus-visible { outline: 2px solid transparent; box-shadow: var(--ring); border-color: var(--accent); }
399
399
  /* The same glyph the palette draws in its own search box, at the same box and the
400
400
  same stroke: the trigger and the thing it opens are not two search marks.
@@ -409,7 +409,7 @@
409
409
 
410
410
  /* The mark alone — no room for two lines on a 52px row. No rule over it, since the
411
411
  band's hairline is under the whole of it, and no column, since this is not the rail.
412
- why: docs/specification.md#the-page-shell */
412
+ why: docs/components.md#the-page-shell */
413
413
  .ui-app__user--bar { flex: none; padding-top: 0; border-top: 0; }
414
414
  .ui-app__user--bar .ui-app__av { margin-inline-start: 0; }
415
415
  /* Crumb, then the title block. At --space-2 the crumb sat 8px off the h1 and
@@ -447,7 +447,7 @@
447
447
  .ui-toolbar > .ui-input-group { flex: 1 1 6rem; min-width: 0; }
448
448
  /* At one column the 6rem basis stops being a floor and becomes the field's size:
449
449
  a row with two narrow chips beside it keeps all three on the line and cuts the
450
- field's own placeholder off. why: docs/specification.md#a-toolbar-at-one-column */
450
+ field's own placeholder off. why: docs/components.md#a-toolbar-at-one-column */
451
451
  @media (max-width: 560px) {
452
452
  .ui-toolbar > .ui-input,
453
453
  .ui-toolbar > .ui-input-group { flex-basis: 100%; }
@@ -466,19 +466,19 @@
466
466
  /* …and the foot goes with it, for the reason the head band does below: in the
467
467
  topbar layout that box holds the toggle and nothing else, so at this width it is
468
468
  padding and a hairline drawn over nothing. Scoped to the shell's own rail, like
469
- every other rule in this block. why: docs/specification.md#the-page-shell */
469
+ every other rule in this block. why: docs/components.md#the-page-shell */
470
470
  .ui-app__rail .ui-app__foot { display: none; }
471
471
  /* …and with it the band, when the band has nothing else in it: a head with no
472
472
  wordmark is the toggle alone, so at this width it is padding and a hairline
473
473
  drawn over nothing. The reader's fold cannot take this rule — there the toggle
474
- IS drawn. why: docs/specification.md#the-page-shell */
474
+ IS drawn. why: docs/components.md#the-page-shell */
475
475
  .ui-app__head:not(:has(> .ui-app__brand)) { display: none; }
476
476
  /* And where the band does hold the mark, the mark stays — at this width the press
477
477
  that folded the rail on a desktop still reads out of the cookie, and the control
478
478
  that would undo it is the one above. A head band faded to nothing here is an empty
479
479
  41px box over a rule, with no way home. The reader's fold cannot take this rule —
480
480
  there the toggle lands on the column the mark gives up.
481
- why: docs/specification.md#the-page-shell */
481
+ why: docs/components.md#the-page-shell */
482
482
  .ui-app__brand { opacity: 1; visibility: visible; pointer-events: auto; }
483
483
  .ui-app__rail .ui-nav__cap,
484
484
  .ui-app__rail .ui-nav__label,
@@ -496,7 +496,7 @@
496
496
  /* The one line of this block that is deliberately NOT the reader's fold: a finger
497
497
  is the only pointer this width has, so a row and the account block are held to
498
498
  44px. Neither floor can spread to the press, where growing the box is the one
499
- thing the travel promises nothing does. why: docs/specification.md#the-page-shell */
499
+ thing the travel promises nothing does. why: docs/components.md#the-page-shell */
500
500
  .ui-app__rail .ui-nav__item,
501
501
  .ui-app__rail .ui-app__user-trigger { min-height: 44px; }
502
502
  .ui-app__rail .ui-nav__item:is(:hover, :focus-visible) > .ui-nav__label,
@@ -534,7 +534,7 @@
534
534
  max-width: var(--panel-md);
535
535
  /* Floats over a spotlit page, so it takes the floating step and the floating
536
536
  treatment: the two-step edge in dark, the drop alone in light.
537
- why: docs/specification.md#elevation */
537
+ why: docs/foundations.md#elevation */
538
538
  background: var(--bg-elevated); --ring-gap: var(--bg-elevated);
539
539
  border: 1px solid var(--float-edge);
540
540
  box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
@@ -9,7 +9,7 @@
9
9
  * own red made it read as a fault the reader had committed. The lock says which
10
10
  * of the two it is.
11
11
  *
12
- * why: docs/specification.md#pending-and-denied-states */
12
+ * why: docs/components.md#pending-and-denied-states */
13
13
 
14
14
  /* Visually hidden, still read aloud. The kit had no such utility, and the live
15
15
  region needs one: its message is for assistive tech only — the sighted
@@ -13,7 +13,7 @@
13
13
  * @imported from here — the icon gates read each stylesheet on its own and
14
14
  * refuse a sheet that pulls in another.
15
15
  *
16
- * why: docs/specification.md#motion */
16
+ * why: docs/foundations.md#motion */
17
17
 
18
18
  /* -- Entrances -------------------------------------------------------------
19
19
  * `both` fill so the element starts at the "from" frame (hidden) and holds
@@ -43,7 +43,7 @@
43
43
  .ui-nav__cap {
44
44
  /* rank: label */
45
45
  /* Words, never a control, at BOTH widths — as __label, __badge and __caret below.
46
- why: docs/specification.md#a-folded-rail-takes-the-pointer-only-where-it-draws */
46
+ why: docs/components.md#a-folded-rail-takes-the-pointer-only-where-it-draws */
47
47
  pointer-events: none;
48
48
  font-size: var(--text-sm);
49
49
  font-weight: var(--weight-medium);
@@ -74,7 +74,7 @@
74
74
  font-family: inherit;
75
75
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
76
76
  }
77
- .ui-nav .ui-nav__item { color: var(--text); } /* (0,2,0): a host sheet's a:link is (0,1,1) — why: docs/specification.md#the-page-shell */
77
+ .ui-nav .ui-nav__item { color: var(--text); } /* (0,2,0): a host sheet's a:link is (0,1,1) — why: docs/components.md#the-page-shell */
78
78
  .ui-nav__item:hover { outline: 1px solid var(--control-edge); outline-offset: -1px; background: var(--surface); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */ color: var(--strong); }
79
79
  .ui-nav__item.is-active {
80
80
  background: var(--surface); /* ring-gap: inherit — control paint; its focus indicator uses the containing surface. */
@@ -164,7 +164,7 @@
164
164
  number, not a second answer to "where am I". It also retires the pair #157
165
165
  recorded: accent ink on --surface fell under WCAG AA in four of the eight
166
166
  theme x accent cells (4.08 in dark Nebula), and no alpha cleared it. Nothing
167
- now paints that pair. See #429 and docs/specification.md#colour-and-contrast. */
167
+ now paints that pair. See #429 and docs/foundations.md#colour-and-contrast. */
168
168
  .ui-nav__item.is-active .ui-nav__badge.is-accent { background: var(--surface); /* ring-gap: inherit — decorative or text-only surface has no nested focus target. */ color: var(--strong); }
169
169
 
170
170
  /* Collapsible group */
@@ -242,7 +242,7 @@
242
242
  /* Every box in the rail closes with it, whether it paints or not. A block that keeps
243
243
  the open column paints nothing and still takes the pointer off 175px of the page
244
244
  beside a positioned rail (#588); clipping it instead cut the rows' ring (#575).
245
- why: docs/specification.md#a-folded-rail-takes-the-pointer-only-where-it-draws */
245
+ why: docs/components.md#a-folded-rail-takes-the-pointer-only-where-it-draws */
246
246
  .ui-nav--side.is-collapsed > * { width: var(--ui-nav-strip); }
247
247
  .ui-nav--side.is-collapsed .ui-nav__item { width: var(--ui-nav-strip); }
248
248
  /* The heading is the one box that keeps the open column: its line breaks are the rail's
@@ -107,7 +107,7 @@
107
107
  declared on the one adjacency the kit can see. `.rx-pager` carried a bare
108
108
  `margin-top: 16px` for this, which is --space-4; the number moves to the scale
109
109
  with it rather than travelling as a literal.
110
- why: docs/specification.md#spacing-and-rhythm */
110
+ why: docs/foundations.md#spacing-and-rhythm */
111
111
  .ui-table + .ui-pager { margin-top: var(--space-4); }
112
112
 
113
113
  /* A step given an `href` is an anchor, and a host stylesheet's `a:link` is
@@ -118,7 +118,7 @@
118
118
  `.ui-nav .ui-nav__item` in nav.css. Storybook ships no `a:link`, so the "Pages
119
119
  as links" story cannot show it — which is why the rule is stated rather than
120
120
  discovered.
121
- why: docs/specification.md#pagination */
121
+ why: docs/components.md#pagination */
122
122
  a.ui-pager__step,
123
123
  a.ui-pager__page { color: var(--text); }
124
124
  a.ui-pager__step:hover,
@@ -6,8 +6,8 @@
6
6
  * `iteration-count: 1` lets one-shot animations settle on their final frame — a
7
7
  * checkmark stays drawn — instead of snapping back to the start.
8
8
  *
9
- * why: docs/specification.md#reduced-motion-travels-with-the-stylesheet
10
- * why: docs/specification.md#motion */
9
+ * why: docs/foundations.md#reduced-motion-travels-with-the-stylesheet
10
+ * why: docs/foundations.md#motion */
11
11
 
12
12
  @media (prefers-reduced-motion: reduce) {
13
13
  html { scroll-behavior: auto !important; }
@@ -75,7 +75,7 @@
75
75
  * 2px stroke, in --signal-contrast — the circle wears the accent's dark ramp in
76
76
  * both themes, so its ink is the one for a fill, not the --accent-contrast that
77
77
  * pairs with --accent-strong. Held by stories/accent-mark.test.js.
78
- * why: docs/specification.md#react-accent-picker */
78
+ * why: docs/components.md#page-furniture, and #472 for the ring that was rejected. */
79
79
  .ui-accent-picker button.is-active::after {
80
80
  content: "";
81
81
  position: absolute;
@@ -92,7 +92,7 @@
92
92
 
93
93
  /* Underline tabs wrap for the reason the pills above do — #435 — and draw no
94
94
  rule of their own: the chosen tab carries the selection. #527, #545
95
- why: docs/specification.md#the-chosen-tab-in-an-underline-strip */
95
+ why: docs/components.md#the-chosen-tab-in-an-underline-strip */
96
96
  .ui-seg--underline { flex-wrap: wrap; overflow: visible; row-gap: var(--space-1); align-self: stretch; justify-self: stretch; background: transparent; --ring-gap: inherit; border-radius: 0; padding: var(--space-1); max-width: 100%; }
97
97
  /* `anywhere` is the half `break-word` cannot do: it lowers the tab's min-content
98
98
  width, so one unbreakable word narrows rather than widening the page. The
@@ -106,7 +106,7 @@
106
106
  /* The chosen tab is its label and one bar under it: no plate, no hairline, no
107
107
  upright rail — those read as a list-row grip. `outline: 0` cancels the accent
108
108
  outline the pill rule gives every chosen button, which is #544's second mark.
109
- #527 r31. why: docs/specification.md#the-chosen-tab-in-an-underline-strip */
109
+ #527 r31. why: docs/components.md#the-chosen-tab-in-an-underline-strip */
110
110
  .ui-seg--underline button.is-active,
111
111
  .ui-seg--underline button[aria-pressed="true"] {
112
112
  background: none;
@@ -3,7 +3,7 @@
3
3
  * .ui-stats--tiles one card per figure — the default
4
4
  * .ui-stats--band one card, figures divided by space
5
5
  * .ui-stats--open no surface; a rule over each figure
6
- * why: docs/specification.md#stat-bands
6
+ * why: docs/components.md#stat-bands
7
7
  * ========================================================================== */
8
8
 
9
9
  /* The band lays out from the width of its own box, not the window's: a band in
@@ -76,7 +76,7 @@ dd.ui-stat__caption { margin-top: var(--space-2); }
76
76
  font-weight: var(--weight-medium);
77
77
  line-height: var(--leading-snug);
78
78
  }
79
- .ui-stat__delta svg { width: 14px; height: 14px; flex: none; stroke-width: 2.7; } /* 2.7 of a 24 box drawn at 14px = 1.58 CSS px. docs/specification.md#icons-and-glyphs */
79
+ .ui-stat__delta svg { width: 14px; height: 14px; flex: none; stroke-width: 2.7; } /* 2.7 of a 24 box drawn at 14px = 1.58 CSS px. docs/foundations.md#icons-and-glyphs */
80
80
  .ui-stat__change { font-variant-numeric: tabular-nums; white-space: nowrap; flex: none; }
81
81
  .ui-stat__basis { color: var(--text); font-weight: var(--weight-normal); }
82
82
 
@@ -129,7 +129,7 @@ dd.ui-stat__caption { contain: inline-size; }
129
129
  count stacks. The widths are where four and three tiles of `€ 6,459,401`
130
130
  stop fitting, and the open band's larger value moves them out; a longer
131
131
  figure still wraps rather than overlaps.
132
- why: docs/specification.md#stat-bands */
132
+ why: docs/components.md#stat-bands */
133
133
  @container (28rem < width <= 56rem) {
134
134
  .ui-stats:not(.ui-stats--open) .ui-stats__list:has(> .ui-stat:nth-child(4):last-child) > .ui-stat { flex-basis: 34%; }
135
135
  }
@@ -18,7 +18,7 @@
18
18
  border-radius: 20px;
19
19
  background: var(--bg-elevated); --ring-gap: var(--bg-elevated); /* Elevated surface for the confirmation and its actions. */
20
20
  /* The floating treatment, like every other surface on that step.
21
- why: docs/specification.md#elevation */
21
+ why: docs/foundations.md#elevation */
22
22
  border: 1px solid var(--float-edge);
23
23
  box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
24
24
  isolation: isolate;
@@ -33,7 +33,7 @@
33
33
  /* The last row of the last section, so a final body row keeps its separator when a
34
34
  * footer follows it. `tr:last-child td` closed the wrong edge: it stripped the border
35
35
  * from the last row of every section, leaving items and totals with nothing between
36
- * them. why: docs/specification.md#spacing-and-rhythm */
36
+ * them. why: docs/foundations.md#spacing-and-rhythm */
37
37
  .ui-table > :last-child > tr:last-child > :is(th, td) { border-bottom: 0; }
38
38
  /* Totals open with the 2px rule the zebra header already uses, so a reader can see
39
39
  * where items end and totals begin; five identical hairlines told them nothing.
@@ -77,7 +77,7 @@
77
77
  * --dense --space-3 across, --space-2 down — one step in from the base table
78
78
  * --zebra legacy spacing and 2px header rule; the base-surface rule below removes stripes
79
79
  * Cell helpers: .ui-table__num (right, tabular), .ui-table__code.
80
- * why: docs/specification.md#spacing-and-rhythm
80
+ * why: docs/foundations.md#spacing-and-rhythm
81
81
  * held by: stories/table-rhythm.test.js */
82
82
  .ui-table--dense th { padding: 0 var(--space-3) var(--space-2); }
83
83
  .ui-table--dense td,
@@ -187,7 +187,7 @@
187
187
  /* The end-cell inset above gives a row's highlight room; the bleed is what stops the grid
188
188
  paying for it. The table hangs out by the same --space-3, into the card's 20-24px
189
189
  padding and never past it, so the columns start on the card's own text edge and the
190
- scroll region stays empty at rest. why: docs/specification.md#spacing-and-rhythm */
190
+ scroll region stays empty at rest. why: docs/foundations.md#spacing-and-rhythm */
191
191
  .ui-card > :where(.ui-table--dense, .ui-table--zebra) {
192
192
  width: calc(100% + 2 * var(--space-3));
193
193
  margin-inline: calc(-1 * var(--space-3));
@@ -212,7 +212,7 @@
212
212
  It had no room of its own to draw in — the padding above is horizontal — which is the
213
213
  second reason the band is an outline: it is painted over the rows, in the cell padding
214
214
  of the first and last, rather than under them. #531
215
- why: docs/specification.md#the-focus-ring */
215
+ why: docs/foundations.md#the-focus-ring */
216
216
  .ui-table-scroll:focus-visible { outline: var(--ring-scroll); outline-offset: var(--ring-scroll-offset); }
217
217
  .ui-table--sticky { border-collapse: separate; border-spacing: 0; }
218
218
  .ui-table--sticky thead th { position: sticky; top: 0; z-index: var(--z-sticky); background: var(--table-bg); --ring-gap: var(--table-bg); padding-top: var(--space-2); }
@@ -249,8 +249,8 @@ a.ui-identity:hover { text-decoration: underline; }
249
249
  * __title reach a cell with two classes, and one class would lose to them and leave
250
250
  * `nowrap` on a paragraph.
251
251
  *
252
- * The consumer's half — the roles a changed `display` drops — is in the specification.
253
- * why: docs/specification.md#dense-financial-tables
252
+ * The consumer's half — the roles a changed `display` drops — is in docs/components.md.
253
+ * why: docs/components.md#dense-financial-tables
254
254
  * held by: src/styles/table-stack.test.js (layout), stories/table-stack.test.js (roles)
255
255
  * ========================================================================== */
256
256
 
@@ -8,7 +8,7 @@
8
8
  * Read LAST, after every component sheet — see src/index.css — because each
9
9
  * opening overrides a gap one of them already set.
10
10
  *
11
- * why: docs/specification.md#a-tap-reaches-the-floor-below-the-phone-step
11
+ * why: docs/foundations.md#a-tap-reaches-the-floor-below-the-phone-step
12
12
  * Held by stories/tap-zone.test.js, measured in a browser at 390.
13
13
  */
14
14
 
@@ -5,7 +5,7 @@
5
5
  * .ui-tip the readout — __label, __value, __detail
6
6
  * The readout is an overlay in every state. It is absolutely placed inside its
7
7
  * host, so showing it, filling it and moving it change the size of nothing.
8
- * why: docs/specification.md#the-hover-readout
8
+ * why: docs/components.md#the-hover-readout
9
9
  * ========================================================================== */
10
10
 
11
11
  .ui-tip-host { position: relative; }
@@ -29,7 +29,7 @@
29
29
  /* The two-step edge and the drop, through the level's own names: in DARK that is
30
30
  --border-strong outside and --border one pixel inside it, then the drop; in LIGHT
31
31
  both lines are transparent and the drop carries the whole separation.
32
- why: docs/specification.md#elevation */
32
+ why: docs/foundations.md#elevation */
33
33
  border: 1px solid var(--float-edge);
34
34
  box-shadow: inset 0 0 0 1px var(--elev-edge, var(--float-edge-inner)), var(--elev-drop);
35
35
  border-radius: var(--radius-sm);
@@ -51,7 +51,7 @@
51
51
 
52
52
  /* The readout uses the floating panel surface in both themes. Its edge
53
53
  and shadow separate it from the card underneath.
54
- why: docs/specification.md#elevation */
54
+ why: docs/foundations.md#elevation */
55
55
 
56
56
  /* Below the mark: the wiring's flip when above would be clipped, or the
57
57
  author's own choice. */