@redseed/redseed-ui-tailwindcss 7.55.0 → 7.57.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.
@@ -24,12 +24,314 @@
24
24
 
25
25
  .rsui-section-slider__action {
26
26
  @apply shrink-0 inline-flex items-center justify-center size-14 rounded-full no-underline transition-all disabled:opacity-50 disabled:text-grey-400 hover:cursor-pointer disabled:hover:cursor-default border border-grey-400 bg-transparent;
27
+ @apply focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-border-primary;
27
28
  }
28
29
 
30
+ /*
31
+ * The trailing "view all" card. The element carries `rsui-card
32
+ * rsui-card--bordered` plus any `rsui-card--<variant>`, so radius, background,
33
+ * border colour and the transition all come from Card — including every
34
+ * variant's border colour, which is the point of composing rather than
35
+ * restating. This file adds only what Card has no opinion about.
36
+ *
37
+ * The dashed edge is the one deliberate departure, and it is what marks the card
38
+ * as an opening rather than content. It follows form_field_uploader.css, the
39
+ * package's only other dashed affordance. `section_slider.css` is imported after
40
+ * `card.css`, so this wins on source order at equal specificity.
41
+ *
42
+ * `hover:shadow-md` rather than a background change, mirroring
43
+ * `rsui-card--hoverable`: it reads the same on every variant, whereas shifting
44
+ * the background would fight whatever colour the variant just set.
45
+ *
46
+ * No `color` here on purpose. Card does not set one either — its text comes from
47
+ * whichever Section encloses it — and Tailwind's preflight already gives buttons
48
+ * `color: inherit`, so the card picks up the section the same way a real card
49
+ * does. Setting it explicitly produced the same pixels today but would have
50
+ * ignored a section that ever chose a different text colour.
51
+ *
52
+ * Height is not declared: the rail item is a flex container that stretches, so
53
+ * the shell takes its height from the tallest card in the track. A fixed height
54
+ * would go short or overhang the moment consumer cards changed.
55
+ *
56
+ * Width is a floor rather than a fixed value. The rail item has no intrinsic
57
+ * width — consumer cards supply their own — so `w-full` here would resolve
58
+ * against content and collapse to the label. `min-w-64` matches the common card
59
+ * width and still grows if the consumer puts something wider inside.
60
+ */
61
+ .rsui-section-slider__view-all {
62
+ @apply min-w-64 items-center justify-center gap-3 border-dashed p-space-lg text-center;
63
+ @apply font-semibold;
64
+ @apply hover:cursor-pointer hover:shadow-md;
65
+ @apply focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-border-primary outline-hidden;
66
+ }
67
+
68
+ /*
69
+ * The `ai` variant is the exception: Card gives it an animated gradient, which is
70
+ * a lot of movement for a card that is meant to be an opening rather than a
71
+ * destination. Cleared so the section's own background — itself the ai gradient
72
+ * when the slider is in that variant — shows through instead.
73
+ *
74
+ * `bg-none` and not `bg-transparent`: Card paints this one with
75
+ * `background-image`, which a background-colour reset leaves untouched. That is
76
+ * also why the other variants need no rule here — theirs are background colours,
77
+ * and they are meant to stay.
78
+ *
79
+ * Card has no `--bordered.--ai` companion the way the other variants do, so the
80
+ * border would otherwise fall back to the base grey. Brand-500 matches the border
81
+ * the `--ai` section itself uses.
82
+ */
83
+ .rsui-section-slider__view-all.rsui-card--ai {
84
+ @apply bg-none border-brand-500;
85
+ }
86
+
87
+ /*
88
+ * The icon slot, stacked above the label the way Empty stacks its image. Sizing
89
+ * belongs to whichever Icon component the consumer puts inside — those size
90
+ * their own SVG child.
91
+ *
92
+ * Colour, though, has to be taken back. Icon's variants pin the SVG to a fixed
93
+ * token (`--primary` is `text-text-primary`), which would leave the icon sitting
94
+ * still while the label darkens on hover, and dark on the brand-600 surface of
95
+ * `--featured` where the rest of the card has inverted. Forcing `currentColor`
96
+ * onto the SVG makes the icon inherit the button, so it moves and inverts with
97
+ * the label without the consumer having to pick a matching Icon variant.
98
+ *
99
+ * `IconCircleBackground` is excluded, though — it already carries a deliberate
100
+ * on-colour pairing, and forcing `currentColor` would put a dark glyph on its dark
101
+ * contrast-coloured circle.
102
+ *
103
+ * Both branches of the `:is()` need the guard. A bare `svg` alternative looks
104
+ * harmless but matches the heroicon inside a background icon just the same, and
105
+ * with the wrapper class in front the rule is (0,3,0) — above the (0,2,0) that
106
+ * paints the glyph — so it would win outright and defeat the exclusion this
107
+ * comment claims to make.
108
+ */
109
+ .rsui-section-slider__view-all-icon {
110
+ @apply flex items-center justify-center;
111
+ }
112
+
113
+ .rsui-section-slider__view-all-icon :is(.rsui-icon:not(.rsui-icon--background) svg, .rsui-icon:not(.rsui-icon--background) > *) {
114
+ color: currentColor;
115
+ }
116
+
117
+ /*
118
+ * Card's tokens are built for a light surface, and this variant is brand-600, so
119
+ * they invert here — the same thing the header title and subtitle already do for
120
+ * `--featured`.
121
+ *
122
+ * `bg-transparent` is load-bearing, not tidying. `.rsui-card` paints
123
+ * `bg-background-primary`, which is white, and nothing else in this cascade
124
+ * resets it — inverting only the foreground leaves white text and a white dashed
125
+ * border on a white card, i.e. an invisible card on a brand-600 slider. The card
126
+ * has to sit on the brand surface for the inversion to mean anything.
127
+ */
128
+ .rsui-section-slider--featured .rsui-section-slider__view-all {
129
+ @apply bg-transparent border-white/60 text-white/80;
130
+ @apply hover:border-white hover:bg-white/10 hover:text-white;
131
+ @apply focus-visible:ring-white;
132
+ }
133
+
134
+ /*
135
+ * Same reasoning on the `--ai` section, minus the inversion. That gradient is
136
+ * light enough for the default dark label to stay legible, so only the fill has
137
+ * to go — Card's white would otherwise sit on the gradient as a flat patch, which
138
+ * is the one place a ghost card should be showing what is behind it.
139
+ *
140
+ * `bg-transparent` and not `bg-none` here: the card's own background is a colour
141
+ * at this point, since `--ai` describes the section rather than the card. The
142
+ * `bg-none` rule above is for `viewAllVariant="ai"`, where Card paints a gradient
143
+ * via `background-image` instead.
144
+ */
145
+ .rsui-section-slider--ai .rsui-section-slider__view-all {
146
+ @apply bg-transparent;
147
+ @apply hover:bg-white/40;
148
+ }
149
+
150
+ /*
151
+ * The `focus-visible` ring below is not decorative. Below `lg` this is a real
152
+ * scroll port, and Chrome can make scroll containers keyboard-focusable so they
153
+ * can be arrow-keyed — measured at 500px, this one is focusable with
154
+ * `outline-style: none`, i.e. a focus stop with no visible indicator (WCAG
155
+ * 2.4.7). At `lg` and up the track is `overflow-x-hidden`, which is not
156
+ * user-scrollable and so not focusable, and the rule never fires.
157
+ *
158
+ * `ring-inset` rather than an offset ring: the slider root is `overflow-x-hidden`
159
+ * with `px-0`, so the track sits flush against it and an outset ring would be
160
+ * clipped away on both edges — and clipped a second time by the mask in
161
+ * `--hover-actions` mode. Same reason card_group.css and form_field_date_range.css
162
+ * use it.
163
+ */
29
164
  .rsui-section-slider__container {
30
165
  @apply relative flex gap-x-3 lg:gap-x-6 overflow-x-auto lg:overflow-x-hidden focus:outline-hidden scroll-smooth snap-x snap-mandatory scroll-pl-space-lg;
166
+ @apply focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-border-primary;
167
+ }
168
+
169
+ /*
170
+ * Position announcements for screen readers. The rail is a list of cards, not a
171
+ * carousel, so there is no slide to name -- what a non-sighted user cannot
172
+ * recover is simply how far along the rail they now are.
173
+ */
174
+ .rsui-section-slider__announcer {
175
+ @apply sr-only;
31
176
  }
32
177
 
33
178
  .rsui-section-slider__container::-webkit-scrollbar {
34
179
  @apply hidden;
35
180
  }
181
+
182
+ /*
183
+ * Edge fades for `hover-actions`. With the arrows held back until hover, a
184
+ * resting rail has nothing at all to say it moves, and the peeking last card is
185
+ * doing that work alone. Fading the edge that has content behind it gives the
186
+ * rail a permanent affordance that costs no hover, no touch and no semantics.
187
+ *
188
+ * A mask rather than a gradient overlay, because the fade has to work over four
189
+ * different section backgrounds — default, `--featured` (brand-600) and `--ai`
190
+ * (itself a gradient). Colour-matching an overlay to a gradient is not possible;
191
+ * masking the content to transparent is background-agnostic and needs no variant
192
+ * of its own.
193
+ *
194
+ * Both widths rest at 0, which collapses the gradient to fully opaque, so the
195
+ * mask is inert until Vue adds a fade modifier. Not transitioned: the widths
196
+ * would need registering via @property to animate at all, and the switch happens
197
+ * mid-scroll where the movement already covers it.
198
+ */
199
+ .rsui-section-slider__container {
200
+ --rsui-section-slider-fade-start: 0px;
201
+ --rsui-section-slider-fade-end: 0px;
202
+ }
203
+
204
+ .rsui-section-slider--hover-actions .rsui-section-slider__container {
205
+ mask-image: linear-gradient(
206
+ to right,
207
+ transparent 0,
208
+ black var(--rsui-section-slider-fade-start),
209
+ black calc(100% - var(--rsui-section-slider-fade-end)),
210
+ transparent 100%
211
+ );
212
+ }
213
+
214
+ .rsui-section-slider__container--fade-start {
215
+ --rsui-section-slider-fade-start: 3rem;
216
+ }
217
+
218
+ .rsui-section-slider__container--fade-end {
219
+ --rsui-section-slider-fade-end: 3rem;
220
+ }
221
+
222
+ /*
223
+ * Positioning context for the `hover-actions` overlay. Deliberately a wrapper
224
+ * around the track rather than the track itself: the container is the scroll
225
+ * port, so anything absolutely positioned inside it scrolls away with the cards.
226
+ */
227
+ .rsui-section-slider__viewport {
228
+ @apply relative;
229
+ }
230
+
231
+ /*
232
+ * Overlay navigation layer — one full-bleed layer rather than two individually
233
+ * positioned buttons, so `justify-between` places the pair on the two edges and
234
+ * `items-center` centres them on the rail without any transform maths.
235
+ *
236
+ * The layer spans the cards, so it has to stay transparent to the pointer;
237
+ * `pointer-events-none` here with `pointer-events-auto` back on the buttons
238
+ * keeps the cards underneath clickable.
239
+ *
240
+ * Hidden below `lg` on purpose. Up to that breakpoint the track is
241
+ * `overflow-x-auto` and swipe already moves it, so arrows over the artwork would
242
+ * be covering content to duplicate a gesture the user already has.
243
+ */
244
+ .rsui-section-slider__actions {
245
+ @apply hidden lg:flex absolute inset-0 z-10 items-center justify-between px-3 pointer-events-none;
246
+ }
247
+
248
+ /*
249
+ * Overlaid arrows sit on card artwork, so the header's transparent pill would
250
+ * leave the chevron competing with whatever is behind it. Give these ones a
251
+ * solid surface — scoped to the overlay so header arrows keep their existing
252
+ * look.
253
+ *
254
+ * This single-tone border does not *guarantee* 1.4.11 against arbitrary
255
+ * photography: its outer edge always has an unknown image beside it, so it fails
256
+ * on mid-tone imagery. It narrows the gap rather than closing it, helped by the
257
+ * fade behind the pill — though note the fade only covers the outer part of the
258
+ * pill's backdrop (the fade runs 0–3rem from the edge, the pill roughly
259
+ * 0.75–4.25rem), and only partially at that.
260
+ *
261
+ * A two-tone indicator would actually close it: two adjacent bands with 3:1
262
+ * against each other means at least one of them clears 3:1 against whatever is
263
+ * behind, whatever that turns out to be. Deliberately not done here — it is a
264
+ * visible design change to the control rather than a correctness fix, so it wants
265
+ * a decision rather than a commit.
266
+ */
267
+ .rsui-section-slider__actions .rsui-section-slider__action {
268
+ @apply pointer-events-auto bg-background-primary border-grey-600 shadow-xl;
269
+ }
270
+
271
+ @media (hover: hover) {
272
+ /*
273
+ * Rest hidden, reveal on the rail. Opacity rather than `display`/`hidden` so
274
+ * the buttons keep their box (no reflow as they appear) and stay reachable
275
+ * by keyboard — a focusable control that cannot be seen fails WCAG 2.4.7,
276
+ * which is what `:focus-within` below is for. The base class already carries
277
+ * `transition-all`, so the fade needs nothing added here.
278
+ *
279
+ * Gated on `(hover: hover)`: from `lg` up the track is `overflow-x-hidden`,
280
+ * so these arrows are the only way to move the rail. A touch device at a
281
+ * desktop width — iPad in landscape, touchscreen laptop — has no swipe and
282
+ * no hover, and would be left with no way to navigate at all. Those devices
283
+ * keep the arrows on permanently.
284
+ */
285
+ .rsui-section-slider__actions .rsui-section-slider__action {
286
+ @apply opacity-0;
287
+ }
288
+
289
+ /*
290
+ * `:enabled` so only arrows that can actually move the rail come forward.
291
+ * In rail mode that tracks scroll position, so a resting rail shows no
292
+ * previous arrow at all rather than one pointing into nothing, and the pair
293
+ * disappears entirely when every card already fits. The button stays in the
294
+ * DOM and in the a11y tree as disabled, which tells a screen reader user
295
+ * "start of the rail" — something an unmounted button cannot do.
296
+ */
297
+ .rsui-section-slider__viewport:hover .rsui-section-slider__action:enabled,
298
+ .rsui-section-slider__viewport:focus-within .rsui-section-slider__action:enabled {
299
+ @apply opacity-100;
300
+ }
301
+
302
+ /*
303
+ * Escape hides the arrows again while the pointer is still on the rail —
304
+ * WCAG 1.4.13 wants hover-revealed content that obscures other content to be
305
+ * dismissable without moving the pointer, and these do sit over the cards.
306
+ *
307
+ * `:not(:focus-within)` because dismissal must not win over the focus reveal
308
+ * above. Without it, pressing Escape with the pointer on the rail and focus on
309
+ * an arrow hid a control that was still focused and still clickable — the
310
+ * exact 2.4.7 failure the reveal rule exists to prevent.
311
+ *
312
+ * `:enabled` carries no extra weight of its own here: this selector and the
313
+ * reveal above both compute to (0,4,0), so it only brings this level and the
314
+ * cascade decides on source order. That is why this block has to stay last
315
+ * inside the query.
316
+ */
317
+ .rsui-section-slider__viewport--navigation-dismissed:not(:focus-within):hover .rsui-section-slider__action:enabled {
318
+ @apply opacity-0;
319
+ }
320
+ }
321
+
322
+ /*
323
+ * Reduced motion. This rule covers swipe and keyboard scrolling, which never go
324
+ * through JavaScript. Arrow presses are handled separately in scrollToPosition,
325
+ * which passes an explicit `'instant'` — a scripted `behavior` other than `auto`
326
+ * overrides `scroll-behavior`, so the two paths do not overlap and neither is
327
+ * redundant.
328
+ */
329
+ @media (prefers-reduced-motion: reduce) {
330
+ .rsui-section-slider__container {
331
+ scroll-behavior: auto;
332
+ }
333
+
334
+ .rsui-section-slider__action {
335
+ transition: none;
336
+ }
337
+ }
@@ -53,6 +53,28 @@
53
53
  @apply absolute inset-[15%] flex items-center justify-center text-center;
54
54
  }
55
55
 
56
+ /* On a coloured or dark surface. The centre content has no colour of its own and
57
+ inherits the page ink, which on a dark band is near-invisible — this is the
58
+ only thing the variant needs to change. Same mechanism as
59
+ .rsui-body-text--on-color, including the child selector, since the slot
60
+ usually holds its own elements.
61
+
62
+ The track is deliberately NOT changed, because measuring said it did not need
63
+ to be. Grey-400 against the two tonal bands:
64
+
65
+ on Journey Green 800 (#0a4c38) 4.13:1
66
+ on Deep Teal 700 (#0c3035) 5.84:1
67
+
68
+ both clear of the 3:1 WCAG 1.4.11 asks of a non-text graphic. The obvious
69
+ "improvement" would have made it worse: a translucent white track, which is
70
+ what this looked like in the mock, measures 1.64:1 at 18% and 2.61:1 at 35%
71
+ — both failures. If a consumer wants the track tinted to their band, that is
72
+ a --rsui-stage-dial-* style override, not a default. */
73
+ .rsui-stage-dial--on-color .rsui-stage-dial__content {
74
+ @apply text-text-on-color;
75
+ @apply *:text-text-on-color;
76
+ }
77
+
56
78
  @media (prefers-reduced-motion: reduce) {
57
79
  .rsui-stage-dial--animate .rsui-stage-dial__fill {
58
80
  transition: none;
@@ -14,3 +14,109 @@
14
14
  .rsui-switcher .rsui-switcher-item {
15
15
  @apply w-full sm:w-fit;
16
16
  }
17
+
18
+ /* Bordered — for a switcher on a surface that is not white. Opt in with the
19
+ `bordered` prop.
20
+
21
+ The track is `background-disabled` (Grey-25, #fcfcfc) and a secondary Section is
22
+ `background-secondary` (Grey-50, #fafafa): 2/255 apart, and the track is the
23
+ *lighter* of the two, so on a grey surface it does not read as a container at all.
24
+
25
+ A border rather than a darker fill, so the tonal well stays the same grey
26
+ everywhere it already works. Note it does add 2px to each axis, so a bordered
27
+ switcher no longer aligns exactly with an unbordered sibling.
28
+
29
+ `:not(--chips)` on both new modifiers: chips deliberately has no track
30
+ (`bg-transparent p-0 rounded-none`), so a border there is a square hairline box
31
+ hugging the chips with a clipped shadow — broken-looking rather than opt-out-able.
32
+ Excluded here rather than reset in the chips block, so no existing chips rule
33
+ changes. */
34
+ .rsui-switcher--bordered:not(.rsui-switcher--chips) {
35
+ @apply border border-border-secondary;
36
+ }
37
+
38
+ /* The active item is already delineated by its own Grey-300 border
39
+ (`switcher_item.css`, `--active` sets `border-border-secondary` against a base of
40
+ `border-transparent`). Once the container gains a Grey-300 border too, the pill
41
+ edge and the track edge are the same colour and the nesting reads flat. The shadow
42
+ re-separates the two by depth rather than by adding a third colour.
43
+
44
+ `shadow-sm` rather than a raw `box-shadow`, which would be the only literal shadow
45
+ in the package — every other component uses a utility. */
46
+ .rsui-switcher--bordered:not(.rsui-switcher--chips) .rsui-switcher-item--active {
47
+ @apply shadow-sm;
48
+ }
49
+
50
+ /* Inline — one row below `sm`, split between the options. Opt in with the `inline`
51
+ prop, and pair it with `full`: `inline` sets the direction, `full` gives it a row
52
+ to split. On its own the container is still `w-fit` and shrink-wraps.
53
+
54
+ Scoped to `max-sm` on purpose: at `sm` and above the default is already a row, so
55
+ there is nothing to change and nothing to accidentally break — `--full`'s `flex-1`
56
+ in particular is left entirely alone. Only the sub-`sm` stack is overridden.
57
+
58
+ Three declarations, all load-bearing:
59
+ - `w-auto` undoes `w-full` from `.rsui-switcher .rsui-switcher-item`, which would
60
+ otherwise make each option claim the full width of a row it is now sharing.
61
+ This works by source order at equal specificity (0,2,0), so this block must
62
+ stay BELOW that base item rule.
63
+ - `flex-1` is what actually splits the row between the options.
64
+ - `min-w-0` is what stops it clipping. Flex items floor at `min-width: auto`, and
65
+ the item is `whitespace-nowrap`, so without this they refuse to shrink below
66
+ their label, the row outgrows the `overflow-hidden` track, and options are cut
67
+ off with no scrollbar and no way to reach them — measured at 166px of a 360px
68
+ track lost with three long labels. `overflow-hidden` on the item keeps a long
69
+ label inside its own button rather than spilling over its neighbour. */
70
+ .rsui-switcher--inline:not(.rsui-switcher--chips) {
71
+ @apply max-sm:flex-row max-sm:items-center;
72
+ }
73
+
74
+ .rsui-switcher--inline:not(.rsui-switcher--chips) .rsui-switcher-item {
75
+ @apply max-sm:w-auto max-sm:flex-1 max-sm:min-w-0 max-sm:overflow-hidden;
76
+ }
77
+
78
+ /* Chips variant — a filter chip set rather than a segmented control. Opt in with
79
+ the `chips` prop; the default is untouched.
80
+
81
+ Two differences, and both are the reason it exists:
82
+ 1. No tonal container, so the chips sit directly on the page rather than in
83
+ a grey well.
84
+ 2. One row that scrolls sideways when it runs out of width, instead of
85
+ stacking. The default stacks below `sm` — documented and deliberate for a
86
+ segmented control — but a stacking chip set makes its container grow by an
87
+ unpredictable number of lines, which is what this avoids.
88
+
89
+ Every rule below has to out-specify a same-specificity rule above it, so this
90
+ block must stay last in the file. */
91
+ .rsui-switcher--chips {
92
+ @apply w-full flex-row items-center flex-nowrap gap-2;
93
+ @apply bg-transparent p-0 rounded-none;
94
+
95
+ /* The default is overflow-hidden; this row is meant to scroll. Scrollbar
96
+ hidden to match .rsui-tab-slider, which already does exactly this. */
97
+ @apply overflow-x-auto;
98
+ scrollbar-width: none;
99
+ }
100
+
101
+ .rsui-switcher--chips::-webkit-scrollbar {
102
+ display: none;
103
+ }
104
+
105
+ /* Overrides `w-full sm:w-fit` above: a chip is sized by its own label at every
106
+ width, never stretched to fill the row. */
107
+ .rsui-switcher--chips .rsui-switcher-item {
108
+ @apply w-fit rounded-full;
109
+ @apply bg-background-primary text-text-secondary border-border-primary;
110
+
111
+ /* 44px, so a chip clears the Apple HIG touch target on a phone. The default
112
+ item computes to 42px and is deliberately left alone. */
113
+ @apply min-h-11;
114
+ }
115
+
116
+ .rsui-switcher--chips .rsui-switcher-item--active {
117
+ @apply bg-background-primary-contrast text-text-on-color border-transparent;
118
+ }
119
+
120
+ .rsui-switcher--chips .rsui-switcher-item--disabled {
121
+ @apply bg-background-disabled text-text-disabled border-transparent;
122
+ }
@@ -1,7 +1,24 @@
1
+ /* The item is a native <button role="tab"> so it is keyboard operable and announces as a
2
+ tab (it used to be a click-handled <div>, which no keyboard could reach). These plain
3
+ declarations strip the UA button chrome so the visual design is unchanged — written out
4
+ rather than assumed from Tailwind preflight, because RSUI's index.css does not import
5
+ Tailwind itself and the consuming app may not ship preflight. */
1
6
  .rsui-switcher-item {
7
+ appearance: none;
8
+ background: none;
9
+ margin: 0;
10
+ border: 0 solid transparent;
11
+ font: inherit;
12
+ color: inherit;
13
+
2
14
  @apply h-fit inline-flex shrink-0 items-center justify-center select-none outline-hidden whitespace-nowrap will-change-transform cursor-pointer;
3
15
  @apply font-semibold gap-2 rounded-lg border border-transparent transition;
4
16
  @apply text-base px-3 py-2;
17
+
18
+ /* The class list above sets outline-hidden, which previously left the item with no focus
19
+ indicator at all once it became focusable. Drawn inset because .rsui-switcher is
20
+ overflow-hidden and would clip an offset ring. */
21
+ @apply focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-border-primary;
5
22
  }
6
23
 
7
24
  .rsui-switcher-item--active {
@@ -16,6 +33,8 @@
16
33
  @apply size-6;
17
34
  }
18
35
 
36
+ /* No ml-space-xs here: the parent is a flex row that already supplies gap-space-xs, so the
37
+ margin stacked on top of it and the badge sat 16px from its label instead of 8px. */
19
38
  .rsui-switcher-item__badge {
20
- @apply ml-space-xs flex items-center;
21
- }
39
+ @apply flex items-center;
40
+ }
@@ -1,7 +1,26 @@
1
+ /* The item is a native <button role="tab"> so it is keyboard operable and announces as a
2
+ tab (it used to be a click-handled <div>, which no keyboard could reach). These plain
3
+ declarations strip the UA button chrome so the visual design is byte-for-byte unchanged.
4
+ They are written out rather than assumed from Tailwind preflight because RSUI's index.css
5
+ does not import Tailwind itself — the consuming app does, and may not ship preflight.
6
+ The border reset matters most: the @apply below sets only `border-b-2`, so without an
7
+ all-sides width of 0 the UA's default `medium outset` border would remain on the other
8
+ three sides and widen every tab. */
1
9
  .rsui-tab-slider-item {
10
+ appearance: none;
11
+ background: none;
12
+ margin: 0;
13
+ border: 0 solid transparent;
14
+ font: inherit;
15
+ color: inherit;
16
+
2
17
  @apply inline-flex shrink-0 items-center justify-center select-none cursor-pointer whitespace-nowrap;
3
18
  @apply text-base px-4 py-3 gap-2 border-b-2 border-transparent -mb-px;
4
19
  @apply text-text-secondary;
20
+
21
+ /* Focus is drawn inside the box: .rsui-tab-slider is an overflow-x-auto scroller, so an
22
+ offset ring on the first or last tab would be clipped by it. */
23
+ @apply outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-border-primary;
5
24
  }
6
25
 
7
26
  .rsui-tab-slider-item--active {
@@ -16,6 +35,8 @@
16
35
  @apply size-5;
17
36
  }
18
37
 
38
+ /* No ml-space-xs here: the parent is a flex row that already supplies gap-space-xs, so the
39
+ margin stacked on top of it and the badge sat 16px from its label instead of 8px. */
19
40
  .rsui-tab-slider-item__badge {
20
- @apply ml-space-xs flex items-center;
41
+ @apply flex items-center;
21
42
  }
package/components.css CHANGED
@@ -54,7 +54,6 @@ Please be careful when adding new components and updating the order.
54
54
  @import './components/form_wrapper_build.css';
55
55
  @import './components/form_wrapper_lms.css';
56
56
  @import './components/grid_container.css';
57
- @import './components/hero_section.css';
58
57
  @import './components/icon.css';
59
58
  @import './components/image.css';
60
59
  @import './components/image_16by9.css';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redseed/redseed-ui-tailwindcss",
3
- "version": "7.55.0",
3
+ "version": "7.57.0",
4
4
  "description": "RedSeed UI Tailwindcss",
5
5
  "main": "index.js",
6
6
  "style": "index.css",
package/tokens.css CHANGED
@@ -12,7 +12,11 @@
12
12
  --color-text-warning: #b54708;
13
13
  --color-text-error: #b42318;
14
14
  --color-text-info: #0077cc;
15
- --color-text-ai: var(--Colors-Warm-Mauve-600);
15
+ /* Warm-Mauve-800, not -600: the AI treatments set this over the pale AI gradient
16
+ (#ebe0fa -> #fff6eb), where -600 measured 2.93:1 and failed WCAG AA for 14px text.
17
+ -800 clears it at 4.52:1 at the gradient's worst point. Consumed by Badge AI,
18
+ Button AI, the AI body-text modifier and the AI icon treatments. */
19
+ --color-text-ai: var(--Colors-Warm-Mauve-800);
16
20
  --color-text-on-color: var(--Colors-Base-white);
17
21
 
18
22
  --color-background-primary: var(--Colors-Base-white);
@@ -1,32 +0,0 @@
1
- .rsui-hero-section {
2
- @apply rounded-xl px-5 py-6 flex flex-col gap-4 md:gap-6 relative overflow-hidden bg-text-primary text-text-on-color;
3
- }
4
-
5
- .rsui-hero-section::before {
6
- content: '';
7
- position: absolute;
8
- inset: 0;
9
- background-size: auto;
10
- background-position: right center;
11
- background-repeat: no-repeat;
12
- opacity: 1;
13
- z-index: 0;
14
- }
15
-
16
- .rsui-hero-section > * {
17
- position: relative;
18
- z-index: 1;
19
- }
20
-
21
- .rsui-hero-section__cards {
22
- @apply grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-6;
23
- }
24
-
25
- .rsui-hero-section__cards--hidden {
26
- @apply hidden;
27
- }
28
-
29
- .rsui-hero-section__content--hidden {
30
- @apply hidden;
31
- }
32
-