actual-css 0.12.0 → 0.13.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 (78) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +7 -8
  3. package/components.json +8 -2
  4. package/dist/actual.full.css +505 -233
  5. package/dist/actual.full.js +1 -1
  6. package/dist/actual.full.min.css +1 -1
  7. package/docs/design-notes/architecture.md +67 -0
  8. package/docs/design-notes/steps.md +45 -28
  9. package/docs/pages/components/avatar.md +17 -11
  10. package/docs/pages/components/breadcrumb.md +16 -2
  11. package/docs/pages/components/list.md +9 -13
  12. package/docs/pages/components/navbar.md +42 -22
  13. package/docs/pages/components/pagination.md +19 -0
  14. package/docs/pages/components/steps.md +24 -20
  15. package/docs/pages/enhancements/scrollspy.md +6 -6
  16. package/docs/pages/enhancements/tabs.md +74 -3
  17. package/docs/pages/forms/floating-field.md +21 -7
  18. package/docs/pages/forms/form-actions.md +3 -6
  19. package/docs/pages/forms/states-and-sizes.md +15 -15
  20. package/docs/pages/foundations/philosophy.md +97 -1
  21. package/docs/pages/foundations/tokens.md +40 -4
  22. package/docs/pages/guides/design-tools.md +1 -1
  23. package/docs/pages/guides/integrating-actual-css.md +74 -8
  24. package/docs/pages/guides/introduction.md +3 -2
  25. package/docs/pages/guides/modular-import.md +1 -1
  26. package/docs/pages/guides/progressive-enhancement.md +25 -7
  27. package/docs/pages/guides/upgrading.md +86 -9
  28. package/docs/pages/layout/center.md +2 -1
  29. package/docs/pages/layout/cluster.md +11 -4
  30. package/docs/pages/layout/grid.md +2 -0
  31. package/docs/pages/layout/sidebar-layout.md +3 -0
  32. package/docs/pages/layout/switcher.md +2 -0
  33. package/docs/pages/layout/topbar.md +6 -4
  34. package/docs/pages/patterns/icon-slot.md +17 -1
  35. package/docs/pages/utilities/flex.md +1 -1
  36. package/docs/pages/utilities/sizing-wrapping.md +51 -6
  37. package/package.json +5 -5
  38. package/src/cli/actual-css.js +1 -1
  39. package/src/css/components/alert.css +34 -34
  40. package/src/css/components/avatar.css +2 -18
  41. package/src/css/components/badge.css +0 -1
  42. package/src/css/components/breadcrumb.css +74 -8
  43. package/src/css/components/drawer.css +23 -42
  44. package/src/css/components/flyout.css +0 -1
  45. package/src/css/components/join.css +2 -2
  46. package/src/css/components/list.css +10 -10
  47. package/src/css/components/modal.css +17 -10
  48. package/src/css/components/navbar.css +10 -8
  49. package/src/css/components/pagination.css +5 -0
  50. package/src/css/components/scrollspy.css +1 -1
  51. package/src/css/components/steps.css +66 -12
  52. package/src/css/components/tab.css +134 -4
  53. package/src/css/core/focus.css +8 -6
  54. package/src/css/core/theme.css +6 -1
  55. package/src/css/core/tokens.css +4 -2
  56. package/src/css/forms/choice-card.css +1 -1
  57. package/src/css/forms/choice.css +1 -1
  58. package/src/css/forms/control.css +1 -1
  59. package/src/css/forms/floating-field.css +20 -18
  60. package/src/css/forms/form-actions.css +5 -8
  61. package/src/css/forms/native.css +2 -2
  62. package/src/css/forms/otp.css +4 -5
  63. package/src/css/forms/switch.css +1 -1
  64. package/src/css/forms/validation.css +23 -30
  65. package/src/css/layout/center.css +2 -0
  66. package/src/css/layout/cluster.css +14 -0
  67. package/src/css/layout/grid.css +7 -0
  68. package/src/css/layout/scroller.css +19 -3
  69. package/src/css/layout/sidebar-layout.css +3 -0
  70. package/src/css/layout/switcher.css +3 -0
  71. package/src/css/utilities/extra.css +3 -3
  72. package/src/js/full.js +4 -0
  73. package/src/js/inline-visible.js +54 -0
  74. package/src/js/parsed.js +21 -0
  75. package/src/js/tab.js +33 -7
  76. package/src/tooling/design-export.js +1 -1
  77. package/src/tooling/design-tokens.js +44 -33
  78. package/src/tooling/theme-contrast.js +32 -24
@@ -63,11 +63,30 @@ handle, and cleanup happens per element when an element leaves the DOM.
63
63
 
64
64
  ## The full runtime
65
65
 
66
- Loading `dist/actual.full.js` as a plain `<script>` (no `type="module"`, no
67
- bundler, no `import`) gets the full runtime. Static HTML that needs to trigger
68
- something from its own inline `<script>` dispatches the module's public event
69
- instead of calling into a global — `actual:status` for the status bar, for
70
- example:
66
+ Import `actual-css/js/full` to enable the full runtime:
67
+
68
+ ```js
69
+ import "actual-css/js/full";
70
+ ```
71
+
72
+ The same entrypoint exposes the public enhancement API from the same runtime
73
+ instance, for adopters that extend the runtime they already run:
74
+
75
+ ```js
76
+ import { applyEnhancement, enhance, registerEnhancement } from "actual-css/js/full";
77
+
78
+ registerEnhancement("autosubmit", (form) => {
79
+ // ...
80
+ });
81
+ ```
82
+
83
+ For anything beyond that extension API, keep using `actual-css/js/*`.
84
+
85
+ The same entrypoint produces the `dist/actual.full.js` standalone for a
86
+ classic `<script>`, where no global API is exposed. Static HTML that needs to
87
+ trigger something from its own inline `<script>` dispatches the module's
88
+ public event instead of calling into a global — `actual:status` for the
89
+ status bar, for example:
71
90
 
72
91
  ```html
73
92
  <script src="actual.full.js"></script>
@@ -110,8 +129,7 @@ needed.
110
129
  The JS is designed to run on its own, without Actual's stylesheet.
111
130
 
112
131
  - **`data-enhance` tokens** register named behaviors. The runtime discovers
113
- components through `data-enhance="tabs"`, `data-enhance="flyout"`,
114
- `data-enhance="range"`, `data-enhance="scrollspy"`, and
132
+ components through `data-enhance="tabs"`, `data-enhance="flyout"`, `data-enhance="range"`, `data-enhance="scrollspy"`, and
115
133
  `data-enhance="validation"` — no Actual presentation class needed.
116
134
  Self-describing attributes (`data-mask`, `data-tooltip`,
117
135
  `data-context-menu`) stay framework-neutral by construction.
@@ -1,12 +1,90 @@
1
- # Upgrading to 0.12
1
+ # Upgrading
2
2
 
3
3
  Each step below is a search for a removed class or hook and its replacement.
4
4
  The [changelog](https://github.com/lekoala/actual-css/blob/master/CHANGELOG.md)
5
- lists every change; this page keeps the ones that need an edit.
5
+ lists every change; this page keeps the ones that need an edit. Apply the
6
+ sections in order when skipping a release.
6
7
 
7
8
  **Related terms:** migration, breaking changes, update, version.
8
9
 
9
- ## Action rows
10
+ ## 0.12 to 0.13
11
+
12
+ ### Layout hooks stop at each layout
13
+
14
+ `--cluster-justify`, `--cluster-align` and `--cluster-wrap` are reset on every
15
+ `.cluster`, and `--grid-columns` and `--grid-min` on every `.grid`. A value set
16
+ on an ancestor, including an outer cluster or grid, no longer reaches the
17
+ layout inside it. Search application CSS and inline styles for these hooks on
18
+ anything but the layout itself, then set them on the row or grid, or select it:
19
+
20
+ ```css
21
+ .toolbar > .cluster {
22
+ --cluster-justify: space-between;
23
+ }
24
+ ```
25
+
26
+ `--gap` still inherits, so a density context keeps reaching every nested
27
+ layout.
28
+
29
+ ### Avatar stacks
30
+
31
+ `.avatar-stack` no longer takes its size from a child `.avatar.sm` or
32
+ `.avatar.lg`. Move the size class to the stack and drop it from its avatars:
33
+
34
+ ```html
35
+ <div class="avatar-stack sm" role="group" aria-label="Team members">
36
+ <div class="avatar" role="img" aria-label="John Doe">…</div>
37
+ </div>
38
+ ```
39
+
40
+ ### Focus outline
41
+
42
+ `--focus-outline` has no default value any more. Search application CSS for
43
+ `var(--focus-outline)` and write the generic line instead:
44
+
45
+ ```css
46
+ outline: var(--focus-ring-width) solid var(--focus-outline-color);
47
+ ```
48
+
49
+ Setting `--focus-outline` still replaces the generic line.
50
+
51
+ ### List rows
52
+
53
+ `.list-item` regions center on the row. For rows with long supporting text,
54
+ add `.items-start` to the row or to the `.list` to keep them top-aligned.
55
+
56
+ ### Step rows
57
+
58
+ `.steps-horizontal` budgets each step from its marker instead of `7rem`, so a
59
+ row fits narrower widths before it scrolls. To keep the previous budget on a
60
+ row, set `--step-min: 7rem` on it.
61
+
62
+ ### Current links and rows
63
+
64
+ `.nav-link` shows its current state only for `aria-current="page"` or
65
+ `aria-current="location"`, and `a.list-item` only for `aria-current="page"` or
66
+ `aria-current="true"`. Search markup for other values on these classes and
67
+ use the matching one.
68
+
69
+ ### Tabs
70
+
71
+ `data-enhance="tabs"` only wires an element that also carries
72
+ `role="tablist"`. Search markup for the token and add the role where it is
73
+ missing; the console names each list it skipped.
74
+
75
+ ### Rendering changes without an edit
76
+
77
+ - A horizontal `.tabs` strip never wraps: a strip that does not fit scrolls
78
+ horizontally, with no scrollbar and faded edges.
79
+ - `.breadcrumb` never wraps either: a trail that does not fit truncates its
80
+ labels with an ellipsis, ancestors first. Ancestor labels need an `<a>` or
81
+ `<span>`.
82
+ - The focus reserve of a scrolling dialog or drawer body no longer grows with
83
+ `--border-width`: 1px narrower under `prefers-contrast: more`.
84
+
85
+ ## 0.11 to 0.12
86
+
87
+ ### Action rows
10
88
 
11
89
  `.actions`, `.navbar-nav` and the layout of `.form-actions` are gone. A row of
12
90
  actions is a `.cluster`; a vertical list is `stack list-reset`. Replace
@@ -27,12 +105,11 @@ actions is a `.cluster`; a vertical list is `stack list-reset`. Replace
27
105
  `gap: var(--space-10)` on that row in application CSS.
28
106
  - `.form-actions` has no top margin and no `--form-actions-margin-block-start`:
29
107
  put `.stack` on the form. `--form-actions-justify` and `--form-actions-align`
30
- still apply. In a modular build, import `layout/cluster` before
31
- `forms/form-actions`.
108
+ still apply. In a modular build, also import `layout/cluster`.
32
109
  - `.justify-content-*` aligns only its own element and no longer reaches a
33
110
  nested `.cluster`. Put the utility on the row it should align.
34
111
 
35
- ## Dialogs
112
+ ### Dialogs
36
113
 
37
114
  - `.dialog-confirmation` is removed. Compose `.media` with `.dialog-icon`, then
38
115
  a `<footer class="bleed background-subtle cluster justify-content-space-between">`;
@@ -46,7 +123,7 @@ actions is a `.cluster`; a vertical list is `stack list-reset`. Replace
46
123
  `.dialog-confirmation` used 1.5rem. Set `--modal-pad: var(--space-50)` on
47
124
  the dialog to keep the roomier treatment.
48
125
 
49
- ## Cards
126
+ ### Cards
50
127
 
51
128
  The layout of a `.card` header or footer row is a zero-specificity default: any
52
129
  author rule that targets the slot replaces it, not only a `.media`, `.cluster`,
@@ -54,7 +131,7 @@ author rule that targets the slot replaces it, not only a `.media`, `.cluster`,
54
131
  element rules such as `header { … }` or `footer { … }`, which now win over the
55
132
  card's slot row.
56
133
 
57
- ## Themes and density
134
+ ### Themes and density
58
135
 
59
136
  - A theme sets `--control-pad-x-sm`, `--control-pad-x-md` and
60
137
  `--control-pad-x-lg` instead of `--control-pad-x`. Used as a nested island,
@@ -63,7 +140,7 @@ card's slot row.
63
140
  - `--font-width-dense` is removed, and `.compact` no longer condenses type: set
64
141
  `font-stretch` on the element that should render condensed.
65
142
 
66
- ## Rendering changes without an edit
143
+ ### Rendering changes without an edit
67
144
 
68
145
  These need no markup change; compare the affected screens.
69
146
 
@@ -15,7 +15,8 @@ Constrain readable content and center it in the viewport, with width and padding
15
15
  </main>
16
16
  ```
17
17
 
18
- Tune width and side padding with local variables.
18
+ Tune width and side padding with `--center-size` and `--center-pad`. Both
19
+ inherit: set them on `:root` for the site's content width, or on one region.
19
20
 
20
21
  ```css
21
22
  .docs-page {
@@ -61,11 +61,15 @@ separate `.split` or `.spread` primitive; this is the same relationship.
61
61
  </div>
62
62
  ```
63
63
 
64
+ Once the row wraps, `space-between` puts an item alone on its line at the
65
+ start. To keep the end item on the end edge when it wraps, add
66
+ `.margin-inline-start-auto` to it.
67
+
64
68
  To align a row to its top edge instead of centering it — useful when one item
65
- wraps to several lines — set `--cluster-align`.
69
+ wraps to several lines — set `--cluster-align` on the cluster itself.
66
70
 
67
71
  ```css
68
- .filters {
72
+ .cluster.filters {
69
73
  --cluster-align: start;
70
74
  --cluster-justify: space-between;
71
75
  }
@@ -74,8 +78,11 @@ wraps to several lines — set `--cluster-align`.
74
78
  The optional utility layer ships `.justify-content-start`, `.justify-content-center`,
75
79
  `.justify-content-end` and `.justify-content-space-between`. They set
76
80
  `justify-content` on that one row only; a nested `.cluster` keeps its own
77
- alignment. `--cluster-justify` is inherited, so setting it on a region reaches
78
- nested clusters too. See the utilities page.
81
+ alignment. The `--cluster-*` hooks behave the same way: each cluster resets
82
+ them, so a value applies to the cluster it is set on and never to a nested
83
+ one. To align nested rows, select them (`.toolbar > .cluster`). `--gap` keeps
84
+ inheriting, so a density context still reaches every nested cluster. See the
85
+ utilities page.
79
86
 
80
87
  ## Controls inside a wrapping cluster
81
88
 
@@ -172,3 +172,5 @@ stacked, prefer `.switcher`.
172
172
  - `--grid-min` tunes the minimum item width of the intrinsic `.grid` recipe.
173
173
  It does not apply to `.grid-N`.
174
174
  - `--grid-columns` replaces that recipe with an author-owned template.
175
+
176
+ Both stop at a nested `.grid`: set them on the grid itself.
@@ -47,3 +47,6 @@ When the layout stacks (narrow space), the aside stays on top.
47
47
 
48
48
  - `--sidebar-layout-size` sets the aside's preferred width.
49
49
  - `--sidebar-content-min` sets the main region's minimum viable width.
50
+
51
+ The regions read both, so they also reach the regions of a nested
52
+ `.sidebar-layout`; set them on the nested layout to give it its own sizes.
@@ -18,3 +18,5 @@ independently.
18
18
  ### Hooks
19
19
 
20
20
  - `--switcher-threshold` controls the space needed before all peers share a row.
21
+ The children read it, so it also reaches the children of a nested
22
+ switcher; set it on the nested switcher to give it its own threshold.
@@ -11,10 +11,12 @@ Use `.topbar` for the structural shell of an app-shell header: sticky positionin
11
11
  <button class="btn neutral ghost" type="button" aria-label="Open navigation">
12
12
  <i class="ti ti-menu-2" aria-hidden="true"></i>
13
13
  </button>
14
- <ol class="breadcrumb" aria-label="Breadcrumb">
15
- <li><a href="#">Overview</a></li>
16
- <li aria-current="page">Accounts</li>
17
- </ol>
14
+ <nav aria-label="Breadcrumb">
15
+ <ol class="breadcrumb">
16
+ <li><a href="#">Overview</a></li>
17
+ <li aria-current="page">Accounts</li>
18
+ </ol>
19
+ </nav>
18
20
  <div class="grow"></div>
19
21
  <span class="avatar sm"><abbr>LW</abbr></span>
20
22
  </header>
@@ -42,6 +42,22 @@ For a round disc, add the `.circle` utility — it supplies the `border-radius`:
42
42
  }
43
43
  ```
44
44
 
45
+ ## Webfont glyphs
46
+
47
+ An icon font draws nothing measurable until it loads, so a button or nav link
48
+ shifts when the glyph arrives. Reserve a `1em` square on the icon library's
49
+ class in application CSS; it follows the surrounding font size:
50
+
51
+ ```css
52
+ .ti {
53
+ display: inline-grid;
54
+ flex: none;
55
+ place-items: center;
56
+ inline-size: 1em;
57
+ block-size: 1em;
58
+ }
59
+ ```
60
+
45
61
  ## Reuse the existing icon slots
46
62
 
47
63
  Several components already embody this slot — reach for them before composing
@@ -55,7 +71,7 @@ your own:
55
71
  ```html demo
56
72
  <div class="media">
57
73
  <span class="avatar primary"><abbr>AM</abbr></span>
58
- <div class="stack">
74
+ <div class="stack gap-none">
59
75
  <strong>Ada Meridian</strong>
60
76
  <span class="muted">Senior designer.</span>
61
77
  </div>
@@ -80,7 +80,7 @@ These helpers work by setting a custom property that participating components re
80
80
  so they also apply inside a component's own grid anatomy rather than only on plain
81
81
  flex containers:
82
82
 
83
- - `.items-start` / `.items-center` / `.items-end` / `.items-baseline` set `--items-align`, read by `.alert` and `.card`.
83
+ - `.items-start` / `.items-center` / `.items-end` / `.items-baseline` set `--items-align`, read by `.alert`, `.card` and `.list-item`.
84
84
  - `.text-start` / `.text-center` / `.text-end` set `--text-align`, read by `.table` cells.
85
85
 
86
86
  `.justify-content-*` and `.flex-wrap` / `.flex-nowrap` (utilities/extra) set the property
@@ -66,11 +66,10 @@ Use `.truncate` on the flexible item that should ellipsize inside a constrained
66
66
 
67
67
  ## Scroller
68
68
 
69
- Use `.scroller` to apply optional framework scrollbar treatment to a scroll container. It styles the scrollbar only; pair it with `.overflow-auto` or a component that already creates overflow.
69
+ Use `.scroller` to apply optional framework overflow treatment to a scroll container: a quieter scrollbar. It does not create overflow; pair it with `.overflow-auto` or a component that already creates overflow.
70
70
 
71
- The utility is two standard declarations and nothing else — the engine keeps
72
- drawing the scrollbar, `.scroller` only hands it a density and a colour that
73
- follow the theme. There is no `::-webkit-scrollbar` chrome: rebuilding a thumb
71
+ The engine keeps drawing the scrollbar; `.scroller` only hands it a density
72
+ and a colour that follow the theme. There is no `::-webkit-scrollbar` chrome: rebuilding a thumb
74
73
  by hand means re-implementing the hover, the corner and the light/dark
75
74
  adaptation that `color-scheme` already provides, and the hand-built version
76
75
  never quite matches the native one anyway.
@@ -80,6 +79,9 @@ above the capability floor. An engine that knows neither ignores both
80
79
  declarations and draws its native scrollbar — the intended fallback, not a
81
80
  broken state.
82
81
 
82
+ `.scroller` does not apply to touch screens, where the native overlay scrollbar
83
+ stays: it hides at rest, where a styled bar would stay visible.
84
+
83
85
  `.scroller` is a layout primitive, so it comes with `actual.full.css` and with
84
86
  `actual-css/css/layout` like `.stack` or `.cluster`. A project importing module
85
87
  by module reaches it directly:
@@ -102,9 +104,13 @@ by module reaches it directly:
102
104
  .scroller {
103
105
  --scroller-track: transparent;
104
106
  --scroller-thumb: var(--border);
107
+ }
105
108
 
106
- scrollbar-color: var(--scroller-thumb) var(--scroller-track);
107
- scrollbar-width: thin;
109
+ @media not all and (pointer: coarse) {
110
+ .scroller {
111
+ scrollbar-color: var(--scroller-thumb) var(--scroller-track);
112
+ scrollbar-width: thin;
113
+ }
108
114
  }
109
115
  ```
110
116
 
@@ -120,6 +126,45 @@ Thickness is not a hook: `scrollbar-width` takes `thin` or `auto`, not a length.
120
126
  Hover is left to the engine — it varies by platform, and matching it by hand was
121
127
  the part of a custom scrollbar that never held up.
122
128
 
129
+ ### One-row strips
130
+
131
+ Components that never wrap scroll horizontally when they do not fit: `.tabs`,
132
+ `.steps-horizontal`, and `.table-wrap`. (`.breadcrumb` truncates its labels
133
+ instead; see [Breadcrumb](../components/breadcrumb.md). `.pagination` wraps.)
134
+ In supporting browsers, a strip that loads on a current link tab or step starts
135
+ scrolled to it; elsewhere it starts at its first item.
136
+
137
+ `.tabs` hides its scrollbar and fades its edges instead: selecting the clipped
138
+ tab scrolls it into view. The others leave the scrollbar to the engine, so an
139
+ OS-default horizontal scrollbar can sit under a short strip, and on touch
140
+ screens it overlays the strip and hides at rest, leaving a clipped item as the
141
+ cue that the strip continues. Put `.scroller` on the strip itself — the element
142
+ that scrolls — for a thin, theme-coloured bar under a mouse; touch keeps the
143
+ overlay. These strips have no edge fade (overflow shadow, scroll hint): the
144
+ clipped item and the scrollbar already say there is more. Keyboard focus stops
145
+ an item with its focus line inside the strip.
146
+
147
+ ```html
148
+ <ol class="steps steps-horizontal scroller">
149
+ ```
150
+
151
+ There is no class that hides the scrollbar: on a strip whose items do not
152
+ scroll it themselves, it is the only visible scroll control for a mouse without
153
+ a horizontal wheel. Apply `.scroller` to every such strip of a page, or to
154
+ none, so the bars stay consistent.
155
+
156
+ A strip keeps scrolling inside a flex or grid row, such as a label and link
157
+ tabs on one `.cluster`: a `<nav>` directly around `.tabs` shrinks with the row
158
+ (and around `.breadcrumb`, which then truncates). Any other wrapper needs
159
+ `min-inline-size: 0`, or the row pushes the whole page into scrolling.
160
+
161
+ ```html
162
+ <div class="cluster">
163
+ <span>Sections</span>
164
+ <nav aria-label="Account sections"><ul class="tabs">…</ul></nav>
165
+ </div>
166
+ ```
167
+
123
168
  ## CSS hooks
124
169
 
125
170
  - `--scroller-track` — scrollbar track color.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "actual-css",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Plain CSS component framework with semantic classes, universal variants, small tokens, theme hooks, and progressive enhancements.",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.4.2",
@@ -112,7 +112,8 @@
112
112
  "node": ">=18"
113
113
  },
114
114
  "scripts": {
115
- "lint": "biome check",
115
+ "hooks:install": "bun scripts/install-hooks.js",
116
+ "lint": "biome check --reporter concise",
116
117
  "lint:fix": "biome check --write",
117
118
  "build:docs": "bun run build:themes && bun scripts/build-docs.js",
118
119
  "watch:docs": "bun run build:themes && bun scripts/build-docs.js --watch",
@@ -139,7 +140,6 @@
139
140
  "check:catalog": "bun scripts/check-catalog.js",
140
141
  "check:links": "bun scripts/check-doc-links.js",
141
142
  "check:templates": "bun scripts/check-templates.js",
142
- "check:markup": "bun scripts/check-markup.js",
143
143
  "shot:crop": "bun scripts/shot-crop.js",
144
144
  "shot:forced": "bun scripts/forced-colors-shot.js",
145
145
  "shot:multi": "bun scripts/multi-shot.js",
@@ -152,11 +152,11 @@
152
152
  "release:notes": "bun scripts/release-notes.js",
153
153
  "test": "bun test",
154
154
  "test:changed": "bun test --changed=master",
155
- "build:all": "bun run lint && bun run build:dist && bun run build:js && bun run build:size && bun run format:docs && bun run build:docs && bun run check:docs && bun run check:doc-classes && bun run check:compat && bun run check:css-api && bun run check:color-space && bun run check:architecture && bun run check:enhance && bun run generate:reserved && bun run check:reserved && bun run generate:catalog && bun run check:catalog && bun run check:sync && bun run check:links && bun run check:templates && bun run check:markup && bun run test",
155
+ "build:all": "bun run lint && bun run build:dist && bun run build:js && bun run build:size && bun run format:docs && bun run build:docs && bun run check:docs && bun run check:doc-classes && bun run check:compat && bun run check:css-api && bun run check:color-space && bun run check:architecture && bun run check:enhance && bun run generate:reserved && bun run check:reserved && bun run generate:catalog && bun run check:catalog && bun run check:sync && bun run check:links && bun run check:templates && bun run test",
156
156
  "prepublishOnly": "bun run build:all"
157
157
  },
158
158
  "devDependencies": {
159
- "@biomejs/biome": "^2.5.12",
159
+ "@biomejs/biome": "^2.5.15",
160
160
  "happy-dom": "^20.14.0"
161
161
  },
162
162
  "dependencies": {
@@ -12,7 +12,7 @@ function usage() {
12
12
  "",
13
13
  " -o, --out FILE write the bundle to FILE / the export to DIR (required)",
14
14
  " --minify collapse comments and whitespace",
15
- " --theme FILE read this [data-theme] file instead of the default theme",
15
+ " --theme FILE read this theme file ([data-theme] or :root) over the default",
16
16
  " --name NAME the data-theme name, when the file declares several",
17
17
  " -h, --help show this message",
18
18
  " --version print the actual-css version",
@@ -107,10 +107,11 @@
107
107
  }
108
108
  }
109
109
 
110
- /* Decorative leading icon — use .alert-icon on the icon element. */
110
+ /* Decorative leading icon — use .alert-icon on the icon element. display and
111
+ vertical-align are the no-:has() layout (Degraded tier: the icon sits inline
112
+ before the text); the grid anatomy below replaces them. */
111
113
  .alert > .alert-icon {
112
114
  display: inline-block;
113
- flex: none;
114
115
  inline-size: var(--alert-icon-size);
115
116
  block-size: var(--alert-icon-size);
116
117
  font-size: var(--alert-icon-size);
@@ -142,45 +143,44 @@
142
143
 
143
144
  /* Grid anatomy — activated by a leading icon, a trailing dismiss button, or
144
145
  both. Icon and dismiss are pinned to the outer columns; anything else (the
145
- message content) flows into the remaining text column. */
146
- @supports selector(.alert:has(> *)) {
147
- .alert:has(> .alert-icon, > .close) {
148
- display: grid;
149
- grid-template-columns: minmax(0, 1fr);
150
- align-items: var(--items-align, start);
151
- column-gap: var(--space-30);
152
- }
153
-
154
- .alert:has(> .alert-icon) {
155
- grid-template-columns: auto minmax(0, 1fr);
156
- }
146
+ message content) flows into the remaining text column. Without :has(), the
147
+ grid rules drop together and the alert keeps ordinary block flow. */
148
+ .alert:has(> .alert-icon, > .close) {
149
+ display: grid;
150
+ /* No grid-template-columns: the icon and close branches below always set
151
+ it, since one of them is what matched. */
152
+ align-items: var(--items-align, start);
153
+ column-gap: var(--space-30);
154
+ }
157
155
 
158
- .alert:has(> .alert-icon) > .alert-icon {
159
- grid-column: 1;
160
- grid-row: 1 / -1;
161
- display: inline-grid;
162
- place-items: center;
163
- margin-block-start: 0.125em;
164
- }
156
+ .alert:has(> .alert-icon) {
157
+ grid-template-columns: auto minmax(0, 1fr);
158
+ }
165
159
 
166
- .alert:has(> .alert-icon) > :not(.alert-icon, .close) {
167
- grid-column: 2;
168
- }
160
+ .alert:has(> .alert-icon) > .alert-icon {
161
+ grid-column: 1;
162
+ grid-row: 1 / -1;
163
+ display: inline-grid;
164
+ place-items: center;
165
+ margin-block-start: 0.125em;
166
+ }
169
167
 
170
- .alert:has(> .close) {
171
- grid-template-columns: minmax(0, 1fr) auto;
172
- }
168
+ .alert:has(> .alert-icon) > :not(.alert-icon, .close) {
169
+ grid-column: 2;
170
+ }
173
171
 
174
- .alert:has(> .alert-icon):has(> .close) {
175
- grid-template-columns: auto minmax(0, 1fr) auto;
176
- }
172
+ .alert:has(> .close) {
173
+ grid-template-columns: minmax(0, 1fr) auto;
174
+ }
177
175
 
178
- .alert:has(> .close) > .close {
179
- grid-column: -2 / -1;
180
- grid-row: 1;
181
- }
176
+ .alert:has(> .alert-icon):has(> .close) {
177
+ grid-template-columns: auto minmax(0, 1fr) auto;
182
178
  }
183
179
 
180
+ .alert:has(> .close) > .close {
181
+ grid-column: -2 / -1;
182
+ grid-row: 1;
183
+ }
184
184
  /* Links */
185
185
  .alert :where(a:not(.btn)) {
186
186
  color: inherit;
@@ -11,13 +11,13 @@
11
11
  * --avatar-size
12
12
  * --avatar-radius
13
13
  * --avatar-font-size
14
+ * --avatar-bg
14
15
  * --avatar-stack-size
15
16
  * --avatar-stack-font-size
16
17
  * --avatar-stack-overlap
17
18
  * --avatar-stack-ring
18
19
  *
19
20
  * Internal:
20
- * --avatar-bg
21
21
  * --avatar-fg
22
22
  * --avatar-status-translate-x
23
23
  */
@@ -95,16 +95,13 @@
95
95
 
96
96
  .avatar > img,
97
97
  .avatar > picture > img {
98
+ display: block;
98
99
  inline-size: 100%;
99
100
  block-size: 100%;
100
101
  object-fit: cover;
101
102
  border-radius: inherit;
102
103
  }
103
104
 
104
- .avatar > picture > img {
105
- display: block;
106
- }
107
-
108
105
  button.avatar {
109
106
  appearance: none;
110
107
  cursor: pointer;
@@ -198,19 +195,6 @@ a.avatar[aria-disabled="true"] {
198
195
  --avatar-stack-font-size: var(--font-size-lg);
199
196
  }
200
197
 
201
- /* Infer the stack scale from its avatars. Progressive: without :has() the
202
- explicit .avatar-stack.sm/.lg classes and the default size still size the
203
- group, only the inference is lost. */
204
- .avatar-stack:has(> .avatar.sm) {
205
- --avatar-stack-size: 1.75rem;
206
- --avatar-stack-font-size: var(--font-size-xs);
207
- }
208
-
209
- .avatar-stack:has(> .avatar.lg) {
210
- --avatar-stack-size: 3rem;
211
- --avatar-stack-font-size: var(--font-size-lg);
212
- }
213
-
214
198
  /* Overlapping avatars hide their neighbour: a translucent fill (--surface-subtle
215
199
  on a glass palette) would show the next avatar's edge through it, most of all
216
200
  when hover raises one above the other. The fill is layered over the opaque
@@ -137,7 +137,6 @@
137
137
  --badge-size: var(--badge-dot-size);
138
138
  --badge-bg: var(--intent, var(--neutral));
139
139
  --badge-fg: var(--intent-fg, var(--neutral-fg));
140
- --badge-border: transparent;
141
140
  padding: 0;
142
141
  border: 0;
143
142
  inline-size: var(--badge-size);