@codenhub/styles 0.1.0 → 0.2.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 (51) hide show
  1. package/README.md +8 -69
  2. package/dist/aesthetics/chunky-tile.css +1 -1
  3. package/dist/aesthetics/index.css +1 -1
  4. package/dist/components.css +1 -1
  5. package/dist/index.css +1 -1
  6. package/dist/native.css +1 -1
  7. package/dist/theme.css +1 -1
  8. package/dist/tw/aesthetics/chunky-tile.css +20 -2
  9. package/dist/tw/box.css +45 -2
  10. package/dist/tw/components/button.css +38 -29
  11. package/dist/tw/components/feedback.css +58 -41
  12. package/dist/tw/components/form.css +139 -47
  13. package/dist/tw/components/index.css +16 -6
  14. package/dist/tw/components/loader.css +2 -16
  15. package/dist/tw/components/surface.css +122 -5
  16. package/dist/tw/components/tooltip.css +102 -91
  17. package/dist/tw/elevation.css +57 -14
  18. package/dist/tw/index.css +23 -5
  19. package/dist/tw/intent.css +36 -12
  20. package/dist/tw/native.css +4 -20
  21. package/dist/tw/reset.css +40 -32
  22. package/dist/tw/theme.css +46 -8
  23. package/dist/tw/utilities/content.css +104 -18
  24. package/dist/tw/utilities/index.css +1 -1
  25. package/dist/tw/utilities/layout.css +33 -0
  26. package/docs/accessibility.md +68 -48
  27. package/docs/changelog/0.1.0.md +37 -0
  28. package/docs/changelog/0.1.1.md +10 -0
  29. package/docs/changelog/0.2.0.md +41 -0
  30. package/docs/changelog/index.md +11 -0
  31. package/docs/concepts.md +21 -46
  32. package/docs/index.md +18 -45
  33. package/docs/integrating/astro.md +13 -7
  34. package/docs/integrating/index.md +25 -16
  35. package/docs/integrating/nextjs.md +31 -8
  36. package/docs/integrating/svelte.md +14 -8
  37. package/docs/integrating/tailwind.md +31 -15
  38. package/docs/integrating/vue.md +13 -7
  39. package/docs/setup.md +31 -32
  40. package/docs/usage/aesthetics.md +31 -107
  41. package/docs/usage/buttons.md +24 -36
  42. package/docs/usage/composing.md +31 -102
  43. package/docs/usage/content-and-layout.md +65 -83
  44. package/docs/usage/customizing.md +25 -90
  45. package/docs/usage/feedback.md +25 -56
  46. package/docs/usage/forms.md +48 -80
  47. package/docs/usage/index.md +9 -17
  48. package/docs/usage/theming.md +25 -81
  49. package/docs/usage/tooltips.md +55 -35
  50. package/llms-full.txt +1193 -1510
  51. package/package.json +121 -44
@@ -1,32 +1,26 @@
1
1
  ---
2
2
  title: Content and layout
3
3
  description: Layout helpers, content chips and tables, surfaces, and typography utilities.
4
+ order: 9
4
5
  ---
5
6
 
6
7
  # Content and layout
7
8
 
8
9
  ## Layout
9
10
 
10
- Layout helpers use the shared `--layout-gap` token. `.tight` sets it to
11
- `0.5rem` and `.loose` sets it to `1.5rem` within a view, stack, cluster, or
12
- auto-grid.
11
+ Layout helpers use the shared `--layout-gap` token. `.tight` sets it to `0.5rem` and `.loose` sets it to `1.5rem` within a view, stack, cluster, or auto-grid.
13
12
 
14
- - `.view` is a flex container; `.vertical` and `.horizontal` set its
15
- direction, and horizontal views wrap with centered cross-axis alignment.
13
+ - `.view` is a flex container; `.vertical` and `.horizontal` set its direction, and horizontal views wrap with centered cross-axis alignment.
16
14
  - `.stack` is a vertical flex stack.
17
- - `.cluster` is a wrapping horizontal flex row; `.between` adds
18
- `space-between` alignment.
15
+ - `.cluster` is a wrapping horizontal flex row; `.between` adds `space-between` alignment.
19
16
  - `.auto-grid` is a responsive auto-fit grid using `--layout-grid-min`.
20
- - `.tight` and `.loose` set the shared gap to `0.5rem` or `1.5rem` on views,
21
- stacks, clusters, and auto-grids.
17
+ - `.tight` and `.loose` set the shared gap to `0.5rem` or `1.5rem` on views, stacks, clusters, and auto-grids.
22
18
  - `.section` adds responsive block padding and an inline gutter.
23
- - `.section-content` centers content at `--container-max`; `.narrow` and
24
- `.wide` select the corresponding container tokens.
25
- - `.divider` is horizontal; `.vertical` makes it self-stretch vertically. It
26
- takes intent, but presentation classes do not affect it.
19
+ - `.section-content` centers content at `--container-max`; `.narrow` and `.wide` select the corresponding container tokens.
20
+ - `.divider` is horizontal; `.vertical` makes it self-stretch vertically. It takes intent, but presentation classes do not affect it.
21
+ - `.visually-hidden` hides content visually while keeping it in the accessibility tree, using the standard clip-based recipe. Not named `.sr-only`: on a `/tw` entry the consumer's own Tailwind build already ships a real `.sr-only`, and a same-named utility of this package's own would silently collide with it in the cascade — the same reason `.data-table` is not named `.table`.
27
22
 
28
- The removed `--layout-stack-gap` and `--layout-cluster-gap` tokens have no
29
- compatibility aliases.
23
+ The removed `--layout-stack-gap` and `--layout-cluster-gap` tokens have no compatibility aliases.
30
24
 
31
25
  ## Content
32
26
 
@@ -44,8 +38,7 @@ compatibility aliases.
44
38
 
45
39
  ### Table rules
46
40
 
47
- A table draws three kinds of line, and `.ruled` and `.ruleless` move all of
48
- them together:
41
+ A table draws three kinds of line, and `.ruled` and `.ruleless` move all of them together:
49
42
 
50
43
  | Class | Head and foot boundaries | Rules between body rows |
51
44
  | ----------- | ------------------------ | ----------------------- |
@@ -54,36 +47,32 @@ them together:
54
47
  | `.ruled` | Yes | Yes |
55
48
 
56
49
  ```html
57
- <table class="data-table">Head and foot boundaries only</table>
58
- <table class="data-table ruled">Every row separated</table>
59
- <table class="data-table ruleless">No lines inside the table at all</table>
50
+ <table class="data-table">
51
+ Head and foot boundaries only
52
+ </table>
53
+ <table class="data-table ruled">
54
+ Every row separated
55
+ </table>
56
+ <table class="data-table ruleless">
57
+ No lines inside the table at all
58
+ </table>
60
59
  ```
61
60
 
62
- The boundaries under a head and above a foot separate the parts of a table
63
- from each other, so they are drawn by default where the row rules are not.
64
- Rules between body rows used to arrive on their own, because the
65
- component's published edge default is `edged` and the edge axis wrote the
66
- rules along with the boundary — so whether you got them depended on a
67
- registry default rather than on anything in your markup.
61
+ The boundaries under a head and above a foot separate the parts of a table from each other, so they are drawn by default where the row rules are not. Rules between body rows used to arrive on their own, because the component's published edge default is `edged` and the edge axis wrote the rules along with the boundary — so whether you got them depended on a registry default rather than on anything in your markup.
68
62
 
69
- `--ui-rule` is the token behind both classes, so a container can set the
70
- answer for a whole region without classing each table:
63
+ `--ui-rule` is the token behind both classes, so a container can set the answer for a whole region without classing each table:
71
64
 
72
65
  ```html
73
66
  <section style="--ui-rule: 100%">
74
- <table class="data-table">Ruled by the region</table>
67
+ <table class="data-table">
68
+ Ruled by the region
69
+ </table>
75
70
  </section>
76
71
  ```
77
72
 
78
- The frame around the table is the edge axis and is asked for the same way:
79
- `.data-table` publishes `edgeless`, so `.edged` draws one. None of the
80
- three switches reaches the others — `.data-table.ruleless.edged` is a
81
- framed table with no lines inside it, and `.data-table.ruled` is a
82
- frameless one with every row separated.
73
+ The frame around the table is the edge axis and is asked for the same way: `.data-table` publishes `edgeless`, so `.edged` draws one. None of the three switches reaches the others — `.data-table.ruleless.edged` is a framed table with no lines inside it, and `.data-table.ruled` is a frameless one with every row separated.
83
74
 
84
- A table's rows deliberately inherit its intent instead of resetting it, so
85
- `.data-table.success` tints throughout. A row carrying its own intent still
86
- wins:
75
+ A table's rows deliberately inherit its intent instead of resetting it, so `.data-table.success` tints throughout. A row carrying its own intent still wins:
87
76
 
88
77
  ```html
89
78
  <table class="data-table success">
@@ -98,37 +87,30 @@ wins:
98
87
  </table>
99
88
  ```
100
89
 
101
- This is the one place intent cascades, because a table's rows are parts of
102
- the table rather than independent components.
90
+ This is the one place intent cascades, because a table's rows are parts of the table rather than independent components.
103
91
 
104
- `.data-table`, `.kbd`, `.code`, and `.pre` also read
105
- [presentation](./composing.md#presentation). A table applies it to its
106
- header, its rules and its border; a chip to its whole plate:
92
+ `.data-table`, `.kbd`, `.code`, and `.pre` also read [presentation](./composing.md#presentation). A table applies it to its header, its rules and its border; a chip to its whole plate:
107
93
 
108
94
  ```html
109
- <table class="data-table success soft edged">...</table>
110
- <table class="data-table">A ghost table: rules and type, no header plate</table>
95
+ <table class="data-table success soft edged">
96
+ ...
97
+ </table>
98
+ <table class="data-table">
99
+ A ghost table: rules and type, no header plate
100
+ </table>
111
101
  <kbd class="kbd primary solid">Ctrl</kbd>
112
102
  <kbd class="kbd primary soft edged">Shift</kbd>
113
103
  ```
114
104
 
115
- `.ghost` means two different things on these components, and both are worth
116
- knowing before you reach for it.
105
+ `.ghost` means two different things on these components, and both are worth knowing before you reach for it.
117
106
 
118
- On `.data-table` it removes the header plate along with the body tint, so
119
- `.data-table.ghost` is boundaries and type alone. The component rests at
120
- `soft`, so that is something to ask for rather than the default.
107
+ On `.data-table` it removes the header plate along with the body tint, so `.data-table.ghost` is boundaries and type alone. The component rests at `soft`, so that is something to ask for rather than the default.
121
108
 
122
- On `.kbd`, `.code`, and `.pre` it is **not supported**. All three rest on
123
- `--intent-subtle`, and that ground draws the plate whatever the fill says —
124
- so `.ghost` took the fill away and changed nothing visible. Worse, the
125
- ground alone is a near-page tint: a ghost chip measured the same `#e5e5e5`
126
- for neutral and primary on the light page, and `#f5f5f5` at 1.04:1 against
127
- it for secondary. All three rest at `.soft` instead, which puts a real `12%`
128
- of the intent over the ground and separates them.
109
+ `.soft` rests untinted throughout -- `--color-foreground`, no intent color mixed in, for every intent, including the resting default, on the head plate and the table's own base fill alike. A table has no hover or interaction state to reveal a tint into the way `.card.soft` does on `.interactive`/`.hoverable`, so unlike a card there is no state where a `.data-table.success.soft` reveals green; only the boundary and rule lines still read the intent.
129
110
 
130
- Use `.table-wrap` around `.data-table` when table width may exceed its
131
- container:
111
+ On `.kbd`, `.code`, and `.pre` it is **not supported**. All three rest on `--intent-subtle`, and that ground draws the plate whatever the fill says — so `.ghost` took the fill away and changed nothing visible. Worse, the ground alone is a near-page tint: a ghost chip measured the same `#e5e5e5` for neutral and primary on the light page, and `#f5f5f5` at 1.04:1 against it for secondary. A named intent rests at `.soft` instead, which puts a real `12%` of the intent over the ground and separates it from the others; the no-named-intent case reads no differently from `.ghost` either way, so it rests at the ground alone rather than adding an unmotivated wash of its own.
112
+
113
+ Use `.table-wrap` around `.data-table` when table width may exceed its container:
132
114
 
133
115
  ```html
134
116
  <div class="table-wrap">
@@ -151,38 +133,38 @@ container:
151
133
 
152
134
  ## Surfaces
153
135
 
154
- | Class | Purpose |
155
- | -------------------- | ---------------------------------------------------------------------------- |
156
- | `.card` | Bordered container, surface radius, padded. Rests at elevation `1`. |
157
- | `.panel` | Flush container for sidebars, toolbars, and wells. No elevation. |
158
- | `.interactive` | On `.card`. Adds pointer cursor, hover and press response, and a focus ring. |
159
- | `.p-sm`, `.compact` | On `.card` or `.panel`. Reduces padding. |
160
- | `.p-lg`, `.spacious` | On `.card` or `.panel`. Increases padding. |
161
- | `.flush` | On `.card` or `.panel`. Removes padding, for edge-to-edge content. |
162
-
163
- Both read intent, [presentation](./composing.md#presentation), and
164
- [material tokens](./customizing.md#material-tokens). A plain `.card` is a
165
- neutral bordered container; only an explicit presentation tints it. Resting
166
- at elevation `1` is not a visible shadow by itself — nothing draws depth
167
- until an [aesthetic](./aesthetics.md) supplies shadow geometry or
168
- `.elevation-sm`/`.elevation-md` asks for it; see
169
- [Composing → Elevation](./composing.md#elevation).
170
-
171
- On the base look, `.card.interactive` scales down slightly on press
172
- (`--ui-active-transform`, `scale(0.97)`); an [aesthetic](./aesthetics.md)
173
- substitutes its own press gesture, and `prefers-reduced-motion` turns it off.
136
+ | Class | Purpose |
137
+ | -------------------- | ------------------------------------------------------------------------------------- |
138
+ | `.card` | Bordered container, surface radius, padded. Rests at elevation `1`. |
139
+ | `.panel` | Flush container for sidebars, toolbars, and wells. No elevation. |
140
+ | `.interactive` | On `.card`. Adds pointer cursor, hover and press response, and a focus ring. |
141
+ | `.hoverable` | On `.card`. The hover half of `.interactive`: hover response only, no pointer cursor. |
142
+ | `.pressable` | On `.card`. The press half of `.interactive`: press response and pointer cursor. |
143
+ | `.p-xs`, `.dense` | On `.card` or `.panel`. Reduces padding further than `.compact`. |
144
+ | `.p-sm`, `.compact` | On `.card` or `.panel`. Reduces padding. |
145
+ | `.p-lg`, `.spacious` | On `.card` or `.panel`. Increases padding. |
146
+ | `.flush` | On `.card` or `.panel`. Removes padding, for edge-to-edge content. |
147
+
148
+ Both read intent, [presentation](./composing.md#presentation), and [material tokens](./customizing.md#material-tokens). A plain `.card` is a neutral bordered container; only an explicit presentation tints it. Resting at elevation `1` is not a visible shadow by itself — nothing draws depth until an [aesthetic](./aesthetics.md) supplies shadow geometry or `.elevation-sm`/`.elevation-md` asks for it; see [Composing → Elevation](./composing.md#elevation).
149
+
150
+ `.card.soft` with no named intent is untinted at rest — a plain `--color-foreground` plate, no ink mixed in, marking a different container without drawing attention to it. The intent tint and a `--color-surface` ground only appear together, on `:hover`, and only on `.card.interactive`/`.card.hoverable`: a plain `.card.soft` with neither has no hover state to reveal into and stays at the quiet rest. A named intent (`.card.soft.success`, `.card.soft.destructive`, and so on) keeps its ordinary tint at rest instead, and deepens further on hover the same way any other filled surface does — only the no-intent case is untinted, since removing an intent's own color would silence it rather than quiet it. `.solid` and `.ghost` are unaffected either way.
151
+
152
+ `.panel` with no named intent behaves the same way, permanently rather than on hover: a plain `.panel` rests at the same untinted `--color-foreground` plate a neutral `.card.soft` does, because a panel has no hover state to reveal a tint into. `.panel.primary`, `.panel.destructive`, and every other named intent keep their ordinary tint. `.kbd`, `.code`, and `.pre` follow the same no-named-intent rule for their own fill, without moving off their `--intent-subtle` ground.
153
+
154
+ On the base look, `.card.interactive` scales down slightly on press (`--ui-active-transform`, `scale(0.97)`); an [aesthetic](./aesthetics.md) substitutes its own press gesture, and `prefers-reduced-motion` turns it off.
155
+
156
+ `.interactive` is the pair `.hoverable` (hover response only, no pointer cursor) and `.pressable` (press response and pointer cursor) applied together. Take one half for a card that answers a single gesture: a card that warms on hover but holds its own action in a nested button takes `.hoverable`, so pressing that button does not dip the whole card.
174
157
 
175
158
  ```html
176
159
  <article class="card">Neutral card</article>
177
- <article class="card success soft">Tinted success card</article>
160
+ <article class="card success solid">Filled success card</article>
178
161
  <article class="card primary ghost edged">Intent border, no fill</article>
179
- <a class="card interactive" href="/package">Responds to hover and press</a>
162
+ <a class="card success soft interactive" href="/package">Success-tinted at rest; deepens on hover</a>
163
+ <article class="card hoverable">Warms on hover; the action is a nested button</article>
180
164
  <aside class="panel">Flush panel</aside>
181
165
  ```
182
166
 
183
- `.interactive` is styling only. Use a real interactive element and give it
184
- an accessible name; a `<div class="card interactive">` is not focusable or
185
- operable by keyboard.
167
+ `.interactive` and `.pressable` are styling only. Use a real interactive element and give it an accessible name; a `<div class="card interactive">` is not focusable or operable by keyboard.
186
168
 
187
169
  ## Typography utilities
188
170
 
@@ -1,20 +1,16 @@
1
1
  ---
2
2
  title: Customizing
3
3
  description: Presentation and material token reference, and aesthetic knobs.
4
+ order: 3
4
5
  ---
5
6
 
6
7
  # Customizing
7
8
 
8
- Presentation tokens decide how much of an intent shows. Material tokens
9
- decide what a component is made of. Aesthetic tokens are the small set of
10
- named knobs a shipped aesthetic exposes to scale its own look.
9
+ Presentation tokens decide how much of an intent shows. Material tokens decide what a component is made of. Aesthetic tokens are the small set of named knobs a shipped aesthetic exposes to scale its own look.
11
10
 
12
11
  ## Presentation tokens
13
12
 
14
- Presentation tokens describe _how much_ of an intent a component shows,
15
- never _which_ intent it shows. They are unitless numbers and percentages, so
16
- they carry no color and inherit safely: a container sets them once and every
17
- component below resolves them against its own intent.
13
+ Presentation tokens describe _how much_ of an intent a component shows, never _which_ intent it shows. They are unitless numbers and percentages, so they carry no color and inherit safely: a container sets them once and every component below resolves them against its own intent.
18
14
 
19
15
  | Token | Purpose |
20
16
  | ----------------- | -------------------------------------------------------------------------- |
@@ -22,45 +18,25 @@ component below resolves them against its own intent.
22
18
  | `--ui-fg-on-fill` | Percentage blended from the intent readable tone toward its contrast tone. |
23
19
  | `--ui-border` | Percentage of the intent color mixed into the border color. |
24
20
 
25
- A component resolves them with `color-mix` from its published default. Hover
26
- is derived by adding `--hover-step` to the resting fill and using
27
- `--intent-hover`; there are no per-presentation hover tokens.
21
+ A component resolves them with `color-mix` from its published default. Hover is derived by adding `--hover-step` to the resting fill and using `--intent-hover`; there are no per-presentation hover tokens.
28
22
 
29
- No fill class writes `--ui-border` and no edge class writes `--ui-fill`. A
30
- filled box with no line is `.solid.edgeless`, which is worth reaching for on
31
- a neutral component: neutral caps its fill, so the box stays translucent and
32
- a border over it paints a second coat of the same tint instead of blending
33
- into it.
23
+ No fill class writes `--ui-border` and no edge class writes `--ui-fill`. A filled box with no line is `.solid.edgeless`, which is worth reaching for on a neutral component: neutral caps its fill, so the box stays translucent and a border over it paints a second coat of the same tint instead of blending into it.
34
24
 
35
25
  ```css
36
26
  background: color-mix(in oklab, var(--color-primary) var(--ui-fill, 100%), transparent);
37
27
  ```
38
28
 
39
- Two choices there are deliberate. Mixing toward `transparent` rather than a
40
- background token lets a tinted surface adapt to whatever it is placed on.
41
- Mixing in `oklab` keeps the wide-gamut token palette intact and blends
42
- perceptually, where `srgb` would clip it.
29
+ Two choices there are deliberate. Mixing toward `transparent` rather than a background token lets a tinted surface adapt to whatever it is placed on. Mixing in `oklab` keeps the wide-gamut token palette intact and blends perceptually, where `srgb` would clip it.
43
30
 
44
- A computed color therefore reaches the page as a resolved `color-mix` result
45
- rather than the token's own `oklch` syntax. It is the same color; code that
46
- compares computed color strings should compare colors instead.
31
+ A computed color therefore reaches the page as a resolved `color-mix` result rather than the token's own `oklch` syntax. It is the same color; code that compares computed color strings should compare colors instead.
47
32
 
48
- > **Presentation token contract**: only presentation classes and consumer
49
- > overrides set these tokens; components only read them. Setting a value
50
- > that no presentation class produces is supported but unvalidated. See
51
- > [Composing](./composing.md) for the classes that ship these values.
33
+ > **Presentation token contract**: only presentation classes and consumer overrides set these tokens; components only read them. Setting a value that no presentation class produces is supported but unvalidated. See [Composing](./composing.md) for the classes that ship these values.
52
34
 
53
35
  ## Material tokens
54
36
 
55
- Material tokens describe what a component is _made of_ rather than which
56
- intent it shows or how strongly. They control shape, borders, shadows,
57
- translucency, filters, and transforms.
37
+ Material tokens describe what a component is _made of_ rather than which intent it shows or how strongly. They control shape, borders, shadows, translucency, filters, and transforms.
58
38
 
59
- Components read each with a fallback, so leaving them unset produces the
60
- default look. Setting them on a container restyles the whole subtree. Only
61
- shadow geometry is split into colorless parts that inherit safely;
62
- color-capable inputs such as `--ui-ink` and `--ui-surface-shadow` may
63
- include their own colors.
39
+ Components read each with a fallback, so leaving them unset produces the default look. Setting them on a container restyles the whole subtree. Only shadow geometry is split into colorless parts that inherit safely; color-capable inputs such as `--ui-ink` and `--ui-surface-shadow` may include their own colors.
64
40
 
65
41
  | Token | Purpose | Fallback |
66
42
  | ----------------------- | ------------------------------------------------------------------------------------------------------------- | -------------------- |
@@ -99,29 +75,15 @@ include their own colors.
99
75
  </section>
100
76
  ```
101
77
 
102
- > **Material token contract**: components read these; aesthetic classes and
103
- > consumer overrides set them.
78
+ > **Material token contract**: components read these; aesthetic classes and consumer overrides set them.
104
79
 
105
80
  ### Shape and ring composition
106
81
 
107
- Clipping removes borders, outlines, and outer shadows. An aesthetic that uses
108
- a clip can replace the border with an inset shadow by setting
109
- `--ui-shadow-inset` and the four shadow geometry parts. Set
110
- `--ui-border-max: 0px` when that ring replaces the component border.
111
- Focusable components restore the clipped focus outline through
112
- `--ui-focus-inset`.
113
-
114
- Declare `--ui-shadow-edge` when that ring _is_ the border. The ring then
115
- takes the element's edge color, which carries the edge axis as its alpha, so
116
- `.edged` draws it and `.edgeless` does not — the same answer a real border
117
- gives. Without it the ring paints on every component the aesthetic reaches
118
- and the edge classes have no effect. Use `--ui-shadow-ink` instead when the
119
- shadow is depth cast in the intent's own ink, such as a hard offset slab,
120
- which an `.edgeless` element still gets.
121
-
122
- The token is read for its presence, not its value: declare it empty to
123
- switch the ring on, and `initial` to switch it back off in an aesthetic
124
- nested inside one that declares it.
82
+ Clipping removes borders, outlines, and outer shadows. An aesthetic that uses a clip can replace the border with an inset shadow by setting `--ui-shadow-inset` and the four shadow geometry parts. Set `--ui-border-max: 0px` when that ring replaces the component border. Focusable components restore the clipped focus outline through `--ui-focus-inset`.
83
+
84
+ Declare `--ui-shadow-edge` when that ring _is_ the border. The ring then takes the element's edge color, which carries the edge axis as its alpha, so `.edged` draws it and `.edgeless` does not — the same answer a real border gives. Without it the ring paints on every component the aesthetic reaches and the edge classes have no effect. Use `--ui-shadow-ink` instead when the shadow is depth cast in the intent's own ink, such as a hard offset slab, which an `.edgeless` element still gets.
85
+
86
+ The token is read for its presence, not its value: declare it empty to switch the ring on, and `initial` to switch it back off in an aesthetic nested inside one that declares it.
125
87
 
126
88
  ```css
127
89
  .stepped {
@@ -138,16 +100,11 @@ nested inside one that declares it.
138
100
  }
139
101
  ```
140
102
 
141
- Variables named `--shape-*` are internal composition outputs. Do not set or
142
- read them; only the `--ui-*` inputs above are public.
103
+ Variables prefixed `--_` are internal composition outputs — `--_bg`, `--_fg`, `--_edge`, `--_fill`, `--_shadow`, and the `--_d-*` resting slots a component states for `box` to read. Do not set or read them; only the `--ui-*` inputs above are public.
143
104
 
144
105
  ## Aesthetic tokens
145
106
 
146
- The shipped [aesthetic classes](./aesthetics.md) set material tokens for you.
147
- Only aesthetics with a token listed below expose an aesthetic-specific
148
- token. Tune all other behavior through the shared material tokens above.
149
- Listed tokens are available only where that aesthetic's stylesheet is
150
- imported.
107
+ The shipped [aesthetic classes](./aesthetics.md) set material tokens for you. Only aesthetics with a token listed below expose an aesthetic-specific token. Tune all other behavior through the shared material tokens above. Listed tokens are available only where that aesthetic's stylesheet is imported.
151
108
 
152
109
  | Token | Aesthetic | Purpose | Default |
153
110
  | ------------------------ | --------------- | ----------------------------------------------------------- | --------------------------------- |
@@ -160,11 +117,7 @@ imported.
160
117
  | `--tile-lift` | `.chunky-tile` | Depth of the seated bar, and how far a press travels. | `4px` |
161
118
  | `--font-rounded` | `.chunky-tile` | Consumer-supplied rounded font stack. | Falls back to the page stack |
162
119
 
163
- All four aesthetics reach the same way: each knob is _read_ with its default
164
- as a `var()` fallback rather than declared, so it resolves once into a
165
- private on the aesthetic's own class (`--_pixel-unit`, `--_neo-offset`,
166
- `--_tile-radius`, `--_tile-lift`, and so on). Set a knob on the element
167
- carrying the aesthetic class, or on any ancestor including `:root`:
120
+ All four aesthetics reach the same way: each knob is _read_ with its default as a `var()` fallback rather than declared, so it resolves once into a private on the aesthetic's own class (`--_pixel-unit`, `--_neo-offset`, `--_tile-radius`, `--_tile-lift`, and so on). Set a knob on the element carrying the aesthetic class, or on any ancestor including `:root`:
168
121
 
169
122
  ```html
170
123
  <section class="pixel" style="--pixel-unit: 6px">
@@ -180,34 +133,16 @@ carrying the aesthetic class, or on any ancestor including `:root`:
180
133
  </html>
181
134
  ```
182
135
 
183
- Knobs and material tokens reach in opposite directions, and telling them
184
- apart matters. A knob resolves once at the aesthetic's own class and
185
- inherits down already-resolved, so it reaches the aesthetic **from above**:
186
- setting it on the element or any ancestor works, but setting it on a
187
- _descendant_ of the aesthetic class changes nothing — the value has already
188
- been read. `--ui-radius` and the other material tokens above are read fresh
189
- by each component as it draws, so they reach **at or below** the element
190
- carrying them, which is how you round one card differently from its
191
- neighbours without touching the knob at all.
136
+ Knobs and material tokens reach in opposite directions, and telling them apart matters. A knob resolves once at the aesthetic's own class and inherits down already-resolved, so it reaches the aesthetic **from above**: setting it on the element or any ancestor works, but setting it on a _descendant_ of the aesthetic class changes nothing — the value has already been read. `--ui-radius` and the other material tokens above are read fresh by each component as it draws, so they reach **at or below** the element carrying them, which is how you round one card differently from its neighbours without touching the knob at all.
192
137
 
193
- Shipped aesthetics set the shared material tokens above. `.neobrutalism` and
194
- `.pixel` set `--ui-ink` for their neutral outline; intent classes still
195
- override the intent slots on each component.
138
+ Shipped aesthetics set the shared material tokens above. `.neobrutalism` and `.pixel` set `--ui-ink` for their neutral outline; intent classes still override the intent slots on each component.
196
139
 
197
140
  ## Component internals
198
141
 
199
- Component classes may define scoped implementation variables such as
200
- `--button-*`, `--surface-*`, `--control-*`, `--feedback-*`, and `--tooltip-*`.
201
- These variables are internal wiring for class composition and are not the
202
- public token contract.
142
+ Component classes may define scoped implementation variables such as `--surface-padding`, `--field-gap`, `--input-group-pad`, `--switch-*`, `--table-*`, `--quote-*`, and `--tooltip-*`. These variables are internal wiring for class composition and are not the public token contract.
203
143
 
204
- Consumers should customize broad behavior through color, foundation, motion,
205
- elevation, radius, layout, and focus tokens first. The only supported
206
- component-scoped input is `--progress-value` on the `.progress` element,
207
- because consumers must provide a value such as `64%`.
144
+ Consumers should customize broad behavior through color, foundation, motion, elevation, radius, layout, and focus tokens first. The only supported component-scoped input is `--progress-value` on the `.progress` element, because consumers must provide a value such as `64%`.
208
145
 
209
- `--layout-gap` replaces the removed `--layout-stack-gap` and
210
- `--layout-cluster-gap` tokens. No compatibility aliases are provided.
146
+ `--layout-gap` replaces the removed `--layout-stack-gap` and `--layout-cluster-gap` tokens. No compatibility aliases are provided.
211
147
 
212
- Next: [Aesthetics](./aesthetics.md) covers each shipped aesthetic's complete
213
- look and its documented exceptions.
148
+ Next: [Aesthetics](./aesthetics.md) covers each shipped aesthetic's complete look and its documented exceptions.
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  title: Feedback
3
3
  description: Alert, badge, loader, skeleton, and progress class reference.
4
+ order: 7
4
5
  ---
5
6
 
6
7
  # Feedback
@@ -8,7 +9,7 @@ description: Alert, badge, loader, skeleton, and progress class reference.
8
9
  | Class | Purpose |
9
10
  | ---------------- | ---------------------------------------------------------------------------- |
10
11
  | `.alert` | Inline feedback surface. |
11
- | `.icon` | Subclass of `.alert`. Adds a corresponding intent icon and padding. |
12
+ | `.alert-icon` | Sizing and alignment for an icon element dropped in as a child of `.alert`. |
12
13
  | `.badge` | Compact status pill. |
13
14
  | `.loader-mask` | Low-level activity indicator composition utility. Applies the spinner mask. |
14
15
  | `.loader` | Standalone inline loader artwork. |
@@ -32,48 +33,41 @@ Activity indicator modifier classes compose with `.loader`:
32
33
  | `.bars-wave` | Three vertical bars scaling in a wave. |
33
34
  | `.pulse-ring` | Two concentric rings pulsing outward. |
34
35
 
35
- These variants retain their embedded SVG animations normally. Under
36
- `prefers-reduced-motion: reduce`, loader CSS substitutes a corresponding
37
- static mask. This fallback is part of focused loader, button, and components
38
- imports; it does not depend on the global reset. See
39
- [Accessibility](../accessibility.md).
36
+ These variants retain their embedded SVG animations normally. Under `prefers-reduced-motion: reduce`, loader CSS substitutes a corresponding static mask. This fallback is part of focused loader, button, and components imports; it does not depend on the global reset. See [Accessibility](../accessibility.md).
40
37
 
41
38
  Loader size modifiers:
42
39
 
43
- | Class | Size |
44
- | -------- | ----------------- |
45
- | _(none)_ | Default (`2rem`). |
46
- | `.sm` | Small (`1.5rem`). |
47
- | `.lg` | Large (`2.5rem`). |
40
+ | Class | Size |
41
+ | -------- | -------------------- |
42
+ | _(none)_ | Default (`1.75rem`). |
43
+ | `.sm` | Small (`1.25rem`). |
44
+ | `.lg` | Large (`2.25rem`). |
48
45
 
49
- Alerts, badges, progress bars, skeletons, and loaders accept `.primary`,
50
- `.secondary`, `.success`, `.warning`, `.destructive`, `.danger`, `.error`,
51
- and `.info`. Without an intent, they use the text palette, except `.loader`,
52
- which keeps `currentColor` so it matches whatever content surrounds it.
46
+ Alerts, badges, progress bars, skeletons, and loaders accept `.primary`, `.secondary`, `.success`, `.warning`, `.destructive`, `.danger`, `.error`, and `.info`. Without an intent, they use the text palette, except `.loader`, which keeps `currentColor` so it matches whatever content surrounds it.
53
47
 
54
- Skeletons, loaders, progress bars, and dividers are indicators. They read
55
- intent but ignore fill and edge [presentation](./composing.md#presentation).
48
+ Skeletons, loaders, progress bars, and dividers are indicators. They read intent but ignore fill and edge [presentation](./composing.md#presentation).
56
49
 
57
50
  ```html
58
- <span class="loader success" aria-hidden="true"></span>
59
- <span class="skeleton info"></span>
51
+ <span class="loader success" aria-hidden="true"></span> <span class="skeleton info"></span>
60
52
  ```
61
53
 
62
- `.icon` is a subclass of `.alert`. When applied as `.alert.icon`, it
63
- increases the left padding and adds an embedded SVG. Success, warning, and
64
- destructive intents use corresponding symbols; other intents use the
65
- information symbol.
54
+ The package ships no icon of its own: `.alert` is already `flex`, so an icon dropped in as a child is spaced from the message by its `gap-3` with nothing to trigger. `.alert-icon` only sizes and aligns whatever icon element you provide — an inline `<svg>`, an `<img>`, or a class from an icon set such as `@codenhub/icons` — the same contract [`.input-group`](./forms.md#icons) documents.
66
55
 
67
- Alerts and badges read the shared [presentation](./composing.md#presentation)
68
- classes. Without one they use a tinted surface, intent-colored text, and a
69
- mixed intent border.
56
+ Alerts and badges read the shared [presentation](./composing.md#presentation) classes. Without one they use a tinted surface, intent-colored text, and a mixed intent border -- except a neutral `.alert` (no named intent), which rests untinted instead, the same no-named-intent carve-out `.card.soft` and `.panel` use: a plain `--color-foreground` plate rather than 12% of near-black ink over the page. A named intent (`.alert.success`, `.alert.destructive`, and so on) keeps its ordinary tint. `.badge` is unaffected either way -- it has no border to fall back on at rest, so untinting it would make a neutral badge disappear rather than read quieter.
70
57
 
71
58
  ## Example
72
59
 
73
60
  ```html
74
61
  <div class="alert success" role="status">Saved successfully.</div>
75
62
  <div class="alert primary solid" role="status">Deployment started.</div>
76
- <div class="alert warning soft icon" role="status">Review required.</div>
63
+ <div class="alert warning soft" role="status">
64
+ <svg class="alert-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
65
+ <path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" />
66
+ <path d="M12 9v4" />
67
+ <path d="M12 17h.01" />
68
+ </svg>
69
+ Review required.
70
+ </div>
77
71
  <div class="alert destructive ghost edged" role="alert">Deployment failed.</div>
78
72
  <span class="badge warning">Queued</span>
79
73
  <span class="badge success solid">Live</span>
@@ -84,34 +78,9 @@ mixed intent border.
84
78
  <span class="loader bars-wave" aria-hidden="true"></span>
85
79
  <span class="loader pulse-ring sm" aria-hidden="true"></span>
86
80
  <span class="loader dots-grow lg" aria-hidden="true"></span>
87
- <div
88
- class="progress"
89
- role="progressbar"
90
- aria-label="Upload progress"
91
- aria-valuemin="0"
92
- aria-valuemax="100"
93
- aria-valuenow="64"
94
- style="--progress-value: 64%"
95
- ></div>
96
- <div
97
- class="progress secondary active"
98
- role="progressbar"
99
- aria-label="Upload progress"
100
- aria-valuemin="0"
101
- aria-valuemax="100"
102
- aria-valuenow="64"
103
- style="--progress-value: 64%"
104
- ></div>
105
- <div
106
- class="progress info indeterminate"
107
- role="progressbar"
108
- aria-label="Loading"
109
- aria-valuemin="0"
110
- aria-valuemax="100"
111
- ></div>
81
+ <div class="progress" role="progressbar" aria-label="Upload progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="64" style="--progress-value: 64%"></div>
82
+ <div class="progress secondary active" role="progressbar" aria-label="Upload progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="64" style="--progress-value: 64%"></div>
83
+ <div class="progress info indeterminate" role="progressbar" aria-label="Loading" aria-valuemin="0" aria-valuemax="100"></div>
112
84
  ```
113
85
 
114
- Add `role="status"` or `role="alert"` to alerts based on announcement
115
- urgency, mark decorative loading visuals with `aria-hidden="true"`, and use
116
- semantic progress elements or ARIA values when numeric progress must be
117
- announced; see [Accessibility](../accessibility.md).
86
+ Add `role="status"` or `role="alert"` to alerts based on announcement urgency, mark decorative loading visuals with `aria-hidden="true"`, and use semantic progress elements or ARIA values when numeric progress must be announced; see [Accessibility](../accessibility.md).