actual-css 0.3.1 → 0.4.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 (223) hide show
  1. package/CHANGELOG.md +109 -3
  2. package/README.md +35 -30
  3. package/dist/actual.css +66 -4958
  4. package/dist/actual.full.css +7548 -0
  5. package/dist/actual.full.js +1 -0
  6. package/dist/actual.full.min.css +1 -0
  7. package/dist/actual.js +1 -1
  8. package/dist/actual.min.css +1 -1
  9. package/docs/design-notes/app-ui.md +33 -0
  10. package/docs/design-notes/cascade-layer.md +34 -13
  11. package/docs/design-notes/column-layout.md +677 -0
  12. package/docs/design-notes/enhancement-contract.md +25 -0
  13. package/docs/design-notes/forced-colors.md +3 -0
  14. package/docs/design-notes/grid.md +785 -0
  15. package/docs/design-notes/naming.md +15 -0
  16. package/docs/design-notes/references.md +1 -1
  17. package/docs/design-notes/widget-primitives.md +1 -0
  18. package/docs/navigation.json +12 -2
  19. package/docs/pages/components/alert.md +21 -14
  20. package/docs/pages/components/app-navigation.md +34 -0
  21. package/docs/pages/components/aura.md +1 -1
  22. package/docs/pages/components/avatar.md +16 -6
  23. package/docs/pages/components/badge.md +9 -7
  24. package/docs/pages/components/button.md +46 -16
  25. package/docs/pages/components/card.md +17 -9
  26. package/docs/pages/components/chat.md +8 -8
  27. package/docs/pages/components/dialog.md +7 -7
  28. package/docs/pages/components/drawer.md +3 -3
  29. package/docs/pages/components/fab.md +9 -7
  30. package/docs/pages/components/indicator.md +52 -0
  31. package/docs/pages/components/list.md +62 -0
  32. package/docs/pages/components/navbar.md +15 -8
  33. package/docs/pages/components/pagination.md +4 -3
  34. package/docs/pages/components/rating.md +68 -0
  35. package/docs/pages/components/skeleton.md +4 -4
  36. package/docs/pages/components/spinner.md +5 -5
  37. package/docs/pages/components/steps.md +57 -0
  38. package/docs/pages/components/table.md +30 -5
  39. package/docs/pages/enhancements/flyout.md +15 -15
  40. package/docs/pages/enhancements/overview.md +1 -1
  41. package/docs/pages/enhancements/scrollspy.md +6 -6
  42. package/docs/pages/enhancements/status-bar.md +5 -1
  43. package/docs/pages/enhancements/tabs.md +7 -8
  44. package/docs/pages/enhancements/tooltip.md +1 -1
  45. package/docs/pages/examples/overview.md +47 -22
  46. package/docs/pages/forms/choice-cards.md +11 -6
  47. package/docs/pages/forms/controls.md +1 -1
  48. package/docs/pages/forms/detached-actions.md +1 -1
  49. package/docs/pages/forms/floating-field.md +10 -5
  50. package/docs/pages/forms/form-actions.md +1 -1
  51. package/docs/pages/forms/input-policy.md +1 -1
  52. package/docs/pages/forms/joined-controls.md +4 -4
  53. package/docs/pages/forms/labels.md +6 -6
  54. package/docs/pages/forms/otp.md +33 -1
  55. package/docs/pages/forms/overview.md +19 -19
  56. package/docs/pages/forms/password.md +1 -1
  57. package/docs/pages/forms/range.md +1 -1
  58. package/docs/pages/forms/states-and-sizes.md +44 -48
  59. package/docs/pages/forms/sticky-actions.md +3 -3
  60. package/docs/pages/forms/switch.md +110 -2
  61. package/docs/pages/forms/validation.md +9 -9
  62. package/docs/pages/foundations/philosophy.md +1 -1
  63. package/docs/pages/foundations/theming.md +17 -2
  64. package/docs/pages/foundations/tokens.md +22 -10
  65. package/docs/pages/foundations/typography.md +50 -20
  66. package/docs/pages/guides/bootstrap.md +11 -11
  67. package/docs/pages/guides/integrating-actual-css.md +192 -0
  68. package/docs/pages/guides/introduction.md +23 -26
  69. package/docs/pages/guides/modular-import.md +173 -0
  70. package/docs/pages/guides/progressive-enhancement.md +81 -78
  71. package/docs/pages/guides/tailwind.md +6 -8
  72. package/docs/pages/layout/app-layout.md +57 -0
  73. package/docs/pages/layout/app-shell.md +28 -7
  74. package/docs/pages/layout/center.md +12 -1
  75. package/docs/pages/layout/choosing.md +54 -0
  76. package/docs/pages/layout/column-layout.md +206 -0
  77. package/docs/pages/layout/frame.md +6 -1
  78. package/docs/pages/layout/grid.md +133 -102
  79. package/docs/pages/layout/media.md +1 -1
  80. package/docs/pages/layout/overview.md +15 -2
  81. package/docs/pages/layout/scroll-snap.md +2 -2
  82. package/docs/pages/layout/scroll-target.md +45 -0
  83. package/docs/pages/layout/sidebar-layout.md +38 -18
  84. package/docs/pages/layout/stack.md +70 -1
  85. package/docs/pages/layout/switcher.md +10 -26
  86. package/docs/pages/layout/topbar.md +2 -2
  87. package/docs/pages/patterns/actions.md +1 -1
  88. package/docs/pages/patterns/code-block.md +1 -1
  89. package/docs/pages/patterns/exclusive-accordion.md +1 -1
  90. package/docs/pages/patterns/hierarchical-nav.md +1 -1
  91. package/docs/pages/patterns/icon-input.md +1 -1
  92. package/docs/pages/patterns/icon-slot.md +61 -0
  93. package/docs/pages/patterns/intent-nesting.md +1 -1
  94. package/docs/pages/patterns/navigation-list.md +1 -1
  95. package/docs/pages/patterns/overview.md +1 -1
  96. package/docs/pages/patterns/structured-lists.md +38 -40
  97. package/docs/pages/utilities/accessibility.md +3 -3
  98. package/docs/pages/utilities/flex.md +15 -15
  99. package/docs/pages/utilities/links.md +4 -4
  100. package/docs/pages/utilities/list.md +8 -8
  101. package/docs/pages/utilities/overflow.md +8 -8
  102. package/docs/pages/utilities/overview.md +1 -1
  103. package/docs/pages/utilities/shape.md +3 -3
  104. package/docs/pages/utilities/sizing-wrapping.md +23 -16
  105. package/docs/pages/utilities/spacing.md +20 -20
  106. package/docs/pages/utilities/text.md +10 -10
  107. package/llms.txt +46 -4
  108. package/package.json +43 -13
  109. package/scripts/reserved-classes.json +278 -0
  110. package/src/cli/actual-css.js +133 -0
  111. package/src/css/actual.css +1 -31
  112. package/src/css/actual.full.css +11 -2
  113. package/src/css/components/alert.css +17 -4
  114. package/src/css/components/app-nav.css +76 -0
  115. package/src/css/components/avatar.css +4 -0
  116. package/src/css/components/badge.css +19 -19
  117. package/src/css/components/breadcrumb.css +1 -1
  118. package/src/css/components/button.css +20 -32
  119. package/src/css/components/card.css +34 -9
  120. package/src/css/{optional → components}/chat.css +0 -6
  121. package/src/css/components/drawer.css +24 -5
  122. package/src/css/{optional → components}/fab.css +1 -7
  123. package/src/css/components/flyout.css +5 -0
  124. package/src/css/components/index.css +37 -27
  125. package/src/css/components/indicator.css +47 -0
  126. package/src/css/components/join.css +8 -1
  127. package/src/css/components/key.css +2 -0
  128. package/src/css/components/list.css +83 -0
  129. package/src/css/components/menu.css +11 -8
  130. package/src/css/components/meter.css +4 -1
  131. package/src/css/components/modal.css +5 -17
  132. package/src/css/components/navbar.css +6 -15
  133. package/src/css/components/pagination.css +11 -0
  134. package/src/css/components/rating.css +101 -0
  135. package/src/css/components/spinner.css +5 -0
  136. package/src/css/components/status-bar.css +5 -0
  137. package/src/css/components/steps.css +122 -0
  138. package/src/css/components/surface.css +5 -0
  139. package/src/css/components/tab.css +20 -22
  140. package/src/css/components/table.css +6 -0
  141. package/src/css/components/tooltip.css +3 -7
  142. package/src/css/{focus.css → core/focus.css} +0 -8
  143. package/src/css/core/index.css +9 -0
  144. package/src/css/core/print.css +18 -0
  145. package/src/css/{theme.css → core/theme.css} +19 -19
  146. package/src/css/{tokens.css → core/tokens.css} +16 -4
  147. package/src/css/{variants.css → core/variants.css} +3 -2
  148. package/src/css/{optional → effects}/aura.css +1 -10
  149. package/src/css/effects/index.css +2 -0
  150. package/src/css/forms/base.css +8 -0
  151. package/src/css/forms/choice-card.css +7 -15
  152. package/src/css/forms/choice.css +49 -37
  153. package/src/css/forms/control.css +4 -1
  154. package/src/css/forms/custom-select.css +2 -0
  155. package/src/css/{optional → forms}/floating-field.css +25 -7
  156. package/src/css/forms/index.css +10 -13
  157. package/src/css/forms/native.css +15 -2
  158. package/src/css/{optional → forms}/otp.css +25 -16
  159. package/src/css/forms/range.css +14 -4
  160. package/src/css/forms/switch.css +31 -29
  161. package/src/css/layout/app-layout.css +102 -0
  162. package/src/css/layout/app-shell.css +6 -0
  163. package/src/css/layout/center.css +14 -0
  164. package/src/css/layout/cluster.css +21 -0
  165. package/src/css/layout/column-layout.css +144 -0
  166. package/src/css/layout/container-query.css +15 -0
  167. package/src/css/layout/frame.css +19 -0
  168. package/src/css/layout/grid.css +155 -0
  169. package/src/css/layout/index.css +44 -0
  170. package/src/css/layout/measure.css +9 -0
  171. package/src/css/layout/media.css +10 -0
  172. package/src/css/layout/scroll-target.css +15 -0
  173. package/src/css/layout/scroller.css +41 -0
  174. package/src/css/layout/sidebar-layout.css +52 -0
  175. package/src/css/layout/stack.css +21 -0
  176. package/src/css/layout/switcher.css +23 -0
  177. package/src/css/{optional/layout-extra.css → layout/topbar.css} +0 -20
  178. package/src/css/typography/index.css +5 -0
  179. package/src/css/typography/lead.css +7 -0
  180. package/src/css/{components → typography}/overline.css +2 -2
  181. package/src/css/{prose.css → typography/prose.css} +57 -38
  182. package/src/css/{utilities.css → utilities/base.css} +2 -0
  183. package/src/css/utilities/index.css +3 -0
  184. package/src/js/escape.js +36 -0
  185. package/src/js/flyout.js +22 -12
  186. package/src/js/full.js +26 -0
  187. package/src/js/index.js +5 -21
  188. package/src/js/surface.js +1 -31
  189. package/src/js/tooltip.js +48 -19
  190. package/src/js/validation.js +1 -1
  191. package/src/tooling/css-bundle.js +308 -0
  192. package/dist/actual-themes.min.css +0 -1
  193. package/dist/optional.css +0 -1048
  194. package/dist/optional.min.css +0 -1
  195. package/docs/pages/guides/optional-components.md +0 -33
  196. package/docs/pages/layout/list.md +0 -41
  197. package/src/css/grid.css +0 -109
  198. package/src/css/layout.css +0 -123
  199. package/src/css/optional/index.css +0 -10
  200. package/src/css/optional/scroller.css +0 -63
  201. package/src/css/print.css +0 -47
  202. package/src/css/themes/corporate.css +0 -60
  203. package/src/css/themes/cyberpunk.css +0 -60
  204. package/src/css/themes/dim.css +0 -33
  205. package/src/css/themes/edge.css +0 -117
  206. package/src/css/themes/forest.css +0 -65
  207. package/src/css/themes/gradient.css +0 -97
  208. package/src/css/themes/index.css +0 -47
  209. package/src/css/themes/indigo.css +0 -33
  210. package/src/css/themes/lavender.css +0 -66
  211. package/src/css/themes/mono.css +0 -60
  212. package/src/css/themes/neon.css +0 -66
  213. package/src/css/themes/ocean.css +0 -60
  214. package/src/css/themes/petrol.css +0 -64
  215. package/src/css/themes/spruce.css +0 -64
  216. package/src/css/themes/square.css +0 -65
  217. package/src/css/themes/sunset.css +0 -66
  218. /package/src/css/{base.css → core/base.css} +0 -0
  219. /package/src/css/{intents.css → core/intents.css} +0 -0
  220. /package/src/css/{reset.css → core/reset.css} +0 -0
  221. /package/src/css/{optional → layout}/scroll-snap.css +0 -0
  222. /package/src/css/{optional/typography-fluid.css → typography/fluid.css} +0 -0
  223. /package/src/css/{optional/utilities-extra.css → utilities/extra.css} +0 -0
@@ -0,0 +1,206 @@
1
+ # Column Layout
2
+
3
+ `.column-layout` is an explicit twelve-column composition canvas. Place regions
4
+ with `.column-span-N` and `.column-start-N`.
5
+
6
+ Reach for it when the placement of each region **is** the design. If the regions
7
+ are a collection, a known density, peers that switch together, or a main region
8
+ with an aside, one of the other primitives already says so — and says it with
9
+ intrinsic responsive behavior this one does not have.
10
+
11
+ ```html demo
12
+ <div class="column-layout">
13
+ <main class="column-span-8 card">Main — 8 columns</main>
14
+ <aside class="column-span-4 card">Aside — 4 columns</aside>
15
+ </div>
16
+ ```
17
+
18
+ Neither child names a start line, so grid auto-placement flows the aside into
19
+ columns 9 through 12.
20
+
21
+ ## Spans
22
+
23
+ A span declares how many of the twelve units a region occupies.
24
+
25
+ ```html demo
26
+ <div class="column-layout">
27
+ <div class="column-span-3 card">3</div>
28
+ <div class="column-span-6 card">6</div>
29
+ <div class="column-span-3 card">3</div>
30
+ </div>
31
+ ```
32
+
33
+ A child with no placement class spans the whole canvas, so a heading can share
34
+ the canvas with placed regions without carrying a class.
35
+
36
+ ```html demo
37
+ <div class="column-layout">
38
+ <h3>Full canvas — no class needed</h3>
39
+ <div class="column-span-4 card">4</div>
40
+ <div class="column-span-4 card">4</div>
41
+ <div class="column-span-4 card">4</div>
42
+ </div>
43
+ ```
44
+
45
+ Regions that do not fit wrap to the next row, as any grid does. Two
46
+ `.column-span-8` regions need sixteen units, so the second moves down.
47
+
48
+ ## Starts
49
+
50
+ A start declares the line a region begins on. This replaces margin-based
51
+ offsets and is direction-independent: line 1 is the inline start, so the
52
+ placement flips with `dir="rtl"` on its own.
53
+
54
+ ```html demo
55
+ <div class="column-layout">
56
+ <article class="column-span-10 column-start-2 card">
57
+ Columns 2 through 11
58
+ </article>
59
+ </div>
60
+ ```
61
+
62
+ Used without a span, a start runs to the end of the canvas.
63
+
64
+ ```html demo
65
+ <div class="column-layout">
66
+ <aside class="column-start-9 card">Columns 9 through 12</aside>
67
+ </div>
68
+ ```
69
+
70
+ Keep a combined placement inside the canvas: `S + N - 1 <= 12`. So
71
+ `.column-start-9 .column-span-4` is valid and `.column-start-10 .column-span-4`
72
+ is not. Exceeding the canvas adds a thirteenth, content-sized column, and every
73
+ other region shrinks with it — the failure is canvas-wide, not local to the
74
+ region you got wrong.
75
+
76
+ ## Cross-section alignment
77
+
78
+ The canvas is shared across sibling sections, so regions in different sections
79
+ can line up on the same columns — something a collection or a sidebar cannot
80
+ guarantee. This is the case no other primitive can replace.
81
+
82
+ ```html demo
83
+ <div class="stack">
84
+ <div class="column-layout">
85
+ <h3 class="column-span-8 column-start-3">Feature title</h3>
86
+ <p class="muted column-span-8 column-start-3">Kicker aligned to the same line.</p>
87
+ </div>
88
+
89
+ <div class="column-layout">
90
+ <p class="column-span-8 column-start-3">
91
+ Body copy starts on the same column as the title above and spans the same
92
+ eight columns.
93
+ </p>
94
+ <aside class="column-span-2 column-start-11 card">Inline note</aside>
95
+ </div>
96
+ </div>
97
+ ```
98
+
99
+ Both sections name the same `column-start-3` / `column-span-8`, so their content
100
+ shares a left edge and an alignment gutter without a wrapping grid.
101
+
102
+ ## The responsive contract
103
+
104
+ `.column-layout` has **no automatic collapse**. The canvas stays twelve columns
105
+ at every width, and the application owns narrow-container behavior.
106
+
107
+ This is deliberate. `8 + 4` and `3 + 9` do not become unusable at the same
108
+ width, a centered article may only need wider gutters, and a dashboard may want
109
+ three regions to become two before stacking. A single framework threshold would
110
+ be wrong more often than right, and a hidden one would have to be undone rather
111
+ than extended.
112
+
113
+ The simplest recomposition stacks everything:
114
+
115
+ ```css
116
+ @container (width < 40rem) {
117
+ .profile-layout > * {
118
+ grid-column: 1 / -1;
119
+ }
120
+ }
121
+ ```
122
+
123
+ A coordinate system is more useful when you keep it through an intermediate
124
+ state:
125
+
126
+ ```css
127
+ @container (width < 48rem) {
128
+ .profile-main {
129
+ grid-column: 1 / span 6;
130
+ }
131
+
132
+ .profile-aside {
133
+ grid-column: 7 / span 6;
134
+ }
135
+ }
136
+
137
+ @container (width < 32rem) {
138
+ .profile-main,
139
+ .profile-aside {
140
+ grid-column: 1 / -1;
141
+ }
142
+ }
143
+ ```
144
+
145
+ ```html
146
+ <div class="container-query">
147
+ <div class="column-layout profile-layout">
148
+ <main class="column-span-8 profile-main">...</main>
149
+ <aside class="column-span-4 column-start-9 profile-aside">...</aside>
150
+ </div>
151
+ </div>
152
+ ```
153
+
154
+ The `.container-query` wrapper here enables **your** `@container` rules, not a
155
+ hidden framework behavior. Remove your rules and the wrapper stops mattering.
156
+ This is the opposite of a primitive whose responsive contract depends on a
157
+ wrapper someone else has to remember.
158
+
159
+ Placement classes carry zero specificity, so a single-class rule of your own
160
+ wins without `!important` and without having to undo a framework declaration
161
+ first.
162
+
163
+ ## Narrow containers
164
+
165
+ Twelve columns is a wide-context tool. With the default `--gap`, a 279px
166
+ container spends 132px on its eleven gaps and leaves about 12px per unit — a
167
+ `.column-span-4` region is 84px wide.
168
+
169
+ The framework guarantees the canvas itself never overflows its container: the
170
+ tracks are `minmax(0, 1fr)` and every child gets `min-inline-size: 0`, so item
171
+ boxes stay inside their tracks. It does not guarantee that content inside a
172
+ narrow span stays readable, or that an unbreakable word will not paint outside
173
+ its track. Define a narrow representation where the composition needs one.
174
+
175
+ ## Scope
176
+
177
+ The primitive is horizontal only. There are no `.row-span-*`, `.area-*`, or
178
+ `.order-*` classes, and no breakpoint variants such as `md-column-span-6` —
179
+ those would move responsive strategy back into markup. For genuinely
180
+ two-dimensional placement, use CSS Grid directly on your own class:
181
+
182
+ ```css
183
+ .dashboard-summary {
184
+ grid-row: 1 / span 2;
185
+ }
186
+ ```
187
+
188
+ The column count is fixed at twelve and is not configurable. Twelve is what
189
+ makes the vocabulary shared and lets `6 + 6`, `4 + 4 + 4`, `3 + 3 + 3 + 3`,
190
+ `8 + 4`, and `2 + 8 + 2` all land on the same canvas. For a track system whose
191
+ sizes carry meaning rather than twelve interchangeable units, use
192
+ `--grid-columns` on `.grid`.
193
+
194
+ Unlike `.grid-N`, the track template does not read `--gap`, so the gap
195
+ utilities are exact here at every width.
196
+
197
+ A region carrying a placement class must generate a box. `display: contents`
198
+ removes that box and promotes its descendants to grid items, which leaves the
199
+ placement with nothing to apply to.
200
+
201
+ ### Classes
202
+
203
+ - `.column-layout` establishes the twelve-column canvas.
204
+ - `.column-span-1` … `.column-span-12` set the width in canvas units.
205
+ - `.column-start-1` … `.column-start-12` set the starting line, running to the
206
+ canvas end unless a span refines it.
@@ -27,4 +27,9 @@ Use local variables for common ratios.
27
27
  .avatar-preview {
28
28
  --frame-ratio: 1;
29
29
  }
30
- ```
30
+ ```
31
+
32
+ `overflow: hidden` is what makes the frame a media frame: it clips the media to
33
+ the ratio and its corners. Floating decorations (badges, live dots, captions
34
+ that overhang) therefore cannot live inside the frame — they are clipped too.
35
+ Place them in a sibling or wrapper around the frame instead.
@@ -1,25 +1,26 @@
1
1
  # Grid
2
2
 
3
- Responsive equal-width item grids with a tunable minimum item width.
3
+ Two contracts sit behind these classes. Pick by asking what determines the
4
+ column count.
5
+
6
+ - The **item width** is what matters — use `.grid` and tune `--grid-min`.
7
+ - The **column density** is what matters — use `.grid-2`, `.grid-3`, `.grid-4`,
8
+ or `.grid-6`.
9
+
10
+ ## Space-driven collection
11
+
12
+ `.grid` fits as many columns as the available inline space permits. Incomplete
13
+ final rows are part of the contract.
4
14
 
5
15
  ```html demo
6
16
  <section class="grid">
7
- <article class="card">
8
- <h3>Starter</h3>
9
- <p>For small projects.</p>
10
- </article>
11
- <article class="card">
12
- <h3>Team</h3>
13
- <p>For shared products.</p>
14
- </article>
15
- <article class="card">
16
- <h3>Scale</h3>
17
- <p>For larger systems.</p>
18
- </article>
17
+ <article class="card"><h3>Starter</h3><p>For small projects.</p></article>
18
+ <article class="card"><h3>Team</h3><p>For shared products.</p></article>
19
+ <article class="card"><h3>Scale</h3><p>For larger systems.</p></article>
19
20
  </section>
20
21
  ```
21
22
 
22
- Tune the minimum item width with `--grid-min`.
23
+ Tune the item minimum with `--grid-min`.
23
24
 
24
25
  ```css
25
26
  .pricing-grid {
@@ -27,116 +28,146 @@ Tune the minimum item width with `--grid-min`.
27
28
  }
28
29
  ```
29
30
 
30
- Or replace the responsive template entirely with `--grid-columns` for a
31
- custom or asymmetric layout. Because this overrides the intrinsic
32
- `auto-fit/minmax` algorithm, you own any narrow-container collapse:
31
+ ## Count-driven density
33
32
 
34
- ```css
35
- .feature-grid {
36
- --grid-columns: minmax(0, 2fr) minmax(0, 1fr);
37
- }
33
+ `.grid-N` declares a structural density of N columns. It is responsive on its
34
+ own: it never exceeds N columns, never overflows, and every item keeps the same
35
+ width.
38
36
 
39
- @container (width < 40rem) {
40
- .feature-grid {
41
- --grid-columns: 1fr;
42
- }
43
- }
37
+ ```html demo bare
38
+ <div class="grid-4">
39
+ <div class="card">Exercitation</div>
40
+ <div class="card">Amet mollit</div>
41
+ <div class="card">Aute cillum</div>
42
+ <div class="card">Duis non </div>
43
+ </div>
44
44
  ```
45
45
 
46
- `--grid-columns` applies to `.grid` only. The `.grid-2`, `.grid-3`,
47
- `.grid-4`, and `.grid-6` presets retain their fixed-column contracts.
46
+ `--grid-min` does not apply here. Item width is `.grid`'s contract; column
47
+ density is `.grid-N`'s. Choose the preset that suits your item size:
48
48
 
49
- ## Fixed columns
49
+ | Item | Preset |
50
+ |-----------------------------------|----------------------|
51
+ | large card | `.grid-2` |
52
+ | card with a heading and a summary | `.grid-3`, `.grid-4` |
53
+ | compact tile, stat, avatar | `.grid-6` |
50
54
 
51
- Predictable 2/3/4/6-column grids. Full count by default; wrap in `.container-query` to make the column count collapse on narrow wrappers.
55
+ ## Balanced subdivision
52
56
 
53
- Use `.grid-2`, `.grid-3`, `.grid-4`, and `.grid-6` when the column count matters more than the item minimum width — for example, when a row should always read as "three items side by side", or when an empty cell should not stretch to fill space. Unlike `.grid`, the columns are fixed; if you have only two items in a `.grid-3`, the third cell stays empty rather than redistributing.
57
+ Left alone, a preset collapses one column at a time, so a six-item `.grid-6`
58
+ can pass through five columns — five items and a lone sixth. The example above
59
+ is that bare version. Placed inside a container named **`actual-grid`** — the
60
+ `.container-query` helper, or a region of your own that declares
61
+ `container: actual-grid / inline-size` — it only ever enters a **divisor of N**:
54
62
 
55
- A `.grid-2/3/4/6` without a wrapper is a **fixed grid** (always at its full column count); with a `.container-query` wrapper, it's a **responsive grid** (the column count collapses on narrow wrappers). The wrapper is the query container; the grid itself is a plain block grid.
63
+ ```text
64
+ .grid-2 2 → 1
65
+ .grid-3 3 → 1
66
+ .grid-4 4 → 2 → 1
67
+ .grid-6 6 → 3 → 2 → 1
68
+ ```
69
+
70
+ Every state splits the collection evenly, and all items keep the same width.
56
71
 
57
72
  ```html demo
58
73
  <div class="container-query">
59
- <div class="grid-3">
60
- <article class="card">
61
- <h3>Starter</h3>
62
- <p>For small projects.</p>
63
- </article>
64
- <article class="card">
65
- <h3>Team</h3>
66
- <p>For shared products.</p>
67
- </article>
68
- <article class="card">
69
- <h3>Scale</h3>
70
- <p>For larger systems.</p>
71
- </article>
74
+ <div class="grid-6">
75
+ <div class="card">1</div>
76
+ <div class="card">2</div>
77
+ <div class="card">3</div>
78
+ <div class="card">4</div>
79
+ <div class="card">5</div>
80
+ <div class="card">6</div>
72
81
  </div>
73
82
  </div>
74
83
  ```
75
84
 
76
- A `grid-4` demo:
85
+ ### Container sizes
77
86
 
78
- ```html demo
79
- <div class="container-query">
80
- <div class="grid-4">
81
- <article class="card">
82
- <h3>Starter</h3>
83
- <p>For small projects.</p>
84
- </article>
85
- <article class="card">
86
- <h3>Team</h3>
87
- <p>For shared products.</p>
88
- </article>
89
- <article class="card">
90
- <h3>Scale</h3>
91
- <p>For larger systems.</p>
92
- </article>
93
- <article class="card">
94
- <h3>Enterprise</h3>
95
- <p>Contact us.</p>
96
- </article>
97
- </div>
98
- </div>
87
+ The steps are read from the **container's content box** — not the viewport, and
88
+ not the grid's own width. Padding and borders on the container come off before
89
+ the query resolves.
90
+
91
+ | Container content box | `.grid-2` | `.grid-3` | `.grid-4` | `.grid-6` |
92
+ |-----------------------|-----------|-----------|-----------|-----------|
93
+ | under `28rem` | 1 | 1 | 1 | 1 |
94
+ | `28rem` to `48rem` | 2 | 1 | 2 | 2 |
95
+ | `48rem` to `64rem` | 2 | 3 | 2 | 3 |
96
+ | `64rem` and up | 2 | 3 | 4 | 6 |
97
+
98
+ Size a region that hosts a `.grid-N` so it lands on the step you want, with room
99
+ to spare. The step is a cliff, not a ramp: a container at `47rem` gives
100
+ `.grid-3` a single column, the same as one at `20rem`. `.grid-3` has no
101
+ intermediate state by design — it never shows `2 + 1`.
102
+
103
+ Budget backwards from the content box. A region that must reach a step needs
104
+ that width **plus its own padding and borders**:
105
+
106
+ ```text
107
+ 3 columns 48rem + 2 x 1rem padding ~= 50rem outer
108
+ 4 or 6 64rem + 2 x 1rem padding ~= 66rem outer
99
109
  ```
100
110
 
101
- A `grid-6` demo for compact items:
111
+ Round up past the figure rather than matching it exactly, so a later padding
112
+ change cannot drop the region a state.
102
113
 
103
- ```html demo
114
+ Balanced subdivision is precision, never a prerequisite for responsive
115
+ behavior — forgetting the container costs you the exact chain, nothing else.
116
+ The grid responds only to a container named `actual-grid`, never to an
117
+ incidental query container, so a region that sets `container-type: inline-size`
118
+ for its own reasons leaves the grid untouched. The container has to be an
119
+ ancestor: an element cannot query its own size without taking inline-size
120
+ containment, which would collapse the grid inside a `.cluster`, a float, or any
121
+ shrink-to-fit box. Put it on a normal block-level wrapper for the same reason.
122
+
123
+ The chain balances the **declared density**, not your actual item count. Eight
124
+ items in `.grid-6` still give `6 + 2`. For a paginated collection, choose a page
125
+ size that suits the density — 12, 20, and 24 divide well. A partial final page
126
+ is normal.
127
+
128
+ ## Exact templates
129
+
130
+ `--grid-columns` replaces `.grid`'s intrinsic recipe. Use it for exact track
131
+ templates that do not match a built-in layout contract: arbitrary structural
132
+ counts such as seven calendar days, asymmetric fractional tracks, or mixed
133
+ intrinsic/flexible tracks. Once set, the application owns narrow-container
134
+ behavior.
135
+
136
+ ```css
137
+ /* Semantic count not represented by .grid-N */
138
+ --grid-columns: repeat(7, minmax(0, 1fr));
139
+
140
+ /* Meaningful asymmetric ratio */
141
+ --grid-columns: 2fr 1fr 1fr 1fr;
142
+
143
+ /* Intrinsic trailing control */
144
+ --grid-columns: repeat(4, minmax(0, 1fr)) auto;
145
+ ```
146
+
147
+ ```html
104
148
  <div class="container-query">
105
- <div class="grid-6">
106
- <article class="card compact">
107
- <span class="muted">Open</span>
108
- <strong>18</strong>
109
- </article>
110
- <article class="card compact">
111
- <span class="muted">Queued</span>
112
- <strong>7</strong>
113
- </article>
114
- <article class="card compact">
115
- <span class="muted">Blocked</span>
116
- <strong>2</strong>
117
- </article>
118
- <article class="card compact">
119
- <span class="muted">Shipped</span>
120
- <strong>41</strong>
121
- </article>
122
- <article class="card compact">
123
- <span class="muted">Owners</span>
124
- <strong>6</strong>
125
- </article>
126
- <article class="card compact">
127
- <span class="muted">SLA</span>
128
- <strong>99%</strong>
129
- </article>
130
- </div>
149
+ <div class="editorial-grid grid">...</div>
131
150
  </div>
132
151
  ```
133
152
 
134
- ## Behavior
153
+ ```css
154
+ .editorial-grid {
155
+ --grid-columns: minmax(0, 2fr) minmax(0, 1fr);
156
+ }
157
+
158
+ @container (width < 40rem) {
159
+ .editorial-grid {
160
+ --grid-columns: 1fr;
161
+ }
162
+ }
163
+ ```
164
+
165
+ For an ordinary main region plus an aside, prefer `.sidebar-layout`. When a
166
+ small group of peer regions must be either entirely horizontal or entirely
167
+ stacked, prefer `.switcher`.
135
168
 
136
- - Without `.container-query`: `.grid-2` is always 2 cols, `.grid-3` is always 3 cols, `.grid-4` is always 4 cols, and `.grid-6` is always 6 cols.
137
- - With `.container-query`: `.grid-2`, `.grid-3`, and `.grid-4` collapse to one column on a narrow wrapper (under 28rem). `.grid-3` and `.grid-4` step through 2 columns between 28rem and 48rem. `.grid-6` starts at 2 columns under 28rem, steps through 3 columns between 28rem and 64rem, then returns to 6 columns.
138
- - The intermediate 2-col step is useful for lists of items divisible by both 2 and 3 (or 4) — a 12-item list reads as 12 lines, then 6 lines of 2, then 4 lines of 3 (or 3 lines of 4), depending on the grid.
139
- - `.grid-6` is for compact items such as stats, shortcut tiles, swatches, avatar summaries, and small settings cards. It does not collapse to one column by default. If item width matters more than an exact six-column rhythm, prefer `.grid` with a smaller `--grid-min`.
140
- - The wrapper is the query container, so the same class behaves differently in a narrow sidebar than in a wide main area. No viewport breakpoints are involved.
169
+ ### Hooks
141
170
 
142
- Do not add `.row`, `.col-6`, `.offset-2`, or other fixed grid-system classes unless the project later proves it needs a formal grid system.
171
+ - `--grid-min` tunes the minimum item width of the intrinsic `.grid` recipe.
172
+ It does not apply to `.grid-N`.
173
+ - `--grid-columns` replaces that recipe with an author-owned template.
@@ -25,4 +25,4 @@ Add `.items-center` to align the leading element with short trailing content. Fo
25
25
  </div>
26
26
  ```
27
27
 
28
- The media object is the underlying pattern of `.blog-author`, `.blog-comment`, and similar compositions in templates. Components can adopt it instead of repeating the grid rule.
28
+ The media object is the underlying pattern of `.blog-author`, `.blog-comment`, and similar compositions in templates. Components can adopt it instead of repeating the grid rule.
@@ -1,6 +1,6 @@
1
1
  # Layout Overview
2
2
 
3
- Layout provides a small set of composable building blocks for common page, app, and content structure. It is not a utility-first framework and it is not a twelve-column grid system.
3
+ Layout provides a small set of composable building blocks for common page, app, and content structure. It is not a utility-first framework, and the twelve-column canvas it does ship (`.column-layout`) is an opt-in vocabulary for deliberate composition rather than the default way to build a page.
4
4
 
5
5
  - Layout classes compose components; components do not own page spacing.
6
6
  - Use custom properties to tune a layout instance.
@@ -8,6 +8,19 @@ Layout provides a small set of composable building blocks for common page, app,
8
8
  - Keep class names semantic enough to remember and generic enough to reuse.
9
9
  - Add a new layout primitive only when a pattern appears often and is awkward to express with existing primitives.
10
10
 
11
+ See [Choosing a layout](./choosing.md) for the distinctions between responsive
12
+ collections, fixed structural grids, all-or-nothing peer regions, sidebars, and
13
+ explicit column placement.
14
+
15
+ ## Child contract
16
+
17
+ Layout primitives operate on the boxes generated by their direct children.
18
+ Applying `display: contents` to a participating child removes that box and
19
+ promotes its descendants into the parent layout, bypassing the sizing or
20
+ placement assigned to the child. The layout contracts below are expressed
21
+ against direct children — keep those children as real boxes unless you intend
22
+ that bypass.
23
+
11
24
  ## Spacing tokens
12
25
 
13
26
  Layout shares the global spacing surface and exposes a small set of gap and rhythm tokens.
@@ -34,4 +47,4 @@ Most layout primitives read `--gap` and allow local overrides.
34
47
 
35
48
  Prefer a local custom property over adding many one-off utility classes. Use inline styles only for demos, prototypes, or truly dynamic values.
36
49
 
37
- There are no `.gap-sm` / `.gap-md` / `.gap-lg` density variants on the core layout primitives; set `--gap` locally when only spacing should change. The optional `utilities-extra.css` layer ships those gap utilities for row/column containers.
50
+ There are no `.gap-sm` / `.gap-md` / `.gap-lg` density variants on the core layout primitives; set `--gap` locally when only spacing should change. The extra utilities (`src/css/utilities/extra.css`) ship those gap utilities for row/column containers.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Horizontal rails that stay useful without JavaScript and snap in modern browsers.
4
4
 
5
- > **Optional** — import `actual-css/css/optional/scroll-snap` or `actual-css/css/optional/index`.
5
+ > **Module** — import `actual-css/css/layout/scroll-snap` or `actual-css/css/layout`.
6
6
 
7
7
  Use `.scroll-snap` for a niche row of items that should scroll horizontally, such as card rails, media strips, overflow tabs, or a simple touch-friendly carousel baseline. Scrolling only appears when the items are wider than the container; set `--scroll-snap-item-size` for card rails.
8
8
 
@@ -51,4 +51,4 @@ Keep scrollbars visible by default. If a product deliberately hides them, make t
51
51
  </div>
52
52
  ```
53
53
 
54
- `.scroll-snap` is not a full interactive carousel. For previous/next controls, pagination, active state, mouse drag, looping, autoplay, or robust accessibility behavior, use a dedicated carousel library such as Swiper and compose it with Actual components.
54
+ `.scroll-snap` is not a full interactive carousel. For previous/next controls, pagination, active state, mouse drag, looping, autoplay, or robust accessibility behavior, use a dedicated carousel library such as Swiper and compose it with Actual components.
@@ -0,0 +1,45 @@
1
+ # Scroll Target
2
+
3
+ Anchor scroll offset: keep `#hash` and `scrollIntoView()` targets clear of sticky headers.
4
+
5
+ > **Module** — import `actual-css/css/layout/scroll-target` or `actual-css/css/layout`.
6
+
7
+ A hash link or scripted scroll places the target flush at the scroll container's start edge. Under a sticky header such as `.topbar`, the heading you jumped to lands underneath it. Add `.scroll-target` to the elements that are link targets — sections, headings — and the browser stops early, reserving space above them.
8
+
9
+ ```html demo
10
+ <nav class="cluster" aria-label="Sections" style="margin-block-end: var(--space-30)">
11
+ <a class="btn neutral sm" href="#st-alpha">Alpha</a>
12
+ <a class="btn neutral sm" href="#st-beta">Beta</a>
13
+ <a class="btn neutral sm" href="#st-gamma">Gamma</a>
14
+ </nav>
15
+ <div class="overflow-auto" style="block-size: 10rem; border: var(--border-width) solid var(--border); border-radius: var(--radius)">
16
+ <section id="st-alpha" class="scroll-target" style="padding: var(--space-30)">
17
+ <h3>Alpha</h3>
18
+ <p>The first section. Followed by enough content to make the container scroll.</p>
19
+ </section>
20
+ <section id="st-beta" class="scroll-target" style="padding: var(--space-30)">
21
+ <h3>Beta</h3>
22
+ <p>The second section. Its top edge stops below the container edge.</p>
23
+ </section>
24
+ <section id="st-gamma" class="scroll-target" style="padding: var(--space-30)">
25
+ <h3>Gamma</h3>
26
+ <p>The last section.</p>
27
+ </section>
28
+ </div>
29
+ ```
30
+
31
+ The offset is a plain `scroll-margin-block-start`, so it works in every scroll container — the viewport, a sidebar, an overflow region — and composes with the scrollspy enhancer. Scrollspy only decides which link is active; this offset decides where the page actually lands when the link is followed.
32
+
33
+ ## CSS hooks
34
+
35
+ - `--scroll-target-offset` — space kept above the target after scrolling. Set it
36
+ once on `:root` (or on the sticky header's height) in applications with a
37
+ fixed header:
38
+
39
+ ```css
40
+ :root {
41
+ --scroll-target-offset: 5rem;
42
+ }
43
+ ```
44
+
45
+ Deliberately no `[id]` global rule: making the offset explicit per target keeps plain ids (modals, form fields, skip links) untouched.
@@ -1,27 +1,47 @@
1
1
  # Sidebar Layout
2
2
 
3
- Two-column layout where one side has a preferred width and the other takes the remaining space.
3
+ Use `.sidebar-layout` for a main region followed by a secondary region. It
4
+ switches intrinsically according to its own available width: the regions sit
5
+ side by side when the main minimum, preferred aside width, and gap fit; they
6
+ otherwise stack. No `.container-query` ancestor is required.
4
7
 
5
- Use `.sidebar-layout` for two-column layouts where the aside should align to the top of the content, stay sticky, or keep a predictable declared width.
8
+ ```html demo
9
+ <div class="sidebar-layout">
10
+ <article class="stack">
11
+ <h1>Long-form article</h1>
12
+ <p>Article body that benefits from a related table of contents.</p>
13
+ </article>
14
+
15
+ <aside class="stack">
16
+ <h3>On this page</h3>
17
+ <ol class="list-reset"><li><a class="link-muted" href="#">Section</a></li></ol>
18
+ </aside>
19
+ </div>
20
+ ```
6
21
 
7
- Wrap it in `.container-query` to make the switch depend on the container width. Below 64rem the columns stack; at and above it the aside takes `--sidebar-layout-size` and the content takes the remaining space. Older browsers use the viewport fallback.
22
+ The first child is the flexible main region and the last child is the aside.
23
+ Use a custom `.grid` template only when an exact editorial ratio is structural.
24
+
25
+ To place the aside on the inline start instead, add `.reverse` and put the
26
+ aside first in the DOM — visual, reading and keyboard order then all agree:
8
27
 
9
28
  ```html demo
10
- <div class="container-query">
11
- <div class="sidebar-layout" style="--sidebar-layout-size: 18rem">
12
- <article class="stack">
13
- <h1>Long-form article</h1>
14
- <p>Article body that benefits from a sticky table of contents.</p>
15
- </article>
16
-
17
- <aside class="stack">
18
- <h3>On this page</h3>
19
- <ol class="list-reset">
20
- <li><a class="link-muted" href="#">Section</a></li>
21
- </ol>
22
- </aside>
23
- </div>
29
+ <div class="sidebar-layout reverse">
30
+ <aside class="stack">
31
+ <h3>On this page</h3>
32
+ <ol class="list-reset"><li><a class="link-muted" href="#">Section</a></li></ol>
33
+ </aside>
34
+
35
+ <article class="stack">
36
+ <h1>Long-form article</h1>
37
+ <p>Article body that benefits from a related table of contents.</p>
38
+ </article>
24
39
  </div>
25
40
  ```
26
41
 
27
- Tune the side width with `--sidebar-layout-size`.
42
+ When the layout stacks (narrow space), the aside stays on top.
43
+
44
+ ### Hooks
45
+
46
+ - `--sidebar-layout-size` sets the aside's preferred width.
47
+ - `--sidebar-content-min` sets the main region's minimum viable width.