@apliteni/apliteni-ui 0.34.2 → 0.35.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apliteni/apliteni-ui",
3
- "version": "0.34.2",
3
+ "version": "0.35.0",
4
4
  "workspaces": [
5
5
  "react"
6
6
  ],
package/react/README.md CHANGED
@@ -30,6 +30,11 @@ import { DataTable, Modal, Button } from '@apliteni/apliteni-ui/react';
30
30
 
31
31
  Components: `DataTable`, `Pagination`, `StatBand`, `Modal`, `Drawer`, `CommandPalette`, `Dropdown`, `BackLink`, `Button`, `Badge`, `Card`, `Icon`.
32
32
 
33
+ `Button` accepts `size="xs" | "sm" | "md" | "lg"` (default `md`). Use `xs`
34
+ for a small inline control: `<Button size="xs" variant="ghost" icon="copy" iconOnly>Copy</Button>`.
35
+ Its glyph is 13px and its icon-only target is 24×24px; labelled xs buttons use
36
+ `--text-xs`. The other sizes keep 16px glyphs.
37
+
33
38
  `CommandPalette` renders the kit's `commandPalette()` markup, class for class, and imports the
34
39
  kit's ranking rather than repeating it — so a palette a server rendered and the same palette
35
40
  after a keystroke put the same row first. Three differences from the vanilla one. Two are
@@ -7,7 +7,7 @@ declare function Icon({ name }: {
7
7
 
8
8
  type ButtonProps = {
9
9
  variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
10
- size?: 'sm' | 'md' | 'lg';
10
+ size?: 'xs' | 'sm' | 'md' | 'lg';
11
11
  icon?: string;
12
12
  iconRight?: string;
13
13
  iconOnly?: boolean;
@@ -1,6 +1,6 @@
1
1
  /* ============================================================================
2
2
  * Button — .ui-btn (variants: primary / secondary / ghost / danger)
3
- * (sizes: sm / md / lg, [icon], [disabled], [aria-busy])
3
+ * (sizes: xs / sm / md / lg, [icon], [disabled], [aria-busy])
4
4
  * ========================================================================== */
5
5
 
6
6
  .ui-btn {
@@ -72,11 +72,15 @@
72
72
  }
73
73
 
74
74
  /* -- Sizes -------------------------------------------------------------- */
75
- .ui-btn--sm { --btn-pad-y: 6px; --btn-pad-x: 12px; --btn-font: 12.5px; }
75
+ /* why: docs/specification.md#extra-small-buttons */
76
+ .ui-btn--xs { --btn-pad-y: 4.5px; --btn-pad-x: 8px; --btn-font: var(--text-xs); min-width: 24px; min-height: 24px; }
77
+ .ui-btn--xs svg { width: 13px; height: 13px; stroke-width: 2.8; }
78
+ .ui-btn--sm { --btn-pad-y: 6px; --btn-pad-x: 12px; --btn-font: calc(var(--text-sm) - 0.5px); }
76
79
  .ui-btn--lg { --btn-pad-y: 13px; --btn-pad-x: 24px; --btn-font: var(--text-md); border-radius: var(--radius-md); }
77
80
 
78
81
  /* Icon-only */
79
82
  .ui-btn--icon { padding: 9px; border-radius: var(--radius-sm); }
83
+ .ui-btn--icon.ui-btn--xs { padding: 4.5px; }
80
84
  .ui-btn--icon.ui-btn--sm { padding: 6px; }
81
85
 
82
86
  .ui-btn--block { width: 100%; }
@@ -139,6 +143,7 @@
139
143
  transform-origin: center;
140
144
  animation: ui-bars-in var(--dur-fast) var(--ease) both;
141
145
  }
146
+ .ui-btn--xs .ui-btn__bars { left: 4px; right: 4px; bottom: 2px; height: 2px; }
142
147
  .ui-btn--sm .ui-btn__bars { left: 7px; right: 7px; bottom: 4px; }
143
148
  .ui-btn--lg .ui-btn__bars { left: 14px; right: 14px; bottom: 7px; }
144
149
  .ui-btn__bars i {
@@ -8,7 +8,7 @@
8
8
  padding: 15px 17px;
9
9
  border-radius: var(--radius-md);
10
10
  background: var(--surface-2);
11
- font-size: 13.5px;
11
+ font-size: calc(var(--text-sm) + 0.5px);
12
12
  line-height: 1.55;
13
13
  color: var(--dim);
14
14
  }
@@ -80,7 +80,7 @@
80
80
  }
81
81
  .ui-card__row + .ui-card__row { border-top: 1px solid var(--border); }
82
82
  .ui-card__row .lab { color: var(--strong); font-size: var(--text-md); font-weight: var(--weight-medium); }
83
- .ui-card__row .hint { color: var(--dim); font-size: 13.5px; margin-top: 3px; }
83
+ .ui-card__row .hint { color: var(--dim); font-size: calc(var(--text-sm) + 0.5px); margin-top: 3px; }
84
84
 
85
85
  /* Icon chip that leads a card header */
86
86
  .ui-card__icon {
@@ -36,7 +36,7 @@
36
36
  color: var(--muted);
37
37
  cursor: pointer;
38
38
  font-family: var(--font-sans);
39
- font-size: 12px;
39
+ font-size: calc(var(--text-xs) + 1px);
40
40
  display: inline-flex;
41
41
  align-items: center;
42
42
  gap: 6px;
@@ -147,7 +147,7 @@
147
147
  .ui-drawer__title {
148
148
  margin: 0;
149
149
  font-family: var(--font-sans);
150
- font-size: 15px;
150
+ font-size: calc(var(--text-base) + 0.5px);
151
151
  font-weight: 600;
152
152
  letter-spacing: 0.01em;
153
153
  color: var(--strong);
@@ -180,7 +180,7 @@
180
180
  padding: 20px;
181
181
  color: var(--text);
182
182
  font-family: var(--font-sans);
183
- font-size: 13px;
183
+ font-size: var(--text-sm);
184
184
  line-height: 1.55;
185
185
  }
186
186
 
@@ -14,7 +14,7 @@
14
14
  gap: 8px;
15
15
  cursor: pointer;
16
16
  font-family: var(--font-sans);
17
- font-size: 12.5px;
17
+ font-size: calc(var(--text-sm) - 0.5px);
18
18
  font-weight: 500;
19
19
  color: var(--text);
20
20
  background: var(--surface);
@@ -155,8 +155,8 @@
155
155
  .ui-dropdown__item:hover { background: var(--surface-3); }
156
156
  .ui-dropdown__item:focus-visible { outline: none; background: var(--surface-3); box-shadow: var(--ring); }
157
157
  .ui-dropdown__main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
158
- .ui-dropdown__label { font-family: var(--font-sans); font-size: 12.5px; color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
159
- .ui-dropdown__desc { font-size: 11px; color: var(--muted); line-height: 1.35; }
158
+ .ui-dropdown__label { font-family: var(--font-sans); font-size: calc(var(--text-sm) - 0.5px); color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
159
+ .ui-dropdown__desc { font-size: var(--text-xs); color: var(--muted); line-height: 1.35; }
160
160
  .ui-dropdown__ic { display: inline-flex; flex: none; color: var(--muted); }
161
161
  .ui-dropdown__ic svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 2.1; }
162
162
 
@@ -255,7 +255,7 @@
255
255
  .ui-dropdown__search-input {
256
256
  width: 100%;
257
257
  font: inherit;
258
- font-size: 12.5px;
258
+ font-size: calc(var(--text-sm) - 0.5px);
259
259
  color: var(--strong);
260
260
  /* A field is the sunken step, the same one .ui-input takes. why: docs/specification.md#elevation */
261
261
  background: var(--surface-2);
@@ -290,5 +290,5 @@
290
290
  anything matches, so it takes no room. */
291
291
  .ui-dropdown__none { display: flex; flex-direction: column; gap: 3px; padding: 14px 12px 10px; text-align: center; }
292
292
  .ui-dropdown__none:empty { display: none; }
293
- .ui-dropdown__none-title { font-size: 12.5px; font-weight: 600; color: var(--strong); }
294
- .ui-dropdown__none-hint { font-size: 11px; color: var(--muted); line-height: 1.35; }
293
+ .ui-dropdown__none-title { font-size: calc(var(--text-sm) - 0.5px); font-weight: 600; color: var(--strong); }
294
+ .ui-dropdown__none-hint { font-size: var(--text-xs); color: var(--muted); line-height: 1.35; }
@@ -31,7 +31,7 @@
31
31
  either way and is declared because leaving it to the element is the dependency
32
32
  this refuses. why: #251 */
33
33
  border: 0; text-align: center; font: inherit;
34
- font-family: var(--font-sans); font-size: 13px; font-weight: var(--weight-semibold); letter-spacing: .01em;
34
+ font-family: var(--font-sans); font-size: var(--text-sm); font-weight: var(--weight-semibold); letter-spacing: .01em;
35
35
  padding: 9px 17px 9px 15px; border-radius: 999px; cursor: pointer; white-space: nowrap; overflow: hidden;
36
36
  /* The pill cast two layers of ink and an accent glow until #295, and grew both on
37
37
  hover. Nothing casts now, and it takes no hairline either: it is the accent at full
@@ -74,24 +74,24 @@
74
74
  .ui-fbcomposer.show { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
75
75
 
76
76
  .ui-fbc__head { display: flex; align-items: center; gap: 12px; padding: 17px 20px 0; }
77
- .ui-fbc__chip { display: inline-flex; align-items: center; gap: 8px; color: var(--accent); font-size: 13px; font-weight: var(--weight-semibold); letter-spacing: .01em; white-space: nowrap; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
77
+ .ui-fbc__chip { display: inline-flex; align-items: center; gap: 8px; color: var(--accent); font-size: var(--text-sm); font-weight: var(--weight-semibold); letter-spacing: .01em; white-space: nowrap; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
78
78
  .ui-fbc__chip svg { width: 14px; height: 14px; flex: none; opacity: .85; stroke-width: 2.7; }
79
79
  .ui-fbc__x { margin-left: auto; background: var(--surface-2); color: var(--dim); border: 0; width: 28px; height: 28px; border-radius: 8px; cursor: pointer; display: grid; place-items: center; flex: none; font: inherit; }
80
80
  .ui-fbc__x:hover { color: var(--strong); }
81
81
  .ui-fbc__x svg { width: 14px; height: 14px; stroke-width: 2.7; }
82
82
  .ui-fbc__quote { margin: 14px 20px 0; background: var(--surface-2); border-radius: 12px; padding: 12px 15px; display: flex; gap: 11px; }
83
- .ui-fbc__qm { color: var(--accent); font-size: 22px; font-weight: var(--weight-bold); line-height: .9; flex: none; opacity: .55; }
84
- .ui-fbc__quote q { quotes: none; color: var(--dim); font-style: italic; font-size: 13.5px; line-height: 1.55; }
83
+ .ui-fbc__qm { color: var(--accent); font-size: var(--text-xl); font-weight: var(--weight-bold); line-height: .9; flex: none; opacity: .55; }
84
+ .ui-fbc__quote q { quotes: none; color: var(--dim); font-style: italic; font-size: calc(var(--text-sm) + 0.5px); line-height: 1.55; }
85
85
  .ui-fbc__body { padding: 14px 20px 0; }
86
86
  .ui-fbcomposer textarea {
87
- width: 100%; min-height: 96px; resize: vertical; font-family: var(--font-sans); font-size: 14.5px; line-height: 1.55;
87
+ width: 100%; min-height: 96px; resize: vertical; font-family: var(--font-sans); font-size: var(--text-base); line-height: 1.55;
88
88
  color: var(--strong); background: var(--surface-2); border: 0; border-radius: 12px; padding: 13px 15px; transition: box-shadow var(--dur-fast) var(--ease);
89
89
  }
90
90
  .ui-fbcomposer textarea::placeholder { color: var(--muted); }
91
91
  .ui-fbcomposer textarea:focus { outline: none; box-shadow: 0 0 0 2px var(--accent); }
92
92
  .ui-fbc__foot { display: flex; align-items: center; justify-content: flex-end; gap: 12px; padding: 16px 20px 18px; }
93
93
 
94
- .ui-fbbtn { font-family: var(--font-sans); font-size: 13.5px; font-weight: var(--weight-semibold); border-radius: 10px; padding: 9px 17px; cursor: pointer; border: 0; transition: filter var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease); }
94
+ .ui-fbbtn { font-family: var(--font-sans); font-size: calc(var(--text-sm) + 0.5px); font-weight: var(--weight-semibold); border-radius: 10px; padding: 9px 17px; cursor: pointer; border: 0; transition: filter var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease); }
95
95
  .ui-fbbtn.ghost { background: transparent; color: var(--dim); }
96
96
  .ui-fbbtn.ghost:hover { color: var(--strong); background: var(--surface-2); }
97
97
  .ui-fbbtn.primary { background: var(--accent-strong); color: var(--accent-contrast); display: inline-flex; align-items: center; gap: 9px; }
@@ -114,8 +114,8 @@
114
114
  .ui-fbck-t { fill: none; stroke: var(--surface-2); stroke-width: 9; stroke-linecap: round; stroke-linejoin: round; }
115
115
  .ui-fbck-m { fill: none; stroke: var(--green); stroke-width: 9; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 118; stroke-dashoffset: 118; animation: uiFbCkDraw .6s cubic-bezier(.5,0,.3,1) .1s forwards; /* motion: choreographed — the mark draws while the spring is still settling */ }
116
116
  .ui-fbck-s { fill: none; stroke: var(--sheen); stroke-width: 9; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 15 400; stroke-dashoffset: 133; filter: drop-shadow(0 0 8px var(--green)) drop-shadow(0 0 15px var(--green)); opacity: 0; animation: uiFbCkComet .6s cubic-bezier(.5,0,.3,1) .1s forwards; /* motion: choreographed — the comet rides the mark, so it shares its duration and delay exactly */ }
117
- .ui-fbc__done h4 { color: var(--strong); font-size: 19px; font-weight: var(--weight-semibold); letter-spacing: -.01em; margin-bottom: 7px; }
118
- .ui-fbc__done p { color: var(--dim); font-size: 13.5px; line-height: 1.55; max-width: var(--prose-caption); margin: 0 auto; }
117
+ .ui-fbc__done h4 { color: var(--strong); font-size: calc(var(--text-lg) + 1px); font-weight: var(--weight-semibold); letter-spacing: -.01em; margin-bottom: 7px; }
118
+ .ui-fbc__done p { color: var(--dim); font-size: calc(var(--text-sm) + 0.5px); line-height: 1.55; max-width: var(--prose-caption); margin: 0 auto; }
119
119
  .ui-fbc__done p b { color: var(--text); font-weight: var(--weight-semibold); }
120
120
  .ui-fbc__done .row { margin-top: 18px; display: flex; gap: 10px; justify-content: center; }
121
121
  @keyframes uiFbCkDraw { to { stroke-dashoffset: 0; } }
@@ -123,7 +123,7 @@
123
123
  @keyframes uiFbCkSpring { 0% { transform: scale(1.32); } 62% { transform: scale(.965); } 82% { transform: scale(1.02); } 100% { transform: scale(1); } }
124
124
 
125
125
  /* Error banner */
126
- .ui-fbc__err { margin: 14px 20px 0; background: color-mix(in srgb, var(--pink) 14%, transparent); color: var(--pink); font-size: 13px; padding: 11px 15px; border-radius: 11px; display: none; }
126
+ .ui-fbc__err { margin: 14px 20px 0; background: color-mix(in srgb, var(--pink) 14%, transparent); color: var(--pink); font-size: var(--text-sm); padding: 11px 15px; border-radius: 11px; display: none; }
127
127
  .ui-fbc__err.show { display: block; }
128
128
  /* A failed send's line fades in; wireFeedback() adds the class as it shows it. */
129
129
  .ui-fbc__err.is-entering { animation: m-fade var(--dur-fast) var(--ease-out) both; }
@@ -39,10 +39,10 @@
39
39
  footer breaks into columns, so it answers to the row rather than to a
40
40
  scale. The one width below the floor the measure gate draws. See #208. */
41
41
  .ui-footer__brand { max-width: 300px; }
42
- .ui-footer .ui-footer__brand .brand { font-size: 15px; }
42
+ .ui-footer .ui-footer__brand .brand { font-size: calc(var(--text-base) + 0.5px); }
43
43
  .ui-footer__tagline {
44
44
  margin: 12px 0 0;
45
- font-size: 13px;
45
+ font-size: var(--text-sm);
46
46
  line-height: 1.6;
47
47
  color: var(--footer-text);
48
48
  }
@@ -79,7 +79,7 @@
79
79
  }
80
80
  .ui-footer__links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 11px; }
81
81
  .ui-footer__links a {
82
- font-size: 13.5px;
82
+ font-size: calc(var(--text-sm) + 0.5px);
83
83
  color: var(--footer-link);
84
84
  text-decoration: none;
85
85
  transition: color var(--dur-fast) var(--ease);
@@ -95,7 +95,7 @@
95
95
  flex-wrap: wrap;
96
96
  padding-top: 22px;
97
97
  border-top: 1px solid var(--footer-border);
98
- font-size: 13px;
98
+ font-size: var(--text-sm);
99
99
  color: var(--footer-link);
100
100
  }
101
101
  .ui-footer__legal { color: var(--footer-link); }
@@ -114,7 +114,7 @@
114
114
  border-top: 1px solid var(--footer-border);
115
115
  }
116
116
  .ui-footer--app .ui-footer__in { max-width: none; padding: 12px clamp(14px, 2.4vw, 22px); }
117
- .ui-footer--app .ui-footer__bar { padding-top: 0; border-top: 0; font-size: 12.5px; }
117
+ .ui-footer--app .ui-footer__bar { padding-top: 0; border-top: 0; font-size: calc(var(--text-sm) - 0.5px); }
118
118
 
119
119
  /* Responsive — columns collapse to a stacked layout on narrow screens. Two of
120
120
  the kit's three steps, and the second one is the phone step rather than a
@@ -156,10 +156,10 @@
156
156
  background: var(--surface-3);
157
157
  color: var(--strong);
158
158
  display: grid; place-items: center;
159
- font-size: 12px;
159
+ font-size: calc(var(--text-xs) + 1px);
160
160
  font-weight: var(--weight-semibold);
161
161
  }
162
- .ui-app__who { font-size: 12.5px; line-height: 1.3; min-width: 0; }
162
+ .ui-app__who { font-size: calc(var(--text-sm) - 0.5px); line-height: 1.3; min-width: 0; }
163
163
  .ui-app__who b { display: block; color: var(--strong); font-weight: var(--weight-semibold); }
164
164
  /* nowrap is what makes the ellipsis fire — without it the address wraps, and
165
165
  the rail column is max-content, so a long one widens the rail instead. */
@@ -193,12 +193,12 @@
193
193
  time it is open it is no longer inside the rail that drew it.
194
194
  why: docs/specification.md#the-dropdown-panel */
195
195
  .ui-app__user-panel .ui-dropdown__head { display: flex; flex-direction: column; gap: 2px; }
196
- .ui-app__user-panel .ui-dropdown__head b { display: block; color: var(--strong); font-size: 12.5px; font-weight: var(--weight-semibold); }
196
+ .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); }
197
197
  /* The address wraps rather than truncating: nothing bounds this line, so
198
198
  `text-overflow` would have nothing to fire against — the inert pair
199
199
  .ui-app__who's own comment warns about. `anywhere` keeps an address with no
200
200
  break in it from widening the panel instead. */
201
- .ui-app__user-panel .ui-dropdown__head span { display: block; color: var(--muted); font-size: 11px; overflow-wrap: anywhere; }
201
+ .ui-app__user-panel .ui-dropdown__head span { display: block; color: var(--muted); font-size: var(--text-xs); overflow-wrap: anywhere; }
202
202
 
203
203
  /* The toggle's cell, at the far end of the brand row: the auto margin puts it there
204
204
  with or without a wordmark beside it, and the offset below rides it back onto the
@@ -402,7 +402,7 @@
402
402
  letter-spacing: var(--tracking-tight);
403
403
  margin-bottom: 8px;
404
404
  }
405
- .ui-app__sub { color: var(--dim); font-size: 15px; line-height: 1.6; max-width: var(--prose-body); margin-bottom: 32px; }
405
+ .ui-app__sub { color: var(--dim); font-size: calc(var(--text-base) + 0.5px); line-height: 1.6; max-width: var(--prose-body); margin-bottom: 32px; }
406
406
  .ui-app__body { display: flex; flex-direction: column; gap: var(--space-5); }
407
407
  /* A flex child's min-width is its content by default, so one wide block — a
408
408
  ledger, a code sample — pushes the whole page sideways instead of scrolling
@@ -477,7 +477,7 @@
477
477
  .ui-app__rail .ui-app__user-trigger:is(:hover, :focus-visible) > .ui-app__who { position-anchor: --ui-rail-row; left: calc(anchor(--ui-rail right) + var(--space-2)); top: anchor(top); bottom: anchor(bottom); align-self: center; margin-block: 0; }
478
478
  }
479
479
  .ui-app__main { padding: 28px var(--space-4) 56px; }
480
- .ui-app__main h1 { font-size: 25px; }
480
+ .ui-app__main h1 { font-size: calc(var(--text-xl) + 3px); }
481
481
  /* A settings row is label-beside-control down to the width where the control
482
482
  no longer fits beside anything; below that it stacks. Scoped to the shell
483
483
  rather than written into card.css, because a card row outside a shell is
@@ -507,12 +507,12 @@
507
507
  padding: 38px 36px 32px;
508
508
  }
509
509
  .ui-auth__brand { display: inline-flex; align-items: center; gap: 10px; margin-bottom: 26px; }
510
- .ui-auth__brand span { font-size: 15px; font-weight: 600; color: var(--strong); }
511
- .ui-auth__title { color: var(--strong); font-size: 24px; font-weight: 600; letter-spacing: -0.01em; margin-bottom: 7px; }
512
- .ui-auth__sub { color: var(--dim); font-size: 14.5px; line-height: 1.55; margin-bottom: 26px; }
513
- .ui-auth__foot { margin-top: 24px; text-align: center; font-size: 13px; color: var(--muted); }
510
+ .ui-auth__brand span { font-size: calc(var(--text-base) + 0.5px); font-weight: 600; color: var(--strong); }
511
+ .ui-auth__title { color: var(--strong); font-size: calc(var(--text-xl) + 2px); font-weight: 600; letter-spacing: -0.01em; margin-bottom: 7px; }
512
+ .ui-auth__sub { color: var(--dim); font-size: var(--text-base); line-height: 1.55; margin-bottom: 26px; }
513
+ .ui-auth__foot { margin-top: 24px; text-align: center; font-size: var(--text-sm); color: var(--muted); }
514
514
  .ui-auth__foot a { color: var(--accent); }
515
- .ui-divider { display: flex; align-items: center; gap: 14px; margin: 22px 0; color: var(--muted); font-size: 12px; }
515
+ .ui-divider { display: flex; align-items: center; gap: 14px; margin: 22px 0; color: var(--muted); font-size: calc(var(--text-xs) + 1px); }
516
516
  .ui-divider::before, .ui-divider::after { content: ""; flex: 1; height: 1px; background: var(--border); }
517
517
 
518
518
  /* App scope grant list (OAuth consent) */
@@ -527,8 +527,8 @@
527
527
  color: var(--accent);
528
528
  }
529
529
  .ui-scope__icon svg { width: 21px; height: 21px; stroke: currentColor; fill: none; stroke-width: 1.8; }
530
- .ui-scope__t { color: var(--strong); font-size: 14px; font-weight: 500; }
531
- .ui-scope__d { color: var(--dim); font-size: 13px; margin-top: 2px; line-height: 1.5; }
530
+ .ui-scope__t { color: var(--strong); font-size: calc(var(--text-base) - 0.5px); font-weight: 500; }
531
+ .ui-scope__d { color: var(--dim); font-size: var(--text-sm); margin-top: 2px; line-height: 1.5; }
532
532
 
533
533
  /* -- Landing hero -------------------------------------------------------- */
534
534
  .ui-hero {
@@ -541,7 +541,7 @@
541
541
  display: inline-flex;
542
542
  align-items: center;
543
543
  gap: 8px;
544
- font-size: 12px;
544
+ font-size: calc(var(--text-xs) + 1px);
545
545
  letter-spacing: 0.06em;
546
546
  color: var(--purple-mid);
547
547
  background: var(--glow-purple);
@@ -594,9 +594,9 @@
594
594
  margin-bottom: 16px;
595
595
  }
596
596
  .ui-feature__icon svg { width: 25px; height: 25px; stroke: currentColor; fill: none; stroke-width: 1.8; }
597
- .ui-feature h3 { color: var(--strong); font-size: 17px; font-weight: 600; margin-bottom: 7px; }
598
- .ui-feature p { color: var(--dim); font-size: 14.5px; line-height: 1.6; }
597
+ .ui-feature h3 { color: var(--strong); font-size: calc(var(--text-lg) - 1px); font-weight: 600; margin-bottom: 7px; }
598
+ .ui-feature p { color: var(--dim); font-size: var(--text-base); line-height: 1.6; }
599
599
 
600
600
  .ui-section-head { text-align: center; max-width: var(--panel-lg); margin: 0 auto clamp(40px, 6vh, 64px); }
601
601
  .ui-section-head h2 { color: var(--strong); font-size: clamp(28px, 4vw, 40px); font-weight: 700; letter-spacing: -0.02em; margin-bottom: 14px; }
602
- .ui-section-head p { color: var(--dim); font-size: 17px; line-height: 1.6; }
602
+ .ui-section-head p { color: var(--dim); font-size: calc(var(--text-lg) - 1px); line-height: 1.6; }
@@ -58,7 +58,7 @@
58
58
  padding: 9px 12px;
59
59
  border-radius: 10px;
60
60
  text-decoration: none;
61
- font-size: 14.5px;
61
+ font-size: var(--text-base);
62
62
  font-weight: 400;
63
63
  line-height: 1.2;
64
64
  background: none;
@@ -137,7 +137,7 @@
137
137
  display: inline-flex;
138
138
  align-items: center;
139
139
  justify-content: center;
140
- font-size: 11px;
140
+ font-size: var(--text-xs);
141
141
  font-weight: 600;
142
142
  line-height: 1;
143
143
  background: var(--surface-3);
@@ -188,7 +188,7 @@
188
188
  --m-dist: var(--space-1);
189
189
  animation: m-slide-down var(--dur-fast) var(--ease-out) both;
190
190
  }
191
- .ui-nav__item--sub { font-size: 14px; padding: 7px 12px; }
191
+ .ui-nav__item--sub { font-size: calc(var(--text-base) - 0.5px); padding: 7px 12px; }
192
192
  /* No hairline on a nested current row — but only at rest. box-shadow carries
193
193
  both the hairline and the focus ring, so a rule about the resting look must
194
194
  say so, or it silently cancels the ring (WCAG 2.4.7). */
@@ -269,7 +269,7 @@
269
269
  padding: 11px 14px;
270
270
  color: var(--dim);
271
271
  text-decoration: none;
272
- font-size: 14px;
272
+ font-size: calc(var(--text-base) - 0.5px);
273
273
  font-weight: 500;
274
274
  border-radius: 10px 10px 0 0;
275
275
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
@@ -322,7 +322,7 @@
322
322
  padding: 3px 6px;
323
323
  border-radius: 7px;
324
324
  text-decoration: none;
325
- font-size: 13px;
325
+ font-size: var(--text-sm);
326
326
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
327
327
  }
328
328
  /* Carries the block's class as well as its own, for the reason .ui-nav__item
@@ -12,7 +12,7 @@
12
12
  }
13
13
  .ui-seg button {
14
14
  font-family: var(--font-sans);
15
- font-size: 13.5px;
15
+ font-size: calc(var(--text-sm) + 0.5px);
16
16
  font-weight: var(--weight-semibold);
17
17
  letter-spacing: 0.02em;
18
18
  color: var(--dim);
@@ -33,7 +33,7 @@
33
33
  background: var(--seg-active-bg); /* the step is the lift; nothing casts. #295 */
34
34
  }
35
35
 
36
- .ui-seg--sm button { padding: 5px 13px; font-size: 12px; }
36
+ .ui-seg--sm button { padding: 5px 13px; font-size: calc(var(--text-xs) + 1px); }
37
37
  .ui-seg--block { display: flex; }
38
38
  .ui-seg--block button { flex: 1; }
39
39
 
@@ -60,11 +60,11 @@
60
60
  margin-bottom: 10px;
61
61
  }
62
62
  .ui-sx__title {
63
- color: var(--strong); font-size: 22px; font-weight: var(--weight-semibold);
63
+ color: var(--strong); font-size: var(--text-xl); font-weight: var(--weight-semibold);
64
64
  letter-spacing: -.02em; line-height: 1.2; margin: 0;
65
65
  }
66
66
  .ui-sx__body {
67
- color: var(--dim); font-size: 14.5px; line-height: 1.6; margin: 9px 0 0; max-width: var(--prose-caption);
67
+ color: var(--dim); font-size: var(--text-base); line-height: 1.6; margin: 9px 0 0; max-width: var(--prose-caption);
68
68
  }
69
69
  .ui-sx__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }
70
70
 
@@ -93,8 +93,8 @@
93
93
  .ui-sx--compact .ui-sx__inner { display: flex; align-items: center; gap: 16px; }
94
94
  .ui-sx--compact .ui-sx__visual { flex: none; }
95
95
  .ui-sx--compact .ui-sx__check { width: 44px; height: 44px; }
96
- .ui-sx--compact .ui-sx__title { font-size: 16px; }
97
- .ui-sx--compact .ui-sx__body { font-size: 13px; margin-top: 3px; }
96
+ .ui-sx--compact .ui-sx__title { font-size: calc(var(--text-md) + 0.5px); }
97
+ .ui-sx--compact .ui-sx__body { font-size: var(--text-sm); margin-top: 3px; }
98
98
  .ui-sx--compact .ui-sx__actions { margin-top: 0; margin-left: auto; flex: none; }
99
99
  .ui-sx--compact .ui-sx__content { flex: 1; display: flex; align-items: center; gap: 16px; }
100
100
  .ui-sx--compact .ui-sx__content > div:first-child,
@@ -166,7 +166,7 @@
166
166
  animation: ui-sx-sweep var(--sx-secs, 5s) linear forwards; /* motion: ambient — the caller sets the countdown; the ring just spends it */
167
167
  }
168
168
  @keyframes ui-sx-sweep { from { --sx-a: 360deg; } to { --sx-a: 0deg; } }
169
- .ui-sx__count-text { color: var(--muted); font-size: 13px; }
169
+ .ui-sx__count-text { color: var(--muted); font-size: var(--text-sm); }
170
170
  .ui-sx__count-text b { color: var(--dim); font-weight: var(--weight-semibold); font-variant-numeric: tabular-nums; }
171
171
 
172
172
  /* ---- Reduced motion — static check, no burst / confetti / sweep ---------- */
@@ -13,7 +13,7 @@
13
13
  background: none;
14
14
  border: 0;
15
15
  cursor: pointer;
16
- font: 600 14px/1 var(--font-sans);
16
+ font: 600 calc(var(--text-base) - 0.5px)/1 var(--font-sans);
17
17
  color: var(--dim);
18
18
  padding: 11px 14px;
19
19
  border-bottom: 2px solid transparent;
@@ -40,7 +40,7 @@
40
40
  }
41
41
  .brand svg { display: block; flex: none; }
42
42
  /* Topbar wordmark runs a touch smaller than the auth-card lockup. */
43
- .topbar .brand { font-size: 13px; }
43
+ .topbar .brand { font-size: var(--text-sm); }
44
44
  .topbar .spacer { flex: 1; }
45
45
 
46
46
  /* Deck / Text (segmented, pill) */
@@ -57,7 +57,7 @@
57
57
  .dtsw a {
58
58
  text-decoration: none;
59
59
  font-family: var(--font-sans);
60
- font-size: 12px;
60
+ font-size: calc(var(--text-xs) + 1px);
61
61
  font-weight: 600;
62
62
  letter-spacing: 0.04em;
63
63
  color: var(--muted);
@@ -97,7 +97,7 @@
97
97
  gap: 8px;
98
98
  cursor: pointer;
99
99
  font-family: var(--font-sans);
100
- font-size: 12.5px;
100
+ font-size: calc(var(--text-sm) - 0.5px);
101
101
  font-weight: 500;
102
102
  color: var(--text);
103
103
  background: var(--surface);
@@ -183,8 +183,8 @@
183
183
  src/styles/dropdown.css:155 `.ui-dropdown__item:hover`.
184
184
  why: docs/specification.md#elevation */
185
185
  .vopt:hover { background: var(--surface-3); }
186
- .vopt .vname { font-family: var(--font-sans); font-size: 12.5px; color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
187
- .vopt .vmeta { font-size: 11px; color: var(--muted); margin-top: 2px; }
186
+ .vopt .vname { font-family: var(--font-sans); font-size: calc(var(--text-sm) - 0.5px); color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
187
+ .vopt .vmeta { font-size: var(--text-xs); color: var(--muted); margin-top: 2px; }
188
188
  .vopt .vbadge {
189
189
  /* rank: chip */
190
190
  font-size: var(--text-xs);
@@ -213,7 +213,7 @@
213
213
  color: var(--accent-contrast);
214
214
  font: inherit;
215
215
  font-weight: 600;
216
- font-size: 12.5px;
216
+ font-size: calc(var(--text-sm) - 0.5px);
217
217
  display: grid;
218
218
  place-items: center;
219
219
  cursor: pointer;
@@ -255,9 +255,9 @@
255
255
  .amenu .ahead { padding: 13px 15px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 11px; }
256
256
  .amenu .ahead .avatar { cursor: default; }
257
257
  .amenu .ahead .aw { min-width: 0; display: flex; flex-direction: column; gap: 1px; line-height: 1.35; }
258
- .amenu .ahead .anm { color: var(--strong); font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
259
- .amenu .ahead .aem { color: var(--muted); font-size: 11.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
260
- .amenu a { display: flex; align-items: center; gap: 11px; padding: 10px 15px; color: var(--text); text-decoration: none; font-family: var(--font-sans); font-size: 13px; cursor: pointer; }
258
+ .amenu .ahead .anm { color: var(--strong); font-size: var(--text-sm); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
259
+ .amenu .ahead .aem { color: var(--muted); font-size: calc(var(--text-xs) + 0.5px); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
260
+ .amenu a { display: flex; align-items: center; gap: 11px; padding: 10px 15px; color: var(--text); text-decoration: none; font-family: var(--font-sans); font-size: var(--text-sm); cursor: pointer; }
261
261
  .amenu a:hover { background: var(--surface-3); }
262
262
  .amenu a.cur { color: var(--accent); }
263
263
  .amenu a svg { width: 19px; height: 19px; flex: none; stroke: currentColor; fill: none; stroke-width: 2; opacity: 0.85; }