opui-css 5.4.0 → 5.4.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.4.2 - 2026-06-29
4
+
5
+ ### Fixed
6
+
7
+ - Make overline in `Card` header smaller.
8
+
9
+ ## 5.4.1 - 2026-06-11
10
+
11
+ ### Fixed
12
+
13
+ - Fixed a `@vue/compiler-sfc` compilation crash in `Avatar`.
14
+
3
15
  ## 5.4.0 - 2026-06-09
4
16
 
5
17
  - Added global control for motion that lets you enable or disable all motion with a single class `.ui-motion-on`, `.ui-motion-off`, `.ui-motion-debug`. By default it will listen to `prefers-reduced-motion`. Locally each component individually has `--_motion` variable that can be changed as well.
@@ -106,7 +118,7 @@ Run a project-wide find/replace per token, prompt or whatever. Below are all the
106
118
 
107
119
  </details>
108
120
 
109
- After the search/replace, do a visual smoke test — there is no automated codemod for consumer projects.
121
+ After the search/replace, do a visual smoke test - there is no automated codemod for consumer projects.
110
122
 
111
123
  ## 4.1.0 - 2026-05-18
112
124
 
package/MIGRATING.md CHANGED
@@ -13,7 +13,7 @@ Note: Components that use `critical` for severity styling (such as `Button`, `Ca
13
13
 
14
14
  v5 prefixes every OPUI-owned class with `ui-`. The component prop API is unchanged; only the rendered class names change.
15
15
 
16
- If you use the framework component (e.g. `<Button size="small" variant="outlined">`), you don't need to do anything — the component emits the prefixed classes for you.
16
+ If you use the framework component (e.g. `<Button size="small" variant="outlined">`), you don't need to do anything - the component emits the prefixed classes for you.
17
17
 
18
18
  If you use raw HTML or write CSS that targets library classes, you must rename every reference:
19
19
 
@@ -37,7 +37,7 @@ v4 is a full re-platform.
37
37
 
38
38
  ## 1. `import "opui-css"` still works
39
39
 
40
- The default export still resolves to a complete, ready-to-use stylesheet — just under a different filename. No code change needed unless you want one.
40
+ The default export still resolves to a complete, ready-to-use stylesheet - just under a different filename. No code change needed unless you want one.
41
41
 
42
42
  ```diff
43
43
  - import "opui-css" // resolved to dist/theme-two/theme-two.css
@@ -79,7 +79,7 @@ If you were importing from `src/`:
79
79
 
80
80
  The component CSS now lives under `css/`. The pre-bundled output stays in `dist/`.
81
81
 
82
- ## 5. Pick a theme — there's only one
82
+ ## 5. Pick a theme - there's only one
83
83
 
84
84
  `theme-one` and `theme-two` are removed. The shipped theme lives in `css/theme.css`. To customise, override variables in a layer:
85
85
 
@@ -109,7 +109,7 @@ import { Button, Dialog, Tabs } from "opui-css/astro"
109
109
  <Button variant="primary">Save</Button>
110
110
  ```
111
111
 
112
- `astro` is an _optional_ peer — only required if you actually import from `opui-css/astro`. Pure-CSS consumers won't see a peer warning.
112
+ `astro` is an _optional_ peer - only required if you actually import from `opui-css/astro`. Pure-CSS consumers won't see a peer warning.
113
113
 
114
114
  Astro components emit prefixed `ui-` classes (see the v4 → v5 section at the top of this file). Raw HTML and CSS overrides must use those prefixed names.
115
115
 
@@ -125,7 +125,7 @@ Put your overrides in a later layer or unlayered. If your app already declared `
125
125
 
126
126
  ## 9. Copy/paste is still supported
127
127
 
128
- The source files under `components/` and `css/components/` are unminified and free to vendor in — the license is unchanged (MIT).
128
+ The source files under `components/` and `css/components/` are unminified and free to vendor in - the license is unchanged (MIT).
129
129
 
130
130
  ## 10. Pinning v3
131
131
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Open Props UI
2
2
 
3
- A CSS UI library exploring how next-gen HTML & CSS features can change the way we create components. Built on top of [Open Props](https://open-props.style/) and ships [Astro](https://astro.build/) components alongside framework-agnostic CSS.
3
+ A CSS UI library exploring how next-gen HTML & CSS features can change the way we create components. Built on top of [Open Props](https://open-props.style/) and ships HTML, [Astro](https://astro.build/) and [Vue](https://vuejs.org/) components alongside framework-agnostic CSS.
4
4
 
5
5
  - Docs: [open-props-ui.netlify.app](https://open-props-ui.netlify.app/)
6
6
  - Source: [github.com/felix-bohlin/ui](https://github.com/felix-bohlin/ui)
@@ -14,6 +14,7 @@ pnpm add opui-css open-props
14
14
  Peer dependencies:
15
15
 
16
16
  - `astro` `^6` (only required if you use the Astro components)
17
+ - `vue` `^3` (only required if you use the Vue components)
17
18
  - `open-props` `^1`
18
19
 
19
20
  ## Usage
@@ -69,9 +70,9 @@ Wrap your own styles in a layer above `utils` (or unlayered) to override.
69
70
  | ----------------------------------- | --------------------------------------------- |
70
71
  | `opui-css` | Pre-bundled: everything in one file (default) |
71
72
  | `opui-css/open-props` | Pre-bundled: Open Props tokens only |
72
- | `opui-css/dist/opui.css` | Same as default — explicit path |
73
+ | `opui-css/dist/opui.css` | Same as default - explicit path |
73
74
  | `opui-css/dist/opui.components.css` | Pre-bundled: components only |
74
- | `opui-css/dist/op.css` | Same as `opui-css/open-props` — explicit path |
75
+ | `opui-css/dist/op.css` | Same as `opui-css/open-props` - explicit path |
75
76
  | `opui-css/css/imports.css` | Source: everything (resolved by your bundler) |
76
77
  | `opui-css/css/components.css` | All component styles (no tokens / reset) |
77
78
  | `opui-css/css/components/*.css` | One component at a time |
@@ -22,9 +22,9 @@ When implementing or updating a component, ensure:
22
22
 
23
23
  Every component uses layered type files:
24
24
 
25
- - `types.ts` — shared, framework-agnostic props (component-specific only; no `HTMLAttributes`)
26
- - `types.astro.ts` — Astro props = base + `HTMLAttributes<element>`
27
- - `types.d.vue.ts` / `types.svelte.ts` / `types.solid.ts` — framework-specific extensions (for merge parity)
25
+ - `types.ts` - shared, framework-agnostic props (component-specific only; no `HTMLAttributes`)
26
+ - `types.astro.ts` - Astro props = base + `HTMLAttributes<element>`
27
+ - `types.d.vue.ts` / `types.svelte.ts` / `types.solid.ts` - framework-specific extensions (for merge parity)
28
28
 
29
29
  Every component must follow this exact frontmatter layout:
30
30
 
@@ -47,7 +47,7 @@ const {
47
47
 
48
48
  ### Key Rules:
49
49
  - **Alphabetical Sorting**: Sort property definitions in `types.ts` and variables in the destructuring statement.
50
- - **REST Support**: Use `HTMLAttributes` in `types.astro.ts` and `...rest` in destructuring. Do not add `[key: string]: any` to `types.ts` — native attributes belong in the framework type files.
50
+ - **REST Support**: Use `HTMLAttributes` in `types.astro.ts` and `...rest` in destructuring. Do not add `[key: string]: any` to `types.ts` - native attributes belong in the framework type files.
51
51
  - **Title Export**: This is mandatory for documentation generation.
52
52
 
53
53
  ---
@@ -1,10 +1,11 @@
1
- import type { HTMLAttributes, ImgHTMLAttributes, Slot } from "vue"
1
+ import type { Slot } from "vue"
2
2
  import type { Props as BaseProps } from "./types"
3
3
 
4
- export type Props = BaseProps &
5
- Pick<ImgHTMLAttributes, "alt" | "src"> & {
6
- class?: HTMLAttributes["class"]
7
- }
4
+ export type Props = BaseProps & {
5
+ alt?: string
6
+ src?: string
7
+ class?: string
8
+ }
8
9
 
9
10
  export type Slots = {
10
11
  default?: Slot
@@ -31,9 +31,10 @@ const positionArea =
31
31
  >
32
32
  <slot></slot>
33
33
  <template #anchored>
34
- <span class="ui-badge-indicator" :aria-label="label?.toString()">{{
35
- dot ? "" : label
36
- }}</span>
34
+ <span class="ui-badge-indicator" :aria-label="label?.toString()">
35
+ {{ dot ? "" : label }}
36
+ <slot v-if="!dot" name="indicator"></slot>
37
+ </span>
37
38
  </template>
38
39
  </Anchor>
39
40
  </template>
@@ -1,10 +1,10 @@
1
1
  import type { HTMLAttributes, Slot } from "vue"
2
- import type { Props as BaseProps } from "./types"
2
+ import type { Props as BaseProps, Slots as BaseSlots } from "./types"
3
3
 
4
4
  export type Props = BaseProps & {
5
5
  class?: HTMLAttributes["class"]
6
6
  }
7
7
 
8
- export type Slots = {
8
+ export type Slots = BaseSlots<Slot> & {
9
9
  default?: Slot
10
10
  }
@@ -6,3 +6,7 @@ export type Props = {
6
6
  invisible?: boolean
7
7
  label?: string | number
8
8
  }
9
+
10
+ export type Slots<S> = {
11
+ indicator?: S
12
+ }
package/core/utils.css CHANGED
@@ -1,7 +1,7 @@
1
1
  @layer utils {
2
+
2
3
  /*
3
4
  Screen-reader only
4
- When you visibly want to hide an element but make it accessible for screen readers.
5
5
  */
6
6
  .ui-sr-only {
7
7
  block-size: 1px;
@@ -58,8 +58,7 @@ Add `.ui-scroll-lock` to any element that uses the [open] attribute (native <dia
58
58
  inset-inline-start: 50%;
59
59
  position: absolute;
60
60
  transform-origin: center center;
61
- transform: translateX(calc(var(--isRTL) * 50%)) translateY(-50%)
62
- translateZ(-1px) scale(var(--thumb-scale));
61
+ transform: translateX(calc(var(--isRTL) * 50%)) translateY(-50%) translateZ(-1px) scale(var(--thumb-scale));
63
62
  will-change: transform;
64
63
 
65
64
  transition: transform calc(0.2s * var(--motion, 1)) ease;
@@ -68,7 +68,7 @@
68
68
  }
69
69
 
70
70
  /* Layout */
71
- & > summary {
71
+ &>summary {
72
72
  background-color: inherit;
73
73
  cursor: pointer;
74
74
  font-weight: 700;
@@ -93,17 +93,17 @@
93
93
  }
94
94
  }
95
95
 
96
- &[open] > summary svg {
96
+ &[open]>summary svg {
97
97
  rotate: 180deg;
98
98
  }
99
99
 
100
- & > .ui-content {
100
+ &>.ui-content {
101
101
  margin-block-start: 0;
102
102
  padding-block: var(--_content-padding-block);
103
103
  padding-inline: var(--_content-padding-inline);
104
104
  }
105
105
 
106
- & > .ui-actions {
106
+ &>.ui-actions {
107
107
  display: flex;
108
108
  gap: var(--_actions-gap);
109
109
  justify-content: end;
@@ -128,12 +128,12 @@
128
128
  }
129
129
  }
130
130
 
131
- & > .ui-content {
131
+ &>.ui-content {
132
132
  margin-block: 0;
133
133
  padding: 0;
134
134
  }
135
135
 
136
- & > details.ui-accordion {
136
+ &>details.ui-accordion {
137
137
  --_border-color: transparent;
138
138
  --_border-width: 0;
139
139
  --_margin-inline: 0;
@@ -142,7 +142,7 @@
142
142
  --_summary-padding-inline: var(--_item-summary-padding-inline);
143
143
 
144
144
  /* Border between accordion items */
145
- & + & {
145
+ &+& {
146
146
  border-block-start: 1px solid var(--_gutter-color);
147
147
  border-radius: 0;
148
148
  }
@@ -15,21 +15,21 @@
15
15
 
16
16
  /* Floating wrapper: traditional inset-based positioning so this works
17
17
  in browsers without position-area support (Firefox, older Safari). */
18
- & > .ui-anchor-floating:not([popover]) {
18
+ &>.ui-anchor-floating:not([popover]) {
19
19
  inset: var(--_badge-inset);
20
20
  position-anchor: auto;
21
21
  position-area: none;
22
22
  }
23
23
 
24
24
  /* Indicator */
25
- & > .ui-anchor-floating > .ui-badge-indicator {
25
+ &>.ui-anchor-floating>.ui-badge-indicator {
26
26
  background-color: var(--_bg-color);
27
27
  block-size: var(--_size);
28
28
  border: 2px solid var(--_border-color);
29
29
  border-radius: var(--radius-round);
30
30
  color: var(--_text-color);
31
31
  display: grid;
32
- font-size: 12px;
32
+ font-size: var(--font-size-0);
33
33
  font-weight: 500;
34
34
  inline-size: max-content;
35
35
  line-height: normal;
@@ -91,7 +91,7 @@
91
91
  --_anchor-ty: var(--_dot-size);
92
92
  }
93
93
 
94
- &.ui-dot > .ui-anchor-floating > .ui-badge-indicator {
94
+ &.ui-dot>.ui-anchor-floating>.ui-badge-indicator {
95
95
  block-size: var(--_dot-size);
96
96
  inline-size: var(--_dot-size);
97
97
  min-inline-size: var(--_dot-size);
@@ -99,7 +99,7 @@
99
99
  }
100
100
 
101
101
  /* Visibility */
102
- &.ui-invisible > .ui-anchor-floating > .ui-badge-indicator {
102
+ &.ui-invisible>.ui-anchor-floating>.ui-badge-indicator {
103
103
  opacity: 0;
104
104
  pointer-events: none;
105
105
  }
@@ -11,10 +11,8 @@
11
11
  border-radius: 0;
12
12
 
13
13
  /* button.css > --_accent-tonal */
14
- --_divider-color: light-dark(
15
- oklch(from var(--_accent-tonal) calc(l - 0.1) c h),
16
- oklch(from var(--_accent-tonal) calc(l + 0.1) c h)
17
- );
14
+ --_divider-color: light-dark(oklch(from var(--_accent-tonal) calc(l - 0.1) c h),
15
+ oklch(from var(--_accent-tonal) calc(l + 0.1) c h));
18
16
 
19
17
  &.ui-outlined {
20
18
  --_divider-color: var(--_border-color);
@@ -28,9 +26,7 @@
28
26
  outline-offset: -4px;
29
27
  }
30
28
 
31
- /* Color inheritance from Button Group — shared interaction model.
32
- The .critical scope class in theme.css redirects --palette-source so
33
- --color-6 below becomes a tint of the active color. */
29
+ /* Color inherited from Button Group. */
34
30
  :where(.ui-button-group.ui-critical, .ui-button-group.ui-primary) & {
35
31
  --_color-contrast: var(--gray-1);
36
32
  --_color-tonal: var(--color-6);
@@ -38,12 +34,8 @@
38
34
  --_default-hover-bg-color: oklch(from var(--_accent) l c h / 15%);
39
35
  --_default-active-bg-color: oklch(from var(--_accent) l c h / 25%);
40
36
  --_filled-hover-bg-color: oklch(from var(--_accent) calc(l - 0.1) c h);
41
- --_filled-active-bg-color: oklch(
42
- from var(--_accent) calc(l - 0.15) c h
43
- );
44
- --_outlined-active-bg-color: oklch(
45
- from var(--_accent) calc(l - 0.1) c h
46
- );
37
+ --_filled-active-bg-color: oklch(from var(--_accent) calc(l - 0.15) c h);
38
+ --_outlined-active-bg-color: oklch(from var(--_accent) calc(l - 0.1) c h);
47
39
  }
48
40
 
49
41
  :where(.ui-button-group.ui-critical) & {
@@ -107,10 +99,8 @@
107
99
  --_divider-color: currentColor;
108
100
 
109
101
  :where(.ui-button-group.ui-critical, .ui-button-group.ui-primary) & {
110
- --_divider-color: light-dark(
111
- oklch(from var(--_accent) calc(l - 0.1) c h),
112
- oklch(from var(--_accent) calc(l + 0.1) c h)
113
- );
102
+ --_divider-color: light-dark(oklch(from var(--_accent) calc(l - 0.1) c h),
103
+ oklch(from var(--_accent) calc(l + 0.1) c h));
114
104
  }
115
105
 
116
106
  &:where(:not([disabled])) {
@@ -138,17 +128,15 @@
138
128
  }
139
129
 
140
130
  /* Siblings */
141
- & + & {
131
+ &+& {
142
132
  border-inline-start-color: var(--_divider-color);
143
133
  border-inline-width: 1px;
144
134
  margin-inline-start: -1px;
145
135
 
146
136
  &[disabled] {
147
- border-inline-start-color: color-mix(
148
- in oklch,
149
- var(--_divider-color) 40%,
150
- transparent
151
- );
137
+ border-inline-start-color: color-mix(in oklch,
138
+ var(--_divider-color) 40%,
139
+ transparent);
152
140
  }
153
141
  }
154
142
  }
@@ -175,16 +163,14 @@
175
163
  border-end-end-radius: var(--_border-radius);
176
164
  }
177
165
 
178
- & + & {
166
+ &+& {
179
167
  border-block-start: 1px solid var(--_divider-color);
180
168
  margin-block-start: -1px;
181
169
 
182
170
  &[disabled] {
183
- border-block-start-color: color-mix(
184
- in oklch,
185
- var(--_divider-color) 40%,
186
- transparent
187
- );
171
+ border-block-start-color: color-mix(in oklch,
172
+ var(--_divider-color) 40%,
173
+ transparent);
188
174
  }
189
175
  }
190
176
  }
@@ -10,23 +10,15 @@
10
10
  --_accent-tonal: var(--_color-tonal);
11
11
  --_accent-tonal-contrast: var(--_color);
12
12
 
13
- --_default-hover-bg-color: light-dark(
14
- oklch(from var(--_accent) l 0.01 h / 10%),
15
- oklch(from var(--_accent) l 0.01 h / 20%)
16
- );
17
- --_default-active-bg-color: light-dark(
18
- oklch(from var(--_accent) l 0.06 h / 20%),
19
- oklch(from var(--_accent) l 0.06 h / 30%)
20
- );
21
-
22
- --_filled-hover-bg-color: light-dark(
23
- oklch(from var(--_accent) calc(l + 0.2) c h),
24
- oklch(from var(--_accent) calc(l - 0.1) c h)
25
- );
26
- --_filled-active-bg-color: light-dark(
27
- oklch(from var(--_accent) calc(l + 0.3) c h),
28
- oklch(from var(--_accent) calc(l - 0.15) c h)
29
- );
13
+ --_default-hover-bg-color: light-dark(oklch(from var(--_accent) l 0.01 h / 10%),
14
+ oklch(from var(--_accent) l 0.01 h / 20%));
15
+ --_default-active-bg-color: light-dark(oklch(from var(--_accent) l 0.06 h / 20%),
16
+ oklch(from var(--_accent) l 0.06 h / 30%));
17
+
18
+ --_filled-hover-bg-color: light-dark(oklch(from var(--_accent) calc(l + 0.2) c h),
19
+ oklch(from var(--_accent) calc(l - 0.1) c h));
20
+ --_filled-active-bg-color: light-dark(oklch(from var(--_accent) calc(l + 0.3) c h),
21
+ oklch(from var(--_accent) calc(l - 0.15) c h));
30
22
  --_outlined-active-bg-color: var(--_filled-active-bg-color);
31
23
 
32
24
  --_bg-color: transparent;
@@ -61,11 +53,6 @@
61
53
  box-shadow calc(0.1s * var(--_motion)) ease;
62
54
  user-select: none;
63
55
 
64
- /* Colors — shared interaction model for critical and primary.
65
- Each color modifier below only swaps --_color; the tonal surface,
66
- contrast text, and hover/active strategy are identical.
67
- The .critical scope class in theme.css redirects --palette-source so
68
- --color-6 below becomes a tint of the active color. */
69
56
  &.ui-critical,
70
57
  &.ui-primary {
71
58
  --_color-contrast: var(--gray-1);
@@ -91,11 +78,9 @@
91
78
 
92
79
  /* Disabled */
93
80
  &:where([disabled]) {
94
- --_text-color: color-mix(
95
- in oklch,
96
- var(--text-muted) 50%,
97
- var(--surface-default)
98
- );
81
+ --_text-color: color-mix(in oklch,
82
+ var(--text-muted) 50%,
83
+ var(--surface-default));
99
84
 
100
85
  cursor: not-allowed;
101
86
  opacity: 0.64;
@@ -133,8 +118,7 @@
133
118
  line-height: 1.2;
134
119
  }
135
120
 
136
- /* Sizes — heights aliased from the shared --control-size scale.
137
- Override --button-size-* in a parent scope to resize an entire region. */
121
+ /* Sizes */
138
122
  &.ui-x-small {
139
123
  --_min-height: var(--button-size-x-small);
140
124
  --_font-size: var(--font-size-0);
@@ -208,7 +192,7 @@
208
192
  }
209
193
  }
210
194
 
211
- /* file input */
195
+ /* File input */
212
196
  :where(input[type="file"]) {
213
197
  align-self: flex-start;
214
198
  border: var(--border-size-1) solid var(--surface-filled);
@@ -54,7 +54,7 @@
54
54
  --_card-border-width: 1px;
55
55
  }
56
56
 
57
- & > :where(hgroup, .ui-content) {
57
+ &> :where(hgroup, .ui-content) {
58
58
  padding-inline: var(--size-3);
59
59
 
60
60
  &:last-child {
@@ -63,11 +63,12 @@
63
63
  }
64
64
 
65
65
  /* Header */
66
- & > hgroup {
66
+ &>hgroup {
67
67
  padding-block: var(--size-3) 0;
68
68
 
69
69
  /* Top paragraph */
70
- & > p:first-of-type:first-child {
70
+ &>p:first-of-type:first-child {
71
+ font-size: var(--font-size-0);
71
72
  line-height: 1.3;
72
73
  }
73
74
 
@@ -76,18 +77,18 @@
76
77
  }
77
78
 
78
79
  /* Bottom paragraph */
79
- & > p:last-of-type:last-child:not(:first-child) {
80
+ &>p:last-of-type:last-child:not(:first-child) {
80
81
  font-size: var(--font-size-1);
81
82
  }
82
83
  }
83
84
 
84
85
  /* Content */
85
- & > .ui-content:where(:only-child, :first-child) {
86
+ &>.ui-content:where(:only-child, :first-child) {
86
87
  padding-block: var(--size-3) var(--size-4);
87
88
  }
88
89
 
89
90
  /* Actions */
90
- & > .ui-actions {
91
+ &>.ui-actions {
91
92
  display: flex;
92
93
  gap: var(--size-2);
93
94
  margin-block: var(--size-2) 0;
@@ -157,9 +157,7 @@
157
157
  }
158
158
  }
159
159
 
160
- /* Scroll-lock is provided by the shared `.ui-scroll-lock` utility in core/utils.css.
161
- This carve-out re-enables page scrolling when a transparent-backdrop drawer is
162
- open on wide viewports (where the drawer doesn't visually cover the page). */
160
+ /* Scroll-lock is provided by the shared `.ui-scroll-lock` utility in core/utils.css. */
163
161
  html:has(dialog.ui-drawer.ui-scroll-lock[open].ui-backdrop-transparent) {
164
162
  overflow: unset;
165
163
  overscroll-behavior: auto;
@@ -1,4 +1,5 @@
1
1
  @layer components.extended {
2
+
2
3
  /* Form */
3
4
  :where(.ui-form) {
4
5
  display: grid;
@@ -112,9 +113,7 @@
112
113
  gap: var(--size-4);
113
114
 
114
115
  /* If it only has checkboxes, radios, or switches */
115
- &:has(> :where(.ui-checkbox, .ui-radio, .ui-switch)):not(
116
- :has(> :not(.ui-checkbox, .ui-radio, .ui-switch))
117
- ) {
116
+ &:has(> :where(.ui-checkbox, .ui-radio, .ui-switch)):not( :has(> :not(.ui-checkbox, .ui-radio, .ui-switch))) {
118
117
  gap: var(--size-2);
119
118
  }
120
119
 
@@ -124,13 +123,13 @@
124
123
  flex-direction: row;
125
124
  gap: var(--size-2);
126
125
 
127
- /* If it's not preceeded by an hr */
126
+ /* If it's not preceded by an hr */
128
127
  &:not(hr + &) {
129
128
  margin-block-start: var(--size-4);
130
129
  }
131
130
  }
132
131
 
133
- & + & {
132
+ &+& {
134
133
  margin-block-start: var(--size-5);
135
134
  }
136
135
 
@@ -9,22 +9,14 @@
9
9
  --_accent-contrast: var(--_color-contrast);
10
10
  --_accent-tonal: var(--_color-tonal);
11
11
  --_accent-tonal-contrast: var(--_color);
12
- --_default-hover-bg-color: light-dark(
13
- oklch(from var(--_accent) l 0.01 h / 10%),
14
- oklch(from var(--_accent) l 0.01 h / 20%)
15
- );
16
- --_default-active-bg-color: light-dark(
17
- oklch(from var(--_accent) l 0.06 h / 20%),
18
- oklch(from var(--_accent) l 0.06 h / 30%)
19
- );
20
- --_filled-hover-bg-color: light-dark(
21
- oklch(from var(--_accent) calc(l + 0.2) c h),
22
- oklch(from var(--_accent) calc(l - 0.1) c h)
23
- );
24
- --_filled-active-bg-color: light-dark(
25
- oklch(from var(--_accent) calc(l + 0.3) c h),
26
- oklch(from var(--_accent) calc(l - 0.15) c h)
27
- );
12
+ --_default-hover-bg-color: light-dark(oklch(from var(--_accent) l 0.01 h / 10%),
13
+ oklch(from var(--_accent) l 0.01 h / 20%));
14
+ --_default-active-bg-color: light-dark(oklch(from var(--_accent) l 0.06 h / 20%),
15
+ oklch(from var(--_accent) l 0.06 h / 30%));
16
+ --_filled-hover-bg-color: light-dark(oklch(from var(--_accent) calc(l + 0.2) c h),
17
+ oklch(from var(--_accent) calc(l - 0.1) c h));
18
+ --_filled-active-bg-color: light-dark(oklch(from var(--_accent) calc(l + 0.3) c h),
19
+ oklch(from var(--_accent) calc(l - 0.15) c h));
28
20
  --_outlined-active-bg-color: var(--_filled-active-bg-color);
29
21
 
30
22
  --_bg-color: transparent;
@@ -73,11 +65,6 @@
73
65
  background-color calc(0.1s * var(--_motion)) ease;
74
66
  }
75
67
 
76
- /* Colors — shared interaction model for critical and primary.
77
- Each color modifier below only swaps --_color; the tonal surface,
78
- contrast text, and hover/active strategy are identical.
79
- The .critical scope class in theme.css redirects --palette-source so
80
- --color-6 below becomes a tint of the active color. */
81
68
  &.ui-critical,
82
69
  &.ui-primary {
83
70
  --_color-contrast: var(--gray-1);
@@ -105,20 +92,16 @@
105
92
  &:where(:not([disabled])) {
106
93
  &:where(:not(:active):hover) {
107
94
  &::before {
108
- background-color: var(
109
- --_interaction-hover-color,
110
- var(--_default-hover-bg-color)
111
- );
95
+ background-color: var(--_interaction-hover-color,
96
+ var(--_default-hover-bg-color));
112
97
  }
113
98
  }
114
99
 
115
100
  &:where(:hover:active),
116
101
  &[aria-current="page"] {
117
102
  &::before {
118
- background-color: var(
119
- --_interaction-active-color,
120
- var(--_default-active-bg-color)
121
- );
103
+ background-color: var(--_interaction-active-color,
104
+ var(--_default-active-bg-color));
122
105
  }
123
106
  }
124
107
  }