@apliteni/apliteni-ui 0.31.0 → 0.32.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.
@@ -30,8 +30,7 @@
30
30
  .ui-seg button[aria-pressed="true"],
31
31
  .ui-seg button[aria-selected="true"] {
32
32
  color: var(--strong);
33
- background: var(--seg-active-bg);
34
- box-shadow: var(--shadow-seg);
33
+ background: var(--seg-active-bg); /* the step is the lift; nothing casts. #295 */
35
34
  }
36
35
 
37
36
  .ui-seg--sm button { padding: 5px 13px; font-size: 12px; }
@@ -0,0 +1,121 @@
1
+ /* ============================================================================
2
+ * Stat band — .ui-stats (a row of key figures: label, value, change, trend)
3
+ * .ui-stats--tiles one card per figure — the default
4
+ * .ui-stats--band one card, figures divided by space
5
+ * .ui-stats--open no surface; a rule over each figure
6
+ * why: docs/specification.md#stat-bands
7
+ * ========================================================================== */
8
+
9
+ /* The band lays out from the width of its own box, not the window's: a band in
10
+ a column beside a rail and a band across a full page are different widths at
11
+ the same viewport. */
12
+ .ui-stats { container-type: inline-size; }
13
+
14
+ /* Equal columns while the figures fit. A figure is never narrower than its
15
+ widest unbreakable piece — the value — so a band too narrow for its figures
16
+ wraps a figure onto the next row rather than letting it overlap the next. */
17
+ .ui-stats__list {
18
+ display: flex;
19
+ flex-wrap: wrap;
20
+ gap: var(--space-6) var(--space-10);
21
+ margin: 0;
22
+ }
23
+
24
+ .ui-stat { display: flex; flex-direction: column; flex: 1 1 0; min-width: min-content; }
25
+
26
+ /* Takes the label rank's size and weight, but not its inherited leading: a
27
+ figure's parts are held close, so the label keeps the band's tighter line.
28
+ It sits outside the rank table for that one reason, and claims no rank. */
29
+ .ui-stat__label {
30
+ color: var(--dim);
31
+ font-size: var(--text-sm);
32
+ font-weight: var(--weight-medium);
33
+ line-height: var(--leading-snug);
34
+ }
35
+
36
+ /* A figure is never broken across lines and never truncated: `€` stays with its
37
+ digits and every digit stays on screen. The band stacks before a figure
38
+ would have to do either. */
39
+ .ui-stat__value {
40
+ margin-top: var(--space-2);
41
+ color: var(--strong);
42
+ /* display: readout — a key figure is read as a number at a glance, not as a line of prose */
43
+ font-family: var(--font-display);
44
+ font-size: var(--text-2xl);
45
+ font-weight: var(--weight-semibold);
46
+ line-height: var(--leading-tight);
47
+ letter-spacing: var(--tracking-tight);
48
+ font-variant-numeric: tabular-nums;
49
+ white-space: nowrap;
50
+ }
51
+
52
+ .ui-stat__delta {
53
+ display: flex;
54
+ flex-wrap: wrap;
55
+ align-items: center;
56
+ gap: 2px var(--space-1);
57
+ margin-top: var(--space-2);
58
+ color: var(--dim);
59
+ font-size: var(--text-sm);
60
+ font-weight: var(--weight-medium);
61
+ line-height: var(--leading-snug);
62
+ }
63
+ .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 */
64
+ .ui-stat__change { font-variant-numeric: tabular-nums; white-space: nowrap; }
65
+ .ui-stat__basis { color: var(--muted); font-weight: var(--weight-normal); }
66
+ .ui-stat__delta--none { color: var(--muted); font-weight: var(--weight-normal); }
67
+
68
+ /* Tone is set by the caller and says good or bad news. Direction is the arrow's
69
+ job, so an unset tone keeps the change neutral whichever way it points. */
70
+ .ui-stat--good .ui-stat__delta { color: var(--chip-success-ink); }
71
+ .ui-stat--bad .ui-stat__delta { color: var(--chip-danger-ink); }
72
+
73
+ /* The trend is the caller's <svg>. margin-top: auto seats it on the bottom of
74
+ the figure, so trends line up across figures whose text wraps differently. */
75
+ .ui-stat__trend { margin-top: auto; padding-top: var(--space-4); color: var(--muted); }
76
+ .ui-stat__trend svg { display: block; width: 100%; height: 32px; overflow: visible; }
77
+ .ui-stat--good .ui-stat__trend { color: var(--chip-success-ink); }
78
+ .ui-stat--bad .ui-stat__trend { color: var(--chip-danger-ink); }
79
+
80
+ /* The band's caption, above the figures rather than in one: it is what every
81
+ change points at, so it sits outside the ranks and takes none of them. The
82
+ margin is under it because it leads the row. */
83
+ .ui-stats__basis {
84
+ margin: 0 0 var(--space-5);
85
+ color: var(--muted);
86
+ font-size: var(--text-xs);
87
+ line-height: var(--leading-snug);
88
+ }
89
+
90
+ .ui-stats--tiles .ui-stats__list { gap: var(--space-4); }
91
+
92
+ .ui-stats--open .ui-stat {
93
+ border-top: 1px solid var(--border-strong);
94
+ padding-top: var(--space-4);
95
+ }
96
+ .ui-stats--open .ui-stat__value { font-size: var(--text-3xl); }
97
+
98
+ /* Wrapping alone would leave three figures on one row and one on the next. So
99
+ before a row of figures runs out of room, four fold two by two and an odd
100
+ count stacks. The widths are where four and three tiles of `€ 6,459,401`
101
+ stop fitting, and the open band's larger value moves them out; a longer
102
+ figure still wraps rather than overlaps.
103
+ why: docs/specification.md#stat-bands */
104
+ @container (28rem < width <= 56rem) {
105
+ .ui-stats:not(.ui-stats--open) .ui-stats__list:has(> .ui-stat:nth-child(4):last-child) > .ui-stat { flex-basis: 34%; }
106
+ }
107
+ @container (width <= 42rem) {
108
+ .ui-stats__list:has(> .ui-stat:last-child:nth-child(odd)) > .ui-stat { flex-basis: 100%; }
109
+ }
110
+ @container (width <= 28rem) {
111
+ .ui-stats__list > .ui-stat { flex-basis: 100%; }
112
+ }
113
+ @container (32rem < width <= 66rem) {
114
+ .ui-stats--open .ui-stats__list:has(> .ui-stat:nth-child(4):last-child) > .ui-stat { flex-basis: 34%; }
115
+ }
116
+ @container (width <= 50rem) {
117
+ .ui-stats--open .ui-stats__list:has(> .ui-stat:last-child:nth-child(odd)) > .ui-stat { flex-basis: 100%; }
118
+ }
119
+ @container (width <= 32rem) {
120
+ .ui-stats--open .ui-stats__list > .ui-stat { flex-basis: 100%; }
121
+ }
@@ -19,8 +19,8 @@
19
19
  position: relative;
20
20
  overflow: hidden;
21
21
  border-radius: 20px;
22
- background: var(--bg-elevated);
23
- box-shadow: var(--shadow-md);
22
+ background: var(--bg-elevated); /* the floating step carries it. #295 */
23
+ border: 1px solid var(--border);
24
24
  isolation: isolate;
25
25
  }
26
26
 
@@ -28,7 +28,6 @@
28
28
  background: var(--ui-tip-bg);
29
29
  border: 1px solid var(--border);
30
30
  border-radius: var(--radius-sm);
31
- box-shadow: var(--shadow-md);
32
31
  font-family: var(--font-sans);
33
32
  font-size: var(--text-xs);
34
33
  line-height: 1.45;
@@ -45,9 +44,9 @@
45
44
  visibility var(--dur-fast) linear;
46
45
  }
47
46
 
48
- /* Light is an all-white app, so the raised surface is white over a hairline,
49
- the way a light card is. */
50
- :root[data-theme="light"] .ui-tip { --ui-tip-bg: var(--surface); }
47
+ /* No light override: it re-pointed the readout at --surface, which #295 made the card
48
+ step, so a readout over a card was painted the card's own colour. --surface-3 is the
49
+ readout's step in both themes. why: docs/specification.md#elevation */
51
50
 
52
51
  /* Below the mark: the wiring's flip when above would be clipped, or the
53
52
  author's own choice. */
@@ -66,7 +66,7 @@
66
66
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
67
67
  }
68
68
  .dtsw a:hover { color: var(--text); }
69
- .dtsw a.cur { color: var(--strong); background: var(--surface); box-shadow: var(--shadow-sm); }
69
+ .dtsw a.cur { color: var(--strong); background: var(--surface); }
70
70
 
71
71
  /* Theme toggle — a single icon-only switch (no label). */
72
72
  .toggle {
@@ -122,11 +122,10 @@
122
122
  top: calc(100% + 9px);
123
123
  left: 0;
124
124
  min-width: 266px;
125
- background: var(--surface-2);
125
+ background: var(--bg-elevated); /* the floating step — see dropdown.css. #295 */
126
126
  border: 1px solid var(--border);
127
127
  border-radius: 16px;
128
128
  padding: 6px;
129
- box-shadow: var(--shadow-lg);
130
129
  opacity: 0;
131
130
  visibility: hidden;
132
131
  transform: translateY(-6px);
@@ -160,7 +159,9 @@
160
159
  font: inherit;
161
160
  transition: background var(--dur-fast) var(--ease);
162
161
  }
163
- .vopt:hover { background: var(--surface); }
162
+ /* The menu is raised, so a hovered row takes the step ABOVE it — see
163
+ src/styles/dropdown.css:130. why: docs/specification.md#elevation */
164
+ .vopt:hover { background: var(--surface-3); }
164
165
  .vopt .vname { font-family: var(--font-sans); font-size: 12.5px; color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
165
166
  .vopt .vmeta { font-size: 11px; color: var(--muted); margin-top: 2px; }
166
167
  .vopt .vbadge {
@@ -174,7 +175,7 @@
174
175
  margin-top: 1px;
175
176
  }
176
177
  .vbadge.live { color: var(--chip-success-ink); background: var(--chip-success-fill); }
177
- .vbadge.arch { color: var(--muted); background: var(--surface); }
178
+ .vbadge.arch { color: var(--muted); background: var(--surface-3); }
178
179
  /* The switcher keeps its glyph and drops its label where the shell folds — the
179
180
  same step the rail folds at: docs/specification.md#breakpoints. */
180
181
  @media (max-width: 720px) { .vsw__btn .lbl { display: none; } }
@@ -203,10 +204,9 @@
203
204
  position: absolute;
204
205
  right: 0; top: 44px;
205
206
  width: 252px;
206
- background: var(--surface-2);
207
+ background: var(--bg-elevated); /* the floating step — see dropdown.css. #295 */
207
208
  border: 1px solid var(--border);
208
209
  border-radius: 14px;
209
- box-shadow: var(--shadow-lg);
210
210
  overflow: hidden;
211
211
  opacity: 0;
212
212
  visibility: hidden;
@@ -225,7 +225,7 @@
225
225
  .amenu .ahead .anm { color: var(--strong); font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
226
226
  .amenu .ahead .aem { color: var(--muted); font-size: 11.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
227
227
  .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; }
228
- .amenu a:hover { background: var(--surface); }
228
+ .amenu a:hover { background: var(--surface-3); }
229
229
  .amenu a.cur { color: var(--accent); }
230
230
  .amenu a svg { width: 19px; height: 19px; flex: none; stroke: currentColor; fill: none; stroke-width: 2; opacity: 0.85; }
231
231
  .amenu .asep { height: 1px; background: var(--border); margin: 5px 0; }
@@ -77,9 +77,9 @@
77
77
  --purple-light: #1568d6;
78
78
  --purple-mid: #1560c8;
79
79
  /* Deepened for WCAG AA on the raised grey panel and its wash — hue and chroma held
80
- in OKLCH (H 258, C 0.185), four points of lightness down. The washed figures are
81
- read at the 0.10 alpha below, which is what this cell ships. See issues #96, #157. */
82
- --accent: #005bc8;
80
+ in OKLCH (H 258, C 0.185), read at the 0.10 alpha below. Down a second step at
81
+ #295, which took the light page off white. See issues #96, #157, #295. */
82
+ --accent: #005ab4;
83
83
  --accent-strong: var(--accent);
84
84
  --accent-contrast: #ffffff;
85
85
  /* Back to the 0.10 this cell carried before #157: deepening the ink closed the pair,
@@ -107,9 +107,10 @@
107
107
  --purple: #0a865a;
108
108
  --purple-light: #0b9c68;
109
109
  --purple-mid: #0a9060;
110
- /* Deepened for WCAG AA on the light ground (#fff): #0b9c68 was 3.52:1 as text
111
- and as the ink-on-fill; #087a52 clears AA at 5.36:1. See issue #96. */
112
- --accent: #087a52;
110
+ /* Deepened for WCAG AA on the light ground: #0b9c68 was 3.52:1 as text and as the
111
+ ink-on-fill. Down again at #295 green has the least room of the four hues, and
112
+ this was the only cell that failed flat as well as washed. See issues #96, #295. */
113
+ --accent: #076c48;
113
114
  --accent-strong: var(--accent);
114
115
  --accent-contrast: #ffffff;
115
116
  /* Thinned from 0.10 for WCAG AA, the same grey-panel pair as light Ocean and
@@ -133,12 +133,15 @@
133
133
  --pink: #e97ca5;
134
134
  --amber: #ffcf6a;
135
135
 
136
- --bg: #16151f;
137
- --bg-elevated: #1c1a28;
138
- --surface: #221f2e;
139
- --surface-2: #1b1927;
140
- --surface-3: #2a2739;
141
- --seg-active-bg: #34314a; /* raised pill — clearly above the inset track in dark */
136
+ /* The elevation ladder, bottom to top. Nothing casts; a surface says how high it is
137
+ with its step and with the hairline around it, and --muted caps how far the ladder
138
+ can go. why: docs/specification.md#elevation */
139
+ --bg: #0e0d14;
140
+ --surface-2: #161520; /* SUNKEN — fields, tracks, disabled, code */
141
+ --surface: #211e2d; /* the card */
142
+ --bg-elevated: #2a2639; /* FLOATING — menus, panels, drawer, modal, toasts */
143
+ --surface-3: #2d293c; /* the top step — the hover readout, chips, the nav rail */
144
+ --seg-active-bg: #383350; /* raised pill — clearly above the inset track in dark */
142
145
  /* The raised handle on a control track (switch knob). White in both themes and under
143
146
  every accent: it reads on the plain track AND on the accent fill of an on control. */
144
147
  --control-knob: #ffffff;
@@ -148,7 +151,10 @@
148
151
  --text: #e9e7f0;
149
152
  --strong: #ffffff;
150
153
  --dim: #c6c2d6;
151
- --muted: #948fa8;
154
+ /* Picked against the TOP of the ladder above, not against the page: #948fa8 cleared the
155
+ two floating steps by hundredths. Same violet-grey, fourteen steps up every channel.
156
+ why: docs/specification.md#elevation */
157
+ --muted: #a29db6;
152
158
 
153
159
  /* The paint of a control that is off. NOT an opacity: `opacity` is a group property,
154
160
  so it fades label and box toward the ground TOGETHER — a disabled primary button
@@ -208,14 +214,19 @@
208
214
  --signal-solid-info: var(--cyan);
209
215
  --signal-solid-neutral: var(--muted);
210
216
 
211
- --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.28);
212
- --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.4);
213
- --shadow-lg: 0 18px 50px rgba(0, 0, 0, 0.5);
214
- /* Tight elevation for the active segmented pill — stays contained in its track. */
215
- --shadow-seg: 0 1px 2px rgba(0, 0, 0, 0.45), 0 2px 4px rgba(0, 0, 0, 0.3);
216
- /* A card's resting elevation. Nothing in the kit reads it since #284 made .ui-card
217
- flat; it stays because it is published and a consumer may. Dark casts nothing. */
218
- --shadow-card: none;
217
+ /* DEPRECATED since #295: the kit casts no shadow anywhere. Published still, so a
218
+ consumer reading one gets nothing rather than an unresolved var(), and a consumer who
219
+ wants a cast shadow sets them. Nothing in src/ reads them.
220
+
221
+ A transparent shadow, not `none`, because these are read in a LIST. The kit's own
222
+ pre-0.32 pattern was `box-shadow: var(--shadow-lg), var(--ring)`, and `none` is only
223
+ valid alone it makes the whole declaration invalid, which silently takes the focus
224
+ ring with it. `0 0 #0000` composes. why: docs/specification.md#elevation */
225
+ --shadow-sm: 0 0 #0000;
226
+ --shadow-md: 0 0 #0000;
227
+ --shadow-lg: 0 0 #0000;
228
+ --shadow-seg: 0 0 #0000;
229
+ --shadow-card: 0 0 #0000;
219
230
  /* THE ONLY --ring in the kit — light and every data-accent sub-theme declare an
220
231
  --accent and inherit this line. Opaque because a translucent ring is a glow, and the
221
232
  eight rgba() literals it replaced all missed WCAG 1.4.11's 3:1 (#218). Held by
@@ -250,17 +261,19 @@
250
261
  --cyan: #0c8fa8;
251
262
  --green: #1c8a2c;
252
263
  /* Deeper than the dark pink for the same reason dark's is lighter: the wash under it
253
- is white, so the ink has to come down to meet it. See issue #131. */
254
- --pink: #b63361;
264
+ is the page, so the ink comes down to meet it. Down a second step at #295, which
265
+ took the page off white. See issues #131 and #295. */
266
+ --pink: #a92d59;
255
267
  --amber: #b5730a;
256
268
 
257
- /* A WHITE app: page and cards are both white, and cards are delineated by a hairline
258
- border (see card.css), not a grey canvas or a shadow. */
259
- --bg: #ffffff;
260
- --bg-elevated: #ffffff;
261
- --surface: #ffffff;
262
- --surface-2: #f5f6f9;
263
- --surface-3: #eceef3;
269
+ /* The same ladder, run the only way light can run it: nothing is brighter than the
270
+ white a card already was, so light moves DOWN and keeps white for the top step.
271
+ why: docs/specification.md#elevation */
272
+ --bg: #eef0f5;
273
+ --surface-2: #e3e6ee; /* SUNKEN — fields, tracks, disabled, code */
274
+ --surface: #f8f9fc; /* the card */
275
+ --bg-elevated: #ffffff; /* FLOATING — menus, panels, drawer, modal, toasts */
276
+ --surface-3: #e7eaf1; /* the hover readout, chips, the nav rail */
264
277
  --seg-active-bg: #ffffff; /* white pill raised above the grey track in light */
265
278
  --control-knob: #ffffff;
266
279
  --border: #e4e7ee;
@@ -292,20 +305,22 @@
292
305
  --glow-green: rgba(28, 138, 44, 0.1);
293
306
  --glow-purple: rgba(106, 45, 204, 0.09);
294
307
  --glow-cyan: rgba(12, 143, 168, 0.1);
295
- --glow-pink: rgba(182, 51, 97, 0.1);
308
+ --glow-pink: rgba(169, 45, 89, 0.1); /* an exact tint of --pink above */
296
309
 
297
- /* Solid chip pairs for the white app. Each ink is deepened past its signal hue so 11px
298
- chip text clears WCAG AA on its own pale fill. */
299
- --chip-success-ink: #1f7a38;
310
+ /* Solid chip pairs for the light app. Each ink is deepened past its signal hue so 11px
311
+ chip text clears WCAG AA on its own pale fill, and on the soft toast's wash, which
312
+ #131 gave the same ink. Three came down again at #295 with the page; danger did not
313
+ need to. */
314
+ --chip-success-ink: #1c7034;
300
315
  --chip-success-fill: #dff3e4;
301
- --chip-warn-ink: #8a5e00;
316
+ --chip-warn-ink: #825900;
302
317
  --chip-warn-fill: #fbedd2;
303
318
  --chip-danger-ink: #b7295f;
304
319
  --chip-danger-fill: #fbe0ea;
305
320
  /* Info was the one signal family without a pair, so the info badge painted --cyan on
306
321
  --glow-cyan over white and missed AA. This pair sits in the band the other three
307
322
  already occupy. See issue #131. */
308
- --chip-info-ink: #0a7286;
323
+ --chip-info-ink: #096a7c;
309
324
  --chip-info-fill: #ddeff3;
310
325
 
311
326
  /* Light runs the same rule the other way. The signals are mid-tone here, so NO ink
@@ -319,14 +334,12 @@
319
334
  --signal-solid-info: var(--chip-info-ink);
320
335
  --signal-solid-neutral: var(--muted);
321
336
 
322
- --shadow-sm: 0 1px 3px rgba(30, 30, 50, 0.08);
323
- --shadow-md: 0 8px 24px rgba(30, 30, 50, 0.1);
324
- --shadow-lg: 0 18px 50px rgba(30, 30, 50, 0.16);
325
- /* Tight elevation for the active segmented pill — stays contained in its track. */
326
- --shadow-seg: 0 1px 2px rgba(30, 30, 50, 0.12), 0 2px 4px rgba(30, 30, 50, 0.1);
327
- /* A hairline contact shadow plus a wide soft one. Unread by the kit since #284 —
328
- see the dark block. */
329
- --shadow-card: 0 1px 2px rgba(20, 25, 45, 0.04), 0 4px 14px rgba(20, 25, 45, 0.05);
337
+ /* Deprecated and unread see the dark block. */
338
+ --shadow-sm: 0 0 #0000;
339
+ --shadow-md: 0 0 #0000;
340
+ --shadow-lg: 0 0 #0000;
341
+ --shadow-seg: 0 0 #0000;
342
+ --shadow-card: 0 0 #0000;
330
343
  /* No --ring here. :root's is var(--accent), and light re-points --accent. */
331
344
 
332
345
  --shadow-ink: #1e1e32;