gbs-add-block 2.0.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/.gbs/skills/gbs-components/references/styling.md +35 -10
  2. package/README.md +22 -7
  3. package/package.json +1 -1
  4. package/source/beta-components/accordion/styles.css +5 -5
  5. package/source/beta-components/alert/styles.css +4 -4
  6. package/source/beta-components/avatar/styles.css +226 -227
  7. package/source/beta-components/badge/styles.css +7 -7
  8. package/source/beta-components/breadcrumb/styles.css +5 -4
  9. package/source/beta-components/button/styles.css +5 -4
  10. package/source/beta-components/card/styles.css +5 -4
  11. package/source/beta-components/checkbox/styles.css +5 -4
  12. package/source/beta-components/combobox/styles.css +4 -4
  13. package/source/beta-components/data-grid/styles.css +7 -8
  14. package/source/beta-components/date-picker/styles.css +4 -4
  15. package/source/beta-components/dialog/styles.css +5 -4
  16. package/source/beta-components/file-uploader/styles.css +5 -4
  17. package/source/beta-components/input/styles.css +5 -4
  18. package/source/beta-components/menu/styles.css +5 -4
  19. package/source/beta-components/modal/styles.css +5 -4
  20. package/source/beta-components/number-input/styles.css +5 -5
  21. package/source/beta-components/popover/styles.css +5 -4
  22. package/source/beta-components/progress/styles.css +1 -2
  23. package/source/beta-components/radio-group/styles.css +270 -270
  24. package/source/beta-components/skeleton/styles.css +5 -4
  25. package/source/beta-components/spinner/styles.css +174 -174
  26. package/source/beta-components/switch/styles.css +229 -229
  27. package/source/beta-components/tabs/styles.css +264 -264
  28. package/source/beta-components/textarea/styles.css +5 -4
  29. package/source/beta-components/toaster/styles.css +1 -2
  30. package/source/beta-components/tooltip/styles.css +5 -4
@@ -113,18 +113,25 @@ exist is silently ignored, so check the list.
113
113
  Classes are joined with `cx` from `shared/core/cx.ts`, which drops falsy values
114
114
  — a conditional that evaluates to `undefined` contributes nothing.
115
115
 
116
- ## 4. Tailwind
116
+ ## 4. Cascade layers and Tailwind
117
117
 
118
- Every `styles.css` declares:
118
+ Every `styles.css` ships its rules in one layer and declares nothing else:
119
119
 
120
120
  ```css
121
- @layer theme, base, components, utilities;
122
- @layer components { /* the component's rules */ }
121
+ @layer gbs { /* the component's rules */ }
123
122
  ```
124
123
 
125
- Component rules live in the `components` layer, so **Tailwind utilities passed
126
- through `className` / `classNames` win** without `!important`. That is the
127
- supported way to adjust spacing, typography and layout.
124
+ Where `gbs` sits is the app's call. Declare the order once in the global CSS;
125
+ anything in a later layer beats the components:
126
+
127
+ ```css
128
+ @layer reset, gbs, app, utilities;
129
+ ```
130
+
131
+ With Tailwind v4, naming `gbs` before `utilities` means **a utility passed
132
+ through `className` / `classNames` wins** without `!important`. Tailwind v3
133
+ needs no line — it emits utilities unlayered, which already outrank a layer.
134
+ A project with no CSS framework needs no line either.
128
135
 
129
136
  ```tsx
130
137
  <Button className="w-full sm:w-auto" classNames={{ content: "gap-3" }}>Save</Button>
@@ -134,7 +141,25 @@ Do not use `!important`, and do not write selectors against internal class names
134
141
  (`.bt-root`, `.dg-cell`) in app CSS — they are implementation detail. Use the
135
142
  variables or the slots.
136
143
 
137
- ## 5. State attributes
144
+ ## 5. Unlayered resets (Bootstrap, Normalize)
145
+
146
+ Any stylesheet that ships **unlayered** beats every layered rule regardless of
147
+ specificity — the cascade settles layers before specificity. So Bootstrap's
148
+ Reboot (`button { border-radius: 0 }`, `button, input, textarea { font-size:
149
+ inherit }`) overrides our classes, and import order does not help.
150
+
151
+ Fix it in the project's global CSS by giving the reset its own layer, named
152
+ before `gbs`:
153
+
154
+ ```css
155
+ @layer bootstrap, gbs, app, utilities;
156
+ @import url("bootstrap/dist/css/bootstrap.min.css") layer(bootstrap);
157
+ ```
158
+
159
+ Only components whose root is a native form element are affected (Button,
160
+ Textarea). Class names never collide — ours are two-letter prefixed.
161
+
162
+ ## 6. State attributes
138
163
 
139
164
  Components expose their state as `data-*` attributes, so you can style states
140
165
  without tracking them in React.
@@ -155,7 +180,7 @@ without tracking them in React.
155
180
  .cb-option[data-active] { outline: 2px solid var(--gbs-focus); }
156
181
  ```
157
182
 
158
- ## 6. Dark mode
183
+ ## 7. Dark mode
159
184
 
160
185
  Colours are `light-dark()` pairs driven by the page's `color-scheme`, so the
161
186
  default is whatever the device prefers. To pin it, set `color-scheme` — the
@@ -174,7 +199,7 @@ Do not maintain a second palette for dark mode. Override the `--gbs-*` variables
174
199
  with `light-dark()` pairs, or set them inside your own `[data-theme="dark"]`
175
200
  block, and every component follows.
176
201
 
177
- ## 7. Right-to-left
202
+ ## 8. Right-to-left
178
203
 
179
204
  The components use logical properties and read `dir` from the document, so RTL
180
205
  works without configuration. Arrow keys in Menu, Switch and Tabs mirror
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # GBS Building Blocks 2.0 (v2.0.3)
1
+ # GBS Building Blocks 2.0 (v2.1.0)
2
2
 
3
3
  Latest and upgraded version of GBS building blocks with headless UI and removed dependencies.
4
4
 
@@ -33,13 +33,28 @@ Pick a subset with `--for claude,codex`, or `--for none` for just `.gbs/`.
33
33
  Commit the result so everyone's agent picks it up. Re-run to update; a file you
34
34
  have edited is never replaced without `--force`.
35
35
 
36
- ## What's New 🎉 (Ver 2.0.3)
36
+ ## What's New 🎉 (Ver 2.1.0)
37
37
 
38
- - Agent skill: stylesheets are now documented as a single import in the
39
- project's global CSS. The previous wording showed the stylesheet import
40
- beside the component import, which led coding agents to repeat it in every
41
- component file they wrote — making CSS order depend on module import order,
42
- and arriving late on lazy-loaded routes.
38
+ **The application now owns CSS cascade order.** Component rules moved out of the
39
+ `components` layer into a layer of their own, `gbs`, and the stylesheets no
40
+ longer declare a global layer order.
41
+
42
+ Previously every `styles.css` opened with
43
+ `@layer theme, base, components, utilities;` — a leaf file asserting the order
44
+ of the whole document. Whichever stylesheet the bundler emitted first silently
45
+ won that argument. It also meant a Tailwind v3 build failed outright, and
46
+ Bootstrap's Reboot could not be put in front of the components.
47
+
48
+ - Tailwind **v3** projects now build. Utilities override components there too,
49
+ with no setup.
50
+ - Tailwind **v4** projects add one line to their global CSS:
51
+ `@layer gbs, utilities;` — **without it, utilities no longer override
52
+ component styles.** This is the migration step.
53
+ - Bootstrap, Normalize or any unlayered reset can now be placed before the
54
+ components: `@layer bootstrap, gbs, app, utilities;`
55
+ - Projects with no CSS framework need no change.
56
+
57
+ See the Theming page, "Cascade layers", for the full model.
43
58
 
44
59
  ## Authors
45
60
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gbs-add-block",
3
- "version": "2.0.3",
3
+ "version": "2.1.0",
4
4
  "description": "React Component Library",
5
5
  "type": "module",
6
6
  "files": [
@@ -4,13 +4,13 @@
4
4
  * Each section is a native <details>, so the marker has to be taken off (two
5
5
  * ways: `list-item` display in Firefox, the WebKit pseudo-element elsewhere)
6
6
  * before a chevron of our own goes on. Tokens read the shared --gbs-*
7
- * variables when they are set on an ancestor (set them on :root to theme every
8
- * component at once). Rules live in the `components` layer, so utility classes
9
- * passed through `className` / `classNames` override them.
7
+ * variables when they are set on an ancestor (set them on :root to theme
8
+ * every component at once). Rules live in the `gbs` layer; declare where it
9
+ * sits in your global CSS, e.g. `@layer reset, gbs, app, utilities;`, and
10
+ * anything in a later layer overrides them.
10
11
  */
11
- @layer theme, base, components, utilities;
12
12
 
13
- @layer components {
13
+ @layer gbs {
14
14
  .ac-root {
15
15
  --ac-fg: var(--gbs-fg, var(--dg-fg, light-dark(#18181b, #f4f4f5)));
16
16
  --ac-muted: var(--gbs-muted, var(--dg-muted, light-dark(#71717a, #a1a1aa)));
@@ -3,12 +3,12 @@
3
3
  *
4
4
  * A banner that sits in the page, tinted by variant. Tokens read the shared
5
5
  * --gbs-* variables when they are set on an ancestor (set them on :root to
6
- * theme every component at once). Rules live in the `components` layer, so
7
- * utility classes passed through `className` / `classNames` override them.
6
+ * theme every component at once). Rules live in the `gbs` layer; declare
7
+ * where it sits in your global CSS, e.g. `@layer reset, gbs, app,
8
+ * utilities;`, and anything in a later layer overrides them.
8
9
  */
9
- @layer theme, base, components, utilities;
10
10
 
11
- @layer components {
11
+ @layer gbs {
12
12
  .al-root {
13
13
  --al-fg: var(--gbs-fg, var(--dg-fg, light-dark(#18181b, #f4f4f5)));
14
14
  --al-muted: var(--gbs-muted, var(--dg-muted, light-dark(#71717a, #a1a1aa)));
@@ -1,227 +1,226 @@
1
- /*
2
- * Avatar and AvatarGroup styles.
3
- *
4
- * The fallback colour comes from --av-hue-index, which the component sets from
5
- * a hash of the name: the same person is the same colour everywhere, and the
6
- * palette is generated rather than listed, so it follows a themed hue. Tokens
7
- * read the shared --gbs-* variables when they are set on an ancestor (set them
8
- * on :root to theme every component at once). Rules live in the `components`
9
- * layer, so utility classes passed through `className` / `classNames` override
10
- * them.
11
- */
12
- @layer theme, base, components, utilities;
13
-
14
- @layer components {
15
- .av-root,
16
- .av-group,
17
- .av-overflow {
18
- --av-fg: var(--gbs-fg, var(--dg-fg, light-dark(#18181b, #f4f4f5)));
19
- --av-muted: var(--gbs-muted, var(--dg-muted, light-dark(#71717a, #a1a1aa)));
20
- --av-bg: var(--gbs-bg, var(--dg-bg, light-dark(#ffffff, #0b0b0e)));
21
- --av-subtle: var(--gbs-subtle, light-dark(#f4f4f5, #1c1c20));
22
- --av-border: var(--gbs-border, var(--dg-border, light-dark(#e4e4e7, #27272a)));
23
- --av-success: var(--gbs-success, light-dark(#15803d, #4ade80));
24
- --av-warning: var(--gbs-warning, light-dark(#b45309, #fbbf24));
25
- --av-danger: var(--gbs-danger, var(--dg-danger, light-dark(#dc2626, #f87171)));
26
- --av-radius: var(--gbs-radius, var(--dg-radius, 8px));
27
- --av-size: 32px;
28
- --av-font-size: 13px;
29
- --av-hue-index: 0;
30
- /* Eight hues, 45° apart, starting at the blue end. */
31
- --av-hue: calc(210 + var(--av-hue-index) * 45);
32
-
33
- color-scheme: inherit;
34
- }
35
-
36
- :where(.dark, [data-theme="dark"]) :is(.av-root, .av-group, .av-overflow) {
37
- color-scheme: dark;
38
- }
39
- :where(.light, [data-theme="light"]) :is(.av-root, .av-group, .av-overflow) {
40
- color-scheme: light;
41
- }
42
-
43
- :where(.av-root, .av-group) *,
44
- :where(.av-root, .av-group) *::before,
45
- :where(.av-root, .av-group) *::after {
46
- box-sizing: border-box;
47
- }
48
-
49
- .av-root {
50
- position: relative;
51
- display: inline-flex;
52
- flex: none;
53
- align-items: center;
54
- justify-content: center;
55
- width: var(--av-size);
56
- height: var(--av-size);
57
- border-radius: 50%;
58
- background: var(--av-subtle);
59
- font-size: var(--av-font-size);
60
- font-weight: 600;
61
- line-height: 1;
62
- overflow: hidden;
63
- user-select: none;
64
- vertical-align: middle;
65
- }
66
- .av-root[data-shape="square"] {
67
- border-radius: var(--av-radius);
68
- overflow: visible;
69
- }
70
- .av-root[data-shape="square"] .av-image,
71
- .av-root[data-shape="square"] .av-fallback {
72
- border-radius: var(--av-radius);
73
- }
74
-
75
- .av-root[data-size="xs"] {
76
- --av-size: 20px;
77
- --av-font-size: 10px;
78
- }
79
- .av-root[data-size="sm"] {
80
- --av-size: 24px;
81
- --av-font-size: 11px;
82
- }
83
- .av-root[data-size="lg"] {
84
- --av-size: 40px;
85
- --av-font-size: 15px;
86
- }
87
- .av-root[data-size="xl"] {
88
- --av-size: 56px;
89
- --av-font-size: 20px;
90
- }
91
-
92
- .av-image {
93
- width: 100%;
94
- height: 100%;
95
- object-fit: cover;
96
- }
97
-
98
- /* `oklch` keeps every hue at the same lightness, so no one person's initials
99
- come out harder to read than another's — which is what a list of hand-picked
100
- hex pairs always ends up doing. */
101
- .av-fallback {
102
- display: flex;
103
- align-items: center;
104
- justify-content: center;
105
- width: 100%;
106
- height: 100%;
107
- background: oklch(from light-dark(oklch(0.93 0.05 0), oklch(0.32 0.06 0)) l c var(--av-hue));
108
- color: oklch(from light-dark(oklch(0.42 0.13 0), oklch(0.88 0.1 0)) l c var(--av-hue));
109
- text-transform: uppercase;
110
- }
111
- .av-fallback > svg {
112
- width: 60%;
113
- height: 60%;
114
- }
115
-
116
- .av-status {
117
- position: absolute;
118
- right: 0;
119
- bottom: 0;
120
- width: 30%;
121
- height: 30%;
122
- min-width: 8px;
123
- min-height: 8px;
124
- border: 2px solid var(--av-bg);
125
- border-radius: 50%;
126
- background: var(--av-muted);
127
- }
128
- .av-root[data-shape="square"] .av-status {
129
- right: -2px;
130
- bottom: -2px;
131
- }
132
- .av-status[data-status="online"] {
133
- background: var(--av-success);
134
- }
135
- .av-status[data-status="away"] {
136
- background: var(--av-warning);
137
- }
138
- .av-status[data-status="busy"] {
139
- background: var(--av-danger);
140
- }
141
-
142
- /* ---------------------------------------------------------------- group */
143
-
144
- .av-group {
145
- display: inline-flex;
146
- align-items: center;
147
- vertical-align: middle;
148
- }
149
- /* Each face overlaps the one before and is ringed in the page colour, so the
150
- stack reads as separate people rather than one smear. */
151
- .av-group > * {
152
- margin-inline-start: calc(var(--av-size) / -4);
153
- box-shadow: 0 0 0 2px var(--av-bg);
154
- }
155
- .av-group > *:first-child {
156
- margin-inline-start: 0;
157
- }
158
-
159
- .av-overflow {
160
- position: relative;
161
- display: inline-flex;
162
- flex: none;
163
- align-items: center;
164
- justify-content: center;
165
- width: var(--av-size);
166
- height: var(--av-size);
167
- border-radius: 50%;
168
- background: var(--av-subtle);
169
- /* Muted grey clears 4.5:1 on the page background but only reaches 4.39:1
170
- on this one, so the count moves a step towards the text colour. */
171
- color: color-mix(in oklab, var(--av-muted) 65%, var(--av-fg));
172
- font-size: calc(var(--av-font-size) - 1px);
173
- font-weight: 600;
174
- font-variant-numeric: tabular-nums;
175
- line-height: 1;
176
- }
177
- .av-overflow[data-shape="square"] {
178
- border-radius: var(--av-radius);
179
- }
180
- .av-group[data-size="xs"],
181
- .av-overflow[data-size="xs"] {
182
- --av-size: 20px;
183
- --av-font-size: 10px;
184
- }
185
- .av-group[data-size="sm"],
186
- .av-overflow[data-size="sm"] {
187
- --av-size: 24px;
188
- --av-font-size: 11px;
189
- }
190
- .av-group[data-size="lg"],
191
- .av-overflow[data-size="lg"] {
192
- --av-size: 40px;
193
- --av-font-size: 15px;
194
- }
195
- .av-group[data-size="xl"],
196
- .av-overflow[data-size="xl"] {
197
- --av-size: 56px;
198
- --av-font-size: 20px;
199
- }
200
- /* The group's size reaches the avatars inside it, unless one sets its own. */
201
- .av-group[data-size="xs"] .av-root:not([data-size]) {
202
- --av-size: 20px;
203
- --av-font-size: 10px;
204
- }
205
- .av-group[data-size="sm"] .av-root:not([data-size]) {
206
- --av-size: 24px;
207
- --av-font-size: 11px;
208
- }
209
- .av-group[data-size="lg"] .av-root:not([data-size]) {
210
- --av-size: 40px;
211
- --av-font-size: 15px;
212
- }
213
- .av-group[data-size="xl"] .av-root:not([data-size]) {
214
- --av-size: 56px;
215
- --av-font-size: 20px;
216
- }
217
-
218
- @media (forced-colors: active) {
219
- .av-root,
220
- .av-overflow {
221
- border: 1px solid CanvasText;
222
- }
223
- .av-status {
224
- border-color: Canvas;
225
- }
226
- }
227
- }
1
+ /*
2
+ * Avatar and AvatarGroup styles.
3
+ *
4
+ * The fallback colour comes from --av-hue-index, which the component sets from
5
+ * a hash of the name: the same person is the same colour everywhere, and the
6
+ * palette is generated rather than listed, so it follows a themed hue. Tokens
7
+ * read the shared --gbs-* variables when they are set on an ancestor (set them
8
+ * on :root to theme every component at once). Rules live in the `components`
9
+ * layer, so utility classes passed through `className` / `classNames` override
10
+ * them.
11
+ */
12
+
13
+ @layer gbs {
14
+ .av-root,
15
+ .av-group,
16
+ .av-overflow {
17
+ --av-fg: var(--gbs-fg, var(--dg-fg, light-dark(#18181b, #f4f4f5)));
18
+ --av-muted: var(--gbs-muted, var(--dg-muted, light-dark(#71717a, #a1a1aa)));
19
+ --av-bg: var(--gbs-bg, var(--dg-bg, light-dark(#ffffff, #0b0b0e)));
20
+ --av-subtle: var(--gbs-subtle, light-dark(#f4f4f5, #1c1c20));
21
+ --av-border: var(--gbs-border, var(--dg-border, light-dark(#e4e4e7, #27272a)));
22
+ --av-success: var(--gbs-success, light-dark(#15803d, #4ade80));
23
+ --av-warning: var(--gbs-warning, light-dark(#b45309, #fbbf24));
24
+ --av-danger: var(--gbs-danger, var(--dg-danger, light-dark(#dc2626, #f87171)));
25
+ --av-radius: var(--gbs-radius, var(--dg-radius, 8px));
26
+ --av-size: 32px;
27
+ --av-font-size: 13px;
28
+ --av-hue-index: 0;
29
+ /* Eight hues, 45° apart, starting at the blue end. */
30
+ --av-hue: calc(210 + var(--av-hue-index) * 45);
31
+
32
+ color-scheme: inherit;
33
+ }
34
+
35
+ :where(.dark, [data-theme="dark"]) :is(.av-root, .av-group, .av-overflow) {
36
+ color-scheme: dark;
37
+ }
38
+ :where(.light, [data-theme="light"]) :is(.av-root, .av-group, .av-overflow) {
39
+ color-scheme: light;
40
+ }
41
+
42
+ :where(.av-root, .av-group) *,
43
+ :where(.av-root, .av-group) *::before,
44
+ :where(.av-root, .av-group) *::after {
45
+ box-sizing: border-box;
46
+ }
47
+
48
+ .av-root {
49
+ position: relative;
50
+ display: inline-flex;
51
+ flex: none;
52
+ align-items: center;
53
+ justify-content: center;
54
+ width: var(--av-size);
55
+ height: var(--av-size);
56
+ border-radius: 50%;
57
+ background: var(--av-subtle);
58
+ font-size: var(--av-font-size);
59
+ font-weight: 600;
60
+ line-height: 1;
61
+ overflow: hidden;
62
+ user-select: none;
63
+ vertical-align: middle;
64
+ }
65
+ .av-root[data-shape="square"] {
66
+ border-radius: var(--av-radius);
67
+ overflow: visible;
68
+ }
69
+ .av-root[data-shape="square"] .av-image,
70
+ .av-root[data-shape="square"] .av-fallback {
71
+ border-radius: var(--av-radius);
72
+ }
73
+
74
+ .av-root[data-size="xs"] {
75
+ --av-size: 20px;
76
+ --av-font-size: 10px;
77
+ }
78
+ .av-root[data-size="sm"] {
79
+ --av-size: 24px;
80
+ --av-font-size: 11px;
81
+ }
82
+ .av-root[data-size="lg"] {
83
+ --av-size: 40px;
84
+ --av-font-size: 15px;
85
+ }
86
+ .av-root[data-size="xl"] {
87
+ --av-size: 56px;
88
+ --av-font-size: 20px;
89
+ }
90
+
91
+ .av-image {
92
+ width: 100%;
93
+ height: 100%;
94
+ object-fit: cover;
95
+ }
96
+
97
+ /* `oklch` keeps every hue at the same lightness, so no one person's initials
98
+ come out harder to read than another's — which is what a list of hand-picked
99
+ hex pairs always ends up doing. */
100
+ .av-fallback {
101
+ display: flex;
102
+ align-items: center;
103
+ justify-content: center;
104
+ width: 100%;
105
+ height: 100%;
106
+ background: oklch(from light-dark(oklch(0.93 0.05 0), oklch(0.32 0.06 0)) l c var(--av-hue));
107
+ color: oklch(from light-dark(oklch(0.42 0.13 0), oklch(0.88 0.1 0)) l c var(--av-hue));
108
+ text-transform: uppercase;
109
+ }
110
+ .av-fallback > svg {
111
+ width: 60%;
112
+ height: 60%;
113
+ }
114
+
115
+ .av-status {
116
+ position: absolute;
117
+ right: 0;
118
+ bottom: 0;
119
+ width: 30%;
120
+ height: 30%;
121
+ min-width: 8px;
122
+ min-height: 8px;
123
+ border: 2px solid var(--av-bg);
124
+ border-radius: 50%;
125
+ background: var(--av-muted);
126
+ }
127
+ .av-root[data-shape="square"] .av-status {
128
+ right: -2px;
129
+ bottom: -2px;
130
+ }
131
+ .av-status[data-status="online"] {
132
+ background: var(--av-success);
133
+ }
134
+ .av-status[data-status="away"] {
135
+ background: var(--av-warning);
136
+ }
137
+ .av-status[data-status="busy"] {
138
+ background: var(--av-danger);
139
+ }
140
+
141
+ /* ---------------------------------------------------------------- group */
142
+
143
+ .av-group {
144
+ display: inline-flex;
145
+ align-items: center;
146
+ vertical-align: middle;
147
+ }
148
+ /* Each face overlaps the one before and is ringed in the page colour, so the
149
+ stack reads as separate people rather than one smear. */
150
+ .av-group > * {
151
+ margin-inline-start: calc(var(--av-size) / -4);
152
+ box-shadow: 0 0 0 2px var(--av-bg);
153
+ }
154
+ .av-group > *:first-child {
155
+ margin-inline-start: 0;
156
+ }
157
+
158
+ .av-overflow {
159
+ position: relative;
160
+ display: inline-flex;
161
+ flex: none;
162
+ align-items: center;
163
+ justify-content: center;
164
+ width: var(--av-size);
165
+ height: var(--av-size);
166
+ border-radius: 50%;
167
+ background: var(--av-subtle);
168
+ /* Muted grey clears 4.5:1 on the page background but only reaches 4.39:1
169
+ on this one, so the count moves a step towards the text colour. */
170
+ color: color-mix(in oklab, var(--av-muted) 65%, var(--av-fg));
171
+ font-size: calc(var(--av-font-size) - 1px);
172
+ font-weight: 600;
173
+ font-variant-numeric: tabular-nums;
174
+ line-height: 1;
175
+ }
176
+ .av-overflow[data-shape="square"] {
177
+ border-radius: var(--av-radius);
178
+ }
179
+ .av-group[data-size="xs"],
180
+ .av-overflow[data-size="xs"] {
181
+ --av-size: 20px;
182
+ --av-font-size: 10px;
183
+ }
184
+ .av-group[data-size="sm"],
185
+ .av-overflow[data-size="sm"] {
186
+ --av-size: 24px;
187
+ --av-font-size: 11px;
188
+ }
189
+ .av-group[data-size="lg"],
190
+ .av-overflow[data-size="lg"] {
191
+ --av-size: 40px;
192
+ --av-font-size: 15px;
193
+ }
194
+ .av-group[data-size="xl"],
195
+ .av-overflow[data-size="xl"] {
196
+ --av-size: 56px;
197
+ --av-font-size: 20px;
198
+ }
199
+ /* The group's size reaches the avatars inside it, unless one sets its own. */
200
+ .av-group[data-size="xs"] .av-root:not([data-size]) {
201
+ --av-size: 20px;
202
+ --av-font-size: 10px;
203
+ }
204
+ .av-group[data-size="sm"] .av-root:not([data-size]) {
205
+ --av-size: 24px;
206
+ --av-font-size: 11px;
207
+ }
208
+ .av-group[data-size="lg"] .av-root:not([data-size]) {
209
+ --av-size: 40px;
210
+ --av-font-size: 15px;
211
+ }
212
+ .av-group[data-size="xl"] .av-root:not([data-size]) {
213
+ --av-size: 56px;
214
+ --av-font-size: 20px;
215
+ }
216
+
217
+ @media (forced-colors: active) {
218
+ .av-root,
219
+ .av-overflow {
220
+ border: 1px solid CanvasText;
221
+ }
222
+ .av-status {
223
+ border-color: Canvas;
224
+ }
225
+ }
226
+ }
@@ -1,15 +1,15 @@
1
1
  /*
2
2
  * Badge and Tag styles.
3
3
  *
4
- * One tinted pill in six variants and three appearances; the variant only ever
5
- * sets --bd-accent, so adding one is a single rule. Tokens read the shared
6
- * --gbs-* variables when they are set on an ancestor (set them on :root to
7
- * theme every component at once). Rules live in the `components` layer, so
8
- * utility classes passed through `className` / `classNames` override them.
4
+ * One tinted pill in six variants and three appearances; the variant only
5
+ * ever sets --bd-accent, so adding one is a single rule. Tokens read the
6
+ * shared --gbs-* variables when they are set on an ancestor (set them on
7
+ * :root to theme every component at once). Rules live in the `gbs` layer;
8
+ * declare where it sits in your global CSS, e.g. `@layer reset, gbs, app,
9
+ * utilities;`, and anything in a later layer overrides them.
9
10
  */
10
- @layer theme, base, components, utilities;
11
11
 
12
- @layer components {
12
+ @layer gbs {
13
13
  .bd-root,
14
14
  .bd-tag {
15
15
  --bd-fg: var(--gbs-fg, var(--dg-fg, light-dark(#18181b, #f4f4f5)));