@codenhub/styles 0.2.0 → 0.4.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.
package/llms-full.txt CHANGED
@@ -68,7 +68,7 @@ The package ships as ready-to-import compiled CSS, or as Tailwind CSS v4 source
68
68
  - Publishes color, foundation, intent, presentation, and material design tokens as CSS custom properties, themed with `light-dark()`.
69
69
  - Provides a reset, focus-visible handling, and responsive layout/content utilities.
70
70
  - Provides composable classes for buttons, form controls and toggles, alerts, badges, loaders, progress, cards/panels, tables, quotes, code, and tooltips.
71
- - Provides four opt-in aesthetics that restyle the same components by setting material tokens, not by adding component variants.
71
+ - Provides five opt-in aesthetics that restyle the same components by setting material tokens, not by adding component variants, each with a solo class that paints the look onto an element the package does not style.
72
72
  - Provides classless mappings so plain HTML elements pick up base styling without added classes, from a dedicated entrypoint.
73
73
  - Publishes Tailwind CSS v4 source entrypoints alongside the compiled output.
74
74
 
@@ -77,7 +77,7 @@ The package ships as ready-to-import compiled CSS, or as Tailwind CSS v4 source
77
77
  - No JavaScript. There is no runtime, no framework bindings, and no build-time code generation beyond the CSS itself.
78
78
  - No semantic HTML, ARIA, keyboard behavior, focus management, validation, or announcement timing. See [Accessibility](docs/accessibility.md) for the exact line between what the CSS provides and what an application must still add.
79
79
  - No theme-toggling logic. Theme selection is a class or attribute a consumer applies; wiring a toggle to system preference, storage, or a user setting is outside this package. The `@codenhub/theme` package covers that need for consumers who want it.
80
- - No shipped font binaries. `.pixel` and `.chunky-tile` accept a consumer-supplied font and fall back to a system stack when none is given.
80
+ - No shipped font binaries. `.pixel`, `.chunky-tile`, and `.cyber` accept a consumer-supplied font and fall back to a system stack when none is given.
81
81
  - No compatibility layer for removed tokens or classes. Breaking changes are documented, not silently aliased.
82
82
 
83
83
  ## Next steps
@@ -168,28 +168,29 @@ The one place it does not track the token theme: nesting an explicit selector in
168
168
 
169
169
  Compiled entrypoints are ready-to-import CSS and require only tooling that can resolve package CSS imports. `/tw` entrypoints publish copied, uncompiled source from `dist/tw`; a Tailwind v4 build must still process their `@theme`, `@utility`, `@apply`, and related directives. Focused source component entrypoints include theme tokens so their classes can work independently.
170
170
 
171
- | Import path | Composition and effects |
172
- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
173
- | `@codenhub/styles` | Compiled complete surface: Tailwind base/theme output, tokens, typography, utilities, components, and reset. Applies global reset, root theme, and focus rules. |
174
- | `@codenhub/styles/theme` | Compiled Tailwind theme variables, Codenhub tokens, and the presentation classes. Sets root theme properties and system/explicit theme selectors; no reset or component classes. |
175
- | `@codenhub/styles/components` | Compiled theme tokens, typography utilities, and every component class. Includes static reduced-motion loader masks; no reset, layout/content utilities, or native mappings. |
176
- | `@codenhub/styles/native` | Compiled complete surface plus classless mappings for headings, text, content elements, form controls, and buttons. Applies the reset and broad element selectors. |
177
- | `@codenhub/styles/aesthetics` | Compiled `.neobrutalism`, `.glass`, `.pixel`, and `.chunky-tile` classes. Adds no tokens or components of its own; import after the base stylesheet. |
178
- | `@codenhub/styles/aesthetics/*` | One compiled aesthetic: `/neobrutalism`, `/glass`, `/pixel`, or `/chunky-tile`. Same rules and ordering as the combined file. |
179
- | `@codenhub/styles/tw` | Source equivalent of the complete stylesheet. Imports Tailwind itself, theme, typography, utilities, components, and reset; applies the same global rules. |
180
- | `@codenhub/styles/tw/theme` | Source theme, tokens, and presentation classes. Imports Tailwind's theme layer; emits root/system/explicit theme selectors and defines the package's custom `dark:` variant. |
181
- | `@codenhub/styles/tw/components` | Published Tailwind source for theme, typography, buttons, feedback, forms, loaders, surfaces, and tooltips, including static reduced-motion loader masks. No reset, layout/content utilities, or native mappings. |
182
- | `@codenhub/styles/tw/surface` | Source theme plus `.surface`, `.card`, and `.panel`. |
183
- | `@codenhub/styles/tw/button` | Published Tailwind source for theme and `.btn`. Pair it with `/tw/loader` for a loading state composed from `.loader`. |
184
- | `@codenhub/styles/tw/form` | Source theme plus field, public `text-control`, input, textarea, select, checkbox, radio, and switch utilities. |
185
- | `@codenhub/styles/tw/feedback` | Source theme plus alert, badge, skeleton, and progress utilities and their keyframes. |
186
- | `@codenhub/styles/tw/loader` | Published Tailwind source for activity indicators and loaders, including static reduced-motion masks. It has no theme or reset side effects and uses `currentColor`. |
187
- | `@codenhub/styles/tw/tooltip` | Source theme plus tooltip utilities. |
188
- | `@codenhub/styles/tw/reset` | Source theme, typography utilities, and global reset/accessibility rules. It changes root/body/elements and selection, motion, focus, scrollbar, and forced colors. |
189
- | `@codenhub/styles/tw/native` | Source complete surface plus reset and classless native-element mappings; broadest global effects. |
190
- | `@codenhub/styles/tw/typography` | Source theme plus typography utilities; sets theme selectors but no reset or classless mappings. |
191
- | `@codenhub/styles/tw/utilities` | Source theme and typography composition plus layout and content utilities; safelists the package utility names. |
192
- | `@codenhub/styles/tw/aesthetics` | Source aesthetics, combined. `/tw/aesthetics/neobrutalism`, `/glass`, `/pixel`, and `/chunky-tile` publish one apiece. Plain CSS with no theme or reset side effects. |
171
+ | Import path | Composition and effects |
172
+ | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
173
+ | `@codenhub/styles` | Compiled complete surface: Tailwind base/theme output, tokens, typography, utilities, components, and reset. Applies global reset, root theme, and focus rules. |
174
+ | `@codenhub/styles/theme` | Compiled Tailwind theme variables, Codenhub tokens, and the presentation classes. Sets root theme properties and system/explicit theme selectors; no reset or component classes. |
175
+ | `@codenhub/styles/palette` | Generated, self-contained `--palette-*` custom properties: every intent/presentation cell's fill, text, and edge color, plus the flat `border`/`surface`/`text` neutral tokens, pre-composed to a flat value. For a consumer that cannot take this package as a build-time dependency (an optional peer, for example) but wants to look consistent with it. Not a replacement for the components themselves when Tailwind is available -- see [Customizing → Generated palette](docs/usage/customizing.md#generated-palette). |
176
+ | `@codenhub/styles/components` | Compiled theme tokens, typography utilities, and every component class. Includes static reduced-motion loader masks; no reset, layout/content utilities, or native mappings. |
177
+ | `@codenhub/styles/native` | Compiled complete surface plus classless mappings for headings, text, content elements, form controls, and buttons. Applies the reset and broad element selectors. |
178
+ | `@codenhub/styles/aesthetics` | Compiled `.neobrutalism`, `.glass`, `.pixel`, `.chunky-tile`, and `.cyber` classes, and each one's `-solo` class. Adds no tokens or components of its own; import after the base stylesheet. |
179
+ | `@codenhub/styles/aesthetics/*` | One compiled aesthetic and its solo class: `/neobrutalism`, `/glass`, `/pixel`, `/chunky-tile`, or `/cyber`. Same rules and ordering as the combined file. |
180
+ | `@codenhub/styles/tw` | Source equivalent of the complete stylesheet. Imports Tailwind itself, theme, typography, utilities, components, and reset; applies the same global rules. |
181
+ | `@codenhub/styles/tw/theme` | Source theme, tokens, and presentation classes. Imports Tailwind's theme layer; emits root/system/explicit theme selectors and defines the package's custom `dark:` variant. |
182
+ | `@codenhub/styles/tw/components` | Published Tailwind source for theme, typography, buttons, feedback, forms, loaders, surfaces, and tooltips, including static reduced-motion loader masks. No reset, layout/content utilities, or native mappings. |
183
+ | `@codenhub/styles/tw/surface` | Source theme plus `.surface`, `.card`, and `.panel`. |
184
+ | `@codenhub/styles/tw/button` | Published Tailwind source for theme and `.btn`. Pair it with `/tw/loader` for a loading state composed from `.loader`. |
185
+ | `@codenhub/styles/tw/form` | Source theme plus field, public `text-control`, input, textarea, select, checkbox, radio, and switch utilities. |
186
+ | `@codenhub/styles/tw/feedback` | Source theme plus alert, badge, skeleton, and progress utilities and their keyframes. |
187
+ | `@codenhub/styles/tw/loader` | Published Tailwind source for activity indicators and loaders, including static reduced-motion masks. It has no theme or reset side effects and uses `currentColor`. |
188
+ | `@codenhub/styles/tw/tooltip` | Source theme plus tooltip utilities. |
189
+ | `@codenhub/styles/tw/reset` | Source theme, typography utilities, and global reset/accessibility rules. It changes root/body/elements and selection, motion, focus, scrollbar, and forced colors. |
190
+ | `@codenhub/styles/tw/native` | Source complete surface plus reset and classless native-element mappings; broadest global effects. |
191
+ | `@codenhub/styles/tw/typography` | Source theme plus typography utilities; sets theme selectors but no reset or classless mappings. |
192
+ | `@codenhub/styles/tw/utilities` | Source theme and typography composition plus layout and content utilities; safelists the package utility names. |
193
+ | `@codenhub/styles/tw/aesthetics` | Source aesthetics, combined. `/tw/aesthetics/neobrutalism`, `/glass`, `/pixel`, `/chunky-tile`, and `/cyber` publish one apiece. Plain CSS with no theme or reset side effects. |
193
194
 
194
195
  Avoid importing overlapping entrypoints in the same build unless duplicate generated CSS is acceptable; pick the narrowest entrypoint that covers what a page needs.
195
196
 
@@ -210,11 +211,11 @@ Read this before the usage guides. It explains the mental model every component,
210
211
 
211
212
  Every component separates three independent choices, so each can change without a component-specific variant:
212
213
 
213
- | Axis | Question | Classes | Inheritance |
214
- | ------------ | --------------- | ----------------------------------------------------------------------------------------- | ------------ |
215
- | Intent | Which color? | `.primary`, `.secondary`, `.success`, `.warning`, `.destructive`, `.info` | Element only |
216
- | Presentation | How much of it? | `.solid`, `.soft`, `.ghost`, `.edged`, `.edgeless` | Cascades |
217
- | Aesthetic | Made of what? | `.neobrutalism`, `.glass`, `.pixel`, `.chunky-tile` from an optional aesthetic stylesheet | Cascades |
214
+ | Axis | Question | Classes | Inheritance |
215
+ | ------------ | --------------- | --------------------------------------------------------------------------------------------------- | ------------ |
216
+ | Intent | Which color? | `.primary`, `.secondary`, `.success`, `.warning`, `.destructive`, `.info` | Element only |
217
+ | Presentation | How much of it? | `.solid`, `.soft`, `.ghost`, `.edged`, `.edgeless` | Cascades |
218
+ | Aesthetic | Made of what? | `.neobrutalism`, `.glass`, `.pixel`, `.chunky-tile`, `.cyber` from an optional aesthetic stylesheet | Cascades |
218
219
 
219
220
  ```html
220
221
  <section class="soft pixel">
@@ -347,18 +348,19 @@ The edge is the silhouette and nothing else. Rules _inside_ a component that has
347
348
 
348
349
  With no presentation class in scope, each component keeps its own default: buttons are filled, alerts and badges are tinted, surfaces and controls are neutral and bordered.
349
350
 
350
- | Component | Reads |
351
- | ----------------------------------------------- | ------------------------------------------- |
352
- | `.btn`, `.alert`, `.badge`, `.card`, `.panel` | Fill, text, border, and border width. |
353
- | `.kbd` | Fill, text, border, and border width. |
354
- | `.data-table` | Header fill and text, border, border width. |
355
- | `.ipt`, `.textarea`, `.select`, `.text-control` | Border, border width, and a capped fill. |
356
- | `.input-group` | Border, border width, and a capped fill. |
357
- | `.checkbox`, `.radio` | A capped fill, checked and unchecked. |
358
- | `.switch` | Border, border width, and a capped fill. |
359
- | `.quote` | Fill, text, border, and width. |
360
- | `.code`, `.pre`, `.tooltip-bubble` | Fill, text, border, and material. |
361
- | `.loader`, `.skeleton`, `.progress`, `.divider` | Intent only, not presentation. |
351
+ | Component | Reads |
352
+ | ----------------------------------------------- | ----------------------------------------------------------------------------------------------- |
353
+ | `.btn`, `.alert`, `.badge`, `.card`, `.panel` | Fill, text, border, and border width. |
354
+ | `.kbd` | Fill, text, border, and border width. |
355
+ | `.data-table` | Header fill and text, border, border width. |
356
+ | `.ipt`, `.textarea`, `.select`, `.text-control` | Border, border width, and a capped fill. |
357
+ | `.input-group` | Border, border width, and a capped fill. |
358
+ | `.checkbox`, `.radio` | A capped fill, checked and unchecked. |
359
+ | `.switch` | Border, border width, and a capped fill. |
360
+ | `.quote` | Fill, text, border, and width. |
361
+ | `.code`, `.pre`, `.tooltip-bubble` | Fill, text, border, and material. |
362
+ | `.progress` | Track fill, border, and border width; the value fill is always the intent color, full strength. |
363
+ | `.loader`, `.skeleton`, `.divider` | Intent only, not presentation. |
362
364
 
363
365
  A text control caps a **cascaded** fill at `6%`, keeping typed text legible when a `.solid` container reaches a field nobody classed. A fill class written on the control itself names its own cap instead, because that is a consumer describing what they want: `.soft` takes `12%` and `.solid` takes `20%`.
364
366
 
@@ -397,13 +399,15 @@ Presentation is two independent axes, so they get a column each. A `Yes` means t
397
399
  | `.surface` | Yes | Yes | Yes | Shape |
398
400
  | `.checkbox`, `.radio` | Yes | Yes | No | Radius and edge |
399
401
  | `.switch` | Yes | Yes | Yes | Radius and edge |
400
- | `.progress` | Yes | No | No | No |
402
+ | `.progress` | Yes | Yes | Yes | Radius and edge |
401
403
  | `.code`, `.pre` | Yes | Yes | Yes | Radius and clip |
402
404
  | `.tooltip-bubble` | Yes | Yes | Yes | Shape and overlay |
403
405
  | `.table-wrap`, `.quote-inline`, layout and text utilities | No | No | No | No |
404
406
 
405
407
  `.checkbox` and `.radio` are the only components that read one axis and not the other. Their line is the only thing marking an unchecked box, so it is drawn whatever the edge class says, from a container or from the element itself. `.edgeless` on either is unsupported rather than merely discouraged.
406
408
 
409
+ `.progress` reads both axes on its track; the value fill, the moving bar itself, is always the intent color at full strength and never changes. `.solid` is unsupported on the track: at full fill the track and the value fill compose the same color, and the one thing the component exists to show — how much is filled versus not — disappears. `.ghost.edgeless` renders (no fill, no border) but is not recommended: `.ghost.edged` — an outline capsule around the moving fill — keeps a visible frame at rest, while pairing `.ghost` with `.edgeless` leaves the track with none.
410
+
407
411
  Every other text control floors a _cascaded_ `.edgeless` and honours its own: a `.edgeless` toolbar will not erase the line of a field nobody classed, while `.ipt.edgeless` is a consumer describing what they want and gets it.
408
412
 
409
413
  Intent aliases such as `.danger` and `.error` occupy the same intent axis as `.destructive`; they do not add component behavior. State and modifier classes such as `.interactive`, `.hoverable`, `.pressable`, `.invalid`, `.compact`, and `.vertical` sit above this map and are documented with their component.
@@ -617,35 +621,38 @@ Material tokens describe what a component is _made of_ rather than which intent
617
621
 
618
622
  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.
619
623
 
620
- | Token | Purpose | Fallback |
621
- | ----------------------- | ------------------------------------------------------------------------------------------------------------- | -------------------- |
622
- | `--ui-radius` | Corner radius for controls. | `--radius-control` |
623
- | `--ui-radius-surface` | Corner radius for surfaces. | `--radius-surface` |
624
- | `--ui-border-width` | Edge thickness. | `--border-width` |
625
- | `--ui-border-max` | Ceiling on computed edge width. | `100px` |
626
- | `--ui-ink` | Neutral line color when no intent is set. | `--color-border` |
627
- | `--ui-rule` | Lines inside a table. Unset draws the head and foot boundaries only; `0%` draws none; `100%` rules every row. | unset |
628
- | `--ui-shadow-x` | Shadow horizontal offset. | `0px` |
629
- | `--ui-shadow-y` | Shadow vertical offset. | `0px` |
630
- | `--ui-shadow-blur` | Shadow blur radius. | `0px` |
631
- | `--ui-shadow-spread` | Shadow spread radius. | `0px` |
632
- | `--ui-shadow-inset` | The `inset` keyword for an inner ring. | Empty |
633
- | `--ui-hover-shadow-x` | Shadow horizontal offset while hovered. | `--ui-shadow-x` |
634
- | `--ui-hover-shadow-y` | Shadow vertical offset while hovered. | `--ui-shadow-y` |
635
- | `--ui-active-shadow-x` | Shadow horizontal offset while pressed. | `--ui-shadow-x` |
636
- | `--ui-active-shadow-y` | Shadow vertical offset while pressed. | `--ui-shadow-y` |
637
- | `--ui-active-transform` | Transform while pressed. `none` under `prefers-reduced-motion`. | `scale(0.97)` |
638
- | `--ui-shadow-ink` | Percentage of shadow color taken from intent ink. | `0%` |
639
- | `--ui-shadow-edge` | Declared, even empty, when the shadow is the element's edge rather than its depth. Read for presence. | Unset |
640
- | `--ui-elevation` | Unitless multiplier over shadow geometry. | `1` |
641
- | `--ui-surface-shadow` | Complete multi-layer shadow accepted by surfaces only. | Unset |
642
- | `--ui-surface-ground` | Ground a surface sits on. | `--color-background` |
643
- | `--ui-bg-alpha` | Multiplier over fill for translucent materials. | `1` |
644
- | `--ui-backdrop` | Backdrop filter accepted by surfaces only. | `none` |
645
- | `--ui-hover-transform` | Transform while an interactive element is hovered. | `none` |
646
- | `--ui-clip` | Structural component silhouette. | `none` |
647
- | `--ui-clip-tight` | Compact component silhouette. | `--ui-clip` |
648
- | `--ui-focus-inset` | Inset focus layer width. | Unset |
624
+ | Token | Purpose | Fallback |
625
+ | ----------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------- |
626
+ | `--ui-radius` | Corner radius for controls. | `--radius-control` |
627
+ | `--ui-radius-surface` | Corner radius for surfaces. | `--radius-surface` |
628
+ | `--ui-corner-shape` | What every corner the two radii set draws: `round`, or `bevel` for a straight cut. Chromium only today. | `round` |
629
+ | `--ui-radius-pill` | Corner for what is fully round by default: badges, switches, progress, the tooltip icon. | `--ui-radius`, then full |
630
+ | `--ui-radius-tight` | Corner for chips -- checkbox, `.kbd`, `.code` -- before their `--radius-small` cap. | `--ui-radius`, then small |
631
+ | `--ui-border-width` | Edge thickness. | `--border-width` |
632
+ | `--ui-border-max` | Ceiling on computed edge width. | `100px` |
633
+ | `--ui-ink` | Neutral line color when no intent is set. | `--color-border` |
634
+ | `--ui-rule` | Lines inside a table. Unset draws the head and foot boundaries only; `0%` draws none; `100%` rules every row. | unset |
635
+ | `--ui-shadow-x` | Shadow horizontal offset. | `0px` |
636
+ | `--ui-shadow-y` | Shadow vertical offset. | `0px` |
637
+ | `--ui-shadow-blur` | Shadow blur radius. | `0px` |
638
+ | `--ui-shadow-spread` | Shadow spread radius. | `0px` |
639
+ | `--ui-shadow-inset` | The `inset` keyword for an inner ring. | Empty |
640
+ | `--ui-hover-shadow-x` | Shadow horizontal offset while hovered. | `--ui-shadow-x` |
641
+ | `--ui-hover-shadow-y` | Shadow vertical offset while hovered. | `--ui-shadow-y` |
642
+ | `--ui-active-shadow-x` | Shadow horizontal offset while pressed. | `--ui-shadow-x` |
643
+ | `--ui-active-shadow-y` | Shadow vertical offset while pressed. | `--ui-shadow-y` |
644
+ | `--ui-active-transform` | Transform while pressed. `none` under `prefers-reduced-motion`. | `scale(0.97)` |
645
+ | `--ui-shadow-ink` | Percentage of shadow color taken from intent ink. | `0%` |
646
+ | `--ui-shadow-edge` | Declared, even empty, when the shadow is the element's edge rather than its depth. Read for presence. | Unset |
647
+ | `--ui-elevation` | Unitless multiplier over shadow geometry. | `1` |
648
+ | `--ui-surface-shadow` | Complete multi-layer shadow accepted by surfaces only. | Unset |
649
+ | `--ui-surface-ground` | Ground a surface sits on. | `--color-background` |
650
+ | `--ui-bg-alpha` | Multiplier over fill for translucent materials. | `1` |
651
+ | `--ui-backdrop` | Backdrop filter accepted by surfaces only. | `none` |
652
+ | `--ui-hover-transform` | Transform while an interactive element is hovered. | `none` |
653
+ | `--ui-clip` | Structural component silhouette. | `none` |
654
+ | `--ui-clip-tight` | Compact component silhouette. | `--ui-clip` |
655
+ | `--ui-focus-inset` | Inset focus layer width. | Unset |
649
656
 
650
657
  ```html
651
658
  <section style="--ui-radius: 0; --ui-border-width: 3px">
@@ -660,6 +667,10 @@ Components read each with a fallback, so leaving them unset produces the default
660
667
 
661
668
  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`.
662
669
 
670
+ A clip is not the only way to cut a corner. `--ui-corner-shape: bevel` draws the corner the radius sets as a straight cut instead of an arc, and the border, outer shadow, focus outline, and backdrop all follow it -- so a bevelled element keeps its glow and its line, where a clipped one loses both. `.cyber` uses it. Engines without `corner-shape` ignore it and draw the radius round, so an aesthetic that bevels should square its radius under `@supports not (corner-shape: bevel)`. A bevel on a full radius cuts to points: a radio, a `.btn.pill`, and anything reading `--ui-radius-pill` become diamonds or pointed hexagons.
671
+
672
+ Because `--ui-radius` accepts any `border-radius` value, it can also place the corner per side: `10px 0` cuts only top-left and bottom-right. The pill and chip corners are separate tokens for that reason -- a pill's full radius and a chip's `min()` cap cannot take a per-corner value -- and each falls back to `--ui-radius` when unset.
673
+
663
674
  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.
664
675
 
665
676
  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.
@@ -685,18 +696,24 @@ Variables prefixed `--_` are internal composition outputs — `--_bg`, `--_fg`,
685
696
 
686
697
  The shipped [aesthetic classes](docs/usage/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.
687
698
 
688
- | Token | Aesthetic | Purpose | Default |
689
- | ------------------------ | --------------- | ----------------------------------------------------------- | --------------------------------- |
690
- | `--neo-offset` | `.neobrutalism` | Hard shadow offset and distance the press travels. | `4px` |
691
- | `--glass-radius` | `.glass` | Control corner radius. | `0.75rem` |
692
- | `--glass-radius-surface` | `.glass` | Surface corner radius. | `1rem` |
693
- | `--pixel-unit` | `.pixel` | One pixel of the grid. The corner cut and the ring are one. | `4px` |
694
- | `--font-pixel` | `.pixel` | Consumer-supplied pixel font stack. | Falls back to the monospace stack |
695
- | `--tile-radius` | `.chunky-tile` | Corner radius, on controls and surfaces alike. | `0.75rem` |
696
- | `--tile-lift` | `.chunky-tile` | Depth of the seated bar, and how far a press travels. | `4px` |
697
- | `--font-rounded` | `.chunky-tile` | Consumer-supplied rounded font stack. | Falls back to the page stack |
698
-
699
- 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`:
699
+ | Token | Aesthetic | Purpose | Default |
700
+ | ------------------------ | --------------- | --------------------------------------------------------------------------------------------- | ---------------------------------- |
701
+ | `--neo-offset` | `.neobrutalism` | Hard shadow offset and distance the press travels. | `4px` |
702
+ | `--glass-radius` | `.glass` | Control corner radius. | `0.75rem` |
703
+ | `--glass-radius-surface` | `.glass` | Surface corner radius. | `1rem` |
704
+ | `--pixel-unit` | `.pixel` | One pixel of the grid. The corner cut and the ring are one. | `4px` |
705
+ | `--font-pixel` | `.pixel` | Consumer-supplied pixel font stack. | Falls back to the monospace stack |
706
+ | `--tile-radius` | `.chunky-tile` | Corner radius, on controls and surfaces alike. | `0.75rem` |
707
+ | `--tile-lift` | `.chunky-tile` | Depth of the seated bar, and how far a press travels. | `4px` |
708
+ | `--font-rounded` | `.chunky-tile` | Consumer-supplied rounded font stack. | Falls back to the page stack |
709
+ | `--cyber-cut` | `.cyber` | Largest cut, on controls and surfaces alike; the default shapes cap it at 25% of the element. | `0.625rem` |
710
+ | `--cyber-shape` | `.cyber` | Where controls take the cut: any `border-radius` value. | `<cut> 0` (top-left, bottom-right) |
711
+ | `--cyber-shape-surface` | `.cyber` | Where surfaces take the cut: any `border-radius` value. | `0 <cut>` (top-right, bottom-left) |
712
+ | `--cyber-glow` | `.cyber` | Blur of the glow. | `8px` |
713
+ | `--cyber-ink` | `.cyber` | Neutral line and glow colour, where no intent sets one. | Theme ink (near-black, near-white) |
714
+ | `--font-cyber` | `.cyber` | Consumer-supplied technical font stack. | Falls back to the monospace stack |
715
+
716
+ Every aesthetic's knobs 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`:
700
717
 
701
718
  ```html
702
719
  <section class="pixel" style="--pixel-unit: 6px">
@@ -714,7 +731,36 @@ All four aesthetics reach the same way: each knob is _read_ with its default as
714
731
 
715
732
  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.
716
733
 
717
- 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.
734
+ Shipped aesthetics set the shared material tokens above. `.neobrutalism`, `.pixel`, and `.cyber` set `--ui-ink` for their neutral outline; intent classes still override the intent slots on each component.
735
+
736
+ The same knobs tune each aesthetic's [solo class](docs/usage/aesthetics.md#solo-classes), which reads them on its own element.
737
+
738
+ ## Generated palette
739
+
740
+ `@codenhub/styles/palette` is a generated, self-contained stylesheet of every `intent x presentation` cell's composed colors, baked to flat `--palette-*` custom properties -- the same values `box.css` composes live, computed once at build time rather than re-derived. It exists for a consumer that cannot take `@codenhub/styles` as a build-time dependency (an optional peer, for example) but still wants to look consistent with it, not as a replacement for the components themselves when Tailwind is available.
741
+
742
+ ```css
743
+ @import "@codenhub/styles/palette";
744
+ ```
745
+
746
+ ```css
747
+ .my-badge {
748
+ background: var(--palette-success-soft-page-bg);
749
+ color: var(--palette-success-soft-fg);
750
+ border-color: var(--palette-success-soft-page-edge);
751
+ }
752
+ ```
753
+
754
+ Every value is already the composited color -- never a `var(--color-background)` or `var(--intent-subtle)` reference -- so this file never needs `./theme` loaded alongside it to resolve anything.
755
+
756
+ Naming: `--palette-<intent>-<presentation>-<slot>`, where `<intent>` is one of the seven published intents (`neutral`, `primary`, `secondary`, `success`, `warning`, `destructive`, `info`) and `<presentation>` is `solid`, `soft`, or `ghost`. `<slot>` is `bg`, `fg`, or `edge`. Two qualifiers layer on only where they apply:
757
+
758
+ - A ground qualifier (`page` or `subtle`) inserted before the slot, present only on `.soft`/`.ghost`'s `bg` and `edge` -- `.solid` is ground-independent at full fill, and `fg` never varies by ground. No qualifier means the `transparent` ground (`.badge`/`.btn`'s ground): `--palette-success-soft-bg`. `page` is `.alert`'s ground (`--color-background`): `--palette-success-soft-page-bg`. `subtle` is `.pre`/`.code`/`.kbd`/`.tooltip-bubble`'s ground (that intent's own `--intent-subtle`): `--palette-success-soft-subtle-bg`.
759
+ - A `-hover` suffix on `bg` and `edge` only -- `fg` never changes on hover: `--palette-success-soft-page-bg-hover`.
760
+
761
+ Dark values are scoped the same way `@codenhub/styles`' own explicit theme override is: `.dark`, `.theme-dark`, and `[data-theme="dark"]`, on the element or an ancestor. There is no `prefers-color-scheme` fallback in this file -- a consumer reaching for a standalone palette is already handling its own theme switching, so the OS-preference case is left to `@codenhub/styles`' own `light-dark()`-based tokens when that package is actually in use.
762
+
763
+ Three more tokens sit alongside the intent cells for the same reason, without an intent, presentation, ground, or hover axis of their own: `--palette-border`, `--palette-surface`, and `--palette-text`, flat values for `--color-border`, `--color-surface`, and `--color-text` -- the resting colors anything that is not intent-colored needs (a container's border, a dialog's background, its text), which an optional-peer consumer needs just as much as the intent cells.
718
764
 
719
765
  ## Component internals
720
766
 
@@ -754,6 +800,7 @@ Like presentation, an aesthetic class cascades to any subtree:
754
800
  | `.glass` | Translucent surfaces over a blurred backdrop with a hairline highlight edge. |
755
801
  | `.pixel` | Corners cut by one grid unit, a chunky outline drawn as an inset ring, and the consumer-supplied `--font-pixel` over monospace. |
756
802
  | `.chunky-tile` | Rounded slabs seated on a darker shade of themselves, with a press that moves the element down into its own bar. |
803
+ | `.cyber` | Bevelled corners, a thin bright edge, and a glow in the component's own colour. |
757
804
 
758
805
  Aesthetics compose with every supported fill and edge pair. `.ghost.edgeless` intentionally removes the visible material traits from components whose aesthetic is expressed only through their fill, edge, or elevation.
759
806
 
@@ -844,6 +891,79 @@ The bar is a darker shade of the element's own colour rather than a shadow under
844
891
  - The shipped `.primary` is a near-black-or-near-white monochrome depending on theme, and the bar mixes toward a fixed black regardless of theme. In light theme this leaves a primary button's bar almost invisible against its own near-black plate (measured `1.04:1`, 10 units of sRGB distance); in dark theme the near-white plate against the same black-anchored bar reads fine (`2.48:1`, 154 units). Give `.primary` a hue of its own if it is the call to action and needs the depth cue in both themes.
845
892
  - Depth in this aesthetic is the bar, never a blurred drop shadow. Anything the registry rests flat sits flush on the page.
846
893
 
894
+ ## Cyber
895
+
896
+ Bevelled corners, a 1px edge, and a glow in the component's own colour: a success button glows green, a destructive card red. The bevel is drawn with `corner-shape`, so the border, the glow, and the focus outline all follow the cut rather than being clipped by it.
897
+
898
+ Controls and surfaces take the cut on opposite diagonals, so a button and the card around it read as the same material and as different things: buttons and fields cut top-left and bottom-right, cards, panels, and alerts top-right and bottom-left. Anything fully round cuts to points -- a radio, a switch knob, and the tooltip icon become diamonds, a pill button or a badge a pointed hexagon -- and chips square, so the checkbox reads as a plain square beside the diamond radio.
899
+
900
+ `--cyber-cut` is the largest cut, `0.625rem`: the default shapes cap it at a quarter of the element's own box, so a normal button or a card takes the full cut and a small icon button a smaller one rather than losing its corners. `--cyber-shape` and `--cyber-shape-surface` place it, and take any `border-radius` value. `--cyber-glow` is the glow's blur, `8px`. `--cyber-ink` is the neutral line and glow colour, which follows the theme by default -- near-black on light, near-white on dark -- and is where a neon neutral goes if you want one.
901
+
902
+ ```html
903
+ <section class="cyber" style="--cyber-ink: rgb(0 229 255); --cyber-cut: 0.75rem">
904
+ <button class="btn">Jack in</button>
905
+ </section>
906
+ ```
907
+
908
+ Other shapes are a value away. Set them on the `.cyber` element or any ancestor; `--ui-radius` set on one element changes just that element. A shape you set is used as written, so wrap a length in `min(..., 25%)` if small controls should keep the cap.
909
+
910
+ | Shape | Value |
911
+ | ---------------------- | --------------------- |
912
+ | All four corners | `0.625rem` |
913
+ | The other diagonal | `0 0.625rem` |
914
+ | Hexagon (pointed ends) | `0.625rem / 50%` |
915
+ | Parallelogram | `0.625rem 0 / 100% 0` |
916
+ | One notch, top-right | `0 0.625rem 0 0` |
917
+
918
+ ```html
919
+ <section class="cyber" style="--cyber-shape: 0.625rem / 50%">
920
+ <button class="btn primary">Hexagonal buttons</button>
921
+ </section>
922
+ ```
923
+
924
+ A parallelogram slants its sides into the content, so give a surface that takes one extra inline padding.
925
+
926
+ **Exceptions:**
927
+
928
+ - The bevel is Chromium-only today. Firefox and Safari do not draw `corner-shape` yet, and there the aesthetic squares its cut corners instead of rounding them, and what is fully round stays round, so the look degrades to square, lined, and glowing. It picks up the bevel with no change once an engine ships it.
929
+ - The glow is depth, so it reaches what the registry rests above zero -- buttons and cards -- and anything you raise with `.raised` or `.floating`. Fields, badges, and alerts keep the edge without the glow, and `.flat` takes it off anything.
930
+ - In the light theme the glow of a neutral or `.primary` component is its near-black ink, which reads as a soft shadow rather than as light. The look is at its strongest on a dark page, or with a hued `--cyber-ink`.
931
+ - A plain `.btn.icon` is a square control, so it takes the control diagonal; a `.btn.icon.pill` is round, so it becomes a diamond.
932
+ - `--font-cyber` is yours to supply. The package ships no font binary, so the aesthetic falls back to the monospace stack.
933
+ - Casing is left alone, for the reason [Chunky tile](#chunky-tile) gives.
934
+
935
+ ## Solo classes
936
+
937
+ An aesthetic class sets material tokens and nothing paints until a component reads them, so `.glass` on an element this package does not style -- a toast from another library, a dialog, a plain `<div>` on a page without the base stylesheet -- changes nothing. Each aesthetic also ships a solo class that paints its look directly onto the one element carrying it:
938
+
939
+ | Aesthetic | Solo class | Paints |
940
+ | --------------- | -------------------- | ----------------------------------------------------------------------------------------- |
941
+ | `.glass` | `.glass-solo` | Translucent ground, hairline edge, blur, the tucked two-layer shadow, the surface corner. |
942
+ | `.neobrutalism` | `.neobrutalism-solo` | 2px ink edge, square corners, the hard offset slab. |
943
+ | `.pixel` | `.pixel-solo` | The stepped silhouette, the inset ring in place of a border, the pixel font. |
944
+ | `.chunky-tile` | `.chunky-tile-solo` | The tile corner, 2px edge, the bar under it, the rounded font. |
945
+ | `.cyber` | `.cyber-solo` | The surface diagonal (the control one on an action), 1px edge, the glow, the font. |
946
+
947
+ ```css
948
+ /* The only stylesheet from this package on the page. */
949
+ @import "@codenhub/styles/aesthetics/glass";
950
+ ```
951
+
952
+ ```html
953
+ <div class="toast glass-solo">A pane over whatever is behind it.</div>
954
+ ```
955
+
956
+ A solo class ships in the same entrypoint as its aesthetic, and needs nothing else loaded:
957
+
958
+ - **It paints material, not colour.** Edge, corner, depth, silhouette, backdrop, font, and press. No intent, no fill amount, no hover tint -- the element has no presentation to compose. Glass's translucent ground is the one fill, because it is glass's material.
959
+ - **It reads its aesthetic's knobs and the theme's tokens, with the shipped values as fallbacks.** `--glass-radius-surface`, `--neo-offset`, `--pixel-unit`, `--tile-lift`, `--tile-radius`, `--cyber-cut`, `--cyber-shape`, `--cyber-shape-surface`, `--cyber-glow`, `--cyber-ink`, and the font knobs all work, set on the element or any ancestor. With the theme loaded it follows it; without it, it renders the shipped look.
960
+ - **It ignores the aesthetic around it.** It reads no `--ui-*` or `--elevation-color`, so a `.glass-solo` inside a `.pixel` region keeps its corners. The elevation modifiers do not reach it either.
961
+ - **It beats a foreign component's own styles.** The rules are unlayered and one class deep, so they win over a component's zero-specificity or layered rules wherever the two load. The flip side is that a Tailwind utility on the same element (`rounded-none`) loses to it: tune a solo class through its knobs.
962
+ - **It presses only an action.** Neobrutalism, chunky tile, and cyber press a `button`, `a[href]`, `[role="button"]`, `summary`, or button-type `input` that is not disabled; a container stays put, so a toast does not sink when clicked. Reduced motion drops the movement. Chunky tile's heavier label follows the same rule.
963
+ - **Dark values need a colour scheme.** Light and dark pairs are `light-dark()`, which follows the element's `color-scheme`. The package theme sets it; a page without it gets the light values.
964
+
965
+ Do not put a solo class on this package's own components. On a `.card` it would replace the composed fill, edge, and intent with material alone; use the aesthetic class there.
966
+
847
967
  <!-- Source: docs/usage/buttons.md -->
848
968
 
849
969
  # Buttons
@@ -1088,7 +1208,7 @@ Loader size modifiers:
1088
1208
 
1089
1209
  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.
1090
1210
 
1091
- Skeletons, loaders, progress bars, and dividers are indicators. They read intent but ignore fill and edge [presentation](docs/usage/composing.md#presentation).
1211
+ Skeletons, loaders, and dividers are indicators: they read intent but ignore fill and edge [presentation](docs/usage/composing.md#presentation). `.progress` is not one of them — its track reads both, `.soft.edgeless` by default; only the moving value fill stays intent-colored at full strength regardless of presentation. `.solid` is unsupported on the track, and `.ghost.edgeless` renders but is discouraged, since neither leaves the track a visible frame. See [Composing → Component axis reference](docs/usage/composing.md#component-axis-reference) for the full table.
1092
1212
 
1093
1213
  ```html
1094
1214
  <span class="loader success" aria-hidden="true"></span> <span class="skeleton info"></span>
@@ -1123,6 +1243,7 @@ Alerts and badges read the shared [presentation](docs/usage/composing.md#present
1123
1243
  <span class="loader dots-grow lg" aria-hidden="true"></span>
1124
1244
  <div class="progress" role="progressbar" aria-label="Upload progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="64" style="--progress-value: 64%"></div>
1125
1245
  <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>
1246
+ <div class="progress primary ghost edged" role="progressbar" aria-label="Upload progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="64" style="--progress-value: 64%"></div>
1126
1247
  <div class="progress info indeterminate" role="progressbar" aria-label="Loading" aria-valuemin="0" aria-valuemax="100"></div>
1127
1248
  ```
1128
1249
 
@@ -1648,13 +1769,14 @@ This package provides CSS hooks for accessible states. It does not provide seman
1648
1769
 
1649
1770
  ### Control boundaries
1650
1771
 
1651
- | Feature | Behavior |
1652
- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1653
- | Control boundaries | Text controls rest at `--_line-rest` of their intent, under 3:1 by choice; hover and focus take the tone whole. |
1654
- | Toggle boundaries | `.checkbox`, `.radio`, and `.switch` draw their line whole, because it is the only thing marking an unchecked box. |
1655
- | Cascaded `.edgeless` | Floored on every text control: a container cannot erase the line of a field or toggle nobody classed. |
1656
- | Own `.edgeless` | On the element, `.ipt`, `.textarea`, `.select`, and `.switch` do drop their line and do not meet 1.4.11 at rest, except `.switch.ghost`: `.ghost` already asks for zero fill, so dropping the line too would leave no boundary at all, and `.switch.ghost.edgeless` keeps it up instead. |
1657
- | `.checkbox`/`.radio` | Never drop their line, on the element or from a container. `.edgeless` on them is unsupported, not merely discouraged. |
1772
+ | Feature | Behavior |
1773
+ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1774
+ | Control boundaries | Text controls rest at `--_line-rest` of their intent, under 3:1 by choice; hover and focus take the tone whole. |
1775
+ | Toggle boundaries | `.checkbox`, `.radio`, and `.switch` draw their line whole, because it is the only thing marking an unchecked box. |
1776
+ | Cascaded `.edgeless` | Floored on every text control: a container cannot erase the line of a field or toggle nobody classed. |
1777
+ | Own `.edgeless` | On the element, `.ipt`, `.textarea`, `.select`, and `.switch` do drop their line and do not meet 1.4.11 at rest, except `.switch.ghost`: `.ghost` already asks for zero fill, so dropping the line too would leave no boundary at all, and `.switch.ghost.edgeless` keeps it up instead. |
1778
+ | `.checkbox`/`.radio` | Never drop their line, on the element or from a container. `.edgeless` on them is unsupported, not merely discouraged. |
1779
+ | Progress track | Known gap. `.progress`'s registered default, `.soft.edgeless`, does not meet 1.4.11 at rest -- measured ~1.1-1.3:1 against the page in both themes and across intents, down from the ~3.6-4.3:1 the prior fixed-neutral track cleared. An `.edged` presentation restores a boundary through the line for most intents (`primary.soft.edged` ~15:1), but not every one clears 3:1 there either (`warning.soft.edged` ~2.7:1). A consumer whose track must meet 1.4.11 should choose an `.edged` presentation and verify the intents they use, until this is resolved. |
1658
1780
 
1659
1781
  ### Motion and transparency
1660
1782
 
@@ -1723,6 +1845,29 @@ Use ARIA or data attributes when native attributes are not available for the ele
1723
1845
 
1724
1846
  `aria-disabled="true"` communicates disabled state but does not prevent activation. JavaScript or element choice must prevent activation when required.
1725
1847
 
1848
+ <!-- Source: docs/changelog/0.4.0.md -->
1849
+
1850
+ # 0.4.0
1851
+
1852
+ ## Added
1853
+
1854
+ - **`.cyber`**, a fifth aesthetic from `@codenhub/styles/aesthetics/cyber` (and `/tw/aesthetics/cyber`, and both aggregates): bevelled corners, a 1px edge, and a glow in each component's own colour. Controls cut top-left and bottom-right, surfaces top-right and bottom-left; what is fully round (a radio, a switch, a pill, a badge) cuts to diamonds and pointed hexagons, and chips square. Knobs: `--cyber-cut`, `--cyber-shape`, `--cyber-shape-surface`, `--cyber-glow`, `--cyber-ink`, and the consumer-supplied `--font-cyber`. The bevel is drawn with `corner-shape`, which only Chromium supports today; Firefox and Safari get square cut corners and round round ones. See [Aesthetics → Cyber](docs/usage/aesthetics.md#cyber).
1855
+ - **A solo class for every aesthetic**: `.glass-solo`, `.neobrutalism-solo`, `.pixel-solo`, `.chunky-tile-solo`, and `.cyber-solo` paint the aesthetic's look onto the one element carrying the class, for an element this package does not style -- a toast from another library, or a `<div>` on a page without the base stylesheet. Each ships in its aesthetic's existing entrypoint and needs nothing else loaded. See [Aesthetics → Solo classes](docs/usage/aesthetics.md#solo-classes).
1856
+ - **Three material tokens**: `--ui-corner-shape` (what a corner draws: `round`, or a `bevel` cut), `--ui-radius-pill` (the corner of what is fully round by default), and `--ui-radius-tight` (the corner of chips, before their `--radius-small` cap). All three default to today's look, so nothing changes unless an aesthetic or your own CSS sets them. See [Customizing → Material tokens](docs/usage/customizing.md#material-tokens).
1857
+
1858
+ <!-- Source: docs/changelog/0.3.0.md -->
1859
+
1860
+ # 0.3.0
1861
+
1862
+ ## Added
1863
+
1864
+ - **`@codenhub/styles/palette`**, a generated, self-contained stylesheet of every `intent x presentation` cell's composed colors -- `--palette-<intent>-<presentation>[-<ground>]-<slot>[-hover]` custom properties, already-composited light and dark values, for a consumer that cannot take this package as a build-time dependency (an optional peer, for example) but wants to look consistent with it. Not a replacement for the components themselves when Tailwind is available. Also includes `--palette-border`/`--palette-surface`/`--palette-text`, flat values for the three neutral surface tokens that sit outside the intent x presentation cross. See [Customizing → Generated palette](docs/usage/customizing.md#generated-palette).
1865
+
1866
+ ## Changed
1867
+
1868
+ - **`.progress`'s track reads presentation.** It used to be intent-only, like `.loader`, `.skeleton`, and `.divider`; now it composes a fill and an edge like `.quote` does, while the moving value fill stays `--intent-color` at full strength, unaffected by presentation. The registered default is `.soft.edgeless`, chosen to stay closest to the previous fixed-neutral look, but it renders differently than before: it now tints by intent instead of a fixed grey, and every existing `.progress` gets that new look with no markup change. `.solid` is unsupported on the track (a fully-filled track and the value fill it carries would become the same color); `.ghost.edgeless` renders but is discouraged, since it leaves the track with neither fill nor line.
1869
+ - **Known issue: the new `.progress.soft.edgeless` default does not meet WCAG 1.4.11's 3:1 non-text contrast floor.** Measured at roughly 1.1-1.3:1 against the page, in both themes and across intents -- down from the ~3.6-4.3:1 the prior fixed-neutral track cleared. An `.edged` presentation restores a boundary through the line for most intents, but not all of them clear 3:1 there either (`warning.soft.edged` measured ~2.7:1). A consumer whose track must meet 1.4.11 should choose an `.edged` presentation and verify the intents they use. See [Accessibility](docs/accessibility.md#control-boundaries).
1870
+
1726
1871
  <!-- Source: docs/changelog/0.2.0.md -->
1727
1872
 
1728
1873
  # 0.2.0