actual-css 0.11.0 → 0.12.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 (92) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +29 -5
  3. package/components.json +15 -17
  4. package/dist/actual.full.css +403 -227
  5. package/dist/actual.full.min.css +1 -1
  6. package/docs/brand/favicon.svg +5 -0
  7. package/docs/brand/lockup.svg +12 -0
  8. package/docs/brand/logo-dark.svg +9 -0
  9. package/docs/brand/logo-light.svg +9 -0
  10. package/docs/brand/logo.svg +11 -0
  11. package/docs/brand/mark.svg +11 -0
  12. package/docs/navigation.json +4 -2
  13. package/docs/pages/components/alert.md +2 -10
  14. package/docs/pages/components/badge.md +3 -9
  15. package/docs/pages/components/bleed.md +5 -4
  16. package/docs/pages/components/card.md +31 -2
  17. package/docs/pages/components/close.md +9 -3
  18. package/docs/pages/components/dialog.md +248 -31
  19. package/docs/pages/components/drawer.md +2 -2
  20. package/docs/pages/components/meter.md +2 -0
  21. package/docs/pages/components/navbar.md +8 -9
  22. package/docs/pages/components/table.md +3 -3
  23. package/docs/pages/enhancements/flyout.md +2 -2
  24. package/docs/pages/enhancements/scrollspy.md +1 -1
  25. package/docs/pages/enhancements/status-bar.md +2 -2
  26. package/docs/pages/examples/overview.md +3 -1
  27. package/docs/pages/forms/date-picker.md +90 -0
  28. package/docs/pages/forms/detached-actions.md +37 -30
  29. package/docs/pages/forms/form-actions.md +61 -28
  30. package/docs/pages/forms/input-policy.md +1 -1
  31. package/docs/pages/forms/overview.md +6 -5
  32. package/docs/pages/forms/sticky-actions.md +85 -83
  33. package/docs/pages/forms/validation.md +5 -5
  34. package/docs/pages/foundations/philosophy.md +5 -3
  35. package/docs/pages/foundations/theming.md +15 -4
  36. package/docs/pages/foundations/tokens.md +50 -33
  37. package/docs/pages/foundations/typography.md +4 -7
  38. package/docs/pages/guides/bootstrap.md +2 -2
  39. package/docs/pages/guides/design-tools.md +36 -0
  40. package/docs/pages/guides/integrating-actual-css.md +5 -1
  41. package/docs/pages/guides/introduction.md +3 -4
  42. package/docs/pages/guides/modular-import.md +3 -0
  43. package/docs/pages/guides/progressive-enhancement.md +2 -2
  44. package/docs/pages/guides/tailwind.md +70 -0
  45. package/docs/pages/guides/upgrading.md +74 -0
  46. package/docs/pages/layout/cluster.md +28 -2
  47. package/docs/pages/layout/overview.md +1 -1
  48. package/docs/pages/layout/stack.md +21 -16
  49. package/docs/pages/layout/topbar.md +1 -1
  50. package/docs/pages/patterns/navigation-list.md +16 -46
  51. package/docs/pages/patterns/overview.md +3 -4
  52. package/docs/pages/utilities/flex.md +30 -20
  53. package/docs/pages/utilities/sizing-wrapping.md +1 -1
  54. package/docs/pages/utilities/spacing.md +4 -3
  55. package/package.json +3 -2
  56. package/reserved-classes.json +3 -3
  57. package/skills/actual-css/references/enhancements.md +38 -0
  58. package/src/cli/actual-css.js +75 -6
  59. package/src/css/components/avatar.css +16 -9
  60. package/src/css/components/badge.css +1 -5
  61. package/src/css/components/bleed.css +5 -5
  62. package/src/css/components/button.css +17 -10
  63. package/src/css/components/card.css +18 -10
  64. package/src/css/components/chat.css +4 -5
  65. package/src/css/components/close.css +17 -6
  66. package/src/css/components/drawer.css +19 -3
  67. package/src/css/components/flyout.css +3 -0
  68. package/src/css/components/index.css +0 -1
  69. package/src/css/components/meter.css +5 -2
  70. package/src/css/components/modal.css +157 -69
  71. package/src/css/components/navbar.css +14 -25
  72. package/src/css/core/base.css +1 -1
  73. package/src/css/core/reset.css +2 -1
  74. package/src/css/core/theme.css +4 -0
  75. package/src/css/core/tokens.css +28 -10
  76. package/src/css/core/variants.css +41 -14
  77. package/src/css/forms/form-actions.css +15 -10
  78. package/src/css/forms/native.css +5 -1
  79. package/src/css/layout/cluster.css +11 -0
  80. package/src/css/layout/topbar.css +12 -6
  81. package/src/css/utilities/base.css +5 -0
  82. package/src/css/utilities/extra.css +3 -7
  83. package/src/tooling/color.js +65 -0
  84. package/src/tooling/design-components.js +286 -0
  85. package/src/tooling/design-export.js +69 -0
  86. package/src/tooling/design-tokens.js +474 -0
  87. package/src/tooling/penpot-plugin/manifest.json +7 -0
  88. package/src/tooling/penpot-plugin/plugin.js +272 -0
  89. package/src/tooling/penpot-plugin/ui.html +58 -0
  90. package/src/tooling/theme-contrast.js +209 -0
  91. package/docs/pages/patterns/actions.md +0 -52
  92. package/src/css/components/actions.css +0 -27
@@ -70,6 +70,8 @@ marker to that background rather than to the neutral intent.
70
70
 
71
71
  ### Hooks
72
72
 
73
+ - `--meter-track` — track color; raise it when the meter sits on a
74
+ `--surface-subtle` card, where the default track would disappear.
73
75
  - `--bar-height` — bar thickness, shared with `.progress`.
74
76
  - `--meter-value` — relative weight of a direct child in a segmented meter.
75
77
 
@@ -1,10 +1,10 @@
1
1
  # Navbar
2
2
 
3
- > Horizontal top-level navigation bar with a brand, an inline link list, and a vertical nav-list for drawers.
3
+ > Horizontal top-level navigation bar with a brand, an inline `.cluster` link list, and a vertical `.nav-list` for drawers.
4
4
 
5
5
  - Use `.navbar` for the horizontal bar shell.
6
6
  - `.navbar-brand` is the brand link at the inline start.
7
- - `.navbar-nav` is the horizontal link list; its items are `.nav-link`.
7
+ - Horizontal links live in a `.cluster`; its items are `.nav-link`.
8
8
  - `.nav-list` is the shared vertical navigation list, reused by `.drawer` for stacked links.
9
9
  - Mark the current page with `aria-current="page"` on the active `.nav-link`.
10
10
  - Presence is the contract: set `aria-current` on the current link and remove
@@ -15,9 +15,9 @@ For a public or normally scrolling page, `.navbar` belongs inside the semantic
15
15
  site header. Do not use `.topbar` or `.app-layout` unless the page actually has
16
16
  the specialized persistent application-shell behavior those APIs describe.
17
17
 
18
- `.navbar-nav` and `.nav-list` are mutually exclusive: `.navbar-nav` is a horizontal
19
- flex list, `.nav-list` a vertical grid. Putting both on one element resolves to
20
- `.nav-list` (vertical) — pick one per container.
18
+ Horizontal navbar links use a `.cluster`. Use `.nav-list` when the navigation
19
+ becomes a full-width vertical list. The two are distinct contracts, so pick one
20
+ per container.
21
21
 
22
22
  `.navbar` stays the horizontal bar for a site or webapp header with a brand and
23
23
  normal document scrolling. `.app-nav` is not merely a stacked-icon flavour of it:
@@ -32,7 +32,6 @@ icons. See [App Navigation](app-navigation.md).
32
32
  | --------------- | ----------- | ----------------------------------------------------- |
33
33
  | `.navbar` | Component | Horizontal bar shell. |
34
34
  | `.navbar-brand` | Composition | Brand link at the inline start. |
35
- | `.navbar-nav` | Composition | Horizontal link list. |
36
35
  | `.nav-link` | Component | A link item; current page via `aria-current="page"`. |
37
36
  | `.nav-list` | Component | Shared vertical navigation list, reused by `.drawer`. |
38
37
 
@@ -41,7 +40,7 @@ icons. See [App Navigation](app-navigation.md).
41
40
  ```html demo
42
41
  <nav class="navbar" aria-label="Main">
43
42
  <a class="navbar-brand" href="/">Actual CSS</a>
44
- <ul class="navbar-nav">
43
+ <ul class="cluster">
45
44
  <li><a class="nav-link" href="/docs" aria-current="page">Docs</a></li>
46
45
  <li><a class="nav-link" href="/components">Components</a></li>
47
46
  <li><a class="nav-link" href="/examples">Examples</a></li>
@@ -70,7 +69,7 @@ accessible name.
70
69
  ```html demo
71
70
  <nav class="navbar" aria-label="Main">
72
71
  <a class="navbar-brand" href="/">Actual CSS</a>
73
- <ul class="navbar-nav">
72
+ <ul class="cluster">
74
73
  <li><a class="nav-link" href="/" aria-current="page">Home</a></li>
75
74
  <li><a class="nav-link" href="/docs">Docs</a></li>
76
75
  </ul>
@@ -99,7 +98,7 @@ accessible name.
99
98
  </header>
100
99
 
101
100
  <nav>
102
- <ul class="nav-list stack">
101
+ <ul class="nav-list">
103
102
  <li><a class="nav-link" href="#" aria-current="page">Home</a></li>
104
103
  <li><a class="nav-link" href="#">Docs</a></li>
105
104
  <li><a class="nav-link" href="#">Components</a></li>
@@ -101,9 +101,9 @@ table width before the wrapper scrolls horizontally.
101
101
  ## Compact tables
102
102
 
103
103
  `.compact` lowers cell padding and establishes compact density for controls or
104
- spacing helpers inside cells. Font size and icons stay unchanged; the framework's
105
- denser font width may apply when the typeface supports it. It is the
106
- same vocabulary as `.card.compact`.
104
+ spacing helpers inside cells. The text stays as set; a data-heavy table that
105
+ also wants condensed type sets `font-stretch` on itself. It is the same
106
+ vocabulary as `.card.compact`.
107
107
 
108
108
  ```html demo
109
109
  <div class="table-wrap">
@@ -322,7 +322,7 @@ can be multi-column with `<section>` / `<ul>` groups.
322
322
 
323
323
  ```html demo
324
324
  <nav aria-label="Main navigation">
325
- <ul class="list-reset cluster">
325
+ <ul class="cluster">
326
326
  <li class="flyout-trigger">
327
327
  <button class="btn ghost"
328
328
  type="button"
@@ -373,7 +373,7 @@ a separate `dialog.drawer` when the content needs a modal mobile presentation.
373
373
 
374
374
  ```html demo
375
375
  <nav aria-label="Product navigation">
376
- <ul class="list-reset cluster">
376
+ <ul class="cluster">
377
377
  <li class="flyout-trigger">
378
378
  <button class="btn ghost"
379
379
  type="button"
@@ -26,7 +26,7 @@ or style `[aria-current]` yourself.
26
26
 
27
27
  ```html demo
28
28
  <nav class="scrollspy" data-enhance="scrollspy" aria-label="Page sections">
29
- <ol class="nav-list stack">
29
+ <ol class="nav-list">
30
30
  <li><a class="nav-link" href="#overview" aria-current="location">Overview</a></li>
31
31
  <li><a class="nav-link" href="#tokens">Tokens</a></li>
32
32
  <li><a class="nav-link" href="#components">Components</a></li>
@@ -31,14 +31,14 @@ fails to submit shows its `data-validation-message` in the status bar with the
31
31
  stays optional.
32
32
 
33
33
  ```html demo
34
- <form class="needs-validation" data-enhance="validation" data-validation-message="Please check the highlighted fields.">
34
+ <form class="stack needs-validation" data-enhance="validation" data-validation-message="Please check the highlighted fields.">
35
35
  <label class="field">
36
36
  <span class="field-label">Email</span>
37
37
  <input class="input" type="email" name="email" required
38
38
  aria-describedby="sb-email-error" />
39
39
  <span class="field-error" id="sb-email-error" role="alert">Enter a valid email.</span>
40
40
  </label>
41
- <div class="form-actions">
41
+ <div class="cluster form-actions">
42
42
  <button class="btn primary" type="submit">Submit</button>
43
43
  </div>
44
44
  </form>
@@ -14,7 +14,7 @@ rest show it composed, isolated, or under stress.
14
14
 
15
15
  ### Start here
16
16
 
17
- - [Visual guide](../../demo/templates/visual-guide.html) - seventeen illustrated figures on the spacing scale, the layout primitives, and density versus local size
17
+ - [Visual guide](../../demo/templates/visual-guide.html) - twenty illustrated figures on the spacing scale, the layout primitives, and rhythm versus density versus local size
18
18
  - [Color guide](../../demo/templates/color-guide.html) - theming principles measured live on `ocean` and `sunset`, in light and dark, as `data-theme` islands
19
19
  - [Kitchen sink](../../demo/templates/kitchen-sink.html) - one-screen test bed for themes, scopes, variants and interactions
20
20
 
@@ -28,6 +28,7 @@ Whole pages, composed the way a real product would.
28
28
  - [Marketing](../../demo/templates/marketing.html) - landing page with typography and fluid type
29
29
  - [Blog](../../demo/templates/blog.html) - article page with prose
30
30
  - [Settings modal](../../demo/templates/settings-modal.html) - two-pane preferences dialog, with the local CSS it needs audited rule by rule
31
+ - [Modal patterns](../../demo/templates/modal-patterns.html) - eight application modals, each the modal surface plus the smallest application CSS it needs
31
32
  - [Workspace settings](../../demo/templates/settings-pricing.html) - plans with visible native choices, preferences and a local segmented tab treatment
32
33
  - [Card compositions](../../demo/templates/card-compositions.html) - editorial, team, sign-in and horizontal cards composed from existing primitives
33
34
  - [Register form](../../demo/templates/register-form.html) - registration page with choice cards, masks, the password toggle, `tel-prefix` validation, an OTP verification dialog, and status feedback
@@ -59,6 +60,7 @@ extension points.
59
60
 
60
61
  - [Data grid](../../demo/templates/data-grid.html) - an external data grid component themed with Actual tokens (sort, filter, search, selection)
61
62
  - [Combobox](../../demo/templates/combobox.html) - an external combobox themed with Actual tokens (search, tags, autocomplete)
63
+ - [Date fields](../../demo/templates/date-fields.html) - a native date input, a masked text field and an external date picker on Actual tokens, side by side
62
64
 
63
65
  ## Sites
64
66
 
@@ -0,0 +1,90 @@
1
+ # Date picker
2
+
3
+ > A JavaScript date picker is not shipped by the framework — the native `<input type="date">` stays the baseline. Use `data-mask` for a fixed text shape, or theme an external picker with Actual tokens.
4
+
5
+ The native control is the default: a real calendar, no JavaScript, and an ISO
6
+ `yyyy-mm-dd` value whatever the platform displays. Reach for an external picker
7
+ only when the product needs a shape the native control cannot express — a month
8
+ grid for a range, a typed constraint, a styled calendar.
9
+
10
+ **Related terms:** date field, datepicker, calendar, native date, date input, masked date, input mask, date range.
11
+
12
+ ## Native baseline
13
+
14
+ ```html demo
15
+ <label class="field">
16
+ <span class="field-label">Start date</span>
17
+ <input class="input" type="date" />
18
+ </label>
19
+ ```
20
+
21
+ ## Masked text field
22
+
23
+ `data-mask` structures a plain text field to a fixed shape and the `date` rule
24
+ validates meaning. The mask enforces shape, not validity, so `2026-13-40` needs
25
+ the rule (or server validation).
26
+
27
+ ```html demo
28
+ <label class="field">
29
+ <span class="field-label">Date</span>
30
+ <input class="input" data-mask="9999-99-99" inputmode="numeric" autocomplete="off" placeholder="yyyy-mm-dd" />
31
+ </label>
32
+ ```
33
+
34
+ ## Theme bridge
35
+
36
+ The [date fields template](../../demo/templates/date-fields.html) puts the native
37
+ control, the masked field and
38
+ [`@lekoala/date-picker`](https://github.com/lekoala/date-picker) side by side, the
39
+ picker skinned entirely with Actual tokens.
40
+
41
+ ```html
42
+ <label class="field">
43
+ <span class="field-label">Booking date</span>
44
+ <date-picker value="2026-09-25" open-on-focus="false">
45
+ <input class="input" name="date">
46
+ </date-picker>
47
+ </label>
48
+ ```
49
+
50
+ ```css
51
+ date-picker,
52
+ date-calendar {
53
+ --dp-bg: var(--surface-raised);
54
+ --dp-fg: var(--text);
55
+ --dp-muted: var(--text-muted);
56
+ --dp-border: var(--border);
57
+ --dp-hover: var(--surface-subtle);
58
+ --dp-accent: var(--primary);
59
+ --dp-accent-fg: var(--primary-fg);
60
+ --dp-radius: var(--radius);
61
+ /* Trigger glyph on the select chevron axis. */
62
+ --dp-picker-button-size: calc(var(--control-pad-x) * 2 + 1em + var(--border-width) * 2);
63
+ }
64
+
65
+ .dp-calendar-header :where(button, select, input):focus-visible {
66
+ border-color: var(--dp-border);
67
+ outline: var(--focus-ring-width) solid var(--focus);
68
+ outline-offset: calc(var(--focus-ring-width) * -1);
69
+ box-shadow: none;
70
+ }
71
+
72
+ .dp-picker-button:focus-visible,
73
+ .dp-day:focus-visible {
74
+ outline-color: var(--focus);
75
+ }
76
+ ```
77
+
78
+ The field is a plain `.input`, so the core inset focus outline already outranks
79
+ the library's halo; the calendar's own controls paint a `--dp-accent` halo, so
80
+ the two focus rules map them onto the core outline. The calendar popup is its own
81
+ element, so the `--dp-*` map is declared on `date-picker`/`date-calendar` rather
82
+ than inherited from a wrapper.
83
+ As with the combobox, the bridge stays in docs/demo — it is a recipe, not package
84
+ API, and pins no widget version.
85
+
86
+ ## Which one?
87
+
88
+ - A plain date the platform can collect: native `<input type="date">`.
89
+ - A fixed text format that must survive as typed text: `data-mask` plus the `date` rule.
90
+ - A calendar, range, or constraint the native control cannot express: an external picker on the token bridge.
@@ -5,12 +5,12 @@
5
5
  The simplest case stays inside the form.
6
6
 
7
7
  ```html
8
- <form novalidate>
8
+ <form class="stack" novalidate>
9
9
  <div class="stack">
10
10
  <!-- fields -->
11
11
  </div>
12
12
 
13
- <div class="form-actions">
13
+ <div class="cluster form-actions">
14
14
  <button type="button" class="btn outline">Cancel</button>
15
15
  <button type="submit" class="btn primary">Save changes</button>
16
16
  </div>
@@ -20,40 +20,47 @@ The simplest case stays inside the form.
20
20
  For sticky page footers, dialog footers, card footers, and split layouts, detach the actions and connect the submit button with `form="<id>"`.
21
21
 
22
22
  ```html
23
- <form id="profile-form" novalidate>
24
- <div class="stack">
25
- <!-- long form fields -->
26
- </div>
27
- </form>
23
+ <div class="stack">
24
+ <form id="profile-form" novalidate>
25
+ <div class="stack">
26
+ <!-- long form fields -->
27
+ </div>
28
+ </form>
28
29
 
29
- <footer class="form-actions">
30
- <button type="button" class="btn outline">Cancel</button>
31
- <button type="submit" class="btn primary" form="profile-form">
32
- Save changes
33
- </button>
34
- </footer>
30
+ <footer class="cluster form-actions">
31
+ <button type="button" class="btn outline">Cancel</button>
32
+ <button type="submit" class="btn primary" form="profile-form">
33
+ Save changes
34
+ </button>
35
+ </footer>
36
+ </div>
35
37
  ```
36
38
 
39
+ The wrapper that holds the form and its detached actions owns the distance
40
+ between them: give it `.stack`.
41
+
37
42
  For multiple submit intents, pair the `form` attribute with `formaction`. The form has one action; each submit button can override it.
38
43
 
39
44
  ```html
40
- <form id="article-form"
41
- action="/articles/publish"
42
- method="post">
43
- <!-- fields -->
44
- </form>
45
+ <div class="stack">
46
+ <form id="article-form"
47
+ action="/articles/publish"
48
+ method="post">
49
+ <!-- fields -->
50
+ </form>
45
51
 
46
- <div class="form-actions">
47
- <button type="submit"
48
- class="btn outline"
49
- form="article-form"
50
- formaction="/articles/draft">
51
- Save draft
52
- </button>
53
- <button type="submit"
54
- class="btn primary"
55
- form="article-form">
56
- Publish
57
- </button>
52
+ <div class="cluster form-actions">
53
+ <button type="submit"
54
+ class="btn outline"
55
+ form="article-form"
56
+ formaction="/articles/draft">
57
+ Save draft
58
+ </button>
59
+ <button type="submit"
60
+ class="btn primary"
61
+ form="article-form">
62
+ Publish
63
+ </button>
64
+ </div>
58
65
  </div>
59
66
  ```
@@ -1,20 +1,25 @@
1
1
  # Form Actions
2
2
 
3
- > `.form-actions` is a class-only flex row that closes a form. It may live
4
- > inside or outside the `<form>` (see Detached Actions) and has an opt-in
3
+ > `.form-actions` is the role of the `.cluster` row that closes a form. It may
4
+ > live inside or outside the `<form>` (see Detached Actions) and has an opt-in
5
5
  > sticky variant (see Sticky Actions).
6
6
 
7
- The default layout is a wrapping flex row: items are centered on the cross
8
- axis and start-aligned on the main axis, with a default top margin that
9
- separates the actions from the fields above.
7
+ `.cluster` owns the row: flex, wrap and gap. `.form-actions` adds the alignment
8
+ policy for form actions and the sticky behaviour. The space before the row
9
+ belongs to the parent layout: put `.stack` on the form.
10
10
 
11
- ```html
12
- <form novalidate>
13
- <div class="stack">
14
- <!-- fields -->
15
- </div>
11
+ `.form-actions` refines `.cluster` with alignment rules of equal specificity,
12
+ so it wins on import order. In a modular build, import `layout/cluster` before
13
+ `forms/form-actions`; the family entries and the full bundle already do.
14
+
15
+ ```html demo
16
+ <form class="stack" novalidate>
17
+ <label class="field">
18
+ <span class="field-label">Project name</span>
19
+ <input class="input" type="text" value="Atlas" />
20
+ </label>
16
21
 
17
- <div class="form-actions">
22
+ <div class="cluster form-actions">
18
23
  <button type="button" class="btn outline">Cancel</button>
19
24
  <button type="submit" class="btn primary">Save changes</button>
20
25
  </div>
@@ -23,34 +28,62 @@ separates the actions from the fields above.
23
28
 
24
29
  ## CSS hooks
25
30
 
26
- The three layout hooks are unset by default and fall back to the values below.
31
+ - `--form-actions-justify` — main-axis distribution (`justify-content`).
32
+ - `--form-actions-align` — cross-axis alignment (`align-items`).
27
33
 
28
- - `--form-actions-align` — `center` — cross-axis alignment (`align-items`).
29
- - `--form-actions-justify` — `flex-start` — main-axis distribution (`justify-content`).
30
- - `--form-actions-margin-block-start` — `var(--space-50)` — top margin separating actions from the form.
34
+ Both are inherited role hooks: set them on a page or container to align every
35
+ form action row inside it, without touching other clusters. Below, the
36
+ container right-aligns the form actions while the tag row, also a `.cluster`,
37
+ keeps its start alignment.
31
38
 
32
- ### Common arrangements
39
+ ```html demo
40
+ <section class="stack" style="--form-actions-justify: flex-end">
41
+ <div class="cluster">
42
+ <span class="badge">Draft</span>
43
+ <span class="badge">Internal</span>
44
+ </div>
33
45
 
34
- Right-align the submit on wide rows:
46
+ <form class="stack" novalidate>
47
+ <label class="field">
48
+ <span class="field-label">Release title</span>
49
+ <input class="input" type="text" value="Autumn update" />
50
+ </label>
35
51
 
36
- ```css
37
- .form-actions {
38
- --form-actions-justify: flex-end;
39
- }
52
+ <div class="cluster form-actions">
53
+ <button type="button" class="btn outline">Cancel</button>
54
+ <button type="submit" class="btn primary">Publish</button>
55
+ </div>
56
+ </form>
57
+ </section>
40
58
  ```
41
59
 
42
- Stretch each action to fill the full row width:
60
+ In application CSS, the same policy is one declaration on the region:
43
61
 
44
62
  ```css
45
- .form-actions {
46
- --form-actions-align: stretch;
63
+ .checkout {
64
+ --form-actions-justify: flex-end;
47
65
  }
48
66
  ```
49
67
 
50
- Because the hooks are inherited custom properties, set them on a page or
51
- container to apply one arrangement to every `.form-actions` inside it.
68
+ On a form action row, `--cluster-justify` and `--cluster-align` have no effect;
69
+ use the hooks above, or a `.justify-content-*` / `.items-*` utility on one row.
70
+ A split pair keeps the dismissive action at the leading edge and the committing
71
+ one at the trailing edge:
72
+
73
+ ```html demo
74
+ <form class="stack" novalidate>
75
+ <label class="field">
76
+ <span class="field-label">Display name</span>
77
+ <input class="input" type="text" value="Jane Doe" />
78
+ </label>
79
+
80
+ <div class="cluster form-actions justify-content-space-between">
81
+ <button type="button" class="btn outline">Cancel</button>
82
+ <button type="submit" class="btn primary">Save</button>
83
+ </div>
84
+ </form>
85
+ ```
52
86
 
53
87
  > The sticky variant adds `--form-actions-sticky-block-offset`,
54
88
  > `--form-actions-sticky-padding`, and `--form-actions-sticky-inline-offset` —
55
- > see Sticky Actions. `.form-actions` is class-only and works inside or
56
- > outside the form — see Detached Actions.
89
+ > see Sticky Actions.
@@ -124,7 +124,7 @@ of the value and never rewrites it.
124
124
  </span>
125
125
  </label>
126
126
 
127
- <div class="form-actions">
127
+ <div class="cluster form-actions">
128
128
  <button class="btn primary" type="submit">Submit</button>
129
129
  <button class="btn neutral outline" type="reset">Reset</button>
130
130
  </div>
@@ -10,6 +10,7 @@
10
10
  - `.field-group` and `.choice` provide layout without depending on parent scope.
11
11
  - Customizable select is progressive enhancement only — the native select remains the baseline.
12
12
  - Searchable selects, tags and autocomplete are a JavaScript widget concern; theme an external combobox with Actual tokens — see the [combobox template](../../demo/templates/combobox.html).
13
+ - A date is native `<input type="date">` first; use `data-mask` for a fixed text shape, or theme an external picker — see [date picker](date-picker.md) and the [date fields template](../../demo/templates/date-fields.html).
13
14
  - Formatted text (bold, lists, links) is a hosted-editor concern; the native textarea stays the baseline and an external engine is themed the same way — see the [rich-text template](../../demo/templates/rich-text.html) and the [composer template](../../demo/templates/composer.html) for the plain-text case.
14
15
 
15
16
  **Related terms:** form controls, select, custom select, dropdown, input, textarea, checkbox, radio.
@@ -33,7 +34,7 @@
33
34
  | `.field-error` | Composition | Inline error message, shown while invalid. |
34
35
  | `.field-group` | Composition | `<fieldset>` with a tunable legend gutter. |
35
36
  | `.choice` | Composition | Choice-label layout around an inline control. |
36
- | `.form-actions` | Composition | Class-only flex row that closes a form. |
37
+ | `.form-actions` | Composition | Role of the `.cluster` row closing a form. |
37
38
 
38
39
  `.input` shares the text-control recipe with `.textarea` and `.select`, and
39
40
  `.select` also has an opt-in enhanced picker. `.field-label` works on a
@@ -46,7 +47,7 @@
46
47
  A full form using the control classes, field wrappers, and form actions:
47
48
 
48
49
  ```html demo
49
- <form novalidate>
50
+ <form class="stack" novalidate>
50
51
  <div class="stack">
51
52
 
52
53
  <label class="field">
@@ -101,7 +102,7 @@ A full form using the control classes, field wrappers, and form actions:
101
102
 
102
103
  <fieldset class="field-group">
103
104
  <legend class="field-label">Availability</legend>
104
- <div class="stack compact">
105
+ <div class="stack tight">
105
106
  <label class="choice">
106
107
  <input class="radio" type="radio" name="availability" value="available" checked />
107
108
  <span>Available for work</span>
@@ -161,7 +162,7 @@ A full form using the control classes, field wrappers, and form actions:
161
162
 
162
163
  </div>
163
164
 
164
- <div class="form-actions">
165
+ <div class="cluster form-actions">
165
166
  <button type="button" class="btn outline">Cancel</button>
166
167
  <button type="submit" class="btn primary">Save changes</button>
167
168
  </div>
@@ -185,7 +186,7 @@ it a stronger fill.
185
186
  - `.choice` is the choice-label API. Use `.check` or `.radio` on the nested control. The control goes first, the label group second, so multi-line labels align the control with the first line.
186
187
  - For a switch, use `class="switch"` and `role="switch"`.
187
188
  - `.range` skins the native range control (`appearance: none` track, thumb, and focus ring). Add `data-enhance="range"` for the fill share, named `datalist` values, and output sync.
188
- - `.form-actions` carries a default top margin. Override it with `--form-actions-margin-block-start`, `--form-actions-align`, or `--form-actions-justify`. It is class-only and may live inside or outside `<form>`. See Detached Actions below.
189
+ - `.form-actions` is the role of a `.cluster` row (`class="cluster form-actions"`) and carries no outer margin: `.stack` on the form spaces it from the fields. It is class-only and may live inside or outside `<form>`. See Detached Actions below.
189
190
  - `.join` visually joins adjacent controls into a single unit. Use `.join-addon` for static prefix/suffix content. The container still carries `role="group"` for accessibility.
190
191
 
191
192
  ## Optional automatic required marks