actual-css 0.14.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +4 -4
  3. package/components.json +51 -6
  4. package/dist/actual.full.css +363 -31
  5. package/dist/actual.full.js +1 -1
  6. package/dist/actual.full.min.css +1 -1
  7. package/docs/navigation.json +4 -1
  8. package/docs/pages/components/accordion.md +15 -18
  9. package/docs/pages/components/avatar.md +1 -0
  10. package/docs/pages/components/badge.md +41 -5
  11. package/docs/pages/components/button.md +5 -0
  12. package/docs/pages/components/card.md +34 -0
  13. package/docs/pages/components/diagrams.md +96 -0
  14. package/docs/pages/components/steps.md +1 -1
  15. package/docs/pages/components/table.md +4 -0
  16. package/docs/pages/components/timeline.md +111 -0
  17. package/docs/pages/enhancements/tabs.md +48 -6
  18. package/docs/pages/examples/overview.md +3 -0
  19. package/docs/pages/forms/choice-cards.md +3 -0
  20. package/docs/pages/forms/combobox.md +34 -19
  21. package/docs/pages/forms/controls.md +2 -0
  22. package/docs/pages/forms/date-picker.md +34 -13
  23. package/docs/pages/forms/file-upload.md +120 -0
  24. package/docs/pages/forms/overview.md +8 -0
  25. package/docs/pages/foundations/philosophy.md +6 -0
  26. package/docs/pages/foundations/theming.md +57 -5
  27. package/docs/pages/foundations/typography.md +3 -0
  28. package/docs/pages/guides/introduction.md +1 -1
  29. package/docs/pages/guides/modular-import.md +124 -0
  30. package/docs/pages/guides/upgrading.md +63 -0
  31. package/package.json +2 -2
  32. package/reserved-classes.json +3 -0
  33. package/src/css/components/accordion.css +7 -3
  34. package/src/css/components/alert.css +9 -1
  35. package/src/css/components/badge.css +38 -11
  36. package/src/css/components/button.css +10 -2
  37. package/src/css/components/card.css +9 -0
  38. package/src/css/components/index.css +1 -0
  39. package/src/css/components/skeleton.css +11 -0
  40. package/src/css/components/tab.css +77 -0
  41. package/src/css/components/table.css +7 -1
  42. package/src/css/components/timeline.css +160 -0
  43. package/src/css/core/base.css +3 -1
  44. package/src/css/core/theme.css +6 -1
  45. package/src/css/core/tokens.css +3 -3
  46. package/src/css/forms/choice-card.css +5 -2
  47. package/src/css/forms/control.css +12 -3
  48. package/src/css/forms/custom-select.css +1 -1
  49. package/src/css/typography/prose.css +4 -2
  50. package/src/tooling/design-tokens.js +2 -0
  51. package/src/tooling/theme-contrast.js +1 -1
@@ -60,6 +60,7 @@
60
60
  "dialog",
61
61
  "drawer",
62
62
  "data-list",
63
+ "diagrams",
63
64
  "fab",
64
65
  "indicator",
65
66
  "key",
@@ -74,7 +75,8 @@
74
75
  "skeleton",
75
76
  "spinner",
76
77
  "steps",
77
- "table"
78
+ "table",
79
+ "timeline"
78
80
  ]
79
81
  },
80
82
  {
@@ -85,6 +87,7 @@
85
87
  "controls",
86
88
  "combobox",
87
89
  "date-picker",
90
+ "file-upload",
88
91
  "rich-text",
89
92
  "labels",
90
93
  "floating-field",
@@ -6,7 +6,7 @@
6
6
  - Use the `name` attribute for exclusive accordions.
7
7
  - Supports any valid body element (`div`, `p`, `ul`, ...).
8
8
  - Three container treatments: the default common shell, `.flush` (bare separators, for embedding inside an existing surface), and `.separated` (independent items).
9
- - The toggle marker color is customizable with `--accordion-marker-color`; it reinforces to the summary text color on hover, and the marker icon comes from the shared `--icon-chevron` token.
9
+ - The end marker is a chevron that turns when open; its glyph, turn, color, and size are hooks.
10
10
 
11
11
  ```html demo
12
12
  <div class="accordion">
@@ -89,26 +89,21 @@ The accordion owns its disclosure marker; the trigger content belongs to the mar
89
89
  </div>
90
90
  ```
91
91
 
92
- ## Custom markers
92
+ ## Plus / close marker
93
93
 
94
- The end marker is a shared token-based chevron; swapping it for a local icon is a demo concern, not part of the base API.
94
+ Swap the glyph and the turn: a plus turned 45° reads as a close cross (plus
95
+ minus, expand collapse, + / ×).
95
96
 
96
- ```html
97
- <div class="accordion accordion-demo">
97
+ ```html demo
98
+ <div class="accordion" style="--accordion-marker-icon: var(--icon-plus); --accordion-marker-open-rotate: 45deg">
98
99
  <details open>
99
- <summary>
100
- <span class="accordion-demo-icon" aria-hidden="true"></span>
101
- <span>Custom marker at the start</span>
102
- </summary>
103
- <p>This demo swaps the default end marker for a local plus/minus icon.</p>
100
+ <summary>Open: the plus has turned into a cross</summary>
101
+ <p>The turn animates with the open state.</p>
104
102
  </details>
105
103
 
106
104
  <details>
107
- <summary>
108
- <span class="accordion-demo-icon" aria-hidden="true"></span>
109
- <span>Another item</span>
110
- </summary>
111
- <p>The icon belongs to the example, not the base accordion API.</p>
105
+ <summary>Closed: a plus</summary>
106
+ <p>Any mask-ready icon token works as the glyph.</p>
112
107
  </details>
113
108
  </div>
114
109
  ```
@@ -119,6 +114,8 @@ The end marker is a shared token-based chevron; swapping it for a local icon is
119
114
  - `--accordion-pad` — inset of the summary row and the panel. The panel relays it as `--surface-pad`, so a direct `.bleed` child of the panel reaches the item's sides and bottom corners (never the summary); `.flush` drops the inline half and the relay with it.
120
115
  - `--accordion-marker-color` — color of the end marker; it reinforces to the summary text color on hover. In forced-colors mode the marker is pinned to `CanvasText` on the property itself, so an application override of the hook cannot leave a `Canvas`-remapped fill.
121
116
  - `--accordion-marker-size` — edge length of the end marker.
117
+ - `--accordion-marker-icon` — the marker glyph, any mask image (`--icon-chevron`, `--icon-plus`, …).
118
+ - `--accordion-marker-open-rotate` — the marker's turn when open.
122
119
 
123
120
  ### Replacing the marker
124
121
 
@@ -153,8 +150,8 @@ recipe repeats it on its own property:
153
150
  inline-size: var(--accordion-marker-size);
154
151
  block-size: var(--accordion-marker-size);
155
152
  background-color: var(--accordion-marker-color);
156
- -webkit-mask: var(--icon-chevron) center / contain no-repeat;
157
- mask: var(--icon-chevron) center / contain no-repeat;
153
+ -webkit-mask: var(--accordion-marker-icon) center / contain no-repeat;
154
+ mask: var(--accordion-marker-icon) center / contain no-repeat;
158
155
  }
159
156
 
160
157
  .accordion.custom-marker summary:hover .marker {
@@ -162,7 +159,7 @@ recipe repeats it on its own property:
162
159
  }
163
160
 
164
161
  .accordion.custom-marker details[open] .marker {
165
- transform: rotate(180deg);
162
+ transform: rotate(var(--accordion-marker-open-rotate));
166
163
  }
167
164
 
168
165
  @media (forced-colors: active) {
@@ -6,6 +6,7 @@
6
6
  - Can be an inert element, link, or button when the link/button has a real destination or action.
7
7
  - Stack avatars with `.avatar-stack` for overlapping group displays.
8
8
  - A status dot attaches as an empty `.badge` child; the badge carries an `aria-label` so the dot conveys its meaning to assistive tech.
9
+ - For a person chip (mention, assignee), put the avatar first in a `.badge`; see [Badge](badge.md#with-an-avatar).
9
10
  - Does not support shape modifiers as public API. Shape is theme-level.
10
11
  - Sizes can be adjusted with CSS variables and optional `.sm` or `.lg`.
11
12
  - Background is an exposed css variable (and can use `data-tone`).
@@ -23,7 +23,7 @@ direct child of `.stack` (where flex children otherwise stretch), and a flex
23
23
  parent never compresses it (`flex: none`). Use `inline-size: 100%` — or the
24
24
  optional `.inline-size-full` utility — when a full-width badge is intentional.
25
25
 
26
- **Related terms:** chip, tag, pill, removable tag.
26
+ **Related terms:** chip, tag, pill, removable tag, user chip, mention, assignee.
27
27
 
28
28
  ## Class reference
29
29
 
@@ -32,6 +32,7 @@ optional `.inline-size-full` utility — when a full-width badge is intentional.
32
32
  | `.badge` | Component | Compact label; soft by default. |
33
33
  | `.badge:empty` | Composition | Truly-empty badge renders as a solid dot. |
34
34
  | `.dot` | Composition | Status dot inside a badge. |
35
+ | `.avatar` | Composition | Leading avatar sized to the badge. |
35
36
  | Shared intents | Intent | `.primary`, `.secondary`, `.success`, … |
36
37
  | Shared variants | Variant | `.solid`, `.outline`, `.surface`. |
37
38
  | `.sm` / `.lg` | Size | Smaller or larger optical scale. |
@@ -133,7 +134,7 @@ badge.
133
134
  ## With an icon
134
135
 
135
136
  Decorative SVG, image, or `[aria-hidden="true"]` children follow
136
- `--badge-icon-size`.
137
+ `--badge-icon-size`. An `.avatar` keeps its own sizing (see below).
137
138
 
138
139
  ```html demo
139
140
  <span class="badge success">
@@ -150,6 +151,36 @@ Decorative SVG, image, or `[aria-hidden="true"]` children follow
150
151
  </span>
151
152
  ```
152
153
 
154
+ ## With an avatar
155
+
156
+ Put an [`.avatar`](avatar.md) first in the badge for a person chip: mention,
157
+ assignee, contributor, author. The avatar follows the badge size, so the pill
158
+ keeps its height and `.sm` / `.lg` scale both together. Wrap the chips in a
159
+ [`.cluster`](../layout/cluster.md) to let them wrap.
160
+
161
+ ```html demo
162
+ <div class="cluster tight">
163
+ <a href="#" class="badge lg">
164
+ <span class="avatar">
165
+ <img src="https://mockmind-api.uifaces.co/content/human/219.jpg" alt="" />
166
+ </span>
167
+ @jane-doe
168
+ </a>
169
+ <a href="#" class="badge lg">
170
+ <span class="avatar success"><abbr>RM</abbr></span>
171
+ @rin-moreau
172
+ </a>
173
+ <span class="badge primary">
174
+ <span class="avatar"><abbr>AM</abbr></span>
175
+ Ada Morgan
176
+ <button class="close" type="button" aria-label="Remove Ada Morgan"></button>
177
+ </span>
178
+ </div>
179
+ ```
180
+
181
+ Keep `alt=""` when the handle or name sits next to the image. Initials fit
182
+ the default and `.lg` sizes; use an image on `.sm`.
183
+
153
184
  ## Loading status
154
185
 
155
186
  A decorative spinner follows the badge color and optical size.
@@ -185,17 +216,22 @@ an interactive target driving its checkbox/radio, and a nested button would mix
185
216
  two interactive targets. A removable tag next to a selectable chip is a sibling
186
217
  (a widget tag or a `.badge` + `.close`), never a child of the label.
187
218
 
188
- Inside a badge the close follows the pill's size, keeps a 24px pointer target,
189
- and tucks into the padding.
219
+ Put the close last. It mirrors a leading avatar: a disc inside the pill at the
220
+ same inset, so a fill or the hover wash never leaves the pill. On small badges
221
+ the disc is small; an invisible hit area keeps the pointer target at 24px.
190
222
 
191
223
  ```html demo
192
- <span class="badge primary soft">
224
+ <span class="badge primary soft sm">
193
225
  Design
194
226
  <button class="close" type="button" aria-label="Remove Design"></button>
195
227
  </span>
196
228
  <span class="badge primary soft">
229
+ Design
197
230
  <button class="close" type="button" aria-label="Remove Design"></button>
231
+ </span>
232
+ <span class="badge primary soft lg">
198
233
  Design
234
+ <button class="close" type="button" aria-label="Remove Design"></button>
199
235
  </span>
200
236
  ```
201
237
 
@@ -280,3 +280,8 @@ For exclusive groups, manage a single pressed button:
280
280
 
281
281
  - `--btn-radius` — corner radius.
282
282
  - `--btn-gap` — space between an icon and the label text (default `0.375em`).
283
+ - `--btn-shadow` — resting elevation (unset by default). It inherits, so a
284
+ theme can set it once on its root; the solid hover overlay composes with it.
285
+ Change it in `:hover`/`:active` rules for a lift and press.
286
+ Supply shadow-list items; use `0 0 #0000` for no elevation. `none` cannot
287
+ compose with the inset hover overlay and invalidates the whole shadow list.
@@ -16,6 +16,13 @@ Flexible content container with optional header, body, and footer regions.
16
16
  `--surface-raised` and leaves the intent to the text. For a dark card on a
17
17
  light page (or the reverse), put `data-theme="dark"` on the card.
18
18
 
19
+ Shared `.soft` with an intent class gives the card a tone: an opaque surface
20
+ tinted by the intent, with the soft ink. See [Tones](#tones).
21
+
22
+ On `.card.solid`, bare and `.prose` links follow the surrounding text color,
23
+ including hover and keyboard focus, instead of the theme's `--link` ink.
24
+ Nested cards and `data-theme` islands establish their own link context.
25
+
19
26
  ## Basic usage
20
27
 
21
28
  Use semantic elements inside the card. A direct `<header>` or `<footer>` is the
@@ -126,6 +133,33 @@ all footers in the row line up regardless of body length.
126
133
  </section>
127
134
  ```
128
135
 
136
+ ## Tones
137
+
138
+ A toned, tinted, or colored card (accent card, highlight card) is `.soft` plus
139
+ an intent class. The tint is opaque, so it holds over an image, and the ink
140
+ follows the soft recipe, so muted text and links stay readable on it.
141
+
142
+ ```html demo
143
+ <section class="grid">
144
+ <article class="card soft primary">
145
+ <h3>Primary</h3>
146
+ <p class="muted">A highlighted plan or feature.</p>
147
+ </article>
148
+ <article class="card soft success">
149
+ <h3>Success</h3>
150
+ <p class="muted">A completed step.</p>
151
+ </article>
152
+ <article class="card soft warning">
153
+ <h3>Warning</h3>
154
+ <p class="muted">Something to check.</p>
155
+ </article>
156
+ </section>
157
+ ```
158
+
159
+ For a fully colored card, use a `data-theme` island rather than `.solid`: the
160
+ island recomputes muted text, links, and fields for the new surface, where
161
+ `.solid` only repaints the fill and the main ink.
162
+
129
163
  ## Surfaces
130
164
 
131
165
  A card is a surface-owning component: inside a painted band it keeps its own
@@ -0,0 +1,96 @@
1
+ # Diagrams
2
+
3
+ > The framework draws no diagrams. Render Mermaid text with an external engine such as Pele and theme it with Actual tokens.
4
+
5
+ A diagram is a drawing to look at: a chronology, a schedule, a process. For
6
+ content a reader scans, follows links from or acts on, stay in HTML.
7
+
8
+ - Events with links or actions in them: [Timeline](timeline.md).
9
+ - Progress through the steps of a flow: [Steps](steps.md).
10
+ - A timeline chart, Gantt chart, flowchart or any other Mermaid diagram: an
11
+ external engine on the token bridge below.
12
+
13
+ **Related terms:** chart, Mermaid, Gantt, flowchart, sequence diagram, mind
14
+ map, roadmap, timeline chart, org chart, diagram library.
15
+
16
+ ## Pele on Actual tokens
17
+
18
+ [Pele](https://pele.run/) renders Mermaid text to SVG with no runtime
19
+ dependency, and reads its colors, fonts and radius from `--pele-*` custom
20
+ properties on the SVG or any ancestor. The
21
+ [diagrams template](../../demo/templates/diagrams.html) wraps it in a small
22
+ `<pele-diagram>` web component:
23
+
24
+ ```html
25
+ <pele-diagram>
26
+ <script type="text/plain">
27
+ flowchart LR
28
+ A[Request] --> B{Slot free?}
29
+ B -- Yes --> C[Confirm]
30
+ </script>
31
+ </pele-diagram>
32
+ ```
33
+
34
+ The component, in
35
+ [`demo/scripts/pele-diagram.js`](../../demo/scripts/pele-diagram.js), is an
36
+ example to copy, not Actual CSS API. It loads `pele/lazy` from a CDN, which
37
+ fetches each diagram type on first use, and mounts the source found in its
38
+ `text/plain` script. Zoom is off; the boolean `zoom` attribute turns on
39
+ Pele's automatic zoom controls for one diagram.
40
+
41
+ ```css
42
+ pele-diagram {
43
+ --pele-bg: var(--surface-opaque);
44
+ --pele-fg: var(--text);
45
+ --pele-muted: var(--text-muted);
46
+ --pele-line: var(--text-muted);
47
+ --pele-surface: var(--surface-subtle);
48
+ --pele-surface-alt: var(--surface-raised);
49
+ --pele-border: var(--border);
50
+ --pele-accent: var(--primary);
51
+ --pele-critical: var(--danger);
52
+ --pele-error: var(--danger);
53
+ --pele-font: var(--font-sans);
54
+ --pele-font-mono: var(--font-mono);
55
+ --pele-radius: var(--radius);
56
+
57
+ display: block;
58
+ min-inline-size: 0;
59
+ }
60
+
61
+ @supports (color: oklch(from red l c h)) {
62
+ pele-diagram {
63
+ --diagram-series: var(
64
+ --primary-soft-fg,
65
+ color-mix(in oklab, var(--text), var(--primary) var(--soft-fg-mix))
66
+ );
67
+ --pele-series-1: var(--diagram-series);
68
+ --pele-series-2: oklch(from var(--diagram-series) l c calc(h + 135));
69
+ --pele-series-3: oklch(from var(--diagram-series) l c calc(h + 270));
70
+ --pele-series-4: oklch(from var(--diagram-series) l c calc(h + 45));
71
+ --pele-series-5: oklch(from var(--diagram-series) l c calc(h + 180));
72
+ --pele-series-6: oklch(from var(--diagram-series) l c calc(h + 315));
73
+ --pele-series-7: oklch(from var(--diagram-series) l c calc(h + 90));
74
+ --pele-series-8: oklch(from var(--diagram-series) l c calc(h + 225));
75
+ }
76
+ }
77
+ ```
78
+
79
+ Colors resolve at paint time, so a theme or light/dark switch restyles a
80
+ mounted diagram without a re-render; a font change needs the mounted
81
+ diagram's `refresh()`.
82
+
83
+ - `--pele-bg` is opaque because Pele also writes series labels and edge-label
84
+ plates in it.
85
+ - Series colors (timeline sections, pie slices, kanban lanes) are categories,
86
+ so they turn one hue rather than borrow intents, which would read as
87
+ status. The base is the soft primary ink, readable against the surface, and
88
+ Pele writes the series labels in `--pele-bg`.
89
+ - The `@supports` guard is required: a custom property accepts any value, so
90
+ an engine without relative colors would receive an invalid fill. Without
91
+ it, Pele keeps its own series palette.
92
+
93
+ The bridge stays in docs and the demo, like the
94
+ [combobox](../forms/combobox.md) and [date picker](../forms/date-picker.md)
95
+ ones: Actual CSS does not depend on Pele. The template pins the version the
96
+ bridge was checked against.
@@ -4,7 +4,7 @@
4
4
 
5
5
  Use an `<ol>` because the order is part of the meaning. Add `.step-complete` to
6
6
  finished steps and `aria-current="step"` to the current one. Unmarked steps are
7
- upcoming.
7
+ upcoming. For a history of past events, use [Timeline](timeline.md).
8
8
 
9
9
  Orientation and labels are two independent choices.
10
10
 
@@ -141,3 +141,7 @@ a duplication.
141
141
 
142
142
  - `--table-cell-pad` — cell padding; `.compact` re-declares it tighter.
143
143
  - `--table-min` — minimum table width before `.table-wrap` scrolls horizontally.
144
+ - `--table-header-bg`, `--table-header-fg` — header band fill and ink. Set
145
+ them on a theme root rather than on `.table`: a data grid bridge reads the
146
+ same pair, so the table and the grid share one header (see the
147
+ [data grid template](../../demo/templates/data-grid.html)).
@@ -0,0 +1,111 @@
1
+ # Timeline
2
+
3
+ > Vertical history of dated events: activity feed, audit log, order tracking.
4
+
5
+ Use an `<ol>` of events, most recent first or oldest first. Each event gets a
6
+ dot on a rail; a direct `<time>` child is its dateline. The content is plain
7
+ HTML in block flow, so a sentence that mixes text and links stays one
8
+ sentence.
9
+
10
+ **Related terms:** activity feed, activity log, history, audit trail, event
11
+ log, changelog, order tracking.
12
+
13
+ For progress through a process (checkout, onboarding), use
14
+ [Steps](steps.md): a timeline records what happened, steps show where you
15
+ are. For a horizontal, alternating or time-scaled chronology, or a Gantt
16
+ chart, render a diagram: see [Diagrams](diagrams.md).
17
+
18
+ ## Basic usage
19
+
20
+ ```html demo
21
+ <ol class="timeline">
22
+ <li>
23
+ <time datetime="2026-10-18T09:30">Today, 09:30</time>
24
+ <strong>Appointment confirmed</strong>
25
+ <p class="muted">The patient received a confirmation email.</p>
26
+ </li>
27
+ <li>
28
+ <time datetime="2026-10-17T14:00">Yesterday, 14:00</time>
29
+ <strong>Appointment requested</strong>
30
+ <p class="muted">The booking was submitted online.</p>
31
+ </li>
32
+ <li>
33
+ <time datetime="2026-10-15">October 15</time>
34
+ <strong>Patient registered</strong>
35
+ </li>
36
+ </ol>
37
+ ```
38
+
39
+ The dot lines up with the first line of the event, whether it opens with the
40
+ `<time>` or with text. Block children drop their margins; wrap the content in
41
+ a [`.stack`](../layout/stack.md) when an event needs more spacing.
42
+
43
+ ## Intents
44
+
45
+ An intent class on the `<li>` colors its dot.
46
+
47
+ ```html demo
48
+ <ol class="timeline">
49
+ <li class="success">
50
+ <time datetime="2026-10-18">October 18</time>
51
+ Order delivered
52
+ </li>
53
+ <li class="warning">
54
+ <time datetime="2026-10-17">October 17</time>
55
+ Delivery delayed
56
+ </li>
57
+ <li class="primary">
58
+ <time datetime="2026-10-16">October 16</time>
59
+ Order shipped
60
+ </li>
61
+ </ol>
62
+ ```
63
+
64
+ The color is decoration: write the state in the text too.
65
+
66
+ ## Avatars and icons
67
+
68
+ An [`.avatar`](avatar.md) or an `aria-hidden` icon written first in the `<li>`
69
+ replaces the dot. One such event widens the rail for the whole list, so dots
70
+ and slots stay aligned. An icon sits in a disc colored by the event's intent.
71
+
72
+ ```html demo
73
+ <ol class="timeline">
74
+ <li>
75
+ <span class="avatar primary"><abbr>AM</abbr></span>
76
+ <time datetime="2026-10-18T09:30">Today, 09:30</time>
77
+ <a href="#">Ada Morgan</a> approved the security terms.
78
+ </li>
79
+ <li class="success">
80
+ <i class="ti ti-check" aria-hidden="true"></i>
81
+ <time datetime="2026-10-17">Yesterday</time>
82
+ Contract signed
83
+ </li>
84
+ <li>
85
+ <time datetime="2026-10-15">October 15</time>
86
+ Account created
87
+ </li>
88
+ </ol>
89
+ ```
90
+
91
+ ## Density
92
+
93
+ The gap between events follows the density context: `.compact` and
94
+ `.spacious` on the list or an ancestor tighten or loosen it.
95
+
96
+ ```html demo
97
+ <ol class="timeline compact">
98
+ <li><time datetime="2026-10-18">Today</time>Build passed</li>
99
+ <li><time datetime="2026-10-17">Yesterday</time>Build failed</li>
100
+ <li><time datetime="2026-10-16">October 16</time>Build passed</li>
101
+ </ol>
102
+ ```
103
+
104
+ ## Hooks
105
+
106
+ - `--timeline-dot-size` — dot diameter.
107
+ - `--timeline-slot-size` — avatar and icon diameter; the rail takes this width
108
+ as soon as one event has a slot.
109
+ - `--timeline-gap` — space between events; follows `--density-space`.
110
+ - `--timeline-inline-gap` — space between the rail and the content.
111
+ - `--timeline-line-size` — rail line thickness.
@@ -4,11 +4,13 @@
4
4
 
5
5
  ## Class reference
6
6
 
7
- | Class | Kind | Description |
8
- | ---------- | --------- | -------------------------------------------- |
9
- | `.tabs` | Component | Tab strip; pairs with `role="tablist"`. |
10
- | `.tab` | Component | One tab trigger; pairs with `role="tab"`. |
11
- | `.primary` | Intent | Tints the selected tab's indicator and text. |
7
+ | Class | Kind | Description |
8
+ | ---------------- | --------- | -------------------------------------------- |
9
+ | `.tabs` | Component | Tab strip; pairs with `role="tablist"`. |
10
+ | `.tab` | Component | One tab trigger; pairs with `role="tab"`. |
11
+ | `.primary` | Intent | Tints the selected tab's indicator and text. |
12
+ | `.tabs-attached` | Component | Joins a horizontal tablist to its panels. |
13
+ | `.tab-panel` | Part | Framed panel inside `.tabs-attached`. |
12
14
 
13
15
  ## Usage
14
16
 
@@ -89,6 +91,43 @@ JavaScript involved:
89
91
  </nav>
90
92
  ```
91
93
 
94
+ ## Attached panels
95
+
96
+ For attached tabs (folder tabs, connected or enclosed panels), wrap the
97
+ horizontal tablist and its panels as direct children of `.tabs-attached`.
98
+ Put `.tab` buttons directly in the strip and `.tab-panel` on each panel.
99
+ The selected tab and panel share one surface; selection uses the open edge
100
+ instead of an underline.
101
+ The selected tab uses the panel fill and text color; intent classes such as
102
+ `.primary` do not tint it. `.tab-panel` receives its frame only as a direct
103
+ child of `.tabs-attached`.
104
+ Keep the wrapper free of layout gaps and panel background overrides.
105
+
106
+ ```html demo
107
+ <div class="tabs-attached">
108
+ <div class="tabs" role="tablist" aria-label="Traffic" data-enhance="tabs">
109
+ <button class="tab" type="button" role="tab" id="traffic-overview-tab"
110
+ aria-selected="true" aria-controls="traffic-overview">Overview</button>
111
+ <button class="tab" type="button" role="tab" id="traffic-activity-tab"
112
+ aria-selected="false" aria-controls="traffic-activity" tabindex="-1">Activity</button>
113
+ </div>
114
+ <section class="tab-panel" role="tabpanel" id="traffic-overview"
115
+ aria-labelledby="traffic-overview-tab" tabindex="-1">
116
+ Traffic is up 12% week over week, led by organic search.
117
+ </section>
118
+ <section class="tab-panel" role="tabpanel" id="traffic-activity"
119
+ aria-labelledby="traffic-activity-tab" tabindex="-1" hidden>
120
+ Recent activity appears here.
121
+ </section>
122
+ </div>
123
+ ```
124
+
125
+ Set `--tab-panel-bg`, `--tab-panel-pad`, and `--tab-panel-shadow` on
126
+ `.tabs-attached` to customize the shared fill, panel padding and elevation.
127
+ The neo-brutalist demo theme supplies the panel shadow. Use ordinary `.tabs`
128
+ for vertical rails or navigation links; attached tabs are a horizontal panel
129
+ switcher. Long strips retain horizontal scrolling and keyboard navigation.
130
+
92
131
  ## Equal-width tabs
93
132
 
94
133
  To make a few tabs share the strip's width (full-width, fill), set
@@ -160,8 +199,11 @@ the current item of the strip. This is the only place a `.tab` takes `true`.
160
199
  Do not put a flyout trigger in a `role="tablist"`: a tablist holds only
161
200
  `role="tab"` items, and the arrow keys of the two widgets collide.
162
201
 
163
- ## CSS hooks
202
+ ### Hooks
164
203
 
165
204
  - `--tab-flex` — flex of each item; set `1 1 0` on the strip for equal-width tabs
166
205
  (fill the width). A strip that cannot fit its labels still scrolls.
167
206
  - `--tab-gap` — space between an icon and the label text (default `0.375em`).
207
+ - `--tab-panel-bg` — shared fill for the attached panel and selected tab.
208
+ - `--tab-panel-pad` — attached panel padding.
209
+ - `--tab-panel-shadow` — attached panel elevation; the strip casts no shadow.
@@ -33,6 +33,7 @@ Whole pages, composed the way a real product would.
33
33
  - [Workspace settings](../../demo/templates/settings-pricing.html) - plans with visible native choices, preferences and segmented tabs
34
34
  - [iOS-style settings](../../demo/templates/settings-ios.html) - iOS-like controls and grouped settings from unchanged framework markup, a local theme, and its findings listed rule by rule
35
35
  - [Card compositions](../../demo/templates/card-compositions.html) - editorial, team, sign-in and horizontal cards composed from existing primitives
36
+ - [Neo-brutalist](../../demo/templates/neo-brutalist.html) - a risograph print studio on the `neo-brutalist` theme (order alerts, plus-marker FAQ, ruled testimonial grid, docked cookie banner) with the page loading its own fonts
36
37
  - [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
37
38
 
38
39
  ### Layout references
@@ -63,6 +64,8 @@ extension points.
63
64
  - [Data grid](../../demo/templates/data-grid.html) - an external data grid component themed with Actual tokens (sort, filter, search, selection)
64
65
  - [Combobox](../../demo/templates/combobox.html) - an external combobox themed with Actual tokens (search, tags, autocomplete)
65
66
  - [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
67
+ - [File upload](../../demo/templates/file-upload.html) - the native file input, Dropzone rendering its file rows as Actual components, and FilePond on Actual tokens
68
+ - [Diagrams](../../demo/templates/diagrams.html) - Mermaid timelines, Gantt charts and flowcharts drawn by Pele through a small web component, on Actual tokens
66
69
 
67
70
  ## Sites
68
71
 
@@ -197,6 +197,9 @@ The dot is `::before`: a full-chip layer clipped to a `circle()` centred on
197
197
  the check slot (`--choice-chip-dot`). A theme can grow it into a selected fill
198
198
  by widening the clip, as the `material` theme does.
199
199
 
200
+ The check uses `--state-selected-text` when the theme sets it, including on
201
+ chips with an explicit intent. Otherwise it follows the chip's intent.
202
+
200
203
  ## CSS hooks
201
204
 
202
205
  - `--choice-card-pad` — inner padding.