actual-css 0.2.0 → 0.3.1

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 (214) hide show
  1. package/CHANGELOG.md +49 -1
  2. package/README.md +24 -9
  3. package/dist/actual-themes.min.css +1 -0
  4. package/dist/actual.css +1532 -1114
  5. package/dist/actual.js +1 -3
  6. package/dist/actual.min.css +1 -1
  7. package/dist/optional.css +1048 -0
  8. package/dist/optional.min.css +1 -0
  9. package/docs/design-notes/browser-support.md +94 -14
  10. package/docs/design-notes/cascade-layer.md +7 -6
  11. package/docs/design-notes/enhancement-contract.md +11 -14
  12. package/docs/design-notes/forced-colors.md +105 -0
  13. package/docs/design-notes/naming.md +2 -1
  14. package/docs/design-notes/platform-alignment.md +492 -0
  15. package/docs/design-notes/references.md +8 -0
  16. package/docs/design-notes/widget-primitives.md +37 -1
  17. package/docs/navigation.json +135 -0
  18. package/docs/pages/components/accordion.md +80 -0
  19. package/docs/pages/components/alert.md +203 -0
  20. package/docs/pages/components/aura.md +35 -0
  21. package/docs/pages/components/avatar.md +95 -0
  22. package/docs/pages/components/badge.md +102 -0
  23. package/docs/pages/components/breadcrumb.md +19 -0
  24. package/docs/pages/components/button.md +210 -0
  25. package/docs/pages/components/card.md +195 -0
  26. package/docs/pages/components/chat.md +50 -0
  27. package/docs/pages/components/dialog.md +367 -0
  28. package/docs/pages/components/drawer.md +113 -0
  29. package/docs/pages/components/fab.md +118 -0
  30. package/docs/pages/components/key.md +33 -0
  31. package/docs/pages/components/meter.md +23 -0
  32. package/docs/pages/components/navbar.md +92 -0
  33. package/docs/pages/components/pagination.md +55 -0
  34. package/docs/pages/components/progress.md +29 -0
  35. package/docs/pages/components/skeleton.md +38 -0
  36. package/docs/pages/components/spinner.md +93 -0
  37. package/docs/pages/components/table.md +102 -0
  38. package/docs/pages/enhancements/flyout.md +391 -0
  39. package/docs/pages/enhancements/overview.md +36 -0
  40. package/docs/pages/enhancements/scrollspy.md +71 -0
  41. package/docs/pages/enhancements/status-bar.md +72 -0
  42. package/docs/pages/enhancements/tabs.md +80 -0
  43. package/docs/pages/enhancements/tooltip.md +130 -0
  44. package/docs/pages/examples/overview.md +43 -0
  45. package/docs/pages/forms/choice-cards.md +102 -0
  46. package/docs/pages/forms/controls.md +32 -0
  47. package/docs/pages/forms/detached-actions.md +59 -0
  48. package/docs/pages/forms/floating-field.md +88 -0
  49. package/docs/pages/forms/form-actions.md +56 -0
  50. package/docs/pages/forms/input-policy.md +91 -0
  51. package/docs/pages/forms/joined-controls.md +37 -0
  52. package/docs/pages/forms/labels.md +42 -0
  53. package/docs/pages/forms/otp.md +50 -0
  54. package/docs/pages/forms/overview.md +188 -0
  55. package/docs/pages/forms/password.md +40 -0
  56. package/docs/pages/forms/range.md +17 -0
  57. package/docs/pages/forms/states-and-sizes.md +321 -0
  58. package/docs/pages/forms/sticky-actions.md +187 -0
  59. package/docs/pages/forms/switch.md +31 -0
  60. package/docs/pages/forms/validation.md +241 -0
  61. package/docs/{mental-model.md → pages/foundations/philosophy.md} +33 -18
  62. package/docs/pages/foundations/theming.md +99 -0
  63. package/docs/pages/foundations/tokens.md +421 -0
  64. package/docs/{typography.md → pages/foundations/typography.md} +27 -9
  65. package/docs/pages/guides/bootstrap.md +438 -0
  66. package/docs/pages/guides/introduction.md +157 -0
  67. package/docs/pages/guides/optional-components.md +33 -0
  68. package/docs/pages/guides/progressive-enhancement.md +686 -0
  69. package/docs/pages/guides/tailwind.md +455 -0
  70. package/docs/pages/layout/app-shell.md +25 -0
  71. package/docs/pages/layout/center.md +29 -0
  72. package/docs/pages/layout/cluster.md +59 -0
  73. package/docs/pages/layout/frame.md +30 -0
  74. package/docs/pages/layout/grid.md +142 -0
  75. package/docs/pages/layout/list.md +41 -0
  76. package/docs/pages/layout/media.md +28 -0
  77. package/docs/pages/layout/overview.md +37 -0
  78. package/docs/pages/layout/scroll-snap.md +54 -0
  79. package/docs/pages/layout/sidebar-layout.md +27 -0
  80. package/docs/pages/layout/stack.md +55 -0
  81. package/docs/pages/layout/switcher.md +36 -0
  82. package/docs/pages/layout/topbar.md +23 -0
  83. package/docs/pages/patterns/actions.md +52 -0
  84. package/docs/pages/patterns/code-block.md +36 -0
  85. package/docs/pages/patterns/exclusive-accordion.md +16 -0
  86. package/docs/pages/patterns/hierarchical-nav.md +26 -0
  87. package/docs/pages/patterns/icon-input.md +25 -0
  88. package/docs/pages/patterns/intent-nesting.md +3 -0
  89. package/docs/pages/patterns/navigation-list.md +235 -0
  90. package/docs/pages/patterns/overview.md +58 -0
  91. package/docs/pages/patterns/structured-lists.md +47 -0
  92. package/docs/pages/utilities/accessibility.md +34 -0
  93. package/docs/pages/utilities/flex.md +105 -0
  94. package/docs/pages/utilities/links.md +18 -0
  95. package/docs/pages/utilities/list.md +32 -0
  96. package/docs/pages/utilities/overflow.md +43 -0
  97. package/docs/pages/utilities/overview.md +18 -0
  98. package/docs/pages/utilities/shape.md +25 -0
  99. package/docs/pages/utilities/sizing-wrapping.md +115 -0
  100. package/docs/pages/utilities/spacing.md +79 -0
  101. package/docs/pages/utilities/text.md +43 -0
  102. package/llms.txt +4 -4
  103. package/package.json +21 -12
  104. package/src/css/actual.css +16 -2
  105. package/src/css/base.css +3 -5
  106. package/src/css/components/accordion.css +18 -30
  107. package/src/css/components/actions.css +4 -1
  108. package/src/css/components/alert.css +139 -102
  109. package/src/css/components/avatar.css +16 -10
  110. package/src/css/components/badge.css +69 -42
  111. package/src/css/components/breadcrumb.css +7 -15
  112. package/src/css/components/busy.css +6 -0
  113. package/src/css/components/button.css +84 -34
  114. package/src/css/components/card.css +26 -38
  115. package/src/css/components/drawer.css +30 -13
  116. package/src/css/components/flyout.css +39 -109
  117. package/src/css/components/index.css +1 -0
  118. package/src/css/components/join.css +14 -2
  119. package/src/css/components/key.css +2 -0
  120. package/src/css/components/menu.css +125 -0
  121. package/src/css/components/meter.css +0 -23
  122. package/src/css/components/modal.css +162 -7
  123. package/src/css/components/navbar.css +30 -23
  124. package/src/css/components/overline.css +8 -9
  125. package/src/css/components/pagination.css +1 -1
  126. package/src/css/components/progress.css +8 -26
  127. package/src/css/components/skeleton.css +7 -0
  128. package/src/css/components/spinner.css +6 -7
  129. package/src/css/components/status-bar.css +15 -24
  130. package/src/css/components/surface.css +2 -8
  131. package/src/css/components/tab.css +19 -48
  132. package/src/css/components/table.css +7 -5
  133. package/src/css/components/tooltip.css +14 -7
  134. package/src/css/focus.css +14 -38
  135. package/src/css/forms/choice-card.css +13 -14
  136. package/src/css/forms/choice.css +21 -27
  137. package/src/css/forms/control.css +18 -17
  138. package/src/css/forms/custom-select.css +9 -11
  139. package/src/css/forms/form-actions.css +14 -3
  140. package/src/css/forms/form.css +7 -4
  141. package/src/css/forms/index.css +4 -4
  142. package/src/css/forms/input-icon.css +30 -12
  143. package/src/css/forms/native.css +50 -11
  144. package/src/css/forms/range.css +17 -9
  145. package/src/css/forms/select.css +8 -8
  146. package/src/css/forms/switch.css +14 -12
  147. package/src/css/forms/validation.css +32 -5
  148. package/src/css/grid.css +32 -18
  149. package/src/css/intents.css +2 -2
  150. package/src/css/layout.css +45 -2
  151. package/src/css/optional/aura.css +93 -0
  152. package/src/css/optional/chat.css +105 -0
  153. package/src/css/optional/fab.css +104 -0
  154. package/src/css/optional/floating-field.css +87 -0
  155. package/src/css/optional/index.css +5 -0
  156. package/src/css/optional/layout-extra.css +7 -4
  157. package/src/css/optional/otp.css +115 -0
  158. package/src/css/optional/scroll-snap.css +6 -0
  159. package/src/css/optional/scroller.css +13 -7
  160. package/src/css/optional/typography-fluid.css +5 -0
  161. package/src/css/optional/utilities-extra.css +17 -2
  162. package/src/css/prose.css +18 -8
  163. package/src/css/reset.css +0 -10
  164. package/src/css/theme.css +21 -5
  165. package/src/css/themes/cyberpunk.css +1 -1
  166. package/src/css/themes/dim.css +3 -3
  167. package/src/css/themes/edge.css +8 -10
  168. package/src/css/themes/index.css +8 -4
  169. package/src/css/themes/{dark.css → indigo.css} +5 -4
  170. package/src/css/themes/neon.css +5 -5
  171. package/src/css/themes/square.css +0 -3
  172. package/src/css/tokens.css +74 -20
  173. package/src/css/utilities.css +8 -10
  174. package/src/css/variants.css +51 -66
  175. package/src/js/command.js +1 -3
  176. package/src/js/context-menu.js +67 -35
  177. package/src/js/dialog.js +68 -79
  178. package/src/js/dismiss.js +15 -0
  179. package/src/js/enhance.js +54 -23
  180. package/src/js/enhancement-loader.js +301 -0
  181. package/src/js/events.js +3 -0
  182. package/src/js/filter.js +3 -3
  183. package/src/js/floating.js +101 -131
  184. package/src/js/flyout.js +104 -87
  185. package/src/js/focus-group.js +116 -0
  186. package/src/js/focus.js +6 -1
  187. package/src/js/index.js +4 -2
  188. package/src/js/input.js +1 -1
  189. package/src/js/keys.js +27 -0
  190. package/src/js/mask.js +7 -6
  191. package/src/js/menu.js +87 -34
  192. package/src/js/parse-config.js +47 -0
  193. package/src/js/password.js +9 -1
  194. package/src/js/scrollspy.js +12 -4
  195. package/src/js/selectors.js +0 -7
  196. package/src/js/status.js +3 -1
  197. package/src/js/surface.js +187 -136
  198. package/src/js/tab.js +36 -53
  199. package/src/js/tooltip.js +70 -35
  200. package/src/js/validation.js +34 -8
  201. package/dist/actual.js.map +0 -31
  202. package/docs/README.md +0 -28
  203. package/docs/components.md +0 -860
  204. package/docs/design-notes/previous-work.md +0 -5
  205. package/docs/forms.md +0 -1265
  206. package/docs/javascript.md +0 -496
  207. package/docs/layout.md +0 -480
  208. package/docs/patterns.md +0 -504
  209. package/docs/reserved.md +0 -7
  210. package/docs/tokens.md +0 -455
  211. package/docs/ui.md +0 -929
  212. package/docs/utilities.md +0 -384
  213. package/src/css/dialog-fallback.css +0 -56
  214. package/src/js/dialog-fallback.js +0 -163
@@ -0,0 +1,93 @@
1
+ /*
2
+ * Decorative intent-colored frame for one direct child.
3
+ *
4
+ * Public hooks:
5
+ * --aura-color
6
+ * --aura-width
7
+ * --aura-blur
8
+ * --aura-radius
9
+ * --aura-duration
10
+ */
11
+ @property --aura-angle {
12
+ syntax: "<angle>";
13
+ inherits: false;
14
+ initial-value: 0deg;
15
+ }
16
+
17
+ /* Intent boundary — an outer intent does not tint nested aura frames. */
18
+ :where(.aura) {
19
+ --intent: initial;
20
+ --intent-fg: initial;
21
+ }
22
+
23
+ .aura {
24
+ --aura-color: var(--intent, var(--primary));
25
+ --aura-width: 2px;
26
+ --aura-blur: 0.75rem;
27
+ --aura-radius: var(--radius-lg);
28
+ --aura-duration: 6s;
29
+
30
+ position: relative;
31
+ isolation: isolate;
32
+ display: inline-grid;
33
+ padding: var(--aura-width);
34
+ border-radius: calc(var(--aura-radius) + var(--aura-width));
35
+ background: var(--aura-color);
36
+ background: conic-gradient(from var(--aura-angle), transparent 0 65%, var(--aura-color));
37
+ }
38
+
39
+ .aura::before {
40
+ position: absolute;
41
+ z-index: -1;
42
+ inset: 0;
43
+ border-radius: inherit;
44
+ background: inherit;
45
+ filter: blur(var(--aura-blur));
46
+ opacity: 0.45;
47
+ pointer-events: none;
48
+ content: "";
49
+ }
50
+
51
+ .aura > * {
52
+ position: relative;
53
+ }
54
+
55
+ .aura-glow {
56
+ background: var(--aura-color);
57
+ }
58
+
59
+ @media (prefers-reduced-motion: no-preference) {
60
+ .aura:not(.aura-glow) {
61
+ animation: aura-rotate var(--aura-duration) linear infinite;
62
+ }
63
+ }
64
+
65
+ @keyframes aura-rotate {
66
+ to {
67
+ --aura-angle: 360deg;
68
+ }
69
+ }
70
+
71
+ @supports selector(:has(*)) {
72
+ .aura:has(> .btn) {
73
+ --aura-radius: var(--radius);
74
+ }
75
+
76
+ .aura:has(> :is(.card, .alert)) {
77
+ --aura-radius: var(--radius-lg);
78
+ }
79
+
80
+ .aura:has(> .badge) {
81
+ --aura-radius: var(--radius-full);
82
+ }
83
+ }
84
+
85
+ @media (forced-colors: active) {
86
+ .aura {
87
+ background: CanvasText;
88
+ }
89
+
90
+ .aura::before {
91
+ display: none;
92
+ }
93
+ }
@@ -0,0 +1,105 @@
1
+ /*
2
+ * Message rows composed from an optional avatar, metadata, and bubble.
3
+ *
4
+ * Public hooks:
5
+ * --chat-gap
6
+ * --chat-max-size
7
+ *
8
+ * Internal:
9
+ * --chat-bubble-bg
10
+ * --chat-bubble-fg
11
+ * --chat-bubble-border
12
+ */
13
+ .chat {
14
+ --chat-gap: var(--space-30);
15
+ --chat-max-size: min(85%, 40rem);
16
+
17
+ display: grid;
18
+ grid-auto-rows: min-content;
19
+ column-gap: var(--chat-gap);
20
+ }
21
+
22
+ .chat-start {
23
+ grid-template-columns: auto minmax(0, 1fr);
24
+ justify-items: start;
25
+ }
26
+
27
+ .chat-end {
28
+ grid-template-columns: minmax(0, 1fr) auto;
29
+ justify-items: end;
30
+ }
31
+
32
+ .chat-avatar {
33
+ grid-row: 1 / span 3;
34
+ align-self: end;
35
+ }
36
+
37
+ .chat-start > .chat-avatar {
38
+ grid-column: 1;
39
+ }
40
+
41
+ .chat-end > .chat-avatar {
42
+ grid-column: 2;
43
+ }
44
+
45
+ .chat-header,
46
+ .chat-footer {
47
+ display: flex;
48
+ gap: var(--space-10);
49
+ color: var(--text-muted);
50
+ font-size: var(--font-size-xs);
51
+ }
52
+
53
+ .chat-start > :is(.chat-header, .chat-bubble, .chat-footer) {
54
+ grid-column: 2;
55
+ }
56
+
57
+ .chat-end > :is(.chat-header, .chat-bubble, .chat-footer) {
58
+ grid-column: 1;
59
+ }
60
+
61
+ /* Intent boundary — an outer intent does not tint nested messages. */
62
+ :where(.chat-bubble) {
63
+ --intent: initial;
64
+ --intent-fg: initial;
65
+ --ui-bg: initial;
66
+ --ui-fg: initial;
67
+ --ui-border: initial;
68
+ }
69
+
70
+ .chat-bubble {
71
+ --chat-bubble-bg: var(--ui-bg, var(--intent, var(--surface-subtle)));
72
+ --chat-bubble-fg: var(--ui-fg, var(--intent-fg, var(--text)));
73
+ --chat-bubble-border: var(--ui-border, transparent);
74
+
75
+ inline-size: fit-content;
76
+ max-inline-size: var(--chat-max-size);
77
+ padding: var(--space-20) var(--space-30);
78
+ border: var(--border-width) solid var(--chat-bubble-border);
79
+ border-radius: var(--radius-lg);
80
+ background: var(--chat-bubble-bg);
81
+ color: var(--chat-bubble-fg);
82
+ overflow-wrap: anywhere;
83
+ }
84
+
85
+ .chat-start > .chat-bubble {
86
+ border-end-start-radius: var(--radius-sm);
87
+ }
88
+
89
+ .chat-end > .chat-bubble {
90
+ border-end-end-radius: var(--radius-sm);
91
+ }
92
+
93
+ /* Remove the reserved avatar gutter when a message has no avatar. This is a
94
+ cosmetic enhancement; the two-column baseline remains fully readable. */
95
+ @supports selector(:has(*)) {
96
+ .chat:not(:has(> .chat-avatar)) {
97
+ column-gap: 0;
98
+ }
99
+ }
100
+
101
+ @media (forced-colors: active) {
102
+ .chat-bubble {
103
+ border-color: CanvasText;
104
+ }
105
+ }
@@ -0,0 +1,104 @@
1
+ /*
2
+ * Fixed floating action placement and a native-details speed dial.
3
+ * Button owns the action's size, shape, and intent; FAB only owns placement.
4
+ *
5
+ * Public hooks:
6
+ * --fab-offset
7
+ * --fab-gap
8
+ */
9
+ .fab {
10
+ --fab-offset: var(--space-40);
11
+ --fab-gap: var(--space-20);
12
+
13
+ position: fixed;
14
+ z-index: var(--z-menu);
15
+ inset-block-end: max(var(--fab-offset), env(safe-area-inset-bottom));
16
+ inset-inline-end: var(--fab-offset);
17
+ }
18
+
19
+ .fab > summary {
20
+ list-style: none;
21
+ cursor: pointer;
22
+ }
23
+
24
+ .fab > summary::-webkit-details-marker {
25
+ display: none;
26
+ }
27
+
28
+ /* A lone decorative plus can communicate the open/close state without
29
+ requiring a second icon or JavaScript-managed content. */
30
+ .fab > summary > [aria-hidden="true"]:only-child {
31
+ display: inline-block;
32
+ transition: transform var(--duration);
33
+ }
34
+
35
+ .fab-actions {
36
+ position: absolute;
37
+ inset-inline-end: 0;
38
+ inset-block-end: calc(100% + var(--fab-gap));
39
+ display: flex;
40
+ flex-direction: column;
41
+ align-items: flex-end;
42
+ gap: var(--fab-gap);
43
+ opacity: 0;
44
+ visibility: hidden;
45
+ pointer-events: none;
46
+ transform: translateY(var(--space-10));
47
+ transition:
48
+ opacity var(--duration),
49
+ transform var(--duration),
50
+ visibility 0s linear var(--duration);
51
+ }
52
+
53
+ /* One action is one compact row. Keeping this relationship inside FAB avoids
54
+ wrapping and prevents labels from becoming visually associated with the
55
+ preceding or following button. */
56
+ .fab-action {
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: flex-end;
60
+ gap: var(--fab-gap);
61
+ inline-size: max-content;
62
+ max-inline-size: calc(var(--viewport-inline) - var(--fab-offset) - var(--fab-offset));
63
+ }
64
+
65
+ .fab-label {
66
+ flex: 0 1 auto;
67
+ overflow: hidden;
68
+ max-inline-size: 16rem;
69
+ padding: var(--space-10) var(--space-20);
70
+ border-radius: var(--radius);
71
+ background: var(--surface);
72
+ color: var(--text);
73
+ box-shadow: var(--shadow);
74
+ font-size: var(--font-size-xs);
75
+ font-weight: var(--font-weight-medium);
76
+ line-height: var(--line-height-tight);
77
+ text-overflow: ellipsis;
78
+ white-space: nowrap;
79
+ }
80
+
81
+ .fab[open] > .fab-actions {
82
+ opacity: 1;
83
+ visibility: visible;
84
+ pointer-events: auto;
85
+ transform: translateY(0);
86
+ transition-delay: 0s;
87
+ }
88
+
89
+ .fab[open] > summary > [aria-hidden="true"]:only-child {
90
+ transform: rotate(45deg);
91
+ }
92
+
93
+ @media (forced-colors: active) {
94
+ .fab-label {
95
+ border: var(--border-width) solid CanvasText;
96
+ box-shadow: none;
97
+ }
98
+ }
99
+
100
+ @media print {
101
+ .fab {
102
+ display: none;
103
+ }
104
+ }
@@ -0,0 +1,87 @@
1
+ /*
2
+ * Floating labels — optional composition over the text controls
3
+ * (.input, .textarea, .select) and .field-label.
4
+ *
5
+ * The cell owns a control plus its label; the label overlays the control and
6
+ * floats to the top when the control is focused or non-empty. Help and error
7
+ * messages stay in the surrounding .field, not inside the cell, so the
8
+ * resting label can center on the control alone.
9
+ *
10
+ * The control must precede the label: the float is driven by the sibling
11
+ * combinator and :placeholder-shown. Every .input/.textarea needs
12
+ * placeholder=" " to expose a reliable empty state — without it the label
13
+ * only reacts to focus.
14
+ *
15
+ * Density flows through --control-size: .sm/.lg shrink the control geometry
16
+ * and the reserved headroom with it, leaving typography untouched.
17
+ *
18
+ * Public hooks:
19
+ * --floating-pad-block-start
20
+ */
21
+ .floating-field {
22
+ --floating-pad-block-start: calc(var(--control-size) / 2 + var(--space-20));
23
+
24
+ /* Grid blockifies the control, removing the inline descender gap a textarea
25
+ would otherwise leave under itself. */
26
+ position: relative;
27
+ display: grid;
28
+ }
29
+
30
+ .floating-field > :is(.input, .textarea, .select) {
31
+ /* Headroom for the floated label is always reserved, so the value never
32
+ jumps when the label floats. Half the control centers the resting label;
33
+ the extra step clears the floated label's bottom edge. */
34
+ padding-block-start: var(--floating-pad-block-start);
35
+ padding-block-end: var(--space-10);
36
+ }
37
+
38
+ .floating-field > .field-label {
39
+ position: absolute;
40
+ inset-block-start: 50%;
41
+ inset-inline-start: calc(var(--space-30) + var(--border-width));
42
+ transform: translateY(-50%);
43
+ color: var(--text-muted);
44
+ font-size: var(--control-font-size);
45
+ font-weight: var(--font-weight);
46
+ pointer-events: none;
47
+ transition:
48
+ inset-block-start var(--duration),
49
+ transform var(--duration),
50
+ font-size var(--duration),
51
+ color var(--duration);
52
+ }
53
+
54
+ /* A textarea's resting label aligns with the first text line instead of
55
+ centering in the (tall) control. */
56
+ .floating-field > .textarea + .field-label {
57
+ inset-block-start: var(--floating-pad-block-start);
58
+ transform: none;
59
+ }
60
+
61
+ /* :autofill covers prefilled values before interaction, when the browser may
62
+ not have propagated the value to the placeholder state yet. */
63
+ .floating-field
64
+ > :is(.input, .textarea):is(:focus, :autofill, :not(:placeholder-shown))
65
+ + .field-label {
66
+ inset-block-start: var(--space-10);
67
+ transform: none;
68
+ font-size: var(--font-size-xs);
69
+ }
70
+
71
+ /* Controls without a dependable :placeholder-shown empty state stay floated:
72
+ select always, and date/time inputs whose placeholder rendering is
73
+ inconsistent across engines (Firefox shows none). */
74
+ .floating-field
75
+ > :is(
76
+ .select,
77
+ .input[type="date"],
78
+ .input[type="time"],
79
+ .input[type="datetime-local"],
80
+ .input[type="month"],
81
+ .input[type="week"]
82
+ )
83
+ + .field-label {
84
+ inset-block-start: var(--space-10);
85
+ transform: none;
86
+ font-size: var(--font-size-xs);
87
+ }
@@ -1,3 +1,8 @@
1
+ @import "otp.css";
2
+ @import "chat.css";
3
+ @import "aura.css";
4
+ @import "fab.css";
5
+ @import "floating-field.css";
1
6
  @import "scroller.css";
2
7
  @import "scroll-snap.css";
3
8
  @import "typography-fluid.css";
@@ -2,6 +2,9 @@
2
2
  * Additional layout primitives not included in the core bundle.
3
3
  *
4
4
  * Import this file explicitly when a project needs these patterns.
5
+ *
6
+ * Public hooks:
7
+ * --switcher-threshold
5
8
  */
6
9
  .switcher {
7
10
  display: flex;
@@ -22,8 +25,8 @@
22
25
  * to the page.
23
26
  *
24
27
  * Not for marketing/editorial site headers — those are one-off visual
25
- * identity per page; see docs/patterns.md's Header Navigation section.
26
- * This is for the structural app-shell topbar, which recurs unchanged
28
+ * identity per page; see docs/pages/patterns/overview.md's Header Navigation
29
+ * section. This is for the structural app-shell topbar, which recurs unchanged
27
30
  * across app UIs regardless of brand.
28
31
  */
29
32
  .topbar {
@@ -34,8 +37,8 @@
34
37
  display: flex;
35
38
  align-items: center;
36
39
  gap: var(--gap);
37
- padding-block: var(--space-3);
38
- padding-inline: var(--space-4);
40
+ padding-block: var(--space-30);
41
+ padding-inline: var(--space-40);
39
42
  border-block-end: var(--border-width) solid var(--border);
40
43
  background: var(--surface);
41
44
  }
@@ -0,0 +1,115 @@
1
+ /*
2
+ * One-time code input with visual cells and one native input.
3
+ *
4
+ * Add one direct span per accepted character. The cells determine the
5
+ * component width; the overlaid input remains the only interactive control.
6
+ *
7
+ * Public hooks:
8
+ * --otp-cell-size
9
+ * --otp-gap
10
+ * --otp-font-size
11
+ *
12
+ * Internal:
13
+ * --otp-cell-border
14
+ * --otp-cell-bg
15
+ */
16
+ .otp {
17
+ --otp-cell-size: var(--control-size);
18
+ --otp-gap: var(--space-10);
19
+ --otp-font-size: 1.5rem;
20
+ --otp-cell-border: var(--border);
21
+ --otp-cell-bg: var(--surface);
22
+
23
+ position: relative;
24
+ display: inline-grid;
25
+ grid-auto-flow: column;
26
+ grid-auto-columns: var(--otp-cell-size);
27
+ inline-size: fit-content;
28
+ max-inline-size: 100%;
29
+ gap: var(--otp-gap);
30
+ border-radius: var(--radius);
31
+ direction: ltr;
32
+ }
33
+
34
+ .otp > span {
35
+ inline-size: var(--otp-cell-size);
36
+ block-size: var(--otp-cell-size);
37
+ border: var(--border-width) solid var(--otp-cell-border);
38
+ border-radius: var(--radius);
39
+ background: var(--otp-cell-bg);
40
+ transition:
41
+ border-color var(--duration),
42
+ background-color var(--duration),
43
+ box-shadow var(--duration);
44
+ }
45
+
46
+ /* The native input owns focus, selection, autofill, paste, and one-time-code
47
+ integration. Its spacing aligns monospace glyphs with the visual cells. */
48
+ .otp > input {
49
+ position: absolute;
50
+ z-index: 1;
51
+ inset: 0;
52
+ inline-size: 100%;
53
+ block-size: 100%;
54
+ margin: 0;
55
+ padding: 0 calc((var(--otp-cell-size) - 1ch) / 2);
56
+ border: 0;
57
+ outline: 2px solid transparent;
58
+ box-shadow: none;
59
+ background: transparent;
60
+ color: var(--text);
61
+ font-family: var(--font-mono);
62
+ font-size: var(--otp-font-size);
63
+ font-variant-numeric: tabular-nums;
64
+ line-height: var(--otp-cell-size);
65
+ letter-spacing: calc(var(--otp-cell-size) + var(--otp-gap) - 1ch);
66
+ text-align: start;
67
+ appearance: none;
68
+ }
69
+
70
+ .otp:focus-within {
71
+ box-shadow: var(--focus-ring-shadow);
72
+ }
73
+
74
+ .otp > input:focus ~ span {
75
+ --otp-cell-border: var(--focus);
76
+ }
77
+
78
+ .otp > input[aria-invalid="true"] ~ span,
79
+ .needs-validation.was-validated .otp > input:invalid ~ span {
80
+ --otp-cell-border: var(--danger);
81
+ }
82
+
83
+ @supports selector(:user-invalid) {
84
+ .needs-validation .otp > input:user-invalid ~ span {
85
+ --otp-cell-border: var(--danger);
86
+ }
87
+ }
88
+
89
+ .otp > input:disabled {
90
+ color: var(--state-disabled);
91
+ cursor: not-allowed;
92
+ }
93
+
94
+ .otp > input:disabled ~ span {
95
+ --otp-cell-bg: var(--surface-subtle);
96
+
97
+ opacity: var(--disabled-opacity);
98
+ }
99
+
100
+ @media (forced-colors: active) {
101
+ .otp:focus-within {
102
+ outline: var(--focus-outline);
103
+ outline-offset: var(--focus-outline-offset);
104
+ box-shadow: none;
105
+ }
106
+
107
+ .otp > input:focus ~ span {
108
+ --otp-cell-border: Highlight;
109
+ }
110
+
111
+ .otp > input[aria-invalid="true"] ~ span,
112
+ .needs-validation.was-validated .otp > input:invalid ~ span {
113
+ --otp-cell-border: Mark;
114
+ }
115
+ }
@@ -5,6 +5,12 @@
5
5
  * This is not a full carousel. For previous/next controls, pagination,
6
6
  * active state, drag behavior, looping, or robust desktop mouse interaction,
7
7
  * use a dedicated carousel library.
8
+ *
9
+ * Public hooks:
10
+ * --scroll-snap-gap
11
+ * --scroll-snap-align
12
+ * --scroll-snap-item-size
13
+ * --scroll-snap-padding
8
14
  */
9
15
  .scroll-snap {
10
16
  --scroll-snap-gap: var(--gap);
@@ -2,8 +2,16 @@
2
2
  * Scroller — optional custom scrollbar styling for overflow regions.
3
3
  *
4
4
  * Apply to any scroll container (.overflow-auto, sidebars, long tables). Both
5
- * stable-color (Firefox) and ::-webkit-scrollbar (Safari/Chromium) are styled;
6
- * the thumb lands as a thin, theme-aware affordance with a hover state.
5
+ * scrollbar-color (Firefox) and ::-webkit-scrollbar (Safari/Chromium) are
6
+ * styled; the thumb lands as a thin, theme-aware affordance with a hover
7
+ * state.
8
+ *
9
+ * Public hooks:
10
+ * --scroller-size
11
+ * --scroller-padding
12
+ * --scroller-track
13
+ * --scroller-thumb
14
+ * --scroller-thumb-hover
7
15
  */
8
16
  .scroller {
9
17
  --scroller-size: 0.625rem;
@@ -38,11 +46,9 @@
38
46
  background-clip: content-box;
39
47
  }
40
48
 
41
- @media (hover: hover) {
42
- .scroller::-webkit-scrollbar-thumb:hover {
43
- background: var(--scroller-thumb-hover);
44
- background-clip: content-box;
45
- }
49
+ .scroller::-webkit-scrollbar-thumb:hover {
50
+ background: var(--scroller-thumb-hover);
51
+ background-clip: content-box;
46
52
  }
47
53
 
48
54
  .scroller::-webkit-scrollbar-corner {
@@ -14,6 +14,11 @@
14
14
  * --fluid-display, --fluid-title, --fluid-lead (size tokens, clamp())
15
15
  * .text-display, .text-title, .text-lead (composed classes)
16
16
  *
17
+ * Public hooks:
18
+ * --fluid-display
19
+ * --fluid-title
20
+ * --fluid-lead
21
+ *
17
22
  * Values are generated from scripts/rfs.ts over the 360px -> 1440px range.
18
23
  */
19
24
  :root {
@@ -5,10 +5,13 @@
5
5
  * They are escape hatches for layout nudges, not a full atomic scale.
6
6
  *
7
7
  * Core principle:
8
- * - .sm / .lg provide local rhythm through --gap and --variant-space.
8
+ * - .sm / .lg provide local rhythm through --gap and --density-space.
9
9
  * - utilities consume the current context instead of defining their own -sm/-lg scale.
10
10
  * - optional utilities extend core utilities, they do not re-express them.
11
11
  * - follow verbose .{property}-{value} naming.
12
+ *
13
+ * Internal:
14
+ * --cluster-justify (local relay consumed by .cluster)
12
15
  */
13
16
 
14
17
  /* Display */
@@ -83,6 +86,18 @@
83
86
  flex-wrap: nowrap;
84
87
  }
85
88
 
89
+ .gap-sm {
90
+ gap: var(--space-20);
91
+ }
92
+
93
+ .gap-md {
94
+ gap: var(--space-40);
95
+ }
96
+
97
+ .gap-lg {
98
+ gap: var(--space-50);
99
+ }
100
+
86
101
  .justify-content-start {
87
102
  --cluster-justify: flex-start;
88
103
  justify-content: flex-start;
@@ -117,7 +132,7 @@
117
132
 
118
133
  /* Spacing */
119
134
  .padding-context {
120
- padding: var(--variant-space);
135
+ padding: var(--density-space);
121
136
  }
122
137
 
123
138
  .margin-inline-auto {
package/src/css/prose.css CHANGED
@@ -3,6 +3,17 @@
3
3
  *
4
4
  * Global element styles stay mild so app UI is not shaped accidentally. Page
5
5
  * layout, forms, cards, navigation, and app tables remain outside this scope.
6
+ *
7
+ * Public hooks:
8
+ * --prose-size
9
+ * --prose-line-height
10
+ * --prose-measure
11
+ * --prose-flow
12
+ * --prose-heading-line-height
13
+ * --prose-h1
14
+ * --prose-h2
15
+ * --prose-h3
16
+ * --prose-h4
6
17
  */
7
18
 
8
19
  .prose {
@@ -66,15 +77,13 @@
66
77
  text-underline-offset: 0.18em;
67
78
  }
68
79
 
69
- @media (hover: hover) {
70
- .prose a:hover {
71
- text-decoration-thickness: 0.12em;
72
- }
80
+ .prose a:hover {
81
+ text-decoration-thickness: 0.12em;
82
+ }
73
83
 
74
- @supports (color: color-mix(in oklch, red, white)) {
75
- .prose a:hover {
76
- color: color-mix(in oklch, var(--primary), var(--text) 15%);
77
- }
84
+ @supports (color: color-mix(in oklch, red, white)) {
85
+ .prose a:hover {
86
+ color: color-mix(in oklch, var(--primary), var(--text) 15%);
78
87
  }
79
88
  }
80
89
 
@@ -94,6 +103,7 @@
94
103
  font-size: 0.875em;
95
104
  }
96
105
 
106
+ /* Visual twin of .key (components/key.css) — keep the two recipes in sync. */
97
107
  .prose kbd {
98
108
  display: inline-flex;
99
109
  align-items: center;