@redseed/redseed-ui-tailwindcss 7.56.0 → 7.58.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/components/button_card.css +4 -2
- package/components/button_slot.css +124 -1
- package/components/card.css +154 -26
- package/components/card_header.css +79 -19
- package/components/card_horizontal.css +15 -3
- package/components/checkbox_card.css +24 -11
- package/components/form_field_date_range.css +32 -0
- package/components/icon.css +104 -1
- package/components/message_box.css +104 -4
- package/components/meta_info.css +36 -10
- package/components/metric_card.css +1 -1
- package/components/page_header.css +51 -17
- package/components/radio_card.css +15 -8
- package/components/section_footer.css +68 -0
- package/components/section_header.css +58 -11
- package/components/section_slider.css +302 -0
- package/components/switcher.css +60 -0
- package/package.json +1 -1
- package/tokens.css +7 -0
|
@@ -153,6 +153,38 @@
|
|
|
153
153
|
@apply hover:bg-background-brand-contrast;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
/*
|
|
157
|
+
* Square off the edge each endpoint faces the range on, so the band closes.
|
|
158
|
+
*
|
|
159
|
+
* The base `.rsui-form-field-date-range__day` is `rounded-lg` on all four
|
|
160
|
+
* corners and the endpoints only override the background, so an endpoint used to
|
|
161
|
+
* sit between two square in-range fills as a rounded square — leaving a white
|
|
162
|
+
* notch at each corner where its curve pulled away from its neighbour. The band
|
|
163
|
+
* read as interrupted by the endpoint rather than containing it.
|
|
164
|
+
*
|
|
165
|
+
* MUI solves the same problem by drawing a continuous highlight band behind the
|
|
166
|
+
* cells and putting the endpoint circle on top of it. That needs a second
|
|
167
|
+
* element per cell; squaring the inner edge of the endpoint's own fill gets the
|
|
168
|
+
* same join out of the existing one.
|
|
169
|
+
*/
|
|
170
|
+
.rsui-form-field-date-range__day--range-start {
|
|
171
|
+
@apply rounded-r-none;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.rsui-form-field-date-range__day--range-end {
|
|
175
|
+
@apply rounded-l-none;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/*
|
|
179
|
+
* Both modifiers land on the same day for a single-day window — `today`, or a
|
|
180
|
+
* range picked start-and-end on one date. There is no band to join, so restore
|
|
181
|
+
* the full radius. This selector is deliberately last and doubly-classed so it
|
|
182
|
+
* outranks the two above.
|
|
183
|
+
*/
|
|
184
|
+
.rsui-form-field-date-range__day--range-start.rsui-form-field-date-range__day--range-end {
|
|
185
|
+
@apply rounded-lg;
|
|
186
|
+
}
|
|
187
|
+
|
|
156
188
|
/*
|
|
157
189
|
* The day the presets resolve against — "today" as the server sees it.
|
|
158
190
|
*
|
package/components/icon.css
CHANGED
|
@@ -88,42 +88,52 @@
|
|
|
88
88
|
|
|
89
89
|
.rsui-icon--primary {
|
|
90
90
|
@apply *:text-text-primary;
|
|
91
|
+
--rsui-icon-pulse: var(--color-text-primary);
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
.rsui-icon--secondary {
|
|
94
95
|
@apply *:text-text-secondary;
|
|
96
|
+
--rsui-icon-pulse: var(--color-text-secondary);
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
.rsui-icon--brand {
|
|
98
100
|
@apply *:text-text-brand;
|
|
101
|
+
--rsui-icon-pulse: var(--color-text-brand);
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
.rsui-icon--success {
|
|
102
105
|
@apply *:text-text-success;
|
|
106
|
+
--rsui-icon-pulse: var(--color-text-success);
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
.rsui-icon--info {
|
|
106
110
|
@apply *:text-text-info;
|
|
111
|
+
--rsui-icon-pulse: var(--color-text-info);
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
.rsui-icon--warning {
|
|
110
115
|
@apply *:text-text-warning;
|
|
116
|
+
--rsui-icon-pulse: var(--color-text-warning);
|
|
111
117
|
}
|
|
112
118
|
|
|
113
119
|
.rsui-icon--error {
|
|
114
120
|
@apply *:text-text-error;
|
|
121
|
+
--rsui-icon-pulse: var(--color-text-error);
|
|
115
122
|
}
|
|
116
123
|
|
|
117
124
|
.rsui-icon--ai {
|
|
118
125
|
@apply *:text-text-ai;
|
|
126
|
+
--rsui-icon-pulse: var(--color-text-ai);
|
|
119
127
|
}
|
|
120
128
|
|
|
121
129
|
.rsui-icon--disabled {
|
|
122
130
|
@apply *:text-text-disabled;
|
|
131
|
+
--rsui-icon-pulse: var(--color-text-disabled);
|
|
123
132
|
}
|
|
124
133
|
|
|
125
134
|
.rsui-icon--classic {
|
|
126
135
|
@apply *:text-pink-500;
|
|
136
|
+
--rsui-icon-pulse: var(--color-pink-500);
|
|
127
137
|
}
|
|
128
138
|
|
|
129
139
|
.rsui-icon--primary.rsui-icon--invert {
|
|
@@ -216,52 +226,145 @@
|
|
|
216
226
|
@apply *:text-text-on-color;
|
|
217
227
|
}
|
|
218
228
|
|
|
229
|
+
/*
|
|
230
|
+
* Both flags together is the one combination that puts the glyph back on its
|
|
231
|
+
* variant colour, against a tinted fill — so each of these restates the pulse
|
|
232
|
+
* token alongside it, undoing the on-colour default set below. Kept here rather
|
|
233
|
+
* than in a block of its own so the ring colour is edited in the same place as
|
|
234
|
+
* the glyph colour it has to match.
|
|
235
|
+
*/
|
|
219
236
|
.rsui-icon--primary.rsui-icon--background.rsui-icon--invert {
|
|
220
237
|
@apply bg-background-primary-invert;
|
|
221
238
|
@apply *:text-text-primary;
|
|
239
|
+
--rsui-icon-pulse: var(--color-text-primary);
|
|
222
240
|
}
|
|
223
241
|
|
|
224
242
|
.rsui-icon--secondary.rsui-icon--background.rsui-icon--invert {
|
|
225
243
|
@apply bg-background-secondary-invert;
|
|
226
244
|
@apply *:text-text-secondary;
|
|
245
|
+
--rsui-icon-pulse: var(--color-text-secondary);
|
|
227
246
|
}
|
|
228
247
|
|
|
229
248
|
.rsui-icon--brand.rsui-icon--background.rsui-icon--invert {
|
|
230
249
|
@apply bg-background-brand-invert;
|
|
231
250
|
@apply *:text-text-brand;
|
|
251
|
+
--rsui-icon-pulse: var(--color-text-brand);
|
|
232
252
|
}
|
|
233
253
|
|
|
234
254
|
.rsui-icon--success.rsui-icon--background.rsui-icon--invert {
|
|
235
255
|
@apply bg-background-success-invert;
|
|
236
256
|
@apply *:text-text-success;
|
|
257
|
+
--rsui-icon-pulse: var(--color-text-success);
|
|
237
258
|
}
|
|
238
259
|
|
|
239
260
|
.rsui-icon--info.rsui-icon--background.rsui-icon--invert {
|
|
240
261
|
@apply bg-background-info-invert;
|
|
241
262
|
@apply *:text-text-info;
|
|
263
|
+
--rsui-icon-pulse: var(--color-text-info);
|
|
242
264
|
}
|
|
243
265
|
|
|
244
266
|
.rsui-icon--warning.rsui-icon--background.rsui-icon--invert {
|
|
245
267
|
@apply bg-background-warning-invert;
|
|
246
268
|
@apply *:text-text-warning;
|
|
269
|
+
--rsui-icon-pulse: var(--color-text-warning);
|
|
247
270
|
}
|
|
248
271
|
|
|
249
272
|
.rsui-icon--error.rsui-icon--background.rsui-icon--invert {
|
|
250
273
|
@apply bg-background-error-invert;
|
|
251
274
|
@apply *:text-text-error;
|
|
275
|
+
--rsui-icon-pulse: var(--color-text-error);
|
|
252
276
|
}
|
|
253
277
|
|
|
254
278
|
.rsui-icon--ai.rsui-icon--background.rsui-icon--invert {
|
|
255
279
|
@apply bg-background-ai-invert;
|
|
256
280
|
@apply *:text-text-ai;
|
|
281
|
+
--rsui-icon-pulse: var(--color-text-ai);
|
|
257
282
|
}
|
|
258
283
|
|
|
259
284
|
.rsui-icon--disabled.rsui-icon--background.rsui-icon--invert {
|
|
260
285
|
@apply bg-background-disabled-invert;
|
|
261
286
|
@apply *:text-text-disabled;
|
|
287
|
+
--rsui-icon-pulse: var(--color-text-disabled);
|
|
262
288
|
}
|
|
263
289
|
|
|
264
290
|
.rsui-icon--classic.rsui-icon--background.rsui-icon--invert {
|
|
265
291
|
@apply bg-pink-50;
|
|
266
292
|
@apply *:text-pink-500;
|
|
267
|
-
|
|
293
|
+
--rsui-icon-pulse: var(--color-pink-500);
|
|
294
|
+
}
|
|
295
|
+
/*
|
|
296
|
+
* On a filled or inverted icon the glyph is repainted to an on-colour token, so
|
|
297
|
+
* the ring follows it rather than staying on a variant colour it no longer
|
|
298
|
+
* matches. Same specificity as the base variant rules and declared after them,
|
|
299
|
+
* so it wins on source order — but it loses to the two-flag rules above, which
|
|
300
|
+
* is the point: those put the glyph back on its variant colour and take the ring
|
|
301
|
+
* with them.
|
|
302
|
+
*/
|
|
303
|
+
.rsui-icon--background,
|
|
304
|
+
.rsui-icon--invert {
|
|
305
|
+
--rsui-icon-pulse: var(--color-text-on-color);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/*
|
|
309
|
+
* Optional attention pulse: a ring expands out from the icon and fades, a few
|
|
310
|
+
* times, when the icon arrives.
|
|
311
|
+
*
|
|
312
|
+
* Deliberately a fixed number of iterations rather than `infinite`. An animation
|
|
313
|
+
* that repeats for more than five seconds needs a pause control (WCAG 2.2.2), and
|
|
314
|
+
* an icon has nowhere sensible to put one — three bursts draw the eye on arrival
|
|
315
|
+
* without taking on that obligation.
|
|
316
|
+
*
|
|
317
|
+
* Duration x iterations is the number that matters there, and it must stay under
|
|
318
|
+
* five seconds: 1.4s x 3 leaves 800ms of headroom. Slowing the ring to 1.8s to
|
|
319
|
+
* soften it further would put the total at 5.4s and trip the criterion, so the
|
|
320
|
+
* softening is done with opacity, border width and travel instead.
|
|
321
|
+
*
|
|
322
|
+
* The ring takes its colour from `--rsui-icon-pulse`, which each colour variant
|
|
323
|
+
* sets alongside its glyph rule.
|
|
324
|
+
*
|
|
325
|
+
* A custom property rather than `currentColor`: the variants colour the SVG child
|
|
326
|
+
* (`*:text-…`) and not the wrapper, so an inherited ring comes out near-black.
|
|
327
|
+
* Setting `color` on the wrapper instead would fix the base variants but silently
|
|
328
|
+
* miss `--invert` and `--background`, which repaint the glyph and would leave the
|
|
329
|
+
* ring on the old colour. A property the combination rules can override keeps the
|
|
330
|
+
* answer in one place — and, unlike a wrapper colour, it is inert for everything
|
|
331
|
+
* that does not read it.
|
|
332
|
+
*
|
|
333
|
+
* `pointer-events-none` because the ring overflows the icon's box and would
|
|
334
|
+
* otherwise sit over whatever is beside it.
|
|
335
|
+
*/
|
|
336
|
+
.rsui-icon--pulse {
|
|
337
|
+
@apply relative;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.rsui-icon--pulse::after {
|
|
341
|
+
@apply content-[''] absolute inset-0 rounded-full pointer-events-none;
|
|
342
|
+
border: 1px solid var(--rsui-icon-pulse, currentColor);
|
|
343
|
+
/* Invisible at rest, in both directions. Without this the ring reverts to its
|
|
344
|
+
un-animated state once the iterations finish — full opacity at scale 1 —
|
|
345
|
+
and a solid ring stays welded around the icon for the life of the page. */
|
|
346
|
+
@apply opacity-0;
|
|
347
|
+
animation: rsui-icon-pulse 1.4s ease-out 3;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
@keyframes rsui-icon-pulse {
|
|
351
|
+
0% {
|
|
352
|
+
opacity: 0.35;
|
|
353
|
+
transform: scale(1);
|
|
354
|
+
}
|
|
355
|
+
100% {
|
|
356
|
+
opacity: 0;
|
|
357
|
+
transform: scale(1.8);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/*
|
|
362
|
+
* The pulse is decoration on top of an icon that is already visible, so removing
|
|
363
|
+
* it costs nothing — no state is conveyed by the animation alone.
|
|
364
|
+
*/
|
|
365
|
+
@media (prefers-reduced-motion: reduce) {
|
|
366
|
+
.rsui-icon--pulse::after {
|
|
367
|
+
animation: none;
|
|
368
|
+
display: none;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
@@ -1,5 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* A row: optional icon, the text column, optional close. `items-start` so the
|
|
3
|
+
* icon and the close button align with the first line rather than centring
|
|
4
|
+
* against a tall body.
|
|
5
|
+
*/
|
|
1
6
|
.rsui-message-box {
|
|
2
|
-
@apply border rounded-lg overflow-hidden p-4 flex
|
|
7
|
+
@apply border rounded-lg overflow-hidden p-4 flex items-start gap-x-3;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* The text column. Carries the vertical rhythm the box itself used to own, so a
|
|
12
|
+
* box with no icon and no actions lays out exactly as it did before.
|
|
13
|
+
*/
|
|
14
|
+
.rsui-message-box__main {
|
|
15
|
+
@apply flex-1 flex flex-col gap-y-3;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
* Narrow and with an icon: the icon and the close button take a row of their own
|
|
20
|
+
* and the text runs full width beneath them, rather than indenting past a column
|
|
21
|
+
* that costs more than it gives at this width.
|
|
22
|
+
*
|
|
23
|
+
* Ordering is what makes it work — the DOM runs icon, text, close, so without it
|
|
24
|
+
* the full-width text column would wrap between the two and strand the close
|
|
25
|
+
* button on a third row. Scoped to `--with-icon` because a box with no icon has
|
|
26
|
+
* no column to escape: its close button already sits beside the title, and a
|
|
27
|
+
* lone X on its own row would be a wasted line.
|
|
28
|
+
*
|
|
29
|
+
* The box itself sets only `gap-x`, which buys nothing once these become two
|
|
30
|
+
* flex lines — so the row gap is set here, matching the text column's own
|
|
31
|
+
* rhythm. Inert at `sm:flex-nowrap`, where there is only ever one line.
|
|
32
|
+
*/
|
|
33
|
+
.rsui-message-box--with-icon {
|
|
34
|
+
@apply flex-wrap gap-y-3 sm:flex-nowrap;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.rsui-message-box--with-icon .rsui-message-box__close {
|
|
38
|
+
@apply order-2 ms-auto sm:order-3 sm:ms-0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* `sm:basis-0` rather than `basis-auto`, to restore exactly what `flex-1` sets. */
|
|
42
|
+
.rsui-message-box--with-icon .rsui-message-box__main {
|
|
43
|
+
@apply order-3 basis-full sm:order-2 sm:basis-0;
|
|
3
44
|
}
|
|
4
45
|
|
|
5
46
|
.rsui-message-box--default {
|
|
@@ -37,17 +78,76 @@
|
|
|
37
78
|
}
|
|
38
79
|
|
|
39
80
|
.rsui-message-box__head {
|
|
40
|
-
@apply flex
|
|
81
|
+
@apply flex items-center gap-x-2;
|
|
41
82
|
}
|
|
42
83
|
|
|
43
84
|
.rsui-message-box__content {
|
|
44
|
-
@apply flex
|
|
85
|
+
@apply flex items-start gap-x-2;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/*
|
|
89
|
+
* `items-start` so the icon aligns with the first line of the message rather
|
|
90
|
+
* than centring against a multi-line body. `shrink-0` keeps it from being
|
|
91
|
+
* squeezed by long text.
|
|
92
|
+
*/
|
|
93
|
+
.rsui-message-box__icon {
|
|
94
|
+
@apply shrink-0 flex items-center h-6;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/*
|
|
98
|
+
* Actions sit under the message, indented to the body rather than the icon, so
|
|
99
|
+
* they read as belonging to the text.
|
|
100
|
+
*
|
|
101
|
+
* Neutral, not variant-coloured: a coloured action on a coloured tint is a
|
|
102
|
+
* contrast problem, and the action is a way out of the message rather than a
|
|
103
|
+
* restatement of its severity. The dismiss is quieter than whatever the consumer
|
|
104
|
+
* puts beside it, which is the only hierarchy this row needs.
|
|
105
|
+
*/
|
|
106
|
+
.rsui-message-box__actions {
|
|
107
|
+
@apply flex flex-wrap items-center gap-x-4 gap-y-2 pt-1;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.rsui-message-box__dismiss,
|
|
111
|
+
.rsui-message-box__action {
|
|
112
|
+
@apply bg-transparent border-0 p-0 cursor-pointer;
|
|
113
|
+
@apply text-sm font-semibold transition-colors;
|
|
114
|
+
@apply hover:underline underline-offset-4 decoration-2;
|
|
115
|
+
@apply outline-hidden focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-border-primary rounded-sm;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/*
|
|
119
|
+
* Two tiers, and the only hierarchy this row needs: dismiss is the quieter of
|
|
120
|
+
* the pair, whatever the consumer puts beside it is the one they want pressed.
|
|
121
|
+
*/
|
|
122
|
+
.rsui-message-box__dismiss {
|
|
123
|
+
@apply text-text-secondary hover:text-text-primary;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.rsui-message-box__action {
|
|
127
|
+
@apply text-text-primary;
|
|
45
128
|
}
|
|
46
129
|
|
|
130
|
+
/*
|
|
131
|
+
* `-my-2` so the 40px hit target centres on the first 24px line rather than
|
|
132
|
+
* hanging 8px below it. Under `items-start` the button's own box starts at the
|
|
133
|
+
* padding edge, which put its glyph at y=36 against a title centred at y=28 —
|
|
134
|
+
* and, with an icon shown, two icons in the same row not lining up. The negative
|
|
135
|
+
* margin keeps the target size while claiming only 24px of layout height.
|
|
136
|
+
*/
|
|
47
137
|
.rsui-message-box__close {
|
|
48
|
-
@apply size-10;
|
|
138
|
+
@apply size-10 shrink-0 -my-2;
|
|
49
139
|
}
|
|
50
140
|
|
|
141
|
+
/*
|
|
142
|
+
* The glyph colour is set on the Icon itself (`secondary`), not here — the
|
|
143
|
+
* variant rules target the SVG child directly, so a colour on this button would
|
|
144
|
+
* lose to them.
|
|
145
|
+
*
|
|
146
|
+
* It was `disabled` before, which painted a working control in the disabled text
|
|
147
|
+
* colour — Grey-400, 2.41:1 on white — so it looked permanently greyed out and
|
|
148
|
+
* fell under the 3:1 WCAG 1.4.11 asks of a control. Grey-700 reads as quiet
|
|
149
|
+
* without reading as dead.
|
|
150
|
+
*/
|
|
51
151
|
.rsui-message-box__close-icon {
|
|
52
152
|
@apply size-10 cursor-pointer rounded-lg flex items-center justify-center hover:bg-border-secondary transition duration-200;
|
|
53
153
|
/* Reset native <button> chrome so it matches the prior inline affordance ... */
|
package/components/meta_info.css
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
.rsui-meta-info {
|
|
2
|
+
/* TIGHT PAIR — 4px between a label and its value, deliberately off the brand's 8px
|
|
3
|
+
rhythm. See the note above .rsui-card-header__text in card_header.css for the full
|
|
4
|
+
reasoning. Do not "fix" it back to space-xs.
|
|
5
|
+
|
|
6
|
+
The book assigns 8px to a label/value pair, but that assumes 16px body text, where
|
|
7
|
+
8px is a third of a line box. This component sets 12px with a 16px line box, so 8px
|
|
8
|
+
is HALF a line — measured — and at that size the pair stops reading as one field and
|
|
9
|
+
reads as two loose rows. 4px is a quarter of the line, and against the 16px between
|
|
10
|
+
fields it gives a 1:4 grouping instead of 1:2.
|
|
11
|
+
|
|
12
|
+
The real cause is that the meta is 12px at all, which is below the brand's own 14px
|
|
13
|
+
caption floor. Fix the size and 8px becomes correct; that belongs with the MetaInfo
|
|
14
|
+
size ramp in #316, not here. Until then this is the size the component ships at, and
|
|
15
|
+
the gap has to suit it. */
|
|
2
16
|
@apply flex flex-col gap-y-1;
|
|
3
17
|
}
|
|
4
18
|
|
|
@@ -6,7 +20,7 @@
|
|
|
6
20
|
legacy pattern, double-counts against any gap and breaks once the row wraps. Every other
|
|
7
21
|
component in the library spaces with gap. */
|
|
8
22
|
.rsui-meta-info__top {
|
|
9
|
-
@apply flex gap-x-
|
|
23
|
+
@apply flex gap-x-space-xs items-center;
|
|
10
24
|
}
|
|
11
25
|
|
|
12
26
|
.rsui-meta-info__label-icon {
|
|
@@ -18,7 +32,7 @@
|
|
|
18
32
|
eye landed on "Age" instead of on the number. Grey-600 on white measures 7.26:1, so it stays
|
|
19
33
|
comfortably readable at 12px. */
|
|
20
34
|
.rsui-meta-info__label {
|
|
21
|
-
@apply font-medium text-
|
|
35
|
+
@apply font-medium text-text-tertiary;
|
|
22
36
|
}
|
|
23
37
|
|
|
24
38
|
.rsui-meta-info__help {
|
|
@@ -32,25 +46,37 @@
|
|
|
32
46
|
/* The value carries the information, so it takes the emphasis the label gave up. */
|
|
33
47
|
.rsui-meta-info__value {
|
|
34
48
|
@apply flex items-center gap-x-space-xs;
|
|
35
|
-
@apply
|
|
49
|
+
@apply font-semibold text-text-primary;
|
|
36
50
|
}
|
|
37
51
|
|
|
38
|
-
.
|
|
39
|
-
|
|
52
|
+
/* SIZE RAMP. Three steps, matching StageDial. The label and value always share a
|
|
53
|
+
size — they are one field, and a field whose descriptor and content disagree on
|
|
54
|
+
size reads as two things.
|
|
55
|
+
|
|
56
|
+
`sm` is the default, and it is now DECLARED rather than left implicit in the base
|
|
57
|
+
rules. The size used to live on .rsui-meta-info__label and __value directly, so
|
|
58
|
+
the default had no class of its own: it could not be targeted, and the ramp read
|
|
59
|
+
as "md, lg, or nothing".
|
|
60
|
+
|
|
61
|
+
The names sit one step below the scale they produce — sm is text-xs, md is
|
|
62
|
+
text-sm, lg is text-base. That predates this change and is deliberately not
|
|
63
|
+
renamed: md and lg are used in consuming apps, so renaming them is a breaking
|
|
64
|
+
change for a cosmetic gain. */
|
|
65
|
+
.rsui-meta-info--sm .rsui-meta-info__label,
|
|
66
|
+
.rsui-meta-info--sm .rsui-meta-info__value {
|
|
67
|
+
@apply text-xs;
|
|
40
68
|
}
|
|
41
69
|
|
|
70
|
+
.rsui-meta-info--md .rsui-meta-info__label,
|
|
42
71
|
.rsui-meta-info--md .rsui-meta-info__value {
|
|
43
72
|
@apply text-sm;
|
|
44
73
|
}
|
|
45
74
|
|
|
46
|
-
.rsui-meta-info--lg .rsui-meta-info__label
|
|
47
|
-
@apply text-base;
|
|
48
|
-
}
|
|
49
|
-
|
|
75
|
+
.rsui-meta-info--lg .rsui-meta-info__label,
|
|
50
76
|
.rsui-meta-info--lg .rsui-meta-info__value {
|
|
51
77
|
@apply text-base;
|
|
52
78
|
}
|
|
53
79
|
|
|
54
80
|
.rsui-meta-info--inline {
|
|
55
|
-
@apply flex-row flex-wrap items-center gap-x-
|
|
81
|
+
@apply flex-row flex-wrap items-center gap-x-space-xs gap-y-space-xs;
|
|
56
82
|
}
|
|
@@ -1,39 +1,71 @@
|
|
|
1
|
+
/* gap, not space-y. space-* adds margins to children, which is the legacy pattern the
|
|
2
|
+
rest of the library has moved off — see the note in meta_info.css. It double-counts
|
|
3
|
+
against any margin a child sets for itself and it breaks once a row wraps. Both
|
|
4
|
+
happened here: see __title below. */
|
|
1
5
|
.rsui-page-header {
|
|
2
|
-
@apply w-full flex justify-between
|
|
6
|
+
@apply w-full flex justify-between gap-y-space-md;
|
|
3
7
|
@apply lg:flex-col;
|
|
4
8
|
}
|
|
5
9
|
|
|
6
10
|
.rsui-page-header__top {
|
|
7
|
-
@apply w-full flex flex-col items-start
|
|
8
|
-
@apply lg:flex-row lg:
|
|
11
|
+
@apply w-full flex flex-col items-start gap-y-space-xs flex-wrap;
|
|
12
|
+
@apply lg:flex-row lg:gap-y-0 lg:items-center;
|
|
9
13
|
}
|
|
10
14
|
|
|
15
|
+
/* 16px avatar -> title, matching the card family's avatar gap, and set once as a gap
|
|
16
|
+
rather than twice as margins.
|
|
17
|
+
|
|
18
|
+
It was space-x-6 here plus mr-3 on the avatar. In Tailwind v4 space-x-* sets
|
|
19
|
+
margin-inline-end on every child but the last, so the avatar's own mr-3 overrode it
|
|
20
|
+
and the rendered gap was 12px, not the 24px this rule reads as. Measured. Neither
|
|
21
|
+
value was reachable by editing the other, which is the whole problem with space-*. */
|
|
11
22
|
.rsui-page-header__title {
|
|
12
|
-
@apply pr-
|
|
23
|
+
@apply pr-space-xs flex flex-row items-start gap-x-space-md;
|
|
13
24
|
}
|
|
14
25
|
|
|
26
|
+
/* Material 3 puts a prominent page title in its Headline range and sets all UI type in
|
|
27
|
+
a sans face — so this drops Newsreader and lands on the two RedSeed steps that cover
|
|
28
|
+
that range: Header 3 (Inter Bold 28/120%) below lg, Header 2 (Inter Black 40/115%,
|
|
29
|
+
-1% tracking) from lg up.
|
|
30
|
+
|
|
31
|
+
It was font-redseed-heading — which resolves to Newsreader — at 30 -> 36px. Off-brand
|
|
32
|
+
twice over: the book restricts Newsreader to Header 1 and says not to push it below
|
|
33
|
+
Header 1 sizes, and neither 30 nor 36 is a step on the scale at all.
|
|
34
|
+
|
|
35
|
+
40px also keeps a page title a clear step above SectionHeader's 28px, which is the
|
|
36
|
+
hierarchy M3 maintains between a top app bar and a heading inside content.
|
|
37
|
+
|
|
38
|
+
Deviation worth naming: M3 sets top-app-bar titles at weight 400 Regular. RedSeed's
|
|
39
|
+
scale specifies Bold for Header 3 and Black for Header 2, and the tokens win here per
|
|
40
|
+
the same rule the card family followed — M3's structure, RedSeed's type.
|
|
41
|
+
|
|
42
|
+
lg:mr-4 removed. __title-text-container already supplies a 24px gap between the title
|
|
43
|
+
and the status slot, so the margin added to it and the rendered gap was 40px — the
|
|
44
|
+
same accidental sum the avatar had. */
|
|
15
45
|
.rsui-page-header__title h1 {
|
|
16
|
-
@apply
|
|
46
|
+
@apply text-[1.75rem] leading-[1.2] font-bold text-text-primary;
|
|
47
|
+
@apply lg:text-[2.5rem] lg:leading-[1.15] lg:tracking-[-0.01em] lg:font-black;
|
|
17
48
|
}
|
|
18
49
|
|
|
19
50
|
.rsui-page-header__title-text-container {
|
|
20
|
-
@apply flex flex-row
|
|
51
|
+
@apply flex flex-row gap-x-space-lg items-center;
|
|
21
52
|
}
|
|
22
53
|
|
|
23
54
|
.rsui-page-header__status {
|
|
24
55
|
@apply flex-shrink-0;
|
|
25
56
|
}
|
|
26
57
|
|
|
58
|
+
/* Brand body: 16px at 150%. leading-relaxed is 1.625, so this rendered 16/26. */
|
|
27
59
|
.rsui-page-header__subtitle {
|
|
28
|
-
@apply text-base text-text-secondary
|
|
60
|
+
@apply text-base leading-normal text-text-secondary;
|
|
29
61
|
}
|
|
30
62
|
|
|
31
63
|
.rsui-page-header__status-actions {
|
|
32
|
-
@apply flex-1 flex
|
|
64
|
+
@apply flex-1 flex gap-x-space-xs items-center justify-between lg:pr-space-xs;
|
|
33
65
|
}
|
|
34
66
|
|
|
35
67
|
.rsui-page-header__actions {
|
|
36
|
-
@apply flex-1 flex space-
|
|
68
|
+
@apply flex-1 flex flex-wrap gap-space-xs items-center justify-end;
|
|
37
69
|
}
|
|
38
70
|
|
|
39
71
|
.rsui-page-header__meta-action {
|
|
@@ -41,7 +73,7 @@
|
|
|
41
73
|
}
|
|
42
74
|
|
|
43
75
|
.rsui-page-header__search {
|
|
44
|
-
@apply w-full pt-
|
|
76
|
+
@apply w-full pt-space-xs lg:pt-0 lg:w-auto;
|
|
45
77
|
}
|
|
46
78
|
|
|
47
79
|
.rsui-page-header__meta-modal {
|
|
@@ -49,15 +81,15 @@
|
|
|
49
81
|
}
|
|
50
82
|
|
|
51
83
|
.rsui-page-header__meta-modal__body {
|
|
52
|
-
@apply flex flex-col
|
|
84
|
+
@apply flex flex-col gap-y-space-md;
|
|
53
85
|
}
|
|
54
86
|
|
|
55
87
|
.rsui-page-header__meta {
|
|
56
|
-
@apply hidden lg:flex
|
|
88
|
+
@apply hidden lg:flex gap-x-space-xl;
|
|
57
89
|
}
|
|
58
90
|
|
|
59
91
|
.rsui-page-header__avatar {
|
|
60
|
-
@apply shrink-0 size-12
|
|
92
|
+
@apply shrink-0 size-12;
|
|
61
93
|
}
|
|
62
94
|
|
|
63
95
|
/* Profile variant — larger avatar, bottom-aligned text, inline subtitle */
|
|
@@ -65,16 +97,18 @@
|
|
|
65
97
|
@apply lg:items-end;
|
|
66
98
|
}
|
|
67
99
|
|
|
100
|
+
/* The profile avatar is larger, so it takes more room beside the title than the
|
|
101
|
+
default 16px — 24px from lg up, added to the gap rather than replacing it. */
|
|
68
102
|
.rsui-page-header--profile .rsui-page-header__avatar {
|
|
69
|
-
@apply shrink-0 size-auto
|
|
103
|
+
@apply shrink-0 size-auto lg:me-space-xs lg:pb-space-md;
|
|
70
104
|
}
|
|
71
105
|
|
|
72
106
|
.rsui-page-header--profile .rsui-page-header__status-actions {
|
|
73
|
-
@apply lg:self-end lg:pb-
|
|
107
|
+
@apply lg:self-end lg:pb-space-lg;
|
|
74
108
|
}
|
|
75
109
|
|
|
76
110
|
.rsui-page-header--profile .rsui-page-header__subtitle {
|
|
77
|
-
@apply flex flex-col gap-
|
|
111
|
+
@apply flex flex-col gap-space-xs lg:flex-row lg:items-center lg:gap-space-md;
|
|
78
112
|
}
|
|
79
113
|
|
|
80
114
|
|
|
@@ -99,7 +133,7 @@
|
|
|
99
133
|
/* Fallbacks keep an unrecognised tone legible rather than transparent. */
|
|
100
134
|
background: var(--rsui-page-header-bg, var(--color-background-secondary));
|
|
101
135
|
|
|
102
|
-
@apply
|
|
136
|
+
@apply p-space-lg;
|
|
103
137
|
}
|
|
104
138
|
|
|
105
139
|
.rsui-page-header--tone-green {
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
.rsui-radio-card {
|
|
2
2
|
@apply relative cursor-pointer transition-all;
|
|
3
3
|
/* No resting shadow: this was the only card in the family that sat lifted while the
|
|
4
|
-
other seven are flat.
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
other seven are flat. ring-offset-2 matches the focus geometry every other card
|
|
5
|
+
uses — this ring previously hugged the border with no offset.
|
|
6
|
+
|
|
7
|
+
Padding is 24/24, the same as every other member — but it has to be written here
|
|
8
|
+
rather than inherited, because RadioCard is the one family member that does NOT
|
|
9
|
+
render a <Card>, so the padding rule in card.css never reaches it. Keep the two in
|
|
10
|
+
step. The 32px sides it used to carry were 20% of its fixed 320px width. */
|
|
7
11
|
@apply rounded-xl outline-hidden select-none;
|
|
8
|
-
@apply flex flex-col gap-
|
|
12
|
+
@apply flex flex-col gap-space-md py-space-lg px-space-lg max-w-80 w-80;
|
|
9
13
|
@apply bg-background-primary border border-border-primary;
|
|
10
14
|
@apply focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-border-primary;
|
|
11
15
|
}
|
|
@@ -48,7 +52,7 @@
|
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
.rsui-radio-card__title-row {
|
|
51
|
-
@apply relative text-
|
|
55
|
+
@apply relative text-xl leading-[1.3] font-medium text-text-primary line-clamp-3 min-h-6 pr-8;
|
|
52
56
|
|
|
53
57
|
@apply after:content-[''] after:absolute after:top-0 after:right-0;
|
|
54
58
|
@apply after:size-6 after:rounded-full after:transition-all;
|
|
@@ -72,8 +76,11 @@
|
|
|
72
76
|
@apply after:border-7 after:border-background-primary after:bg-border-primary;
|
|
73
77
|
}
|
|
74
78
|
|
|
79
|
+
/* Brand Header 4, matching .rsui-card-header__title. The row above carries the same
|
|
80
|
+
size deliberately: line-clamp-3 lives there, and it measures against the clamped
|
|
81
|
+
element's own line-height, so a mismatch clips at the wrong place. */
|
|
75
82
|
.rsui-radio-card__title {
|
|
76
|
-
@apply flex-1 text-
|
|
83
|
+
@apply flex-1 text-xl leading-[1.3] font-semibold text-text-primary;
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
.rsui-radio-card__content-row {
|
|
@@ -85,9 +92,9 @@
|
|
|
85
92
|
}
|
|
86
93
|
|
|
87
94
|
.rsui-radio-card__meta-row {
|
|
88
|
-
@apply grid grid-cols-1 sm:grid-cols-2 gap-x-
|
|
95
|
+
@apply grid grid-cols-1 sm:grid-cols-2 gap-x-space-xl gap-y-space-xs;
|
|
89
96
|
}
|
|
90
97
|
|
|
91
98
|
.rsui-radio-card__action-row {
|
|
92
|
-
@apply flex flex-wrap gap-
|
|
99
|
+
@apply flex flex-wrap gap-space-xs;
|
|
93
100
|
}
|